summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2023-08-09 00:41:52 +0300
committerOxore <oxore@protonmail.com>2023-08-09 00:41:52 +0300
commit8417537e503f86a8a659d64418c7b2547d555b51 (patch)
tree3af81a0b11073f620062ad9d8ecdbe392e4dd400
parent5c5c60a18b41d2f5a077d5fa8fa8b266db537578 (diff)
Finally fix parsing indirect indexed addr args
-rw-r--r--main.c94
-rwxr-xr-xtest.sh1
-rw-r--r--tests/test2.S65
-rw-r--r--tests/test3.S9
4 files changed, 159 insertions, 10 deletions
diff --git a/main.c b/main.c
index ebc660d..85ba133 100644
--- a/main.c
+++ b/main.c
@@ -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);
diff --git a/test.sh b/test.sh
index 41bfa8c..acc8151 100755
--- a/test.sh
+++ b/test.sh
@@ -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