Подразделы

Другие разделы

Дата и время

19/04/2024 15:10:31

Авторизация

Имя:
Пароль:
Зарегистрироваться
Восстановить пароль
 

printРазработка компиляторов и интерпретаторов

printПример компилятора

Изменяются только функции для обработки 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
Скачать архив с примером
loading