xref: /openbsd/gnu/usr.bin/binutils/gas/macro.c (revision 007c2a45)
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 = &macro->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 (&macro->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", &macro->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