diff options
| -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 | 
