gas: require an operand to .startof.()/.sizeof.()
[deliverable/binutils-gdb.git] / gas / expr.c
index f8acd4129b46f4726ad0ce43f6fabd9cfb88ca1a..6fc707b8a593eea0441568cf46e6cf7c14d71932 100644 (file)
@@ -1,5 +1,5 @@
 /* expr.c -operands, expressions-
-   Copyright (C) 1987-2015 Free Software Foundation, Inc.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -46,15 +46,13 @@ static void clean_up_expression (expressionS * expressionP);
 static segT operand (expressionS *, enum expr_mode);
 static operatorT operatorf (int *);
 
-extern const char EXP_CHARS[], FLT_CHARS[];
-
 /* We keep a mapping of expression symbols to file positions, so that
    we can provide better error messages.  */
 
 struct expr_symbol_line {
   struct expr_symbol_line *next;
   symbolS *sym;
-  char *file;
+  const char *file;
   unsigned int line;
 };
 
@@ -108,9 +106,9 @@ make_expr_symbol (expressionS *expressionP)
   if (expressionP->X_op == O_constant)
     resolve_symbol_value (symbolP);
 
-  n = (struct expr_symbol_line *) xmalloc (sizeof *n);
+  n = XNEW (struct expr_symbol_line);
   n->sym = symbolP;
-  as_where (&n->file, &n->line);
+  n->file = as_where (&n->line);
   n->next = expr_symbol_lines;
   expr_symbol_lines = n;
 
@@ -122,7 +120,7 @@ make_expr_symbol (expressionS *expressionP)
    the symbol.  */
 
 int
-expr_symbol_where (symbolS *sym, char **pfile, unsigned int *pline)
+expr_symbol_where (symbolS *sym, const char **pfile, unsigned int *pline)
 {
   struct expr_symbol_line *l;
 
@@ -510,6 +508,21 @@ integer_constant (int radix, expressionS *expressionP)
       && input_line_pointer - 1 == suffix)
     c = *input_line_pointer++;
 
