-/* macro.c - macro support for gas and gasp
- Copyright (C) 1994, 95, 96, 97, 98, 99, 2000
+/* macro.c - macro support for gas
+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
Written by Steve and Judy Chamberlain of Cygnus Support,
#include "config.h"
-/* AIX requires this to be the first thing in the file. */
-#ifdef __GNUC__
-# ifndef alloca
-# ifdef __STDC__
-extern void *alloca ();
-# else
-extern char *alloca ();
-# endif
-# endif
-#else
+#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 */
# endif /* alloca */
# endif /* _AIX */
# endif /* HAVE_ALLOCA_H */
-#endif
+#endif /* __GNUC__ */
#include <stdio.h>
#ifdef HAVE_STRING_H
#else
#include <strings.h>
#endif
-#include <ctype.h>
#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 both gasp and gas. */
+ They are called by gas. */
/* Internal functions. */
-static int get_token PARAMS ((int, sb *, sb *));
-static int getstring PARAMS ((int, sb *, sb *));
-static int get_any_string PARAMS ((int, sb *, sb *, int, int));
-static int do_formals PARAMS ((macro_entry *, int, sb *));
-static int get_apost_token PARAMS ((int, sb *, sb *, int));
-static int sub_actual
- PARAMS ((int, sb *, sb *, struct hash_control *, int, sb *, int));
+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 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
- PARAMS ((sb *, sb *, formal_entry *, struct hash_control *, int, int));
-static const char *macro_expand PARAMS ((int, sb *, macro_entry *, sb *, int));
+ (sb *, sb *, formal_entry *, struct hash_control *, int);
+static const char *macro_expand (int, sb *, macro_entry *, sb *);
#define ISWHITE(x) ((x) == ' ' || (x) == '\t')
/* The macro hash table. */
-static struct hash_control *macro_hash;
+struct hash_control *macro_hash;
/* Whether any macros have been defined. */
int macro_defined;
-/* Whether we are in GASP alternate mode. */
+/* Whether we are in alternate syntax mode. */
static int macro_alternate;
/* Function to use to parse an expression. */
-static int (*macro_expr) PARAMS ((const char *, int, sb *, int *));
+static int (*macro_expr) (const char *, int, sb *, int *);
/* Number of macro expansions that have been done. */
/* Initialize macro processing. */
void
-macro_init (alternate, mri, strip_at, expr)
- int alternate;
- int mri;
- int strip_at;
- int (*expr) PARAMS ((const char *, int, sb *, int *));
+macro_init (int alternate, int mri, int strip_at,
+ int (*expr) (const char *, int, sb *, int *))
{
macro_hash = hash_new ();
macro_defined = 0;
macro_expr = expr;
}
+/* Switch in and out of alternate mode on the fly. */
+
+void
+macro_set_alternate (int alternate)
+{
+ macro_alternate = alternate;
+}
+
/* Switch in and out of MRI mode on the fly. */
void
-macro_mri_mode (mri)
- int mri;
+macro_mri_mode (int mri)
{
macro_mri = mri;
}
Return 1 on success, 0 on unexpected EOF. */
int
-buffer_and_nest (from, to, ptr, get_line)
- const char *from;
- const char *to;
- sb *ptr;
- int (*get_line) PARAMS ((sb *));
+buffer_and_nest (const char *from, const char *to, sb *ptr,
+ int (*get_line) (sb *))
{
int from_len = strlen (from);
int to_len = strlen (to);
/* Skip over a label. */
while (i < ptr->len
- && (isalnum ((unsigned char) ptr->ptr[i])
+ && (ISALNUM (ptr->ptr[i])
|| ptr->ptr[i] == '_'
|| ptr->ptr[i] == '$'))
i++;
i++;
if (strncasecmp (ptr->ptr + i, from, from_len) == 0
&& (ptr->len == (i + from_len)
- || ! isalnum (ptr->ptr[i + from_len])))
+ || ! ISALNUM (ptr->ptr[i + from_len])))
depth++;
if (strncasecmp (ptr->ptr + i, to, to_len) == 0
&& (ptr->len == (i + to_len)
- || ! isalnum (ptr->ptr[i + to_len])))
+ || ! ISALNUM (ptr->ptr[i + to_len])))
{
depth--;
if (depth == 0)
}
}
- /* Add a CR to the end and keep running. */
- sb_add_char (ptr, '\n');
+ /* Add the original end-of-line char to the end and keep running. */
+ sb_add_char (ptr, more);
line_start = ptr->len;
more = get_line (ptr);
}
/* Pick up a token. */
static int
-get_token (idx, in, name)
- int idx;
- sb *in;
- sb *name;
+get_token (int idx, sb *in, sb *name)
{
if (idx < in->len
- && (isalpha ((unsigned char) in->ptr[idx])
+ && (ISALPHA (in->ptr[idx])
|| in->ptr[idx] == '_'
|| in->ptr[idx] == '$'))
{
sb_add_char (name, in->ptr[idx++]);
while (idx < in->len
- && (isalnum ((unsigned char) in->ptr[idx])
+ && (ISALNUM (in->ptr[idx])
|| in->ptr[idx] == '_'
|| in->ptr[idx] == '$'))
{
/* Pick up a string. */
static int
-getstring (idx, in, acc)
- int idx;
- sb *in;
- sb *acc;
+getstring (int idx, sb *in, sb *acc)
{
idx = sb_skip_white (idx, in);
if (macro_alternate && in->ptr[idx] == '!')
{
- idx++;
+ idx ++;
sb_add_char (acc, in->ptr[idx]);
- idx++;
+ idx ++;
}
else if (escaped && in->ptr[idx] == tchar)
{
sb_add_char (acc, tchar);
- idx++;
+ idx ++;
}
else
{
if (in->ptr[idx] == tchar)
{
- idx++;
+ idx ++;
if (idx >= in->len || in->ptr[idx] != tchar)
break;
}
sb_add_char (acc, in->ptr[idx]);
- idx++;
+ idx ++;
}
}
}
*/
static int
-get_any_string (idx, in, out, expand, pretend_quoted)
- int idx;
- sb *in;
- sb *out;
- int expand;
- int pretend_quoted;
+get_any_string (int idx, sb *in, sb *out, int expand, int pretend_quoted)
{
sb_reset (out);
idx = sb_skip_white (idx, in);
if (idx < in->len)
{
- if (in->len > 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))
+ if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))
{
while (!ISSEP (in->ptr[idx]))
sb_add_char (out, in->ptr[idx++]);
int val;
char buf[20];
/* Turns the next expression into a string. */
+ /* xgettext: no-c-format */
idx = (*macro_expr) (_("% operator needs absolute expression"),
idx + 1,
in,
&val);
- sprintf(buf, "%d", val);
+ sprintf (buf, "%d", val);
sb_add_string (out, buf);
}
else if (in->ptr[idx] == '"'
/* Pick up the formal parameters of a macro definition. */
static int
-do_formals (macro, idx, in)
- macro_entry *macro;
- int idx;
- sb *in;
+do_formals (macro_entry *macro, int idx, sb *in)
{
formal_entry **p = ¯o->formals;
the macro which was defined. */
const char *
-define_macro (idx, in, label, get_line, namep)
- int idx;
- sb *in;
- sb *label;
- int (*get_line) PARAMS ((sb *));
- const char **namep;
+define_macro (int idx, sb *in, sb *label,
+ int (*get_line) (sb *), const char **namep)
{
macro_entry *macro;
sb name;
/* And stick it in the macro hash table. */
for (idx = 0; idx < name.len; idx++)
- if (isupper ((unsigned char) name.ptr[idx]))
- name.ptr[idx] = tolower (name.ptr[idx]);
+ name.ptr[idx] = TOLOWER (name.ptr[idx]);
namestr = sb_terminate (&name);
hash_jam (macro_hash, namestr, (PTR) macro);
/* Scan a token, and then skip KIND. */
static int
-get_apost_token (idx, in, name, kind)
- int idx;
- sb *in;
- sb *name;
- int kind;
+get_apost_token (int idx, sb *in, sb *name, int kind)
{
idx = get_token (idx, in, name);
if (idx < in->len
/* Substitute the actual value for a formal parameter. */
static int
-sub_actual (start, in, t, formal_hash, kind, out, copyifnotthere)
- int start;
- sb *in;
- sb *t;
- struct hash_control *formal_hash;
- int kind;
- sb *out;
- int copyifnotthere;
+sub_actual (int start, sb *in, sb *t, struct hash_control *formal_hash,
+ int kind, sb *out, int copyifnotthere)
{
int src;
formal_entry *ptr;
{
/* Doing this permits people to use & in macro bodies. */
sb_add_char (out, '&');
+ sb_add_sb (out, t);
}
else if (copyifnotthere)
{
/* Expand the body of a macro. */
static const char *
-macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
- sb *in;
- sb *out;
- formal_entry *formals;
- struct hash_control *formal_hash;
- int comment_char;
- int locals;
+macro_expand_body (sb *in, sb *out, formal_entry *formals,
+ struct hash_control *formal_hash, int locals)
{
sb t;
int src = 0;
else if (in->ptr[src] == '\\')
{
src++;
- if (in->ptr[src] == comment_char && comment_char != '\0')
- {
- /* This is a comment, just drop the rest of the line. */
- while (src < in->len
- && in->ptr[src] != '\n')
- src++;
- }
- else if (in->ptr[src] == '(')
+ if (in->ptr[src] == '(')
{
/* Sub in till the next ')' literally. */
src++;
sb_add_char (out, '&');
src++;
}
- else if (macro_mri
- && isalnum ((unsigned char) in->ptr[src]))
+ else if (macro_mri && ISALNUM (in->ptr[src]))
{
int ind;
formal_entry *f;
- if (isdigit ((unsigned char) in->ptr[src]))
+ if (ISDIGIT (in->ptr[src]))
ind = in->ptr[src] - '0';
- else if (isupper ((unsigned char) in->ptr[src]))
+ else if (ISUPPER (in->ptr[src]))
ind = in->ptr[src] - 'A' + 10;
else
ind = in->ptr[src] - 'a' + 10;
}
}
else if ((macro_alternate || macro_mri)
- && (isalpha ((unsigned char) in->ptr[src])
+ && (ISALPHA (in->ptr[src])
|| in->ptr[src] == '_'
|| in->ptr[src] == '$')
&& (! inquote
formal_entry *f;
src = sb_skip_white (src + 5, in);
- while (in->ptr[src] != '\n' && in->ptr[src] != comment_char)
+ while (in->ptr[src] != '\n')
{
static int loccnt;
char buf[20];
src = get_token (src, in, &f->name);
++loccnt;
- sprintf (buf, "LL%04x", loccnt);
+ sprintf (buf, IS_ELF ? ".LL%04x" : "LL%04x", loccnt);
sb_add_string (&f->actual, buf);
err = hash_jam (formal_hash, sb_terminate (&f->name), f);
}
}
}
- else if (comment_char != '\0'
- && in->ptr[src] == comment_char
- && src + 1 < in->len
- && in->ptr[src + 1] == comment_char
- && !inquote)
- {
- /* Two comment chars in a row cause the rest of the line to
- be dropped. */
- while (src < in->len && in->ptr[src] != '\n')
- src++;
- }
else if (in->ptr[src] == '"'
|| (macro_mri && in->ptr[src] == '\''))
{
body. */
static const char *
-macro_expand (idx, in, m, out, comment_char)
- int idx;
- sb *in;
- macro_entry *m;
- sb *out;
- int comment_char;
+macro_expand (int idx, sb *in, macro_entry *m, sb *out)
{
sb t;
formal_entry *ptr;
be referred to in the macro body as \0. */
if (idx < in->len && in->ptr[idx] == '.')
{
- formal_entry *n;
+ /* The Microtec assembler ignores this if followed by a white space.
+ (Macro invocation with empty extension) */
+ idx++;
+ if ( idx < in->len
+ && in->ptr[idx] != ' '
+ && in->ptr[idx] != '\t')
+ {
+ formal_entry *n;
- n = (formal_entry *) xmalloc (sizeof (formal_entry));
- sb_new (&n->name);
- sb_new (&n->def);
- sb_new (&n->actual);
- n->index = QUAL_INDEX;
+ 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;
+ n->next = m->formals;
+ m->formals = n;
- idx = get_any_string (idx + 1, in, &n->actual, 1, 0);
+ idx = get_any_string (idx, in, &n->actual, 1, 0);
+ }
}
}
/* Peel off the actuals and store them away in the hash tables' actuals. */
idx = sb_skip_white (idx, in);
- while (idx < in->len && in->ptr[idx] != comment_char)
+ while (idx < in->len)
{
int scan;
sb_add_string (&ptr->actual, buffer);
}
- err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash,
- comment_char, 1);
+ err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, 1);
if (err != NULL)
return err;
}
/* Check for a macro. If one is found, put the expansion into
- *EXPAND. COMMENT_CHAR is the comment character--this is used by
- gasp. Return 1 if a macro is found, 0 otherwise. */
+ *EXPAND. Return 1 if a macro is found, 0 otherwise. */
int
-check_macro (line, expand, comment_char, error, info)
- const char *line;
- sb *expand;
- int comment_char;
- const char **error;
- macro_entry **info;
+check_macro (const char *line, sb *expand,
+ const char **error, macro_entry **info)
{
const char *s;
char *copy, *cs;
macro_entry *macro;
sb line_sb;
- if (! isalpha ((unsigned char) *line)
+ if (! ISALPHA (*line)
&& *line != '_'
&& *line != '$'
&& (! macro_mri || *line != '.'))
return 0;
s = line + 1;
- while (isalnum ((unsigned char) *s)
+ while (ISALNUM (*s)
|| *s == '_'
|| *s == '$')
++s;
memcpy (copy, line, s - line);
copy[s - line] = '\0';
for (cs = copy; *cs != '\0'; cs++)
- if (isupper ((unsigned char) *cs))
- *cs = tolower (*cs);
+ *cs = TOLOWER (*cs);
macro = (macro_entry *) hash_find (macro_hash, copy);
sb_add_char (&line_sb, *s++);
sb_new (expand);
- *error = macro_expand (0, &line_sb, macro, expand, comment_char);
+ *error = macro_expand (0, &line_sb, macro, expand);
sb_kill (&line_sb);
/* Delete a macro. */
void
-delete_macro (name)
- const char *name;
+delete_macro (const char *name)
{
hash_delete (macro_hash, name);
}
success, or an error message otherwise. */
const char *
-expand_irp (irpc, idx, in, out, get_line, comment_char)
- int irpc;
- int idx;
- sb *in;
- sb *out;
- int (*get_line) PARAMS ((sb *));
- int comment_char;
+expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *))
{
const char *mn;
sb sub;
sb_reset (out);
idx = sb_skip_comma (idx, in);
- if (idx >= in->len || in->ptr[idx] == comment_char)
+ if (idx >= in->len)
{
/* Expand once with a null string. */
- err = macro_expand_body (&sub, out, &f, h, comment_char, 0);
+ err = macro_expand_body (&sub, out, &f, h, 0);
if (err != NULL)
return err;
}
{
if (irpc && in->ptr[idx] == '"')
++idx;
- while (idx < in->len && in->ptr[idx] != comment_char)
+ while (idx < in->len)
{
if (!irpc)
idx = get_any_string (idx, in, &f.actual, 1, 0);
int nxt;
nxt = sb_skip_white (idx + 1, in);
- if (nxt >= in->len || in->ptr[nxt] == comment_char)
+ if (nxt >= in->len)
{
idx = nxt;
break;
sb_add_char (&f.actual, in->ptr[idx]);
++idx;
}
- err = macro_expand_body (&sub, out, &f, h, comment_char, 0);
+ err = macro_expand_body (&sub, out, &f, h, 0);
if (err != NULL)
return err;
if (!irpc)