void stmt_codegen(struct stmt *s, FILE *f) { if(!s) return; switch(s -> kind) { case STMT_DECL: decl_codegen(s -> decl, f, SYMBOL_LOCAL); break; case STMT_EXPR: expr_codegen(s -> expr, f); register_free(s -> expr -> reg); break; case STMT_IF_ELSE: { int done = assembly_jump_label++; expr_codegen(s -> expr, f); fprintf(f, "\tCMP $0, %s\n", register_name(s -> expr -> reg)); register_free(s -> expr -> reg); if(s -> else_body) { int el = assembly_jump_label++; // jump to else fprintf(f, "\tJE L%d\n", el); stmt_codegen(s -> body, f); assembly_comment(f, "\t# jump to done label (don't evaluate else label)\n"); fprintf(f, "JMP L%d\n", done); assembly_comment(f, "\t# else label\n"); fprintf(f, "L%d:\n", el); stmt_codegen(s -> else_body, f); assembly_comment(f, "\t# done label\n"); fprintf(f, "L%d:\n", done); } else { // jump to done fprintf(f, "\tJE L%d\n", done); stmt_codegen(s -> body, f); assembly_comment(f, "\t# done label\n"); fprintf(f, "L%d:\n", done); } break; } case STMT_FOR: { // check for nulls since all exprs optional int loop = assembly_jump_label++; int done = assembly_jump_label++; if(s -> init_expr) { expr_codegen(s -> init_expr, f); register_free(s -> init_expr -> reg); } // loop label assembly_comment(f, "\t# loop label\n"); fprintf(f, "L%d:\n", loop); if(s -> expr) { expr_codegen(s -> expr, f); // don't need the return value fprintf(f, "\tCMP $0, %s\n", register_name(s -> expr -> reg)); register_free(s -> expr -> reg); assembly_comment(f, "\t# jump to done label (break condition)\n"); fprintf(f, "\tJE L%d\n", done); } stmt_codegen(s -> body, f); if(s -> next_expr) { expr_codegen(s -> next_expr, f); register_free(s -> next_expr -> reg); } assembly_comment(f, "\t# unconditional jump to next loop\n"); fprintf(f, "JMP L%d\n", loop); assembly_comment(f, "\t# done label\n"); fprintf(f, "L%d:\n", done); break; } case STMT_WHILE: fprintf(stderr, "CODEGEN_ERROR: cminor does not support while loops\n"); exit(1); break; case STMT_PRINT: { struct expr *curr = s -> expr; while(curr) { expr_codegen(curr, f); int count = 0; if(ASSEMBLY_COMMENT_FLAG) { fprintf(f, "\t# move arg %d (in %s) into %s\n", count, register_name(curr -> reg), register_arg_names[count]); } fprintf(f, "\tMOVQ %s, %s\n", register_name(curr -> reg), register_arg_names[count++]); register_free(curr -> reg); // calls func_codegen which save ret val in reg // so need to free reg beforehand stmt_call_print(curr, f); curr = curr -> next; } break; } case STMT_RET: expr_codegen(s -> expr, f); if(ASSEMBLY_COMMENT_FLAG) { fprintf(f, "\n\t# return statement (return "); expr_fprint(f, s -> expr); fprintf(f, ")\n"); } if(s -> expr) { fprintf(f, "\tMOVQ %s, %%rax\n", register_name(s -> expr -> reg)); register_free(s -> expr -> reg); } // postamble assembly_comment(f, "\t### function postamble\n"); assembly_comment(f, "\t# restore callee-saved registers\n"); fprintf(f, "\tPOPQ %%r15\n"); fprintf(f, "\tPOPQ %%r14\n"); fprintf(f, "\tPOPQ %%r13\n"); fprintf(f, "\tPOPQ %%r12\n"); fprintf(f, "\tPOPQ %%rbx\n"); assembly_comment(f, "\t# reset stack to base pointer\n"); fprintf(f, "\tMOVQ %%rbp, %%rsp\n"); assembly_comment(f, "\t# restore the old base pointer\n"); fprintf(f, "\tPOPQ %%rbp\n"); fprintf(f, "\tRET\n"); break; case STMT_BLOCK: stmt_codegen(s -> body, f); break; } stmt_codegen(s -> next, f); }
void decl_codegen(struct decl *d, FILE * file){ if(!d)return; if(d->symbol->kind == SYMBOL_GLOBAL){ if(!d->code && !d->value && d->type->kind != TYPE_FUNCTION){ if(d->type->kind != TYPE_STRING)fprintf(file,".data\n%s: .quad 0\n",d->name); else{ //printf("teste"); fprintf(file,".data\n.global %s\n%s:\n .string \"\" \n",d->name,d->name); } } else{ if(d->value && d->type->kind != TYPE_FUNCTION){ if(d->type->kind == TYPE_STRING && d->type->kind != TYPE_FUNCTION){ fprintf(file,".data\n.global %s\n%s:\n .string ""%s""\n",d->name,d->name,d->value->string_literal);//nao esquecer de tratar quebras de linha } else if(d->type->kind != TYPE_FUNCTION) fprintf(file,".data\n.global %s\n%s:\n .quad %d\n",d->name,d->name,d->value->literal_value);//pode ter expressoes do tipo 10+1 na declaracao? }else{ if(d->code){ fprintf(file,".text\n.global %s\n%s:\n",d->name,d->name); struct param_list *p = d->type->params; fprintf(file," pushq %%rbp\n movq %%rsp, %%rbp\n"); int parameters_cont = 0; while(p){ p = p->next; parameters_cont++; } if(parameters_cont >= 1){ fprintf(file," pushq %%rdi\n"); } if(parameters_cont >= 2){ fprintf(file," pushq %%rsi\n"); } if(parameters_cont >= 3){ fprintf(file," pushq %%rdx\n"); } if(parameters_cont >= 4){ fprintf(file," pushq %%rcx\n"); } if(parameters_cont >= 5){ fprintf(file," pushq %%r8\n"); } if(parameters_cont == 6){ fprintf(file," pushq %%r9\n"); } if(d->symbol->total_locals > 0){ fprintf(file," subq $%d,%%rsp\n",d->symbol->total_locals*8); } fprintf(file," pushq %%rbx\n"); fprintf(file," pushq %%r12\n"); fprintf(file," pushq %%r13\n"); fprintf(file," pushq %%r14\n"); fprintf(file," pushq %%r15\n\n"); stmt_codegen(d->code,file); fprintf(file,"FUNCAO%d:\n",funcoes); fprintf(file,"\n"); fprintf(file," popq %%r15\n"); fprintf(file," popq %%r14\n"); fprintf(file," popq %%r13\n"); fprintf(file," popq %%r12\n"); fprintf(file," popq %%rbx\n"); fprintf(file," movq %%rbp,%%rsp\n"); fprintf(file," popq %%rbp\n"); fprintf(file," ret\n"); funcoes++; //postamble como tratar } } } } else if(d->symbol->kind == SYMBOL_LOCAL){ if(d->value){ expr_codegen(d->value,file); fprintf(file," movq %s,-%d(%%rbp)\n",register_name(d->value->reg),d->symbol->param_local_variables*8);//arrumar isso, voce usou valor aleatorio, register_free(d->value->reg); //dont forget to free registers //voltar no video do dia 20, minuto 35 para tratar o caso das strings } } decl_codegen(d->next,file); }
void stmt_codegen(struct stmt *s, FILE * output) { struct expr * e_cursor; int label_save; if (!s) return; switch (s->kind) { case STMT_DECL: decl_codegen(s->decl, output); break; case STMT_EXPR: expr_codegen(s->expr, output); register_free(s->expr->reg); break; case STMT_IF_ELSE: fprintf(output, "\n\t## if statement ##\n"); label_save = label_count; label_count+=2; expr_codegen(s->expr, output); fprintf(output, "\tCMP $0, %s\n", register_name(s->expr->reg)); register_free(s->expr->reg); fprintf(output, "\tJE .L%d\n", label_save); stmt_codegen(s->body, output); fprintf(output, "\tJMP .L%d\n", label_save+1); fprintf(output, "\t.L%d:\n", label_save); stmt_codegen(s->else_body, output); fprintf(output, "\t.L%d:\n", label_save+1); fprintf(output, "\n\t## end of if statement ##\n"); break; case STMT_FOR: label_save = label_count; label_count+=2; fprintf(output, "\n\t## for loop ##\n"); expr_codegen(s->init_expr, output); if(s->init_expr) { // for infinite for loops register_free(s->init_expr->reg); } fprintf(output, "\t.L%d:\n", label_save); expr_codegen(s->expr, output); if (s->expr) { // for infinite for loops register_free(s->expr->reg); fprintf(output, "\tCMP $0, %s\n", register_name(s->expr->reg)); fprintf(output, "\tJE .L%d\n", label_save+1); } stmt_codegen(s->body, output); expr_codegen(s->next_expr, output); if (s->next_expr) { register_free(s->next_expr->reg); } fprintf(output, "\tJMP .L%d\n", label_save); fprintf(output, "\t.L%d:\n", label_save+1); fprintf(output, "\t## end of for loop ##\n"); break; case STMT_PRINT: if(s->expr) { if(s->expr->kind == EXPR_LIST) { // multiple things to print e_cursor = s->expr; // traverse the expr_list while(e_cursor) { expr_print_codegen(e_cursor->left, output); e_cursor = e_cursor->right; } } else { // single thing to print expr_print_codegen(s->expr, output); } } break; case STMT_RETURN: fprintf(output, "\n\t## return statement ##\n"); if (s->expr) { expr_codegen(s->expr, output); fprintf(output, "\tMOV %s, %%rax\n", register_name(s->expr->reg)); register_free(s->expr->reg); fprintf(output, "\tJMP .ret%d\n", ret_count); // return to caller } else { fprintf(output, "\tJMP .ret%d\n", ret_count); } fprintf(output, "\t## end return statement ##\n\n"); break; case STMT_BLOCK: stmt_codegen(s->body, output); break; case STMT_EMPTY: break; } stmt_codegen(s->next, output); }