#include "gbasm/gb_types.h" #include "gbasm/opcodes.h" #include "gbasm/errors.h" #include "tri.h" #include "common.h" #include static bool operands_initted = false; static struct tri operand_tri; static struct tri prefixes_tri; static const struct gbasm_operand_info gbasm_operand_infos[] = { { .token = "a", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_8, .r8 = { .type = GBASM_OPERAND_R8_A }, } }, { .token = "b", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_8, .r8 = { .type = GBASM_OPERAND_R8_B }, }, }, { /* TODO: handle C condition code */ .token = "c", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_8, .r8 = { .type = GBASM_OPERAND_R8_C }, }, }, { .token = "d", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_8, .r8 = { .type = GBASM_OPERAND_R8_D }, }, }, { .token = "e", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_8, .r8 = { .type = GBASM_OPERAND_R8_E }, }, }, { .token = "h", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_8, .r8 = { .type = GBASM_OPERAND_R8_H }, }, }, { .token = "l", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_8, .r8 = { .type = GBASM_OPERAND_R8_L }, }, }, { .token = "bc", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_16, .r16 = { GBASM_OPERAND_R16_BC }, }, }, { .token = "de", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_16, .r16 = { GBASM_OPERAND_R16_DE }, }, }, { .token = "hl", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_16, .r16 = { GBASM_OPERAND_R16_HL }, }, }, { .token = "(hl)", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_16, .r16 = { GBASM_OPERAND_R16_HL_DEREF }, }, }, { .token = "sp", .fixed = true, .op_info = { .type = GBASM_OPERAND_REG_16, .r16 = { GBASM_OPERAND_R16_SP }, }, }, { .token = "nc", .fixed = true, .op_info = { .type = GBASM_OPERAND_COND, .cond = { GBASM_OPERAND_COND_NC }, }, }, { .token = "z", .fixed = true, .op_info = { .type = GBASM_OPERAND_COND, .cond = { GBASM_OPERAND_COND_Z }, }, }, { .token = "nz", .fixed = true, .op_info = { .type = GBASM_OPERAND_COND, .cond = { GBASM_OPERAND_COND_NZ }, }, }, }; static int convert_constant(const char *token, struct gbasm_operand *info) { int val = strtol(token + 1, NULL, 0); if (val <= 0xff || val >= -0xff) { info->type = GBASM_OPERAND_IMM_8; info->d8.value = val; } else if (val <= 0xffff || val >= 0xffff) { info->type = GBASM_OPERAND_IMM_16; info->d16.value = val; } else { return -1; } return 0; } static const struct gbasm_operand_prefix prefixes[] = { { .prefix = "$", .convert = convert_constant, }, }; static void init_opcode_tri() { int i; tri_init(&operand_tri); tri_init(&prefixes_tri); for (i = 0; i < ARRAY_SIZE(gbasm_operand_infos); i++) { tri_add_string(&operand_tri, gbasm_operand_infos[i].token, (void *) &gbasm_operand_infos[i]); } for (i = 0; i < ARRAY_SIZE(prefixes); i++) { tri_add_string(&prefixes_tri, prefixes[i].prefix, (void *) &prefixes[i]); } operands_initted = true; } int gbasm_parse_operand(const char *token, struct gbasm_operand *out) { struct gbasm_operand_info *info; struct gbasm_operand_prefix *prefix; if (!operands_initted) { init_opcode_tri(); } info = (struct gbasm_operand_info *) tri_get_string(&operand_tri, token); if (info != NULL) { if (info->fixed) { memcpy(out, &info->op_info, sizeof(*out)); } else { info->convert(token, out); } return 0; } prefix = (struct gbasm_operand_prefix *) tri_prefix_match(&prefixes_tri, token); if (prefix != NULL) { prefix->convert(token, out); return 0; } return -1; }