include/opcode/
[deliverable/binutils-gdb.git] / gas / macro.c
index be73b98d9b960212d8246ffbb3591a4110952fea..e6e9d05ba2728814140a2cfefc7e7add80497610 100644 (file)
@@ -70,7 +70,9 @@ extern void *alloca ();
 
 static int get_token (int, sb *, sb *);
 static int getstring (int, sb *, sb *);
-static int get_any_string (int, sb *, sb *, int, int);
+static int get_any_string (int, sb *, sb *);
+static formal_entry *new_formal (void);
+static void del_formal (formal_entry *);
 static int do_formals (macro_entry *, int, sb *);
 static int get_apost_token (int, sb *, sb *, int);
 static int sub_actual (int, sb *, sb *, struct hash_control *, int, sb *, int);
@@ -178,49 +180,46 @@ buffer_and_nest (const char *from, const char *to, sb *ptr,
 
   while (more)
     {
-      /* Try and find the first pseudo op on the line.  */
+      /* Try to find the first pseudo op on the line.  */
       int i = line_start;
 
-      if (! NO_PSEUDO_DOT && ! flag_m68k_mri)
-       {
-         /* With normal syntax we can suck what we want till we get
-            to the dot.  With the alternate, labels have to start in
-            the first column, since we can't tell what's a label and
-            whats a pseudoop.  */
+      /* With normal syntax we can suck what we want till we get
+        to the dot.  With the alternate, labels have to start in
+        the first column, since we can't tell what's a label and
+        what's a pseudoop.  */
 
-         if (! LABELS_WITHOUT_COLONS)
-           {
-             /* Skip leading whitespace.  */
-             while (i < ptr->len && ISWHITE (ptr->ptr[i]))
-               i++;
-           }
+      if (! LABELS_WITHOUT_COLONS)
+       {
+         /* Skip leading whitespace.  */
+         while (i < ptr->len && ISWHITE (ptr->ptr[i]))
+           i++;
+       }
 
-         for (;;)
+      for (;;)
+       {
+         /* Skip over a label, if any.  */
+         if (i >= ptr->len || ! is_name_beginner (ptr->ptr[i]))
+           break;
+         i++;
+         while (i < ptr->len && is_part_of_name (ptr->ptr[i]))
+           i++;
+         if (i < ptr->len && is_name_ender (ptr->ptr[i]))
+           i++;
+         if (LABELS_WITHOUT_COLONS)
+           break;
+         /* Skip whitespace.  */
+         while (i < ptr->len && ISWHITE (ptr->ptr[i]))
+           i++;
+         /* Check for the colon.  */
+         if (i >= ptr->len || ptr->ptr[i] != ':')
            {
-             /* Skip over a label, if any.  */
-             if (i >= ptr->len || ! is_name_beginner (ptr->ptr[i]))
-               break;
-             i++;
-             while (i < ptr->len && is_part_of_name (ptr->ptr[i]))
-               i++;
-             if (i < ptr->len && is_name_ender (ptr->ptr[i]))
-               i++;
-             if (LABELS_WITHOUT_COLONS)
-               break;
-             /* Skip whitespace.  */
-             while (i < ptr->len && ISWHITE (ptr->ptr[i]))
-               i++;
-             /* Check for the colon.  */
-             if (i >= ptr->len || ptr->ptr[i] != ':')
-               {
-                 i = line_start;
-                 break;
-               }
-             i++;
-             line_start = i;
+             i = line_start;
+             break;
            }
-
+         i++;
+         line_start = i;
        }
+
       /* Skip trailing whitespace.  */
       while (i < ptr->len && ISWHITE (ptr->ptr[i]))
        i++;
@@ -302,8 +301,6 @@ get_token (int idx, sb *in, sb *name)
 static int
 getstring (int idx, sb *in, sb *acc)
 {
-  idx = sb_skip_white (idx, in);
-
   while (idx < in->len
         && (in->ptr[idx] == '"'
             || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
@@ -382,13 +379,13 @@ getstring (int idx, sb *in, sb *acc)
 /* Fetch string from the input stream,
    rules:
     'Bxyx<whitespace>          -> return 'Bxyza
-    %<char>            -> return string of decimal value of x
-    "<string>"         -> return string
-    xyx<whitespace>     -> return xyz
-*/
+    %<expr>            -> return string of decimal value of <expr>
+    "string"           -> return string
+    (string)           -> return (string-including-whitespaces)
+    xyx<whitespace>     -> return xyz.  */
 
 static int
-get_any_string (int idx, sb *in, sb *out, int expand, int pretend_quoted)
+get_any_string (int idx, sb *in, sb *out)
 {
   sb_reset (out);
   idx = sb_skip_white (idx, in);
@@ -400,12 +397,11 @@ get_any_string (int idx, sb *in, sb *out, int expand, int pretend_quoted)
          while (!ISSEP (in->ptr[idx]))
            sb_add_char (out, in->ptr[idx++]);
        }
-      else if (in->ptr[idx] == '%'
-              && macro_alternate
-              && expand)
+      else if (in->ptr[idx] == '%' && macro_alternate)
        {
          int val;
          char buf[20];
+
          /* Turns the next expression into a string.  */
          /* xgettext: no-c-format */
          idx = (*macro_expr) (_("% operator needs absolute expression"),
@@ -419,15 +415,12 @@ get_any_string (int idx, sb *in, sb *out, int expand, int pretend_quoted)
               || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
               || (macro_alternate && in->ptr[idx] == '\''))
        {
-         if (macro_alternate
-             && ! macro_strip_at
-             && expand)
+         if (macro_alternate && ! macro_strip_at && in->ptr[idx] != '<')
            {
              /* Keep the quotes.  */
-             sb_add_char (out, '\"');
-
+             sb_add_char (out, '"');
              idx = getstring (idx, in, out);
-             sb_add_char (out, '\"');
+             sb_add_char (out, '"');
            }
          else
            {
@@ -436,35 +429,91 @@ get_any_string (int idx, sb *in, sb *out, int expand, int pretend_quoted)
        }
       else
        {
+         char *br_buf = xmalloc(1);
+         char *in_br = br_buf;
+
+         *in_br = '\0';
          while (idx < in->len
-                && (in->ptr[idx] == '"'
-                    || in->ptr[idx] == '\''
-                    || pretend_quoted
+                && (*in_br
                     || (in->ptr[idx] != ' '
-                        && in->ptr[idx] != '\t'
-                        && in->ptr[idx] != ','
-                        && (in->ptr[idx] != '<'
-                            || (! macro_alternate && ! macro_mri)))))
+                        && in->ptr[idx] != '\t'))
+                && in->ptr[idx] != ','
+                && (in->ptr[idx] != '<'
+                    || (! macro_alternate && ! macro_mri)))
            {
-             if (in->ptr[idx] == '"'
-                 || in->ptr[idx] == '\'')
+             char tchar = in->ptr[idx];
+
+             switch (tchar)
                {
-                 char tchar = in->ptr[idx];
+               case '"':
+               case '\'':
                  sb_add_char (out, in->ptr[idx++]);
                  while (idx < in->len
                         && in->ptr[idx] != tchar)
                    sb_add_char (out, in->ptr[idx++]);
                  if (idx == in->len)
                    return idx;
+                 break;
+               case '(':
+               case '[':
+                 if (in_br > br_buf)
+                   --in_br;
+                 else
+                   {
+                     br_buf = xmalloc(strlen(in_br) + 2);
+                     strcpy(br_buf + 1, in_br);
+                     free(in_br);
+                     in_br = br_buf;
+                   }
+                 *in_br = tchar;
+                 break;
+               case ')':
+                 if (*in_br == '(')
+                   ++in_br;
+                 break;
+               case ']':
+                 if (*in_br == '[')
+                   ++in_br;
+                 break;
                }
-             sb_add_char (out, in->ptr[idx++]);
+             sb_add_char (out, tchar);
+             ++idx;
            }
+         free(br_buf);
        }
     }
 
   return idx;
 }
 
+/* Allocate a new formal.  */
+
+static formal_entry *
+new_formal (void)
+{
+  formal_entry *formal;
+
+  formal = xmalloc (sizeof (formal_entry));
+
+  sb_new (&formal->name);
+  sb_new (&formal->def);
+  sb_new (&formal->actual);
+  formal->next = NULL;
+  formal->type = FORMAL_OPTIONAL;
+  return formal;
+}
+
+/* Free a formal.  */
+
+static void
+del_formal (formal_entry *formal)
+{
+  sb_kill (&formal->actual);
+  sb_kill (&formal->def);
+  sb_kill (&formal->name);
+  free (formal);
+}
+
 /* Pick up the formal parameters of a macro definition.  */
 
 static int
@@ -476,15 +525,9 @@ do_formals (macro_entry *macro, int idx, sb *in)
   idx = sb_skip_white (idx, in);
   while (idx < in->len)
     {
-      formal_entry *formal;
+      formal_entry *formal = new_formal ();
       int cidx;
 
-      formal = (formal_entry *) xmalloc (sizeof (formal_entry));
-
-      sb_new (&formal->name);
-      sb_new (&formal->def);
-      sb_new (&formal->actual);
-
       idx = get_token (idx, in, &formal->name);
       if (formal->name.len == 0)
        {
@@ -494,15 +537,57 @@ do_formals (macro_entry *macro, int idx, sb *in)
        }
       idx = sb_skip_white (idx, in);
       /* This is a formal.  */
+      name = sb_terminate (&formal->name);
+      if (! macro_mri
+         && idx < in->len
+         && in->ptr[idx] == ':'
+         && (! is_name_beginner (':')
+             || idx + 1 >= in->len
+             || ! is_part_of_name (in->ptr[idx + 1])))
+       {
+         /* Got a qualifier.  */
+         sb qual;
+
+         sb_new (&qual);
+         idx = get_token (sb_skip_white (idx + 1, in), in, &qual);
+         sb_terminate (&qual);
+         if (qual.len == 0)
+           as_bad_where (macro->file,
+                         macro->line,
+                         _("Missing parameter qualifier for `%s' in macro `%s'"),
+                         name,
+                         macro->name);
+         else if (strcmp (qual.ptr, "req") == 0)
+           formal->type = FORMAL_REQUIRED;
+         else if (strcmp (qual.ptr, "vararg") == 0)
+           formal->type = FORMAL_VARARG;
+         else
+           as_bad_where (macro->file,
+                         macro->line,
+                         _("`%s' is not a valid parameter qualifier for `%s' in macro `%s'"),
+                         qual.ptr,
+                         name,
+                         macro->name);
+         sb_kill (&qual);
+         idx = sb_skip_white (idx, in);
+       }
       if (idx < in->len && in->ptr[idx] == '=')
        {
          /* Got a default.  */
-         idx = get_any_string (idx + 1, in, &formal->def, 1, 0);
+         idx = get_any_string (idx + 1, in, &formal->def);
          idx = sb_skip_white (idx, in);
+         if (formal->type == FORMAL_REQUIRED)
+           {
+             sb_reset (&formal->def);
+             as_warn_where (macro->file,
+                           macro->line,
+                           _("Pointless default value for required parameter `%s' in macro `%s'"),
+                           name,
+                           macro->name);
+           }
        }
 
       /* Add to macro's hash table.  */
-      name = sb_terminate (&formal->name);
       if (! hash_find (macro->formal_hash, name))
        hash_jam (macro->formal_hash, name, formal);
       else
@@ -513,6 +598,10 @@ do_formals (macro_entry *macro, int idx, sb *in)
                      macro->name);
 
       formal->index = macro->formal_count++;
+      *p = formal;
+      p = &formal->next;
+      if (formal->type == FORMAL_VARARG)
+       break;
       cidx = idx;
       idx = sb_skip_comma (idx, in);
       if (idx != cidx && idx >= in->len)
@@ -520,23 +609,14 @@ do_formals (macro_entry *macro, int idx, sb *in)
          idx = cidx;
          break;
        }
-      *p = formal;
-      p = &formal->next;
-      *p = NULL;
     }
 
   if (macro_mri)
     {
-      formal_entry *formal;
+      formal_entry *formal = new_formal ();
 
       /* Add a special NARG formal, which macro_expand will set to the
          number of arguments.  */
-      formal = (formal_entry *) xmalloc (sizeof (formal_entry));
-
-      sb_new (&formal->name);
-      sb_new (&formal->def);
-      sb_new (&formal->actual);
-
       /* The same MRI assemblers which treat '@' characters also use
          the name $NARG.  At least until we find an exception.  */
       if (macro_strip_at)
@@ -557,7 +637,6 @@ do_formals (macro_entry *macro, int idx, sb *in)
 
       formal->index = NARG_INDEX;
       *p = formal;
-      formal->next = NULL;
     }
 
   return idx;
@@ -827,10 +906,8 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
              while (in->ptr[src] != '\n')
                {
                  const char *name;
-                 formal_entry *f;
+                 formal_entry *f = new_formal ();
 
-                 f = (formal_entry *) xmalloc (sizeof (formal_entry));
-                 sb_new (&f->name);
                  src = get_token (src, in, &f->name);
                  name = sb_terminate (&f->name);
                  if (! hash_find (formal_hash, name))
@@ -838,8 +915,6 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
                      static int loccnt;
                      char buf[20];
 
-                     sb_new (&f->def);
-                     sb_new (&f->actual);
                      f->index = LOCAL_INDEX;
                      f->next = loclist;
                      loclist = f;
@@ -857,8 +932,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
                                    macro->line + macro_line,
                                    _("`%s' was already used as parameter (or another local) name"),
                                    name);
-                     sb_kill (&f->name);
-                     free (f);
+                     del_formal (f);
                    }
 
                  src = sb_skip_comma (src, in);
@@ -935,10 +1009,7 @@ macro_expand_body (sb *in, sb *out, formal_entry *formals,
       /* Setting the value to NULL effectively deletes the entry.  We
          avoid calling hash_delete because it doesn't reclaim memory.  */
       hash_jam (formal_hash, sb_terminate (&loclist->name), NULL);
-      sb_kill (&loclist->name);
-      sb_kill (&loclist->def);
-      sb_kill (&loclist->actual);
-      free (loclist);
+      del_formal (loclist);
       loclist = f;
     }
 
@@ -954,10 +1025,9 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
   sb t;
   formal_entry *ptr;
   formal_entry *f;
-  int is_positional = 0;
   int is_keyword = 0;
   int narg = 0;
-  const char *err;
+  const char *err = NULL;
 
   sb_new (&t);
 
@@ -981,18 +1051,14 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
                  && in->ptr[idx] != ' '
                  && in->ptr[idx] != '\t')
            {
-             formal_entry *n;
+             formal_entry *n = new_formal ();
 
-             n = (formal_entry *) xmalloc (sizeof (formal_entry));
-             sb_new (&n->name);
-             sb_new (&n->def);
-             sb_new (&n->actual);
              n->index = QUAL_INDEX;
 
              n->next = m->formals;
              m->formals = n;
 
-             idx = get_any_string (idx, in, &n->actual, 1, 0);
+             idx = get_any_string (idx, in, &n->actual);
            }
        }
     }
