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 | |
parent | 5c5c60a18b41d2f5a077d5fa8fa8b266db537578 (diff) |
Finally fix parsing indirect indexed addr args
-rw-r--r-- | main.c | 94 | ||||
-rwxr-xr-x | test.sh | 1 | ||||
-rw-r--r-- | tests/test2.S | 65 | ||||
-rw-r--r-- | tests/test3.S | 9 |
4 files changed, 159 insertions, 10 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); @@ -12,4 +12,5 @@ set TEMP=c:\\tmp END echo "asm68 -l -Q -o test1.o test1.S" >>"$dosbuild_dir/build.bat" echo "asm68 -l -Q -o test2.o test2.S" >>"$dosbuild_dir/build.bat" +echo "asm68 -l -Q -o test3.o test3.S" >>"$dosbuild_dir/build.bat" dosemu -quiet -K "$dosbuild_dir" -E'build.bat' diff --git a/tests/test2.S b/tests/test2.S index 4a8ee7d..20c68c5 100644 --- a/tests/test2.S +++ b/tests/test2.S @@ -1,43 +1,102 @@ +move 32767.l(a1),d1 +move (32767.l,a1),d1 +move (a1,32767.l),d1 + +move 32767.l(pc),d1 +move (32767.l,pc),d1 +move (pc,32767.l),d1 + +move 127.l(a1,d1),d1 +move 127.w(a1,d1),d1 move 127(a1,d1.l),d1 -move 127(a1,d1.l),d1 +move 127(a1,d1.w),d1 move 127.l(a1,d1.l),d1 +move 127.w(a1,d1.l),d1 +move 127.l(a1,d1.w),d1 +move 127.w(a1,d1.w),d1 move 127(d1.l,a1),d1 -move 127(d1.l,a1),d1 +move 127(d1.w,a1),d1 move 127.l(d1.l,a1),d1 +move 127.w(d1.l,a1),d1 +move 127.l(d1.w,a1),d1 +move 127.w(d1.w,a1),d1 move 127(pc,d1.l),d1 +move 127(pc,d1.w),d1 move 127.l(pc,d1),d1 +move 127.w(pc,d1),d1 move 127.l(pc,d1.l),d1 +move 127.w(pc,d1.l),d1 +move 127.l(pc,d1.w),d1 +move 127.w(pc,d1.w),d1 move 127(d1.l,pc),d1 +move 127(d1.w,pc),d1 move 127.l(d1,pc),d1 +move 127.w(d1,pc),d1 move 127.l(d1.l,pc),d1 +move 127.w(d1.l,pc),d1 +move 127.l(d1.w,pc),d1 +move 127.w(d1.w,pc),d1 move (a1,d1.l,127),d1 +move (a1,d1.l,127.w),d1 move (a1,d1.l,127.l),d1 +move (a1,d1.w,127.w),d1 +move (a1,d1.w,127.l),d1 move (a1,d1,127.l),d1 +move (a1,d1,127.w),d1 move (d1.l,a1,127),d1 move (d1,a1,127.l),d1 move (d1.l,a1,127.l),d1 +move (d1.l,a1,127.w),d1 +move (d1.w,a1,127.l),d1 +move (d1.w,a1,127.w),d1 move (a1,127,d1.l),d1 move (a1,127.l,d1),d1 +move (a1,127.w,d1),d1 move (a1,127.l,d1.l),d1 +move (a1,127.w,d1.l),d1 +move (a1,127.l,d1.w),d1 +move (a1,127.w,d1.w),d1 move (d1.l,127,a1),d1 move (d1,127.l,a1),d1 move (d1.l,127.l,a1),d1 -move (d1.l,127.l,a1),d1 +move (d1.l,127.w,a1),d1 +move (d1.w,127.l,a1),d1 +move (d1.w,127.w,a1),d1 move (a1.l,127.l,a1),d1 +move (a1.l,127.w,a1),d1 +move (a1.w,127.l,a1),d1 +move (a1.w,127.w,a1),d1 move (pc,d1.l,127),d1 +move (pc,d1.w,127),d1 move (pc,d1,127.l),d1 +move (pc,d1,127.w),d1 move (d1.l,pc,127),d1 +move (d1.w,pc,127),d1 move (d1,pc,127.l),d1 +move (d1,pc,127.w),d1 move (d1.l,pc,127.l),d1 +move (d1.l,pc,127.w),d1 +move (d1.w,pc,127.l),d1 +move (d1.w,pc,127.w),d1 move (pc,127,d1.l),d1 +move (pc,127,d1.w),d1 move (pc,127.l,d1),d1 +move (pc,127.w,d1),d1 move (pc,127.l,d1.l),d1 +move (pc,127.w,d1.l),d1 +move (pc,127.l,d1.w),d1 +move (pc,127.w,d1.w),d1 move (d1.l,127,pc),d1 +move (d1.w,127,pc),d1 move (d1,127.l,pc),d1 +move (d1,127.w,pc),d1 move (d1.l,127.l,pc),d1 +move (d1.l,127.w,pc),d1 +move (d1.w,127.l,pc),d1 +move (d1.w,127.w,pc),d1 loc: move 0.l,d1 diff --git a/tests/test3.S b/tests/test3.S new file mode 100644 index 0000000..a4acdc8 --- /dev/null +++ b/tests/test3.S @@ -0,0 +1,9 @@ +move 127.w(d1.l,a1),d1 ; Long size in extension word +move 127.l(d1.w,a1),d1 ; Word size in extension word +move 127.w(d1,a1),d1 ; Word size in extension word +move 127.l(d1,a1),d1 ; Word size in extension word +move 127(d1.w,a1),d1 ; Word size in extension word +move 127(d1.l,a1),d1 ; Long size in extension word +move (127.l,d1,a1),d1 ; Word size in extension word +move (127,d1.l,a1),d1 ; Long size in extension word +move ((127).b,d1.l,a1),d1 ; Long size in extension word |