diff --git a/src/assembler.c b/src/assembler.c index e16ab26..0cbd7e7 100644 --- a/src/assembler.c +++ b/src/assembler.c @@ -23,7 +23,6 @@ struct ASMLine { const Line *original; const char *filename; struct ASMLine *next; - struct ASMLine *include; }; typedef struct ASMLine ASMLine; @@ -198,7 +197,7 @@ static bool write_binary_file(const char *path, const uint8_t *data, size_t size void error_info_print(const ErrorInfo *error_info, FILE *file) { // TODO - fprintf(file, "Error: Unknown error"); + fprintf(file, "Error: Unknown error\n"); } /* @@ -241,7 +240,6 @@ static void free_asm_lines(ASMLine *line) while (line) { ASMLine *temp = line->next; free(line->data); - free_asm_lines(line->include); free(line); line = temp; } @@ -295,6 +293,75 @@ static void free_asm_symtable(ASMSymbolTable *symtable) } /* + Preprocess a single source line (source, length) into a normalized ASMLine. + + *Only* the data and length fields in the ASMLine object are populated. The + normalization process converts tabs to spaces, removes runs of multiple + spaces (outside of string literals), strips comments, and other things. + + Return NULL if an ASM line was not generated from the source, i.e. if it is + blank after being stripped. +*/ +static ASMLine* normalize_line(const char *source, size_t length) +{ + char *data = malloc(sizeof(char) * length); + if (!data) + OUT_OF_MEMORY() + + size_t si, di, slashes = 0; + bool has_content = false, space_pending = false, in_string = false; + for (si = di = 0; si < length; si++) { + char c = source[si]; + + if (c == '\\') + slashes++; + else + slashes = 0; + + if (in_string) { + if (c == '"' && (slashes % 2) == 0) + in_string = false; + + data[di++] = c; + } else { + if (c == ';') + break; + if (c == '"' && (slashes % 2) == 0) + in_string = true; + + if (c == '\t' || c == ' ') + space_pending = true; + else { + if (space_pending) { + if (has_content) + data[di++] = ' '; + space_pending = false; + } + has_content = true; + data[di++] = c; + } + } + } + + if (!has_content) { + free(data); + return NULL; + } + + ASMLine *line = malloc(sizeof(ASMLine)); + if (!line) + OUT_OF_MEMORY() + + data = realloc(data, sizeof(char) * di); + if (!data) + OUT_OF_MEMORY() + + line->data = data; + line->length = di; + return line; +} + +/* Preprocess the LineBuffer into ASMLines. Change some state along the way. This function processes include directives, so read_source_file() may be @@ -322,6 +389,34 @@ static ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) // if giving reported and actual rom size, check reported is <= actual // ensure no duplicate explicit assignments + ASMLine dummy = {.next = NULL}; + ASMLine *line, *prev = &dummy; + const Line *orig = source->lines; + + while (orig) { + if ((line = normalize_line(orig->data, orig->length))) { + line->original = orig; + line->filename = source->filename; + line->next = NULL; + + prev->next = line; + prev = line; + } + orig = orig->next; + } + + state->lines = dummy.next; + +#ifdef DEBUG_MODE + DEBUG("Dumping ASMLines:") + const ASMLine *temp = state->lines; + while (temp) { + DEBUG("- %-40.*s [%s:%02zu]", (int) temp->length, temp->data, + temp->filename, temp->original->lineno) + temp = temp->next; + } +#endif + return NULL; }