lr/gen.c
2024-02-04 11:47:02 -06:00

1326 lines
33 KiB
C

#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;i<pn->pnodes.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;i<tokens->size;++i)
{
printf("%s",vec_at(tokens,i,const Tok*)->str.buffer);
if(i<tokens->size-1)
printf(", ");
}
printf("]\n");
}
void vec_print_eval_elems(Vec*stack)
{
if(!stack)return;
printf("%p stack: [",&stack);
for(size_t i=0;i<stack->size;++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(i<stack->size-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;i<gen->stackptr->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;i<gen->rootnode->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;i<pn->tokens.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;i<pn->pnodes.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;i<pn->pnodes.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;i<rpn_stack.size;++i)
{
switch(vec_at(&rpn_stack,i,const Tok*)->type)
{
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;i<pn->vars.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;i<pn->pnodes.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;j<gen->rootnode->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;j<gen->stackptr->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;i<pn->pnodes.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;i<pn->pnodes.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;i<gen->rootnode->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;i<pn->pnodes.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;i<pn->pnodes.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;i<pn->tokens.size;++i)
{
fprintf(file,"%s",vec_at(&pn->tokens,i,const Tok*)->str.buffer);
}
fprintf(file,"\n");
}
break;
}
//for(size_t i=0;i<pn->pnodes.size;++i)
//gen_code(gen,vec_at(&pn->pnodes,i,PNode*),file);
}
// Convert infix to RPN
// Vec<Tok>
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;i<tokens->size;++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;i<pn->tokens.size;++i)
{
for(size_t j=0;j<gen->rootnode->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;k<pn->tokens.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,k<pn->tokens.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;i<pn->tokens.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;i<rpn_stack.size;++i)
{
switch(vec_at(&rpn_stack,i,const Tok*)->type)
{
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;k<nops;++k)
{
elem[k]=*vec_at(&stack,stack.size-1,eval_elem*);
vec_pop(&stack);
if(elem[k].type==EE_FUNC)
{
fprintf(file,"\tcall %s\n",elem[k].val.name);
{
tmpelem=(eval_elem){.type=EE_ACC,.val.i32=0};
vec_push(&stack,&tmpelem);
--k;
}
}
// Still not categorized as func or var
else if(elem[k].type==EE_IDENT)
err_log("%u: undeclared identifier '%s'",vec_at(&pn->tokens,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_no<funarg_max)
{
if(gen->buildarch==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;i<nops;++i)
{
switch(elem[i].type)
{
case EE_VAR: sprintf(operands[i],"%d(%%%s)",elem[i].vstackloc,gen->ld.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);
}
}