Пример компилятора
Изменяются только функции для обработки AST и добавляется библиотека времени исполнения.
Файл basic2s.caio
...
%%
void generate(Expr e);
void genargs(Expr x, Expr y)
{ generate(y);
cout<<"\tpush eax\n";
generate(x);
cout<<"\tpop ebx\n";
}
void generate(Expr e)
{
match e {
rule plus(x, y):
genargs(x, y);
cout<<"\tadd eax,ebx\n";
rule minus(x, y):
genargs(x, y);
cout<<"\tsub eax,ebx\n";
rule mult(x, y):
genargs(x, y);
cout<<"\timul ebx\n";
rule divide(x, y):
genargs(x, y);
cout<<"\tcdq\n\tidiv ebx\n";
rule modulo(x, y):
genargs(x, y);
cout<<"\tcdq\n\tidiv ebx\n\tmov eax,edx\n";
rule neg(x):
generate(x);
cout<<"\tneg eax\n";
rule number(x):
cout<<"\tmov eax,"<<x<<"\n";
rule ident(x):
cout<<"\tmov eax,[mem+"<<((x-1)*4)<<"]\n";
}
}
//
int label=0;
void generate(List<Statement> p)
{
int l1,l2;
for(auto s:p)
match s {
rule assign(v, e):
generate(e);
cout<<"\tmov [mem+"<<((v-1)*4)<<"],eax\n";
rule input(v):
cout<<"\tcall inputnum\n\tmov [mem+"<<((v-1)*4)<<"],eax\n";
rule print(e):
generate(e);
cout<<"\tcall printnum\n\tmov eax,offset endl\n\tmov ecx,1\n\tcall printstr\n";
rule printstr(e):
cout<<"\tmov eax,offset text"<<e<<"\n\tmov ecx,"
<<(tc[e].size()+1)<<"\n\tcall printstr\n";
rule whilestmt(e,p1):
l1=++label; l2=++label;
cout<<"label"<<l1<<":\n";
generate(e);
cout<<"\tcmp eax,0\n\tje label"<<l2<<"\n";
generate(p1);
cout<<"\tjmp label"<<l1<<"\nlabel"<<l2<<":\n";
rule ifstmt(e,p1,p2):
l1=++label; l2=++label;
generate(e);
cout<<"\tcmp eax,0\n\tje label"<<l1<<"\n";
generate(p1);
if(p2) cout<<"\tjmp label"<<l2<<"\n";
cout<<"label"<<l1<<":\n";
if(p2) {
generate(p2);
cout<<"label"<<l2<<":\n";
}
}
}
map<string,int> ti; //
int find_id(string name) //
{ for(auto &ch:name) ch=toupper(ch);
int k=ti[name];
if(k==0) k=ti[name]=ti.size();
return k;
}
vector<string> tc; //
void yyinterpret(List<Statement> p)
{ //
string outname=yyinputfile;
size_t pos=outname.rfind('/');
if(pos!=string::npos) outname=outname.substr(pos+1);
pos=outname.rfind('\\');
if(pos!=string::npos) outname=outname.substr(pos+1);
pos=outname.rfind('.');
if(pos!=string::npos) outname=outname.substr(0,pos)+".s";
freopen(outname.c_str(),"w",stdout);
cout<<".intel_syntax noprefix\n.data\n"
"endl: .ascii \"\\n\"\n"
"mem: .fill "<<ti.size()<<",4,0\n";
//
for(int i=0;i<tc.size();++i)
{
cout<<"text"<<i<<": .ascii \"";
for(auto c:tc[i])
switch(c)
{
case '\\':
case '"':
cout<<"\\"<<c;
break;
default:
cout<<c;
break;
}
cout<<"\\n\"\n";
}
cout<<".text\n.global main\nmain:\n";
generate(p);
cout<<("\tret\n");
}
Файл rtl.s:
.intel_syntax noprefix
.data
rckeep: .int 0
buffer: .byte 0
number: .fill 21,1,0
numsign: .byte 0
stdin: .int 0
stdout: .int 0
.text
.global printstr
.global printnum
.global inputnum
start:
push 1251
call _SetConsoleOutputCP@4
push 1251
call _SetConsoleCP@4
push -10 # std_input_handle
call _GetStdHandle@4
mov [stdin],eax
push -11 # std_output_handle
call _GetStdHandle@4
mov [stdout],eax
call main
xor eax,eax
ret
printstr:
push 0
push offset rckeep
push ecx
push eax
push [stdout]
call _WriteFile@20
ret
printnum:
mov esi,21
mov ebx,10
movb [numsign],0
cmp eax,0
je printeq
jg printplus
movb [numsign],1
neg eax
printplus:
cmp eax,0
je printnum1
xor edx,edx
idiv ebx
dec esi
add dl,'0'
mov [number+esi],dl
jmp printplus
printeq:
dec esi
movb [number+esi],'0'
printnum1:
cmpb [numsign],0
je printnum2
dec esi
movb [number+esi],'-'
printnum2:
push 0
push offset rckeep
mov eax,21
sub eax,esi
push eax
add esi,offset number
push esi
push [stdout]
call _WriteFile@20
ret
inputnum:
movb [numsign],0
inputnum0:
push 0
push offset rckeep
push 1
push offset buffer
push [stdin]
call _ReadFile@20
cmpb [buffer],'-'
je inputminus
cmpb [buffer],'0'
jl inputnum0
cmpb [buffer],'9'
jg inputnum0
xor eax,eax
mov al,[buffer]
sub al,'0'
jmp inputnum1
inputminus:
xor eax,eax
movb [numsign],1
inputnum1:
push eax
push 0
push offset rckeep
push 1
push offset buffer
push [stdin]
call _ReadFile@20
pop eax
cmpb [buffer],'0'
jl inputnum2
cmpb [buffer],'9'
jg inputnum2
mov ecx,10
imul ecx
xor ebx,ebx
mov bl,[buffer]
sub bl,'0'
add eax,ebx
jmp inputnum1
inputnum2:
cmpb [numsign],0
je inputnum3
neg eax
inputnum3:
ret
Для компиляции исполняемого файла используется следующие команды:
basic2s.exe test.bas
as -o rtl.o rtl.s
as -o test.o test.s
ld -o test.exe rtl.o test.o -L%MinIDE%\i686-w64-mingw32\lib -lkernel32
Скачать архив с примером