From a7a3055325c72c200de3725c9b599595193da21a Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 24 Apr 2015 02:04:32 -0500 Subject: [PATCH] More robust labels, implement symbol resolution. --- src/assembler.c | 35 ++++++++++++++++++++++++++++------- src/assembler/errors.c | 5 ++++- src/assembler/errors.h | 5 ++++- src/assembler/preprocessor.c | 8 +++++--- src/assembler/state.c | 4 +++- src/assembler/state.h | 5 +++-- 6 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/assembler.c b/src/assembler.c index 6f0efb6..bae4d35 100644 --- a/src/assembler.c +++ b/src/assembler.c @@ -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; } diff --git a/src/assembler/errors.c b/src/assembler/errors.c index c76d75d..8d8e26c 100644 --- a/src/assembler/errors.c +++ b/src/assembler/errors.c @@ -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 }; diff --git a/src/assembler/errors.h b/src/assembler/errors.h index 692a282..94b370d 100644 --- a/src/assembler/errors.h +++ b/src/assembler/errors.h @@ -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; diff --git a/src/assembler/preprocessor.c b/src/assembler/preprocessor.c index 4274d6a..64f07a0 100644 --- a/src/assembler/preprocessor.c +++ b/src/assembler/preprocessor.c @@ -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 diff --git a/src/assembler/state.c b/src/assembler/state.c index de6b3ef..307b65b 100644 --- a/src/assembler/state.c +++ b/src/assembler/state.c @@ -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) { diff --git a/src/assembler/state.h b/src/assembler/state.h index dbaeb21..3e71dfd 100644 --- a/src/assembler/state.h +++ b/src/assembler/state.h @@ -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;