/* m68k.y -- bison grammar for m68k operand parsing
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995-2020 Free Software Foundation, Inc.
Written by Ken Raeburn and Ian Lance Taylor, Cygnus Support
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
/* This file holds a bison grammar to parse m68k operands. The m68k
has a complicated operand syntax, and gas supports two main
#include "as.h"
#include "tc-m68k.h"
#include "m68k-parse.h"
+#include "safe-ctype.h"
/* Remap normal yacc parser interface names (yyparse, yylex, yyerror,
- etc), as well as gratuitiously global symbol names If other parser
+ etc), as well as gratuitously global symbol names If other parser
generators (bison, byacc, etc) produce additional global names that
conflict at link time, then those parser generators need to be
- fixed instead of adding those names to this list. */
+ fixed instead of adding those names to this list. */
#define yymaxdepth m68k_maxdepth
#define yyparse m68k_parse
#define yylval m68k_lval
#define yychar m68k_char
#define yydebug m68k_debug
-#define yypact m68k_pact
-#define yyr1 m68k_r1
-#define yyr2 m68k_r2
-#define yydef m68k_def
-#define yychk m68k_chk
-#define yypgo m68k_pgo
-#define yyact m68k_act
+#define yypact m68k_pact
+#define yyr1 m68k_r1
+#define yyr2 m68k_r2
+#define yydef m68k_def
+#define yychk m68k_chk
+#define yypgo m68k_pgo
+#define yyact m68k_act
#define yyexca m68k_exca
#define yyerrflag m68k_errflag
#define yynerrs m68k_nerrs
/* Internal functions. */
-static enum m68k_register m68k_reg_parse PARAMS ((char **));
-static int yylex PARAMS (());
-static void yyerror PARAMS ((const char *));
+static enum m68k_register m68k_reg_parse (char **);
+static int yylex (void);
+static void yyerror (const char *);
/* The parser sets fields pointed to by this global variable. */
static struct m68k_op *op;
struct m68k_exp exp;
unsigned long mask;
int onereg;
+ int trailing_ampersand;
}
%token <reg> DR AR FPR FPCR LPC ZAR ZDR LZPC CREG
%type <exp> optcexpr optexprc
%type <mask> reglist ireglist reglistpair
%type <onereg> reglistreg
+%type <trailing_ampersand> optional_ampersand
%%
operand:
generic_operand
- | motorola_operand
- | mit_operand
+ | motorola_operand optional_ampersand
+ {
+ op->trailing_ampersand = $2;
+ }
+ | mit_operand optional_ampersand
+ {
+ op->trailing_ampersand = $2;
+ }
+ ;
+
+/* A trailing ampersand(for MAC/EMAC mask addressing). */
+optional_ampersand:
+ /* empty */
+ { $$ = 0; }
+ | '&'
+ { $$ = 1; }
;
/* A generic operand. */
generic_operand:
- DR
+ '<' '<'
+ {
+ op->mode = LSH;
+ }
+
+ | '>' '>'
+ {
+ op->mode = RSH;
+ }
+
+ | DR
{
op->mode = DREG;
op->reg = $1;
else
op->mode = DISP;
}
+ | '(' zapc ',' EXPR ')'
+ {
+ op->reg = $2;
+ op->disp = $4;
+ if (($2 >= ZADDR0 && $2 <= ZADDR7)
+ || $2 == ZPC)
+ op->mode = BASE;
+ else
+ op->mode = DISP;
+ }
| EXPR '(' zapc ')'
{
op->reg = $3;
else
op->mode = DISP;
}
+ | '(' LPC ')'
+ {
+ op->mode = DISP;
+ op->reg = $2;
+ }
| '(' ZAR ')'
{
op->mode = BASE;
op->reg = $2;
}
- | '(' zpc ')'
+ | '(' LZPC ')'
{
op->mode = BASE;
op->reg = $2;
| '(' EXPR ',' zapc ',' zpc ')'
{
if ($4 == PC || $4 == ZPC)
- yyerror ("syntax error");
+ yyerror (_("syntax error"));
op->mode = BASE;
op->reg = $6;
op->disp = $2;
op->disp = $2;
op->index = $4;
}
+ | '(' zdireg ',' EXPR ')'
+ {
+ op->mode = BASE;
+ op->disp = $4;
+ op->index = $2;
+ }
| EXPR '(' zapc ',' zireg ')'
{
op->mode = BASE;
| EXPR '(' zapc ',' zpc ')'
{
if ($3 == PC || $3 == ZPC)
- yyerror ("syntax error");
+ yyerror (_("syntax error"));
op->mode = BASE;
op->reg = $5;
op->disp = $1;
| '(' zapc ',' zpc ')'
{
if ($2 == PC || $2 == ZPC)
- yyerror ("syntax error");
+ yyerror (_("syntax error"));
op->mode = BASE;
op->reg = $4;
op->index.reg = $2;
| '(' '[' EXPR ',' zapc ',' zpc ']' optcexpr ')'
{
if ($5 == PC || $5 == ZPC)
- yyerror ("syntax error");
+ yyerror (_("syntax error"));
op->mode = PRE;
op->reg = $7;
op->disp = $3;
| '(' '[' zapc ',' zpc ']' optcexpr ')'
{
if ($3 == PC || $3 == ZPC)
- yyerror ("syntax error");
+ yyerror (_("syntax error"));
op->mode = PRE;
op->reg = $5;
op->index.reg = $3;
{
/* We use optzapc to avoid a shift/reduce conflict. */
if ($1 < ADDR0 || $1 > ADDR7)
- yyerror ("syntax error");
+ yyerror (_("syntax error"));
op->mode = AINDR;
op->reg = $1;
}
{
/* We use optzapc to avoid a shift/reduce conflict. */
if ($1 < ADDR0 || $1 > ADDR7)
- yyerror ("syntax error");
+ yyerror (_("syntax error"));
op->mode = AINC;
op->reg = $1;
}
{
/* We use optzapc to avoid a shift/reduce conflict. */
if ($1 < ADDR0 || $1 > ADDR7)
- yyerror ("syntax error");
+ yyerror (_("syntax error"));
op->mode = ADEC;
op->reg = $1;
}
reglistpair:
reglistreg '-' reglistreg
{
- $$ = (1 << ($3 + 1)) - 1 - ((1 << $1) - 1);
+ if ($1 <= $3)
+ $$ = (1 << ($3 + 1)) - 1 - ((1 << $1) - 1);
+ else
+ $$ = (1 << ($1 + 1)) - 1 - ((1 << $3) - 1);
}
;
*CCP. Otherwise don't change *CCP, and return 0. */
static enum m68k_register
-m68k_reg_parse (ccp)
- register char **ccp;
+m68k_reg_parse (char **ccp)
{
char *start = *ccp;
char c;
return S_GET_VALUE (symbolp);
}
+ /* In MRI mode, something like foo.bar can be equated to a register
+ name. */
+ while (flag_mri && c == '.')
+ {
+ ++p;
+ while (is_part_of_name (*p) && *p != '.' && *p != ':' && *p != '*')
+ p++;
+ c = *p;
+ *p = '\0';
+ symbolp = symbol_find (start);
+ *p = c;
+ if (symbolp != NULL && S_GET_SEGMENT (symbolp) == reg_section)
+ {
+ *ccp = p;
+ return S_GET_VALUE (symbolp);
+ }
+ }
+
return 0;
}
/* The lexer. */
static int
-yylex ()
+yylex (void)
{
enum m68k_register reg;
char *s;
int parens;
int c = 0;
- char *hold;
+ int tail = 0;
if (*str == ' ')
++str;
/* Various special characters are just returned directly. */
switch (*str)
{
+ case '@':
+ /* In MRI mode, this can be the start of an octal number. */
+ if (flag_mri)
+ {
+ if (ISDIGIT (str[1])
+ || ((str[1] == '+' || str[1] == '-')
+ && ISDIGIT (str[2])))
+ break;
+ }
+ /* Fall through. */
case '#':
case '&':
case ',':
case ')':
case '/':
- case '@':
case '[':
case ']':
+ case '<':
+ case '>':
return *str++;
case '+':
/* It so happens that a '+' can only appear at the end of an
- operand. If it appears anywhere else, it must be a unary
- plus on an expression. */
- if (str[1] == '\0')
+ operand, or if it is trailed by an '&'(see mac load insn).
+ If it appears anywhere else, it must be a unary. */
+ if (str[1] == '\0' || (str[1] == '&' && str[2] == '\0'))
return *str++;
break;
case '-':
/* A '-' can only appear in -(ar), rn-rn, or ar@-. If it
appears anywhere else, it must be a unary minus on an
- expression. */
- if (str[1] == '\0')
+ expression, unless it it trailed by a '&'(see mac load insn). */
+ if (str[1] == '\0' || (str[1] == '&' && str[2] == '\0'))
return *str++;
s = str + 1;
if (*s == '(')
++s;
break;
default:
- yyerror ("illegal size specification");
+ yyerror (_("illegal size specification"));
yylval.indexreg.size = SIZE_UNSPEC;
break;
}
}
- if (*s != '*' && *s != ':')
- yylval.indexreg.scale = 1;
- else
+ yylval.indexreg.scale = 1;
+
+ if (*s == '*' || *s == ':')
{
+ expressionS scale;
+
++s;
- switch (*s)
+
+ temp_ilp (s);
+ expression (&scale);
+ s = input_line_pointer;
+ restore_ilp ();
+
+ if (scale.X_op != O_constant)
+ yyerror (_("scale specification must resolve to a number"));
+ else
{
- case '1':
- case '2':
- case '4':
- case '8':
- yylval.indexreg.scale = *s - '0';
- ++s;
- break;
- default:
- yyerror ("illegal scale specification");
- yylval.indexreg.scale = 1;
- break;
+ switch (scale.X_add_number)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ yylval.indexreg.scale = scale.X_add_number;
+ break;
+ default:
+ yyerror (_("invalid scale value"));
+ break;
+ }
}
}
{
if (parens == 0
&& s > str
- && (s[-1] == ')' || isalnum ((unsigned char) s[-1])))
+ && (s[-1] == ')' || ISALNUM (s[-1])))
break;
++parens;
}
yylval.exp.size = SIZE_UNSPEC;
if (s <= str + 2
|| (s[-2] != '.' && s[-2] != ':'))
- s = NULL;
+ tail = 0;
else
{
switch (s[-1])
yylval.exp.size = SIZE_LONG;
break;
default:
- s = NULL;
break;
}
if (yylval.exp.size != SIZE_UNSPEC)
- {
- c = s[-2];
- s[-2] = '\0';
- }
+ tail = 2;
+ }
+
+#ifdef OBJ_ELF
+ {
+ /* Look for @PLTPC, etc. */
+ char *cp;
+
+ yylval.exp.pic_reloc = pic_none;
+ cp = s - tail;
+ if (cp - 7 > str && cp[-7] == '@')
+ {
+ if (strncmp (cp - 7, "@TLSLDM", 7) == 0)
+ {
+ yylval.exp.pic_reloc = pic_tls_ldm;
+ tail += 7;
+ }
+ else if (strncmp (cp - 7, "@TLSLDO", 7) == 0)
+ {
+ yylval.exp.pic_reloc = pic_tls_ldo;
+ tail += 7;
+ }
+ }
+ else if (cp - 6 > str && cp[-6] == '@')
+ {
+ if (strncmp (cp - 6, "@PLTPC", 6) == 0)
+ {
+ yylval.exp.pic_reloc = pic_plt_pcrel;
+ tail += 6;
+ }
+ else if (strncmp (cp - 6, "@GOTPC", 6) == 0)
+ {
+ yylval.exp.pic_reloc = pic_got_pcrel;
+ tail += 6;
+ }
+ else if (strncmp (cp - 6, "@TLSGD", 6) == 0)
+ {
+ yylval.exp.pic_reloc = pic_tls_gd;
+ tail += 6;
+ }
+ else if (strncmp (cp - 6, "@TLSIE", 6) == 0)
+ {
+ yylval.exp.pic_reloc = pic_tls_ie;
+ tail += 6;
+ }
+ else if (strncmp (cp - 6, "@TLSLE", 6) == 0)
+ {
+ yylval.exp.pic_reloc = pic_tls_le;
+ tail += 6;
+ }
+ }
+ else if (cp - 4 > str && cp[-4] == '@')
+ {
+ if (strncmp (cp - 4, "@PLT", 4) == 0)
+ {
+ yylval.exp.pic_reloc = pic_plt_off;
+ tail += 4;
+ }
+ else if (strncmp (cp - 4, "@GOT", 4) == 0)
+ {
+ yylval.exp.pic_reloc = pic_got_off;
+ tail += 4;
+ }
+ }
+ }
+#endif
+
+ if (tail != 0)
+ {
+ c = s[-tail];
+ s[-tail] = 0;
}
- hold = input_line_pointer;
- input_line_pointer = str;
+ temp_ilp (str);
expression (&yylval.exp.exp);
str = input_line_pointer;
- input_line_pointer = hold;
+ restore_ilp ();
- if (s != NULL)
+ if (tail != 0)
{
- s[-2] = c;
+ s[-tail] = c;
str = s;
}
from outside this file. */
int
-m68k_ip_op (s, oparg)
- char *s;
- struct m68k_op *oparg;
+m68k_ip_op (char *s, struct m68k_op *oparg)
{
memset (oparg, 0, sizeof *oparg);
oparg->error = NULL;
/* The error handler. */
static void
-yyerror (s)
- const char *s;
+yyerror (const char *s)
{
op->error = s;
}