diff options
author | Oxore <oxore@protonmail.com> | 2023-08-09 00:41:52 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2023-08-09 00:41:52 +0300 |
commit | 8417537e503f86a8a659d64418c7b2547d555b51 (patch) | |
tree | 3af81a0b11073f620062ad9d8ecdbe392e4dd400 /main.c | |
parent | 5c5c60a18b41d2f5a077d5fa8fa8b266db537578 (diff) |
Finally fix parsing indirect indexed addr args
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 94 |
1 files changed, 87 insertions, 7 deletions
@@ -50,6 +50,8 @@ #define E_MNEMONIC "valid instruction mnemonic" #define E_INSN_SIZE_SPEC "'.s', '.b', '.w' or '.l'" #define E_ADDR_SIZE_SPEC "'.b', '.w' or '.l'" +#define E_ADDR_INDIR_SIZE_SPEC "'.w' or '.l'" +#define E_ADDR_INDIR_MULTIPLE_INDEX_REGS "multiple index registers specified" #define E_ARGS_COUNT "invalid arguments count" #define E_NL "new line, which is '\\n', '\\r\\n' or '\\r'" #define E_COMMENT_NL "';' or " E_NL @@ -397,6 +399,7 @@ struct arg { uint16_t regmask; ///< For regmask (movem only) uint8_t xn; ///< For Dn, An, (An), -(An), (An)+, (d16,An) uint8_t xi; ///< For (d8,An,Xi) and (d8,PC,Xi), it has 0x8 mask set if An + enum opsize briefext_size; struct expr_tokens_span expr; size_t first_token, num_tokens; ///< Argument tokens span }; @@ -1518,6 +1521,10 @@ static void fprint_arg( fprintf(s, " reg [a%d]", arg->xn); fprintf(s, " d8 "), fprint_expr(lex, &arg->expr, s); fprintf(s, " xi [%c%d]", arg->xi & 0x8 ? 'a' : 'd', arg->xi & 0x7); + { + const char size = arg->briefext_size == OPSIZE_L ? 'l' : 'w'; + fprintf(s, " briefext_size [%c]", size); + } break; case ARG_ADDR_WORD: case ARG_ADDR_LONG: @@ -2075,7 +2082,7 @@ static int pars_parse_arg_after_prefix_expr( arg->type = ARG_ADDR_UNSPEC; return OK; } - const struct token token0 = pars_peek(self); + struct token token0 = pars_peek(self); if (token0.type == TT_DOT_ID) { // It must be a size specifier, or error otherwise const size_t size_spec_id = pars_commit(self); @@ -2088,13 +2095,19 @@ static int pars_parse_arg_after_prefix_expr( return pars_yield_error(self, size_spec_id, E_ADDR_SIZE_SPEC); } arg->type = addrsize == OPSIZE_L ? ARG_ADDR_LONG : ARG_ADDR_WORD; + } else if (token0.type != TT_LPAREN) { + // It was a standalone expression without size suffix, yield an + // argument from here + arg->type = ARG_ADDR_UNSPEC; return OK; - } else if (token0.type == TT_LPAREN) { - // It was a prefix expression for (An), (PC), (An,Xn) or (PC,Xn) + } + // Suffix must be read anyway + if (pars_peek(self).type == TT_LPAREN) { + // It is a prefix expression for (An), (PC), (An,Xn) or (PC,Xn) pars_commit(self); return pars_parse_arg_inside_parens(self, arg); } - // It was a standalone expression without size suffix, yield an + // It is a standalone expression with or without size suffix, yield an // argument from here arg->type = ARG_ADDR_UNSPEC; return OK; @@ -2153,6 +2166,7 @@ static int pars_parse_arg_starts_with_minus( struct inside_parens_state { bool an1_found, an2_found, dn_found, pc_found; + enum opsize size; uint8_t an1, an2, dn, parts; }; @@ -2167,10 +2181,35 @@ static int pars_parse_arg_inside_parens_single_item( struct token_recognition r = pars_recognize_token(self, token0); if (r.type == RTT_REG) { // This is definitely a register or regmask. + bool it_is_pc = false; + const size_t token0_id = pars_commit(self); + struct token_recognition r = pars_recognize_token(self, token0); switch (r.reg) { case REG_DN: state->dn_found = true; state->dn = r.reg_num; + const struct token token_size_spec = pars_peek(self); + if (token_size_spec.type == TT_DOT_ID) { + // It must be a size specifier, or error otherwise + const size_t size_spec_id = pars_commit(self); + if (token_size_spec.length != 2) { + return pars_yield_error( + self, size_spec_id, E_ADDR_INDIR_SIZE_SPEC); + } + const char c = self->lex->input[token_size_spec.offset + 1]; + const enum opsize addrsize = get_opsize_from_specifier(c); + if (addrsize != OPSIZE_W && addrsize != OPSIZE_L) { + return pars_yield_error( + self, size_spec_id, E_ADDR_INDIR_SIZE_SPEC); + } + if (state->size != OPSIZE_NONE) { + return pars_yield_error_msg( + self, + size_spec_id, + E_ADDR_INDIR_MULTIPLE_INDEX_REGS); + } + state->size = addrsize; + } break; case REG_AN: if (!state->an1_found) { @@ -2180,26 +2219,65 @@ static int pars_parse_arg_inside_parens_single_item( state->an2_found = true; state->an2 = r.reg_num; } else { - return pars_yield_error(self, pars_commit(self), E_EA_PART_NOT_AN); + return pars_yield_error( + self, token0_id, E_EA_PART_NOT_AN); } break; case REG_PC: state->pc_found = true; + it_is_pc = true; break; case REG_NONE: UNREACHABLE(); case REG_SR: case REG_CCR: case REG_USP: - return pars_yield_error(self, pars_commit(self), E_EA_PART); + return pars_yield_error(self, token0_id, E_EA_PART); + } + if (!it_is_pc) { + const struct token token_size_spec = pars_peek(self); + if (token_size_spec.type == TT_DOT_ID) { + // It must be a size specifier, or error otherwise + const size_t size_spec_id = pars_commit(self); + if (token_size_spec.length != 2) { + return pars_yield_error( + self, size_spec_id, E_ADDR_INDIR_SIZE_SPEC); + } + const char c = self->lex->input[token_size_spec.offset + 1]; + const enum opsize addrsize = get_opsize_from_specifier(c); + if (addrsize != OPSIZE_W && addrsize != OPSIZE_L) { + return pars_yield_error( + self, size_spec_id, E_ADDR_INDIR_SIZE_SPEC); + } + if (state->size != OPSIZE_NONE) { + return pars_yield_error_msg( + self, + size_spec_id, + E_ADDR_INDIR_MULTIPLE_INDEX_REGS); + } + state->size = addrsize; + } } - pars_commit(self); } } else if (arg->expr.first_token == 0) { const int ret = pars_parse_expr(self, &arg->expr); if (ret != OK) { return ret; } + const struct token token_size_spec = pars_peek(self); + if (token_size_spec.type == TT_DOT_ID) { + // It must be a size specifier, or error otherwise + const size_t size_spec_id = pars_commit(self); + if (token_size_spec.length != 2) { + return pars_yield_error(self, size_spec_id, E_ADDR_SIZE_SPEC); + } + const char c = self->lex->input[token_size_spec.offset + 1]; + const enum opsize addrsize = get_opsize_from_specifier(c); + if (addrsize == OPSIZE_NONE || addrsize == OPSIZE_S) { + return pars_yield_error(self, size_spec_id, E_ADDR_SIZE_SPEC); + } + // Just skip it, because it does not matter + } } else { return pars_yield_error(self, self->cur_tok_id, E_EA_PART_NOT_EXPR); } @@ -2295,6 +2373,7 @@ static int pars_parse_arg_inside_parens( arg->type = ARG_PC_ADDR_8_XI; arg->xi = state.an1_found ? (state.an1 | 0x8) : state.dn; arg->num_tokens = self->cur_tok_id - arg->first_token; + arg->briefext_size = state.size; return OK; } else if (state.parts == 3 && state.an1_found && arg->expr.first_token && (state.an2_found || state.dn_found)) { // It is (d8,An,Xn) @@ -2302,6 +2381,7 @@ static int pars_parse_arg_inside_parens( arg->type = ARG_AN_ADDR_8_XI; arg->xi = state.an2_found ? (state.an2 | 0x8) : state.dn; arg->num_tokens = self->cur_tok_id - arg->first_token; + arg->briefext_size = state.size; return OK; } return pars_yield_error_msg(self, self->cur_tok_id, E_EA_INVALID); |