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