| @@ -14,8 +14,6 @@ | |||
| #include "rom.h" | |||
| #include "util.h" | |||
| #define IS_LABEL(line) (line->data[line->length - 1] == ':') | |||
| /* Sentinel values for overlap table */ | |||
| const ASMLine header_sentinel, bounds_sentinel; | |||
| @@ -34,7 +32,7 @@ static ErrorInfo* add_label_to_table( | |||
| const ASMSymbol *current = asm_symtable_find(symtable, symbol); | |||
| if (current) { | |||
| ErrorInfo *ei = error_info_create(line, ET_LAYOUT, ED_LYT_DUPE_LABELS); | |||
| ErrorInfo *ei = error_info_create(line, ET_SYMBOL, ED_SYM_DUPE_LABELS); | |||
| error_info_append(ei, current->line); | |||
| return ei; | |||
| } | |||
| @@ -43,7 +41,8 @@ static ErrorInfo* add_label_to_table( | |||
| if (!label) | |||
| OUT_OF_MEMORY() | |||
| label->offset = offset; | |||
| // TODO: don't assume all ROM gets mapped to slot 2 | |||
| label->offset = (offset >= 0xC000) ? ((offset & 0x3FFF) + 0x8000) : offset; | |||
| label->symbol = symbol; | |||
| label->line = line; | |||
| asm_symtable_insert(symtable, label); | |||
| @@ -144,7 +143,7 @@ static ErrorInfo* tokenize(AssemblerState *state) | |||
| overlap_table[state->header.offset + i] = &header_sentinel; | |||
| while (line) { | |||
| if (IS_LABEL(line)) { | |||
| if (line->is_label) { | |||
| if ((ei = add_label_to_table(state->symtable, line, offset))) | |||
| goto cleanup; | |||
| } | |||
| @@ -261,9 +260,31 @@ static ErrorInfo* resolve_defaults(AssemblerState *state) | |||
| */ | |||
| static ErrorInfo* resolve_symbols(AssemblerState *state) | |||
| { | |||
| // TODO | |||
| ErrorInfo *ei; | |||
| ASMInstruction *inst = state->instructions; | |||
| const ASMSymbol *symbol; | |||
| while (inst) { | |||
| if (inst->symbol) { | |||
| symbol = asm_symtable_find(state->symtable, inst->symbol); | |||
| if (!symbol) { | |||
| ei = error_info_create(inst->line, ET_SYMBOL, ED_SYM_NO_LABEL); | |||
| return ei; | |||
| } | |||
| (void) state; | |||
| if (inst->loc.length == 3) { | |||
| inst->b2 = symbol->offset & 0xFF; | |||
| inst->b3 = symbol->offset >> 8; | |||
| } else { | |||
| inst->b3 = symbol->offset & 0xFF; | |||
| inst->b4 = symbol->offset >> 8; | |||
| } | |||
| free(inst->symbol); | |||
| inst->symbol = NULL; | |||
| } | |||
| inst = inst->next; | |||
| } | |||
| return NULL; | |||
| } | |||
| @@ -17,6 +17,7 @@ static const char *asm_error_types[] = { | |||
| "include directive", // ET_INCLUDE | |||
| "preprocessor", // ET_PREPROC | |||
| "memory layout", // ET_LAYOUT | |||
| "symbol table", // ET_SYMBOL | |||
| "instruction parser" // ET_PARSER | |||
| }; | |||
| @@ -33,11 +34,13 @@ static const char *asm_error_descs[] = { | |||
| "header offset exceeds given ROM size", // ED_LYT_HEADER_RANGE | |||
| "declared ROM size in header exceeds actual size", // ED_LYT_DECLARE_RANGE | |||
| "duplicate definitions for label", // ED_LYT_DUPE_LABELS | |||
| "location is out of bounds for the ROM size", // ED_LYT_BOUNDS | |||
| "location overlaps with instruction or data", // ED_LYT_OVERLAP | |||
| "location overlaps with ROM header", // ED_LYT_OVERLAP_HEAD | |||
| "duplicate definitions for label", // ED_SYM_DUPE_LABELS | |||
| "undefined reference to label", // ED_SYM_NO_LABEL | |||
| "syntax error" // ED_PARSE_SYNTAX | |||
| }; | |||
| @@ -13,6 +13,7 @@ typedef enum { | |||
| ET_INCLUDE, | |||
| ET_PREPROC, | |||
| ET_LAYOUT, | |||
| ET_SYMBOL, | |||
| ET_PARSER | |||
| } ASMErrorType; | |||
| @@ -29,11 +30,13 @@ typedef enum { | |||
| ED_LYT_HEADER_RANGE, | |||
| ED_LYT_DECLARE_RANGE, | |||
| ED_LYT_DUPE_LABELS, | |||
| ED_LYT_BOUNDS, | |||
| ED_LYT_OVERLAP, | |||
| ED_LYT_OVERLAP_HEAD, | |||
| ED_SYM_DUPE_LABELS, | |||
| ED_SYM_NO_LABEL, | |||
| ED_PARSE_SYNTAX | |||
| } ASMErrorDesc; | |||
| @@ -88,7 +88,7 @@ | |||
| static inline bool is_valid_label_char(char c, bool first) | |||
| { | |||
| return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || | |||
| (!first && c >= '0' && c <= '9') || c == '_'; | |||
| (!first && c >= '0' && c <= '9') || c == '_' || c == '.'; | |||
| } | |||
| /* | |||
| @@ -125,6 +125,7 @@ static size_t read_labels( | |||
| strncpy(line->data, source + start, i - start + 1); | |||
| line->length = i - start + 1; | |||
| line->is_label = true; | |||
| nexti = read_labels(source + i + 1, length - i - 1, &line->next, tail_ptr); | |||
| *head_ptr = line; | |||
| @@ -136,7 +137,7 @@ static size_t read_labels( | |||
| /* | |||
| Preprocess a single source line (source, length) into one or more ASMLines. | |||
| Only the data, length, and next fields of the ASMLine objects are | |||
| Only the data, length, is_label, and next fields of the ASMLine objects are | |||
| populated. The normalization process strips comments, makes various | |||
| adjustments outside of string literals (converts tabs to spaces, lowercases | |||
| all alphabetical characters, and removes runs of multiple spaces), among | |||
| @@ -209,6 +210,7 @@ static ASMLine* normalize_line(const char *source, size_t length) | |||
| line->data = data; | |||
| line->length = di; | |||
| line->is_label = false; | |||
| line->next = NULL; | |||
| if (head) { // Line has labels, so link the main part up | |||
| @@ -418,7 +420,7 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | |||
| while ((prev = line, line = next)) { | |||
| next = line->next; | |||
| if (line->data[0] != DIRECTIVE_MARKER) | |||
| if (line->is_label || line->data[0] != DIRECTIVE_MARKER) | |||
| continue; | |||
| if (IS_LOCAL_DIRECTIVE(line)) | |||
| continue; // "Local" directives are handled by the tokenizer | |||
| @@ -144,7 +144,7 @@ static inline size_t hash_key(const char *key) | |||
| /* | |||
| Search for a key in the symbol table. | |||
| Return the key on success and NULL on failure. | |||
| Return the corresponding symbol on success and NULL on failure. | |||
| */ | |||
| const ASMSymbol* asm_symtable_find(const ASMSymbolTable *tab, const char *key) | |||
| { | |||
| @@ -159,6 +159,8 @@ const ASMSymbol* asm_symtable_find(const ASMSymbolTable *tab, const char *key) | |||
| /* | |||
| Insert a symbol into the table. | |||
| TODO: return boolean on success instead of void. | |||
| */ | |||
| void asm_symtable_insert(ASMSymbolTable *tab, ASMSymbol *symbol) | |||
| { | |||
| @@ -22,6 +22,7 @@ struct ASMLine { | |||
| size_t length; | |||
| const Line *original; | |||
| const char *filename; | |||
| bool is_label; | |||
| struct ASMLine *next; | |||
| }; | |||
| typedef struct ASMLine ASMLine; | |||
| @@ -40,8 +41,8 @@ typedef struct { | |||
| struct ASMInstruction { | |||
| ASMLocation loc; | |||
| uint8_t b1, b2, b3, b4; | |||
| uint8_t virtual_byte; | |||
| char *symbol; | |||
| const ASMLine *line; | |||
| struct ASMInstruction *next; | |||
| }; | |||
| typedef struct ASMInstruction ASMInstruction; | |||
| @@ -54,7 +55,7 @@ struct ASMData { | |||
| typedef struct ASMData ASMData; | |||
| struct ASMSymbol { | |||
| size_t offset; | |||
| uint16_t offset; | |||
| char *symbol; | |||
| const ASMLine *line; | |||
| struct ASMSymbol *next; | |||