@@ -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; | ||||