Clang ++
Je viens de tomber sur ce bogue amusant.
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
std::stringstream prog;
constexpr unsigned c_strlen( char const* str, unsigned count = 0 )
{
return ('\0' == str[0]) ? count : c_strlen(str+1, count+1);
}
template < char t_c, char... tt_c >
struct rec_eval
{
static void eval()
{
rec_eval<t_c>::eval();
rec_eval < tt_c... > :: eval ();
}
};
template < char t_c >
struct rec_eval < t_c >
{
static void eval() {
switch(t_c) {
case '+':
prog<<"++t[i];";
break;
case '-':
prog<<"--t[i];";
break;
case '>':
prog<<"++i;";
break;
case '<':
prog<<"--i;";
break;
case '[':
prog<<"while(t[i]){";
break;
case ']':
prog<<"}";
break;
case '.':
prog<<"putc(t[i],stdout);";
break;
case ',':
prog<<"t[i]=getchar();";
break;
}
}
};
template < char... tt_c >
struct exploded_string
{
static void eval()
{
rec_eval < tt_c... > :: eval();
}
};
template < typename T_StrProvider, unsigned t_len, char... tt_c >
struct explode_impl
{
using result =
typename explode_impl < T_StrProvider, t_len-1,
T_StrProvider::str()[t_len-1],
tt_c... > :: result;
};
template < typename T_StrProvider, char... tt_c >
struct explode_impl < T_StrProvider, 0, tt_c... >
{
using result = exploded_string < tt_c... >;
};
template < typename T_StrProvider >
using explode =
typename explode_impl < T_StrProvider,
c_strlen(T_StrProvider::str()) > :: result;
int main(int argc, char** argv)
{
if(argc < 2) return 1;
prog << "#include <stdio.h>\n#include <stdlib.h>\nint main(){unsigned char* t=calloc(";
prog << (1 << sizeof(unsigned short));
prog << ",sizeof(unsigned short));unsigned short i=0;";
struct my_str_provider
{
constexpr static char const* str() { return "++++[>+++++<-]>+++[[>+>+<<-]>++++++[<+>-]+++++++++[<++++++++++>-]>[<+>-]<-]+++>+++++++++[<+++++++++>-]>++++++[<++++++++>-]<--[>+>+<<-]>>[<<+>>-]<-->>++++[<++++++++>-]++++++++++>+++++++++[>+++++++++++<-]>[[>+>+>+<<<-]>[<+>-]>>[[>+>+<<-]>>[<<+>>-]<[<->-[<->-[<->-[<->-[<->-[<->-[<->-[<->-[<->-[<<<+>---------->->[-]]]]]]]]]]]<]<<[>>++++++++++++[<++++<++++>>-]<<[.[-]>]<<]>[<++++++[>++++++++<-]>.[-]]<<<<<.<<<<<.[<]>>>>>>>>>.<<<<<..>>>>>>>>.>>>>>>>.[>]>[>+>+<<-]>[<+>-]>[-[[-]+++++++++[<+++++++++++++>-]<--.[-]>]]<<<<<.[<]>>>>>>>>>.>>>>>>>>>.[>]<<.<<<<<.<<<..[<]>>>>>>.[>]<<.[<]>>>>>>>>>.>.[>]<<.[<]>>>>.>>>>>>>>>>>>.>>>.[>]<<.[<]>.[>]<<<<<<.<<<<<<<<<<<..[>]<<<.>.[>]>[>+>+>+<<<-]>[<+>-]>>[[>+>+<<-]>>[<<+>>-]<[<->-[<->-[<->-[<->-[<->-[<->-[<->-[<->-[<->-[<<<+>---------->->[-]]]]]]]]]]]<]<<[>>++++++++++++[<++++<++++>>-]<<[.[-]>]<<]>[<++++++[>++++++++<-]>.[-]]<<<<<.<<<<<.[<]>>>>>>>>>.<<<<<..>>>>>>>>.>>>>>>>.[>]>[>+>+<<-]>[<+>-]>[-[[-]+++++++++[<+++++++++++++>-]<--.[-]>]]<<<<<.[<]>>>>>>>>>.>>>>>>>>>.[>]<<.<<<<<.<<<..[<]>>>>>>.[>]<<<<.>>>.<<<<.<.<<<<<<<<<<.>>>>>>.[>]<<.[<]>>>>>>>>>.>.>>>>>>>>>.[>]<<.<<<<<<<.[<]>>>>>>>>>.[<]>.>>>>>>>>>.[>]<<.<<<<.<<<<<<<<<<<<<.[>]<<<<<<<<<.[>]<<.[<]>>>>>>>>.[>]<<<<<<.[<]>>>>>..[>]<<.<<<<<<<<<<<<.[<]>>>>.[>]<<.<<<<.[<]>>>>>>.>>>.<<<<<<.>>>>>>>.>>>>>>>>>>.[>]<<<.>.>>>-[>+>+>+<<<-]>[<+>-]>>[[>+>+<<-]>>[<<+>>-]<[<->-[<->-[<->-[<->-[<->-[<->-[<->-[<->-[<->-[<<<+>---------->->[-]]]]]]]]]]]<]<<[>>++++++++++++[<++++<++++>>-]<<[.[-]>]<<]>[<++++++[>++++++++<-]>.[-]]<<[>+>+<<-]>[<+>-]+>[<->[-]]<[-<<<[<]>>>>>>>>>>.<.[>]<<.[<]>>>>>>>>>>>.<<.<<<.[>]<<<<<<<<<<.[>]>>]<<<<.<<<<<.[<]>>>>>>>>>.<<<<<..>>>>>>>>.>>>>>>>.[>]>[>+>+<<-]>[<+>-]+>[<->-[<+>[-]]]<[++++++++[>+++++++++++++<-]>--.[-]<]<<<<.[<]>>>>>>>>>.>>>>>>>>>.[>]<<.<<<<<.<<<..[<]>>>>>>.[>]<<.[<]>>>>>>>>>.>.[>]<<.[<]>>>>.>>>>>>>>>>>>.>>>.[>]<<.[<]>.[>]<<<<<<.<<<<<<<<<<<..[>]<<<<.>>>..>>]"; }
};
auto my_str = explode < my_str_provider >{};
my_str.eval();
prog << "}";
std::ofstream ofs(argv[1]);
if(!ofs) return 2;
ofs << prog.str() << std::endl;
ofs.close();
return 0;
}
L'objectif est de traduire Brainfuck en C, en utilisant la méta-programmation de modèles pour effectuer la majeure partie du travail. Ce code fonctionne pour les programmes Brainfuck plus petits, tels que Hello World, mais lorsque j'ai essayé de l'exécuter avec 99 bouteilles ...
$ clang++ -std=c++11 -fconstexpr-depth=1000 bf_static.cpp
clang: error: unable to execute command: Segmentation fault (core dumped)
clang: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 3.5.2 (tags/RELEASE_352/final)
Target: i386-pc-windows-cygnus
Thread model: posix
clang: note: diagnostic msg: PLEASE submit a bug report to http://llvm.org/bugs/ and include the crash backtrace, preprocessed source, and associated run script.
clang: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /tmp/bf_static-afa982.cpp
clang: note: diagnostic msg: /tmp/bf_static-afa982.sh
clang: note: diagnostic msg:
********************
Il sera compilé avec succès dans GCC (après environ 2 minutes), mais le lier provoque un autre problème ...
/usr/lib/gcc/i686-pc-cygwin/4.9.3/../../../../i686-pc-cygwin/bin/as: /tmp/cc0W7cJu.o:
section .eh_frame$_ZN8rec_eval<giant mangled name removed>: string table overflow at offset 10004228
/tmp/cc3JeiMp.s: Assembler messages:
/tmp/cc3JeiMp.s: Fatal error: can't close /tmp/cc0W7cJu.o: File too big
Oops.