@@ -1021,27 +1087,39 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
          sb_reset (&t);
          idx = get_token (idx, in, &t);
          if (in->ptr[idx] != '=')
-           return _("confusion in formal parameters");
+           {
+             err = _("confusion in formal parameters");
+             break;
+           }
 
          /* Lookup the formal in the macro's list.  */
          ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
          if (!ptr)
-           return _("macro formal argument does not exist");
+           as_bad (_("Parameter named `%s' does not exist for macro `%s'"),
+                   t.ptr,
+                   m->name);
          else
            {
              /* Insert this value into the right place.  */
-             sb_reset (&ptr->actual);
-             idx = get_any_string (idx + 1, in, &ptr->actual, 0, 0);
+             if (ptr->actual.len)
+               {
+                 as_warn (_("Value for parameter `%s' of macro `%s' was already specified"),
+                          ptr->name.ptr,
+                          m->name);
+                 sb_reset (&ptr->actual);
+               }
+             idx = get_any_string (idx + 1, in, &ptr->actual);
              if (ptr->actual.len > 0)
                ++narg;
            }
        }
       else
        {
-         /* This is a positional arg.  */
-         is_positional = 1;
          if (is_keyword)
-           return _("can't mix positional and keyword arguments");
+           {
+             err = _("can't mix positional and keyword arguments");
+             break;
+           }
 
          if (!f)
            {
@@ -1049,13 +1127,12 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
              int c;
 
              if (!macro_mri)
-               return _("too many positional arguments");
+               {
+                 err = _("too many positional arguments");
+                 break;
+               }
 
-             f = (formal_entry *) xmalloc (sizeof (formal_entry));
-             sb_new (&f->name);
-             sb_new (&f->def);
-             sb_new (&f->actual);
-             f->next = NULL;
+             f = new_formal ();
 
              c = -1;
              for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next)
@@ -1067,8 +1144,13 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
              f->index = c;
            }
 
