From 8bbca15e472fb6f54f32b05f66f7702ab7944874 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sat, 2 May 2015 19:04:49 -0500 Subject: [PATCH] Parse condition codes. --- src/assembler/errors.c | 1 + src/assembler/errors.h | 1 + src/assembler/instructions.c | 54 ++++++++++++++++++++++++++++++++++++-------- src/assembler/parse_util.c | 45 ++++++++++++++++++++++++++++++++---- src/assembler/parse_util.h | 2 ++ src/assembler/tokenizer.c | 6 ++++- 6 files changed, 93 insertions(+), 16 deletions(-) diff --git a/src/assembler/errors.c b/src/assembler/errors.c index 525798b..12b7dc0 100644 --- a/src/assembler/errors.c +++ b/src/assembler/errors.c @@ -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)", diff --git a/src/assembler/errors.h b/src/assembler/errors.h index 12eff48..1b624bb 100644 --- a/src/assembler/errors.h +++ b/src/assembler/errors.h @@ -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, diff --git a/src/assembler/instructions.c b/src/assembler/instructions.c index 8508154..f6d8071 100644 --- a/src/assembler/instructions.c +++ b/src/assembler/instructions.c @@ -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; } diff --git a/src/assembler/parse_util.c b/src/assembler/parse_util.c index f5d15af..6dbd586 100644 --- a/src/assembler/parse_util.c +++ b/src/assembler/parse_util.c @@ -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; } diff --git a/src/assembler/parse_util.h b/src/assembler/parse_util.h index 011f517..44b98bf 100644 --- a/src/assembler/parse_util.h +++ b/src/assembler/parse_util.h @@ -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*); diff --git a/src/assembler/tokenizer.c b/src/assembler/tokenizer.c index 5b1208e..93baade 100644 --- a/src/assembler/tokenizer.c +++ b/src/assembler/tokenizer.c @@ -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()