| @@ -43,6 +43,7 @@ static const char *error_descs[] = { | |||
| [ED_SYM_DUPE_LABELS] = "duplicate definitions for label", | |||
| [ED_SYM_NO_LABEL] = "undefined reference to label", | |||
| [ED_SYM_IS_REGISTER] = "labels cannot share names with registers", | |||
| [ED_SYM_IS_CONDITION] = "labels cannot share names with condition codes", | |||
| [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)", | |||
| @@ -42,6 +42,7 @@ typedef enum { | |||
| ED_SYM_DUPE_LABELS, | |||
| ED_SYM_NO_LABEL, | |||
| ED_SYM_IS_REGISTER, | |||
| ED_SYM_IS_CONDITION, | |||
| ED_PS_OP_TOO_LONG, | |||
| ED_PS_OP_TOO_SHORT, | |||
| @@ -6,6 +6,7 @@ | |||
| #include "instructions.h" | |||
| #include "inst_args.h" | |||
| #include "parse_util.h" | |||
| #include "../logging.h" | |||
| /* | |||
| @@ -81,7 +82,7 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||
| if (!arg) \ | |||
| INST_ERROR(TOO_FEW_ARGS) \ | |||
| ASMInstArg args[3]; \ | |||
| size_t nargs; \ | |||
| size_t nargs = 0; \ | |||
| ASMErrorDesc err = parse_args(args, &nargs, arg, size); \ | |||
| if (err) \ | |||
| return err; \ | |||
| @@ -90,14 +91,13 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||
| if (nargs > hi) \ | |||
| INST_ERROR(TOO_MANY_ARGS) | |||
| #define INST_ARG(n) (args[n]) | |||
| #define INST_TYPE(n) INST_ARG(n).type | |||
| #define INST_REG(n) INST_ARG(n).data.reg | |||
| #define INST_IMM(n) INST_ARG(n).data.imm | |||
| #define INST_INDIRECT(n) INST_ARG(n).data.indirect | |||
| #define INST_INDEX(n) INST_ARG(n).data.index | |||
| #define INST_LABEL(n) INST_ARG(n).data.label | |||
| #define INST_COND(n) INST_ARG(n).data.cond | |||
| #define INST_TYPE(n) args[n].type | |||
| #define INST_REG(n) args[n].data.reg | |||
| #define INST_IMM(n) args[n].data.imm | |||
| #define INST_INDIRECT(n) args[n].data.indirect | |||
| #define INST_INDEX(n) args[n].data.index | |||
| #define INST_LABEL(n) args[n].data.label | |||
| #define INST_COND(n) args[n].data.cond | |||
| #define INST_REG_PREFIX(n) INST_PREFIX_(INST_REG(n)) | |||
| #define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg) | |||
| @@ -148,7 +148,33 @@ static ASMErrorDesc parse_arg( | |||
| ASMInstArg *arg, const char *str, size_t size, char **symbol) | |||
| { | |||
| // TODO | |||
| DEBUG("parse_arg(): -->%.*s<--", (int) size, str) | |||
| // AT_REGISTER | |||
| // AT_IMMEDIATE | |||
| // AT_INDIRECT | |||
| // AT_INDEXED | |||
| // AT_LABEL | |||
| // AT_CONDITION | |||
| // ASMArgRegister reg; | |||
| // ASMArgImmediate imm; | |||
| // ASMArgIndirect indirect; | |||
| // ASMArgIndexed index; | |||
| // ASMArgLabel label; | |||
| // ASMArgCondition cond; | |||
| DEBUG("parse_arg(): -->%.*s<-- %zu", (int) size, str, size) | |||
| if (parse_register(&arg->data.reg, str, size)) { | |||
| arg->type = AT_REGISTER; | |||
| return ED_NONE; | |||
| } | |||
| if (parse_condition(&arg->data.cond, str, size)) { | |||
| arg->type = AT_CONDITION; | |||
| return ED_NONE; | |||
| } | |||
| return ED_PS_ARG_SYNTAX; | |||
| } | |||
| @@ -190,6 +216,7 @@ static ASMErrorDesc parse_args( | |||
| if (i > start) { | |||
| if ((err = parse_arg(&args[*nargs], str + start, i - start, &symbol))) | |||
| return err; | |||
| (*nargs)++; | |||
| } | |||
| return ED_NONE; | |||
| } | |||
| @@ -254,6 +281,12 @@ INST_FUNC(adc) | |||
| } | |||
| */ | |||
| INST_FUNC(retn) | |||
| { | |||
| INST_TAKES_NO_ARGS | |||
| INST_RETURN(2, 0xED, 0x45) | |||
| } | |||
| /* | |||
| Return the relevant ASMInstParser function for a given mnemonic. | |||
| @@ -271,6 +304,7 @@ ASMInstParser get_inst_parser(char mstr[MAX_MNEMONIC_SIZE]) | |||
| HANDLE(inc) | |||
| // HANDLE(add) | |||
| // HANDLE(adc) | |||
| HANDLE(retn) | |||
| return NULL; | |||
| } | |||
| @@ -12,6 +12,8 @@ | |||
| #define MAX_REGION_SIZE 32 | |||
| #define LCASE(c) ((c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c) | |||
| #define DIRECTIVE_PARSE_FUNC(name, type) \ | |||
| bool dparse_##name(type *result, const ASMLine *line, const char *directive) | |||
| @@ -180,14 +182,12 @@ bool parse_register(ASMArgRegister *result, const char *arg, ssize_t size) | |||
| if (size < 1 || size > 3) | |||
| return false; | |||
| #define LCASE(c) ((c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c) | |||
| char buf[3] = {'\0'}; | |||
| switch (size) { | |||
| case 3: buf[2] = LCASE(arg[2]); | |||
| case 2: buf[1] = LCASE(arg[1]); | |||
| case 1: buf[0] = LCASE(arg[0]); | |||
| } | |||
| #undef LCASE | |||
| switch (size) { | |||
| case 1: | |||
| @@ -209,7 +209,7 @@ bool parse_register(ASMArgRegister *result, const char *arg, ssize_t size) | |||
| case 0x6166: return (*result = REG_AF), true; | |||
| case 0x6263: return (*result = REG_BC), true; | |||
| case 0x6465: return (*result = REG_DE), true; | |||
| case 0x686c: return (*result = REG_HL), true; | |||
| case 0x686C: return (*result = REG_HL), true; | |||
| case 0x6978: return (*result = REG_IX), true; | |||
| case 0x6979: return (*result = REG_IY), true; | |||
| case 0x7063: return (*result = REG_PC), true; | |||
| @@ -220,9 +220,44 @@ bool parse_register(ASMArgRegister *result, const char *arg, ssize_t size) | |||
| switch ((buf[0] << 16) + (buf[1] << 8) + buf[2]) { | |||
| case 0x616627: return (*result = REG_AF_), true; | |||
| case 0x697868: return (*result = REG_IXH), true; | |||
| case 0x69786c: return (*result = REG_IXL), true; | |||
| case 0x69786C: return (*result = REG_IXL), true; | |||
| case 0x697968: return (*result = REG_IYH), true; | |||
| case 0x69796c: return (*result = REG_IYL), true; | |||
| case 0x69796C: return (*result = REG_IYL), true; | |||
| } | |||
| return false; | |||
| } | |||
| return false; | |||
| } | |||
| /* | |||
| Read in a register argument and store it in *result. | |||
| */ | |||
| bool parse_condition(ASMArgCondition *result, const char *arg, ssize_t size) | |||
| { | |||
| if (size < 1 || size > 2) | |||
| return false; | |||
| char buf[2] = {'\0'}; | |||
| switch (size) { | |||
| case 2: buf[1] = LCASE(arg[1]); | |||
| case 1: buf[0] = LCASE(arg[0]); | |||
| } | |||
| switch (size) { | |||
| case 1: | |||
| switch (buf[0]) { | |||
| case 'n': return (*result = COND_N), true; | |||
| case 'c': return (*result = COND_C), true; | |||
| case 'p': return (*result = COND_P), true; | |||
| case 'm': return (*result = COND_M), true; | |||
| } | |||
| return false; | |||
| case 2: | |||
| switch ((buf[0] << 8) + buf[1]) { | |||
| case 0x6E7A: return (*result = COND_NZ), true; | |||
| case 0x6E63: return (*result = COND_NC), true; | |||
| case 0x706F: return (*result = COND_PO), true; | |||
| case 0x7065: return (*result = COND_PE), true; | |||
| } | |||
| return false; | |||
| } | |||
| @@ -17,7 +17,9 @@ bool parse_bool(bool*, const char*, ssize_t); | |||
| bool parse_uint32_t(uint32_t*, const char*, ssize_t); | |||
| bool parse_string(char**, size_t*, const char*, ssize_t); | |||
| bool parse_bytes(uint8_t**, size_t*, const char*, ssize_t); | |||
| bool parse_register(ASMArgRegister*, const char*, ssize_t); | |||
| bool parse_condition(ASMArgCondition*, const char*, ssize_t); | |||
| bool dparse_bool(bool*, const ASMLine*, const char*); | |||
| bool dparse_uint32_t(uint32_t*, const ASMLine*, const char*); | |||
| @@ -57,7 +57,7 @@ static inline int8_t default_bank_slot(uint8_t bank) | |||
| Add a given line, representing a label, to the symbol table. | |||
| Return NULL on success and an ErrorInfo object on failure (e.g. in the case | |||
| of duplicate labels). | |||
| of duplicate labels, or labels sharing names with registers/conditions). | |||
| */ | |||
| static ErrorInfo* add_label_to_table( | |||
| ASMSymbolTable *symtable, const ASMLine *line, size_t offset, int8_t slot) | |||
| @@ -66,6 +66,10 @@ static ErrorInfo* add_label_to_table( | |||
| if (parse_register(®, line->data, line->length - 1)) | |||
| return error_info_create(line, ET_SYMBOL, ED_SYM_IS_REGISTER); | |||
| ASMArgCondition cond; | |||
| if (parse_condition(&cond, line->data, line->length - 1)) | |||
| return error_info_create(line, ET_SYMBOL, ED_SYM_IS_CONDITION); | |||
| char *symbol = strndup(line->data, line->length - 1); | |||
| if (!symbol) | |||
| OUT_OF_MEMORY() | |||