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