/* macro.c - macro support for gas
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Written by Steve and Judy Chamberlain of Cygnus Support,
sac@cygnus.com
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,
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
-#include "config.h"
-
-#ifndef __GNUC__
-# if HAVE_ALLOCA_H
-# include <alloca.h>
-# else
-# ifdef _AIX
-/* Indented so that pre-ansi C compilers will ignore it, rather than
- choke on it. Some versions of AIX require this to be the first
- thing in the file. */
- #pragma alloca
-# else
-# ifndef alloca /* predefined by HP cc +Olibcalls */
-# if !defined (__STDC__) && !defined (__hpux)
-extern char *alloca ();
-# else
-extern void *alloca ();
-# endif /* __STDC__, __hpux */
-# endif /* alloca */
-# endif /* _AIX */
-# endif /* HAVE_ALLOCA_H */
-#endif /* __GNUC__ */
-
-#include <stdio.h>
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#include <strings.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
#include "as.h"
-#include "libiberty.h"
#include "safe-ctype.h"
#include "sb.h"
-#include "hash.h"
#include "macro.h"
-#include "asintl.h"
-
/* The routines in this file handle macro definition and expansion.
They are called by gas. */
-/* Internal functions. */
-
-static int get_token (int, sb *, sb *);
-static int getstring (int, sb *, sb *);
-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);
-static const char *macro_expand_body
- (sb *, sb *, formal_entry *, struct hash_control *, const macro_entry *);
-static const char *macro_expand (int, sb *, macro_entry *, sb *);
-static void free_macro(macro_entry *);
-
#define ISWHITE(x) ((x) == ' ' || (x) == '\t')
#define ISSEP(x) \
void
macro_init (int alternate, int mri, int strip_at,
- int (*expr) (const char *, int, sb *, int *))
+ int (*exp) (const char *, int, sb *, int *))
{
macro_hash = hash_new ();
macro_defined = 0;
macro_alternate = alternate;
macro_mri = mri;
macro_strip_at = strip_at;
- macro_expr = expr;
+ macro_expr = exp;
}
/* Switch in and out of alternate mode on the fly. */
{
/* Try to find the first pseudo op on the line. */
int i = line_start;
+ bfd_boolean had_colon = FALSE;
/* With normal syntax we can suck what we want till we get
to the dot. With the alternate, labels have to start in
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] != ':')
{
+ /* LABELS_WITHOUT_COLONS doesn't mean we cannot have a
+ colon after a label. If we do have a colon on the
+ first label then handle more than one label on the
+ line, assuming that each label has a colon. */
+ if (LABELS_WITHOUT_COLONS && !had_colon)
+ break;
i = line_start;
break;
}
i++;
line_start = i;
+ had_colon = TRUE;
}
/* Skip trailing whitespace. */
}
else
{
- char *br_buf = xmalloc(1);
+ char *br_buf = (char *) xmalloc(1);
char *in_br = br_buf;
*in_br = '\0';
--in_br;
else
{
- br_buf = xmalloc(strlen(in_br) + 2);
+ br_buf = (char *) xmalloc(strlen(in_br) + 2);
strcpy(br_buf + 1, in_br);
free(in_br);
in_br = br_buf;
{
formal_entry *formal;
- formal = xmalloc (sizeof (formal_entry));
+ formal = (formal_entry *) xmalloc (sizeof (formal_entry));
sb_new (&formal->name);
sb_new (&formal->def);
return idx;
}
+/* Free the memory allocated to a macro. */
+
+static void
+free_macro (macro_entry *macro)
+{
+ formal_entry *formal;
+
+ for (formal = macro->formals; formal; )
+ {
+ formal_entry *f;
+
+ f = formal;
+ formal = formal->next;
+ del_formal (f);
+ }
+ hash_die (macro->formal_hash);
+ sb_kill (¯o->sub);
+ free (macro);
+}
+
/* Define a new macro. Returns NULL on success, otherwise returns an
error message. If NAMEP is not NULL, *NAMEP is set to the name of
the macro which was defined. */
if (hash_find (macro_hash, macro->name))
error = _("Macro `%s' was already defined");
if (!error)
- error = hash_jam (macro_hash, macro->name, (PTR) macro);
+ error = hash_jam (macro_hash, macro->name, (void *) macro);
if (namep != NULL)
*namep = macro->name;
if (! macro
|| src + 5 >= in->len
|| strncasecmp (in->ptr + src, "LOCAL", 5) != 0
- || ! ISWHITE (in->ptr[src + 5]))
+ || ! ISWHITE (in->ptr[src + 5])
+ /* PR 11507: Skip keyword LOCAL if it is found inside a quoted string. */
+ || inquote)
{
sb_reset (&t);
src = sub_actual (src, in, &t, formal_hash,
while (loclist != NULL)
{
formal_entry *f;
+ const char *name;
f = loclist->next;
- /* 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);
+ name = sb_terminate (&loclist->name);
+ hash_delete (formal_hash, name, f == NULL);
del_formal (loclist);
loclist = f;
}
sb t;
formal_entry *ptr;
formal_entry *f;
- int is_positional = 0;
int is_keyword = 0;
int narg = 0;
const char *err = NULL;
/* Lookup the formal in the macro's list. */
ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
if (!ptr)
- as_bad (_("Parameter named `%s' does not exist for macro `%s'"),
- t.ptr,
- m->name);
+ {
+ as_bad (_("Parameter named `%s' does not exist for macro `%s'"),
+ t.ptr,
+ m->name);
+ sb_reset (&t);
+ idx = get_any_string (idx + 1, in, &t);
+ }
else
{
/* Insert this value into the right place. */
}
else
{
- /* This is a positional arg. */
- is_positional = 1;
if (is_keyword)
{
err = _("can't mix positional and keyword arguments");
const char **error, macro_entry **info)
{
const char *s;
- char *copy, *cs;
+ char *copy, *cls;
macro_entry *macro;
sb line_sb;
copy = (char *) alloca (s - line + 1);
memcpy (copy, line, s - line);
copy[s - line] = '\0';
- for (cs = copy; *cs != '\0'; cs++)
- *cs = TOLOWER (*cs);
+ for (cls = copy; *cls != '\0'; cls ++)
+ *cls = TOLOWER (*cls);
macro = (macro_entry *) hash_find (macro_hash, copy);
return 1;
}
-/* Free the memory allocated to a macro. */
-
-static void
-free_macro(macro_entry *macro)
-{
- formal_entry *formal;
-
- for (formal = macro->formals; formal; )
- {
- formal_entry *f;
-
- f = formal;
- formal = formal->next;
- del_formal (f);
- }
- hash_die (macro->formal_hash);
- sb_kill (¯o->sub);
- free (macro);
-}
-
/* Delete a macro. */
void
copy[i] = TOLOWER (name[i]);
copy[i] = '\0';
- /* Since hash_delete doesn't free memory, just clear out the entry. */
- if ((macro = hash_find (macro_hash, copy)) != NULL)
+ /* We can only ask hash_delete to free memory if we are deleting
+ macros in reverse order to their definition.
+ So just clear out the entry. */
+ if ((macro = (macro_entry *) hash_find (macro_hash, copy)) != NULL)
{
hash_jam (macro_hash, copy, NULL);
free_macro (macro);
}
else
{
+ bfd_boolean in_quotes = FALSE;
+
if (irpc && in->ptr[idx] == '"')
- ++idx;
+ {
+ in_quotes = TRUE;
+ ++idx;
+ }
+
while (idx < in->len)
{
if (!irpc)
{
int nxt;
+ if (irpc)
+ in_quotes = ! in_quotes;
+
nxt = sb_skip_white (idx + 1, in);
if (nxt >= in->len)
{
sb_add_char (&f.actual, in->ptr[idx]);
++idx;
}
+
err = macro_expand_body (&sub, out, &f, h, 0);
if (err != NULL)
break;
if (!irpc)
idx = sb_skip_comma (idx, in);
- else
+ else if (! in_quotes)
idx = sb_skip_white (idx, in);
}
}