| @@ -33,9 +33,9 @@ static ErrorInfo* parse_instruction( | |||
| /* | |||
| Tokenize ASMLines into ASMInstructions. | |||
| On success, state->instructions is modified and NULL is returned. On error, | |||
| an ErrorInfo object is returned and state->instructions is not modified. | |||
| state->symtable may or may not be modified regardless of success. | |||
| NULL is returned on success and an ErrorInfo object is returned on failure. | |||
| state->instructions, state->data, and state->symtable may or may not be | |||
| modified regardless of success. | |||
| */ | |||
| static ErrorInfo* tokenize(AssemblerState *state) | |||
| { | |||
| @@ -53,32 +53,33 @@ static ErrorInfo* tokenize(AssemblerState *state) | |||
| while (line) { | |||
| if (IS_LOCAL_DIRECTIVE(line)) { | |||
| if (!IS_DIRECTIVE(line, DIR_ORIGIN)) { | |||
| if (IS_DIRECTIVE(line, DIR_ORIGIN)) { | |||
| if (!DIRECTIVE_HAS_ARG(line, DIR_ORIGIN)) { | |||
| ei = error_info_create(line, ET_PREPROC, ED_PP_NO_ARG); | |||
| goto cleanup; | |||
| } | |||
| uint32_t arg; | |||
| if (!parse_uint32_t(&arg, line, DIR_ORIGIN)) { | |||
| ei = error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG); | |||
| goto cleanup; | |||
| } | |||
| offset = arg; | |||
| origin = line; | |||
| } | |||
| else { | |||
| // TODO | |||
| ei = error_info_create(line, ET_PREPROC, ED_PP_UNKNOWN); | |||
| goto error; | |||
| } | |||
| if (!DIRECTIVE_HAS_ARG(line, DIR_ORIGIN)) { | |||
| ei = error_info_create(line, ET_PREPROC, ED_PP_NO_ARG); | |||
| goto error; | |||
| goto cleanup; | |||
| } | |||
| uint32_t arg; | |||
| if (!parse_uint32_t(&arg, line, DIR_ORIGIN)) { | |||
| ei = error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG); | |||
| goto error; | |||
| } | |||
| offset = arg; | |||
| origin = line; | |||
| } | |||
| else if (IS_LABEL(line)) { | |||
| // TODO: add to symbol table | |||
| } | |||
| else { | |||
| if ((ei = parse_instruction(line, &inst, offset))) | |||
| goto error; | |||
| goto cleanup; | |||
| // TODO: bounded check on range [offset, offset + inst->length) against overlap table | |||
| // if clash, use error with current line, | |||
| @@ -92,13 +93,8 @@ static ErrorInfo* tokenize(AssemblerState *state) | |||
| line = line->next; | |||
| } | |||
| state->instructions = dummy.next; | |||
| goto cleanup; | |||
| error: | |||
| asm_instructions_free(dummy.next); | |||
| cleanup: | |||
| state->instructions = dummy.next; | |||
| free(overlap_table); | |||
| return ei; | |||
| } | |||
| @@ -144,7 +140,7 @@ static ErrorInfo* resolve_symbols(AssemblerState *state) | |||
| } | |||
| /* | |||
| Convert finalized ASMInstructions into a binary data block. | |||
| Convert finalized ASMInstructions and ASMData into a binary data block. | |||
| This function should never fail. | |||
| */ | |||
| @@ -208,10 +204,7 @@ size_t assemble(const LineBuffer *source, uint8_t **binary_ptr, ErrorInfo **ei_p | |||
| *ei_ptr = error_info; | |||
| cleanup: | |||
| asm_lines_free(state.lines); | |||
| asm_includes_free(state.includes); | |||
| asm_instructions_free(state.instructions); | |||
| asm_symtable_free(state.symtable); | |||
| state_free(&state); | |||
| return retval; | |||
| } | |||
| @@ -6,7 +6,7 @@ | |||
| #include <string.h> | |||
| #define DIRECTIVE_MARKER '.' | |||
| #define NUM_DIRECTIVES 15 | |||
| #define NUM_DIRECTIVES 14 | |||
| #define DIR_INCLUDE ".include" | |||
| @@ -20,7 +20,6 @@ | |||
| #define DIR_ROM_DECLSIZE ".rom_declsize" | |||
| #define DIR_ORIGIN ".org" | |||
| #define DIR_ALIGN ".align" | |||
| #define DIR_BYTE ".byte" | |||
| #define DIR_ASCII ".ascii" | |||
| #define DIR_ASCIZ ".asciz" | |||
| @@ -34,9 +33,9 @@ | |||
| (!DIRECTIVE_HAS_ARG(line, d) || (line)->data[strlen(d)] == ' ')) | |||
| #define IS_LOCAL_DIRECTIVE(line) \ | |||
| (IS_DIRECTIVE(line, DIR_ORIGIN) || IS_DIRECTIVE(line, DIR_ALIGN) || \ | |||
| IS_DIRECTIVE(line, DIR_BYTE) || IS_DIRECTIVE(line, DIR_ASCII) || \ | |||
| IS_DIRECTIVE(line, DIR_ASCIZ) || IS_DIRECTIVE(line, DIR_ASCIIZ)) | |||
| (IS_DIRECTIVE(line, DIR_ORIGIN) || IS_DIRECTIVE(line, DIR_BYTE) || \ | |||
| IS_DIRECTIVE(line, DIR_ASCII) || IS_DIRECTIVE(line, DIR_ASCIZ) || \ | |||
| IS_DIRECTIVE(line, DIR_ASCIIZ)) | |||
| #define DIRECTIVE_OFFSET(line, d) \ | |||
| (DIRECTIVE_HAS_ARG(line, d) ? strlen(d) : 0) | |||
| @@ -24,10 +24,23 @@ void state_init(AssemblerState *state) | |||
| state->lines = NULL; | |||
| state->includes = NULL; | |||
| state->instructions = NULL; | |||
| state->data = NULL; | |||
| state->symtable = NULL; | |||
| } | |||
| /* | |||
| Deallocate the contents of an AssemblerState object. | |||
| */ | |||
| void state_free(AssemblerState *state) | |||
| { | |||
| asm_lines_free(state->lines); | |||
| asm_includes_free(state->includes); | |||
| asm_instructions_free(state->instructions); | |||
| asm_data_free(state->data); | |||
| asm_symtable_free(state->symtable); | |||
| } | |||
| /* | |||
| Initialize an ASMSymbolTable and place it in *symtable_ptr. | |||
| */ | |||
| void asm_symtable_init(ASMSymbolTable **symtable_ptr) | |||
| @@ -83,6 +96,19 @@ void asm_instructions_free(ASMInstruction *inst) | |||
| } | |||
| /* | |||
| Deallocate an ASMData list. | |||
| */ | |||
| void asm_data_free(ASMData *data) | |||
| { | |||
| while (data) { | |||
| ASMData *temp = data->next; | |||
| free(data->data); | |||
| free(data); | |||
| data = temp; | |||
| } | |||
| } | |||
| /* | |||
| Deallocate an ASMSymbolTable. | |||
| */ | |||
| void asm_symtable_free(ASMSymbolTable *symtable) | |||
| @@ -42,6 +42,14 @@ struct ASMInstruction { | |||
| }; | |||
| typedef struct ASMInstruction ASMInstruction; | |||
| struct ASMData { | |||
| size_t offset; | |||
| size_t length; | |||
| uint8_t *data; | |||
| struct ASMData *next; | |||
| }; | |||
| typedef struct ASMData ASMData; | |||
| struct ASMSymbol { | |||
| size_t offset; | |||
| char *symbol; | |||
| @@ -69,16 +77,19 @@ typedef struct { | |||
| ASMLine *lines; | |||
| ASMInclude *includes; | |||
| ASMInstruction *instructions; | |||
| ASMData *data; | |||
| ASMSymbolTable *symtable; | |||
| } AssemblerState; | |||
| /* Functions */ | |||
| void state_init(AssemblerState*); | |||
| void state_free(AssemblerState*); | |||
| void asm_symtable_init(ASMSymbolTable**); | |||
| void asm_lines_free(ASMLine*); | |||
| void asm_includes_free(ASMInclude*); | |||
| void asm_instructions_free(ASMInstruction*); | |||
| void asm_data_free(ASMData*); | |||
| void asm_symtable_free(ASMSymbolTable*); | |||
| #ifdef DEBUG_MODE | |||