@@ -43,6 +43,7 @@ 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_SYM_IS_REGISTER] = "labels cannot share names with registers", | [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_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_TOO_SHORT] = "opcode mnemonic is too short (2-4 characters)", | ||||
@@ -42,6 +42,7 @@ typedef enum { | |||||
ED_SYM_DUPE_LABELS, | ED_SYM_DUPE_LABELS, | ||||
ED_SYM_NO_LABEL, | ED_SYM_NO_LABEL, | ||||
ED_SYM_IS_REGISTER, | ED_SYM_IS_REGISTER, | ||||
ED_SYM_IS_CONDITION, | |||||
ED_PS_OP_TOO_LONG, | ED_PS_OP_TOO_LONG, | ||||
ED_PS_OP_TOO_SHORT, | ED_PS_OP_TOO_SHORT, | ||||
@@ -6,6 +6,7 @@ | |||||
#include "instructions.h" | #include "instructions.h" | ||||
#include "inst_args.h" | #include "inst_args.h" | ||||
#include "parse_util.h" | |||||
#include "../logging.h" | #include "../logging.h" | ||||
/* | /* | ||||
@@ -81,7 +82,7 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||||
if (!arg) \ | if (!arg) \ | ||||
INST_ERROR(TOO_FEW_ARGS) \ | INST_ERROR(TOO_FEW_ARGS) \ | ||||
ASMInstArg args[3]; \ | ASMInstArg args[3]; \ | ||||
size_t nargs; \ | |||||
size_t nargs = 0; \ | |||||
ASMErrorDesc err = parse_args(args, &nargs, arg, size); \ | ASMErrorDesc err = parse_args(args, &nargs, arg, size); \ | ||||
if (err) \ | if (err) \ | ||||
return err; \ | return err; \ | ||||
@@ -90,14 +91,13 @@ static ASMErrorDesc parse_inst_##mnemonic( \ | |||||
if (nargs > hi) \ | if (nargs > hi) \ | ||||
INST_ERROR(TOO_MANY_ARGS) | 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_REG_PREFIX(n) INST_PREFIX_(INST_REG(n)) | ||||
#define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg) | #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) | ASMInstArg *arg, const char *str, size_t size, char **symbol) | ||||
{ | { | ||||
// TODO | // 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; | return ED_PS_ARG_SYNTAX; | ||||
} | } | ||||
@@ -190,6 +216,7 @@ static ASMErrorDesc parse_args( | |||||
if (i > start) { | if (i > start) { | ||||
if ((err = parse_arg(&args[*nargs], str + start, i - start, &symbol))) | if ((err = parse_arg(&args[*nargs], str + start, i - start, &symbol))) | ||||
return err; | return err; | ||||
(*nargs)++; | |||||
} | } | ||||
return ED_NONE; | 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. | 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(inc) | ||||
// HANDLE(add) | // HANDLE(add) | ||||
// HANDLE(adc) | // HANDLE(adc) | ||||
HANDLE(retn) | |||||
return NULL; | return NULL; | ||||
} | } |
@@ -12,6 +12,8 @@ | |||||
#define MAX_REGION_SIZE 32 | #define MAX_REGION_SIZE 32 | ||||
#define LCASE(c) ((c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c) | |||||
#define DIRECTIVE_PARSE_FUNC(name, type) \ | #define DIRECTIVE_PARSE_FUNC(name, type) \ | ||||
bool dparse_##name(type *result, const ASMLine *line, const char *directive) | 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) | if (size < 1 || size > 3) | ||||
return false; | return false; | ||||
#define LCASE(c) ((c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c) | |||||
char buf[3] = {'\0'}; | char buf[3] = {'\0'}; | ||||
switch (size) { | switch (size) { | ||||
case 3: buf[2] = LCASE(arg[2]); | case 3: buf[2] = LCASE(arg[2]); | ||||
case 2: buf[1] = LCASE(arg[1]); | case 2: buf[1] = LCASE(arg[1]); | ||||
case 1: buf[0] = LCASE(arg[0]); | case 1: buf[0] = LCASE(arg[0]); | ||||
} | } | ||||
#undef LCASE | |||||
switch (size) { | switch (size) { | ||||
case 1: | 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 0x6166: return (*result = REG_AF), true; | ||||
case 0x6263: return (*result = REG_BC), true; | case 0x6263: return (*result = REG_BC), true; | ||||
case 0x6465: return (*result = REG_DE), 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 0x6978: return (*result = REG_IX), true; | ||||
case 0x6979: return (*result = REG_IY), true; | case 0x6979: return (*result = REG_IY), true; | ||||
case 0x7063: return (*result = REG_PC), 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]) { | switch ((buf[0] << 16) + (buf[1] << 8) + buf[2]) { | ||||
case 0x616627: return (*result = REG_AF_), true; | case 0x616627: return (*result = REG_AF_), true; | ||||
case 0x697868: return (*result = REG_IXH), 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 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; | 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_uint32_t(uint32_t*, const char*, ssize_t); | ||||
bool parse_string(char**, size_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_bytes(uint8_t**, size_t*, const char*, ssize_t); | ||||
bool parse_register(ASMArgRegister*, 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_bool(bool*, const ASMLine*, const char*); | ||||
bool dparse_uint32_t(uint32_t*, 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. | 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 | 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( | static ErrorInfo* add_label_to_table( | ||||
ASMSymbolTable *symtable, const ASMLine *line, size_t offset, int8_t slot) | 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)) | if (parse_register(®, line->data, line->length - 1)) | ||||
return error_info_create(line, ET_SYMBOL, ED_SYM_IS_REGISTER); | 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); | char *symbol = strndup(line->data, line->length - 1); | ||||
if (!symbol) | if (!symbol) | ||||
OUT_OF_MEMORY() | OUT_OF_MEMORY() | ||||