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