macro.c revision 38889
133965Sjdp/* macro.c - macro support for gas and gasp 238889Sjdp Copyright (C) 1994, 95, 96, 97, 1998 Free Software Foundation, Inc. 333965Sjdp 433965Sjdp Written by Steve and Judy Chamberlain of Cygnus Support, 533965Sjdp sac@cygnus.com 633965Sjdp 733965Sjdp This file is part of GAS, the GNU Assembler. 833965Sjdp 933965Sjdp GAS is free software; you can redistribute it and/or modify 1033965Sjdp it under the terms of the GNU General Public License as published by 1133965Sjdp the Free Software Foundation; either version 2, or (at your option) 1233965Sjdp any later version. 1333965Sjdp 1433965Sjdp GAS is distributed in the hope that it will be useful, 1533965Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1633965Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1733965Sjdp GNU General Public License for more details. 1833965Sjdp 1933965Sjdp You should have received a copy of the GNU General Public License 2033965Sjdp along with GAS; see the file COPYING. If not, write to the Free 2133965Sjdp Software Foundation, 59 Temple Place - Suite 330, Boston, MA 2233965Sjdp 02111-1307, USA. */ 2333965Sjdp 2433965Sjdp#include "config.h" 2538889Sjdp 2638889Sjdp/* AIX requires this to be the first thing in the file. */ 2738889Sjdp#ifdef __GNUC__ 2838889Sjdp# ifndef alloca 2938889Sjdp# ifdef __STDC__ 3038889Sjdpextern void *alloca (); 3138889Sjdp# else 3238889Sjdpextern char *alloca (); 3338889Sjdp# endif 3438889Sjdp# endif 3538889Sjdp#else 3638889Sjdp# if HAVE_ALLOCA_H 3738889Sjdp# include <alloca.h> 3838889Sjdp# else 3938889Sjdp# ifdef _AIX 4038889Sjdp #pragma alloca 4138889Sjdp# else 4238889Sjdp# ifndef alloca /* predefined by HP cc +Olibcalls */ 4338889Sjdp# if !defined (__STDC__) && !defined (__hpux) 4438889Sjdpextern char *alloca (); 4538889Sjdp# else 4638889Sjdpextern void *alloca (); 4738889Sjdp# endif /* __STDC__, __hpux */ 4838889Sjdp# endif /* alloca */ 4938889Sjdp# endif /* _AIX */ 5038889Sjdp# endif /* HAVE_ALLOCA_H */ 5138889Sjdp#endif 5238889Sjdp 5333965Sjdp#include <stdio.h> 5433965Sjdp#ifdef HAVE_STRING_H 5533965Sjdp#include <string.h> 5633965Sjdp#else 5733965Sjdp#include <strings.h> 5833965Sjdp#endif 5933965Sjdp#include <ctype.h> 6033965Sjdp#ifdef HAVE_STDLIB_H 6133965Sjdp#include <stdlib.h> 6233965Sjdp#endif 6333965Sjdp#include "libiberty.h" 6433965Sjdp#include "sb.h" 6533965Sjdp#include "hash.h" 6633965Sjdp#include "macro.h" 6733965Sjdp 6833965Sjdp/* The routines in this file handle macro definition and expansion. 6933965Sjdp They are called by both gasp and gas. */ 7033965Sjdp 7133965Sjdp/* Structures used to store macros. 7233965Sjdp 7333965Sjdp Each macro knows its name and included text. It gets built with a 7433965Sjdp list of formal arguments, and also keeps a hash table which points 7533965Sjdp into the list to speed up formal search. Each formal knows its 7633965Sjdp name and its default value. Each time the macro is expanded, the 7733965Sjdp formals get the actual values attatched to them. */ 7833965Sjdp 7933965Sjdp/* describe the formal arguments to a macro */ 8033965Sjdp 8133965Sjdptypedef struct formal_struct 8233965Sjdp { 8333965Sjdp struct formal_struct *next; /* next formal in list */ 8433965Sjdp sb name; /* name of the formal */ 8533965Sjdp sb def; /* the default value */ 8633965Sjdp sb actual; /* the actual argument (changed on each expansion) */ 8733965Sjdp int index; /* the index of the formal 0..formal_count-1 */ 8833965Sjdp } 8933965Sjdpformal_entry; 9033965Sjdp 9133965Sjdp/* Other values found in the index field of a formal_entry. */ 9233965Sjdp#define QUAL_INDEX (-1) 9333965Sjdp#define NARG_INDEX (-2) 9433965Sjdp#define LOCAL_INDEX (-3) 9533965Sjdp 9633965Sjdp/* describe the macro. */ 9733965Sjdp 9833965Sjdptypedef struct macro_struct 9933965Sjdp { 10033965Sjdp sb sub; /* substitution text. */ 10133965Sjdp int formal_count; /* number of formal args. */ 10233965Sjdp formal_entry *formals; /* pointer to list of formal_structs */ 10333965Sjdp struct hash_control *formal_hash; /* hash table of formals. */ 10433965Sjdp } 10533965Sjdpmacro_entry; 10633965Sjdp 10733965Sjdp/* Internal functions. */ 10833965Sjdp 10933965Sjdpstatic int get_token PARAMS ((int, sb *, sb *)); 11033965Sjdpstatic int getstring PARAMS ((int, sb *, sb *)); 11133965Sjdpstatic int get_any_string PARAMS ((int, sb *, sb *, int, int)); 11233965Sjdpstatic int do_formals PARAMS ((macro_entry *, int, sb *)); 11333965Sjdpstatic int get_apost_token PARAMS ((int, sb *, sb *, int)); 11433965Sjdpstatic int sub_actual 11533965Sjdp PARAMS ((int, sb *, sb *, struct hash_control *, int, sb *, int)); 11633965Sjdpstatic const char *macro_expand_body 11733965Sjdp PARAMS ((sb *, sb *, formal_entry *, struct hash_control *, int, int)); 11833965Sjdpstatic const char *macro_expand PARAMS ((int, sb *, macro_entry *, sb *, int)); 11933965Sjdp 12033965Sjdp#define ISWHITE(x) ((x) == ' ' || (x) == '\t') 12133965Sjdp 12233965Sjdp#define ISSEP(x) \ 12333965Sjdp ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \ 12438889Sjdp || (x) == ')' || (x) == '(' \ 12538889Sjdp || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>'))) 12633965Sjdp 12733965Sjdp#define ISBASE(x) \ 12833965Sjdp ((x) == 'b' || (x) == 'B' \ 12933965Sjdp || (x) == 'q' || (x) == 'Q' \ 13033965Sjdp || (x) == 'h' || (x) == 'H' \ 13133965Sjdp || (x) == 'd' || (x) == 'D') 13233965Sjdp 13333965Sjdp/* The macro hash table. */ 13433965Sjdp 13533965Sjdpstatic struct hash_control *macro_hash; 13633965Sjdp 13733965Sjdp/* Whether any macros have been defined. */ 13833965Sjdp 13933965Sjdpint macro_defined; 14033965Sjdp 14133965Sjdp/* Whether we are in GASP alternate mode. */ 14233965Sjdp 14333965Sjdpstatic int macro_alternate; 14433965Sjdp 14533965Sjdp/* Whether we are in MRI mode. */ 14633965Sjdp 14733965Sjdpstatic int macro_mri; 14833965Sjdp 14933965Sjdp/* Whether we should strip '@' characters. */ 15033965Sjdp 15133965Sjdpstatic int macro_strip_at; 15233965Sjdp 15333965Sjdp/* Function to use to parse an expression. */ 15433965Sjdp 15533965Sjdpstatic int (*macro_expr) PARAMS ((const char *, int, sb *, int *)); 15633965Sjdp 15733965Sjdp/* Number of macro expansions that have been done. */ 15833965Sjdp 15933965Sjdpstatic int macro_number; 16033965Sjdp 16133965Sjdp/* Initialize macro processing. */ 16233965Sjdp 16333965Sjdpvoid 16433965Sjdpmacro_init (alternate, mri, strip_at, expr) 16533965Sjdp int alternate; 16633965Sjdp int mri; 16733965Sjdp int strip_at; 16833965Sjdp int (*expr) PARAMS ((const char *, int, sb *, int *)); 16933965Sjdp{ 17033965Sjdp macro_hash = hash_new (); 17133965Sjdp macro_defined = 0; 17233965Sjdp macro_alternate = alternate; 17333965Sjdp macro_mri = mri; 17433965Sjdp macro_strip_at = strip_at; 17533965Sjdp macro_expr = expr; 17633965Sjdp} 17733965Sjdp 17833965Sjdp/* Read input lines till we get to a TO string. 17933965Sjdp Increase nesting depth if we get a FROM string. 18033965Sjdp Put the results into sb at PTR. 18133965Sjdp Add a new input line to an sb using GET_LINE. 18233965Sjdp Return 1 on success, 0 on unexpected EOF. */ 18333965Sjdp 18433965Sjdpint 18533965Sjdpbuffer_and_nest (from, to, ptr, get_line) 18633965Sjdp const char *from; 18733965Sjdp const char *to; 18833965Sjdp sb *ptr; 18933965Sjdp int (*get_line) PARAMS ((sb *)); 19033965Sjdp{ 19133965Sjdp int from_len = strlen (from); 19233965Sjdp int to_len = strlen (to); 19333965Sjdp int depth = 1; 19433965Sjdp int line_start = ptr->len; 19533965Sjdp 19633965Sjdp int more = get_line (ptr); 19733965Sjdp 19833965Sjdp while (more) 19933965Sjdp { 20033965Sjdp /* Try and find the first pseudo op on the line */ 20133965Sjdp int i = line_start; 20233965Sjdp 20333965Sjdp if (! macro_alternate && ! macro_mri) 20433965Sjdp { 20533965Sjdp /* With normal syntax we can suck what we want till we get 20633965Sjdp to the dot. With the alternate, labels have to start in 20733965Sjdp the first column, since we cant tell what's a label and 20833965Sjdp whats a pseudoop */ 20933965Sjdp 21033965Sjdp /* Skip leading whitespace */ 21133965Sjdp while (i < ptr->len && ISWHITE (ptr->ptr[i])) 21233965Sjdp i++; 21333965Sjdp 21433965Sjdp /* Skip over a label */ 21533965Sjdp while (i < ptr->len 21633965Sjdp && (isalnum ((unsigned char) ptr->ptr[i]) 21733965Sjdp || ptr->ptr[i] == '_' 21833965Sjdp || ptr->ptr[i] == '$')) 21933965Sjdp i++; 22033965Sjdp 22133965Sjdp /* And a colon */ 22233965Sjdp if (i < ptr->len 22333965Sjdp && ptr->ptr[i] == ':') 22433965Sjdp i++; 22533965Sjdp 22633965Sjdp } 22733965Sjdp /* Skip trailing whitespace */ 22833965Sjdp while (i < ptr->len && ISWHITE (ptr->ptr[i])) 22933965Sjdp i++; 23033965Sjdp 23133965Sjdp if (i < ptr->len && (ptr->ptr[i] == '.' 23233965Sjdp || macro_alternate 23333965Sjdp || macro_mri)) 23433965Sjdp { 23533965Sjdp if (ptr->ptr[i] == '.') 23633965Sjdp i++; 23733965Sjdp if (strncasecmp (ptr->ptr + i, from, from_len) == 0) 23833965Sjdp depth++; 23933965Sjdp if (strncasecmp (ptr->ptr + i, to, to_len) == 0) 24033965Sjdp { 24133965Sjdp depth--; 24233965Sjdp if (depth == 0) 24333965Sjdp { 24433965Sjdp /* Reset the string to not include the ending rune */ 24533965Sjdp ptr->len = line_start; 24633965Sjdp break; 24733965Sjdp } 24833965Sjdp } 24933965Sjdp } 25033965Sjdp 25133965Sjdp /* Add a CR to the end and keep running */ 25233965Sjdp sb_add_char (ptr, '\n'); 25333965Sjdp line_start = ptr->len; 25433965Sjdp more = get_line (ptr); 25533965Sjdp } 25633965Sjdp 25733965Sjdp /* Return 1 on success, 0 on unexpected EOF. */ 25833965Sjdp return depth == 0; 25933965Sjdp} 26033965Sjdp 26133965Sjdp/* Pick up a token. */ 26233965Sjdp 26333965Sjdpstatic int 26433965Sjdpget_token (idx, in, name) 26533965Sjdp int idx; 26633965Sjdp sb *in; 26733965Sjdp sb *name; 26833965Sjdp{ 26933965Sjdp if (idx < in->len 27033965Sjdp && (isalpha ((unsigned char) in->ptr[idx]) 27133965Sjdp || in->ptr[idx] == '_' 27233965Sjdp || in->ptr[idx] == '$')) 27333965Sjdp { 27433965Sjdp sb_add_char (name, in->ptr[idx++]); 27533965Sjdp while (idx < in->len 27633965Sjdp && (isalnum ((unsigned char) in->ptr[idx]) 27733965Sjdp || in->ptr[idx] == '_' 27833965Sjdp || in->ptr[idx] == '$')) 27933965Sjdp { 28033965Sjdp sb_add_char (name, in->ptr[idx++]); 28133965Sjdp } 28233965Sjdp } 28333965Sjdp /* Ignore trailing & */ 28433965Sjdp if (macro_alternate && idx < in->len && in->ptr[idx] == '&') 28533965Sjdp idx++; 28633965Sjdp return idx; 28733965Sjdp} 28833965Sjdp 28933965Sjdp/* Pick up a string. */ 29033965Sjdp 29133965Sjdpstatic int 29233965Sjdpgetstring (idx, in, acc) 29333965Sjdp int idx; 29433965Sjdp sb *in; 29533965Sjdp sb *acc; 29633965Sjdp{ 29733965Sjdp idx = sb_skip_white (idx, in); 29833965Sjdp 29933965Sjdp while (idx < in->len 30033965Sjdp && (in->ptr[idx] == '"' 30138889Sjdp || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) 30233965Sjdp || (in->ptr[idx] == '\'' && macro_alternate))) 30333965Sjdp { 30433965Sjdp if (in->ptr[idx] == '<') 30533965Sjdp { 30638889Sjdp int nest = 0; 30738889Sjdp idx++; 30838889Sjdp while ((in->ptr[idx] != '>' || nest) 30938889Sjdp && idx < in->len) 31033965Sjdp { 31138889Sjdp if (in->ptr[idx] == '!') 31233965Sjdp { 31338889Sjdp idx++ ; 31438889Sjdp sb_add_char (acc, in->ptr[idx++]); 31533965Sjdp } 31638889Sjdp else 31738889Sjdp { 31838889Sjdp if (in->ptr[idx] == '>') 31938889Sjdp nest--; 32038889Sjdp if (in->ptr[idx] == '<') 32138889Sjdp nest++; 32238889Sjdp sb_add_char (acc, in->ptr[idx++]); 32338889Sjdp } 32433965Sjdp } 32538889Sjdp idx++; 32633965Sjdp } 32733965Sjdp else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') 32833965Sjdp { 32933965Sjdp char tchar = in->ptr[idx]; 33033965Sjdp idx++; 33133965Sjdp while (idx < in->len) 33233965Sjdp { 33333965Sjdp if (macro_alternate && in->ptr[idx] == '!') 33433965Sjdp { 33533965Sjdp idx++ ; 33633965Sjdp sb_add_char (acc, in->ptr[idx++]); 33733965Sjdp } 33833965Sjdp else 33933965Sjdp { 34033965Sjdp if (in->ptr[idx] == tchar) 34133965Sjdp { 34233965Sjdp idx++; 34333965Sjdp if (idx >= in->len || in->ptr[idx] != tchar) 34433965Sjdp break; 34533965Sjdp } 34633965Sjdp sb_add_char (acc, in->ptr[idx]); 34733965Sjdp idx++; 34833965Sjdp } 34933965Sjdp } 35033965Sjdp } 35133965Sjdp } 35233965Sjdp 35333965Sjdp return idx; 35433965Sjdp} 35533965Sjdp 35633965Sjdp/* Fetch string from the input stream, 35733965Sjdp rules: 35833965Sjdp 'Bxyx<whitespace> -> return 'Bxyza 35933965Sjdp %<char> -> return string of decimal value of x 36033965Sjdp "<string>" -> return string 36133965Sjdp xyx<whitespace> -> return xyz 36233965Sjdp*/ 36333965Sjdp 36433965Sjdpstatic int 36533965Sjdpget_any_string (idx, in, out, expand, pretend_quoted) 36633965Sjdp int idx; 36733965Sjdp sb *in; 36833965Sjdp sb *out; 36933965Sjdp int expand; 37033965Sjdp int pretend_quoted; 37133965Sjdp{ 37233965Sjdp sb_reset (out); 37333965Sjdp idx = sb_skip_white (idx, in); 37433965Sjdp 37533965Sjdp if (idx < in->len) 37633965Sjdp { 37733965Sjdp if (in->len > 2 && in->ptr[idx+1] == '\'' && ISBASE (in->ptr[idx])) 37833965Sjdp { 37933965Sjdp while (!ISSEP (in->ptr[idx])) 38033965Sjdp sb_add_char (out, in->ptr[idx++]); 38133965Sjdp } 38233965Sjdp else if (in->ptr[idx] == '%' 38333965Sjdp && macro_alternate 38433965Sjdp && expand) 38533965Sjdp { 38633965Sjdp int val; 38733965Sjdp char buf[20]; 38833965Sjdp /* Turns the next expression into a string */ 38933965Sjdp idx = (*macro_expr) ("% operator needs absolute expression", 39033965Sjdp idx + 1, 39133965Sjdp in, 39233965Sjdp &val); 39333965Sjdp sprintf(buf, "%d", val); 39433965Sjdp sb_add_string (out, buf); 39533965Sjdp } 39633965Sjdp else if (in->ptr[idx] == '"' 39738889Sjdp || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) 39833965Sjdp || (macro_alternate && in->ptr[idx] == '\'')) 39933965Sjdp { 40033965Sjdp if (macro_alternate 40133965Sjdp && ! macro_strip_at 40233965Sjdp && expand) 40333965Sjdp { 40433965Sjdp /* Keep the quotes */ 40533965Sjdp sb_add_char (out, '\"'); 40633965Sjdp 40733965Sjdp idx = getstring (idx, in, out); 40833965Sjdp sb_add_char (out, '\"'); 40933965Sjdp } 41033965Sjdp else 41133965Sjdp { 41233965Sjdp idx = getstring (idx, in, out); 41333965Sjdp } 41433965Sjdp } 41533965Sjdp else 41633965Sjdp { 41733965Sjdp while (idx < in->len 41833965Sjdp && (in->ptr[idx] == '"' 41933965Sjdp || in->ptr[idx] == '\'' 42033965Sjdp || pretend_quoted 42133965Sjdp || (in->ptr[idx] != ' ' 42233965Sjdp && in->ptr[idx] != '\t' 42333965Sjdp && in->ptr[idx] != ',' 42438889Sjdp && (in->ptr[idx] != '<' 42538889Sjdp || (! macro_alternate && ! macro_mri))))) 42633965Sjdp { 42733965Sjdp if (in->ptr[idx] == '"' 42833965Sjdp || in->ptr[idx] == '\'') 42933965Sjdp { 43033965Sjdp char tchar = in->ptr[idx]; 43133965Sjdp sb_add_char (out, in->ptr[idx++]); 43233965Sjdp while (idx < in->len 43333965Sjdp && in->ptr[idx] != tchar) 43433965Sjdp sb_add_char (out, in->ptr[idx++]); 43533965Sjdp if (idx == in->len) 43633965Sjdp return idx; 43733965Sjdp } 43833965Sjdp sb_add_char (out, in->ptr[idx++]); 43933965Sjdp } 44033965Sjdp } 44133965Sjdp } 44233965Sjdp 44333965Sjdp return idx; 44433965Sjdp} 44533965Sjdp 44633965Sjdp/* Pick up the formal parameters of a macro definition. */ 44733965Sjdp 44833965Sjdpstatic int 44933965Sjdpdo_formals (macro, idx, in) 45033965Sjdp macro_entry *macro; 45133965Sjdp int idx; 45233965Sjdp sb *in; 45333965Sjdp{ 45433965Sjdp formal_entry **p = ¯o->formals; 45533965Sjdp 45633965Sjdp macro->formal_count = 0; 45733965Sjdp macro->formal_hash = hash_new (); 45833965Sjdp while (idx < in->len) 45933965Sjdp { 46033965Sjdp formal_entry *formal; 46133965Sjdp 46233965Sjdp formal = (formal_entry *) xmalloc (sizeof (formal_entry)); 46333965Sjdp 46433965Sjdp sb_new (&formal->name); 46533965Sjdp sb_new (&formal->def); 46633965Sjdp sb_new (&formal->actual); 46733965Sjdp 46833965Sjdp idx = sb_skip_white (idx, in); 46933965Sjdp idx = get_token (idx, in, &formal->name); 47033965Sjdp if (formal->name.len == 0) 47133965Sjdp break; 47233965Sjdp idx = sb_skip_white (idx, in); 47333965Sjdp if (formal->name.len) 47433965Sjdp { 47533965Sjdp /* This is a formal */ 47633965Sjdp if (idx < in->len && in->ptr[idx] == '=') 47733965Sjdp { 47833965Sjdp /* Got a default */ 47933965Sjdp idx = get_any_string (idx + 1, in, &formal->def, 1, 0); 48033965Sjdp } 48133965Sjdp } 48233965Sjdp 48333965Sjdp /* Add to macro's hash table */ 48433965Sjdp hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal); 48533965Sjdp 48633965Sjdp formal->index = macro->formal_count; 48733965Sjdp idx = sb_skip_comma (idx, in); 48833965Sjdp macro->formal_count++; 48933965Sjdp *p = formal; 49033965Sjdp p = &formal->next; 49133965Sjdp *p = NULL; 49233965Sjdp } 49333965Sjdp 49433965Sjdp if (macro_mri) 49533965Sjdp { 49633965Sjdp formal_entry *formal; 49733965Sjdp const char *name; 49833965Sjdp 49933965Sjdp /* Add a special NARG formal, which macro_expand will set to the 50033965Sjdp number of arguments. */ 50133965Sjdp formal = (formal_entry *) xmalloc (sizeof (formal_entry)); 50233965Sjdp 50333965Sjdp sb_new (&formal->name); 50433965Sjdp sb_new (&formal->def); 50533965Sjdp sb_new (&formal->actual); 50633965Sjdp 50733965Sjdp /* The same MRI assemblers which treat '@' characters also use 50833965Sjdp the name $NARG. At least until we find an exception. */ 50933965Sjdp if (macro_strip_at) 51033965Sjdp name = "$NARG"; 51133965Sjdp else 51233965Sjdp name = "NARG"; 51333965Sjdp 51433965Sjdp sb_add_string (&formal->name, name); 51533965Sjdp 51633965Sjdp /* Add to macro's hash table */ 51733965Sjdp hash_jam (macro->formal_hash, name, formal); 51833965Sjdp 51933965Sjdp formal->index = NARG_INDEX; 52033965Sjdp *p = formal; 52133965Sjdp formal->next = NULL; 52233965Sjdp } 52333965Sjdp 52433965Sjdp return idx; 52533965Sjdp} 52633965Sjdp 52733965Sjdp/* Define a new macro. Returns NULL on success, otherwise returns an 52833965Sjdp error message. If NAMEP is not NULL, *NAMEP is set to the name of 52933965Sjdp the macro which was defined. */ 53033965Sjdp 53133965Sjdpconst char * 53233965Sjdpdefine_macro (idx, in, label, get_line, namep) 53333965Sjdp int idx; 53433965Sjdp sb *in; 53533965Sjdp sb *label; 53633965Sjdp int (*get_line) PARAMS ((sb *)); 53733965Sjdp const char **namep; 53833965Sjdp{ 53933965Sjdp macro_entry *macro; 54033965Sjdp sb name; 54133965Sjdp const char *namestr; 54233965Sjdp 54333965Sjdp macro = (macro_entry *) xmalloc (sizeof (macro_entry)); 54433965Sjdp sb_new (¯o->sub); 54533965Sjdp sb_new (&name); 54633965Sjdp 54733965Sjdp macro->formal_count = 0; 54833965Sjdp macro->formals = 0; 54933965Sjdp 55033965Sjdp idx = sb_skip_white (idx, in); 55133965Sjdp if (! buffer_and_nest ("MACRO", "ENDM", ¯o->sub, get_line)) 55233965Sjdp return "unexpected end of file in macro definition"; 55333965Sjdp if (label != NULL && label->len != 0) 55433965Sjdp { 55533965Sjdp sb_add_sb (&name, label); 55638889Sjdp if (idx < in->len && in->ptr[idx] == '(') 55733965Sjdp { 55833965Sjdp /* It's the label: MACRO (formals,...) sort */ 55933965Sjdp idx = do_formals (macro, idx + 1, in); 56033965Sjdp if (in->ptr[idx] != ')') 56133965Sjdp return "missing ) after formals"; 56233965Sjdp } 56333965Sjdp else 56433965Sjdp { 56533965Sjdp /* It's the label: MACRO formals,... sort */ 56633965Sjdp idx = do_formals (macro, idx, in); 56733965Sjdp } 56833965Sjdp } 56933965Sjdp else 57033965Sjdp { 57133965Sjdp idx = get_token (idx, in, &name); 57233965Sjdp idx = sb_skip_comma (idx, in); 57333965Sjdp idx = do_formals (macro, idx, in); 57433965Sjdp } 57533965Sjdp 57633965Sjdp /* and stick it in the macro hash table */ 57733965Sjdp for (idx = 0; idx < name.len; idx++) 57838889Sjdp if (isupper ((unsigned char) name.ptr[idx])) 57933965Sjdp name.ptr[idx] = tolower (name.ptr[idx]); 58033965Sjdp namestr = sb_terminate (&name); 58133965Sjdp hash_jam (macro_hash, namestr, (PTR) macro); 58233965Sjdp 58333965Sjdp macro_defined = 1; 58433965Sjdp 58533965Sjdp if (namep != NULL) 58633965Sjdp *namep = namestr; 58733965Sjdp 58833965Sjdp return NULL; 58933965Sjdp} 59033965Sjdp 59133965Sjdp/* Scan a token, and then skip KIND. */ 59233965Sjdp 59333965Sjdpstatic int 59433965Sjdpget_apost_token (idx, in, name, kind) 59533965Sjdp int idx; 59633965Sjdp sb *in; 59733965Sjdp sb *name; 59833965Sjdp int kind; 59933965Sjdp{ 60033965Sjdp idx = get_token (idx, in, name); 60133965Sjdp if (idx < in->len 60233965Sjdp && in->ptr[idx] == kind 60333965Sjdp && (! macro_mri || macro_strip_at) 60433965Sjdp && (! macro_strip_at || kind == '@')) 60533965Sjdp idx++; 60633965Sjdp return idx; 60733965Sjdp} 60833965Sjdp 60933965Sjdp/* Substitute the actual value for a formal parameter. */ 61033965Sjdp 61133965Sjdpstatic int 61233965Sjdpsub_actual (start, in, t, formal_hash, kind, out, copyifnotthere) 61333965Sjdp int start; 61433965Sjdp sb *in; 61533965Sjdp sb *t; 61633965Sjdp struct hash_control *formal_hash; 61733965Sjdp int kind; 61833965Sjdp sb *out; 61933965Sjdp int copyifnotthere; 62033965Sjdp{ 62133965Sjdp int src; 62233965Sjdp formal_entry *ptr; 62333965Sjdp 62433965Sjdp src = get_apost_token (start, in, t, kind); 62533965Sjdp /* See if it's in the macro's hash table, unless this is 62633965Sjdp macro_strip_at and kind is '@' and the token did not end in '@'. */ 62733965Sjdp if (macro_strip_at 62833965Sjdp && kind == '@' 62933965Sjdp && (src == start || in->ptr[src - 1] != '@')) 63033965Sjdp ptr = NULL; 63133965Sjdp else 63233965Sjdp ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t)); 63333965Sjdp if (ptr) 63433965Sjdp { 63533965Sjdp if (ptr->actual.len) 63633965Sjdp { 63733965Sjdp sb_add_sb (out, &ptr->actual); 63833965Sjdp } 63933965Sjdp else 64033965Sjdp { 64133965Sjdp sb_add_sb (out, &ptr->def); 64233965Sjdp } 64333965Sjdp } 64438889Sjdp else if (kind == '&') 64538889Sjdp { 64638889Sjdp /* Doing this permits people to use & in macro bodies. */ 64738889Sjdp sb_add_char (out, '&'); 64838889Sjdp } 64933965Sjdp else if (copyifnotthere) 65033965Sjdp { 65133965Sjdp sb_add_sb (out, t); 65233965Sjdp } 65333965Sjdp else 65433965Sjdp { 65533965Sjdp sb_add_char (out, '\\'); 65633965Sjdp sb_add_sb (out, t); 65733965Sjdp } 65833965Sjdp return src; 65933965Sjdp} 66033965Sjdp 66133965Sjdp/* Expand the body of a macro. */ 66233965Sjdp 66333965Sjdpstatic const char * 66433965Sjdpmacro_expand_body (in, out, formals, formal_hash, comment_char, locals) 66533965Sjdp sb *in; 66633965Sjdp sb *out; 66733965Sjdp formal_entry *formals; 66833965Sjdp struct hash_control *formal_hash; 66933965Sjdp int comment_char; 67033965Sjdp int locals; 67133965Sjdp{ 67233965Sjdp sb t; 67333965Sjdp int src = 0; 67433965Sjdp int inquote = 0; 67533965Sjdp formal_entry *loclist = NULL; 67633965Sjdp 67733965Sjdp sb_new (&t); 67833965Sjdp 67933965Sjdp while (src < in->len) 68033965Sjdp { 68133965Sjdp if (in->ptr[src] == '&') 68233965Sjdp { 68333965Sjdp sb_reset (&t); 68433965Sjdp if (macro_mri) 68533965Sjdp { 68633965Sjdp if (src + 1 < in->len && in->ptr[src + 1] == '&') 68733965Sjdp src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1); 68833965Sjdp else 68933965Sjdp sb_add_char (out, in->ptr[src++]); 69033965Sjdp } 69133965Sjdp else 69233965Sjdp { 69338889Sjdp /* FIXME: Why do we do this? */ 69433965Sjdp src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0); 69533965Sjdp } 69633965Sjdp } 69733965Sjdp else if (in->ptr[src] == '\\') 69833965Sjdp { 69933965Sjdp src++; 70033965Sjdp if (in->ptr[src] == comment_char && comment_char != '\0') 70133965Sjdp { 70233965Sjdp /* This is a comment, just drop the rest of the line */ 70333965Sjdp while (src < in->len 70433965Sjdp && in->ptr[src] != '\n') 70533965Sjdp src++; 70633965Sjdp } 70733965Sjdp else if (in->ptr[src] == '(') 70833965Sjdp { 70933965Sjdp /* Sub in till the next ')' literally */ 71033965Sjdp src++; 71133965Sjdp while (src < in->len && in->ptr[src] != ')') 71233965Sjdp { 71333965Sjdp sb_add_char (out, in->ptr[src++]); 71433965Sjdp } 71533965Sjdp if (in->ptr[src] == ')') 71633965Sjdp src++; 71733965Sjdp else 71833965Sjdp return "missplaced )"; 71933965Sjdp } 72033965Sjdp else if (in->ptr[src] == '@') 72133965Sjdp { 72233965Sjdp /* Sub in the macro invocation number */ 72333965Sjdp 72438889Sjdp char buffer[10]; 72533965Sjdp src++; 72633965Sjdp sprintf (buffer, "%05d", macro_number); 72733965Sjdp sb_add_string (out, buffer); 72833965Sjdp } 72933965Sjdp else if (in->ptr[src] == '&') 73033965Sjdp { 73133965Sjdp /* This is a preprocessor variable name, we don't do them 73233965Sjdp here */ 73333965Sjdp sb_add_char (out, '\\'); 73433965Sjdp sb_add_char (out, '&'); 73533965Sjdp src++; 73633965Sjdp } 73733965Sjdp else if (macro_mri 73833965Sjdp && isalnum ((unsigned char) in->ptr[src])) 73933965Sjdp { 74033965Sjdp int ind; 74133965Sjdp formal_entry *f; 74233965Sjdp 74333965Sjdp if (isdigit ((unsigned char) in->ptr[src])) 74433965Sjdp ind = in->ptr[src] - '0'; 74533965Sjdp else if (isupper ((unsigned char) in->ptr[src])) 74633965Sjdp ind = in->ptr[src] - 'A' + 10; 74733965Sjdp else 74833965Sjdp ind = in->ptr[src] - 'a' + 10; 74933965Sjdp ++src; 75033965Sjdp for (f = formals; f != NULL; f = f->next) 75133965Sjdp { 75233965Sjdp if (f->index == ind - 1) 75333965Sjdp { 75433965Sjdp if (f->actual.len != 0) 75533965Sjdp sb_add_sb (out, &f->actual); 75633965Sjdp else 75733965Sjdp sb_add_sb (out, &f->def); 75833965Sjdp break; 75933965Sjdp } 76033965Sjdp } 76133965Sjdp } 76233965Sjdp else 76333965Sjdp { 76433965Sjdp sb_reset (&t); 76533965Sjdp src = sub_actual (src, in, &t, formal_hash, '\'', out, 0); 76633965Sjdp } 76733965Sjdp } 76833965Sjdp else if ((macro_alternate || macro_mri) 76933965Sjdp && (isalpha ((unsigned char) in->ptr[src]) 77033965Sjdp || in->ptr[src] == '_' 77133965Sjdp || in->ptr[src] == '$') 77233965Sjdp && (! inquote 77333965Sjdp || ! macro_strip_at 77433965Sjdp || (src > 0 && in->ptr[src - 1] == '@'))) 77533965Sjdp { 77633965Sjdp if (! locals 77733965Sjdp || src + 5 >= in->len 77833965Sjdp || strncasecmp (in->ptr + src, "LOCAL", 5) != 0 77933965Sjdp || ! ISWHITE (in->ptr[src + 5])) 78033965Sjdp { 78133965Sjdp sb_reset (&t); 78233965Sjdp src = sub_actual (src, in, &t, formal_hash, 78333965Sjdp (macro_strip_at && inquote) ? '@' : '\'', 78433965Sjdp out, 1); 78533965Sjdp } 78633965Sjdp else 78733965Sjdp { 78833965Sjdp formal_entry *f; 78933965Sjdp 79033965Sjdp src = sb_skip_white (src + 5, in); 79133965Sjdp while (in->ptr[src] != '\n' && in->ptr[src] != comment_char) 79233965Sjdp { 79333965Sjdp static int loccnt; 79433965Sjdp char buf[20]; 79533965Sjdp const char *err; 79633965Sjdp 79733965Sjdp f = (formal_entry *) xmalloc (sizeof (formal_entry)); 79833965Sjdp sb_new (&f->name); 79933965Sjdp sb_new (&f->def); 80033965Sjdp sb_new (&f->actual); 80133965Sjdp f->index = LOCAL_INDEX; 80233965Sjdp f->next = loclist; 80333965Sjdp loclist = f; 80433965Sjdp 80533965Sjdp src = get_token (src, in, &f->name); 80633965Sjdp ++loccnt; 80733965Sjdp sprintf (buf, "LL%04x", loccnt); 80833965Sjdp sb_add_string (&f->actual, buf); 80933965Sjdp 81033965Sjdp err = hash_jam (formal_hash, sb_terminate (&f->name), f); 81133965Sjdp if (err != NULL) 81233965Sjdp return err; 81333965Sjdp 81433965Sjdp src = sb_skip_comma (src, in); 81533965Sjdp } 81633965Sjdp } 81733965Sjdp } 81833965Sjdp else if (comment_char != '\0' 81933965Sjdp && in->ptr[src] == comment_char 82033965Sjdp && src + 1 < in->len 82133965Sjdp && in->ptr[src + 1] == comment_char 82233965Sjdp && !inquote) 82333965Sjdp { 82433965Sjdp /* Two comment chars in a row cause the rest of the line to 82533965Sjdp be dropped. */ 82633965Sjdp while (src < in->len && in->ptr[src] != '\n') 82733965Sjdp src++; 82833965Sjdp } 82933965Sjdp else if (in->ptr[src] == '"' 83033965Sjdp || (macro_mri && in->ptr[src] == '\'')) 83133965Sjdp { 83233965Sjdp inquote = !inquote; 83333965Sjdp sb_add_char (out, in->ptr[src++]); 83433965Sjdp } 83533965Sjdp else if (in->ptr[src] == '@' && macro_strip_at) 83633965Sjdp { 83733965Sjdp ++src; 83833965Sjdp if (src < in->len 83933965Sjdp && in->ptr[src] == '@') 84033965Sjdp { 84133965Sjdp sb_add_char (out, '@'); 84233965Sjdp ++src; 84333965Sjdp } 84433965Sjdp } 84533965Sjdp else if (macro_mri 84633965Sjdp && in->ptr[src] == '=' 84733965Sjdp && src + 1 < in->len 84833965Sjdp && in->ptr[src + 1] == '=') 84933965Sjdp { 85033965Sjdp formal_entry *ptr; 85133965Sjdp 85233965Sjdp sb_reset (&t); 85333965Sjdp src = get_token (src + 2, in, &t); 85433965Sjdp ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t)); 85533965Sjdp if (ptr == NULL) 85633965Sjdp { 85733965Sjdp /* FIXME: We should really return a warning string here, 85833965Sjdp but we can't, because the == might be in the MRI 85933965Sjdp comment field, and, since the nature of the MRI 86033965Sjdp comment field depends upon the exact instruction 86133965Sjdp being used, we don't have enough information here to 86233965Sjdp figure out whether it is or not. Instead, we leave 86333965Sjdp the == in place, which should cause a syntax error if 86433965Sjdp it is not in a comment. */ 86533965Sjdp sb_add_char (out, '='); 86633965Sjdp sb_add_char (out, '='); 86733965Sjdp sb_add_sb (out, &t); 86833965Sjdp } 86933965Sjdp else 87033965Sjdp { 87133965Sjdp if (ptr->actual.len) 87233965Sjdp { 87333965Sjdp sb_add_string (out, "-1"); 87433965Sjdp } 87533965Sjdp else 87633965Sjdp { 87733965Sjdp sb_add_char (out, '0'); 87833965Sjdp } 87933965Sjdp } 88033965Sjdp } 88133965Sjdp else 88233965Sjdp { 88333965Sjdp sb_add_char (out, in->ptr[src++]); 88433965Sjdp } 88533965Sjdp } 88633965Sjdp 88733965Sjdp sb_kill (&t); 88833965Sjdp 88933965Sjdp while (loclist != NULL) 89033965Sjdp { 89133965Sjdp formal_entry *f; 89233965Sjdp 89333965Sjdp f = loclist->next; 89433965Sjdp hash_delete (formal_hash, sb_terminate (&loclist->name)); 89533965Sjdp sb_kill (&loclist->name); 89633965Sjdp sb_kill (&loclist->def); 89733965Sjdp sb_kill (&loclist->actual); 89833965Sjdp free (loclist); 89933965Sjdp loclist = f; 90033965Sjdp } 90133965Sjdp 90233965Sjdp return NULL; 90333965Sjdp} 90433965Sjdp 90533965Sjdp/* Assign values to the formal parameters of a macro, and expand the 90633965Sjdp body. */ 90733965Sjdp 90833965Sjdpstatic const char * 90933965Sjdpmacro_expand (idx, in, m, out, comment_char) 91033965Sjdp int idx; 91133965Sjdp sb *in; 91233965Sjdp macro_entry *m; 91333965Sjdp sb *out; 91433965Sjdp int comment_char; 91533965Sjdp{ 91633965Sjdp sb t; 91733965Sjdp formal_entry *ptr; 91833965Sjdp formal_entry *f; 91933965Sjdp int is_positional = 0; 92033965Sjdp int is_keyword = 0; 92133965Sjdp int narg = 0; 92233965Sjdp const char *err; 92333965Sjdp 92433965Sjdp sb_new (&t); 92533965Sjdp 92633965Sjdp /* Reset any old value the actuals may have */ 92733965Sjdp for (f = m->formals; f; f = f->next) 92833965Sjdp sb_reset (&f->actual); 92933965Sjdp f = m->formals; 93033965Sjdp while (f != NULL && f->index < 0) 93133965Sjdp f = f->next; 93233965Sjdp 93333965Sjdp if (macro_mri) 93433965Sjdp { 93533965Sjdp /* The macro may be called with an optional qualifier, which may 93633965Sjdp be referred to in the macro body as \0. */ 93733965Sjdp if (idx < in->len && in->ptr[idx] == '.') 93833965Sjdp { 93933965Sjdp formal_entry *n; 94033965Sjdp 94133965Sjdp n = (formal_entry *) xmalloc (sizeof (formal_entry)); 94233965Sjdp sb_new (&n->name); 94333965Sjdp sb_new (&n->def); 94433965Sjdp sb_new (&n->actual); 94533965Sjdp n->index = QUAL_INDEX; 94633965Sjdp 94733965Sjdp n->next = m->formals; 94833965Sjdp m->formals = n; 94933965Sjdp 95033965Sjdp idx = get_any_string (idx + 1, in, &n->actual, 1, 0); 95133965Sjdp } 95233965Sjdp } 95333965Sjdp 95433965Sjdp /* Peel off the actuals and store them away in the hash tables' actuals */ 95533965Sjdp idx = sb_skip_white (idx, in); 95633965Sjdp while (idx < in->len && in->ptr[idx] != comment_char) 95733965Sjdp { 95833965Sjdp int scan; 95933965Sjdp 96033965Sjdp /* Look and see if it's a positional or keyword arg */ 96133965Sjdp scan = idx; 96233965Sjdp while (scan < in->len 96333965Sjdp && !ISSEP (in->ptr[scan]) 96438889Sjdp && !(macro_mri && in->ptr[scan] == '\'') 96533965Sjdp && (!macro_alternate && in->ptr[scan] != '=')) 96633965Sjdp scan++; 96733965Sjdp if (scan < in->len && !macro_alternate && in->ptr[scan] == '=') 96833965Sjdp { 96933965Sjdp is_keyword = 1; 97033965Sjdp 97138889Sjdp /* It's OK to go from positional to keyword. */ 97238889Sjdp 97333965Sjdp /* This is a keyword arg, fetch the formal name and 97433965Sjdp then the actual stuff */ 97533965Sjdp sb_reset (&t); 97633965Sjdp idx = get_token (idx, in, &t); 97733965Sjdp if (in->ptr[idx] != '=') 97833965Sjdp return "confusion in formal parameters"; 97933965Sjdp 98033965Sjdp /* Lookup the formal in the macro's list */ 98133965Sjdp ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); 98233965Sjdp if (!ptr) 98333965Sjdp return "macro formal argument does not exist"; 98433965Sjdp else 98533965Sjdp { 98633965Sjdp /* Insert this value into the right place */ 98733965Sjdp sb_reset (&ptr->actual); 98833965Sjdp idx = get_any_string (idx + 1, in, &ptr->actual, 0, 0); 98933965Sjdp if (ptr->actual.len > 0) 99033965Sjdp ++narg; 99133965Sjdp } 99233965Sjdp } 99333965Sjdp else 99433965Sjdp { 99533965Sjdp /* This is a positional arg */ 99633965Sjdp is_positional = 1; 99733965Sjdp if (is_keyword) 99833965Sjdp return "can't mix positional and keyword arguments"; 99933965Sjdp 100033965Sjdp if (!f) 100133965Sjdp { 100233965Sjdp formal_entry **pf; 100333965Sjdp int c; 100433965Sjdp 100533965Sjdp if (!macro_mri) 100633965Sjdp return "too many positional arguments"; 100733965Sjdp 100833965Sjdp f = (formal_entry *) xmalloc (sizeof (formal_entry)); 100933965Sjdp sb_new (&f->name); 101033965Sjdp sb_new (&f->def); 101133965Sjdp sb_new (&f->actual); 101233965Sjdp f->next = NULL; 101333965Sjdp 101433965Sjdp c = -1; 101533965Sjdp for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) 101633965Sjdp if ((*pf)->index >= c) 101733965Sjdp c = (*pf)->index + 1; 101833965Sjdp if (c == -1) 101933965Sjdp c = 0; 102033965Sjdp *pf = f; 102133965Sjdp f->index = c; 102233965Sjdp } 102333965Sjdp 102433965Sjdp sb_reset (&f->actual); 102533965Sjdp idx = get_any_string (idx, in, &f->actual, 1, 0); 102633965Sjdp if (f->actual.len > 0) 102733965Sjdp ++narg; 102833965Sjdp do 102933965Sjdp { 103033965Sjdp f = f->next; 103133965Sjdp } 103233965Sjdp while (f != NULL && f->index < 0); 103333965Sjdp } 103433965Sjdp 103533965Sjdp if (! macro_mri) 103633965Sjdp idx = sb_skip_comma (idx, in); 103733965Sjdp else 103833965Sjdp { 103933965Sjdp if (in->ptr[idx] == ',') 104033965Sjdp ++idx; 104133965Sjdp if (ISWHITE (in->ptr[idx])) 104233965Sjdp break; 104333965Sjdp } 104433965Sjdp } 104533965Sjdp 104633965Sjdp if (macro_mri) 104733965Sjdp { 104833965Sjdp char buffer[20]; 104933965Sjdp 105033965Sjdp sb_reset (&t); 105133965Sjdp sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG"); 105233965Sjdp ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); 105333965Sjdp sb_reset (&ptr->actual); 105433965Sjdp sprintf (buffer, "%d", narg); 105533965Sjdp sb_add_string (&ptr->actual, buffer); 105633965Sjdp } 105733965Sjdp 105833965Sjdp err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, 105933965Sjdp comment_char, 1); 106033965Sjdp if (err != NULL) 106133965Sjdp return err; 106233965Sjdp 106333965Sjdp /* Discard any unnamed formal arguments. */ 106433965Sjdp if (macro_mri) 106533965Sjdp { 106633965Sjdp formal_entry **pf; 106733965Sjdp 106833965Sjdp pf = &m->formals; 106933965Sjdp while (*pf != NULL) 107033965Sjdp { 107133965Sjdp if ((*pf)->name.len != 0) 107233965Sjdp pf = &(*pf)->next; 107333965Sjdp else 107433965Sjdp { 107533965Sjdp sb_kill (&(*pf)->name); 107633965Sjdp sb_kill (&(*pf)->def); 107733965Sjdp sb_kill (&(*pf)->actual); 107833965Sjdp f = (*pf)->next; 107933965Sjdp free (*pf); 108033965Sjdp *pf = f; 108133965Sjdp } 108233965Sjdp } 108333965Sjdp } 108433965Sjdp 108533965Sjdp sb_kill (&t); 108633965Sjdp macro_number++; 108733965Sjdp 108833965Sjdp return NULL; 108933965Sjdp} 109033965Sjdp 109133965Sjdp/* Check for a macro. If one is found, put the expansion into 109233965Sjdp *EXPAND. COMMENT_CHAR is the comment character--this is used by 109333965Sjdp gasp. Return 1 if a macro is found, 0 otherwise. */ 109433965Sjdp 109533965Sjdpint 109633965Sjdpcheck_macro (line, expand, comment_char, error) 109733965Sjdp const char *line; 109833965Sjdp sb *expand; 109933965Sjdp int comment_char; 110033965Sjdp const char **error; 110133965Sjdp{ 110233965Sjdp const char *s; 110333965Sjdp char *copy, *cs; 110433965Sjdp macro_entry *macro; 110533965Sjdp sb line_sb; 110633965Sjdp 110733965Sjdp if (! isalpha ((unsigned char) *line) 110833965Sjdp && *line != '_' 110933965Sjdp && *line != '$' 111033965Sjdp && (! macro_mri || *line != '.')) 111133965Sjdp return 0; 111233965Sjdp 111333965Sjdp s = line + 1; 111433965Sjdp while (isalnum ((unsigned char) *s) 111533965Sjdp || *s == '_' 111633965Sjdp || *s == '$') 111733965Sjdp ++s; 111833965Sjdp 111938889Sjdp copy = (char *) alloca (s - line + 1); 112033965Sjdp memcpy (copy, line, s - line); 112133965Sjdp copy[s - line] = '\0'; 112233965Sjdp for (cs = copy; *cs != '\0'; cs++) 112338889Sjdp if (isupper ((unsigned char) *cs)) 112433965Sjdp *cs = tolower (*cs); 112533965Sjdp 112633965Sjdp macro = (macro_entry *) hash_find (macro_hash, copy); 112733965Sjdp 112833965Sjdp if (macro == NULL) 112933965Sjdp return 0; 113033965Sjdp 113133965Sjdp /* Wrap the line up in an sb. */ 113233965Sjdp sb_new (&line_sb); 113333965Sjdp while (*s != '\0' && *s != '\n' && *s != '\r') 113433965Sjdp sb_add_char (&line_sb, *s++); 113533965Sjdp 113633965Sjdp sb_new (expand); 113733965Sjdp *error = macro_expand (0, &line_sb, macro, expand, comment_char); 113833965Sjdp 113933965Sjdp sb_kill (&line_sb); 114033965Sjdp 114133965Sjdp return 1; 114233965Sjdp} 114333965Sjdp 114433965Sjdp/* Delete a macro. */ 114533965Sjdp 114633965Sjdpvoid 114733965Sjdpdelete_macro (name) 114833965Sjdp const char *name; 114933965Sjdp{ 115033965Sjdp hash_delete (macro_hash, name); 115133965Sjdp} 115233965Sjdp 115333965Sjdp/* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a 115433965Sjdp combined macro definition and execution. This returns NULL on 115533965Sjdp success, or an error message otherwise. */ 115633965Sjdp 115733965Sjdpconst char * 115833965Sjdpexpand_irp (irpc, idx, in, out, get_line, comment_char) 115933965Sjdp int irpc; 116033965Sjdp int idx; 116133965Sjdp sb *in; 116233965Sjdp sb *out; 116333965Sjdp int (*get_line) PARAMS ((sb *)); 116433965Sjdp int comment_char; 116533965Sjdp{ 116633965Sjdp const char *mn; 116733965Sjdp sb sub; 116833965Sjdp formal_entry f; 116933965Sjdp struct hash_control *h; 117033965Sjdp const char *err; 117133965Sjdp 117233965Sjdp if (irpc) 117333965Sjdp mn = "IRPC"; 117433965Sjdp else 117533965Sjdp mn = "IRP"; 117633965Sjdp 117733965Sjdp idx = sb_skip_white (idx, in); 117833965Sjdp 117933965Sjdp sb_new (&sub); 118033965Sjdp if (! buffer_and_nest (mn, "ENDR", &sub, get_line)) 118133965Sjdp return "unexpected end of file in irp or irpc"; 118233965Sjdp 118333965Sjdp sb_new (&f.name); 118433965Sjdp sb_new (&f.def); 118533965Sjdp sb_new (&f.actual); 118633965Sjdp 118733965Sjdp idx = get_token (idx, in, &f.name); 118833965Sjdp if (f.name.len == 0) 118933965Sjdp return "missing model parameter"; 119033965Sjdp 119133965Sjdp h = hash_new (); 119233965Sjdp err = hash_jam (h, sb_terminate (&f.name), &f); 119333965Sjdp if (err != NULL) 119433965Sjdp return err; 119533965Sjdp 119633965Sjdp f.index = 1; 119733965Sjdp f.next = NULL; 119833965Sjdp 119933965Sjdp sb_reset (out); 120033965Sjdp 120133965Sjdp idx = sb_skip_comma (idx, in); 120233965Sjdp if (idx >= in->len || in->ptr[idx] == comment_char) 120333965Sjdp { 120433965Sjdp /* Expand once with a null string. */ 120533965Sjdp err = macro_expand_body (&sub, out, &f, h, comment_char, 0); 120633965Sjdp if (err != NULL) 120733965Sjdp return err; 120833965Sjdp } 120933965Sjdp else 121033965Sjdp { 121133965Sjdp if (irpc && in->ptr[idx] == '"') 121233965Sjdp ++idx; 121333965Sjdp while (idx < in->len && in->ptr[idx] != comment_char) 121433965Sjdp { 121533965Sjdp if (!irpc) 121633965Sjdp idx = get_any_string (idx, in, &f.actual, 1, 0); 121733965Sjdp else 121833965Sjdp { 121933965Sjdp if (in->ptr[idx] == '"') 122033965Sjdp { 122133965Sjdp int nxt; 122233965Sjdp 122333965Sjdp nxt = sb_skip_white (idx + 1, in); 122433965Sjdp if (nxt >= in->len || in->ptr[nxt] == comment_char) 122533965Sjdp { 122633965Sjdp idx = nxt; 122733965Sjdp break; 122833965Sjdp } 122933965Sjdp } 123033965Sjdp sb_reset (&f.actual); 123133965Sjdp sb_add_char (&f.actual, in->ptr[idx]); 123233965Sjdp ++idx; 123333965Sjdp } 123433965Sjdp err = macro_expand_body (&sub, out, &f, h, comment_char, 0); 123533965Sjdp if (err != NULL) 123633965Sjdp return err; 123733965Sjdp if (!irpc) 123833965Sjdp idx = sb_skip_comma (idx, in); 123933965Sjdp else 124033965Sjdp idx = sb_skip_white (idx, in); 124133965Sjdp } 124233965Sjdp } 124333965Sjdp 124433965Sjdp hash_die (h); 124533965Sjdp sb_kill (&sub); 124633965Sjdp 124733965Sjdp return NULL; 124833965Sjdp} 1249