macro.c revision 130561
1130561Sobrien/* macro.c - macro support for gas
2130561Sobrien   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
377298Sobrien   Free Software Foundation, Inc.
433965Sjdp
533965Sjdp   Written by Steve and Judy Chamberlain of Cygnus Support,
633965Sjdp      sac@cygnus.com
733965Sjdp
833965Sjdp   This file is part of GAS, the GNU Assembler.
933965Sjdp
1033965Sjdp   GAS is free software; you can redistribute it and/or modify
1133965Sjdp   it under the terms of the GNU General Public License as published by
1233965Sjdp   the Free Software Foundation; either version 2, or (at your option)
1333965Sjdp   any later version.
1433965Sjdp
1533965Sjdp   GAS is distributed in the hope that it will be useful,
1633965Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1733965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1833965Sjdp   GNU General Public License for more details.
1933965Sjdp
2033965Sjdp   You should have received a copy of the GNU General Public License
2133965Sjdp   along with GAS; see the file COPYING.  If not, write to the Free
2233965Sjdp   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2377298Sobrien   02111-1307, USA.  */
2433965Sjdp
2533965Sjdp#include "config.h"
2638889Sjdp
2789857Sobrien#ifndef __GNUC__
2838889Sjdp# if HAVE_ALLOCA_H
2938889Sjdp#  include <alloca.h>
3038889Sjdp# else
3138889Sjdp#  ifdef _AIX
3289857Sobrien/* Indented so that pre-ansi C compilers will ignore it, rather than
3389857Sobrien   choke on it.  Some versions of AIX require this to be the first
3489857Sobrien   thing in the file.  */
3538889Sjdp #pragma alloca
3638889Sjdp#  else
3738889Sjdp#   ifndef alloca /* predefined by HP cc +Olibcalls */
3838889Sjdp#    if !defined (__STDC__) && !defined (__hpux)
3938889Sjdpextern char *alloca ();
4038889Sjdp#    else
4138889Sjdpextern void *alloca ();
4238889Sjdp#    endif /* __STDC__, __hpux */
4338889Sjdp#   endif /* alloca */
4438889Sjdp#  endif /* _AIX */
4538889Sjdp# endif /* HAVE_ALLOCA_H */
4689857Sobrien#endif /* __GNUC__ */
4738889Sjdp
4833965Sjdp#include <stdio.h>
4933965Sjdp#ifdef HAVE_STRING_H
5033965Sjdp#include <string.h>
5133965Sjdp#else
5233965Sjdp#include <strings.h>
5333965Sjdp#endif
5433965Sjdp#ifdef HAVE_STDLIB_H
5533965Sjdp#include <stdlib.h>
5633965Sjdp#endif
5733965Sjdp#include "libiberty.h"
5889857Sobrien#include "safe-ctype.h"
5933965Sjdp#include "sb.h"
6033965Sjdp#include "hash.h"
6133965Sjdp#include "macro.h"
6233965Sjdp
6360484Sobrien#include "asintl.h"
6460484Sobrien
6533965Sjdp/* The routines in this file handle macro definition and expansion.
66130561Sobrien   They are called by gas.  */
6733965Sjdp
6833965Sjdp/* Internal functions.  */
6933965Sjdp
70130561Sobrienstatic int get_token (int, sb *, sb *);
71130561Sobrienstatic int getstring (int, sb *, sb *);
72130561Sobrienstatic int get_any_string (int, sb *, sb *, int, int);
73130561Sobrienstatic int do_formals (macro_entry *, int, sb *);
74130561Sobrienstatic int get_apost_token (int, sb *, sb *, int);
75130561Sobrienstatic int sub_actual (int, sb *, sb *, struct hash_control *, int, sb *, int);
7633965Sjdpstatic const char *macro_expand_body
77130561Sobrien  (sb *, sb *, formal_entry *, struct hash_control *, int);
78130561Sobrienstatic const char *macro_expand (int, sb *, macro_entry *, sb *);
7933965Sjdp
8033965Sjdp#define ISWHITE(x) ((x) == ' ' || (x) == '\t')
8133965Sjdp
8233965Sjdp#define ISSEP(x) \
8333965Sjdp ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \
8438889Sjdp  || (x) == ')' || (x) == '(' \
8538889Sjdp  || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>')))
8633965Sjdp
8733965Sjdp#define ISBASE(x) \
8833965Sjdp  ((x) == 'b' || (x) == 'B' \
8933965Sjdp   || (x) == 'q' || (x) == 'Q' \
9033965Sjdp   || (x) == 'h' || (x) == 'H' \
9133965Sjdp   || (x) == 'd' || (x) == 'D')
9233965Sjdp
9333965Sjdp/* The macro hash table.  */
9433965Sjdp
95130561Sobrienstruct hash_control *macro_hash;
9633965Sjdp
9733965Sjdp/* Whether any macros have been defined.  */
9833965Sjdp
9933965Sjdpint macro_defined;
10033965Sjdp
101130561Sobrien/* Whether we are in alternate syntax mode.  */
10233965Sjdp
10333965Sjdpstatic int macro_alternate;
10433965Sjdp
10533965Sjdp/* Whether we are in MRI mode.  */
10633965Sjdp
10733965Sjdpstatic int macro_mri;
10833965Sjdp
10933965Sjdp/* Whether we should strip '@' characters.  */
11033965Sjdp
11133965Sjdpstatic int macro_strip_at;
11233965Sjdp
11333965Sjdp/* Function to use to parse an expression.  */
11433965Sjdp
115130561Sobrienstatic int (*macro_expr) (const char *, int, sb *, int *);
11633965Sjdp
11733965Sjdp/* Number of macro expansions that have been done.  */
11833965Sjdp
11933965Sjdpstatic int macro_number;
12033965Sjdp
12133965Sjdp/* Initialize macro processing.  */
12233965Sjdp
12333965Sjdpvoid
124130561Sobrienmacro_init (int alternate, int mri, int strip_at,
125130561Sobrien	    int (*expr) (const char *, int, sb *, int *))
12633965Sjdp{
12733965Sjdp  macro_hash = hash_new ();
12833965Sjdp  macro_defined = 0;
12933965Sjdp  macro_alternate = alternate;
13033965Sjdp  macro_mri = mri;
13133965Sjdp  macro_strip_at = strip_at;
13233965Sjdp  macro_expr = expr;
13333965Sjdp}
13433965Sjdp
13560484Sobrien/* Switch in and out of MRI mode on the fly.  */
13660484Sobrien
13760484Sobrienvoid
138130561Sobrienmacro_mri_mode (int mri)
13960484Sobrien{
14060484Sobrien  macro_mri = mri;
14160484Sobrien}
14260484Sobrien
14333965Sjdp/* Read input lines till we get to a TO string.
14433965Sjdp   Increase nesting depth if we get a FROM string.
14533965Sjdp   Put the results into sb at PTR.
14633965Sjdp   Add a new input line to an sb using GET_LINE.
14733965Sjdp   Return 1 on success, 0 on unexpected EOF.  */
14833965Sjdp
14933965Sjdpint
150130561Sobrienbuffer_and_nest (const char *from, const char *to, sb *ptr,
151130561Sobrien		 int (*get_line) (sb *))
15233965Sjdp{
15333965Sjdp  int from_len = strlen (from);
15433965Sjdp  int to_len = strlen (to);
15533965Sjdp  int depth = 1;
15633965Sjdp  int line_start = ptr->len;
15733965Sjdp
15833965Sjdp  int more = get_line (ptr);
15933965Sjdp
16033965Sjdp  while (more)
16133965Sjdp    {
16277298Sobrien      /* Try and find the first pseudo op on the line.  */
16333965Sjdp      int i = line_start;
16433965Sjdp
16533965Sjdp      if (! macro_alternate && ! macro_mri)
16633965Sjdp	{
16733965Sjdp	  /* With normal syntax we can suck what we want till we get
16833965Sjdp	     to the dot.  With the alternate, labels have to start in
16933965Sjdp	     the first column, since we cant tell what's a label and
17077298Sobrien	     whats a pseudoop.  */
17133965Sjdp
17277298Sobrien	  /* Skip leading whitespace.  */
17333965Sjdp	  while (i < ptr->len && ISWHITE (ptr->ptr[i]))
17433965Sjdp	    i++;
17533965Sjdp
17677298Sobrien	  /* Skip over a label.  */
17733965Sjdp	  while (i < ptr->len
17889857Sobrien		 && (ISALNUM (ptr->ptr[i])
17933965Sjdp		     || ptr->ptr[i] == '_'
18033965Sjdp		     || ptr->ptr[i] == '$'))
18133965Sjdp	    i++;
18233965Sjdp
18377298Sobrien	  /* And a colon.  */
18433965Sjdp	  if (i < ptr->len
18533965Sjdp	      && ptr->ptr[i] == ':')
18633965Sjdp	    i++;
18733965Sjdp
18833965Sjdp	}
18977298Sobrien      /* Skip trailing whitespace.  */
19033965Sjdp      while (i < ptr->len && ISWHITE (ptr->ptr[i]))
19133965Sjdp	i++;
19233965Sjdp
19333965Sjdp      if (i < ptr->len && (ptr->ptr[i] == '.'
19433965Sjdp			   || macro_alternate
19533965Sjdp			   || macro_mri))
19633965Sjdp	{
19733965Sjdp	  if (ptr->ptr[i] == '.')
19877298Sobrien	    i++;
19960484Sobrien	  if (strncasecmp (ptr->ptr + i, from, from_len) == 0
20077298Sobrien	      && (ptr->len == (i + from_len)
20189857Sobrien		  || ! ISALNUM (ptr->ptr[i + from_len])))
20233965Sjdp	    depth++;
20360484Sobrien	  if (strncasecmp (ptr->ptr + i, to, to_len) == 0
20477298Sobrien	      && (ptr->len == (i + to_len)
20589857Sobrien		  || ! ISALNUM (ptr->ptr[i + to_len])))
20633965Sjdp	    {
20733965Sjdp	      depth--;
20833965Sjdp	      if (depth == 0)
20933965Sjdp		{
21077298Sobrien		  /* Reset the string to not include the ending rune.  */
21133965Sjdp		  ptr->len = line_start;
21233965Sjdp		  break;
21333965Sjdp		}
21433965Sjdp	    }
21533965Sjdp	}
21633965Sjdp
217130561Sobrien      /* Add the original end-of-line char to the end and keep running.  */
218130561Sobrien      sb_add_char (ptr, more);
21933965Sjdp      line_start = ptr->len;
22033965Sjdp      more = get_line (ptr);
22133965Sjdp    }
22233965Sjdp
22333965Sjdp  /* Return 1 on success, 0 on unexpected EOF.  */
22433965Sjdp  return depth == 0;
22533965Sjdp}
22633965Sjdp
22733965Sjdp/* Pick up a token.  */
22833965Sjdp
22933965Sjdpstatic int
230130561Sobrienget_token (int idx, sb *in, sb *name)
23133965Sjdp{
23233965Sjdp  if (idx < in->len
23389857Sobrien      && (ISALPHA (in->ptr[idx])
23433965Sjdp	  || in->ptr[idx] == '_'
23533965Sjdp	  || in->ptr[idx] == '$'))
23633965Sjdp    {
23733965Sjdp      sb_add_char (name, in->ptr[idx++]);
23833965Sjdp      while (idx < in->len
23989857Sobrien	     && (ISALNUM (in->ptr[idx])
24033965Sjdp		 || in->ptr[idx] == '_'
24133965Sjdp		 || in->ptr[idx] == '$'))
24233965Sjdp	{
24333965Sjdp	  sb_add_char (name, in->ptr[idx++]);
24433965Sjdp	}
24533965Sjdp    }
24677298Sobrien  /* Ignore trailing &.  */
24733965Sjdp  if (macro_alternate && idx < in->len && in->ptr[idx] == '&')
24833965Sjdp    idx++;
24933965Sjdp  return idx;
25033965Sjdp}
25133965Sjdp
25233965Sjdp/* Pick up a string.  */
25333965Sjdp
25433965Sjdpstatic int
255130561Sobriengetstring (int idx, sb *in, sb *acc)
25633965Sjdp{
25733965Sjdp  idx = sb_skip_white (idx, in);
25833965Sjdp
25933965Sjdp  while (idx < in->len
26077298Sobrien	 && (in->ptr[idx] == '"'
26138889Sjdp	     || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
26233965Sjdp	     || (in->ptr[idx] == '\'' && macro_alternate)))
26333965Sjdp    {
26433965Sjdp      if (in->ptr[idx] == '<')
26533965Sjdp	{
26638889Sjdp	  int nest = 0;
26738889Sjdp	  idx++;
26838889Sjdp	  while ((in->ptr[idx] != '>' || nest)
26938889Sjdp		 && idx < in->len)
27033965Sjdp	    {
27138889Sjdp	      if (in->ptr[idx] == '!')
27233965Sjdp		{
27377298Sobrien		  idx++;
27438889Sjdp		  sb_add_char (acc, in->ptr[idx++]);
27533965Sjdp		}
27638889Sjdp	      else
27738889Sjdp		{
27838889Sjdp		  if (in->ptr[idx] == '>')
27938889Sjdp		    nest--;
28038889Sjdp		  if (in->ptr[idx] == '<')
28138889Sjdp		    nest++;
28238889Sjdp		  sb_add_char (acc, in->ptr[idx++]);
28338889Sjdp		}
28433965Sjdp	    }
28538889Sjdp	  idx++;
28633965Sjdp	}
28733965Sjdp      else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
28833965Sjdp	{
28933965Sjdp	  char tchar = in->ptr[idx];
29077298Sobrien	  int escaped = 0;
29177298Sobrien
29233965Sjdp	  idx++;
29377298Sobrien
29433965Sjdp	  while (idx < in->len)
29533965Sjdp	    {
29677298Sobrien	      if (in->ptr[idx - 1] == '\\')
29777298Sobrien		escaped ^= 1;
29877298Sobrien	      else
29977298Sobrien		escaped = 0;
30077298Sobrien
30133965Sjdp	      if (macro_alternate && in->ptr[idx] == '!')
30233965Sjdp		{
30377298Sobrien		  idx ++;
30477298Sobrien
30577298Sobrien		  sb_add_char (acc, in->ptr[idx]);
30677298Sobrien
30777298Sobrien		  idx ++;
30833965Sjdp		}
30977298Sobrien	      else if (escaped && in->ptr[idx] == tchar)
31077298Sobrien		{
31177298Sobrien		  sb_add_char (acc, tchar);
31277298Sobrien		  idx ++;
31377298Sobrien		}
31433965Sjdp	      else
31533965Sjdp		{
31633965Sjdp		  if (in->ptr[idx] == tchar)
31733965Sjdp		    {
31877298Sobrien		      idx ++;
31977298Sobrien
32033965Sjdp		      if (idx >= in->len || in->ptr[idx] != tchar)
32133965Sjdp			break;
32233965Sjdp		    }
32377298Sobrien
32433965Sjdp		  sb_add_char (acc, in->ptr[idx]);
32577298Sobrien		  idx ++;
32633965Sjdp		}
32733965Sjdp	    }
32833965Sjdp	}
32933965Sjdp    }
33077298Sobrien
33133965Sjdp  return idx;
33233965Sjdp}
33333965Sjdp
33433965Sjdp/* Fetch string from the input stream,
33533965Sjdp   rules:
33633965Sjdp    'Bxyx<whitespace>  	-> return 'Bxyza
33733965Sjdp    %<char>		-> return string of decimal value of x
33833965Sjdp    "<string>"		-> return string
33933965Sjdp    xyx<whitespace>     -> return xyz
34033965Sjdp*/
34133965Sjdp
34233965Sjdpstatic int
343130561Sobrienget_any_string (int idx, sb *in, sb *out, int expand, int pretend_quoted)
34433965Sjdp{
34533965Sjdp  sb_reset (out);
34633965Sjdp  idx = sb_skip_white (idx, in);
34733965Sjdp
34833965Sjdp  if (idx < in->len)
34933965Sjdp    {
350130561Sobrien      if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))
35133965Sjdp	{
35233965Sjdp	  while (!ISSEP (in->ptr[idx]))
35333965Sjdp	    sb_add_char (out, in->ptr[idx++]);
35433965Sjdp	}
35533965Sjdp      else if (in->ptr[idx] == '%'
35633965Sjdp	       && macro_alternate
35733965Sjdp	       && expand)
35833965Sjdp	{
35933965Sjdp	  int val;
36033965Sjdp	  char buf[20];
36177298Sobrien	  /* Turns the next expression into a string.  */
36289857Sobrien	  /* xgettext: no-c-format */
36360484Sobrien	  idx = (*macro_expr) (_("% operator needs absolute expression"),
36433965Sjdp			       idx + 1,
36533965Sjdp			       in,
36633965Sjdp			       &val);
367104834Sobrien	  sprintf (buf, "%d", val);
36833965Sjdp	  sb_add_string (out, buf);
36933965Sjdp	}
37033965Sjdp      else if (in->ptr[idx] == '"'
37138889Sjdp	       || (in->ptr[idx] == '<' && (macro_alternate || macro_mri))
37233965Sjdp	       || (macro_alternate && in->ptr[idx] == '\''))
37333965Sjdp	{
37433965Sjdp	  if (macro_alternate
37533965Sjdp	      && ! macro_strip_at
37633965Sjdp	      && expand)
37733965Sjdp	    {
37877298Sobrien	      /* Keep the quotes.  */
37977298Sobrien	      sb_add_char (out, '\"');
38033965Sjdp
38133965Sjdp	      idx = getstring (idx, in, out);
38277298Sobrien	      sb_add_char (out, '\"');
38333965Sjdp	    }
38433965Sjdp	  else
38533965Sjdp	    {
38633965Sjdp	      idx = getstring (idx, in, out);
38733965Sjdp	    }
38833965Sjdp	}
38977298Sobrien      else
39033965Sjdp	{
39177298Sobrien	  while (idx < in->len
39233965Sjdp		 && (in->ptr[idx] == '"'
39333965Sjdp		     || in->ptr[idx] == '\''
39477298Sobrien		     || pretend_quoted
39533965Sjdp		     || (in->ptr[idx] != ' '
39633965Sjdp			 && in->ptr[idx] != '\t'
39733965Sjdp			 && in->ptr[idx] != ','
39838889Sjdp			 && (in->ptr[idx] != '<'
39938889Sjdp			     || (! macro_alternate && ! macro_mri)))))
40033965Sjdp	    {
40177298Sobrien	      if (in->ptr[idx] == '"'
40233965Sjdp		  || in->ptr[idx] == '\'')
40333965Sjdp		{
40433965Sjdp		  char tchar = in->ptr[idx];
40533965Sjdp		  sb_add_char (out, in->ptr[idx++]);
40633965Sjdp		  while (idx < in->len
40733965Sjdp			 && in->ptr[idx] != tchar)
40877298Sobrien		    sb_add_char (out, in->ptr[idx++]);
40933965Sjdp		  if (idx == in->len)
41077298Sobrien		    return idx;
41133965Sjdp		}
41233965Sjdp	      sb_add_char (out, in->ptr[idx++]);
41333965Sjdp	    }
41433965Sjdp	}
41533965Sjdp    }
41633965Sjdp
41733965Sjdp  return idx;
41833965Sjdp}
41933965Sjdp
42033965Sjdp/* Pick up the formal parameters of a macro definition.  */
42133965Sjdp
42233965Sjdpstatic int
423130561Sobriendo_formals (macro_entry *macro, int idx, sb *in)
42433965Sjdp{
42533965Sjdp  formal_entry **p = &macro->formals;
42633965Sjdp
42733965Sjdp  macro->formal_count = 0;
42833965Sjdp  macro->formal_hash = hash_new ();
42933965Sjdp  while (idx < in->len)
43033965Sjdp    {
43133965Sjdp      formal_entry *formal;
43233965Sjdp
43333965Sjdp      formal = (formal_entry *) xmalloc (sizeof (formal_entry));
43433965Sjdp
43533965Sjdp      sb_new (&formal->name);
43633965Sjdp      sb_new (&formal->def);
43733965Sjdp      sb_new (&formal->actual);
43833965Sjdp
43933965Sjdp      idx = sb_skip_white (idx, in);
44033965Sjdp      idx = get_token (idx, in, &formal->name);
44133965Sjdp      if (formal->name.len == 0)
44233965Sjdp	break;
44333965Sjdp      idx = sb_skip_white (idx, in);
44433965Sjdp      if (formal->name.len)
44533965Sjdp	{
44677298Sobrien	  /* This is a formal.  */
44733965Sjdp	  if (idx < in->len && in->ptr[idx] == '=')
44833965Sjdp	    {
44977298Sobrien	      /* Got a default.  */
45033965Sjdp	      idx = get_any_string (idx + 1, in, &formal->def, 1, 0);
45133965Sjdp	    }
45233965Sjdp	}
45333965Sjdp
45477298Sobrien      /* Add to macro's hash table.  */
45533965Sjdp      hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal);
45633965Sjdp
45733965Sjdp      formal->index = macro->formal_count;
45833965Sjdp      idx = sb_skip_comma (idx, in);
45933965Sjdp      macro->formal_count++;
46033965Sjdp      *p = formal;
46133965Sjdp      p = &formal->next;
46233965Sjdp      *p = NULL;
46333965Sjdp    }
46433965Sjdp
46533965Sjdp  if (macro_mri)
46633965Sjdp    {
46733965Sjdp      formal_entry *formal;
46833965Sjdp      const char *name;
46933965Sjdp
47033965Sjdp      /* Add a special NARG formal, which macro_expand will set to the
47133965Sjdp         number of arguments.  */
47233965Sjdp      formal = (formal_entry *) xmalloc (sizeof (formal_entry));
47333965Sjdp
47433965Sjdp      sb_new (&formal->name);
47533965Sjdp      sb_new (&formal->def);
47633965Sjdp      sb_new (&formal->actual);
47733965Sjdp
47833965Sjdp      /* The same MRI assemblers which treat '@' characters also use
47933965Sjdp         the name $NARG.  At least until we find an exception.  */
48033965Sjdp      if (macro_strip_at)
48133965Sjdp	name = "$NARG";
48233965Sjdp      else
48333965Sjdp	name = "NARG";
48433965Sjdp
48533965Sjdp      sb_add_string (&formal->name, name);
48633965Sjdp
48777298Sobrien      /* Add to macro's hash table.  */
48833965Sjdp      hash_jam (macro->formal_hash, name, formal);
48933965Sjdp
49033965Sjdp      formal->index = NARG_INDEX;
49133965Sjdp      *p = formal;
49233965Sjdp      formal->next = NULL;
49333965Sjdp    }
49433965Sjdp
49533965Sjdp  return idx;
49633965Sjdp}
49733965Sjdp
49833965Sjdp/* Define a new macro.  Returns NULL on success, otherwise returns an
49933965Sjdp   error message.  If NAMEP is not NULL, *NAMEP is set to the name of
50033965Sjdp   the macro which was defined.  */
50133965Sjdp
50233965Sjdpconst char *
503130561Sobriendefine_macro (int idx, sb *in, sb *label,
504130561Sobrien	      int (*get_line) (sb *), const char **namep)
50533965Sjdp{
50633965Sjdp  macro_entry *macro;
50733965Sjdp  sb name;
50833965Sjdp  const char *namestr;
50933965Sjdp
51033965Sjdp  macro = (macro_entry *) xmalloc (sizeof (macro_entry));
51133965Sjdp  sb_new (&macro->sub);
51233965Sjdp  sb_new (&name);
51333965Sjdp
51433965Sjdp  macro->formal_count = 0;
51533965Sjdp  macro->formals = 0;
51633965Sjdp
51733965Sjdp  idx = sb_skip_white (idx, in);
51833965Sjdp  if (! buffer_and_nest ("MACRO", "ENDM", &macro->sub, get_line))
51960484Sobrien    return _("unexpected end of file in macro definition");
52033965Sjdp  if (label != NULL && label->len != 0)
52133965Sjdp    {
52233965Sjdp      sb_add_sb (&name, label);
52338889Sjdp      if (idx < in->len && in->ptr[idx] == '(')
52433965Sjdp	{
52577298Sobrien	  /* It's the label: MACRO (formals,...)  sort  */
52633965Sjdp	  idx = do_formals (macro, idx + 1, in);
52733965Sjdp	  if (in->ptr[idx] != ')')
52860484Sobrien	    return _("missing ) after formals");
52933965Sjdp	}
53033965Sjdp      else
53133965Sjdp	{
53277298Sobrien	  /* It's the label: MACRO formals,...  sort  */
53333965Sjdp	  idx = do_formals (macro, idx, in);
53433965Sjdp	}
53533965Sjdp    }
53633965Sjdp  else
53733965Sjdp    {
53833965Sjdp      idx = get_token (idx, in, &name);
53933965Sjdp      idx = sb_skip_comma (idx, in);
54033965Sjdp      idx = do_formals (macro, idx, in);
54133965Sjdp    }
54233965Sjdp
54377298Sobrien  /* And stick it in the macro hash table.  */
54433965Sjdp  for (idx = 0; idx < name.len; idx++)
54589857Sobrien    name.ptr[idx] = TOLOWER (name.ptr[idx]);
54633965Sjdp  namestr = sb_terminate (&name);
54733965Sjdp  hash_jam (macro_hash, namestr, (PTR) macro);
54833965Sjdp
54933965Sjdp  macro_defined = 1;
55033965Sjdp
55133965Sjdp  if (namep != NULL)
55233965Sjdp    *namep = namestr;
55333965Sjdp
55433965Sjdp  return NULL;
55533965Sjdp}
55633965Sjdp
55733965Sjdp/* Scan a token, and then skip KIND.  */
55833965Sjdp
55933965Sjdpstatic int
560130561Sobrienget_apost_token (int idx, sb *in, sb *name, int kind)
56133965Sjdp{
56233965Sjdp  idx = get_token (idx, in, name);
56333965Sjdp  if (idx < in->len
56433965Sjdp      && in->ptr[idx] == kind
56533965Sjdp      && (! macro_mri || macro_strip_at)
56633965Sjdp      && (! macro_strip_at || kind == '@'))
56733965Sjdp    idx++;
56833965Sjdp  return idx;
56933965Sjdp}
57033965Sjdp
57133965Sjdp/* Substitute the actual value for a formal parameter.  */
57233965Sjdp
57333965Sjdpstatic int
574130561Sobriensub_actual (int start, sb *in, sb *t, struct hash_control *formal_hash,
575130561Sobrien	    int kind, sb *out, int copyifnotthere)
57633965Sjdp{
57733965Sjdp  int src;
57833965Sjdp  formal_entry *ptr;
57933965Sjdp
58033965Sjdp  src = get_apost_token (start, in, t, kind);
58133965Sjdp  /* See if it's in the macro's hash table, unless this is
58233965Sjdp     macro_strip_at and kind is '@' and the token did not end in '@'.  */
58333965Sjdp  if (macro_strip_at
58433965Sjdp      && kind == '@'
58533965Sjdp      && (src == start || in->ptr[src - 1] != '@'))
58633965Sjdp    ptr = NULL;
58733965Sjdp  else
58833965Sjdp    ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t));
58933965Sjdp  if (ptr)
59033965Sjdp    {
59133965Sjdp      if (ptr->actual.len)
59233965Sjdp	{
59333965Sjdp	  sb_add_sb (out, &ptr->actual);
59433965Sjdp	}
59533965Sjdp      else
59633965Sjdp	{
59733965Sjdp	  sb_add_sb (out, &ptr->def);
59833965Sjdp	}
59933965Sjdp    }
60038889Sjdp  else if (kind == '&')
60138889Sjdp    {
60238889Sjdp      /* Doing this permits people to use & in macro bodies.  */
60338889Sjdp      sb_add_char (out, '&');
604130561Sobrien      sb_add_sb (out, t);
60538889Sjdp    }
60633965Sjdp  else if (copyifnotthere)
60733965Sjdp    {
60833965Sjdp      sb_add_sb (out, t);
60933965Sjdp    }
61077298Sobrien  else
61133965Sjdp    {
61233965Sjdp      sb_add_char (out, '\\');
61333965Sjdp      sb_add_sb (out, t);
61433965Sjdp    }
61533965Sjdp  return src;
61633965Sjdp}
61733965Sjdp
61833965Sjdp/* Expand the body of a macro.  */
61933965Sjdp
62033965Sjdpstatic const char *
621130561Sobrienmacro_expand_body (sb *in, sb *out, formal_entry *formals,
622130561Sobrien		   struct hash_control *formal_hash, int locals)
62333965Sjdp{
62433965Sjdp  sb t;
62533965Sjdp  int src = 0;
62633965Sjdp  int inquote = 0;
62733965Sjdp  formal_entry *loclist = NULL;
62833965Sjdp
62933965Sjdp  sb_new (&t);
63033965Sjdp
63133965Sjdp  while (src < in->len)
63233965Sjdp    {
63333965Sjdp      if (in->ptr[src] == '&')
63433965Sjdp	{
63533965Sjdp	  sb_reset (&t);
63633965Sjdp	  if (macro_mri)
63733965Sjdp	    {
63833965Sjdp	      if (src + 1 < in->len && in->ptr[src + 1] == '&')
63933965Sjdp		src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1);
64033965Sjdp	      else
64133965Sjdp		sb_add_char (out, in->ptr[src++]);
64233965Sjdp	    }
64333965Sjdp	  else
64433965Sjdp	    {
64538889Sjdp	      /* FIXME: Why do we do this?  */
64633965Sjdp	      src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0);
64733965Sjdp	    }
64833965Sjdp	}
64933965Sjdp      else if (in->ptr[src] == '\\')
65033965Sjdp	{
65133965Sjdp	  src++;
652130561Sobrien	  if (in->ptr[src] == '(')
65333965Sjdp	    {
65477298Sobrien	      /* Sub in till the next ')' literally.  */
65533965Sjdp	      src++;
65633965Sjdp	      while (src < in->len && in->ptr[src] != ')')
65733965Sjdp		{
65833965Sjdp		  sb_add_char (out, in->ptr[src++]);
65933965Sjdp		}
66033965Sjdp	      if (in->ptr[src] == ')')
66133965Sjdp		src++;
66233965Sjdp	      else
66360484Sobrien		return _("missplaced )");
66433965Sjdp	    }
66533965Sjdp	  else if (in->ptr[src] == '@')
66633965Sjdp	    {
66777298Sobrien	      /* Sub in the macro invocation number.  */
66833965Sjdp
66938889Sjdp	      char buffer[10];
67033965Sjdp	      src++;
67177298Sobrien	      sprintf (buffer, "%d", macro_number);
67233965Sjdp	      sb_add_string (out, buffer);
67333965Sjdp	    }
67433965Sjdp	  else if (in->ptr[src] == '&')
67533965Sjdp	    {
67633965Sjdp	      /* This is a preprocessor variable name, we don't do them
67777298Sobrien		 here.  */
67833965Sjdp	      sb_add_char (out, '\\');
67933965Sjdp	      sb_add_char (out, '&');
68033965Sjdp	      src++;
68133965Sjdp	    }
68289857Sobrien	  else if (macro_mri && ISALNUM (in->ptr[src]))
68333965Sjdp	    {
68433965Sjdp	      int ind;
68533965Sjdp	      formal_entry *f;
68633965Sjdp
68789857Sobrien	      if (ISDIGIT (in->ptr[src]))
68833965Sjdp		ind = in->ptr[src] - '0';
68989857Sobrien	      else if (ISUPPER (in->ptr[src]))
69033965Sjdp		ind = in->ptr[src] - 'A' + 10;
69133965Sjdp	      else
69233965Sjdp		ind = in->ptr[src] - 'a' + 10;
69333965Sjdp	      ++src;
69433965Sjdp	      for (f = formals; f != NULL; f = f->next)
69533965Sjdp		{
69633965Sjdp		  if (f->index == ind - 1)
69733965Sjdp		    {
69833965Sjdp		      if (f->actual.len != 0)
69933965Sjdp			sb_add_sb (out, &f->actual);
70033965Sjdp		      else
70133965Sjdp			sb_add_sb (out, &f->def);
70233965Sjdp		      break;
70333965Sjdp		    }
70433965Sjdp		}
70533965Sjdp	    }
70633965Sjdp	  else
70733965Sjdp	    {
70833965Sjdp	      sb_reset (&t);
70933965Sjdp	      src = sub_actual (src, in, &t, formal_hash, '\'', out, 0);
71033965Sjdp	    }
71133965Sjdp	}
71233965Sjdp      else if ((macro_alternate || macro_mri)
71389857Sobrien	       && (ISALPHA (in->ptr[src])
71433965Sjdp		   || in->ptr[src] == '_'
71533965Sjdp		   || in->ptr[src] == '$')
71633965Sjdp	       && (! inquote
71733965Sjdp		   || ! macro_strip_at
71833965Sjdp		   || (src > 0 && in->ptr[src - 1] == '@')))
71933965Sjdp	{
72033965Sjdp	  if (! locals
72133965Sjdp	      || src + 5 >= in->len
72233965Sjdp	      || strncasecmp (in->ptr + src, "LOCAL", 5) != 0
72333965Sjdp	      || ! ISWHITE (in->ptr[src + 5]))
72433965Sjdp	    {
72533965Sjdp	      sb_reset (&t);
72633965Sjdp	      src = sub_actual (src, in, &t, formal_hash,
72733965Sjdp				(macro_strip_at && inquote) ? '@' : '\'',
72833965Sjdp				out, 1);
72933965Sjdp	    }
73033965Sjdp	  else
73133965Sjdp	    {
73233965Sjdp	      formal_entry *f;
73333965Sjdp
73433965Sjdp	      src = sb_skip_white (src + 5, in);
735130561Sobrien	      while (in->ptr[src] != '\n')
73633965Sjdp		{
73733965Sjdp		  static int loccnt;
73833965Sjdp		  char buf[20];
73933965Sjdp		  const char *err;
74033965Sjdp
74133965Sjdp		  f = (formal_entry *) xmalloc (sizeof (formal_entry));
74233965Sjdp		  sb_new (&f->name);
74333965Sjdp		  sb_new (&f->def);
74433965Sjdp		  sb_new (&f->actual);
74533965Sjdp		  f->index = LOCAL_INDEX;
74633965Sjdp		  f->next = loclist;
74733965Sjdp		  loclist = f;
74833965Sjdp
74933965Sjdp		  src = get_token (src, in, &f->name);
75033965Sjdp		  ++loccnt;
75133965Sjdp		  sprintf (buf, "LL%04x", loccnt);
75233965Sjdp		  sb_add_string (&f->actual, buf);
75333965Sjdp
75433965Sjdp		  err = hash_jam (formal_hash, sb_terminate (&f->name), f);
75533965Sjdp		  if (err != NULL)
75633965Sjdp		    return err;
75733965Sjdp
75833965Sjdp		  src = sb_skip_comma (src, in);
75933965Sjdp		}
76033965Sjdp	    }
76133965Sjdp	}
76233965Sjdp      else if (in->ptr[src] == '"'
76333965Sjdp	       || (macro_mri && in->ptr[src] == '\''))
76433965Sjdp	{
76533965Sjdp	  inquote = !inquote;
76633965Sjdp	  sb_add_char (out, in->ptr[src++]);
76733965Sjdp	}
76833965Sjdp      else if (in->ptr[src] == '@' && macro_strip_at)
76933965Sjdp	{
77033965Sjdp	  ++src;
77133965Sjdp	  if (src < in->len
77233965Sjdp	      && in->ptr[src] == '@')
77333965Sjdp	    {
77433965Sjdp	      sb_add_char (out, '@');
77533965Sjdp	      ++src;
77633965Sjdp	    }
77733965Sjdp	}
77833965Sjdp      else if (macro_mri
77933965Sjdp	       && in->ptr[src] == '='
78033965Sjdp	       && src + 1 < in->len
78133965Sjdp	       && in->ptr[src + 1] == '=')
78233965Sjdp	{
78333965Sjdp	  formal_entry *ptr;
78433965Sjdp
78533965Sjdp	  sb_reset (&t);
78633965Sjdp	  src = get_token (src + 2, in, &t);
78733965Sjdp	  ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t));
78833965Sjdp	  if (ptr == NULL)
78933965Sjdp	    {
79033965Sjdp	      /* FIXME: We should really return a warning string here,
79133965Sjdp                 but we can't, because the == might be in the MRI
79233965Sjdp                 comment field, and, since the nature of the MRI
79333965Sjdp                 comment field depends upon the exact instruction
79433965Sjdp                 being used, we don't have enough information here to
79533965Sjdp                 figure out whether it is or not.  Instead, we leave
79633965Sjdp                 the == in place, which should cause a syntax error if
79733965Sjdp                 it is not in a comment.  */
79833965Sjdp	      sb_add_char (out, '=');
79933965Sjdp	      sb_add_char (out, '=');
80033965Sjdp	      sb_add_sb (out, &t);
80133965Sjdp	    }
80233965Sjdp	  else
80333965Sjdp	    {
80433965Sjdp	      if (ptr->actual.len)
80533965Sjdp		{
80633965Sjdp		  sb_add_string (out, "-1");
80733965Sjdp		}
80833965Sjdp	      else
80933965Sjdp		{
81033965Sjdp		  sb_add_char (out, '0');
81133965Sjdp		}
81233965Sjdp	    }
81333965Sjdp	}
81433965Sjdp      else
81533965Sjdp	{
81633965Sjdp	  sb_add_char (out, in->ptr[src++]);
81733965Sjdp	}
81833965Sjdp    }
81933965Sjdp
82033965Sjdp  sb_kill (&t);
82133965Sjdp
82233965Sjdp  while (loclist != NULL)
82333965Sjdp    {
82433965Sjdp      formal_entry *f;
82533965Sjdp
82633965Sjdp      f = loclist->next;
82760484Sobrien      /* Setting the value to NULL effectively deletes the entry.  We
82860484Sobrien         avoid calling hash_delete because it doesn't reclaim memory.  */
82960484Sobrien      hash_jam (formal_hash, sb_terminate (&loclist->name), NULL);
83033965Sjdp      sb_kill (&loclist->name);
83133965Sjdp      sb_kill (&loclist->def);
83233965Sjdp      sb_kill (&loclist->actual);
83333965Sjdp      free (loclist);
83433965Sjdp      loclist = f;
83533965Sjdp    }
83633965Sjdp
83733965Sjdp  return NULL;
83833965Sjdp}
83933965Sjdp
84033965Sjdp/* Assign values to the formal parameters of a macro, and expand the
84133965Sjdp   body.  */
84233965Sjdp
84333965Sjdpstatic const char *
844130561Sobrienmacro_expand (int idx, sb *in, macro_entry *m, sb *out)
84533965Sjdp{
84633965Sjdp  sb t;
84733965Sjdp  formal_entry *ptr;
84833965Sjdp  formal_entry *f;
84933965Sjdp  int is_positional = 0;
85033965Sjdp  int is_keyword = 0;
85133965Sjdp  int narg = 0;
85233965Sjdp  const char *err;
85333965Sjdp
85433965Sjdp  sb_new (&t);
85577298Sobrien
85677298Sobrien  /* Reset any old value the actuals may have.  */
85733965Sjdp  for (f = m->formals; f; f = f->next)
85877298Sobrien    sb_reset (&f->actual);
85933965Sjdp  f = m->formals;
86033965Sjdp  while (f != NULL && f->index < 0)
86133965Sjdp    f = f->next;
86233965Sjdp
86333965Sjdp  if (macro_mri)
86433965Sjdp    {
86533965Sjdp      /* The macro may be called with an optional qualifier, which may
86633965Sjdp         be referred to in the macro body as \0.  */
86733965Sjdp      if (idx < in->len && in->ptr[idx] == '.')
868104834Sobrien	{
869104834Sobrien	  /* The Microtec assembler ignores this if followed by a white space.
870104834Sobrien	     (Macro invocation with empty extension) */
871104834Sobrien	  idx++;
872104834Sobrien	  if (    idx < in->len
873104834Sobrien		  && in->ptr[idx] != ' '
874104834Sobrien		  && in->ptr[idx] != '\t')
875104834Sobrien	    {
876104834Sobrien	      formal_entry *n;
87733965Sjdp
878104834Sobrien	      n = (formal_entry *) xmalloc (sizeof (formal_entry));
879104834Sobrien	      sb_new (&n->name);
880104834Sobrien	      sb_new (&n->def);
881104834Sobrien	      sb_new (&n->actual);
882104834Sobrien	      n->index = QUAL_INDEX;
88333965Sjdp
884104834Sobrien	      n->next = m->formals;
885104834Sobrien	      m->formals = n;
88633965Sjdp
887104834Sobrien	      idx = get_any_string (idx, in, &n->actual, 1, 0);
888104834Sobrien	    }
889104834Sobrien	}
890104834Sobrien    }
89133965Sjdp
89277298Sobrien  /* Peel off the actuals and store them away in the hash tables' actuals.  */
89333965Sjdp  idx = sb_skip_white (idx, in);
894130561Sobrien  while (idx < in->len)
89533965Sjdp    {
89633965Sjdp      int scan;
89733965Sjdp
89877298Sobrien      /* Look and see if it's a positional or keyword arg.  */
89933965Sjdp      scan = idx;
90033965Sjdp      while (scan < in->len
90133965Sjdp	     && !ISSEP (in->ptr[scan])
90238889Sjdp	     && !(macro_mri && in->ptr[scan] == '\'')
90333965Sjdp	     && (!macro_alternate && in->ptr[scan] != '='))
90433965Sjdp	scan++;
90533965Sjdp      if (scan < in->len && !macro_alternate && in->ptr[scan] == '=')
90633965Sjdp	{
90733965Sjdp	  is_keyword = 1;
90833965Sjdp
90938889Sjdp	  /* It's OK to go from positional to keyword.  */
91038889Sjdp
91133965Sjdp	  /* This is a keyword arg, fetch the formal name and
91277298Sobrien	     then the actual stuff.  */
91333965Sjdp	  sb_reset (&t);
91433965Sjdp	  idx = get_token (idx, in, &t);
91533965Sjdp	  if (in->ptr[idx] != '=')
91660484Sobrien	    return _("confusion in formal parameters");
91733965Sjdp
91877298Sobrien	  /* Lookup the formal in the macro's list.  */
91933965Sjdp	  ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
92033965Sjdp	  if (!ptr)
92160484Sobrien	    return _("macro formal argument does not exist");
92233965Sjdp	  else
92333965Sjdp	    {
92477298Sobrien	      /* Insert this value into the right place.  */
92533965Sjdp	      sb_reset (&ptr->actual);
92633965Sjdp	      idx = get_any_string (idx + 1, in, &ptr->actual, 0, 0);
92733965Sjdp	      if (ptr->actual.len > 0)
92833965Sjdp		++narg;
92933965Sjdp	    }
93033965Sjdp	}
93133965Sjdp      else
93233965Sjdp	{
93377298Sobrien	  /* This is a positional arg.  */
93433965Sjdp	  is_positional = 1;
93533965Sjdp	  if (is_keyword)
93660484Sobrien	    return _("can't mix positional and keyword arguments");
93733965Sjdp
93833965Sjdp	  if (!f)
93933965Sjdp	    {
94033965Sjdp	      formal_entry **pf;
94133965Sjdp	      int c;
94233965Sjdp
94333965Sjdp	      if (!macro_mri)
94460484Sobrien		return _("too many positional arguments");
94533965Sjdp
94633965Sjdp	      f = (formal_entry *) xmalloc (sizeof (formal_entry));
94733965Sjdp	      sb_new (&f->name);
94833965Sjdp	      sb_new (&f->def);
94933965Sjdp	      sb_new (&f->actual);
95033965Sjdp	      f->next = NULL;
95133965Sjdp
95233965Sjdp	      c = -1;
95333965Sjdp	      for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next)
95433965Sjdp		if ((*pf)->index >= c)
95533965Sjdp		  c = (*pf)->index + 1;
95633965Sjdp	      if (c == -1)
95733965Sjdp		c = 0;
95833965Sjdp	      *pf = f;
95933965Sjdp	      f->index = c;
96033965Sjdp	    }
96133965Sjdp
96233965Sjdp	  sb_reset (&f->actual);
96333965Sjdp	  idx = get_any_string (idx, in, &f->actual, 1, 0);
96433965Sjdp	  if (f->actual.len > 0)
96533965Sjdp	    ++narg;
96633965Sjdp	  do
96733965Sjdp	    {
96833965Sjdp	      f = f->next;
96933965Sjdp	    }
97033965Sjdp	  while (f != NULL && f->index < 0);
97133965Sjdp	}
97233965Sjdp
97333965Sjdp      if (! macro_mri)
97433965Sjdp	idx = sb_skip_comma (idx, in);
97533965Sjdp      else
97633965Sjdp	{
97733965Sjdp	  if (in->ptr[idx] == ',')
97833965Sjdp	    ++idx;
97933965Sjdp	  if (ISWHITE (in->ptr[idx]))
98033965Sjdp	    break;
98133965Sjdp	}
98233965Sjdp    }
98333965Sjdp
98433965Sjdp  if (macro_mri)
98533965Sjdp    {
98633965Sjdp      char buffer[20];
98733965Sjdp
98833965Sjdp      sb_reset (&t);
98933965Sjdp      sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG");
99033965Sjdp      ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t));
99133965Sjdp      sb_reset (&ptr->actual);
99233965Sjdp      sprintf (buffer, "%d", narg);
99333965Sjdp      sb_add_string (&ptr->actual, buffer);
99433965Sjdp    }
99533965Sjdp
996130561Sobrien  err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, 1);
99733965Sjdp  if (err != NULL)
99833965Sjdp    return err;
99933965Sjdp
100033965Sjdp  /* Discard any unnamed formal arguments.  */
100133965Sjdp  if (macro_mri)
100233965Sjdp    {
100333965Sjdp      formal_entry **pf;
100433965Sjdp
100533965Sjdp      pf = &m->formals;
100633965Sjdp      while (*pf != NULL)
100733965Sjdp	{
100833965Sjdp	  if ((*pf)->name.len != 0)
100933965Sjdp	    pf = &(*pf)->next;
101033965Sjdp	  else
101133965Sjdp	    {
101233965Sjdp	      sb_kill (&(*pf)->name);
101333965Sjdp	      sb_kill (&(*pf)->def);
101433965Sjdp	      sb_kill (&(*pf)->actual);
101533965Sjdp	      f = (*pf)->next;
101633965Sjdp	      free (*pf);
101733965Sjdp	      *pf = f;
101833965Sjdp	    }
101933965Sjdp	}
102033965Sjdp    }
102133965Sjdp
102233965Sjdp  sb_kill (&t);
102333965Sjdp  macro_number++;
102433965Sjdp
102533965Sjdp  return NULL;
102633965Sjdp}
102733965Sjdp
102833965Sjdp/* Check for a macro.  If one is found, put the expansion into
1029130561Sobrien   *EXPAND.  Return 1 if a macro is found, 0 otherwise.  */
103033965Sjdp
103133965Sjdpint
1032130561Sobriencheck_macro (const char *line, sb *expand,
1033130561Sobrien	     const char **error, macro_entry **info)
103433965Sjdp{
103533965Sjdp  const char *s;
103633965Sjdp  char *copy, *cs;
103733965Sjdp  macro_entry *macro;
103833965Sjdp  sb line_sb;
103933965Sjdp
104089857Sobrien  if (! ISALPHA (*line)
104133965Sjdp      && *line != '_'
104233965Sjdp      && *line != '$'
104333965Sjdp      && (! macro_mri || *line != '.'))
104433965Sjdp    return 0;
104533965Sjdp
104633965Sjdp  s = line + 1;
104789857Sobrien  while (ISALNUM (*s)
104833965Sjdp	 || *s == '_'
104933965Sjdp	 || *s == '$')
105033965Sjdp    ++s;
105133965Sjdp
105238889Sjdp  copy = (char *) alloca (s - line + 1);
105333965Sjdp  memcpy (copy, line, s - line);
105433965Sjdp  copy[s - line] = '\0';
105533965Sjdp  for (cs = copy; *cs != '\0'; cs++)
105689857Sobrien    *cs = TOLOWER (*cs);
105733965Sjdp
105833965Sjdp  macro = (macro_entry *) hash_find (macro_hash, copy);
105933965Sjdp
106033965Sjdp  if (macro == NULL)
106133965Sjdp    return 0;
106233965Sjdp
106333965Sjdp  /* Wrap the line up in an sb.  */
106433965Sjdp  sb_new (&line_sb);
106533965Sjdp  while (*s != '\0' && *s != '\n' && *s != '\r')
106633965Sjdp    sb_add_char (&line_sb, *s++);
106733965Sjdp
106833965Sjdp  sb_new (expand);
1069130561Sobrien  *error = macro_expand (0, &line_sb, macro, expand);
107033965Sjdp
107133965Sjdp  sb_kill (&line_sb);
107233965Sjdp
107377298Sobrien  /* Export the macro information if requested.  */
107460484Sobrien  if (info)
107560484Sobrien    *info = macro;
107660484Sobrien
107733965Sjdp  return 1;
107833965Sjdp}
107933965Sjdp
108033965Sjdp/* Delete a macro.  */
108133965Sjdp
108233965Sjdpvoid
1083130561Sobriendelete_macro (const char *name)
108433965Sjdp{
108533965Sjdp  hash_delete (macro_hash, name);
108633965Sjdp}
108733965Sjdp
108833965Sjdp/* Handle the MRI IRP and IRPC pseudo-ops.  These are handled as a
108933965Sjdp   combined macro definition and execution.  This returns NULL on
109033965Sjdp   success, or an error message otherwise.  */
109133965Sjdp
109233965Sjdpconst char *
1093130561Sobrienexpand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *))
109433965Sjdp{
109533965Sjdp  const char *mn;
109633965Sjdp  sb sub;
109733965Sjdp  formal_entry f;
109833965Sjdp  struct hash_control *h;
109933965Sjdp  const char *err;
110033965Sjdp
110133965Sjdp  if (irpc)
110233965Sjdp    mn = "IRPC";
110333965Sjdp  else
110433965Sjdp    mn = "IRP";
110533965Sjdp
110633965Sjdp  idx = sb_skip_white (idx, in);
110733965Sjdp
110833965Sjdp  sb_new (&sub);
110933965Sjdp  if (! buffer_and_nest (mn, "ENDR", &sub, get_line))
111060484Sobrien    return _("unexpected end of file in irp or irpc");
111177298Sobrien
111233965Sjdp  sb_new (&f.name);
111333965Sjdp  sb_new (&f.def);
111433965Sjdp  sb_new (&f.actual);
111533965Sjdp
111633965Sjdp  idx = get_token (idx, in, &f.name);
111733965Sjdp  if (f.name.len == 0)
111860484Sobrien    return _("missing model parameter");
111933965Sjdp
112033965Sjdp  h = hash_new ();
112133965Sjdp  err = hash_jam (h, sb_terminate (&f.name), &f);
112233965Sjdp  if (err != NULL)
112333965Sjdp    return err;
112433965Sjdp
112533965Sjdp  f.index = 1;
112633965Sjdp  f.next = NULL;
112733965Sjdp
112833965Sjdp  sb_reset (out);
112933965Sjdp
113033965Sjdp  idx = sb_skip_comma (idx, in);
1131130561Sobrien  if (idx >= in->len)
113233965Sjdp    {
113333965Sjdp      /* Expand once with a null string.  */
1134130561Sobrien      err = macro_expand_body (&sub, out, &f, h, 0);
113533965Sjdp      if (err != NULL)
113633965Sjdp	return err;
113733965Sjdp    }
113833965Sjdp  else
113933965Sjdp    {
114033965Sjdp      if (irpc && in->ptr[idx] == '"')
114133965Sjdp	++idx;
1142130561Sobrien      while (idx < in->len)
114333965Sjdp	{
114433965Sjdp	  if (!irpc)
114533965Sjdp	    idx = get_any_string (idx, in, &f.actual, 1, 0);
114633965Sjdp	  else
114733965Sjdp	    {
114833965Sjdp	      if (in->ptr[idx] == '"')
114933965Sjdp		{
115033965Sjdp		  int nxt;
115133965Sjdp
115233965Sjdp		  nxt = sb_skip_white (idx + 1, in);
1153130561Sobrien		  if (nxt >= in->len)
115433965Sjdp		    {
115533965Sjdp		      idx = nxt;
115633965Sjdp		      break;
115733965Sjdp		    }
115833965Sjdp		}
115933965Sjdp	      sb_reset (&f.actual);
116033965Sjdp	      sb_add_char (&f.actual, in->ptr[idx]);
116133965Sjdp	      ++idx;
116233965Sjdp	    }
1163130561Sobrien	  err = macro_expand_body (&sub, out, &f, h, 0);
116433965Sjdp	  if (err != NULL)
116533965Sjdp	    return err;
116633965Sjdp	  if (!irpc)
116733965Sjdp	    idx = sb_skip_comma (idx, in);
116833965Sjdp	  else
116933965Sjdp	    idx = sb_skip_white (idx, in);
117033965Sjdp	}
117133965Sjdp    }
117233965Sjdp
117333965Sjdp  hash_die (h);
117433965Sjdp  sb_kill (&sub);
117533965Sjdp
117633965Sjdp  return NULL;
117733965Sjdp}
1178