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