/* cg.c */ #include #include #include "cg.h" typedef struct SL { char *str; int num; struct SL *next; } stringlist; int seen_main=0; int this_is_main=0; int static_total_size=0; int local_total_size=0; int next_label=1; int num_strings=0; stringlist *all_strings=NULL; FILE *cf=NULL, *code_file=NULL; void init_code_generator(void) { seen_main=0; this_is_main=0; static_total_size=0; local_total_size=0; next_label=1; cf=code_file; fprintf(cf,"RESULT:\tBYTES 4\n"); } char *translate_variable(SymbolDescription *var) { static char res[100]; DeclarationRecord *dr=var->decls; struct Sgeneric *type; if (dr==NULL) { sprintf(res,"Undeclared:%s",var->name); return (res); } type=dr->type; if (type->tag==TTfunction) { sprintf(res,"@%s",var->name); return (res); } if (type->tag==TTarrayof) { if (dr->level==1) sprintf(res,"@FP+%d /* %s */",dr->place,var->name); else sprintf(res,"@%s",var->name); return (res); } if (dr->level==1) { sprintf(res,"FP+%d /* %s */",dr->place,var->name); return (res); } return (var->name); } int next_free_label(void) { next_label+=1; return (next_label-1); } void translate_global(struct Sfixeddecl *gd) { DeclarationRecord *dr=gd->var->decls; dr->level=0; dr->place=static_total_size; static_total_size+=sizeoftype(gd->type); fprintf(cf,"%s:\tBYTES %d\n", gd->var->name, sizeoftype(gd->type)); } void local_alloc(SymbolDescription *var, Atype *type) { DeclarationRecord *dr=malloc(sizeof(DeclarationRecord)); dr->type=type; dr->level=1; dr->place=local_total_size; local_total_size+=sizeoftype(type); dr->previous=var->decls; var->decls=dr; fprintf(cf," /* %s is at FP+%d */\n",var->name,dr->place); } void local_dealloc(SymbolDescription *var) { DeclarationRecord *dr=var->decls; var->decls=dr->previous; local_total_size-=sizeoftype(dr->type); free(dr); } void translate_operator(SymbolKind op) { switch (op) { case OPplus: fprintf(cf," ADD\n"); break; case OPFplus: fprintf(cf," ADDF\n"); break; case OPminus: fprintf(cf," SUB\n"); break; case OPFminus: fprintf(cf," SUBF\n"); break; case OPstar: fprintf(cf," MUL\n"); break; case OPFstar: fprintf(cf," MULF\n"); break; case OPdivide: fprintf(cf," DIV\n"); break; case OPFdivide: fprintf(cf," DIVF\n"); break; case OPmod: fprintf(cf," MOD\n"); break; case OPand: fprintf(cf," AND\n"); break; case OPor: fprintf(cf," OR\n"); break; case OPless: fprintf(cf," LSS\n"); break; case OPlessequal: fprintf(cf," LEQ\n"); break; case OPgreater: fprintf(cf," GTR\n"); break; case OPgreaterequal: fprintf(cf," GEQ\n"); break; case OPequalequal: fprintf(cf," EQL\n"); break; case OPnotequal: fprintf(cf," NEQ\n"); break; case OPFless: fprintf(cf," LSSF\n"); break; case OPFlessequal: fprintf(cf," LEQF\n"); break; case OPFgreater: fprintf(cf," GTRF\n"); break; case OPFgreaterequal: fprintf(cf," GEQF\n"); break; case OPFequalequal: fprintf(cf," EQLF\n"); break; case OPFnotequal: fprintf(cf," NEQF\n"); break; case OPplusequal: fprintf(cf," ADD\n"); break; case OPFplusequal: fprintf(cf," ADDF\n"); break; case OPminusequal: fprintf(cf," SUB\n"); break; case OPFminusequal: fprintf(cf," SUBF\n"); break; case OPstarequal: fprintf(cf," MUL\n"); break; case OPFstarequal: fprintf(cf," MULF\n"); break; case OPdivideequal: fprintf(cf," DIV\n"); break; case OPFdivideequal: fprintf(cf," DIVF\n"); break; case OPmodequal: fprintf(cf," MOD\n"); break; default: printf("can't translate operator"); return; } } void translate(Syntax *t); void translate_lvalue(Syntax *t) { struct Sgeneric *s=t; switch (s->tag) { case TTidentifier: { struct Sidentifier *i=t; fprintf(cf," LOAD @%s\n",translate_variable(i->symbol)); local_total_size+=4; return; } case TTarrayaccess: { struct Sarrayaccess *s=t; translate(s->array); translate(s->index); fprintf(cf," ADD\n"); local_total_size-=4; return; } } printf("Can't translate lvalue\n"); print_tagged_tree(stdout,t); } void translate(Syntax *t) { struct Sgeneric *s=t; switch (s->tag) { case TTblock: { struct Sblock *body=t; struct Sstatementlist *locals=body->declarations; struct Sstatementlist *statements=body->statements; int init_stack_depth=local_total_size; int new_local_size; while (locals!=NULL) { struct Sfixeddecl *d=locals->first; local_alloc(d->var, d->type); locals=locals->rest; } new_local_size=local_total_size-init_stack_depth; if (new_local_size>0) fprintf(cf," INCSP %d\n",new_local_size); while (statements!=NULL) { translate(statements->first); statements=statements->rest; } locals=body->declarations; if (new_local_size>0) fprintf(cf," DECSP %d\n",new_local_size); while (locals!=NULL) { struct Sfixeddecl *d=locals->first; local_dealloc(d->var); locals=locals->rest; } return; } case TTidentifier: { struct Sidentifier *s=t; fprintf(cf," LOAD %s\n",translate_variable(s->symbol)); local_total_size+=4; return; } case TTinteger: { struct Sinteger *s=t; fprintf(cf," LOADN %d\n",s->value); local_total_size+=4; return; } case TTfloat: { struct Sfloat *s=t; fprintf(cf," LOADF %f\n",s->value); local_total_size+=4; return; } case TTstring: { struct Sstring *s=t; stringlist *slink; num_strings+=1; slink=malloc(sizeof(stringlist)); slink->str=s->thestring; slink->num=num_strings; slink->next=all_strings; all_strings=slink; fprintf(cf," LOAD @STR%d\n",num_strings); local_total_size+=4; return; } case TTexprstatement: { struct Sexprstatement *s=t; fprintf(cf," /* Line %d */\n", s->linenum); translate(s->expression); fprintf(cf," POP\n"); local_total_size-=4; return; } case TTreturnstatement: { struct Sreturnstatement *s=t; fprintf(cf," /* Line %d */\n", s->linenum); if (this_is_main) { fprintf(cf," STOP\n"); return; } if (s->value!=NULL) { translate(s->value); fprintf(cf," STOR RESULT\n"); local_total_size-=4; } fprintf(cf," DECSP %d\n",local_total_size); fprintf(cf," POPJMP\n"); return; } case TTifstatement: { struct Sifstatement *s=t; int lab1, lab2; lab1=next_free_label(); fprintf(cf," /* Line %d */\n", s->linenum); translate(s->condition); fprintf(cf," PJZ L%d\n",lab1); local_total_size-=4; translate(s->iftrue); if (s->iffalse==NULL) fprintf(cf,"L%d:\n",lab1); else { lab2=next_free_label(); fprintf(cf," JUMP L%d\n",lab2); fprintf(cf,"L%d:\n",lab1); translate(s->iffalse); fprintf(cf,"L%d:\n",lab2); } return; } case TTwhilestatement: { struct Swhilestatement *s=t; int lab1,lab2; lab1=next_free_label(); lab2=next_free_label(); fprintf(cf," /* Line %d */\n", s->linenum); fprintf(cf,"L%d:\n",lab1); translate(s->condition); fprintf(cf," PJZ L%d\n",lab2); local_total_size-=4; translate(s->body); fprintf(cf," JUMP L%d\n",lab1); fprintf(cf,"L%d:\n",lab2); return; } case TTfunctioncall: { struct Sfunctioncall *s=t; struct Sexpressionlist *args=s->arguments; int return_addr=next_free_label(); int orig_stack_depth; fprintf(cf," LDFP\n"); local_total_size+=4; orig_stack_depth=local_total_size; fprintf(cf," LOAD @L%d\n",return_addr); local_total_size+=4; while (args!=NULL) { translate(args->first); args=args->rest; } translate(s->function); fprintf(cf," INCFP %d\n",orig_stack_depth); fprintf(cf," POPJMP\n"); fprintf(cf,"L%d:\n",return_addr); fprintf(cf," POPFP\n"); fprintf(cf," LOAD RESULT\n"); local_total_size=orig_stack_depth; return; } case TTarrayaccess: { struct Sarrayaccess *s=t; translate(s->array); translate(s->index); fprintf(cf," ADD\n"); local_total_size-=4; fprintf(cf," LDI\n"); return; } case TTcoerce: { struct Scoerce *s=t; Atype *fromtype=s->fromtype; Atype *totype=s->totype; translate(s->operand); if ((fromtype==t_char || fromtype==t_int) && totype==t_float) fprintf(cf," FLOAT\n"); else if (fromtype==t_float && (totype==t_char || totype==t_int)) fprintf(cf," FIX\n"); return; } case TTbinaryexpr: { struct Sbinaryexpr *s=t; SymbolKind op=s->operator; if (op==OPequal) { struct Sgeneric *l=s->left; if (l->tag==TTidentifier) { struct Sidentifier *i=s->left; translate(s->right); fprintf(cf," STOR %s\n",translate_variable(i->symbol)); return; } translate_lvalue(s->left); translate(s->right); fprintf(cf," STI\n"); local_total_size-=4; return; } if (op==OPplusequal || op==OPminusequal || op==OPstarequal || op==OPdivideequal || op==OPmodequal || op==OPFplusequal || op==OPFminusequal || op==OPFstarequal || op==OPFdivideequal) { struct Sgeneric *l=s->left; if (l->tag==TTidentifier) { struct Sidentifier *i=s->left; fprintf(cf," LOAD %s\n",translate_variable(i->symbol)); local_total_size+=4; translate(s->right); translate_operator(op); local_total_size-=4; fprintf(cf," STOR %s\n",translate_variable(i->symbol)); return; } translate_lvalue(s->left); fprintf(cf," DUP\n"); local_total_size+=4; fprintf(cf," LDI\n"); translate(s->right); translate_operator(op); local_total_size-=4; fprintf(cf," STI\n"); local_total_size-=4; return; } translate(s->left); translate(s->right); translate_operator(op); local_total_size-=4; return; } case TTunaryexpr: { struct Sunaryexpr *s=t; SymbolKind op=s->operator; if (op==OPstar) { translate(s->operand); fprintf(cf," LDI\n"); return; } if (op==OPaddress) { translate_lvalue(s->operand); return; } if (op==OPplus || op==OPFplus) { translate(s->operand); return; } if (op==OPminus) { fprintf(cf," LOADN 0\n"); local_total_size+=4; translate(s->operand); fprintf(cf," SUB\n"); local_total_size-=4; return; } if (op==OPFminus) { fprintf(cf," LOADF 0.0\n"); local_total_size+=4; translate(s->operand); fprintf(cf," SUBF\n"); local_total_size-=4; return; } if (op==OPnot) { translate_operator(op); fprintf(cf," NOT\n"); return; } return; } default: printf("\ncan't translate:\n"); print_tagged_tree(stdout,t); } } void translate_function(struct Sfixedfuncdef *fd) { struct Sblock *body=fd->body; struct Tfunction *fntype=fd->type; struct Sdeclareparamlist *paramlist=fntype->params; local_total_size=4; fprintf(cf,"\n%s:\n",fd->name->name); if (strcmp(fd->name->name,"MAIN")==0) { seen_main=1; this_is_main=1; fprintf(cf," INIT\n"); fprintf(cf," LOADN 0\n"); } else this_is_main=0; while (paramlist!=NULL) { struct Sfixedparam *p=paramlist->first; local_alloc(p->var, p->type); paramlist=paramlist->rest; } translate(body); if (this_is_main) fprintf(cf," STOP\n"); else { fprintf(cf," DECSP %d\n",local_total_size); fprintf(cf," POPJMP\n"); } paramlist=fntype->params; while (paramlist!=NULL) { struct Sfixedparam *p=paramlist->first; local_dealloc(p->var); paramlist=paramlist->rest; } } void translate_string(int n, char *s) { fprintf(cf,"STR%d:\n",n); while (1) { fprintf(cf," BYTE %d\n",*s); if (*s==0) break; s+=1; } } void translate_declarations(struct Sstatementlist *sl) { if (sl->tag!=TTstatementlist) return; all_strings=NULL; while (sl!=NULL) { Syntax *t=sl->first; struct Sgeneric *s=t; if (s->tag==TTfixedfuncdef) translate_function(t); else if (s->tag==TTfixeddecl) translate_global(t); sl=sl->rest; } while (all_strings!=NULL) { translate_string(all_strings->num, all_strings->str); all_strings=all_strings->next; } }