-         sb_reset (&f->actual);
-         idx = get_any_string (idx, in, &f->actual, 1, 0);
+         if (f->type != FORMAL_VARARG)
+           idx = get_any_string (idx, in, &f->actual);
+         else
+           {
+             sb_add_buffer (&f->actual, in->ptr + idx, in->len - idx);
+             idx = in->len;
+           }
          if (f->actual.len > 0)
            ++narg;
          do
@@ -1089,19 +1171,29 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
        }
     }
 
-  if (macro_mri)
+  if (! err)
     {
-      char buffer[20];
-
-      sb_reset (&t);
-      sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
-      ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
-      sb_reset (&ptr->actual);
-      sprintf (buffer, "%d", narg);
-      sb_add_string (&ptr->actual, buffer);
-    }
+      for (ptr = m->formals; ptr; ptr = ptr->next)
+       {
+         if (ptr->type == FORMAL_REQUIRED && ptr->actual.len == 0)
+           as_bad (_("Missing value for required parameter `%s' of macro `%s'"),
+                   ptr->name.ptr,
+                   m->name);
+       }
+
+      if (macro_mri)
+       {
+         char buffer[20];
+
+         sb_reset (&t);
+         sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
+         ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
+         sprintf (buffer, "%d", narg);
+         sb_add_string (&ptr->actual, buffer);
+       }
 
