#include #include #include #include #include "project.h" static unsigned addr = 0; /* Used for tracking label addresses */ static int pass = 0; /* Pass 1: build map; pass 2: build image */ static FILE* image_file; /* Memory image */ static FILE* map_file; /* Labels */ /* This turns assembly into machine code. */ void asm_assemble(char* source, char* image, char* map) { int ret_val; yyin = fopen(source, "r"); if (yyin == NULL) {perror("fopen"); exit(EXIT_FAILURE);} /* Pass one: generate map */ map_file = fopen(map, "wb"); if (map_file == NULL) {perror("fopen"); exit(EXIT_FAILURE);} pass = 1; scanner_init(); ret_val = yyparse(); if (fclose(map_file) != 0) {perror("fclose"); exit(EXIT_FAILURE);} if (ret_val == 1 || yynerrs != 0) { if (unlink(map) == -1) perror("unlink"); exit(EXIT_FAILURE); } /* Pass two: generate memory image */ image_file = fopen(image, "wb"); if (image_file == NULL) {perror("fopen"); exit(EXIT_FAILURE);} if (fseek(yyin, 0, SEEK_SET) != 0) {perror("fseek");exit(EXIT_FAILURE);} pass = 2; scanner_init(); ret_val = yyparse(); if (fclose(image_file) != 0) {perror("fclose"); exit(EXIT_FAILURE);} if (ret_val == 1 || yynerrs != 0) { if (unlink(image) == -1) perror("unlink"); exit(EXIT_FAILURE); } /* Done reading */ if (fclose(yyin) != 0) {perror("fclose"); exit(EXIT_FAILURE);} /* That's all, folks! At least, until it's time to run the virtual * machine on this sucker... */ exit(EXIT_SUCCESS); } /* Label declaration. */ void asm_label_decl(char* name) { char* ret; if (pass != 1) return; ret = label_add(name, addr); if (ret != NULL) {yyerror(ret); yynerrs++;} fprintf(map_file, "%-20s %04x\n", name, addr); } /* Terminal expression. */ void asm_expr(unsigned val) { if (pass == 1) addr++; else { char buf[4] = {val >> 24, val >> 16, val >> 8, val}; if (fwrite(buf, 4, 1, image_file) != 1) { perror("fwrite"); exit(EXIT_FAILURE); } } } /* Register use. */ unsigned asm_reg(char* name) { reg_t* reg; if (pass == 1) return 0; reg = reg_by_name(name); if (reg == NULL) { yyerror("invalid register"); yynerrs++; return 0; } return reg->code; } /* Instruction use. */ unsigned asm_insn(char* name, unsigned arg1, unsigned arg2, unsigned arg3) { insn_t* insn; if (pass == 1) return 0; insn = insn_by_name(name); if (insn == NULL) { yyerror("invalid instruction"); yynerrs++; return 0; } return insn_encode(insn, arg1, arg2, arg3); } /* Label use. */ unsigned asm_label(char* name) { label_t* label; if (pass == 1) return 0; label = label_by_name(name); if (label == NULL) { yyerror("undefined label"); yynerrs++; return 0; } return label->addr; } /* EOF */