summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c94
1 files changed, 87 insertions, 7 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);