#include "assemble.h" #include "eval.h" #include "parse.h" #include "resolve.h" #include "str.h" #include #include #include #include #include #include #include static inline int define_labels( IdentResolver* resolver, PLabel* label, uint16_t asm_ip, Reporter* rep) { if (label == NULL) return 0; int res = define_labels(resolver, label->next, asm_ip, rep); const IdentResol* existing = ident_resolver_resolve(resolver, label->ident); if (existing != NULL) { REPORTF_ERROR("redefinition of identifier '%s'", label->ident); reporter_print_loc(rep, label->loc); REPORTF_INFO("original definition of '%s'", label->ident); reporter_print_loc(rep, existing->loc); return 1; } if (label->sub_label) { ident_resolver_define_sublabel( resolver, asm_strdup(label->ident), label->loc, asm_ip); } else { ident_resolver_define_label( resolver, asm_strdup(label->ident), label->loc, asm_ip); } return res; } static inline void use_labels(IdentResolver* resolver, PLabel* label) { if (label == NULL) return; use_labels(resolver, label->next); const IdentResol* existing = ident_resolver_resolve(resolver, label->ident); if (existing->ty == IdentResolTy_Label) { resolver->current_parent = existing; } } typedef struct { const char* input_file; const char* output_file; } Args; static inline Args parse_args(int argc, char** argv); int main(int argc, char** argv) { int res = 0; Args args = parse_args(argc, argv); FILE* input_fp = fopen(args.input_file, "r"); if (!input_fp) { REPORTF_ERROR("could not open input file '%s': %s", args.input_file, strerror(errno)); return -1; } fseek(input_fp, 0L, SEEK_END); size_t file_size = (size_t)ftell(input_fp); rewind(input_fp); char* input_text = calloc(file_size + 1, sizeof(char)); size_t bytes_read = fread(input_text, sizeof(char), file_size, input_fp); fclose(input_fp); if (bytes_read != file_size) { REPORTF_ERROR("could not read input file '%s': %s", args.input_file, strerror(errno)); return -1; } bool errors_occured = false; Parser parser; parser_construct(&parser, args.input_file, input_text); Reporter rep = { .filename = parser.lexer.filename, .text = parser.lexer.text, .text_len = parser.lexer.text_len, }; size_t lines_capacity = 1024; PLine** lines = malloc(sizeof(PLine*) * lines_capacity); size_t lines_size = 0; while (!parser_done(&parser)) { if (lines_size + 1 > lines_capacity) { lines_capacity += 2; lines = realloc(lines, sizeof(PLine*) * lines_capacity); } PLine* line = parser_next(&parser); if (!line) { continue; } lines[lines_size++] = line; } errors_occured &= parser_error_occured(&parser); IdentResolver resolver; ident_resolver_construct(&resolver); OperandEvaluator evaluator = { .re = &resolver, .rep = &rep, .second_pass = false, }; size_t chunk_capacity = 64; uint16_t* chunk = malloc(sizeof(uint16_t) * chunk_capacity); uint16_t ip = 0; for (size_t i = 0; i < lines_size; ++i) { int res = define_labels(&resolver, lines[i]->labels, ip, &rep); if (res != 0) errors_occured = true; uint16_t size = pline_assemble(&evaluator, chunk, lines[i], &rep); if (size == 0) errors_occured = true; ip += size; } if (errors_occured) { fprintf(stderr, "nothing written. stopping...\n"); res = -1; goto leave_free_chunk; } evaluator.second_pass = true; FILE* output_fp = fopen(args.output_file, "wb"); if (!output_fp) { REPORTF_ERROR("could not open output file '%s': %s", args.output_file, strerror(errno)); res = -1; goto leave_free_chunk; } size_t total_bytes_written = 0; for (size_t i = 0; i < lines_size; ++i) { use_labels(&resolver, lines[i]->labels); size_t size = pline_assemble(&evaluator, chunk, lines[i], &rep); if (size == 0) { errors_occured = true; } if (errors_occured) continue; size_t bytes_written = fwrite(chunk, sizeof(uint16_t), size, output_fp); total_bytes_written += bytes_written; if (bytes_written != size) { REPORTF_ERROR("could not write to output file '%s': %s", args.output_file, strerror(errno)); errors_occured = true; } } fclose(output_fp); if (errors_occured) { fprintf( stderr, "%ld bytes written. stopping...\n", total_bytes_written); res = -1; goto leave_free_chunk; } res = 0; leave_free_chunk: free(chunk); // leave_free_lines: for (size_t i = 0; i < lines_size; ++i) { pline_free(lines[i]); } free(lines); free(input_text); ident_resolver_destroy(&resolver); return res; } static inline Args parse_args(int argc, char** argv) { const char* input_file = NULL; const char* output_file = NULL; for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "-o") == 0) { i += 1; if (i >= argc) { REPORTF_ERROR("%s", "no filename given to -o"); exit(1); } output_file = argv[i]; } else { if (input_file != NULL) { REPORTF_ERROR("%s", "multiple input files specified"); exit(1); } input_file = argv[i]; } } if (input_file == NULL) { REPORTF_ERROR("%s", "no input file"); exit(1); } if (output_file == NULL) { output_file = "out.o"; } return (Args) { input_file, output_file, }; }