diff options
Diffstat (limited to 'contrib/binutils/gas/macro.c')
-rw-r--r-- | contrib/binutils/gas/macro.c | 1177 |
1 files changed, 0 insertions, 1177 deletions
diff --git a/contrib/binutils/gas/macro.c b/contrib/binutils/gas/macro.c deleted file mode 100644 index 0991744..0000000 --- a/contrib/binutils/gas/macro.c +++ /dev/null @@ -1,1177 +0,0 @@ -/* macro.c - macro support for gas - Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 - Free Software Foundation, Inc. - - Written by Steve and Judy Chamberlain of Cygnus Support, - sac@cygnus.com - - 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) - any later version. - - GAS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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. */ - -#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 "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 *, 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 - (sb *, sb *, formal_entry *, struct hash_control *, int); -static const char *macro_expand (int, sb *, macro_entry *, sb *); - -#define ISWHITE(x) ((x) == ' ' || (x) == '\t') - -#define ISSEP(x) \ - ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \ - || (x) == ')' || (x) == '(' \ - || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>'))) - -#define ISBASE(x) \ - ((x) == 'b' || (x) == 'B' \ - || (x) == 'q' || (x) == 'Q' \ - || (x) == 'h' || (x) == 'H' \ - || (x) == 'd' || (x) == 'D') - -/* The macro hash table. */ - -struct hash_control *macro_hash; - -/* Whether any macros have been defined. */ - -int macro_defined; - -/* Whether we are in alternate syntax mode. */ - -static int macro_alternate; - -/* Whether we are in MRI mode. */ - -static int macro_mri; - -/* Whether we should strip '@' characters. */ - -static int macro_strip_at; - -/* Function to use to parse an expression. */ - -static int (*macro_expr) (const char *, int, sb *, int *); - -/* Number of macro expansions that have been done. */ - -static int macro_number; - -/* Initialize macro processing. */ - -void -macro_init (int alternate, int mri, int strip_at, - int (*expr) (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; -} - -/* Switch in and out of MRI mode on the fly. */ - -void -macro_mri_mode (int mri) -{ - macro_mri = mri; -} - -/* Read input lines till we get to a TO string. - Increase nesting depth if we get a FROM string. - Put the results into sb at PTR. - Add a new input line to an sb using GET_LINE. - Return 1 on success, 0 on unexpected EOF. */ - -int -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); - int depth = 1; - int line_start = ptr->len; - - int more = get_line (ptr); - - while (more) - { - /* Try and find the first pseudo op on the line. */ - int i = line_start; - - if (! macro_alternate && ! macro_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 cant tell what's a label and - whats a pseudoop. */ - - /* Skip leading whitespace. */ - while (i < ptr->len && ISWHITE (ptr->ptr[i])) - i++; - - /* Skip over a label. */ - while (i < ptr->len - && (ISALNUM (ptr->ptr[i]) - || ptr->ptr[i] == '_' - || ptr->ptr[i] == '$')) - i++; - - /* And a colon. */ - if (i < ptr->len - && ptr->ptr[i] == ':') - i++; - - } - /* Skip trailing whitespace. */ - while (i < ptr->len && ISWHITE (ptr->ptr[i])) - i++; - - if (i < ptr->len && (ptr->ptr[i] == '.' - || macro_alternate - || macro_mri)) - { - if (ptr->ptr[i] == '.') - i++; - if (strncasecmp (ptr->ptr + i, from, from_len) == 0 - && (ptr->len == (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]))) - { - depth--; - if (depth == 0) - { - /* Reset the string to not include the ending rune. */ - ptr->len = line_start; - break; - } - } - } - - /* 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); - } - - /* Return 1 on success, 0 on unexpected EOF. */ - return depth == 0; -} - -/* Pick up a token. */ - -static int -get_token (int idx, sb *in, sb *name) -{ - if (idx < in->len - && (ISALPHA (in->ptr[idx]) - || in->ptr[idx] == '_' - || in->ptr[idx] == '$')) - { - sb_add_char (name, in->ptr[idx++]); - while (idx < in->len - && (ISALNUM (in->ptr[idx]) - || in->ptr[idx] == '_' - || in->ptr[idx] == '$')) - { - sb_add_char (name, in->ptr[idx++]); - } - } - /* Ignore trailing &. */ - if (macro_alternate && idx < in->len && in->ptr[idx] == '&') - idx++; - return idx; -} - -/* Pick up a string. */ - -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)) - || (in->ptr[idx] == '\'' && macro_alternate))) - { - if (in->ptr[idx] == '<') - { - int nest = 0; - idx++; - while ((in->ptr[idx] != '>' || nest) - && idx < in->len) - { - if (in->ptr[idx] == '!') - { - idx++; - sb_add_char (acc, in->ptr[idx++]); - } - else - { - if (in->ptr[idx] == '>') - nest--; - if (in->ptr[idx] == '<') - nest++; - sb_add_char (acc, in->ptr[idx++]); - } - } - idx++; - } - else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') - { - char tchar = in->ptr[idx]; - int escaped = 0; - - idx++; - - while (idx < in->len) - { - if (in->ptr[idx - 1] == '\\') - escaped ^= 1; - else - escaped = 0; - - if (macro_alternate && in->ptr[idx] == '!') - { - idx ++; - - sb_add_char (acc, in->ptr[idx]); - - idx ++; - } - else if (escaped && in->ptr[idx] == tchar) - { - sb_add_char (acc, tchar); - idx ++; - } - else - { - if (in->ptr[idx] == tchar) - { - idx ++; - - if (idx >= in->len || in->ptr[idx] != tchar) - break; - } - - sb_add_char (acc, in->ptr[idx]); - idx ++; - } - } - } - } - - return idx; -} - -/* 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 -*/ - -static int -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 > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx])) - { - while (!ISSEP (in->ptr[idx])) - sb_add_char (out, in->ptr[idx++]); - } - else if (in->ptr[idx] == '%' - && macro_alternate - && expand) - { - 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); - sb_add_string (out, buf); - } - else if (in->ptr[idx] == '"' - || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) - || (macro_alternate && in->ptr[idx] == '\'')) - { - if (macro_alternate - && ! macro_strip_at - && expand) - { - /* Keep the quotes. */ - sb_add_char (out, '\"'); - - idx = getstring (idx, in, out); - sb_add_char (out, '\"'); - } - else - { - idx = getstring (idx, in, out); - } - } - else - { - while (idx < in->len - && (in->ptr[idx] == '"' - || in->ptr[idx] == '\'' - || pretend_quoted - || (in->ptr[idx] != ' ' - && 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]; - 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; - } - sb_add_char (out, in->ptr[idx++]); - } - } - } - - return idx; -} - -/* Pick up the formal parameters of a macro definition. */ - -static int -do_formals (macro_entry *macro, int idx, sb *in) -{ - formal_entry **p = ¯o->formals; - - macro->formal_count = 0; - macro->formal_hash = hash_new (); - while (idx < in->len) - { - formal_entry *formal; - - formal = (formal_entry *) xmalloc (sizeof (formal_entry)); - - sb_new (&formal->name); - sb_new (&formal->def); - sb_new (&formal->actual); - - idx = sb_skip_white (idx, in); - idx = get_token (idx, in, &formal->name); - if (formal->name.len == 0) - break; - idx = sb_skip_white (idx, in); - if (formal->name.len) - { - /* This is a formal. */ - if (idx < in->len && in->ptr[idx] == '=') - { - /* Got a default. */ - idx = get_any_string (idx + 1, in, &formal->def, 1, 0); - } - } - - /* Add to macro's hash table. */ - hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal); - - formal->index = macro->formal_count; - idx = sb_skip_comma (idx, in); - macro->formal_count++; - *p = formal; - p = &formal->next; - *p = NULL; - } - - if (macro_mri) - { - formal_entry *formal; - const char *name; - - /* 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) - name = "$NARG"; - else - name = "NARG"; - - sb_add_string (&formal->name, name); - - /* Add to macro's hash table. */ - hash_jam (macro->formal_hash, name, formal); - - formal->index = NARG_INDEX; - *p = formal; - formal->next = NULL; - } - - return idx; -} - -/* 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. */ - -const char * -define_macro (int idx, sb *in, sb *label, - int (*get_line) (sb *), const char **namep) -{ - macro_entry *macro; - sb name; - const char *namestr; - - macro = (macro_entry *) xmalloc (sizeof (macro_entry)); - sb_new (¯o->sub); - sb_new (&name); - - macro->formal_count = 0; - macro->formals = 0; - - idx = sb_skip_white (idx, in); - if (! buffer_and_nest ("MACRO", "ENDM", ¯o->sub, get_line)) - return _("unexpected end of file in macro definition"); - if (label != NULL && label->len != 0) - { - sb_add_sb (&name, label); - if (idx < in->len && in->ptr[idx] == '(') - { - /* It's the label: MACRO (formals,...) sort */ - idx = do_formals (macro, idx + 1, in); - if (in->ptr[idx] != ')') - return _("missing ) after formals"); - } - else - { - /* It's the label: MACRO formals,... sort */ - idx = do_formals (macro, idx, in); - } - } - else - { - idx = get_token (idx, in, &name); - idx = sb_skip_comma (idx, in); - idx = do_formals (macro, idx, in); - } - - /* And stick it in the macro hash table. */ - for (idx = 0; idx < name.len; idx++) - name.ptr[idx] = TOLOWER (name.ptr[idx]); - namestr = sb_terminate (&name); - hash_jam (macro_hash, namestr, (PTR) macro); - - macro_defined = 1; - - if (namep != NULL) - *namep = namestr; - - return NULL; -} - -/* Scan a token, and then skip KIND. */ - -static int -get_apost_token (int idx, sb *in, sb *name, int kind) -{ - idx = get_token (idx, in, name); - if (idx < in->len - && in->ptr[idx] == kind - && (! macro_mri || macro_strip_at) - && (! macro_strip_at || kind == '@')) - idx++; - return idx; -} - -/* Substitute the actual value for a formal parameter. */ - -static int -sub_actual (int start, sb *in, sb *t, struct hash_control *formal_hash, - int kind, sb *out, int copyifnotthere) -{ - int src; - formal_entry *ptr; - - src = get_apost_token (start, in, t, kind); - /* See if it's in the macro's hash table, unless this is - macro_strip_at and kind is '@' and the token did not end in '@'. */ - if (macro_strip_at - && kind == '@' - && (src == start || in->ptr[src - 1] != '@')) - ptr = NULL; - else - ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t)); - if (ptr) - { - if (ptr->actual.len) - { - sb_add_sb (out, &ptr->actual); - } - else - { - sb_add_sb (out, &ptr->def); - } - } - else if (kind == '&') - { - /* Doing this permits people to use & in macro bodies. */ - sb_add_char (out, '&'); - sb_add_sb (out, t); - } - else if (copyifnotthere) - { - sb_add_sb (out, t); - } - else - { - sb_add_char (out, '\\'); - sb_add_sb (out, t); - } - return src; -} - -/* Expand the body of a macro. */ - -static const char * -macro_expand_body (sb *in, sb *out, formal_entry *formals, - struct hash_control *formal_hash, int locals) -{ - sb t; - int src = 0; - int inquote = 0; - formal_entry *loclist = NULL; - - sb_new (&t); - - while (src < in->len) - { - if (in->ptr[src] == '&') - { - sb_reset (&t); - if (macro_mri) - { - if (src + 1 < in->len && in->ptr[src + 1] == '&') - src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1); - else - sb_add_char (out, in->ptr[src++]); - } - else - { - /* FIXME: Why do we do this? */ - src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0); - } - } - else if (in->ptr[src] == '\\') - { - src++; - if (in->ptr[src] == '(') - { - /* Sub in till the next ')' literally. */ - src++; - while (src < in->len && in->ptr[src] != ')') - { - sb_add_char (out, in->ptr[src++]); - } - if (in->ptr[src] == ')') - src++; - else - return _("missplaced )"); - } - else if (in->ptr[src] == '@') - { - /* Sub in the macro invocation number. */ - - char buffer[10]; - src++; - sprintf (buffer, "%d", macro_number); - sb_add_string (out, buffer); - } - else if (in->ptr[src] == '&') - { - /* This is a preprocessor variable name, we don't do them - here. */ - sb_add_char (out, '\\'); - sb_add_char (out, '&'); - src++; - } - else if (macro_mri && ISALNUM (in->ptr[src])) - { - int ind; - formal_entry *f; - - if (ISDIGIT (in->ptr[src])) - ind = in->ptr[src] - '0'; - else if (ISUPPER (in->ptr[src])) - ind = in->ptr[src] - 'A' + 10; - else - ind = in->ptr[src] - 'a' + 10; - ++src; - for (f = formals; f != NULL; f = f->next) - { - if (f->index == ind - 1) - { - if (f->actual.len != 0) - sb_add_sb (out, &f->actual); - else - sb_add_sb (out, &f->def); - break; - } - } - } - else - { - sb_reset (&t); - src = sub_actual (src, in, &t, formal_hash, '\'', out, 0); - } - } - else if ((macro_alternate || macro_mri) - && (ISALPHA (in->ptr[src]) - || in->ptr[src] == '_' - || in->ptr[src] == '$') - && (! inquote - || ! macro_strip_at - || (src > 0 && in->ptr[src - 1] == '@'))) - { - if (! locals - || src + 5 >= in->len - || strncasecmp (in->ptr + src, "LOCAL", 5) != 0 - || ! ISWHITE (in->ptr[src + 5])) - { - sb_reset (&t); - src = sub_actual (src, in, &t, formal_hash, - (macro_strip_at && inquote) ? '@' : '\'', - out, 1); - } - else - { - formal_entry *f; - - src = sb_skip_white (src + 5, in); - while (in->ptr[src] != '\n') - { - static int loccnt; - char buf[20]; - const char *err; - - f = (formal_entry *) xmalloc (sizeof (formal_entry)); - sb_new (&f->name); - sb_new (&f->def); - sb_new (&f->actual); - f->index = LOCAL_INDEX; - f->next = loclist; - loclist = f; - - src = get_token (src, in, &f->name); - ++loccnt; - sprintf (buf, "LL%04x", loccnt); - sb_add_string (&f->actual, buf); - - err = hash_jam (formal_hash, sb_terminate (&f->name), f); - if (err != NULL) - return err; - - src = sb_skip_comma (src, in); - } - } - } - else if (in->ptr[src] == '"' - || (macro_mri && in->ptr[src] == '\'')) - { - inquote = !inquote; - sb_add_char (out, in->ptr[src++]); - } - else if (in->ptr[src] == '@' && macro_strip_at) - { - ++src; - if (src < in->len - && in->ptr[src] == '@') - { - sb_add_char (out, '@'); - ++src; - } - } - else if (macro_mri - && in->ptr[src] == '=' - && src + 1 < in->len - && in->ptr[src + 1] == '=') - { - formal_entry *ptr; - - sb_reset (&t); - src = get_token (src + 2, in, &t); - ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t)); - if (ptr == NULL) - { - /* FIXME: We should really return a warning string here, - but we can't, because the == might be in the MRI - comment field, and, since the nature of the MRI - comment field depends upon the exact instruction - being used, we don't have enough information here to - figure out whether it is or not. Instead, we leave - the == in place, which should cause a syntax error if - it is not in a comment. */ - sb_add_char (out, '='); - sb_add_char (out, '='); - sb_add_sb (out, &t); - } - else - { - if (ptr->actual.len) - { - sb_add_string (out, "-1"); - } - else - { - sb_add_char (out, '0'); - } - } - } - else - { - sb_add_char (out, in->ptr[src++]); - } - } - - sb_kill (&t); - - while (loclist != NULL) - { - formal_entry *f; - - 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); - sb_kill (&loclist->name); - sb_kill (&loclist->def); - sb_kill (&loclist->actual); - free (loclist); - loclist = f; - } - - return NULL; -} - -/* Assign values to the formal parameters of a macro, and expand the - body. */ - -static const char * -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; - - sb_new (&t); - - /* Reset any old value the actuals may have. */ - for (f = m->formals; f; f = f->next) - sb_reset (&f->actual); - f = m->formals; - while (f != NULL && f->index < 0) - f = f->next; - - if (macro_mri) - { - /* The macro may be called with an optional qualifier, which may - be referred to in the macro body as \0. */ - if (idx < in->len && in->ptr[idx] == '.') - { - /* 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->next = m->formals; - m->formals = n; - - 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) - { - int scan; - - /* Look and see if it's a positional or keyword arg. */ - scan = idx; - while (scan < in->len - && !ISSEP (in->ptr[scan]) - && !(macro_mri && in->ptr[scan] == '\'') - && (!macro_alternate && in->ptr[scan] != '=')) - scan++; - if (scan < in->len && !macro_alternate && in->ptr[scan] == '=') - { - is_keyword = 1; - - /* It's OK to go from positional to keyword. */ - - /* This is a keyword arg, fetch the formal name and - then the actual stuff. */ - sb_reset (&t); - idx = get_token (idx, in, &t); - if (in->ptr[idx] != '=') - return _("confusion in formal parameters"); - - /* 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"); - 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 > 0) - ++narg; - } - } - else - { - /* This is a positional arg. */ - is_positional = 1; - if (is_keyword) - return _("can't mix positional and keyword arguments"); - - if (!f) - { - formal_entry **pf; - int c; - - if (!macro_mri) - return _("too many positional arguments"); - - f = (formal_entry *) xmalloc (sizeof (formal_entry)); - sb_new (&f->name); - sb_new (&f->def); - sb_new (&f->actual); - f->next = NULL; - - c = -1; - for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) - if ((*pf)->index >= c) - c = (*pf)->index + 1; - if (c == -1) - c = 0; - *pf = f; - f->index = c; - } - - sb_reset (&f->actual); - idx = get_any_string (idx, in, &f->actual, 1, 0); - if (f->actual.len > 0) - ++narg; - do - { - f = f->next; - } - while (f != NULL && f->index < 0); - } - - if (! macro_mri) - idx = sb_skip_comma (idx, in); - else - { - if (in->ptr[idx] == ',') - ++idx; - if (ISWHITE (in->ptr[idx])) - break; - } - } - - 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)); - sb_reset (&ptr->actual); - sprintf (buffer, "%d", narg); - sb_add_string (&ptr->actual, buffer); - } - - err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, 1); - if (err != NULL) - return err; - - /* Discard any unnamed formal arguments. */ - if (macro_mri) - { - formal_entry **pf; - - pf = &m->formals; - while (*pf != NULL) - { - if ((*pf)->name.len != 0) - pf = &(*pf)->next; - else - { - sb_kill (&(*pf)->name); - sb_kill (&(*pf)->def); - sb_kill (&(*pf)->actual); - f = (*pf)->next; - free (*pf); - *pf = f; - } - } - } - - sb_kill (&t); - macro_number++; - - return NULL; -} - -/* Check for a macro. If one is found, put the expansion into - *EXPAND. Return 1 if a macro is found, 0 otherwise. */ - -int -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 (*line) - && *line != '_' - && *line != '$' - && (! macro_mri || *line != '.')) - return 0; - - s = line + 1; - while (ISALNUM (*s) - || *s == '_' - || *s == '$') - ++s; - - copy = (char *) alloca (s - line + 1); - memcpy (copy, line, s - line); - copy[s - line] = '\0'; - for (cs = copy; *cs != '\0'; cs++) - *cs = TOLOWER (*cs); - - macro = (macro_entry *) hash_find (macro_hash, copy); - - if (macro == NULL) - return 0; - - /* Wrap the line up in an sb. */ - sb_new (&line_sb); - while (*s != '\0' && *s != '\n' && *s != '\r') - sb_add_char (&line_sb, *s++); - - sb_new (expand); - *error = macro_expand (0, &line_sb, macro, expand); - - sb_kill (&line_sb); - - /* Export the macro information if requested. */ - if (info) - *info = macro; - - return 1; -} - -/* Delete a macro. */ - -void -delete_macro (const char *name) -{ - hash_delete (macro_hash, name); -} - -/* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a - combined macro definition and execution. This returns NULL on - success, or an error message otherwise. */ - -const char * -expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *)) -{ - const char *mn; - sb sub; - formal_entry f; - struct hash_control *h; - const char *err; - - if (irpc) - mn = "IRPC"; - else - mn = "IRP"; - - idx = sb_skip_white (idx, in); - - sb_new (&sub); - if (! buffer_and_nest (mn, "ENDR", &sub, get_line)) - return _("unexpected end of file in irp or irpc"); - - sb_new (&f.name); - sb_new (&f.def); - sb_new (&f.actual); - - idx = get_token (idx, in, &f.name); - if (f.name.len == 0) - return _("missing model parameter"); - - h = hash_new (); - err = hash_jam (h, sb_terminate (&f.name), &f); - if (err != NULL) - return err; - - f.index = 1; - f.next = NULL; - - sb_reset (out); - - idx = sb_skip_comma (idx, in); - if (idx >= in->len) - { - /* Expand once with a null string. */ - err = macro_expand_body (&sub, out, &f, h, 0); - if (err != NULL) - return err; - } - else - { - if (irpc && in->ptr[idx] == '"') - ++idx; - while (idx < in->len) - { - if (!irpc) - idx = get_any_string (idx, in, &f.actual, 1, 0); - else - { - if (in->ptr[idx] == '"') - { - int nxt; - - nxt = sb_skip_white (idx + 1, in); - if (nxt >= in->len) - { - idx = nxt; - break; - } - } - sb_reset (&f.actual); - sb_add_char (&f.actual, in->ptr[idx]); - ++idx; - } - err = macro_expand_body (&sub, out, &f, h, 0); - if (err != NULL) - return err; - if (!irpc) - idx = sb_skip_comma (idx, in); - else - idx = sb_skip_white (idx, in); - } - } - - hash_die (h); - sb_kill (&sub); - - return NULL; -} |