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 = ¯o->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 (¯o->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", ¯o->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