-  err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m);
+      err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m);
+    }
 
   /* Discard any unnamed formal arguments.  */
   if (macro_mri)
@@ -1115,11 +1207,8 @@ macro_expand (int idx, sb *in, macro_entry *m, sb *out)
            pf = &(*pf)->next;
          else
            {
-             sb_kill (&(*pf)->name);
-             sb_kill (&(*pf)->def);
-             sb_kill (&(*pf)->actual);
              f = (*pf)->next;
-             free (*pf);
+             del_formal (*pf);
              *pf = f;
            }
        }
@@ -1191,14 +1280,11 @@ free_macro(macro_entry *macro)
 
   for (formal = macro->formals; formal; )
     {
-      void *ptr;
+      formal_entry *f;
 
-      sb_kill (&formal->name);
-      sb_kill (&formal->def);
-      sb_kill (&formal->actual);
-      ptr = formal;
+      f = formal;
       formal = formal->next;
-      free (ptr);
+      del_formal (f);
     }
   hash_die (macro->formal_hash);
   sb_kill (&macro->sub);
@@ -1263,6 +1349,7 @@ expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *))
 
   f.index = 1;
   f.next = NULL;
+  f.type = FORMAL_OPTIONAL;
 
   sb_reset (out);
 
@@ -1279,7 +1366,7 @@ expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *))
       while (idx < in->len)
        {
          if (!irpc)
-           idx = get_any_string (idx, in, &f.actual, 1, 0);
+           idx = get_any_string (idx, in, &f.actual);
          else
            {
              if (in->ptr[idx] == '"')
@@ -1308,6 +1395,9 @@ expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *))
     }
 
   hash_die (h);
+  sb_kill (&f.actual);
+  sb_kill (&f.def);
+  sb_kill (&f.name);
   sb_kill (&sub);
 
   return err;
This page took 0.030243 seconds and 4 git commands to generate.