| @@ -17,6 +17,37 @@ | |||||
| #define IS_LABEL(line) (line->data[line->length - 1] == ':') | #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. | Parse an instruction encoded in line into an ASMInstruction object. | ||||
| On success, return NULL and store the instruction in *inst_ptr. On failure, | 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) | if (!overlap_table) | ||||
| OUT_OF_MEMORY() | 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; | ErrorInfo *ei = NULL; | ||||
| ASMInstruction dummy = {.next = NULL}, *inst, *prev = &dummy; | ASMInstruction dummy = {.next = NULL}, *inst, *prev = &dummy; | ||||
| @@ -77,7 +110,8 @@ static ErrorInfo* tokenize(AssemblerState *state) | |||||
| } | } | ||||
| } | } | ||||
| else if (IS_LABEL(line)) { | else if (IS_LABEL(line)) { | ||||
| // TODO: add to symbol table | |||||
| if ((ei = add_label_to_table(state->symtable, line, offset))) | |||||
| goto cleanup; | |||||
| } | } | ||||
| else { | else { | ||||
| if ((ei = parse_instruction(line, &inst, offset))) | if ((ei = parse_instruction(line, &inst, offset))) | ||||
| @@ -33,6 +33,7 @@ static const char *asm_error_descs[] = { | |||||
| "header offset exceeds given ROM size", // ED_LYT_HEADER_RANGE | "header offset exceeds given ROM size", // ED_LYT_HEADER_RANGE | ||||
| "declared ROM size in header exceeds actual size", // ED_LYT_DECLARE_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 ROM header", // ED_LYT_HEAD_OVERLAP | ||||
| "location overlaps with previous instruction", // ED_LYT_INST_OVERLAP | "location overlaps with previous instruction", // ED_LYT_INST_OVERLAP | ||||
| "location overlaps with previous data", // ED_LYT_DATA_OVERLAP | "location overlaps with previous data", // ED_LYT_DATA_OVERLAP | ||||
| @@ -29,6 +29,7 @@ typedef enum { | |||||
| ED_LYT_HEADER_RANGE, | ED_LYT_HEADER_RANGE, | ||||
| ED_LYT_DECLARE_RANGE, | ED_LYT_DECLARE_RANGE, | ||||
| ED_LYT_DUPE_LABELS, | |||||
| ED_LYT_HEAD_OVERLAP, | ED_LYT_HEAD_OVERLAP, | ||||
| ED_LYT_INST_OVERLAP, | ED_LYT_INST_OVERLAP, | ||||
| ED_LYT_DATA_OVERLAP, | ED_LYT_DATA_OVERLAP, | ||||
| @@ -128,6 +128,40 @@ void asm_symtable_free(ASMSymbolTable *symtable) | |||||
| free(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 | #ifdef DEBUG_MODE | ||||
| /* | /* | ||||
| DEBUG FUNCTION: Print out an ASMLine list to stdout. | DEBUG FUNCTION: Print out an ASMLine list to stdout. | ||||
| @@ -53,6 +53,7 @@ typedef struct ASMData ASMData; | |||||
| struct ASMSymbol { | struct ASMSymbol { | ||||
| size_t offset; | size_t offset; | ||||
| char *symbol; | char *symbol; | ||||
| const ASMLine *line; | |||||
| struct ASMSymbol *next; | struct ASMSymbol *next; | ||||
| }; | }; | ||||
| typedef struct ASMSymbol ASMSymbol; | typedef struct ASMSymbol ASMSymbol; | ||||
| @@ -92,6 +93,9 @@ void asm_instructions_free(ASMInstruction*); | |||||
| void asm_data_free(ASMData*); | void asm_data_free(ASMData*); | ||||
| void asm_symtable_free(ASMSymbolTable*); | void asm_symtable_free(ASMSymbolTable*); | ||||
| const ASMSymbol* asm_symtable_find(const ASMSymbolTable*, const char*); | |||||
| void asm_symtable_insert(ASMSymbolTable*, ASMSymbol*); | |||||
| #ifdef DEBUG_MODE | #ifdef DEBUG_MODE | ||||
| void asm_lines_print(const ASMLine*); | void asm_lines_print(const ASMLine*); | ||||
| #endif | #endif | ||||