1c074d1c9Sdrahn /* macro.c - macro support for gas
2c074d1c9Sdrahn Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
3b55d4692Sfgsch Free Software Foundation, Inc.
42159047fSniklas
52159047fSniklas Written by Steve and Judy Chamberlain of Cygnus Support,
62159047fSniklas sac@cygnus.com
72159047fSniklas
82159047fSniklas This file is part of GAS, the GNU Assembler.
92159047fSniklas
102159047fSniklas GAS is free software; you can redistribute it and/or modify
112159047fSniklas it under the terms of the GNU General Public License as published by
122159047fSniklas the Free Software Foundation; either version 2, or (at your option)
132159047fSniklas any later version.
142159047fSniklas
152159047fSniklas GAS is distributed in the hope that it will be useful,
162159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
172159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
182159047fSniklas GNU General Public License for more details.
192159047fSniklas
202159047fSniklas You should have received a copy of the GNU General Public License
212159047fSniklas along with GAS; see the file COPYING. If not, write to the Free
222159047fSniklas Software Foundation, 59 Temple Place - Suite 330, Boston, MA
232159047fSniklas 02111-1307, USA. */
242159047fSniklas
252159047fSniklas #include "config.h"
26b305b0f1Sespie
27c074d1c9Sdrahn #ifndef __GNUC__
28b305b0f1Sespie # if HAVE_ALLOCA_H
29b305b0f1Sespie # include <alloca.h>
30b305b0f1Sespie # else
31b305b0f1Sespie # ifdef _AIX
32c074d1c9Sdrahn /* Indented so that pre-ansi C compilers will ignore it, rather than
33c074d1c9Sdrahn choke on it. Some versions of AIX require this to be the first
34c074d1c9Sdrahn thing in the file. */
35b305b0f1Sespie #pragma alloca
36b305b0f1Sespie # else
37b305b0f1Sespie # ifndef alloca /* predefined by HP cc +Olibcalls */
38b305b0f1Sespie # if !defined (__STDC__) && !defined (__hpux)
39b305b0f1Sespie extern char *alloca ();
40b305b0f1Sespie # else
41b305b0f1Sespie extern void *alloca ();
42b305b0f1Sespie # endif /* __STDC__, __hpux */
43b305b0f1Sespie # endif /* alloca */
44b305b0f1Sespie # endif /* _AIX */
45b305b0f1Sespie # endif /* HAVE_ALLOCA_H */
46c074d1c9Sdrahn #endif /* __GNUC__ */
47b305b0f1Sespie
482159047fSniklas #include <stdio.h>
492159047fSniklas #ifdef HAVE_STRING_H
502159047fSniklas #include <string.h>
512159047fSniklas #else
522159047fSniklas #include <strings.h>
532159047fSniklas #endif
542159047fSniklas #ifdef HAVE_STDLIB_H
552159047fSniklas #include <stdlib.h>
562159047fSniklas #endif
572159047fSniklas #include "libiberty.h"
58c074d1c9Sdrahn #include "safe-ctype.h"
592159047fSniklas #include "sb.h"
602159047fSniklas #include "hash.h"
612159047fSniklas #include "macro.h"
622159047fSniklas
63b305b0f1Sespie #include "asintl.h"
64b305b0f1Sespie
652159047fSniklas /* The routines in this file handle macro definition and expansion.
66c074d1c9Sdrahn They are called by gas. */
672159047fSniklas
682159047fSniklas /* Internal functions. */
692159047fSniklas
70*007c2a45Smiod static int get_token (int, sb *, sb *);
71*007c2a45Smiod static int getstring (int, sb *, sb *);
72*007c2a45Smiod static int get_any_string (int, sb *, sb *, int, int);
73*007c2a45Smiod static int do_formals (macro_entry *, int, sb *);
74*007c2a45Smiod static int get_apost_token (int, sb *, sb *, int);
75*007c2a45Smiod static int sub_actual (int, sb *, sb *, struct hash_control *, int, sb *, int);
762159047fSniklas static const char *macro_expand_body
77*007c2a45Smiod (sb *, sb *, formal_entry *, struct hash_control *, int);
78*007c2a45Smiod static const char *macro_expand (int, sb *, macro_entry *, sb *);
792159047fSniklas
802159047fSniklas #define ISWHITE(x) ((x) == ' ' || (x) == '\t')
812159047fSniklas
822159047fSniklas #define ISSEP(x) \
832159047fSniklas ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \
84b305b0f1Sespie || (x) == ')' || (x) == '(' \
85b305b0f1Sespie || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>')))
862159047fSniklas
872159047fSniklas #define ISBASE(x) \
882159047fSniklas ((x) == 'b' || (x) == 'B' \
892159047fSniklas || (x) == 'q' || (x) == 'Q' \
902159047fSniklas || (x) == 'h' || (x) == 'H' \
912159047fSniklas || (x) == 'd' || (x) == 'D')
922159047fSniklas
932159047fSniklas /* The macro hash table. */
942159047fSniklas
95c074d1c9Sdrahn struct hash_control *macro_hash;
962159047fSniklas
972159047fSniklas /* Whether any macros have been defined. */
982159047fSniklas
992159047fSniklas int macro_defined;
1002159047fSniklas
101c074d1c9Sdrahn /* Whether we are in alternate syntax mode. */
1022159047fSniklas
1032159047fSniklas static int macro_alternate;
1042159047fSniklas
1052159047fSniklas /* Whether we are in MRI mode. */
1062159047fSniklas
1072159047fSniklas static int macro_mri;
1082159047fSniklas
1092159047fSniklas /* Whether we should strip '@' characters. */
1102159047fSniklas
1112159047fSniklas static int macro_strip_at;
1122159047fSniklas
1132159047fSniklas /* Function to use to parse an expression. */
1142159047fSniklas
115*007c2a45Smiod static int (*macro_expr) (const char *, int, sb *, int *);
1162159047fSniklas
1172159047fSniklas /* Number of macro expansions that have been done. */
1182159047fSniklas
1192159047fSniklas static int macro_number;
1202159047fSniklas
1212159047fSniklas /* Initialize macro processing. */
1222159047fSniklas
1232159047fSniklas void
macro_init(int alternate,int mri,int strip_at,int (* expr)(const char *,int,sb *,int *))124*007c2a45Smiod macro_init (int alternate, int mri, int strip_at,
125*007c2a45Smiod int (*expr) (const char *, int, sb *, int *))
1262159047fSniklas {
1272159047fSniklas macro_hash = hash_new ();
1282159047fSniklas macro_defined = 0;
1292159047fSniklas macro_alternate = alternate;
1302159047fSniklas macro_mri = mri;
1312159047fSniklas macro_strip_at = strip_at;
1322159047fSniklas macro_expr = expr;
1332159047fSniklas }
1342159047fSniklas
135b305b0f1Sespie /* Switch in and out of MRI mode on the fly. */
136b305b0f1Sespie
137b305b0f1Sespie void
macro_mri_mode(int mri)138*007c2a45Smiod macro_mri_mode (int mri)
139b305b0f1Sespie {
140b305b0f1Sespie macro_mri = mri;
141b305b0f1Sespie }
142b305b0f1Sespie
1432159047fSniklas /* Read input lines till we get to a TO string.
1442159047fSniklas Increase nesting depth if we get a FROM string.
1452159047fSniklas Put the results into sb at PTR.
1462159047fSniklas Add a new input line to an sb using GET_LINE.
1472159047fSniklas Return 1 on success, 0 on unexpected EOF. */
1482159047fSniklas
1492159047fSniklas int
buffer_and_nest(const char * from,const char * to,sb * ptr,int (* get_line)(sb *))150*007c2a45Smiod buffer_and_nest (const char *from, const char *to, sb *ptr,
151*007c2a45Smiod int (*get_line) (sb *))
1522159047fSniklas {
1532159047fSniklas int from_len = strlen (from);
1542159047fSniklas int to_len = strlen (to);
1552159047fSniklas int depth = 1;
1562159047fSniklas int line_start = ptr->len;
1572159047fSniklas
1582159047fSniklas int more = get_line (ptr);
1592159047fSniklas
1602159047fSniklas while (more)
1612159047fSniklas {
162b55d4692Sfgsch /* Try and find the first pseudo op on the line. */
1632159047fSniklas int i = line_start;
1642159047fSniklas
1652159047fSniklas if (! macro_alternate && ! macro_mri)
1662159047fSniklas {
1672159047fSniklas /* With normal syntax we can suck what we want till we get
1682159047fSniklas to the dot. With the alternate, labels have to start in
1692159047fSniklas the first column, since we cant tell what's a label and
170b55d4692Sfgsch whats a pseudoop. */
1712159047fSniklas
172b55d4692Sfgsch /* Skip leading whitespace. */
1732159047fSniklas while (i < ptr->len && ISWHITE (ptr->ptr[i]))
1742159047fSniklas i++;
1752159047fSniklas
176b55d4692Sfgsch /* Skip over a label. */
1772159047fSniklas while (i < ptr->len
178c074d1c9Sdrahn && (ISALNUM (ptr->ptr[i])
1792159047fSniklas || ptr->ptr[i] == '_'
1802159047fSniklas || ptr->ptr[i] == '$'))
1812159047fSniklas i++;
1822159047fSniklas
183b55d4692Sfgsch /* And a colon. */
1842159047fSniklas if (i < ptr->len
1852159047fSniklas && ptr->ptr[i] == ':')
1862159047fSniklas i++;
1872159047fSniklas
1882159047fSniklas }
189b55d4692Sfgsch /* Skip trailing whitespace. */
1902159047fSniklas while (i < ptr->len && ISWHITE (ptr->ptr[i]))
1912159047fSniklas i++;
1922159047fSniklas
1932159047fSniklas if (i < ptr->len && (ptr->ptr[i] == '.'
1942159047fSniklas || macro_alternate
1952159047fSniklas || macro_mri))
1962159047fSniklas {
1972159047fSniklas if (ptr->ptr[i] == '.')
1982159047fSniklas i++;
199b305b0f1Sespie if (strncasecmp (ptr->ptr + i, from, from_len) == 0
200b55d4692Sfgsch && (ptr->len == (i + from_len)
201c074d1c9Sdrahn || ! ISALNUM (ptr->ptr[i + from_len])))
2022159047fSniklas depth++;
203b305b0f1Sespie if (strncasecmp (ptr->ptr + i, to, to_len) == 0
204b55d4692Sfgsch && (ptr->len == (i + to_len)
205c074d1c9Sdrahn || ! ISALNUM (ptr->ptr[i + to_len])))
2062159047fSniklas {
2072159047fSniklas depth--;
2082159047fSniklas if (depth == 0)
2092159047fSniklas {
210b55d4692Sfgsch /* Reset the string to not include the ending rune. */
2112159047fSniklas ptr->len = line_start;
2122159047fSniklas break;
2132159047fSniklas }
2142159047fSniklas }
2152159047fSniklas }
2162159047fSniklas
217c074d1c9Sdrahn /* Add the original end-of-line char to the end and keep running. */
218c074d1c9Sdrahn sb_add_char (ptr, more);
2192159047fSniklas line_start = ptr->len;
2202159047fSniklas more = get_line (ptr);
2212159047fSniklas }
2222159047fSniklas
2232159047fSniklas /* Return 1 on success, 0 on unexpected EOF. */
2242159047fSniklas return depth == 0;
2252159047fSniklas }
2262159047fSniklas
2272159047fSniklas /* Pick up a token. */
2282159047fSniklas
2292159047fSniklas static int
get_token(int idx,sb * in,sb * name)230*007c2a45Smiod get_token (int idx, sb *in, sb *name)
2312159047fSniklas {
2322159047fSniklas if (idx < in->len
233c074d1c9Sdrahn && (ISALPHA (in->ptr[idx])
2342159047fSniklas || in->ptr[idx] == '_'
2352159047fSniklas || in->ptr[idx] == '$'))
2362159047fSniklas {
2372159047fSniklas sb_add_char (name, in->ptr[idx++]);
2382159047fSniklas while (idx < in->len
239c074d1c9Sdrahn && (ISALNUM (in->ptr[idx])
2402159047fSniklas || in->ptr[idx] == '_'
2412159047fSniklas || in->ptr[idx] == '$'))
2422159047fSniklas {
2432159047fSniklas sb_add_char (name, in->ptr[idx++]);
2442159047fSniklas }
2452159047fSniklas }
246b55d4692Sfgsch /* Ignore trailing &. */
2472159047fSniklas if (macro_alternate && idx < in->len && in->ptr[idx] == '&')
2482159047fSniklas idx++;
2492159047fSniklas return idx;
2502159047fSniklas }
2512159047fSniklas
2522159047fSniklas /* Pick up a string. */
2532159047fSniklas
2542159047fSniklas static int
getstring(int idx,sb * in,sb * acc)255*007c2a45Smiod getstring (int idx, sb *in, sb *acc)
2562159047fSniklas {
2572159047fSniklas idx = sb_skip_white (idx, in);
2582159047fSniklas
2592159047fSniklas while (idx < in->len
2602159047fSniklas && (in->ptr[idx] == '"'
261b305b0f1Sespie || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
2622159047fSniklas || (in->ptr[idx] == '\'' && macro_alternate)))
2632159047fSniklas {
2642159047fSniklas if (in->ptr[idx] == '<')
2652159047fSniklas {
2662159047fSniklas int nest = 0;
2672159047fSniklas idx++;
2682159047fSniklas while ((in->ptr[idx] != '>' || nest)
2692159047fSniklas && idx < in->len)
2702159047fSniklas {
2712159047fSniklas if (in->ptr[idx] == '!')
2722159047fSniklas {
2732159047fSniklas idx++;
2742159047fSniklas sb_add_char (acc, in->ptr[idx++]);
2752159047fSniklas }
2762159047fSniklas else
2772159047fSniklas {
2782159047fSniklas if (in->ptr[idx] == '>')
2792159047fSniklas nest--;
2802159047fSniklas if (in->ptr[idx] == '<')
2812159047fSniklas nest++;
2822159047fSniklas sb_add_char (acc, in->ptr[idx++]);
2832159047fSniklas }
2842159047fSniklas }
2852159047fSniklas idx++;
2862159047fSniklas }
2872159047fSniklas else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
2882159047fSniklas {
2892159047fSniklas char tchar = in->ptr[idx];
290b55d4692Sfgsch int escaped = 0;
291b55d4692Sfgsch
2922159047fSniklas idx++;
293b55d4692Sfgsch
2942159047fSniklas while (idx < in->len)
2952159047fSniklas {
296b55d4692Sfgsch if (in->ptr[idx - 1] == '\\')
297b55d4692Sfgsch escaped ^= 1;
298b55d4692Sfgsch else
299b55d4692Sfgsch escaped = 0;
300b55d4692Sfgsch
3012159047fSniklas if (macro_alternate && in->ptr[idx] == '!')
3022159047fSniklas {
3032159047fSniklas idx ++;
304b55d4692Sfgsch
305b55d4692Sfgsch sb_add_char (acc, in->ptr[idx]);
306b55d4692Sfgsch
307b55d4692Sfgsch idx ++;
308b55d4692Sfgsch }
309b55d4692Sfgsch else if (escaped && in->ptr[idx] == tchar)
310b55d4692Sfgsch {
311b55d4692Sfgsch sb_add_char (acc, tchar);
312b55d4692Sfgsch idx ++;
3132159047fSniklas }
3142159047fSniklas else
3152159047fSniklas {
3162159047fSniklas if (in->ptr[idx] == tchar)
3172159047fSniklas {
3182159047fSniklas idx ++;
319b55d4692Sfgsch
3202159047fSniklas if (idx >= in->len || in->ptr[idx] != tchar)
3212159047fSniklas break;
3222159047fSniklas }
323b55d4692Sfgsch
3242159047fSniklas sb_add_char (acc, in->ptr[idx]);
3252159047fSniklas idx ++;
3262159047fSniklas }
3272159047fSniklas }
3282159047fSniklas }
3292159047fSniklas }
3302159047fSniklas
3312159047fSniklas return idx;
3322159047fSniklas }
3332159047fSniklas
3342159047fSniklas /* Fetch string from the input stream,
3352159047fSniklas rules:
3362159047fSniklas 'Bxyx<whitespace> -> return 'Bxyza
3372159047fSniklas %<char> -> return string of decimal value of x
3382159047fSniklas "<string>" -> return string
3392159047fSniklas xyx<whitespace> -> return xyz
3402159047fSniklas */
3412159047fSniklas
3422159047fSniklas static int
get_any_string(int idx,sb * in,sb * out,int expand,int pretend_quoted)343*007c2a45Smiod get_any_string (int idx, sb *in, sb *out, int expand, int pretend_quoted)
3442159047fSniklas {
3452159047fSniklas sb_reset (out);
3462159047fSniklas idx = sb_skip_white (idx, in);
3472159047fSniklas
3482159047fSniklas if (idx < in->len)
3492159047fSniklas {
350c074d1c9Sdrahn if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))
3512159047fSniklas {
3522159047fSniklas while (!ISSEP (in->ptr[idx]))
3532159047fSniklas sb_add_char (out, in->ptr[idx++]);
3542159047fSniklas }
3552159047fSniklas else if (in->ptr[idx] == '%'
3562159047fSniklas && macro_alternate
3572159047fSniklas && expand)
3582159047fSniklas {
3592159047fSniklas int val;
3602159047fSniklas char buf[20];
361b55d4692Sfgsch /* Turns the next expression into a string. */
362c074d1c9Sdrahn /* xgettext: no-c-format */
363b305b0f1Sespie idx = (*macro_expr) (_("% operator needs absolute expression"),
3642159047fSniklas idx + 1,
3652159047fSniklas in,
3662159047fSniklas &val);
3672159047fSniklas sprintf (buf, "%d", val);
3682159047fSniklas sb_add_string (out, buf);
3692159047fSniklas }
3702159047fSniklas else if (in->ptr[idx] == '"'
371b305b0f1Sespie || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
3722159047fSniklas || (macro_alternate && in->ptr[idx] == '\''))
3732159047fSniklas {
3742159047fSniklas if (macro_alternate
3752159047fSniklas && ! macro_strip_at
3762159047fSniklas && expand)
3772159047fSniklas {
378b55d4692Sfgsch /* Keep the quotes. */
3792159047fSniklas sb_add_char (out, '\"');
3802159047fSniklas
3812159047fSniklas idx = getstring (idx, in, out);
3822159047fSniklas sb_add_char (out, '\"');
3832159047fSniklas }
3842159047fSniklas else
3852159047fSniklas {
3862159047fSniklas idx = getstring (idx, in, out);
3872159047fSniklas }
3882159047fSniklas }
3892159047fSniklas else
3902159047fSniklas {
3912159047fSniklas while (idx < in->len
3922159047fSniklas && (in->ptr[idx] == '"'
3932159047fSniklas || in->ptr[idx] == '\''
3942159047fSniklas || pretend_quoted
3952159047fSniklas || (in->ptr[idx] != ' '
3962159047fSniklas && in->ptr[idx] != '\t'
3972159047fSniklas && in->ptr[idx] != ','
398b305b0f1Sespie && (in->ptr[idx] != '<'
399b305b0f1Sespie || (! macro_alternate && ! macro_mri)))))
4002159047fSniklas {
4012159047fSniklas if (in->ptr[idx] == '"'
4022159047fSniklas || in->ptr[idx] == '\'')
4032159047fSniklas {
4042159047fSniklas char tchar = in->ptr[idx];
4052159047fSniklas sb_add_char (out, in->ptr[idx++]);
4062159047fSniklas while (idx < in->len
4072159047fSniklas && in->ptr[idx] != tchar)
4082159047fSniklas sb_add_char (out, in->ptr[idx++]);
4092159047fSniklas if (idx == in->len)
4102159047fSniklas return idx;
4112159047fSniklas }
4122159047fSniklas sb_add_char (out, in->ptr[idx++]);
4132159047fSniklas }
4142159047fSniklas }
4152159047fSniklas }
4162159047fSniklas
4172159047fSniklas return idx;
4182159047fSniklas }
4192159047fSniklas
4202159047fSniklas /* Pick up the formal parameters of a macro definition. */
4212159047fSniklas
4222159047fSniklas static int
do_formals(macro_entry * macro,int idx,sb * in)423*007c2a45Smiod do_formals (macro_entry *macro, int idx, sb *in)
4242159047fSniklas {
4252159047fSniklas formal_entry **p = ¯o->formals;
4262159047fSniklas
4272159047fSniklas macro->formal_count = 0;
4282159047fSniklas macro->formal_hash = hash_new ();
4292159047fSniklas while (idx < in->len)
4302159047fSniklas {
4312159047fSniklas formal_entry *formal;
4322159047fSniklas
4332159047fSniklas formal = (formal_entry *) xmalloc (sizeof (formal_entry));
4342159047fSniklas
4352159047fSniklas sb_new (&formal->name);
4362159047fSniklas sb_new (&formal->def);
4372159047fSniklas sb_new (&formal->actual);
4382159047fSniklas
4392159047fSniklas idx = sb_skip_white (idx, in);
4402159047fSniklas idx = get_token (idx, in, &formal->name);
4412159047fSniklas if (formal->name.len == 0)
4422159047fSniklas break;
4432159047fSniklas idx = sb_skip_white (idx, in);
4442159047fSniklas if (formal->name.len)
4452159047fSniklas {
446b55d4692Sfgsch /* This is a formal. */
4472159047fSniklas if (idx < in->len && in->ptr[idx] == '=')
4482159047fSniklas {
449b55d4692Sfgsch /* Got a default. */
4502159047fSniklas idx = get_any_string (idx + 1, in, &formal->def, 1, 0);
4512159047fSniklas }
4522159047fSniklas }
4532159047fSniklas
454b55d4692Sfgsch /* Add to macro's hash table. */
4552159047fSniklas hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal);
4562159047fSniklas
4572159047fSniklas formal->index = macro->formal_count;
4582159047fSniklas idx = sb_skip_comma (idx, in);
4592159047fSniklas macro->formal_count++;
4602159047fSniklas *p = formal;
4612159047fSniklas p = &formal->next;
4622159047fSniklas *p = NULL;
4632159047fSniklas }
4642159047fSniklas
4652159047fSniklas if (macro_mri)
4662159047fSniklas {
4672159047fSniklas formal_entry *formal;
4682159047fSniklas const char *name;
4692159047fSniklas
4702159047fSniklas /* Add a special NARG formal, which macro_expand will set to the
4712159047fSniklas number of arguments. */
4722159047fSniklas formal = (formal_entry *) xmalloc (sizeof (formal_entry));
4732159047fSniklas
4742159047fSniklas sb_new (&formal->name);
4752159047fSniklas sb_new (&formal->def);
4762159047fSniklas sb_new (&formal->actual);
4772159047fSniklas
4782159047fSniklas /* The same MRI assemblers which treat '@' characters also use
4792159047fSniklas the name $NARG. At least until we find an exception. */
4802159047fSniklas if (macro_strip_at)
4812159047fSniklas name = "$NARG";
4822159047fSniklas else
4832159047fSniklas name = "NARG";
4842159047fSniklas
4852159047fSniklas sb_add_string (&formal->name, name);
4862159047fSniklas
487b55d4692Sfgsch /* Add to macro's hash table. */
4882159047fSniklas hash_jam (macro->formal_hash, name, formal);
4892159047fSniklas
4902159047fSniklas formal->index = NARG_INDEX;
4912159047fSniklas *p = formal;
4922159047fSniklas formal->next = NULL;
4932159047fSniklas }
4942159047fSniklas
4952159047fSniklas return idx;
4962159047fSniklas }
4972159047fSniklas
4982159047fSniklas /* Define a new macro. Returns NULL on success, otherwise returns an
49970bcd334Sniklas error message. If NAMEP is not NULL, *NAMEP is set to the name of
50070bcd334Sniklas the macro which was defined. */
5012159047fSniklas
5022159047fSniklas const char *
define_macro(int idx,sb * in,sb * label,int (* get_line)(sb *),const char ** namep)503*007c2a45Smiod define_macro (int idx, sb *in, sb *label,
504*007c2a45Smiod int (*get_line) (sb *), const char **namep)
5052159047fSniklas {
5062159047fSniklas macro_entry *macro;
5072159047fSniklas sb name;
50870bcd334Sniklas const char *namestr;
5092159047fSniklas
5102159047fSniklas macro = (macro_entry *) xmalloc (sizeof (macro_entry));
5112159047fSniklas sb_new (¯o->sub);
5122159047fSniklas sb_new (&name);
5132159047fSniklas
5142159047fSniklas macro->formal_count = 0;
5152159047fSniklas macro->formals = 0;
5162159047fSniklas
5172159047fSniklas idx = sb_skip_white (idx, in);
5182159047fSniklas if (! buffer_and_nest ("MACRO", "ENDM", ¯o->sub, get_line))
519b305b0f1Sespie return _("unexpected end of file in macro definition");
5202159047fSniklas if (label != NULL && label->len != 0)
5212159047fSniklas {
5222159047fSniklas sb_add_sb (&name, label);
523b305b0f1Sespie if (idx < in->len && in->ptr[idx] == '(')
5242159047fSniklas {
5252159047fSniklas /* It's the label: MACRO (formals,...) sort */
5262159047fSniklas idx = do_formals (macro, idx + 1, in);
5272159047fSniklas if (in->ptr[idx] != ')')
528b305b0f1Sespie return _("missing ) after formals");
5292159047fSniklas }
5302159047fSniklas else
5312159047fSniklas {
5322159047fSniklas /* It's the label: MACRO formals,... sort */
5332159047fSniklas idx = do_formals (macro, idx, in);
5342159047fSniklas }
5352159047fSniklas }
5362159047fSniklas else
5372159047fSniklas {
5382159047fSniklas idx = get_token (idx, in, &name);
5392159047fSniklas idx = sb_skip_comma (idx, in);
5402159047fSniklas idx = do_formals (macro, idx, in);
5412159047fSniklas }
5422159047fSniklas
543b55d4692Sfgsch /* And stick it in the macro hash table. */
5442159047fSniklas for (idx = 0; idx < name.len; idx++)
545c074d1c9Sdrahn name.ptr[idx] = TOLOWER (name.ptr[idx]);
54670bcd334Sniklas namestr = sb_terminate (&name);
54770bcd334Sniklas hash_jam (macro_hash, namestr, (PTR) macro);
5482159047fSniklas
5492159047fSniklas macro_defined = 1;
5502159047fSniklas
55170bcd334Sniklas if (namep != NULL)
55270bcd334Sniklas *namep = namestr;
55370bcd334Sniklas
5542159047fSniklas return NULL;
5552159047fSniklas }
5562159047fSniklas
5572159047fSniklas /* Scan a token, and then skip KIND. */
5582159047fSniklas
5592159047fSniklas static int
get_apost_token(int idx,sb * in,sb * name,int kind)560*007c2a45Smiod get_apost_token (int idx, sb *in, sb *name, int kind)
5612159047fSniklas {
5622159047fSniklas idx = get_token (idx, in, name);
5632159047fSniklas if (idx < in->len
5642159047fSniklas && in->ptr[idx] == kind
5652159047fSniklas && (! macro_mri || macro_strip_at)
5662159047fSniklas && (! macro_strip_at || kind == '@'))
5672159047fSniklas idx++;
5682159047fSniklas return idx;
5692159047fSniklas }
5702159047fSniklas
5712159047fSniklas /* Substitute the actual value for a formal parameter. */
5722159047fSniklas
5732159047fSniklas static int
sub_actual(int start,sb * in,sb * t,struct hash_control * formal_hash,int kind,sb * out,int copyifnotthere)574*007c2a45Smiod sub_actual (int start, sb *in, sb *t, struct hash_control *formal_hash,
575*007c2a45Smiod int kind, sb *out, int copyifnotthere)
5762159047fSniklas {
5772159047fSniklas int src;
5782159047fSniklas formal_entry *ptr;
5792159047fSniklas
5802159047fSniklas src = get_apost_token (start, in, t, kind);
5812159047fSniklas /* See if it's in the macro's hash table, unless this is
5822159047fSniklas macro_strip_at and kind is '@' and the token did not end in '@'. */
5832159047fSniklas if (macro_strip_at
5842159047fSniklas && kind == '@'
5852159047fSniklas && (src == start || in->ptr[src - 1] != '@'))
5862159047fSniklas ptr = NULL;
5872159047fSniklas else
5882159047fSniklas ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t));
5892159047fSniklas if (ptr)
5902159047fSniklas {
5912159047fSniklas if (ptr->actual.len)
5922159047fSniklas {
5932159047fSniklas sb_add_sb (out, &ptr->actual);
5942159047fSniklas }
5952159047fSniklas else
5962159047fSniklas {
5972159047fSniklas sb_add_sb (out, &ptr->def);
5982159047fSniklas }
5992159047fSniklas }
600b305b0f1Sespie else if (kind == '&')
601b305b0f1Sespie {
602b305b0f1Sespie /* Doing this permits people to use & in macro bodies. */
603b305b0f1Sespie sb_add_char (out, '&');
604c074d1c9Sdrahn sb_add_sb (out, t);
605b305b0f1Sespie }
6062159047fSniklas else if (copyifnotthere)
6072159047fSniklas {
6082159047fSniklas sb_add_sb (out, t);
6092159047fSniklas }
6102159047fSniklas else
6112159047fSniklas {
6122159047fSniklas sb_add_char (out, '\\');
6132159047fSniklas sb_add_sb (out, t);
6142159047fSniklas }
6152159047fSniklas return src;
6162159047fSniklas }
6172159047fSniklas
6182159047fSniklas /* Expand the body of a macro. */
6192159047fSniklas
6202159047fSniklas static const char *
macro_expand_body(sb * in,sb * out,formal_entry * formals,struct hash_control * formal_hash,int locals)621*007c2a45Smiod macro_expand_body (sb *in, sb *out, formal_entry *formals,
622*007c2a45Smiod struct hash_control *formal_hash, int locals)
6232159047fSniklas {
6242159047fSniklas sb t;
6252159047fSniklas int src = 0;
6262159047fSniklas int inquote = 0;
6272159047fSniklas formal_entry *loclist = NULL;
6282159047fSniklas
6292159047fSniklas sb_new (&t);
6302159047fSniklas
6312159047fSniklas while (src < in->len)
6322159047fSniklas {
6332159047fSniklas if (in->ptr[src] == '&')
6342159047fSniklas {
6352159047fSniklas sb_reset (&t);
636b305b0f1Sespie if (macro_mri)
6372159047fSniklas {
638b305b0f1Sespie if (src + 1 < in->len && in->ptr[src + 1] == '&')
6392159047fSniklas src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
640b305b0f1Sespie else
641b305b0f1Sespie sb_add_char (out, in->ptr[src++]);
6422159047fSniklas }
6432159047fSniklas else
6442159047fSniklas {
645b305b0f1Sespie /* FIXME: Why do we do this? */
6462159047fSniklas src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
6472159047fSniklas }
6482159047fSniklas }
6492159047fSniklas else if (in->ptr[src] == '\\')
6502159047fSniklas {
6512159047fSniklas src++;
652c074d1c9Sdrahn if (in->ptr[src] == '(')
6532159047fSniklas {
654b55d4692Sfgsch /* Sub in till the next ')' literally. */
6552159047fSniklas src++;
6562159047fSniklas while (src < in->len && in->ptr[src] != ')')
6572159047fSniklas {
6582159047fSniklas sb_add_char (out, in->ptr[src++]);
6592159047fSniklas }
6602159047fSniklas if (in->ptr[src] == ')')
6612159047fSniklas src++;
6622159047fSniklas else
663b305b0f1Sespie return _("missplaced )");
6642159047fSniklas }
6652159047fSniklas else if (in->ptr[src] == '@')
6662159047fSniklas {
667b55d4692Sfgsch /* Sub in the macro invocation number. */
6682159047fSniklas
669b305b0f1Sespie char buffer[10];
6702159047fSniklas src++;
671b55d4692Sfgsch sprintf (buffer, "%d", macro_number);
6722159047fSniklas sb_add_string (out, buffer);
6732159047fSniklas }
6742159047fSniklas else if (in->ptr[src] == '&')
6752159047fSniklas {
6762159047fSniklas /* This is a preprocessor variable name, we don't do them
677b55d4692Sfgsch here. */
6782159047fSniklas sb_add_char (out, '\\');
6792159047fSniklas sb_add_char (out, '&');
6802159047fSniklas src++;
6812159047fSniklas }
682c074d1c9Sdrahn else if (macro_mri && ISALNUM (in->ptr[src]))
6832159047fSniklas {
6842159047fSniklas int ind;
6852159047fSniklas formal_entry *f;
6862159047fSniklas
687c074d1c9Sdrahn if (ISDIGIT (in->ptr[src]))
6882159047fSniklas ind = in->ptr[src] - '0';
689c074d1c9Sdrahn else if (ISUPPER (in->ptr[src]))
6902159047fSniklas ind = in->ptr[src] - 'A' + 10;
6912159047fSniklas else
6922159047fSniklas ind = in->ptr[src] - 'a' + 10;
6932159047fSniklas ++src;
6942159047fSniklas for (f = formals; f != NULL; f = f->next)
6952159047fSniklas {
6962159047fSniklas if (f->index == ind - 1)
6972159047fSniklas {
6982159047fSniklas if (f->actual.len != 0)
6992159047fSniklas sb_add_sb (out, &f->actual);
7002159047fSniklas else
7012159047fSniklas sb_add_sb (out, &f->def);
7022159047fSniklas break;
7032159047fSniklas }
7042159047fSniklas }
7052159047fSniklas }
7062159047fSniklas else
7072159047fSniklas {
7082159047fSniklas sb_reset (&t);
7092159047fSniklas src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
7102159047fSniklas }
7112159047fSniklas }
7122159047fSniklas else if ((macro_alternate || macro_mri)
713c074d1c9Sdrahn && (ISALPHA (in->ptr[src])
7142159047fSniklas || in->ptr[src] == '_'
7152159047fSniklas || in->ptr[src] == '$')
7162159047fSniklas && (! inquote
7172159047fSniklas || ! macro_strip_at
7182159047fSniklas || (src > 0 && in->ptr[src - 1] == '@')))
7192159047fSniklas {
7202159047fSniklas if (! locals
7212159047fSniklas || src + 5 >= in->len
7222159047fSniklas || strncasecmp (in->ptr + src, "LOCAL", 5) != 0
7232159047fSniklas || ! ISWHITE (in->ptr[src + 5]))
7242159047fSniklas {
7252159047fSniklas sb_reset (&t);
7262159047fSniklas src = sub_actual (src, in, &t, formal_hash,
7272159047fSniklas (macro_strip_at && inquote) ? '@' : '\'',
7282159047fSniklas out, 1);
7292159047fSniklas }
7302159047fSniklas else
7312159047fSniklas {
7322159047fSniklas formal_entry *f;
7332159047fSniklas
7342159047fSniklas src = sb_skip_white (src + 5, in);
735c074d1c9Sdrahn while (in->ptr[src] != '\n')
7362159047fSniklas {
7372159047fSniklas static int loccnt;
7382159047fSniklas char buf[20];
7392159047fSniklas const char *err;
7402159047fSniklas
7412159047fSniklas f = (formal_entry *) xmalloc (sizeof (formal_entry));
7422159047fSniklas sb_new (&f->name);
7432159047fSniklas sb_new (&f->def);
7442159047fSniklas sb_new (&f->actual);
7452159047fSniklas f->index = LOCAL_INDEX;
7462159047fSniklas f->next = loclist;
7472159047fSniklas loclist = f;
7482159047fSniklas
7492159047fSniklas src = get_token (src, in, &f->name);
7502159047fSniklas ++loccnt;
7512159047fSniklas sprintf (buf, "LL%04x", loccnt);
7522159047fSniklas sb_add_string (&f->actual, buf);
7532159047fSniklas
7542159047fSniklas err = hash_jam (formal_hash, sb_terminate (&f->name), f);
7552159047fSniklas if (err != NULL)
7562159047fSniklas return err;
7572159047fSniklas
7582159047fSniklas src = sb_skip_comma (src, in);
7592159047fSniklas }
7602159047fSniklas }
7612159047fSniklas }
7622159047fSniklas else if (in->ptr[src] == '"'
7632159047fSniklas || (macro_mri && in->ptr[src] == '\''))
7642159047fSniklas {
7652159047fSniklas inquote = !inquote;
7662159047fSniklas sb_add_char (out, in->ptr[src++]);
7672159047fSniklas }
7682159047fSniklas else if (in->ptr[src] == '@' && macro_strip_at)
7692159047fSniklas {
7702159047fSniklas ++src;
7712159047fSniklas if (src < in->len
7722159047fSniklas && in->ptr[src] == '@')
7732159047fSniklas {
7742159047fSniklas sb_add_char (out, '@');
7752159047fSniklas ++src;
7762159047fSniklas }
7772159047fSniklas }
7782159047fSniklas else if (macro_mri
7792159047fSniklas && in->ptr[src] == '='
7802159047fSniklas && src + 1 < in->len
7812159047fSniklas && in->ptr[src + 1] == '=')
7822159047fSniklas {
7832159047fSniklas formal_entry *ptr;
7842159047fSniklas
7852159047fSniklas sb_reset (&t);
7862159047fSniklas src = get_token (src + 2, in, &t);
7872159047fSniklas ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t));
7882159047fSniklas if (ptr == NULL)
7892159047fSniklas {
7902159047fSniklas /* FIXME: We should really return a warning string here,
7912159047fSniklas but we can't, because the == might be in the MRI
7922159047fSniklas comment field, and, since the nature of the MRI
7932159047fSniklas comment field depends upon the exact instruction
7942159047fSniklas being used, we don't have enough information here to
7952159047fSniklas figure out whether it is or not. Instead, we leave
7962159047fSniklas the == in place, which should cause a syntax error if
7972159047fSniklas it is not in a comment. */
7982159047fSniklas sb_add_char (out, '=');
7992159047fSniklas sb_add_char (out, '=');
8002159047fSniklas sb_add_sb (out, &t);
8012159047fSniklas }
8022159047fSniklas else
8032159047fSniklas {
8042159047fSniklas if (ptr->actual.len)
8052159047fSniklas {
8062159047fSniklas sb_add_string (out, "-1");
8072159047fSniklas }
8082159047fSniklas else
8092159047fSniklas {
8102159047fSniklas sb_add_char (out, '0');
8112159047fSniklas }
8122159047fSniklas }
8132159047fSniklas }
8142159047fSniklas else
8152159047fSniklas {
8162159047fSniklas sb_add_char (out, in->ptr[src++]);
8172159047fSniklas }
8182159047fSniklas }
8192159047fSniklas
8202159047fSniklas sb_kill (&t);
8212159047fSniklas
8222159047fSniklas while (loclist != NULL)
8232159047fSniklas {
8242159047fSniklas formal_entry *f;
8252159047fSniklas
8262159047fSniklas f = loclist->next;
827b305b0f1Sespie /* Setting the value to NULL effectively deletes the entry. We
828b305b0f1Sespie avoid calling hash_delete because it doesn't reclaim memory. */
829b305b0f1Sespie hash_jam (formal_hash, sb_terminate (&loclist->name), NULL);
8302159047fSniklas sb_kill (&loclist->name);
8312159047fSniklas sb_kill (&loclist->def);
8322159047fSniklas sb_kill (&loclist->actual);
8332159047fSniklas free (loclist);
8342159047fSniklas loclist = f;
8352159047fSniklas }
8362159047fSniklas
8372159047fSniklas return NULL;
8382159047fSniklas }
8392159047fSniklas
8402159047fSniklas /* Assign values to the formal parameters of a macro, and expand the
8412159047fSniklas body. */
8422159047fSniklas
8432159047fSniklas static const char *
macro_expand(int idx,sb * in,macro_entry * m,sb * out)844*007c2a45Smiod macro_expand (int idx, sb *in, macro_entry *m, sb *out)
8452159047fSniklas {
8462159047fSniklas sb t;
8472159047fSniklas formal_entry *ptr;
8482159047fSniklas formal_entry *f;
8492159047fSniklas int is_positional = 0;
8502159047fSniklas int is_keyword = 0;
8512159047fSniklas int narg = 0;
8522159047fSniklas const char *err;
8532159047fSniklas
8542159047fSniklas sb_new (&t);
8552159047fSniklas
856b55d4692Sfgsch /* Reset any old value the actuals may have. */
8572159047fSniklas for (f = m->formals; f; f = f->next)
8582159047fSniklas sb_reset (&f->actual);
8592159047fSniklas f = m->formals;
8602159047fSniklas while (f != NULL && f->index < 0)
8612159047fSniklas f = f->next;
8622159047fSniklas
8632159047fSniklas if (macro_mri)
8642159047fSniklas {
8652159047fSniklas /* The macro may be called with an optional qualifier, which may
8662159047fSniklas be referred to in the macro body as \0. */
8672159047fSniklas if (idx < in->len && in->ptr[idx] == '.')
8682159047fSniklas {
869c074d1c9Sdrahn /* The Microtec assembler ignores this if followed by a white space.
870c074d1c9Sdrahn (Macro invocation with empty extension) */
871c074d1c9Sdrahn idx++;
872c074d1c9Sdrahn if ( idx < in->len
873c074d1c9Sdrahn && in->ptr[idx] != ' '
874c074d1c9Sdrahn && in->ptr[idx] != '\t')
875c074d1c9Sdrahn {
8762159047fSniklas formal_entry *n;
8772159047fSniklas
8782159047fSniklas n = (formal_entry *) xmalloc (sizeof (formal_entry));
8792159047fSniklas sb_new (&n->name);
8802159047fSniklas sb_new (&n->def);
8812159047fSniklas sb_new (&n->actual);
8822159047fSniklas n->index = QUAL_INDEX;
8832159047fSniklas
8842159047fSniklas n->next = m->formals;
8852159047fSniklas m->formals = n;
8862159047fSniklas
887c074d1c9Sdrahn idx = get_any_string (idx, in, &n->actual, 1, 0);
888c074d1c9Sdrahn }
8892159047fSniklas }
8902159047fSniklas }
8912159047fSniklas
892b55d4692Sfgsch /* Peel off the actuals and store them away in the hash tables' actuals. */
8932159047fSniklas idx = sb_skip_white (idx, in);
894c074d1c9Sdrahn while (idx < in->len)
8952159047fSniklas {
8962159047fSniklas int scan;
8972159047fSniklas
898b55d4692Sfgsch /* Look and see if it's a positional or keyword arg. */
8992159047fSniklas scan = idx;
9002159047fSniklas while (scan < in->len
9012159047fSniklas && !ISSEP (in->ptr[scan])
902b305b0f1Sespie && !(macro_mri && in->ptr[scan] == '\'')
9032159047fSniklas && (!macro_alternate && in->ptr[scan] != '='))
9042159047fSniklas scan++;
9052159047fSniklas if (scan < in->len && !macro_alternate && in->ptr[scan] == '=')
9062159047fSniklas {
9072159047fSniklas is_keyword = 1;
908b305b0f1Sespie
909b305b0f1Sespie /* It's OK to go from positional to keyword. */
9102159047fSniklas
9112159047fSniklas /* This is a keyword arg, fetch the formal name and
912b55d4692Sfgsch then the actual stuff. */
9132159047fSniklas sb_reset (&t);
9142159047fSniklas idx = get_token (idx, in, &t);
9152159047fSniklas if (in->ptr[idx] != '=')
916b305b0f1Sespie return _("confusion in formal parameters");
9172159047fSniklas
918b55d4692Sfgsch /* Lookup the formal in the macro's list. */
9192159047fSniklas ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
9202159047fSniklas if (!ptr)
921b305b0f1Sespie return _("macro formal argument does not exist");
9222159047fSniklas else
9232159047fSniklas {
924b55d4692Sfgsch /* Insert this value into the right place. */
9252159047fSniklas sb_reset (&ptr->actual);
9262159047fSniklas idx = get_any_string (idx + 1, in, &ptr->actual, 0, 0);
9272159047fSniklas if (ptr->actual.len > 0)
9282159047fSniklas ++narg;
9292159047fSniklas }
9302159047fSniklas }
9312159047fSniklas else
9322159047fSniklas {
933b55d4692Sfgsch /* This is a positional arg. */
9342159047fSniklas is_positional = 1;
9352159047fSniklas if (is_keyword)
936b305b0f1Sespie return _("can't mix positional and keyword arguments");
9372159047fSniklas
9382159047fSniklas if (!f)
9392159047fSniklas {
9402159047fSniklas formal_entry **pf;
9412159047fSniklas int c;
9422159047fSniklas
9432159047fSniklas if (!macro_mri)
944b305b0f1Sespie return _("too many positional arguments");
9452159047fSniklas
9462159047fSniklas f = (formal_entry *) xmalloc (sizeof (formal_entry));
9472159047fSniklas sb_new (&f->name);
9482159047fSniklas sb_new (&f->def);
9492159047fSniklas sb_new (&f->actual);
9502159047fSniklas f->next = NULL;
9512159047fSniklas
9522159047fSniklas c = -1;
9532159047fSniklas for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next)
9542159047fSniklas if ((*pf)->index >= c)
9552159047fSniklas c = (*pf)->index + 1;
9562159047fSniklas if (c == -1)
9572159047fSniklas c = 0;
9582159047fSniklas *pf = f;
9592159047fSniklas f->index = c;
9602159047fSniklas }
9612159047fSniklas
9622159047fSniklas sb_reset (&f->actual);
9632159047fSniklas idx = get_any_string (idx, in, &f->actual, 1, 0);
9642159047fSniklas if (f->actual.len > 0)
9652159047fSniklas ++narg;
9662159047fSniklas do
9672159047fSniklas {
9682159047fSniklas f = f->next;
9692159047fSniklas }
9702159047fSniklas while (f != NULL && f->index < 0);
9712159047fSniklas }
9722159047fSniklas
9732159047fSniklas if (! macro_mri)
9742159047fSniklas idx = sb_skip_comma (idx, in);
9752159047fSniklas else
9762159047fSniklas {
9772159047fSniklas if (in->ptr[idx] == ',')
9782159047fSniklas ++idx;
9792159047fSniklas if (ISWHITE (in->ptr[idx]))
9802159047fSniklas break;
9812159047fSniklas }
9822159047fSniklas }
9832159047fSniklas
9842159047fSniklas if (macro_mri)
9852159047fSniklas {
9862159047fSniklas char buffer[20];
9872159047fSniklas
9882159047fSniklas sb_reset (&t);
9892159047fSniklas sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
9902159047fSniklas ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
9912159047fSniklas sb_reset (&ptr->actual);
9922159047fSniklas sprintf (buffer, "%d", narg);
9932159047fSniklas sb_add_string (&ptr->actual, buffer);
9942159047fSniklas }
9952159047fSniklas
996c074d1c9Sdrahn err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, 1);
9972159047fSniklas if (err != NULL)
9982159047fSniklas return err;
9992159047fSniklas
10002159047fSniklas /* Discard any unnamed formal arguments. */
10012159047fSniklas if (macro_mri)
10022159047fSniklas {
10032159047fSniklas formal_entry **pf;
10042159047fSniklas
10052159047fSniklas pf = &m->formals;
10062159047fSniklas while (*pf != NULL)
10072159047fSniklas {
10082159047fSniklas if ((*pf)->name.len != 0)
10092159047fSniklas pf = &(*pf)->next;
10102159047fSniklas else
10112159047fSniklas {
10122159047fSniklas sb_kill (&(*pf)->name);
10132159047fSniklas sb_kill (&(*pf)->def);
10142159047fSniklas sb_kill (&(*pf)->actual);
10152159047fSniklas f = (*pf)->next;
10162159047fSniklas free (*pf);
10172159047fSniklas *pf = f;
10182159047fSniklas }
10192159047fSniklas }
10202159047fSniklas }
10212159047fSniklas
10222159047fSniklas sb_kill (&t);
10232159047fSniklas macro_number++;
10242159047fSniklas
10252159047fSniklas return NULL;
10262159047fSniklas }
10272159047fSniklas
10282159047fSniklas /* Check for a macro. If one is found, put the expansion into
1029c074d1c9Sdrahn *EXPAND. Return 1 if a macro is found, 0 otherwise. */
10302159047fSniklas
10312159047fSniklas int
check_macro(const char * line,sb * expand,const char ** error,macro_entry ** info)1032*007c2a45Smiod check_macro (const char *line, sb *expand,
1033*007c2a45Smiod const char **error, macro_entry **info)
10342159047fSniklas {
10352159047fSniklas const char *s;
10362159047fSniklas char *copy, *cs;
10372159047fSniklas macro_entry *macro;
10382159047fSniklas sb line_sb;
10392159047fSniklas
1040c074d1c9Sdrahn if (! ISALPHA (*line)
10412159047fSniklas && *line != '_'
10422159047fSniklas && *line != '$'
10432159047fSniklas && (! macro_mri || *line != '.'))
10442159047fSniklas return 0;
10452159047fSniklas
10462159047fSniklas s = line + 1;
1047c074d1c9Sdrahn while (ISALNUM (*s)
10482159047fSniklas || *s == '_'
10492159047fSniklas || *s == '$')
10502159047fSniklas ++s;
10512159047fSniklas
1052b305b0f1Sespie copy = (char *) alloca (s - line + 1);
10532159047fSniklas memcpy (copy, line, s - line);
10542159047fSniklas copy[s - line] = '\0';
10552159047fSniklas for (cs = copy; *cs != '\0'; cs++)
1056c074d1c9Sdrahn *cs = TOLOWER (*cs);
10572159047fSniklas
10582159047fSniklas macro = (macro_entry *) hash_find (macro_hash, copy);
10592159047fSniklas
10602159047fSniklas if (macro == NULL)
10612159047fSniklas return 0;
10622159047fSniklas
10632159047fSniklas /* Wrap the line up in an sb. */
10642159047fSniklas sb_new (&line_sb);
10652159047fSniklas while (*s != '\0' && *s != '\n' && *s != '\r')
10662159047fSniklas sb_add_char (&line_sb, *s++);
10672159047fSniklas
10682159047fSniklas sb_new (expand);
1069c074d1c9Sdrahn *error = macro_expand (0, &line_sb, macro, expand);
10702159047fSniklas
10712159047fSniklas sb_kill (&line_sb);
10722159047fSniklas
1073b55d4692Sfgsch /* Export the macro information if requested. */
1074b305b0f1Sespie if (info)
1075b305b0f1Sespie *info = macro;
1076b305b0f1Sespie
10772159047fSniklas return 1;
10782159047fSniklas }
10792159047fSniklas
10802159047fSniklas /* Delete a macro. */
10812159047fSniklas
10822159047fSniklas void
delete_macro(const char * name)1083*007c2a45Smiod delete_macro (const char *name)
10842159047fSniklas {
10852159047fSniklas hash_delete (macro_hash, name);
10862159047fSniklas }
10872159047fSniklas
10882159047fSniklas /* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a
10892159047fSniklas combined macro definition and execution. This returns NULL on
10902159047fSniklas success, or an error message otherwise. */
10912159047fSniklas
10922159047fSniklas const char *
expand_irp(int irpc,int idx,sb * in,sb * out,int (* get_line)(sb *))1093*007c2a45Smiod expand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *))
10942159047fSniklas {
10952159047fSniklas const char *mn;
10962159047fSniklas sb sub;
10972159047fSniklas formal_entry f;
10982159047fSniklas struct hash_control *h;
10992159047fSniklas const char *err;
11002159047fSniklas
11012159047fSniklas if (irpc)
11022159047fSniklas mn = "IRPC";
11032159047fSniklas else
11042159047fSniklas mn = "IRP";
11052159047fSniklas
11062159047fSniklas idx = sb_skip_white (idx, in);
11072159047fSniklas
11082159047fSniklas sb_new (&sub);
11092159047fSniklas if (! buffer_and_nest (mn, "ENDR", &sub, get_line))
1110b305b0f1Sespie return _("unexpected end of file in irp or irpc");
11112159047fSniklas
11122159047fSniklas sb_new (&f.name);
11132159047fSniklas sb_new (&f.def);
11142159047fSniklas sb_new (&f.actual);
11152159047fSniklas
11162159047fSniklas idx = get_token (idx, in, &f.name);
11172159047fSniklas if (f.name.len == 0)
1118b305b0f1Sespie return _("missing model parameter");
11192159047fSniklas
11202159047fSniklas h = hash_new ();
11212159047fSniklas err = hash_jam (h, sb_terminate (&f.name), &f);
11222159047fSniklas if (err != NULL)
11232159047fSniklas return err;
11242159047fSniklas
11252159047fSniklas f.index = 1;
11262159047fSniklas f.next = NULL;
11272159047fSniklas
11282159047fSniklas sb_reset (out);
11292159047fSniklas
11302159047fSniklas idx = sb_skip_comma (idx, in);
1131c074d1c9Sdrahn if (idx >= in->len)
11322159047fSniklas {
11332159047fSniklas /* Expand once with a null string. */
1134c074d1c9Sdrahn err = macro_expand_body (&sub, out, &f, h, 0);
11352159047fSniklas if (err != NULL)
11362159047fSniklas return err;
11372159047fSniklas }
11382159047fSniklas else
11392159047fSniklas {
11402159047fSniklas if (irpc && in->ptr[idx] == '"')
11412159047fSniklas ++idx;
1142c074d1c9Sdrahn while (idx < in->len)
11432159047fSniklas {
11442159047fSniklas if (!irpc)
11452159047fSniklas idx = get_any_string (idx, in, &f.actual, 1, 0);
11462159047fSniklas else
11472159047fSniklas {
11482159047fSniklas if (in->ptr[idx] == '"')
11492159047fSniklas {
11502159047fSniklas int nxt;
11512159047fSniklas
11522159047fSniklas nxt = sb_skip_white (idx + 1, in);
1153c074d1c9Sdrahn if (nxt >= in->len)
11542159047fSniklas {
11552159047fSniklas idx = nxt;
11562159047fSniklas break;
11572159047fSniklas }
11582159047fSniklas }
11592159047fSniklas sb_reset (&f.actual);
11602159047fSniklas sb_add_char (&f.actual, in->ptr[idx]);
11612159047fSniklas ++idx;
11622159047fSniklas }
1163c074d1c9Sdrahn err = macro_expand_body (&sub, out, &f, h, 0);
11642159047fSniklas if (err != NULL)
11652159047fSniklas return err;
11662159047fSniklas if (!irpc)
11672159047fSniklas idx = sb_skip_comma (idx, in);
11682159047fSniklas else
11692159047fSniklas idx = sb_skip_white (idx, in);
11702159047fSniklas }
11712159047fSniklas }
11722159047fSniklas
11732159047fSniklas hash_die (h);
11742159047fSniklas sb_kill (&sub);
11752159047fSniklas
11762159047fSniklas return NULL;
11772159047fSniklas }
1178