@@ -49,21 +49,20 @@ | |||
#define INST_FUNC(mnemonic) \ | |||
static ASMErrorDesc parse_inst_##mnemonic( \ | |||
uint8_t **bytes, size_t *length, char **symbol, const char *arg, size_t size) | |||
uint8_t **bytes, size_t *length, char **symbol, ASMArgParseInfo ap_info) \ | |||
#define INST_ERROR(desc) return ED_PS_##desc; | |||
#define INST_TAKES_NO_ARGS \ | |||
if (arg) \ | |||
if (ap_info.arg) \ | |||
INST_ERROR(TOO_MANY_ARGS) \ | |||
(void) size; | |||
#define INST_TAKES_ARGS(lo, hi) \ | |||
if (!arg) \ | |||
if (!ap_info.arg) \ | |||
INST_ERROR(TOO_FEW_ARGS) \ | |||
ASMInstArg args[3]; \ | |||
size_t nargs = 0; \ | |||
ASMErrorDesc err = parse_args(args, &nargs, arg, size); \ | |||
ASMErrorDesc err = parse_args(args, &nargs, ap_info); \ | |||
if (err) \ | |||
return err; \ | |||
if (nargs < lo) \ | |||
@@ -143,14 +142,16 @@ static uint8_t fill_bytes_variadic(uint8_t *bytes, size_t len, ...) | |||
Return ED_NONE (0) on success or an error code on failure. | |||
*/ | |||
static ASMErrorDesc parse_arg(ASMInstArg *arg, const char *str, size_t size) | |||
static ASMErrorDesc parse_arg( | |||
ASMInstArg *arg, const char *str, size_t size, ASMDefineTable *deftable) | |||
{ | |||
#define TRY_PARSER(func, argtype, field) \ | |||
if (argparse_##func(&arg->data.field, str, size)) { \ | |||
if (argparse_##func(&arg->data.field, info)) { \ | |||
arg->type = argtype; \ | |||
return ED_NONE; \ | |||
} | |||
ASMArgParseInfo info = {.arg = str, .size = size, .deftable = deftable}; | |||
DEBUG("parse_arg(): -->%.*s<-- %zu", (int) size, str, size) | |||
TRY_PARSER(register, AT_REGISTER, reg) | |||
TRY_PARSER(immediate, AT_IMMEDIATE, imm) | |||
@@ -164,22 +165,24 @@ static ASMErrorDesc parse_arg(ASMInstArg *arg, const char *str, size_t size) | |||
} | |||
/* | |||
Parse an argument string int ASMInstArg objects. | |||
Parse an argument string into ASMInstArg objects. | |||
Return ED_NONE (0) on success or an error code on failure. | |||
*/ | |||
static ASMErrorDesc parse_args( | |||
ASMInstArg args[3], size_t *nargs, const char *str, size_t size) | |||
ASMInstArg args[3], size_t *nargs, ASMArgParseInfo ap_info) | |||
{ | |||
ASMErrorDesc err; | |||
size_t start = 0, i = 0; | |||
ASMDefineTable *dt = ap_info.deftable; | |||
const char *str = ap_info.arg; | |||
size_t size = ap_info.size, start = 0, i = 0; | |||
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))) | |||
if ((err = parse_arg(&args[*nargs], str + start, i - start, dt))) | |||
return err; | |||
(*nargs)++; | |||
@@ -202,7 +205,7 @@ static ASMErrorDesc parse_args( | |||
} | |||
if (i > start) { | |||
if ((err = parse_arg(&args[*nargs], str + start, i - start))) | |||
if ((err = parse_arg(&args[*nargs], str + start, i - start, dt))) | |||
return err; | |||
(*nargs)++; | |||
} | |||
@@ -6,6 +6,7 @@ | |||
#include <stdint.h> | |||
#include "errors.h" | |||
#include "parse_util.h" | |||
#define MIN_MNEMONIC_SIZE 2 | |||
#define MAX_MNEMONIC_SIZE 4 | |||
@@ -13,7 +14,7 @@ | |||
/* Typedefs */ | |||
typedef ASMErrorDesc (*ASMInstParser)( | |||
uint8_t**, size_t*, char**, const char*, size_t); | |||
uint8_t**, size_t*, char**, ASMArgParseInfo); | |||
/* Functions */ | |||
@@ -25,15 +25,15 @@ | |||
*/ | |||
/* | |||
Adjust *arg_ptr / *size_ptr for an indirect argument, like (hl) or (ix+*). | |||
Adjust *ap_info for an indirect argument, like (hl) or (ix+*). | |||
*size_ptr must be > 2 to begin with, and is assured to be > 0 on success. | |||
The two arguments are not modified on failure. | |||
ap_info->size must be > 2 to begin with, and will always be > 0 on success. | |||
*ap_info is not modified on failure. | |||
*/ | |||
static bool adjust_for_indirection(const char **arg_ptr, ssize_t *size_ptr) | |||
static bool adjust_for_indirection(ASMArgParseInfo *ap_info) | |||
{ | |||
const char *arg = *arg_ptr; | |||
ssize_t size = *size_ptr; | |||
const char *arg = ap_info->arg; | |||
ssize_t size = ap_info->size; | |||
if (arg[0] != '(' || arg[size - 1] != ')') | |||
return false; | |||
@@ -50,8 +50,8 @@ static bool adjust_for_indirection(const char **arg_ptr, ssize_t *size_ptr) | |||
return false; | |||
} | |||
*arg_ptr = arg; | |||
*size_ptr = size; | |||
ap_info->arg = arg; | |||
ap_info->size = size; | |||
return true; | |||
} | |||
@@ -208,19 +208,19 @@ 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 argparse_register(ASMArgRegister *result, const char *arg, ssize_t size) | |||
bool argparse_register(ASMArgRegister *result, ASMArgParseInfo ai) | |||
{ | |||
if (size < 1 || size > 3) | |||
if (ai.size < 1 || ai.size > 3) | |||
return false; | |||
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]); | |||
switch (ai.size) { | |||
case 3: buf[2] = LCASE(ai.arg[2]); | |||
case 2: buf[1] = LCASE(ai.arg[1]); | |||
case 1: buf[0] = LCASE(ai.arg[0]); | |||
} | |||
switch (size) { | |||
switch (ai.size) { | |||
case 1: | |||
switch (buf[0]) { | |||
case 'a': return (*result = REG_A), true; | |||
@@ -263,18 +263,18 @@ bool argparse_register(ASMArgRegister *result, const char *arg, ssize_t size) | |||
/* | |||
Read in a condition argument and store it in *result. | |||
*/ | |||
bool argparse_condition(ASMArgCondition *result, const char *arg, ssize_t size) | |||
bool argparse_condition(ASMArgCondition *result, ASMArgParseInfo ai) | |||
{ | |||
if (size < 1 || size > 2) | |||
if (ai.size < 1 || ai.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 (ai.size) { | |||
case 2: buf[1] = LCASE(ai.arg[1]); | |||
case 1: buf[0] = LCASE(ai.arg[0]); | |||
} | |||
switch (size) { | |||
switch (ai.size) { | |||
case 1: | |||
switch (buf[0]) { | |||
case 'n': return (*result = COND_N), true; | |||
@@ -298,23 +298,25 @@ bool argparse_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 argparse_immediate(ASMArgImmediate *result, ASMArgParseInfo ai) | |||
{ | |||
if (ai.size <= 0) | |||
return false; | |||
// TODO: lookup here for definition table | |||
bool negative = false; | |||
ssize_t i = 0; | |||
if (size <= 0) | |||
return false; | |||
while (arg[i] == '-' || arg[i] == '+' || arg[i] == ' ') { | |||
if (arg[i] == '-') | |||
while (ai.arg[i] == '-' || ai.arg[i] == '+' || ai.arg[i] == ' ') { | |||
if (ai.arg[i] == '-') | |||
negative = !negative; | |||
if (++i >= size) | |||
if (++i >= ai.size) | |||
return false; | |||
} | |||
uint32_t uval; | |||
if (!parse_uint32_t(&uval, arg + i, size - i) || uval > UINT16_MAX) | |||
if (!parse_uint32_t(&uval, ai.arg + i, ai.size - i) || uval > UINT16_MAX) | |||
return false; | |||
int32_t sval = negative ? -uval : uval; | |||
@@ -351,20 +353,20 @@ bool argparse_immediate(ASMArgImmediate *result, const char *arg, ssize_t size) | |||
/* | |||
Read in an indirect argument and store it in *result. | |||
*/ | |||
bool argparse_indirect(ASMArgIndirect *result, const char *arg, ssize_t size) | |||
bool argparse_indirect(ASMArgIndirect *result, ASMArgParseInfo ai) | |||
{ | |||
if (size < 3 || !adjust_for_indirection(&arg, &size)) | |||
if (ai.size < 3 || !adjust_for_indirection(&ai)) | |||
return false; | |||
ASMArgRegister reg; | |||
ASMArgImmediate imm; | |||
if (argparse_register(®, arg, size)) { | |||
if (argparse_register(®, ai)) { | |||
if (reg == REG_BC || reg == REG_DE || reg == REG_HL) { | |||
result->type = AT_REGISTER; | |||
result->addr.reg = reg; | |||
return true; | |||
} | |||
} else if (argparse_immediate(&imm, arg, size)) { | |||
} else if (argparse_immediate(&imm, ai)) { | |||
if (imm.mask & IMM_U16) { | |||
result->type = AT_IMMEDIATE; | |||
result->addr.imm = imm; | |||
@@ -377,31 +379,31 @@ bool argparse_indirect(ASMArgIndirect *result, const char *arg, ssize_t size) | |||
/* | |||
Read in an indexed argument and store it in *result. | |||
*/ | |||
bool argparse_indexed(ASMArgIndexed *result, const char *arg, ssize_t size) | |||
bool argparse_indexed(ASMArgIndexed *result, ASMArgParseInfo ai) | |||
{ | |||
if (size < 4 || !adjust_for_indirection(&arg, &size) || size < 2) | |||
if (ai.size < 4 || !adjust_for_indirection(&ai) || ai.size < 2) | |||
return false; | |||
ASMArgRegister reg; | |||
if (arg[0] != 'i') | |||
if (ai.arg[0] != 'i') | |||
return false; | |||
if (arg[1] == 'x') | |||
if (ai.arg[1] == 'x') | |||
reg = REG_IX; | |||
else if (arg[1] == 'y') | |||
else if (ai.arg[1] == 'y') | |||
reg = REG_IY; | |||
else | |||
return false; | |||
arg += 2; | |||
size -= 2; | |||
if (size > 0 && arg[0] == ' ') { | |||
arg++; | |||
size--; | |||
ai.arg += 2; | |||
ai.size -= 2; | |||
if (ai.size > 0 && ai.arg[0] == ' ') { | |||
ai.arg++; | |||
ai.size--; | |||
} | |||
if (size > 0) { | |||
if (ai.size > 0) { | |||
ASMArgImmediate imm; | |||
if (!argparse_immediate(&imm, arg, size) || !(imm.mask & IMM_S8)) | |||
if (!argparse_immediate(&imm, ai) || !(imm.mask & IMM_S8)) | |||
return false; | |||
result->offset = imm.sval; | |||
} else { | |||
@@ -414,20 +416,22 @@ bool argparse_indexed(ASMArgIndexed *result, const char *arg, ssize_t size) | |||
/* | |||
Read in a label argument and store it in *result. | |||
*/ | |||
bool argparse_label(ASMArgLabel *result, const char *arg, ssize_t size) | |||
bool argparse_label(ASMArgLabel *result, ASMArgParseInfo ai) | |||
{ | |||
if (size >= MAX_SYMBOL_SIZE) | |||
if (ai.size <= 0 || ai.size >= MAX_SYMBOL_SIZE) | |||
return false; | |||
for (const char *i = arg; i < arg + size; i++) { | |||
// TODO: check for deftable | |||
for (const char *i = ai.arg; i < ai.arg + ai.size; i++) { | |||
char c = *i; | |||
if (!((c >= 'a' && c <= 'z') || (i != arg && c >= '0' && c <= '9') || | |||
c == '_' || c == '.')) | |||
if (!((c >= 'a' && c <= 'z') || c == '_' || c == '.' || | |||
(i != ai.arg && c >= '0' && c <= '9'))) | |||
return false; | |||
} | |||
strncpy(result->text, arg, size); | |||
result->text[size] = '\0'; | |||
strncpy(result->text, ai.arg, ai.size); | |||
result->text[ai.size] = '\0'; | |||
return true; | |||
} | |||
@@ -11,6 +11,14 @@ | |||
#define dparse__Bool dparse_bool | |||
/* Structs */ | |||
typedef struct { | |||
const char *arg; | |||
ssize_t size; | |||
ASMDefineTable *deftable; | |||
} ASMArgParseInfo; | |||
/* Functions */ | |||
/* General parsers */ | |||
@@ -20,12 +28,12 @@ bool parse_string(char**, size_t*, const char*, ssize_t); | |||
bool parse_bytes(uint8_t**, size_t*, 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); | |||
bool argparse_indirect(ASMArgIndirect*, const char*, ssize_t); | |||
bool argparse_indexed(ASMArgIndexed*, const char*, ssize_t); | |||
bool argparse_label(ASMArgLabel*, const char*, ssize_t); | |||
bool argparse_register(ASMArgRegister*, ASMArgParseInfo); | |||
bool argparse_condition(ASMArgCondition*, ASMArgParseInfo); | |||
bool argparse_immediate(ASMArgImmediate*, ASMArgParseInfo); | |||
bool argparse_indirect(ASMArgIndirect*, ASMArgParseInfo); | |||
bool argparse_indexed(ASMArgIndexed*, ASMArgParseInfo); | |||
bool argparse_label(ASMArgLabel*, ASMArgParseInfo); | |||
/* Preprocessor directive parsers */ | |||
bool dparse_bool(bool*, const ASMLine*, const char*); | |||
@@ -184,6 +184,16 @@ void asm_deftable_insert(ASMDefineTable *tab, ASMDefine *define) | |||
hash_table_insert(tab, (HashNode*) define); | |||
} | |||
/* | |||
Remove an ASMDefine from the define table. | |||
Return true if the node was removed, or false if it was not found. | |||
*/ | |||
bool asm_deftable_remove(ASMDefineTable *tab, const char *key) | |||
{ | |||
return hash_table_remove(tab, key); | |||
} | |||
#ifdef DEBUG_MODE | |||
/* | |||
DEBUG FUNCTION: Print out an ASMLine list to stdout. | |||
@@ -110,6 +110,7 @@ const ASMSymbol* asm_symtable_find(const ASMSymbolTable*, const char*); | |||
void asm_symtable_insert(ASMSymbolTable*, ASMSymbol*); | |||
const ASMDefine* asm_deftable_find(const ASMDefineTable*, const char*); | |||
void asm_deftable_insert(ASMDefineTable*, ASMDefine*); | |||
bool asm_deftable_remove(ASMDefineTable*, const char*); | |||
#ifdef DEBUG_MODE | |||
void asm_lines_print(const ASMLine*); | |||
@@ -94,12 +94,13 @@ static ErrorInfo* add_label_to_table( | |||
if (line->length - 1 >= MAX_SYMBOL_SIZE) | |||
return error_info_create(line, ET_SYMBOL, ED_SYM_TOO_LONG); | |||
ASMArgParseInfo info = {.arg = line->data, .size = line->length - 1}; | |||
ASMArgRegister reg; | |||
if (argparse_register(®, line->data, line->length - 1)) | |||
if (argparse_register(®, info)) | |||
return error_info_create(line, ET_SYMBOL, ED_SYM_IS_REGISTER); | |||
ASMArgCondition cond; | |||
if (argparse_condition(&cond, line->data, line->length - 1)) | |||
if (argparse_condition(&cond, info)) | |||
return error_info_create(line, ET_SYMBOL, ED_SYM_IS_CONDITION); | |||
char *symbol = strndup(line->data, line->length - 1); | |||
@@ -301,8 +302,8 @@ static ErrorInfo* parse_instruction( | |||
if (!parser) | |||
return error_info_create(line, ET_PARSER, ED_PS_OP_UNKNOWN); | |||
// TODO: pass deftab here? | |||
ASMErrorDesc edesc = parser(&bytes, &length, &symbol, argstart, arglen); | |||
ASMArgParseInfo ai = {.arg = argstart, .size = arglen, .deftable = deftab}; | |||
ASMErrorDesc edesc = parser(&bytes, &length, &symbol, ai); | |||
if (edesc != ED_NONE) | |||
return error_info_create(line, ET_PARSER, edesc); | |||