| @@ -33,9 +33,9 @@ static ErrorInfo* parse_instruction( | |||||
| /* | /* | ||||
| Tokenize ASMLines into ASMInstructions. | 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) | static ErrorInfo* tokenize(AssemblerState *state) | ||||
| { | { | ||||
| @@ -53,32 +53,33 @@ static ErrorInfo* tokenize(AssemblerState *state) | |||||
| while (line) { | while (line) { | ||||
| if (IS_LOCAL_DIRECTIVE(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 | // TODO | ||||
| ei = error_info_create(line, ET_PREPROC, ED_PP_UNKNOWN); | 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)) { | else if (IS_LABEL(line)) { | ||||
| // TODO: add to symbol table | // TODO: add to symbol table | ||||
| } | } | ||||
| else { | else { | ||||
| if ((ei = parse_instruction(line, &inst, offset))) | if ((ei = parse_instruction(line, &inst, offset))) | ||||
| goto error; | |||||
| goto cleanup; | |||||
| // TODO: bounded check on range [offset, offset + inst->length) against overlap table | // TODO: bounded check on range [offset, offset + inst->length) against overlap table | ||||
| // if clash, use error with current line, | // if clash, use error with current line, | ||||
| @@ -92,13 +93,8 @@ static ErrorInfo* tokenize(AssemblerState *state) | |||||
| line = line->next; | line = line->next; | ||||
| } | } | ||||
| state->instructions = dummy.next; | |||||
| goto cleanup; | |||||
| error: | |||||
| asm_instructions_free(dummy.next); | |||||
| cleanup: | cleanup: | ||||
| state->instructions = dummy.next; | |||||
| free(overlap_table); | free(overlap_table); | ||||
| return ei; | 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. | 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; | *ei_ptr = error_info; | ||||
| cleanup: | 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; | return retval; | ||||
| } | } | ||||
| @@ -6,7 +6,7 @@ | |||||
| #include <string.h> | #include <string.h> | ||||
| #define DIRECTIVE_MARKER '.' | #define DIRECTIVE_MARKER '.' | ||||
| #define NUM_DIRECTIVES 15 | |||||
| #define NUM_DIRECTIVES 14 | |||||
| #define DIR_INCLUDE ".include" | #define DIR_INCLUDE ".include" | ||||
| @@ -20,7 +20,6 @@ | |||||
| #define DIR_ROM_DECLSIZE ".rom_declsize" | #define DIR_ROM_DECLSIZE ".rom_declsize" | ||||
| #define DIR_ORIGIN ".org" | #define DIR_ORIGIN ".org" | ||||
| #define DIR_ALIGN ".align" | |||||
| #define DIR_BYTE ".byte" | #define DIR_BYTE ".byte" | ||||
| #define DIR_ASCII ".ascii" | #define DIR_ASCII ".ascii" | ||||
| #define DIR_ASCIZ ".asciz" | #define DIR_ASCIZ ".asciz" | ||||
| @@ -34,9 +33,9 @@ | |||||
| (!DIRECTIVE_HAS_ARG(line, d) || (line)->data[strlen(d)] == ' ')) | (!DIRECTIVE_HAS_ARG(line, d) || (line)->data[strlen(d)] == ' ')) | ||||
| #define IS_LOCAL_DIRECTIVE(line) \ | #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) \ | #define DIRECTIVE_OFFSET(line, d) \ | ||||
| (DIRECTIVE_HAS_ARG(line, d) ? strlen(d) : 0) | (DIRECTIVE_HAS_ARG(line, d) ? strlen(d) : 0) | ||||
| @@ -24,10 +24,23 @@ void state_init(AssemblerState *state) | |||||
| state->lines = NULL; | state->lines = NULL; | ||||
| state->includes = NULL; | state->includes = NULL; | ||||
| state->instructions = NULL; | state->instructions = NULL; | ||||
| state->data = NULL; | |||||
| state->symtable = 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. | Initialize an ASMSymbolTable and place it in *symtable_ptr. | ||||
| */ | */ | ||||
| void asm_symtable_init(ASMSymbolTable **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. | Deallocate an ASMSymbolTable. | ||||
| */ | */ | ||||
| void asm_symtable_free(ASMSymbolTable *symtable) | void asm_symtable_free(ASMSymbolTable *symtable) | ||||
| @@ -42,6 +42,14 @@ struct ASMInstruction { | |||||
| }; | }; | ||||
| typedef struct ASMInstruction 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 { | struct ASMSymbol { | ||||
| size_t offset; | size_t offset; | ||||
| char *symbol; | char *symbol; | ||||
| @@ -69,16 +77,19 @@ typedef struct { | |||||
| ASMLine *lines; | ASMLine *lines; | ||||
| ASMInclude *includes; | ASMInclude *includes; | ||||
| ASMInstruction *instructions; | ASMInstruction *instructions; | ||||
| ASMData *data; | |||||
| ASMSymbolTable *symtable; | ASMSymbolTable *symtable; | ||||
| } AssemblerState; | } AssemblerState; | ||||
| /* Functions */ | /* Functions */ | ||||
| void state_init(AssemblerState*); | void state_init(AssemblerState*); | ||||
| void state_free(AssemblerState*); | |||||
| void asm_symtable_init(ASMSymbolTable**); | void asm_symtable_init(ASMSymbolTable**); | ||||
| void asm_lines_free(ASMLine*); | void asm_lines_free(ASMLine*); | ||||
| void asm_includes_free(ASMInclude*); | void asm_includes_free(ASMInclude*); | ||||
| void asm_instructions_free(ASMInstruction*); | void asm_instructions_free(ASMInstruction*); | ||||
| void asm_data_free(ASMData*); | |||||
| void asm_symtable_free(ASMSymbolTable*); | void asm_symtable_free(ASMSymbolTable*); | ||||
| #ifdef DEBUG_MODE | #ifdef DEBUG_MODE | ||||