diff --git a/src/assembler.c b/src/assembler.c index cbad7c6..8d4bee6 100644 --- a/src/assembler.c +++ b/src/assembler.c @@ -17,6 +17,37 @@ #define IS_LABEL(line) (line->data[line->length - 1] == ':') /* + Add a given line, representing a label, to the symbol table. + + Return NULL on success and an ErrorInfo object on failure (in the case of + duplicate labels). +*/ +static ErrorInfo* add_label_to_table( + ASMSymbolTable *symtable, const ASMLine *line, size_t offset) +{ + char *symbol = strndup(line->data, line->length - 1); + if (!symbol) + OUT_OF_MEMORY() + + const ASMSymbol *current = asm_symtable_find(symtable, symbol); + if (current) { + ErrorInfo *ei = error_info_create(line, ET_LAYOUT, ED_LYT_DUPE_LABELS); + error_info_append(ei, current->line); + return ei; + } + + ASMSymbol *label = malloc(sizeof(ASMSymbol)); + if (!label) + OUT_OF_MEMORY() + + label->offset = offset; + label->symbol = symbol; + label->line = line; + asm_symtable_insert(symtable, label); + return NULL; +} + +/* Parse an instruction encoded in line into an ASMInstruction object. On success, return NULL and store the instruction in *inst_ptr. On failure, @@ -44,7 +75,9 @@ static ErrorInfo* tokenize(AssemblerState *state) if (!overlap_table) OUT_OF_MEMORY() - // TODO: fill overlap table for header with pointers to a dummy object + ASMLine header_indicator; + for (size_t i = 0; i < HEADER_SIZE; i++) + overlap_table[state->header.offset + i] = &header_indicator; ErrorInfo *ei = NULL; ASMInstruction dummy = {.next = NULL}, *inst, *prev = &dummy; @@ -77,7 +110,8 @@ static ErrorInfo* tokenize(AssemblerState *state) } } else if (IS_LABEL(line)) { - // TODO: add to symbol table + if ((ei = add_label_to_table(state->symtable, line, offset))) + goto cleanup; } else { if ((ei = parse_instruction(line, &inst, offset))) diff --git a/src/assembler/errors.c b/src/assembler/errors.c index 172e558..67ece6d 100644 --- a/src/assembler/errors.c +++ b/src/assembler/errors.c @@ -33,6 +33,7 @@ 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 overlaps with ROM header", // ED_LYT_HEAD_OVERLAP "location overlaps with previous instruction", // ED_LYT_INST_OVERLAP "location overlaps with previous data", // ED_LYT_DATA_OVERLAP diff --git a/src/assembler/errors.h b/src/assembler/errors.h index f912590..87c3cf5 100644 --- a/src/assembler/errors.h +++ b/src/assembler/errors.h @@ -29,6 +29,7 @@ typedef enum { ED_LYT_HEADER_RANGE, ED_LYT_DECLARE_RANGE, + ED_LYT_DUPE_LABELS, ED_LYT_HEAD_OVERLAP, ED_LYT_INST_OVERLAP, ED_LYT_DATA_OVERLAP, diff --git a/src/assembler/state.c b/src/assembler/state.c index 77a8eb4..7f6766f 100644 --- a/src/assembler/state.c +++ b/src/assembler/state.c @@ -128,6 +128,40 @@ void asm_symtable_free(ASMSymbolTable *symtable) free(symtable); } +/* + ... +*/ +static inline size_t hash_key(const char *key) +{ + return 0; +} + +/* + Search for a key in the symbol table. + + Return the key on success and NULL on failure. +*/ +const ASMSymbol* asm_symtable_find(const ASMSymbolTable *tab, const char *key) +{ + ASMSymbol *symbol = tab->buckets[hash_key(key)]; + while (symbol) { + if (!strcmp(key, symbol->symbol)) + return symbol; + symbol = symbol->next; + } + return NULL; +} + +/* + Insert a symbol into the table. +*/ +void asm_symtable_insert(ASMSymbolTable *tab, ASMSymbol *symbol) +{ + size_t index = hash_key(symbol->symbol); + symbol->next = tab->buckets[index]; + tab->buckets[index] = symbol; +} + #ifdef DEBUG_MODE /* DEBUG FUNCTION: Print out an ASMLine list to stdout. diff --git a/src/assembler/state.h b/src/assembler/state.h index b922059..fe98c92 100644 --- a/src/assembler/state.h +++ b/src/assembler/state.h @@ -53,6 +53,7 @@ typedef struct ASMData ASMData; struct ASMSymbol { size_t offset; char *symbol; + const ASMLine *line; struct ASMSymbol *next; }; typedef struct ASMSymbol ASMSymbol; @@ -92,6 +93,9 @@ void asm_instructions_free(ASMInstruction*); void asm_data_free(ASMData*); void asm_symtable_free(ASMSymbolTable*); +const ASMSymbol* asm_symtable_find(const ASMSymbolTable*, const char*); +void asm_symtable_insert(ASMSymbolTable*, ASMSymbol*); + #ifdef DEBUG_MODE void asm_lines_print(const ASMLine*); #endif