#include"gen.h" #include"err.h" Gen gen_new(void) { Gen gen={ .labelno=0, .stackptr=NULL, .buildarch=M_X86_64, }; return gen; } void gen_free(Gen*gen) { if(!gen)return; } bool gen_findret(const PNode*pn,bool found) { if(found)return true; if(!pn)return found; if(pn->type==PRET)return true; for(size_t i=0;ipnodes.size;++i) if(gen_findret(vec_at(&pn->pnodes,i,const PNode*),found)) return true; return false; } void vec_print_tokens(Vec*tokens) { if(!tokens)return; if(tokens->size<1)return; printf("%p (%lu/%lu): [",tokens,tokens->size,tokens->capacity); for(size_t i=0;isize;++i) { printf("%s",vec_at(tokens,i,const Tok*)->str.buffer); if(isize-1) printf(", "); } printf("]\n"); } void vec_print_eval_elems(Vec*stack) { if(!stack)return; printf("%p stack: [",&stack); for(size_t i=0;isize;++i) { eval_elem t=*vec_at(stack,i,eval_elem*); switch(t.type) { case EE_I32:printf("%d",t.val.i32);break; case EE_IDENT: case EE_VAR: case EE_FUNC:printf("%s",t.val.name);break; case EE_ACC:printf("acc");break; default:printf(".");break; } if(isize-1)printf(","); } printf("]\n"); } void gen_declare_variable(Gen*gen,PNode*pn,FILE*file) { if(!gen)return; if(!pn)return; if(!file)return; // Check syntax if(pn->tokens.size>1) { if(vec_at(&pn->tokens,1,const Tok*)->type!=LOPERATOR&& vec_at(&pn->tokens,1,const Tok*)->type!=LASSIGN&& vec_at(&pn->tokens,1,const Tok*)->type!=LSCOLON) { err_log("%u: expected either ';', type specifier, or initializer",vec_at(&pn->tokens,1,const Tok*)->line); } } else if(pn->tokens.size==0) { err_log("%u: expected identifier",pn->firstline); return; } // Check for re-declaration for(size_t i=0;istackptr->vars.size;++i) { if(strcmp(vec_at(&pn->tokens,0,const Tok*)->str.buffer,vec_at(&gen->stackptr->vars,i,Var*)->name)==0) { err_log("%u: '%s' already declared",vec_at(&pn->tokens,0,const Tok*)->line,vec_at(&pn->tokens,0,const Tok*)->str.buffer); break; } } // Add var to PNode, parse tokens if(pn->tokens.size>0) { gen->stackptr->stacksize+=gen->ld.wordsize; const Tok*vartok=vec_at(&pn->tokens,0,const Tok*); Var var={ .name=vartok->str.buffer, .is_arg=false, .type=I32, .stackloc=-gen->stackptr->stacksize, }; vec_push((Vec*)&gen->stackptr->vars,&var); // Evaluate initialization expression if(pn->tokens.size>1) gen_eval(gen,pn,file); } } void gen_declare_function(Gen*gen,PNode*pn,FILE*file) { if(!gen)return; if(!pn)return; if(!file)return; size_t stacksize=0; gen->stackptr=pn; if(pn->parentnode&&pn->parentnode->parentnode!=NULL) err_log("%u: nested function declaration",pn->firstline); // Check for re-declaration for(size_t i=0;irootnode->funcs.size;++i) { if(strcmp(vec_at(&pn->tokens,0,const Tok*)->str.buffer,vec_at(&gen->rootnode->funcs,i,Func*)->name)==0) { err_log("%u: '%s' already declared",vec_at(&pn->tokens,0,const Tok*)->line,vec_at(&pn->tokens,0,const Tok*)->str.buffer); break; } } // Create Func struct Func func={ .name=vec_at(&pn->tokens,0,const Tok*)->str.buffer, .no_args=0, }; vec_push((Vec*)&gen->rootnode->funcs,&func); // Setup stack, find variables if(pn->tokens.size<2|| vec_at(&pn->tokens,1,Tok*)->subtype!=LLPAREN) err_log("%u: expected '('",vec_at(&pn->tokens,0,const Tok*)->line); else { for(size_t i=2;itokens.size;++i) { if(vec_at(&pn->tokens,i,const Tok*)->type==LIDENTIFIER) { stacksize+=gen->ld.wordsize; Var var={ .name=vec_at(&pn->tokens,i,const Tok*)->str.buffer, .is_arg=true, .stackloc=-stacksize, }; // Use the previous stack frame for i386 function arguments if(gen->buildarch==M_I386) { var.stackloc=-var.stackloc; var.stackloc+=gen->ld.wordsize; } vec_push((Vec*)&gen->stackptr->vars,&var); } } } fprintf(file,".global %s\n%s:\n",vec_at(&pn->tokens,0,const Tok*)->str.buffer,vec_at(&pn->tokens,0,const Tok*)->str.buffer); // Function stack settings switch(gen->buildarch) { case M_I386: stacksize+=gen_stacksize(gen,pn); gen_prolog(gen,pn,file,stacksize); for(size_t i=0;ipnodes.size;++i) gen_code(gen,vec_at(&pn->pnodes,i,PNode*),file); break; case M_X86_64: pn->stacksize+=stacksize; stacksize+=gen_stacksize(gen,pn); gen_prolog(gen,pn,file,stacksize); for(size_t i=0;ipnodes.size;++i) gen_code(gen,vec_at(&pn->pnodes,i,PNode*),file); break; } } // For function invocation arglist evaluation // testing void gen_eval_analyze(const PNode*pn) { Vec rpn_stack={0}; Vec stack=vec_new(sizeof(eval_elem)); rpn_stack=gen_i2r(&pn->tokens); // Evaluate RPN if(rpn_stack.buffer&&rpn_stack.size>0) { for(size_t i=0;itype) { case LIDENTIFIER: printf("!%s ",vec_at(&rpn_stack,i,const Tok*)->str.buffer); break; default: printf("%s ",vec_at(&rpn_stack,i,const Tok*)->str.buffer); break; } } printf(";\n"); } vec_free(&rpn_stack); vec_free(&stack); } void gen_prolog(Gen*gen,const PNode*pn,FILE*file,size_t stacksize) { if(!pn) { err_log("NULL PNode passed to gen_prolog"); return; } if(!file) { err_log("NULL FILE* passed to gen_prolog"); return; } fprintf(file,"\t%s %%%s\n",gen->ld.push_wordsize,gen->ld.bp); if(gen->buildarch==M_X86_64) fprintf(file,"\t%s %%%s\n",gen->ld.push_wordsize,gen->ld.registers_abi_wordsize[2]); fprintf(file,"\t%s %%%s,%%%s\n",gen->ld.mov_wordsize,gen->ld.sp,gen->ld.bp); if(stacksize>0) fprintf(file,"\t%s $%lu,%%%s\n",gen->ld.sub_wordsize,stacksize,gen->ld.sp); // Move argument variables to stack if(gen->buildarch==M_X86_64) for(size_t i=0;ivars.size;++i) if(i<6&&vec_at(&pn->vars,i,Var*)->is_arg) fprintf(file,"\t%s %%%s,%d(%%%s)\n",gen->ld.mov_wordsize,gen->ld.registers_abi_wordsize[i],vec_at(&pn->vars,i,Var*)->stackloc,gen->ld.bp); } void gen_epilog(Gen*gen,const PNode*pn,FILE*file) { if(!pn) { err_log("NULL PNode passed to gen_epilog"); return; } if(!file) { err_log("NULL FILE* passed to gen_epilog"); return; } fprintf(file,"\t%s %%%s,%%%s\n",gen->ld.mov_wordsize,gen->ld.bp,gen->ld.sp); if(gen->buildarch==M_X86_64) fprintf(file,"\t%s %%%s\n",gen->ld.pop_wordsize,gen->ld.registers_abi_wordsize[2]); fprintf(file,"\t%s %%%s\n",gen->ld.pop_wordsize,gen->ld.bp); } size_t gen_stacksize(const Gen*gen,const PNode*pn) { size_t stacksize=0; if(pn->pnodes.size==0) { if(pn->type==PVARDECL) return stacksize+gen->ld.wordsize; else return 0; } for(size_t i=0;ipnodes.size;++i) stacksize+=gen_stacksize(gen,vec_at(&pn->pnodes,i,PNode*)); return stacksize; } // Identify functions bool gen_findfunc(const Gen*const gen,eval_elem*e) { if(!gen){err_log("gen_findfunc: bad gen ");return false;}if(!e){err_log("gen_findfunc: bad eval_elem ");return false;}if(!e->val.name){err_log("gen_findfunc: bad eval_elem name ");return false;} if(!e)return false; for(size_t j=0;jrootnode->funcs.size;++j) { if(strcmp(vec_at(&gen->rootnode->funcs,j,Func*)->name,e->val.name)==0) { e->type=EE_FUNC; /* e->val.name=vec_at(&gen->stackptr->funcs,j,Func*)->name; */ return true; } } return false; } bool gen_findvar(const Gen*const gen,eval_elem*e) { if(!gen){err_log("gen_findvar: bad gen ");return false;} if(!e){err_log("gen_findfunc: bad eval_elem ");return false;} if(!e->val.name){err_log("gen_findfunc: bad eval_elem name ");return false;} for(size_t j=0;jstackptr->vars.size;++j) { if(strcmp(vec_at(&gen->stackptr->vars,j,Var*)->name,e->val.name)==0) { e->type=EE_VAR; e->vstackloc=vec_at(&gen->stackptr->vars,j,Var*)->stackloc; e->vtype=vec_at(&gen->stackptr->vars,j,Var*)->type; /* e->val.name=vec_at(&gen->stackptr->vars,j,Var*)->name; */ //var_stackloc[k]=vec_at(&gen->stackptr->vars,j,Var*)->stackloc; return true; } } return false; } void gen_code(Gen*gen,PNode*pn,FILE*file) { if(!pn) { err_log("passed NULL PNode to gen_code"); return; } if(!file) { err_log("NULL FILE* passed to gen_code"); return; } if(gen->rootnode==pn) fprintf(file,".text\n"); switch(pn->type) { case PFUNDECL: { bool found=false; gen_declare_function(gen,pn,file); found=gen_findret(pn,false); if(!found) err_log("%u: no return in function '%s'",vec_at(&pn->tokens,0,const Tok*)->line, vec_at(&pn->tokens,0,const Tok*)->str.buffer); } break; case PVARDECL: gen_declare_variable(gen,pn,file); break; case PRET: if(pn->tokens.size>0) { if(vec_at(&pn->tokens,0,const Tok*)->type==LOPERATOR&&vec_at(&pn->tokens,0,const Tok*)->subtype==LSMINUS) { if(pn->tokens.size<2) err_log("%u: expected integer",vec_at(&pn->tokens,0,const Tok*)->line); else fprintf(file,"\t%s -%s,%%%s\n",gen->ld.mov_wordsize,vec_at(&pn->tokens,1,const Tok*)->str.buffer,gen->ld.acc_wordsize); } /* else if(vec_at(&pn->tokens,0,const Tok*)->type!=LINTEGER) */ /* { */ /* err_log("%u: returning non-integer",vec_at(&pn->tokens,0,const Tok*)->line); */ /* } */ else gen_eval(gen,pn,file); } gen_epilog(gen,pn,file); fprintf(file,"\tret\n"); /***** * IMPORTANT: * This return exits the (recursive) * code generation call and ceases * reading further PNodes belonging * to its parent node (i.e., on the * same level)!! *****/ return; break; case PIF: if(pn->tokens.size>1) { gen_eval(gen,pn,file); fprintf(file,"\t%s $0,%%%s\n",gen->ld.cmp_wordsize,gen->ld.acc_wordsize); } size_t labelno_cache=gen->labelno; ++gen->labelno; fprintf(file,"\tjz .L%02lu\n",labelno_cache); for(size_t i=0;ipnodes.size;++i) gen_code(gen,vec_at(&pn->pnodes,i,PNode*),file); fprintf(file,".L%02lu:\n",labelno_cache); break; case PWHILE: { size_t pwhile_label1=gen->labelno++; size_t pwhile_label2=gen->labelno++; fprintf(file,".L%02lu:\n",pwhile_label1); if(pn->tokens.size>1) { gen_eval(gen,pn,file); fprintf(file,"\t%s $0,%%%s\n",gen->ld.cmp_wordsize,gen->ld.acc_wordsize); } fprintf(file,"\tjz .L%02lu\n",pwhile_label2); for(size_t i=0;ipnodes.size;++i) gen_code(gen,vec_at(&pn->pnodes,i,PNode*),file); fprintf(file,"\tjmp .L%02lu\n",pwhile_label1); fprintf(file,".L%02lu:\n",pwhile_label2); } break; case PASM: { if(pn->tokens.size<1) err_log("%u: expected string after keyword 'asm'",vec_at(&pn->tokens,0,const Tok*)->line); else { if(pn->tokens.size>2) err_log("%u: unexpected token after 'asm' statement",vec_at(&pn->tokens,0,const Tok*)->line); /* gen_x86_64_print_string(gen,pn,file, */ /* &vec_at(&pn->tokens,0,const Tok*)->str); */ fprintf(file,"\t%s\n",vec_at(&pn->tokens,0,const Tok*)->str.buffer); } } break; case PEXTERN: { if(pn->tokens.size<1) err_log("%u: expected identifier after keyword 'ext'",vec_at(&pn->tokens,0,const Tok*)->line); else { if(vec_at(&pn->tokens,0,const Tok*)->type!=LIDENTIFIER) err_log("%u: expected identifier after keyword 'ext'",vec_at(&pn->tokens,0,const Tok*)->line); if(pn->tokens.size>1&&vec_at(&pn->tokens,1,const Tok*)->subtype==LLPAREN) { for(size_t i=0;irootnode->funcs.size;++i) { if(strcmp(vec_at(&pn->tokens,0,const Tok*)->str.buffer,vec_at(&gen->rootnode->funcs,i,Func*)->name)==0) { err_log("%u: '%s' already declared",vec_at(&pn->tokens,0,const Tok*)->line,vec_at(&pn->tokens,0,const Tok*)->str.buffer); break; } } Func func={ .name=vec_at(&pn->tokens,0,const Tok*)->str.buffer, .no_args=0, }; vec_push((Vec*)&gen->rootnode->funcs,&func); } else gen_declare_variable(gen,pn,file); fprintf(file,".extern %s\n",vec_at(&pn->tokens,0,const Tok*)->str.buffer); } } break; case PCOMMENT: fprintf(file,"\t;%s\n",vec_at(&pn->tokens,0,const Tok*)->str.buffer); break; case PBLOCK: for(size_t i=0;ipnodes.size;++i) gen_code(gen,vec_at(&pn->pnodes,i,PNode*),file); break; case PEMPTY: // Root node, otherwise ignore if(pn->parentnode==NULL) { for(size_t i=0;ipnodes.size;++i) gen_code(gen,vec_at(&pn->pnodes,i,PNode*),file); } break; case PEXPRESSION: default: gen_eval(gen,pn,file); if(pn->tokens.size>0) { fprintf(file,";#PNODE ID: %s ",partype_names[pn->type]); for(size_t i=0;itokens.size;++i) { fprintf(file,"%s",vec_at(&pn->tokens,i,const Tok*)->str.buffer); } fprintf(file,"\n"); } break; } //for(size_t i=0;ipnodes.size;++i) //gen_code(gen,vec_at(&pn->pnodes,i,PNode*),file); } // Convert infix to RPN // Vec Vec gen_i2r(const Vec*tokens) { Vec stack=vec_new(sizeof(const Tok)); Vec operators=vec_new(sizeof(const Tok)); size_t parenlvl=0; int precedence[1024]={0}; precedence[LASSIGN]=3; precedence[LLPAREN]=5; precedence[LRPAREN]=5; precedence[LADD]=10; precedence[LSMINUS]=10; precedence[LSNOT]=10; precedence[LSREF]=10; precedence[LSMUL]=20; precedence[LSDIV]=20; precedence[LSDEREF]=25; precedence[LSCOMMA]=30; if(tokens->size>0) { for(size_t i=0;isize;++i) { /* printf("[[%s]]\n",vec_at(tokens,i,const Tok*)->str.buffer); */ // identifiers switch(vec_at(tokens,i,const Tok*)->type) { // integers, keywords (true/false), identifiers case LIDENTIFIER: case LKEYWORD: case LINTEGER: case LFLOAT: vec_push(&stack,vec_at(tokens,i,const Tok*)); break; // operators case LOPERATOR: { // '(' if(vec_at(tokens,i,const Tok*)->subtype==LLPAREN) { ++parenlvl; vec_push(&operators,vec_at(tokens,i,const Tok*)); } // ')' else if(vec_at(tokens,i,const Tok*)->subtype==LRPAREN) { while(operators.size>0&&vec_at(&operators,operators.size-1,const Tok*)->subtype!=LLPAREN) { const Tok*newtok=vec_at(&operators,operators.size-1,const Tok*); vec_push(&stack,newtok); vec_pop(&operators); } --parenlvl; vec_pop(&operators); } // ',' else if(vec_at(tokens,i,const Tok*)->subtype==LSCOMMA) { // TODO: Verify edge cases here. This is a rough test // that could use more rigorous definition while(operators.size>0&&vec_at(&operators,operators.size-1,const Tok*)->subtype!=LLPAREN) { const Tok*newtok=vec_at(&operators,operators.size-1,const Tok*); vec_push(&stack,newtok); vec_pop(&operators); } /* const Tok*newtok=vec_at(&operators,operators.size-1,const Tok*); */ /* vec_push(&stack,newtok); */ /* vec_pop(&operators); */ vec_push(&stack,vec_at(tokens,i,const Tok*)); } // Default operators else { // Pop operators from operators ==> stack // who have higher precedence than current // operator while(operators.size>0&&precedence[(uint32_t)vec_at(&operators,operators.size-1,const Tok*)->subtype]>=precedence[(uint32_t)vec_at(tokens,i,const Tok*)->subtype]) { const Tok*newtok=vec_at(&operators,operators.size-1,const Tok*); vec_push(&stack,newtok); vec_pop(&operators); } vec_push(&operators,vec_at(tokens,i,const Tok*)); } } break; /* default: */ /* err_log("unrecognized token type\n"); */ /* break; */ } } } while(operators.size>0) { const Tok*newtok=vec_at(&operators,operators.size-1,const Tok*); vec_push(&stack,newtok); vec_pop(&operators); } /* printf("s:"); */ /* vec_print_tokens(&stack); */ /* printf("o:"); */ /* vec_print_tokens(&operators); */ /* vec_free(&stack); */ vec_free(&operators); // move ownership to caller return stack; } // Convert to infix, then evaluate void gen_eval(Gen*gen,const PNode*pn,FILE*file) { Vec rpn_stack={0}; Vec stack=vec_new(sizeof(eval_elem)); eval_elem tmpelem={0}; size_t funarg_max=0; // How many function arguments are we looking for? size_t funarg_no=0; // Out of funarg_max, which arg are we finding now? // Find function invocations in pn->tokens // and count their number of arguments. This // will be used to pop the right number of // values from the stack. for(size_t i=0;itokens.size;++i) { for(size_t j=0;jrootnode->funcs.size;++j) { // Identified a function if(strcmp(vec_at(&pn->tokens,i,const Tok*)->str.buffer, vec_at(&gen->rootnode->funcs,j,const Func*)->name)==0) { Tok*functok=vec_at(&pn->tokens,i,Tok*); /* printf("func '%s': [",functok->str.buffer); */ functok->fn_no_args=0; size_t parenlvl=0; bool foundone=false; // Find function tokens, record number of // arguments passed to them for(size_t k=i+1;ktokens.size;++k) { Tok*curtok=vec_at(&pn->tokens,k,Tok*); switch(curtok->subtype) { case LLPAREN: ++parenlvl; break; case LRPAREN: { if(foundone) { ++functok->fn_no_args; foundone=false; } --parenlvl; if(parenlvl==0) k=pn->tokens.size; } break; case LSCOMMA: if(foundone) { ++functok->fn_no_args; foundone=false; } break; default: foundone=true; break; } /* printf("%s%s",curtok->str.buffer,ktokens.size-1?" ":""); */ } /* printf("%p '%s': %lu\n",functok->str.buffer,functok->str.buffer,functok->fn_no_args); */ } } } // Find LSMUL, analyze context, convert // to LSDEREF if used as unary op for(size_t i=0;itokens.size;++i) { if(vec_at(&pn->tokens,i,Tok*)->subtype==LSMUL) { Tok*prev=vec_at(&pn->tokens,i-1,Tok*); if(i==0||(prev->type==LOPERATOR&&prev->subtype!=LRPAREN&&prev->subtype!=LLPAREN)) vec_at(&pn->tokens,i,Tok*)->subtype=LSDEREF; } } rpn_stack=gen_i2r(&pn->tokens); if(gen->showrpn)vec_print_tokens(&rpn_stack); /* gen_eval_analyze(pn); */ // Evaluate RPN if(rpn_stack.buffer&&rpn_stack.size>0) { for(size_t i=0;itype) { case LKEYWORD: { if(strcmp("true",vec_at(&rpn_stack,i,const Tok*)->str.buffer)==0) { tmpelem=(eval_elem){.type=EE_I32,.val.i32=1}; vec_push(&stack,&tmpelem); } else if(strcmp("false",vec_at(&rpn_stack,i,const Tok*)->str.buffer)==0) { tmpelem=(eval_elem){.type=EE_I32,.val.i32=0}; vec_push(&stack,&tmpelem); } } break; case LIDENTIFIER: { // Convert identifiers into functions or vars // Otherwise it is an error tmpelem=(eval_elem){.type=EE_IDENT,.val.name=vec_at(&rpn_stack,i,const Tok*)->str.buffer}; if(!gen_findfunc(gen,&tmpelem)) if(!gen_findvar(gen,&tmpelem)) err_log("%u: undeclared identifier '%s'",vec_at(&pn->tokens,0,Tok*)->line,tmpelem.val.name); if(tmpelem.type==EE_FUNC) { funarg_max=vec_at(&rpn_stack,i,const Tok*)->fn_no_args; funarg_no=0; if(funarg_max==0) fprintf(file,"\tcall %s\n",tmpelem.val.name); } /* printf("[[%s:%lu]]\n",tmpelem.val.name,tmpelem.type); */ vec_push(&stack,&tmpelem); } break; case LINTEGER: case LFLOAT: { int32_t d=atoi(vec_at(&rpn_stack,i,const Tok*)->str.buffer); tmpelem=(eval_elem){.type=EE_I32,.val.i32=d}; vec_push(&stack,&tmpelem); } break; case LOPERATOR: // Get operands if(stack.size>0) { eval_elem elem[2]={{0}}; size_t nops=2; // 2 unless unary operator // Find operators with nops != 2 switch(vec_at(&rpn_stack,i,const Tok*)->subtype) { case LSNOT:case LSREF:case LSDEREF:nops=1;break; case LSCOMMA:nops=0;break; } // Get top two stack elements (variables, integers, etc.) for(size_t k=0;ktokens,0,Tok*)->line,elem[k].val.name); } gen_evalop(gen,(PNode*)pn,elem,nops,vec_at(&rpn_stack,i,Tok*),file,&stack); } break; default: err_log("unrecognized token type\n"); break; } } } // Empty remaining variables/integers on the stack eval_lastelem: if(stack.size>0) { eval_elem e=*(vec_at(&stack,stack.size-1,eval_elem*)); if(funarg_max>0&&funarg_no==funarg_max&&e.type==EE_FUNC) { fprintf(file,"\tcall %s\n",e.val.name); if(gen->buildarch==M_I386) fprintf(file,"\t%s $%lu,%%%s\n",gen->ld.sub_wordsize,funarg_max*gen->ld.wordsize,gen->ld.sp); } vec_pop(&stack); int32_t value=0; if(e.type==EE_I32) { value=e.val.i32; fprintf(file,"\t%s $%d,%%%s\n",gen->ld.mov_wordsize,value,gen->ld.acc_wordsize); } else if(e.type==EE_IDENT|| e.type==EE_FUNC|| e.type==EE_VAR) { // Find identifiers if(e.type==EE_IDENT) { // Convert identifiers into functions or vars // Otherwise it is an error if(!gen_findfunc(gen,&e)) if(!gen_findvar(gen,&e)) err_log("%u: undeclared identifier '%s'",vec_at(&pn->tokens,0,Tok*)->line,tmpelem.val.name); } switch(e.type) { // This call should be done after all arguments are popped off the stack case EE_FUNC: { /* fprintf(file,"\tcall %s\n",e.val.name); */ ///* { */ ///* tmpelem=(eval_elem){.type=EE_ACC,.val.i32=0}; */ ///* vec_push(&stack,&tmpelem); */ ///* } */ } break; // Still not categorized as func or var case EE_IDENT: err_log("%u: undeclared identifier '%s'",vec_at(&pn->tokens,0,Tok*)->line,e.val.name); break; case EE_VAR: fprintf(file,"\t%s %d(%%%s),%%%s\n",gen->ld.mov_wordsize,e.vstackloc,gen->ld.bp,gen->ld.acc_wordsize); break; default: err_log("unrecognized eval_elem type\n"); break; } } // Parse function arglist eval_elems left on stack if(funarg_max>0) { if(funarg_nobuildarch==M_X86_64) fprintf(file,"\t%s %%%s,%%%s\n",gen->ld.mov_wordsize,gen->ld.acc_wordsize,gen->ld.registers_abi_wordsize[funarg_max-funarg_no-1]); else if(gen->buildarch==M_I386) fprintf(file,"\tpushl %%%s\n",gen->ld.acc_wordsize); } /* else */ /* { */ /* if(e.type==EE_FUNC) */ /* err_log("expression contains arglist with no function"); */ /* } */ ++funarg_no; } // End arglist mode if(funarg_max>0&&funarg_no>funarg_max) funarg_max=0; if(funarg_max>0&&funarg_no<=funarg_max) goto eval_lastelem; } vec_free(&rpn_stack); vec_free(&stack); } // Evaluate one operation void gen_evalop(Gen*gen,PNode*pn,eval_elem*elem,size_t nops,Tok*curtok,FILE*file,Vec*stack) { bool push_elem=true; char operands[2][1024]; char operator[1024]; char output_buffer[4096]; eval_elem tmpelem={0}; size_t opos=0; uint32_t addrmode=0; uint32_t res=0; // TODO: refactor this function to be smarter, // removing special cases and pendantic-ness // Create strings of operands, operators // Construct operand strings { // Create operand eval_elems for(size_t i=0;ild.bp); break; case EE_FUNC: sprintf(operands[i],"%s",elem[i].val.name); break; case EE_IDENT: sprintf(operands[i],"%s",elem[i].val.name); break; case EE_I32: sprintf(operands[i],"$%d",elem[i].val.i32); break; case EE_ACC: sprintf(operands[i],"%%%s",gen->ld.acc_wordsize); break; //ERROR //default: sprintf(operands[i],"???"); break; } } /* if(nops>1&&elem[0].type==EE_I32&&elem[1].type==EE_I32) */ /* printf("[[[%d+%d=%d]]]\n",elem[1].val.i32,elem[0].val.i32,elem[1].val.i32+elem[0].val.i32); */ // Convert operator name to instruction name if(curtok->subtype==LADD) sprintf(operator,"%s",gen->ld.add_wordsize); else if(curtok->subtype==LSMINUS) sprintf(operator,"%s",gen->ld.sub_wordsize); else if(curtok->subtype==LSMUL) sprintf(operator,"%s",gen->ld.mul_wordsize); else if(curtok->subtype==LSDIV) sprintf(operator,"%s",gen->ld.div_wordsize); else if(curtok->subtype==LASSIGN) sprintf(operator,"%s",gen->ld.mov_wordsize); else if(curtok->subtype==LSREF) sprintf(operator,"%s",gen->ld.lea_wordsize); else if(curtok->subtype==LSDEREF) sprintf(operator,"%s",gen->ld.mov_wordsize); // Print output if(gen->showeval) { if(nops>1) printf("%s %s, %s\n",operator,operands[0],operands[1]); else printf("%s %s\n",operator,operands[0]); // Move result to accumulator if(elem[1].type!=EE_ACC) printf("%s %s, %s\n",gen->ld.mov_wordsize,operands[0],operands[1]); } } // Set up for multiply/divide instructions if(curtok->subtype==LSDIV||curtok->subtype==LSMUL) { /* if(!((elem[0].type==EE_I32)&&(elem[0].type==EE_I32))) */ { opos+=sprintf(output_buffer+opos,"\t%s %%%s,%%%s\n",gen->ld.xor_wordsize,gen->ld.registers_abi_wordsize[2],gen->ld.registers_abi_wordsize[2]); } } // Set up addressing mode addrmode=AM(elem[0].type,elem[1].type); /* printf("addrmode: %x (%x) (%x)\n",addrmode,elem[0].type,elem[1].type); */ // UNARY OPS if(nops==1) { switch(curtok->subtype) { case LSNOT: switch(elem[0].type) { case EE_VAR: opos+=sprintf(output_buffer+opos,"\t%s $0,%s\n",gen->ld.cmp_wordsize,operands[0]); break; case EE_I32: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[0],gen->ld.acc_wordsize); opos+=sprintf(output_buffer+opos,"\t%s $0,%%%s\n",gen->ld.cmp_wordsize,gen->ld.acc_wordsize); break; case EE_ACC: opos+=sprintf(output_buffer+opos,"\t%s $0,%%%s\n",gen->ld.cmp_wordsize,gen->ld.acc_wordsize); break; } opos+=sprintf(output_buffer+opos,"\tsete %%al\n"); opos+=sprintf(output_buffer+opos,"\tmovzbl %%al,%%%s\n",gen->ld.acc_wordsize); tmpelem=(eval_elem){.type=EE_ACC,.val={0}}; break; // Create reference from var case LSREF: switch(elem[0].type) { case EE_VAR: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",operator,operands[0],gen->ld.scratch1_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %%%s,%%%s\n",gen->ld.mov_wordsize,gen->ld.scratch1_wordsize,gen->ld.acc_wordsize); break; default: err_log("%u: cannot take reference of '%s'",vec_at(&pn->tokens,0,Tok*)->line,operands[0]); break; } tmpelem=(eval_elem){.type=EE_ACC,.val={0}}; break; // Dereference case LSDEREF: switch(elem[0].type) { default: /* FALL THROUGH */ case EE_VAR: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[0],gen->ld.scratch1_wordsize); opos+=sprintf(output_buffer+opos,"\t%s (%%%s),%%%s\n",operator,gen->ld.scratch1_wordsize,gen->ld.acc_wordsize); break; } tmpelem=(eval_elem){.type=EE_ACC,.val={0}}; break; } if(push_elem) vec_push(stack,&tmpelem); fwrite(output_buffer,1,opos,file); } // TWO OPERANDS ------------------------------- // (or more [funcs]) else if(nops>1) { switch(addrmode) { // INT INT case AM(EE_I32,EE_I32): { switch(curtok->subtype) { case LADD:res=elem[1].val.i32+elem[0].val.i32;break; case LSMINUS:res=elem[1].val.i32-elem[0].val.i32;break; case LSMUL:res=elem[1].val.i32*elem[0].val.i32;break; case LSDIV:res=elem[1].val.i32/elem[0].val.i32;break; } tmpelem=(eval_elem){.type=EE_I32,.val.i32=res}; } break; // INT ACC // ACC INT case AM(EE_I32,EE_ACC): case AM(EE_ACC,EE_I32): { tmpelem=(eval_elem){.type=EE_ACC,.val={0}}; if(elem[0].type==EE_I32) { eval_elem etmp=elem[0]; elem[0]=elem[1]; elem[1]=etmp; char btmp[64]={0}; strcpy(btmp,operands[0]); strcpy(operands[0],operands[1]); strcpy(operands[1],btmp); } switch(curtok->subtype) { case LASSIGN: err_log("%u: cannot assign to rvalue '%d'",vec_at(&pn->tokens,0,Tok*)->line,operands[1]); push_elem=false; break; case LADD: case LSMINUS: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",operator,operands[1],gen->ld.acc_wordsize); break; case LSMUL: case LSDIV: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[1],gen->ld.scratch1_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %%%s\n",operator,gen->ld.scratch1_wordsize); break; } } break; // INT VAR case AM(EE_VAR,EE_I32): { tmpelem=(eval_elem){.type=EE_ACC,.val={0}}; switch(curtok->subtype) { case LASSIGN: err_log("%u: cannot assign to rvalue '%s'",vec_at(&pn->tokens,0,Tok*)->line,operands[1]); push_elem=false; break; case LADD: case LSMINUS: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[1],gen->ld.acc_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",operator,operands[0],gen->ld.acc_wordsize); break; case LSMUL: case LSDIV: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[1],gen->ld.scratch1_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[0],gen->ld.acc_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %%%s\n",operator,gen->ld.scratch1_wordsize); break; } } break; // VAR INT case AM(EE_I32,EE_VAR): { tmpelem=(eval_elem){.type=EE_ACC,.val={0}}; switch(curtok->subtype) { case LASSIGN: opos+=sprintf(output_buffer+opos,"\t%s %s,%s\n",operator,operands[0],operands[1]); opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[0],gen->ld.acc_wordsize); break; case LADD: case LSMINUS: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[1],gen->ld.acc_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",operator,operands[0],gen->ld.acc_wordsize); break; case LSMUL: case LSDIV: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[0],gen->ld.scratch1_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[1],gen->ld.acc_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %%%s\n",operator,gen->ld.scratch1_wordsize); break; } } break; // VAR VAR case AM(EE_VAR,EE_VAR): { tmpelem=(eval_elem){.type=EE_ACC,.val={0}}; switch(curtok->subtype) { case LASSIGN: opos+=sprintf(output_buffer+opos,"\t%s %%%s,%s\n",operator,gen->ld.acc_wordsize,operands[1]); opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[0],gen->ld.acc_wordsize); break; case LADD: case LSMINUS: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[1],gen->ld.acc_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",operator,operands[0],gen->ld.acc_wordsize); break; case LSMUL: case LSDIV: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[1],gen->ld.acc_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %s\n",operator,operands[0]); break; } } break; // VAR ACC case AM(EE_VAR,EE_ACC): { tmpelem=(eval_elem){.type=EE_ACC,.val={0}}; switch(curtok->subtype) { case LASSIGN: case LADD: case LSMINUS: opos+=sprintf(output_buffer+opos,"\t%s %s,%s\n",operator,operands[0],operands[1]); break; case LSMUL: case LSDIV: opos+=sprintf(output_buffer+opos,"\t%s %s\n",operator,operands[0]); break; } } break; // ACC VAR case AM(EE_ACC,EE_VAR): { tmpelem=(eval_elem){.type=EE_ACC,.val={0}}; switch(curtok->subtype) { case LASSIGN: opos+=sprintf(output_buffer+opos,"\t%s %s,%s\n",operator,operands[0],operands[1]); break; case LADD: opos+=sprintf(output_buffer+opos,"\t%s %s,%s\n",operator,operands[1],operands[0]); break; case LSMINUS: opos+=sprintf(output_buffer+opos,"\t%s %s,%%%s\n",gen->ld.mov_wordsize,operands[0],gen->ld.scratch1_wordsize); opos+=sprintf(output_buffer+opos,"\t%s %s,%s\n",gen->ld.mov_wordsize,operands[1],operands[0]); opos+=sprintf(output_buffer+opos,"\t%s %%%s,%s\n",gen->ld.sub_wordsize,gen->ld.scratch1_wordsize,operands[0]); break; case LSMUL: case LSDIV: opos+=sprintf(output_buffer+opos,"\t%s %s\n",operator,operands[1]); break; } } break; } if(push_elem) vec_push(stack,&tmpelem); fwrite(output_buffer,1,opos,file); } }