+#ifndef tc_allow_U_suffix
+#define tc_allow_U_suffix 1
+#endif
+  /* PR 19910: Look for, and ignore, a U suffix to the number.  */
+  if (tc_allow_U_suffix && (c == 'U' || c == 'u'))
+    c = * input_line_pointer++;
+
+#ifndef tc_allow_L_suffix
+#define tc_allow_L_suffix 1
+#endif
+  /* PR 20732: Look for, and ignore, a L or LL suffix to the number.  */
+  if (tc_allow_L_suffix)
+    while (c == 'L' || c == 'l')
+      c = * input_line_pointer++;
+
   if (small)
     {
       /* Here with number, in correct radix. c is the next char.
@@ -944,15 +957,21 @@ operand (expressionS *expressionP, enum expr_mode mode)
       if (md_need_index_operator())
        goto de_fault;
 # endif
-      /* FALLTHROUGH */
 #endif
+      /* Fall through.  */
     case '(':
       /* Didn't begin with digit & not a name.  */
       segment = expr (0, expressionP, mode);
       /* expression () will pass trailing whitespace.  */
       if ((c == '(' && *input_line_pointer != ')')
          || (c == '[' && *input_line_pointer != ']'))
-       as_bad (_("missing '%c'"), c == '(' ? ')' : ']');
+       {
+         if (* input_line_pointer)
+           as_bad (_("found '%c', expected: '%c'"),
+                   * input_line_pointer, c == '(' ? ')' : ']');
+         else
+           as_bad (_("missing '%c'"), c == '(' ? ')' : ']');
+       }           
       else
        input_line_pointer++;
       SKIP_WHITESPACE ();
@@ -969,8 +988,8 @@ operand (expressionS *expressionP, enum expr_mode mode)
       if (! flag_m68k_mri || *input_line_pointer != '\'')
        goto de_fault;
       ++input_line_pointer;
-      /* Fall through.  */
 #endif
+      /* Fall through.  */
     case '\'':
       if (! flag_m68k_mri)
        {
@@ -991,12 +1010,13 @@ operand (expressionS *expressionP, enum expr_mode mode)
       /* Double quote is the bitwise not operator in MRI mode.  */
       if (! flag_m68k_mri)
        goto de_fault;
-      /* Fall through.  */
 #endif
+      /* Fall through.  */
     case '~':
       /* '~' is permitted to start a label on the Delta.  */
       if (is_name_beginner (c))
        goto isname;
+      /* Fall through.  */
     case '!':
     case '-':
     case '+':
@@ -1134,6 +1154,10 @@ operand (expressionS *expressionP, enum expr_mode mode)
                   || input_line_pointer[1] == 'T');
          input_line_pointer += start ? 8 : 7;
          SKIP_WHITESPACE ();
+
+         /* Cover for the as_bad () invocations below.  */
+         expressionP->X_op = O_absent;
+
          if (*input_line_pointer != '(')
            as_bad (_("syntax error in .startof. or .sizeof."));
          else
@@ -1142,14 +1166,20 @@ operand (expressionS *expressionP, enum expr_mode mode)
 
              ++input_line_pointer;
              SKIP_WHITESPACE ();
-             name = input_line_pointer;
-             c = get_symbol_end ();
+             c = get_symbol_name (& name);
+             if (! *name)
+               {
+                 as_bad (_("expected symbol name"));
+                 (void) restore_line_pointer (c);
+                 if (c != ')')
+                   ignore_rest_of_line ();
+                 else
+                   ++input_line_pointer;
+                 break;
+               }
 
-             buf = (char *) xmalloc (strlen (name) + 10);
-             if (start)
-               sprintf (buf, ".startof.%s", name);
-             else
-               sprintf (buf, ".sizeof.%s", name);
+             buf = concat (start ? ".startof." : ".sizeof.", name,
+                           (char *) NULL);
              symbolP = symbol_make (buf);
              free (buf);
 
@@ -1158,7 +1188,7 @@ operand (expressionS *expressionP, enum expr_mode mode)
              expressionP->X_add_number = 0;
 
              *input_line_pointer = c;
-             SKIP_WHITESPACE ();
+             SKIP_WHITESPACE_AFTER_NAME ();
              if (*input_line_pointer != ')')
                as_bad (_("syntax error in .startof. or .sizeof."));
              else
@@ -1214,13 +1244,13 @@ operand (expressionS *expressionP, enum expr_mode mode)
 #if defined(md_need_index_operator) || defined(TC_M68K)
     de_fault:
 #endif
-      if (is_name_beginner (c))        /* Here if did not begin with a digit.  */
+      if (is_name_beginner (c) || c == '"')    /* Here if did not begin with a digit.  */
        {
          /* Identifier begins here.
             This is kludged for speed, so code is repeated.  */
        isname:
-         name = --input_line_pointer;
-         c = get_symbol_end ();
+         -- input_line_pointer;
+         c = get_symbol_name (&name);
 
 #ifdef md_operator
          {
@@ -1229,15 +1259,15 @@ operand (expressionS *expressionP, enum expr_mode mode)
            switch (op)
              {
              case O_uminus:
-               *input_line_pointer = c;
+               restore_line_pointer (c);
                c = '-';
                goto unary;
              case O_bit_not:
-               *input_line_pointer = c;
+               restore_line_pointer (c);
                c = '~';
                goto unary;
              case O_logical_not:
-               *input_line_pointer = c;
+               restore_line_pointer (c);
                c = '!';
                goto unary;
              case O_illegal:
@@ -1246,9 +1276,10 @@ operand (expressionS *expressionP, enum expr_mode mode)
              default:
                break;
              }
+
            if (op != O_absent && op != O_illegal)
              {
-               *input_line_pointer = c;
+               restore_line_pointer (c);
                expr (9, expressionP, mode);
                expressionP->X_add_symbol = make_expr_symbol (expressionP);
                expressionP->X_op_symbol = NULL;
@@ -1266,7 +1297,7 @@ operand (expressionS *expressionP, enum expr_mode mode)
             entering it in the symbol table.  */
          if (md_parse_name (name, expressionP, mode, &c))
            {
-             *input_line_pointer = c;
+             restore_line_pointer (c);
              break;
            }
 #endif
@@ -1286,16 +1317,20 @@ operand (expressionS *expressionP, enum expr_mode mode)
                       || name[1] == 'T');
 
              *input_line_pointer = c;
-             SKIP_WHITESPACE ();
+             SKIP_WHITESPACE_AFTER_NAME ();
 
-             name = input_line_pointer;
-             c = get_symbol_end ();
+             c = get_symbol_name (& name);
+             if (! *name)
+               {
+                 as_bad (_("expected symbol name"));
+                 expressionP->X_op = O_absent;
+                 (void) restore_line_pointer (c);
+                 ignore_rest_of_line ();
+                 break;
+               }
 
-             buf = (char *) xmalloc (strlen (name) + 10);
-             if (start)
-               sprintf (buf, ".startof.%s", name);
-             else
-               sprintf (buf, ".sizeof.%s", name);
+             buf = concat (start ? ".startof." : ".sizeof.", name,
+                           (char *) NULL);
              symbolP = symbol_make (buf);
              free (buf);
 
@@ -1304,8 +1339,7 @@ operand (expressionS *expressionP, enum expr_mode mode)
              expressionP->X_add_number = 0;
 
              *input_line_pointer = c;
-             SKIP_WHITESPACE ();
-
+             SKIP_WHITESPACE_AFTER_NAME ();
              break;
            }
 #endif
@@ -1333,7 +1367,8 @@ operand (expressionS *expressionP, enum expr_mode mode)
              expressionP->X_add_symbol = symbolP;
              expressionP->X_add_number = 0;
            }
-         *input_line_pointer = c;
+
+         restore_line_pointer (c);
        }
       else
        {
@@ -1358,7 +1393,7 @@ operand (expressionS *expressionP, enum expr_mode mode)
   /* It is more 'efficient' to clean up the expressionS when they are
      created.  Doing it here saves lines of code.  */
   clean_up_expression (expressionP);
-  SKIP_WHITESPACE ();          /* -> 1st char after operand.  */
+  SKIP_ALL_WHITESPACE ();              /* -> 1st char after operand.  */
   know (*input_line_pointer != ' ');
 
   /* The PA port needs this information.  */
@@ -1589,8 +1624,8 @@ operatorf (int *num_chars)
 #ifdef md_operator
   if (is_name_beginner (c))
     {
-      char *name = input_line_pointer;
-      char ec = get_symbol_end ();
+      char *name;
+      char ec = get_symbol_name (& name);
 
       ret = md_operator (name, 2, &ec);
       switch (ret)
@@ -2318,19 +2353,22 @@ resolve_expression (expressionS *expressionP)
    expr.c is just a branch office read.c anyway, and putting it
    here lessens the crowd at read.c.
 
-   Assume input_line_pointer is at start of symbol name.
+   Assume input_line_pointer is at start of symbol name, or the
+    start of a double quote enclosed symbol name.
    Advance input_line_pointer past symbol name.
-   Turn that character into a '\0', returning its former value.
+   Turn that character into a '\0', returning its former value,
+    which may be the closing double quote.
    This allows a string compare (RMS wants symbol names to be strings)
-   of the symbol name.
+    of the symbol name.
    There will always be a char following symbol name, because all good
    lines end in end-of-line.  */
 
 char
-get_symbol_end (void)
+get_symbol_name (char ** ilp_return)
 {
   char c;
 
+  * ilp_return = input_line_pointer;
   /* We accept \001 in a name in case this is being called with a
      constructed string.  */
   if (is_name_beginner (c = *input_line_pointer++) || c == '\001')
@@ -2341,8 +2379,36 @@ get_symbol_end (void)
       if (is_name_ender (c))
        c = *input_line_pointer++;
     }
+  else if (c == '"')
+    {
+      bfd_boolean backslash_seen;
+
+      * ilp_return = input_line_pointer;
+      do
+       {
+         backslash_seen = c == '\\';
+         c = * input_line_pointer ++;
+       }
+      while (c != 0 && (c != '"' || backslash_seen));
+
+      if (c == 0)
+       as_warn (_("missing closing '\"'"));
+    }
   *--input_line_pointer = 0;
-  return (c);
+  return c;
+}
+
+/* Replace the NUL character pointed to by input_line_pointer
+   with C.  If C is \" then advance past it.  Return the character
+   now pointed to by input_line_pointer.  */
+
+char
+restore_line_pointer (char c)
+{
+  * input_line_pointer = c;
+  if (c == '"')
+    c = * ++ input_line_pointer;
+  return c;
 }
 
 unsigned int
This page took 0.028853 seconds and 4 git commands to generate.