@@ -43,10 +43,13 @@ static const char *error_descs[] = { | |||||
[ED_SYM_DUPE_LABELS] = "duplicate definitions for label", | [ED_SYM_DUPE_LABELS] = "duplicate definitions for label", | ||||
[ED_SYM_NO_LABEL] = "undefined reference to label", | [ED_SYM_NO_LABEL] = "undefined reference to label", | ||||
[ED_PARSE_OP_LONG] = "opcode mnemonic is too long (2-4 characters)", | |||||
[ED_PARSE_OP_SHORT] = "opcode mnemonic is too short (2-4 characters)", | |||||
[ED_PARSE_OP_CHARS] = "invalid characters in opcode mnemonic", | |||||
[ED_PARSE_OP_UNKNOWN] = "unknown opcode mnemonic" | |||||
[ED_PS_OP_TOO_LONG] = "opcode mnemonic is too long (2-4 characters)", | |||||
[ED_PS_OP_TOO_SHORT] = "opcode mnemonic is too short (2-4 characters)", | |||||
[ED_PS_OP_INVALID] = "invalid characters in opcode mnemonic", | |||||
[ED_PS_OP_UNKNOWN] = "unknown opcode mnemonic", | |||||
[ED_PS_TOO_FEW_ARGS] = "too few arguments for opcode", | |||||
[ED_PS_TOO_MANY_ARGS] = "too many arguments for opcode", | |||||
// [ED_PS_ARG1_TYPE] = "invalid type for first argument", | |||||
}; | }; | ||||
/* Internal structs */ | /* Internal structs */ | ||||
@@ -42,10 +42,12 @@ typedef enum { | |||||
ED_SYM_DUPE_LABELS, | ED_SYM_DUPE_LABELS, | ||||
ED_SYM_NO_LABEL, | ED_SYM_NO_LABEL, | ||||
ED_PARSE_OP_LONG, | |||||
ED_PARSE_OP_SHORT, | |||||
ED_PARSE_OP_CHARS, | |||||
ED_PARSE_OP_UNKNOWN | |||||
ED_PS_OP_TOO_LONG, | |||||
ED_PS_OP_TOO_SHORT, | |||||
ED_PS_OP_INVALID, | |||||
ED_PS_OP_UNKNOWN, | |||||
ED_PS_TOO_FEW_ARGS, | |||||
ED_PS_TOO_MANY_ARGS | |||||
} ASMErrorDesc; | } ASMErrorDesc; | ||||
/* Structs */ | /* Structs */ | ||||
@@ -24,13 +24,66 @@ | |||||
page0 := $0 | $8 | $10 | $18 | $20 | $28 | $30 | $38 | page0 := $0 | $8 | $10 | $18 | $20 | $28 | $30 | $38 | ||||
*/ | */ | ||||
/* Helper macros for get_inst_parser() */ | |||||
#define JOIN_(a, b, c, d) ((uint32_t) ((a << 24) + (b << 16) + (c << 8) + d)) | |||||
#define DISPATCH_(s, z) ( \ | |||||
z == 2 ? JOIN_(s[0], s[1], 0x00, 0x00) : \ | |||||
z == 3 ? JOIN_(s[0], s[1], s[2], 0x00) : \ | |||||
JOIN_(s[0], s[1], s[2], s[3])) \ | |||||
#define MAKE_CMP_(s) DISPATCH_(s, (sizeof(s) / sizeof(char) - 1)) | |||||
#define HANDLE(m) if (key == MAKE_CMP_(#m)) return parse_inst_##m; | |||||
/* Instruction parser functions */ | |||||
#define INST_FUNC(mnemonic) \ | |||||
static ASMErrorDesc parse_inst_##mnemonic( \ | |||||
uint8_t **bytes, size_t *length, char **symbol, const char *arg, size_t size) | |||||
INST_FUNC(nop) | |||||
{ | |||||
DEBUG("dispatched to -> NOP") | |||||
return ED_PS_TOO_FEW_ARGS; | |||||
} | |||||
INST_FUNC(inc) | |||||
{ | |||||
DEBUG("dispatched to -> INC") | |||||
return ED_PS_TOO_FEW_ARGS; | |||||
} | |||||
INST_FUNC(add) | |||||
{ | |||||
DEBUG("dispatched to -> ADD") | |||||
return ED_PS_TOO_FEW_ARGS; | |||||
} | |||||
INST_FUNC(adc) | |||||
{ | |||||
DEBUG("dispatched to -> ADC") | |||||
return ED_PS_TOO_FEW_ARGS; | |||||
} | |||||
/* | /* | ||||
... | |||||
Return the relevant ASMInstParser function for a given mnemonic. | |||||
NULL is returned if the mnemonic is not known. | |||||
*/ | */ | ||||
ASMInstParser get_inst_parser(char mnemonic[MAX_MNEMONIC_SIZE + 1]) | |||||
ASMInstParser get_inst_parser(char mstr[MAX_MNEMONIC_SIZE]) | |||||
{ | { | ||||
// TODO | |||||
DEBUG("get_inst_parser(): -->%s<--", mnemonic) | |||||
// Exploit the fact that we can store the entire mnemonic string as a | |||||
// single 32-bit value to do fast lookups: | |||||
uint32_t key = (mstr[0] << 24) + (mstr[1] << 16) + (mstr[2] << 8) + mstr[3]; | |||||
DEBUG("get_inst_parser(): -->%.*s<-- 0x%08X", MAX_MNEMONIC_SIZE, mstr, key) | |||||
HANDLE(nop) | |||||
HANDLE(inc) | |||||
HANDLE(add) | |||||
HANDLE(adc) | |||||
return NULL; | return NULL; | ||||
} | } |
@@ -12,8 +12,9 @@ | |||||
/* Typedefs */ | /* Typedefs */ | ||||
typedef ASMErrorDesc (*ASMInstParser)(uint8_t**, size_t*, char**, const char*, size_t); | |||||
typedef ASMErrorDesc (*ASMInstParser)( | |||||
uint8_t**, size_t*, char**, const char*, size_t); | |||||
/* Functions */ | /* Functions */ | ||||
ASMInstParser get_inst_parser(char[MAX_MNEMONIC_SIZE + 1]); | |||||
ASMInstParser get_inst_parser(char[MAX_MNEMONIC_SIZE]); |
@@ -231,33 +231,32 @@ static ErrorInfo* parse_data( | |||||
static ErrorInfo* parse_instruction( | static ErrorInfo* parse_instruction( | ||||
const ASMLine *line, ASMInstruction **inst_ptr, size_t offset) | const ASMLine *line, ASMInstruction **inst_ptr, size_t offset) | ||||
{ | { | ||||
char mnemonic[MAX_MNEMONIC_SIZE + 1]; | |||||
char mnemonic[MAX_MNEMONIC_SIZE] = {0}; | |||||
size_t i = 0; | size_t i = 0; | ||||
while (i < line->length) { | while (i < line->length) { | ||||
char c = line->data[i]; | char c = line->data[i]; | ||||
if (c == ' ') | if (c == ' ') | ||||
break; | break; | ||||
if (i >= MAX_MNEMONIC_SIZE) | if (i >= MAX_MNEMONIC_SIZE) | ||||
return error_info_create(line, ET_PARSER, ED_PARSE_OP_LONG); | |||||
return error_info_create(line, ET_PARSER, ED_PS_OP_TOO_LONG); | |||||
if ((c < 'a' || c > 'z') && (c < '0' || c > '9')) | if ((c < 'a' || c > 'z') && (c < '0' || c > '9')) | ||||
return error_info_create(line, ET_PARSER, ED_PARSE_OP_CHARS); | |||||
return error_info_create(line, ET_PARSER, ED_PS_OP_INVALID); | |||||
mnemonic[i++] = c; | mnemonic[i++] = c; | ||||
} | } | ||||
if (i < MIN_MNEMONIC_SIZE) | if (i < MIN_MNEMONIC_SIZE) | ||||
return error_info_create(line, ET_PARSER, ED_PARSE_OP_SHORT); | |||||
return error_info_create(line, ET_PARSER, ED_PS_OP_TOO_SHORT); | |||||
uint8_t *bytes; | uint8_t *bytes; | ||||
size_t arglen = line->length - i, length; | size_t arglen = line->length - i, length; | ||||
char *argstart = arglen > 0 ? line->data + i : NULL, *symbol; | char *argstart = arglen > 0 ? line->data + i : NULL, *symbol; | ||||
mnemonic[i] = '\0'; | |||||
ASMInstParser parser = get_inst_parser(mnemonic); | ASMInstParser parser = get_inst_parser(mnemonic); | ||||
if (!parser) | if (!parser) | ||||
return error_info_create(line, ET_PARSER, ED_PARSE_OP_UNKNOWN); | |||||
return error_info_create(line, ET_PARSER, ED_PS_OP_UNKNOWN); | |||||
ASMErrorDesc edesc = parser(&bytes, &length, &symbol, argstart, arglen); | ASMErrorDesc edesc = parser(&bytes, &length, &symbol, argstart, arglen); | ||||
if (edesc) | |||||
if (edesc != ED_NONE) | |||||
return error_info_create(line, ET_PARSER, edesc); | return error_info_create(line, ET_PARSER, edesc); | ||||
ASMInstruction *inst = malloc(sizeof(ASMInstruction)); | ASMInstruction *inst = malloc(sizeof(ASMInstruction)); | ||||