merge from gcc
[external/binutils.git] / gas / config / m68k-parse.y
index d3d690a..2c58266 100644 (file)
@@ -1,12 +1,13 @@
 /* m68k.y -- bison grammar for m68k operand parsing
-   Copyright (C) 1995 Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 2001, 2003, 2004, 2005, 2007, 2009
+   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,
@@ -16,8 +17,8 @@
 
    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
@@ -81,9 +83,9 @@
 
 /* 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;
@@ -97,6 +99,7 @@ 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
@@ -108,6 +111,7 @@ static struct m68k_op *op;
 %type <exp> optcexpr optexprc
 %type <mask> reglist ireglist reglistpair
 %type <onereg> reglistreg
+%type <trailing_ampersand> optional_ampersand
 
 %%
 
@@ -115,14 +119,38 @@ static struct m68k_op *op;
 
 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;
@@ -200,6 +228,16 @@ motorola_operand:
                  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;
@@ -210,12 +248,17 @@ motorola_operand:
                  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;
@@ -230,7 +273,7 @@ motorola_operand:
        | '(' EXPR ',' zapc ',' zpc ')'
                {
                  if ($4 == PC || $4 == ZPC)
-                   yyerror ("syntax error");
+                   yyerror (_("syntax error"));
                  op->mode = BASE;
                  op->reg = $6;
                  op->disp = $2;
@@ -245,6 +288,12 @@ motorola_operand:
                  op->disp = $2;
                  op->index = $4;
                }
+       | '(' zdireg ',' EXPR ')'
+               {
+                 op->mode = BASE;
+                 op->disp = $4;
+                 op->index = $2;
+               }
        | EXPR '(' zapc ',' zireg ')'
                {
                  op->mode = BASE;
@@ -261,7 +310,7 @@ motorola_operand:
        | EXPR '(' zapc ',' zpc ')'
                {
                  if ($3 == PC || $3 == ZPC)
-                   yyerror ("syntax error");
+                   yyerror (_("syntax error"));
                  op->mode = BASE;
                  op->reg = $5;
                  op->disp = $1;
@@ -272,7 +321,7 @@ motorola_operand:
        | '(' zapc ',' zpc ')'
                {
                  if ($2 == PC || $2 == ZPC)
-                   yyerror ("syntax error");
+                   yyerror (_("syntax error"));
                  op->mode = BASE;
                  op->reg = $4;
                  op->index.reg = $2;
@@ -338,7 +387,7 @@ motorola_operand:
        | '(' '[' EXPR ',' zapc ',' zpc ']' optcexpr ')'
                {
                  if ($5 == PC || $5 == ZPC)
-                   yyerror ("syntax error");
+                   yyerror (_("syntax error"));
                  op->mode = PRE;
                  op->reg = $7;
                  op->disp = $3;
@@ -350,7 +399,7 @@ motorola_operand:
        | '(' '[' zapc ',' zpc ']' optcexpr ')'
                {
                  if ($3 == PC || $3 == ZPC)
-                   yyerror ("syntax error");
+                   yyerror (_("syntax error"));
                  op->mode = PRE;
                  op->reg = $5;
                  op->index.reg = $3;
@@ -375,7 +424,7 @@ mit_operand:
                {
                  /* 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;
                }
@@ -383,7 +432,7 @@ mit_operand:
                {
                  /* 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;
                }
@@ -391,7 +440,7 @@ mit_operand:
                {
                  /* 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;
                }
@@ -592,7 +641,10 @@ ireglist:
 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);
                }
        ;
 
@@ -673,6 +725,24 @@ m68k_reg_parse (ccp)
       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;
 }
 
@@ -685,6 +755,7 @@ yylex ()
   char *s;
   int parens;
   int c = 0;
+  int tail = 0;
   char *hold;
 
   if (*str == ' ')
@@ -696,27 +767,38 @@ yylex ()
   /* 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 == '(')
@@ -819,30 +901,42 @@ yylex ()
              ++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)
+
+         hold = input_line_pointer;
+         input_line_pointer = s;
+         expression (&scale);
+         s = input_line_pointer;
+         input_line_pointer = hold;
+
+         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;
+               }
            }
        }
 
@@ -865,7 +959,7 @@ yylex ()
        {
          if (parens == 0
              && s > str
-             && (s[-1] == ')' || isalnum ((unsigned char) s[-1])))
+             && (s[-1] == ')' || ISALNUM (s[-1])))
            break;
          ++parens;
        }
@@ -883,7 +977,7 @@ yylex ()
   yylval.exp.size = SIZE_UNSPEC;
   if (s <= str + 2
       || (s[-2] != '.' && s[-2] != ':'))
-    s = NULL;
+    tail = 0;
   else
     {
       switch (s[-1])
@@ -903,14 +997,80 @@ yylex ()
          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;
@@ -919,9 +1079,9 @@ yylex ()
   str = input_line_pointer;
   input_line_pointer = hold;
 
-  if (s != NULL)
+  if (tail != 0)
     {
-      s[-2] = c;
+      s[-tail] = c;
       str = s;
     }