diff --git a/src/assembler/inst_args.h b/src/assembler/inst_args.h index 8e43585..b900f83 100644 --- a/src/assembler/inst_args.h +++ b/src/assembler/inst_args.h @@ -34,7 +34,8 @@ typedef enum { typedef struct { ASMArgImmType mask; - uint16_t value; + uint16_t uval; + int16_t sval; } ASMArgImmediate; typedef struct { diff --git a/src/assembler/instructions.c b/src/assembler/instructions.c index f6d8071..dbe97e6 100644 --- a/src/assembler/instructions.c +++ b/src/assembler/instructions.c @@ -147,35 +147,30 @@ static uint8_t fill_bytes_variadic(uint8_t *bytes, size_t len, ...) static ASMErrorDesc parse_arg( ASMInstArg *arg, const char *str, size_t size, char **symbol) { - // TODO +#define USE_PARSER(func, argtype, field) \ + if (argparse_##func(&arg->data.field, str, size)) { \ + arg->type = argtype; \ + return ED_NONE; \ + } - // AT_REGISTER - // AT_IMMEDIATE - // AT_INDIRECT - // AT_INDEXED - // AT_LABEL - // AT_CONDITION + DEBUG("parse_arg(): -->%.*s<-- %zu", (int) size, str, size) + USE_PARSER(register, AT_REGISTER, reg) + USE_PARSER(immediate, AT_IMMEDIATE, imm) - // ASMArgRegister reg; - // ASMArgImmediate imm; + // AT_INDIRECT // ASMArgIndirect indirect; - // ASMArgIndexed index; - // ASMArgLabel label; - // ASMArgCondition cond; - DEBUG("parse_arg(): -->%.*s<-- %zu", (int) size, str, size) + // AT_INDEXED + // ASMArgIndexed index; - if (parse_register(&arg->data.reg, str, size)) { - arg->type = AT_REGISTER; - return ED_NONE; - } + USE_PARSER(condition, AT_CONDITION, cond) - if (parse_condition(&arg->data.cond, str, size)) { - arg->type = AT_CONDITION; - return ED_NONE; - } + // AT_LABEL + // ASMArgLabel label; return ED_PS_ARG_SYNTAX; + +#undef USE_PARSER } /* @@ -193,6 +188,8 @@ static ASMErrorDesc parse_args( while (i < size) { char c = str[i]; if (c == ',') { + if (i == start) + return ED_PS_ARG_SYNTAX; if ((err = parse_arg(&args[*nargs], str + start, i - start, &symbol))) return err; (*nargs)++; @@ -201,7 +198,9 @@ static ASMErrorDesc parse_args( if (i < size && str[i] == ' ') i++; start = i; - if (*nargs >= 3 && i < size) + if (i == size) + return ED_PS_ARG_SYNTAX; + if (*nargs >= 3) return ED_PS_TOO_MANY_ARGS; } else { if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || diff --git a/src/assembler/parse_util.c b/src/assembler/parse_util.c index 6dbd586..e6362c1 100644 --- a/src/assembler/parse_util.c +++ b/src/assembler/parse_util.c @@ -177,7 +177,7 @@ bool parse_bytes(uint8_t **result, size_t *length, const char *arg, ssize_t size /* Read in a register argument and store it in *result. */ -bool parse_register(ASMArgRegister *result, const char *arg, ssize_t size) +bool argparse_register(ASMArgRegister *result, const char *arg, ssize_t size) { if (size < 1 || size > 3) return false; @@ -232,7 +232,7 @@ bool parse_register(ASMArgRegister *result, const char *arg, ssize_t size) /* Read in a register argument and store it in *result. */ -bool parse_condition(ASMArgCondition *result, const char *arg, ssize_t size) +bool argparse_condition(ASMArgCondition *result, const char *arg, ssize_t size) { if (size < 1 || size > 2) return false; @@ -265,6 +265,55 @@ bool parse_condition(ASMArgCondition *result, const char *arg, ssize_t size) } /* + Read in an immediate argument and store it in *result. +*/ +bool argparse_immediate(ASMArgImmediate *result, const char *arg, ssize_t size) +{ + bool negative = false; + ssize_t i = 0; + + if (size <= 0) + return false; + + while (arg[i] == '-' || arg[i] == '+' || arg[i] == ' ') { + if (arg[i] == '-') + negative = !negative; + if (++i >= size) + return false; + } + + uint32_t uval; + if (parse_uint32_t(&uval, arg, size) && uval > UINT16_MAX) + return false; + + int32_t sval = negative ? uval : -uval; + if (sval < INT16_MIN) + return false; + + result->uval = uval; + result->sval = sval; + result->mask = 0; + + if (negative) { + if (sval >= INT8_MIN && sval <= INT8_MAX) + result->mask |= IMM_S8; + if (sval >= INT8_MIN + 2 && sval <= INT8_MAX + 2) + result->mask |= IMM_REL; + } else { + result->mask = IMM_U16; + if (uval <= UINT8_MAX) + result->mask |= IMM_U8; + if (uval <= 7) + result->mask |= IMM_BIT; + if (!(uval & ~0x38)) + result->mask |= IMM_RST; + if (uval <= 2) + result->mask |= IMM_IM; + } + return true; +} + +/* Read in a boolean argument from the given line and store it in *result. */ DIRECTIVE_PARSE_FUNC(bool, bool) diff --git a/src/assembler/parse_util.h b/src/assembler/parse_util.h index 44b98bf..38c06be 100644 --- a/src/assembler/parse_util.h +++ b/src/assembler/parse_util.h @@ -13,19 +13,22 @@ /* Functions */ +/* General parsers */ 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); +/* Instruction argument parsers */ +bool argparse_register(ASMArgRegister*, const char*, ssize_t); +bool argparse_condition(ASMArgCondition*, const char*, ssize_t); +bool argparse_immediate(ASMArgImmediate*, const char*, ssize_t); +/* Preprocessor directive parsers */ bool dparse_bool(bool*, const ASMLine*, const char*); bool dparse_uint32_t(uint32_t*, const ASMLine*, const char*); bool dparse_uint16_t(uint16_t*, const ASMLine*, const char*); bool dparse_uint8_t(uint8_t*, const ASMLine*, const char*); - bool dparse_rom_size(uint32_t*, const ASMLine*, const char*); bool dparse_region_string(uint8_t*, const ASMLine*, const char*); bool dparse_size_code(uint8_t*, const ASMLine*, const char*); diff --git a/src/assembler/tokenizer.c b/src/assembler/tokenizer.c index 93baade..9e51f3e 100644 --- a/src/assembler/tokenizer.c +++ b/src/assembler/tokenizer.c @@ -63,11 +63,11 @@ static ErrorInfo* add_label_to_table( ASMSymbolTable *symtable, const ASMLine *line, size_t offset, int8_t slot) { ASMArgRegister reg; - if (parse_register(®, line->data, line->length - 1)) + if (argparse_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)) + if (argparse_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);