diff --git a/src/assembler/errors.c b/src/assembler/errors.c index da75ecc..b74d519 100644 --- a/src/assembler/errors.c +++ b/src/assembler/errors.c @@ -43,10 +43,13 @@ static const char *error_descs[] = { [ED_SYM_DUPE_LABELS] = "duplicate definitions for 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 */ diff --git a/src/assembler/errors.h b/src/assembler/errors.h index 100d745..4ed6da5 100644 --- a/src/assembler/errors.h +++ b/src/assembler/errors.h @@ -42,10 +42,12 @@ typedef enum { ED_SYM_DUPE_LABELS, 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; /* Structs */ diff --git a/src/assembler/instructions.c b/src/assembler/instructions.c index 36d849e..c7f2179 100644 --- a/src/assembler/instructions.c +++ b/src/assembler/instructions.c @@ -24,13 +24,66 @@ 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; } diff --git a/src/assembler/instructions.h b/src/assembler/instructions.h index 9d38d17..1aa0fc3 100644 --- a/src/assembler/instructions.h +++ b/src/assembler/instructions.h @@ -12,8 +12,9 @@ /* 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 */ -ASMInstParser get_inst_parser(char[MAX_MNEMONIC_SIZE + 1]); +ASMInstParser get_inst_parser(char[MAX_MNEMONIC_SIZE]); diff --git a/src/assembler/tokenizer.c b/src/assembler/tokenizer.c index 9c70c41..a21188b 100644 --- a/src/assembler/tokenizer.c +++ b/src/assembler/tokenizer.c @@ -231,33 +231,32 @@ static ErrorInfo* parse_data( static ErrorInfo* parse_instruction( 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; while (i < line->length) { char c = line->data[i]; if (c == ' ') break; 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')) - 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; } 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; size_t arglen = line->length - i, length; char *argstart = arglen > 0 ? line->data + i : NULL, *symbol; - mnemonic[i] = '\0'; ASMInstParser parser = get_inst_parser(mnemonic); 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); - if (edesc) + if (edesc != ED_NONE) return error_info_create(line, ET_PARSER, edesc); ASMInstruction *inst = malloc(sizeof(ASMInstruction));