1130561Sobrien/* macro.c - macro support for gas 2218822Sdim Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 3218822Sdim 2004, 2005, 2006 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 22218822Sdim Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 23218822Sdim 02110-1301, USA. */ 2433965Sjdp 25218822Sdim#include "as.h" 2689857Sobrien#include "safe-ctype.h" 2733965Sjdp#include "sb.h" 2833965Sjdp#include "macro.h" 2933965Sjdp 3033965Sjdp/* The routines in this file handle macro definition and expansion. 31130561Sobrien They are called by gas. */ 3233965Sjdp 3333965Sjdp/* Internal functions. */ 3433965Sjdp 35130561Sobrienstatic int get_token (int, sb *, sb *); 36130561Sobrienstatic int getstring (int, sb *, sb *); 37218822Sdimstatic int get_any_string (int, sb *, sb *); 38218822Sdimstatic formal_entry *new_formal (void); 39218822Sdimstatic void del_formal (formal_entry *); 40130561Sobrienstatic int do_formals (macro_entry *, int, sb *); 41130561Sobrienstatic int get_apost_token (int, sb *, sb *, int); 42130561Sobrienstatic int sub_actual (int, sb *, sb *, struct hash_control *, int, sb *, int); 4333965Sjdpstatic const char *macro_expand_body 44218822Sdim (sb *, sb *, formal_entry *, struct hash_control *, const macro_entry *); 45130561Sobrienstatic const char *macro_expand (int, sb *, macro_entry *, sb *); 46218822Sdimstatic void free_macro(macro_entry *); 4733965Sjdp 4833965Sjdp#define ISWHITE(x) ((x) == ' ' || (x) == '\t') 4933965Sjdp 5033965Sjdp#define ISSEP(x) \ 5133965Sjdp ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \ 5238889Sjdp || (x) == ')' || (x) == '(' \ 5338889Sjdp || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>'))) 5433965Sjdp 5533965Sjdp#define ISBASE(x) \ 5633965Sjdp ((x) == 'b' || (x) == 'B' \ 5733965Sjdp || (x) == 'q' || (x) == 'Q' \ 5833965Sjdp || (x) == 'h' || (x) == 'H' \ 5933965Sjdp || (x) == 'd' || (x) == 'D') 6033965Sjdp 6133965Sjdp/* The macro hash table. */ 6233965Sjdp 63130561Sobrienstruct hash_control *macro_hash; 6433965Sjdp 6533965Sjdp/* Whether any macros have been defined. */ 6633965Sjdp 6733965Sjdpint macro_defined; 6833965Sjdp 69130561Sobrien/* Whether we are in alternate syntax mode. */ 7033965Sjdp 7133965Sjdpstatic int macro_alternate; 7233965Sjdp 7333965Sjdp/* Whether we are in MRI mode. */ 7433965Sjdp 7533965Sjdpstatic int macro_mri; 7633965Sjdp 7733965Sjdp/* Whether we should strip '@' characters. */ 7833965Sjdp 7933965Sjdpstatic int macro_strip_at; 8033965Sjdp 8133965Sjdp/* Function to use to parse an expression. */ 8233965Sjdp 83130561Sobrienstatic int (*macro_expr) (const char *, int, sb *, int *); 8433965Sjdp 8533965Sjdp/* Number of macro expansions that have been done. */ 8633965Sjdp 8733965Sjdpstatic int macro_number; 8833965Sjdp 8933965Sjdp/* Initialize macro processing. */ 9033965Sjdp 9133965Sjdpvoid 92130561Sobrienmacro_init (int alternate, int mri, int strip_at, 93130561Sobrien int (*expr) (const char *, int, sb *, int *)) 9433965Sjdp{ 9533965Sjdp macro_hash = hash_new (); 9633965Sjdp macro_defined = 0; 9733965Sjdp macro_alternate = alternate; 9833965Sjdp macro_mri = mri; 9933965Sjdp macro_strip_at = strip_at; 10033965Sjdp macro_expr = expr; 10133965Sjdp} 10233965Sjdp 103218822Sdim/* Switch in and out of alternate mode on the fly. */ 104218822Sdim 105218822Sdimvoid 106218822Sdimmacro_set_alternate (int alternate) 107218822Sdim{ 108218822Sdim macro_alternate = alternate; 109218822Sdim} 110218822Sdim 11160484Sobrien/* Switch in and out of MRI mode on the fly. */ 11260484Sobrien 11360484Sobrienvoid 114130561Sobrienmacro_mri_mode (int mri) 11560484Sobrien{ 11660484Sobrien macro_mri = mri; 11760484Sobrien} 11860484Sobrien 11933965Sjdp/* Read input lines till we get to a TO string. 12033965Sjdp Increase nesting depth if we get a FROM string. 12133965Sjdp Put the results into sb at PTR. 122218822Sdim FROM may be NULL (or will be ignored) if TO is "ENDR". 12333965Sjdp Add a new input line to an sb using GET_LINE. 12433965Sjdp Return 1 on success, 0 on unexpected EOF. */ 12533965Sjdp 12633965Sjdpint 127130561Sobrienbuffer_and_nest (const char *from, const char *to, sb *ptr, 128130561Sobrien int (*get_line) (sb *)) 12933965Sjdp{ 130218822Sdim int from_len; 13133965Sjdp int to_len = strlen (to); 13233965Sjdp int depth = 1; 13333965Sjdp int line_start = ptr->len; 13433965Sjdp 13533965Sjdp int more = get_line (ptr); 13633965Sjdp 137218822Sdim if (to_len == 4 && strcasecmp(to, "ENDR") == 0) 138218822Sdim { 139218822Sdim from = NULL; 140218822Sdim from_len = 0; 141218822Sdim } 142218822Sdim else 143218822Sdim from_len = strlen (from); 144218822Sdim 14533965Sjdp while (more) 14633965Sjdp { 147218822Sdim /* Try to find the first pseudo op on the line. */ 14833965Sjdp int i = line_start; 14933965Sjdp 150218822Sdim /* With normal syntax we can suck what we want till we get 151218822Sdim to the dot. With the alternate, labels have to start in 152218822Sdim the first column, since we can't tell what's a label and 153218822Sdim what's a pseudoop. */ 154218822Sdim 155218822Sdim if (! LABELS_WITHOUT_COLONS) 15633965Sjdp { 15777298Sobrien /* Skip leading whitespace. */ 15833965Sjdp while (i < ptr->len && ISWHITE (ptr->ptr[i])) 15933965Sjdp i++; 160218822Sdim } 16133965Sjdp 162218822Sdim for (;;) 163218822Sdim { 164218822Sdim /* Skip over a label, if any. */ 165218822Sdim if (i >= ptr->len || ! is_name_beginner (ptr->ptr[i])) 166218822Sdim break; 167218822Sdim i++; 168218822Sdim while (i < ptr->len && is_part_of_name (ptr->ptr[i])) 16933965Sjdp i++; 170218822Sdim if (i < ptr->len && is_name_ender (ptr->ptr[i])) 17133965Sjdp i++; 172218822Sdim if (LABELS_WITHOUT_COLONS) 173218822Sdim break; 174218822Sdim /* Skip whitespace. */ 175218822Sdim while (i < ptr->len && ISWHITE (ptr->ptr[i])) 176218822Sdim i++; 177218822Sdim /* Check for the colon. */ 178218822Sdim if (i >= ptr->len || ptr->ptr[i] != ':') 179218822Sdim { 180218822Sdim i = line_start; 181218822Sdim break; 182218822Sdim } 183218822Sdim i++; 184218822Sdim line_start = i; 185218822Sdim } 18633965Sjdp 18777298Sobrien /* Skip trailing whitespace. */ 18833965Sjdp while (i < ptr->len && ISWHITE (ptr->ptr[i])) 18933965Sjdp i++; 19033965Sjdp 19133965Sjdp if (i < ptr->len && (ptr->ptr[i] == '.' 192218822Sdim || NO_PSEUDO_DOT 19333965Sjdp || macro_mri)) 19433965Sjdp { 195218822Sdim if (! flag_m68k_mri && ptr->ptr[i] == '.') 19677298Sobrien i++; 197218822Sdim if (from == NULL 198218822Sdim && strncasecmp (ptr->ptr + i, "IRPC", from_len = 4) != 0 199218822Sdim && strncasecmp (ptr->ptr + i, "IRP", from_len = 3) != 0 200218822Sdim && strncasecmp (ptr->ptr + i, "IREPC", from_len = 5) != 0 201218822Sdim && strncasecmp (ptr->ptr + i, "IREP", from_len = 4) != 0 202218822Sdim && strncasecmp (ptr->ptr + i, "REPT", from_len = 4) != 0 203218822Sdim && strncasecmp (ptr->ptr + i, "REP", from_len = 3) != 0) 204218822Sdim from_len = 0; 205218822Sdim if ((from != NULL 206218822Sdim ? strncasecmp (ptr->ptr + i, from, from_len) == 0 207218822Sdim : from_len > 0) 20877298Sobrien && (ptr->len == (i + from_len) 209218822Sdim || ! (is_part_of_name (ptr->ptr[i + from_len]) 210218822Sdim || is_name_ender (ptr->ptr[i + from_len])))) 21133965Sjdp depth++; 21260484Sobrien if (strncasecmp (ptr->ptr + i, to, to_len) == 0 21377298Sobrien && (ptr->len == (i + to_len) 214218822Sdim || ! (is_part_of_name (ptr->ptr[i + to_len]) 215218822Sdim || is_name_ender (ptr->ptr[i + to_len])))) 21633965Sjdp { 21733965Sjdp depth--; 21833965Sjdp if (depth == 0) 21933965Sjdp { 22077298Sobrien /* Reset the string to not include the ending rune. */ 22133965Sjdp ptr->len = line_start; 22233965Sjdp break; 22333965Sjdp } 22433965Sjdp } 22533965Sjdp } 22633965Sjdp 227130561Sobrien /* Add the original end-of-line char to the end and keep running. */ 228130561Sobrien sb_add_char (ptr, more); 22933965Sjdp line_start = ptr->len; 23033965Sjdp more = get_line (ptr); 23133965Sjdp } 23233965Sjdp 23333965Sjdp /* Return 1 on success, 0 on unexpected EOF. */ 23433965Sjdp return depth == 0; 23533965Sjdp} 23633965Sjdp 23733965Sjdp/* Pick up a token. */ 23833965Sjdp 23933965Sjdpstatic int 240130561Sobrienget_token (int idx, sb *in, sb *name) 24133965Sjdp{ 24233965Sjdp if (idx < in->len 243218822Sdim && is_name_beginner (in->ptr[idx])) 24433965Sjdp { 24533965Sjdp sb_add_char (name, in->ptr[idx++]); 24633965Sjdp while (idx < in->len 247218822Sdim && is_part_of_name (in->ptr[idx])) 24833965Sjdp { 24933965Sjdp sb_add_char (name, in->ptr[idx++]); 25033965Sjdp } 251218822Sdim if (idx < in->len 252218822Sdim && is_name_ender (in->ptr[idx])) 253218822Sdim { 254218822Sdim sb_add_char (name, in->ptr[idx++]); 255218822Sdim } 25633965Sjdp } 25777298Sobrien /* Ignore trailing &. */ 25833965Sjdp if (macro_alternate && idx < in->len && in->ptr[idx] == '&') 25933965Sjdp idx++; 26033965Sjdp return idx; 26133965Sjdp} 26233965Sjdp 26333965Sjdp/* Pick up a string. */ 26433965Sjdp 26533965Sjdpstatic int 266130561Sobriengetstring (int idx, sb *in, sb *acc) 26733965Sjdp{ 26833965Sjdp while (idx < in->len 26977298Sobrien && (in->ptr[idx] == '"' 27038889Sjdp || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) 27133965Sjdp || (in->ptr[idx] == '\'' && macro_alternate))) 27233965Sjdp { 27333965Sjdp if (in->ptr[idx] == '<') 27433965Sjdp { 27538889Sjdp int nest = 0; 27638889Sjdp idx++; 27738889Sjdp while ((in->ptr[idx] != '>' || nest) 27838889Sjdp && idx < in->len) 27933965Sjdp { 28038889Sjdp if (in->ptr[idx] == '!') 28133965Sjdp { 28277298Sobrien idx++; 28338889Sjdp sb_add_char (acc, in->ptr[idx++]); 28433965Sjdp } 28538889Sjdp else 28638889Sjdp { 28738889Sjdp if (in->ptr[idx] == '>') 28838889Sjdp nest--; 28938889Sjdp if (in->ptr[idx] == '<') 29038889Sjdp nest++; 29138889Sjdp sb_add_char (acc, in->ptr[idx++]); 29238889Sjdp } 29333965Sjdp } 29438889Sjdp idx++; 29533965Sjdp } 29633965Sjdp else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') 29733965Sjdp { 29833965Sjdp char tchar = in->ptr[idx]; 29977298Sobrien int escaped = 0; 30077298Sobrien 30133965Sjdp idx++; 30277298Sobrien 30333965Sjdp while (idx < in->len) 30433965Sjdp { 30577298Sobrien if (in->ptr[idx - 1] == '\\') 30677298Sobrien escaped ^= 1; 30777298Sobrien else 30877298Sobrien escaped = 0; 30977298Sobrien 31033965Sjdp if (macro_alternate && in->ptr[idx] == '!') 31133965Sjdp { 31277298Sobrien idx ++; 31377298Sobrien 31477298Sobrien sb_add_char (acc, in->ptr[idx]); 31577298Sobrien 31677298Sobrien idx ++; 31733965Sjdp } 31877298Sobrien else if (escaped && in->ptr[idx] == tchar) 31977298Sobrien { 32077298Sobrien sb_add_char (acc, tchar); 32177298Sobrien idx ++; 32277298Sobrien } 32333965Sjdp else 32433965Sjdp { 32533965Sjdp if (in->ptr[idx] == tchar) 32633965Sjdp { 32777298Sobrien idx ++; 32877298Sobrien 32933965Sjdp if (idx >= in->len || in->ptr[idx] != tchar) 33033965Sjdp break; 33133965Sjdp } 33277298Sobrien 33333965Sjdp sb_add_char (acc, in->ptr[idx]); 33477298Sobrien idx ++; 33533965Sjdp } 33633965Sjdp } 33733965Sjdp } 33833965Sjdp } 33977298Sobrien 34033965Sjdp return idx; 34133965Sjdp} 34233965Sjdp 34333965Sjdp/* Fetch string from the input stream, 34433965Sjdp rules: 34533965Sjdp 'Bxyx<whitespace> -> return 'Bxyza 346218822Sdim %<expr> -> return string of decimal value of <expr> 347218822Sdim "string" -> return string 348218822Sdim (string) -> return (string-including-whitespaces) 349218822Sdim xyx<whitespace> -> return xyz. */ 35033965Sjdp 35133965Sjdpstatic int 352218822Sdimget_any_string (int idx, sb *in, sb *out) 35333965Sjdp{ 35433965Sjdp sb_reset (out); 35533965Sjdp idx = sb_skip_white (idx, in); 35633965Sjdp 35733965Sjdp if (idx < in->len) 35833965Sjdp { 359130561Sobrien if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx])) 36033965Sjdp { 36133965Sjdp while (!ISSEP (in->ptr[idx])) 36233965Sjdp sb_add_char (out, in->ptr[idx++]); 36333965Sjdp } 364218822Sdim else if (in->ptr[idx] == '%' && macro_alternate) 36533965Sjdp { 36633965Sjdp int val; 36733965Sjdp char buf[20]; 368218822Sdim 36977298Sobrien /* Turns the next expression into a string. */ 37089857Sobrien /* xgettext: no-c-format */ 37160484Sobrien idx = (*macro_expr) (_("% operator needs absolute expression"), 37233965Sjdp idx + 1, 37333965Sjdp in, 37433965Sjdp &val); 375104834Sobrien sprintf (buf, "%d", val); 37633965Sjdp sb_add_string (out, buf); 37733965Sjdp } 37833965Sjdp else if (in->ptr[idx] == '"' 37938889Sjdp || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) 38033965Sjdp || (macro_alternate && in->ptr[idx] == '\'')) 38133965Sjdp { 382218822Sdim if (macro_alternate && ! macro_strip_at && in->ptr[idx] != '<') 38333965Sjdp { 38477298Sobrien /* Keep the quotes. */ 385218822Sdim sb_add_char (out, '"'); 38633965Sjdp idx = getstring (idx, in, out); 387218822Sdim sb_add_char (out, '"'); 38833965Sjdp } 38933965Sjdp else 39033965Sjdp { 39133965Sjdp idx = getstring (idx, in, out); 39233965Sjdp } 39333965Sjdp } 39477298Sobrien else 39533965Sjdp { 396218822Sdim char *br_buf = xmalloc(1); 397218822Sdim char *in_br = br_buf; 398218822Sdim 399218822Sdim *in_br = '\0'; 40077298Sobrien while (idx < in->len 401218822Sdim && (*in_br 40233965Sjdp || (in->ptr[idx] != ' ' 403218822Sdim && in->ptr[idx] != '\t')) 404218822Sdim && in->ptr[idx] != ',' 405218822Sdim && (in->ptr[idx] != '<' 406218822Sdim || (! macro_alternate && ! macro_mri))) 40733965Sjdp { 408218822Sdim char tchar = in->ptr[idx]; 409218822Sdim 410218822Sdim switch (tchar) 41133965Sjdp { 412218822Sdim case '"': 413218822Sdim case '\'': 41433965Sjdp sb_add_char (out, in->ptr[idx++]); 41533965Sjdp while (idx < in->len 41633965Sjdp && in->ptr[idx] != tchar) 41777298Sobrien sb_add_char (out, in->ptr[idx++]); 41833965Sjdp if (idx == in->len) 41977298Sobrien return idx; 420218822Sdim break; 421218822Sdim case '(': 422218822Sdim case '[': 423218822Sdim if (in_br > br_buf) 424218822Sdim --in_br; 425218822Sdim else 426218822Sdim { 427218822Sdim br_buf = xmalloc(strlen(in_br) + 2); 428218822Sdim strcpy(br_buf + 1, in_br); 429218822Sdim free(in_br); 430218822Sdim in_br = br_buf; 431218822Sdim } 432218822Sdim *in_br = tchar; 433218822Sdim break; 434218822Sdim case ')': 435218822Sdim if (*in_br == '(') 436218822Sdim ++in_br; 437218822Sdim break; 438218822Sdim case ']': 439218822Sdim if (*in_br == '[') 440218822Sdim ++in_br; 441218822Sdim break; 44233965Sjdp } 443218822Sdim sb_add_char (out, tchar); 444218822Sdim ++idx; 44533965Sjdp } 446218822Sdim free(br_buf); 44733965Sjdp } 44833965Sjdp } 44933965Sjdp 45033965Sjdp return idx; 45133965Sjdp} 45233965Sjdp 453218822Sdim/* Allocate a new formal. */ 454218822Sdim 455218822Sdimstatic formal_entry * 456218822Sdimnew_formal (void) 457218822Sdim{ 458218822Sdim formal_entry *formal; 459218822Sdim 460218822Sdim formal = xmalloc (sizeof (formal_entry)); 461218822Sdim 462218822Sdim sb_new (&formal->name); 463218822Sdim sb_new (&formal->def); 464218822Sdim sb_new (&formal->actual); 465218822Sdim formal->next = NULL; 466218822Sdim formal->type = FORMAL_OPTIONAL; 467218822Sdim return formal; 468218822Sdim} 469218822Sdim 470218822Sdim/* Free a formal. */ 471218822Sdim 472218822Sdimstatic void 473218822Sdimdel_formal (formal_entry *formal) 474218822Sdim{ 475218822Sdim sb_kill (&formal->actual); 476218822Sdim sb_kill (&formal->def); 477218822Sdim sb_kill (&formal->name); 478218822Sdim free (formal); 479218822Sdim} 480218822Sdim 48133965Sjdp/* Pick up the formal parameters of a macro definition. */ 48233965Sjdp 48333965Sjdpstatic int 484130561Sobriendo_formals (macro_entry *macro, int idx, sb *in) 48533965Sjdp{ 48633965Sjdp formal_entry **p = ¯o->formals; 487218822Sdim const char *name; 48833965Sjdp 489218822Sdim idx = sb_skip_white (idx, in); 49033965Sjdp while (idx < in->len) 49133965Sjdp { 492218822Sdim formal_entry *formal = new_formal (); 493218822Sdim int cidx; 49433965Sjdp 49533965Sjdp idx = get_token (idx, in, &formal->name); 49633965Sjdp if (formal->name.len == 0) 497218822Sdim { 498218822Sdim if (macro->formal_count) 499218822Sdim --idx; 500218822Sdim break; 501218822Sdim } 50233965Sjdp idx = sb_skip_white (idx, in); 503218822Sdim /* This is a formal. */ 504218822Sdim name = sb_terminate (&formal->name); 505218822Sdim if (! macro_mri 506218822Sdim && idx < in->len 507218822Sdim && in->ptr[idx] == ':' 508218822Sdim && (! is_name_beginner (':') 509218822Sdim || idx + 1 >= in->len 510218822Sdim || ! is_part_of_name (in->ptr[idx + 1]))) 51133965Sjdp { 512218822Sdim /* Got a qualifier. */ 513218822Sdim sb qual; 514218822Sdim 515218822Sdim sb_new (&qual); 516218822Sdim idx = get_token (sb_skip_white (idx + 1, in), in, &qual); 517218822Sdim sb_terminate (&qual); 518218822Sdim if (qual.len == 0) 519218822Sdim as_bad_where (macro->file, 520218822Sdim macro->line, 521218822Sdim _("Missing parameter qualifier for `%s' in macro `%s'"), 522218822Sdim name, 523218822Sdim macro->name); 524218822Sdim else if (strcmp (qual.ptr, "req") == 0) 525218822Sdim formal->type = FORMAL_REQUIRED; 526218822Sdim else if (strcmp (qual.ptr, "vararg") == 0) 527218822Sdim formal->type = FORMAL_VARARG; 528218822Sdim else 529218822Sdim as_bad_where (macro->file, 530218822Sdim macro->line, 531218822Sdim _("`%s' is not a valid parameter qualifier for `%s' in macro `%s'"), 532218822Sdim qual.ptr, 533218822Sdim name, 534218822Sdim macro->name); 535218822Sdim sb_kill (&qual); 536218822Sdim idx = sb_skip_white (idx, in); 537218822Sdim } 538218822Sdim if (idx < in->len && in->ptr[idx] == '=') 539218822Sdim { 540218822Sdim /* Got a default. */ 541218822Sdim idx = get_any_string (idx + 1, in, &formal->def); 542218822Sdim idx = sb_skip_white (idx, in); 543218822Sdim if (formal->type == FORMAL_REQUIRED) 54433965Sjdp { 545218822Sdim sb_reset (&formal->def); 546218822Sdim as_warn_where (macro->file, 547218822Sdim macro->line, 548218822Sdim _("Pointless default value for required parameter `%s' in macro `%s'"), 549218822Sdim name, 550218822Sdim macro->name); 55133965Sjdp } 55233965Sjdp } 55333965Sjdp 55477298Sobrien /* Add to macro's hash table. */ 555218822Sdim if (! hash_find (macro->formal_hash, name)) 556218822Sdim hash_jam (macro->formal_hash, name, formal); 557218822Sdim else 558218822Sdim as_bad_where (macro->file, 559218822Sdim macro->line, 560218822Sdim _("A parameter named `%s' already exists for macro `%s'"), 561218822Sdim name, 562218822Sdim macro->name); 56333965Sjdp 564218822Sdim formal->index = macro->formal_count++; 56533965Sjdp *p = formal; 56633965Sjdp p = &formal->next; 567218822Sdim if (formal->type == FORMAL_VARARG) 568218822Sdim break; 569218822Sdim cidx = idx; 570218822Sdim idx = sb_skip_comma (idx, in); 571218822Sdim if (idx != cidx && idx >= in->len) 572218822Sdim { 573218822Sdim idx = cidx; 574218822Sdim break; 575218822Sdim } 57633965Sjdp } 57733965Sjdp 57833965Sjdp if (macro_mri) 57933965Sjdp { 580218822Sdim formal_entry *formal = new_formal (); 58133965Sjdp 58233965Sjdp /* Add a special NARG formal, which macro_expand will set to the 58333965Sjdp number of arguments. */ 58433965Sjdp /* The same MRI assemblers which treat '@' characters also use 58533965Sjdp the name $NARG. At least until we find an exception. */ 58633965Sjdp if (macro_strip_at) 58733965Sjdp name = "$NARG"; 58833965Sjdp else 58933965Sjdp name = "NARG"; 59033965Sjdp 59133965Sjdp sb_add_string (&formal->name, name); 59233965Sjdp 59377298Sobrien /* Add to macro's hash table. */ 594218822Sdim if (hash_find (macro->formal_hash, name)) 595218822Sdim as_bad_where (macro->file, 596218822Sdim macro->line, 597218822Sdim _("Reserved word `%s' used as parameter in macro `%s'"), 598218822Sdim name, 599218822Sdim macro->name); 60033965Sjdp hash_jam (macro->formal_hash, name, formal); 60133965Sjdp 60233965Sjdp formal->index = NARG_INDEX; 60333965Sjdp *p = formal; 60433965Sjdp } 60533965Sjdp 60633965Sjdp return idx; 60733965Sjdp} 60833965Sjdp 60933965Sjdp/* Define a new macro. Returns NULL on success, otherwise returns an 61033965Sjdp error message. If NAMEP is not NULL, *NAMEP is set to the name of 61133965Sjdp the macro which was defined. */ 61233965Sjdp 61333965Sjdpconst char * 614130561Sobriendefine_macro (int idx, sb *in, sb *label, 615218822Sdim int (*get_line) (sb *), 616218822Sdim char *file, unsigned int line, 617218822Sdim const char **namep) 61833965Sjdp{ 61933965Sjdp macro_entry *macro; 62033965Sjdp sb name; 621218822Sdim const char *error = NULL; 62233965Sjdp 62333965Sjdp macro = (macro_entry *) xmalloc (sizeof (macro_entry)); 62433965Sjdp sb_new (¯o->sub); 62533965Sjdp sb_new (&name); 626218822Sdim macro->file = file; 627218822Sdim macro->line = line; 62833965Sjdp 62933965Sjdp macro->formal_count = 0; 63033965Sjdp macro->formals = 0; 631218822Sdim macro->formal_hash = hash_new (); 63233965Sjdp 63333965Sjdp idx = sb_skip_white (idx, in); 63433965Sjdp if (! buffer_and_nest ("MACRO", "ENDM", ¯o->sub, get_line)) 635218822Sdim error = _("unexpected end of file in macro `%s' definition"); 63633965Sjdp if (label != NULL && label->len != 0) 63733965Sjdp { 63833965Sjdp sb_add_sb (&name, label); 639218822Sdim macro->name = sb_terminate (&name); 64038889Sjdp if (idx < in->len && in->ptr[idx] == '(') 64133965Sjdp { 64277298Sobrien /* It's the label: MACRO (formals,...) sort */ 64333965Sjdp idx = do_formals (macro, idx + 1, in); 644218822Sdim if (idx < in->len && in->ptr[idx] == ')') 645218822Sdim idx = sb_skip_white (idx + 1, in); 646218822Sdim else if (!error) 647218822Sdim error = _("missing `)' after formals in macro definition `%s'"); 64833965Sjdp } 64933965Sjdp else 65033965Sjdp { 65177298Sobrien /* It's the label: MACRO formals,... sort */ 65233965Sjdp idx = do_formals (macro, idx, in); 65333965Sjdp } 65433965Sjdp } 65533965Sjdp else 65633965Sjdp { 657218822Sdim int cidx; 658218822Sdim 65933965Sjdp idx = get_token (idx, in, &name); 660218822Sdim macro->name = sb_terminate (&name); 661218822Sdim if (name.len == 0) 662218822Sdim error = _("Missing macro name"); 663218822Sdim cidx = sb_skip_white (idx, in); 664218822Sdim idx = sb_skip_comma (cidx, in); 665218822Sdim if (idx == cidx || idx < in->len) 666218822Sdim idx = do_formals (macro, idx, in); 667218822Sdim else 668218822Sdim idx = cidx; 66933965Sjdp } 670218822Sdim if (!error && idx < in->len) 671218822Sdim error = _("Bad parameter list for macro `%s'"); 67233965Sjdp 67377298Sobrien /* And stick it in the macro hash table. */ 67433965Sjdp for (idx = 0; idx < name.len; idx++) 67589857Sobrien name.ptr[idx] = TOLOWER (name.ptr[idx]); 676218822Sdim if (hash_find (macro_hash, macro->name)) 677218822Sdim error = _("Macro `%s' was already defined"); 678218822Sdim if (!error) 679218822Sdim error = hash_jam (macro_hash, macro->name, (PTR) macro); 68033965Sjdp 68133965Sjdp if (namep != NULL) 682218822Sdim *namep = macro->name; 68333965Sjdp 684218822Sdim if (!error) 685218822Sdim macro_defined = 1; 686218822Sdim else 687218822Sdim free_macro (macro); 688218822Sdim 689218822Sdim return error; 69033965Sjdp} 69133965Sjdp 69233965Sjdp/* Scan a token, and then skip KIND. */ 69333965Sjdp 69433965Sjdpstatic int 695130561Sobrienget_apost_token (int idx, sb *in, sb *name, int kind) 69633965Sjdp{ 69733965Sjdp idx = get_token (idx, in, name); 69833965Sjdp if (idx < in->len 69933965Sjdp && in->ptr[idx] == kind 70033965Sjdp && (! macro_mri || macro_strip_at) 70133965Sjdp && (! macro_strip_at || kind == '@')) 70233965Sjdp idx++; 70333965Sjdp return idx; 70433965Sjdp} 70533965Sjdp 70633965Sjdp/* Substitute the actual value for a formal parameter. */ 70733965Sjdp 70833965Sjdpstatic int 709130561Sobriensub_actual (int start, sb *in, sb *t, struct hash_control *formal_hash, 710130561Sobrien int kind, sb *out, int copyifnotthere) 71133965Sjdp{ 71233965Sjdp int src; 71333965Sjdp formal_entry *ptr; 71433965Sjdp 71533965Sjdp src = get_apost_token (start, in, t, kind); 71633965Sjdp /* See if it's in the macro's hash table, unless this is 71733965Sjdp macro_strip_at and kind is '@' and the token did not end in '@'. */ 71833965Sjdp if (macro_strip_at 71933965Sjdp && kind == '@' 72033965Sjdp && (src == start || in->ptr[src - 1] != '@')) 72133965Sjdp ptr = NULL; 72233965Sjdp else 72333965Sjdp ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t)); 72433965Sjdp if (ptr) 72533965Sjdp { 72633965Sjdp if (ptr->actual.len) 72733965Sjdp { 72833965Sjdp sb_add_sb (out, &ptr->actual); 72933965Sjdp } 73033965Sjdp else 73133965Sjdp { 73233965Sjdp sb_add_sb (out, &ptr->def); 73333965Sjdp } 73433965Sjdp } 73538889Sjdp else if (kind == '&') 73638889Sjdp { 73738889Sjdp /* Doing this permits people to use & in macro bodies. */ 73838889Sjdp sb_add_char (out, '&'); 739130561Sobrien sb_add_sb (out, t); 74038889Sjdp } 74133965Sjdp else if (copyifnotthere) 74233965Sjdp { 74333965Sjdp sb_add_sb (out, t); 74433965Sjdp } 74577298Sobrien else 74633965Sjdp { 74733965Sjdp sb_add_char (out, '\\'); 74833965Sjdp sb_add_sb (out, t); 74933965Sjdp } 75033965Sjdp return src; 75133965Sjdp} 75233965Sjdp 75333965Sjdp/* Expand the body of a macro. */ 75433965Sjdp 75533965Sjdpstatic const char * 756130561Sobrienmacro_expand_body (sb *in, sb *out, formal_entry *formals, 757218822Sdim struct hash_control *formal_hash, const macro_entry *macro) 75833965Sjdp{ 75933965Sjdp sb t; 760218822Sdim int src = 0, inquote = 0, macro_line = 0; 76133965Sjdp formal_entry *loclist = NULL; 762218822Sdim const char *err = NULL; 76333965Sjdp 76433965Sjdp sb_new (&t); 76533965Sjdp 766218822Sdim while (src < in->len && !err) 76733965Sjdp { 76833965Sjdp if (in->ptr[src] == '&') 76933965Sjdp { 77033965Sjdp sb_reset (&t); 77133965Sjdp if (macro_mri) 77233965Sjdp { 77333965Sjdp if (src + 1 < in->len && in->ptr[src + 1] == '&') 77433965Sjdp src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1); 77533965Sjdp else 77633965Sjdp sb_add_char (out, in->ptr[src++]); 77733965Sjdp } 77833965Sjdp else 77933965Sjdp { 78038889Sjdp /* FIXME: Why do we do this? */ 781218822Sdim /* At least in alternate mode this seems correct; without this 782218822Sdim one can't append a literal to a parameter. */ 78333965Sjdp src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0); 78433965Sjdp } 78533965Sjdp } 78633965Sjdp else if (in->ptr[src] == '\\') 78733965Sjdp { 78833965Sjdp src++; 789218822Sdim if (src < in->len && in->ptr[src] == '(') 79033965Sjdp { 79177298Sobrien /* Sub in till the next ')' literally. */ 79233965Sjdp src++; 79333965Sjdp while (src < in->len && in->ptr[src] != ')') 79433965Sjdp { 79533965Sjdp sb_add_char (out, in->ptr[src++]); 79633965Sjdp } 797218822Sdim if (src < in->len) 79833965Sjdp src++; 799218822Sdim else if (!macro) 800218822Sdim err = _("missing `)'"); 80133965Sjdp else 802218822Sdim as_bad_where (macro->file, macro->line + macro_line, _("missing `)'")); 80333965Sjdp } 804218822Sdim else if (src < in->len && in->ptr[src] == '@') 80533965Sjdp { 80677298Sobrien /* Sub in the macro invocation number. */ 80733965Sjdp 80838889Sjdp char buffer[10]; 80933965Sjdp src++; 81077298Sobrien sprintf (buffer, "%d", macro_number); 81133965Sjdp sb_add_string (out, buffer); 81233965Sjdp } 813218822Sdim else if (src < in->len && in->ptr[src] == '&') 81433965Sjdp { 81533965Sjdp /* This is a preprocessor variable name, we don't do them 81677298Sobrien here. */ 81733965Sjdp sb_add_char (out, '\\'); 81833965Sjdp sb_add_char (out, '&'); 81933965Sjdp src++; 82033965Sjdp } 821218822Sdim else if (macro_mri && src < in->len && ISALNUM (in->ptr[src])) 82233965Sjdp { 82333965Sjdp int ind; 82433965Sjdp formal_entry *f; 82533965Sjdp 82689857Sobrien if (ISDIGIT (in->ptr[src])) 82733965Sjdp ind = in->ptr[src] - '0'; 82889857Sobrien else if (ISUPPER (in->ptr[src])) 82933965Sjdp ind = in->ptr[src] - 'A' + 10; 83033965Sjdp else 83133965Sjdp ind = in->ptr[src] - 'a' + 10; 83233965Sjdp ++src; 83333965Sjdp for (f = formals; f != NULL; f = f->next) 83433965Sjdp { 83533965Sjdp if (f->index == ind - 1) 83633965Sjdp { 83733965Sjdp if (f->actual.len != 0) 83833965Sjdp sb_add_sb (out, &f->actual); 83933965Sjdp else 84033965Sjdp sb_add_sb (out, &f->def); 84133965Sjdp break; 84233965Sjdp } 84333965Sjdp } 84433965Sjdp } 84533965Sjdp else 84633965Sjdp { 84733965Sjdp sb_reset (&t); 84833965Sjdp src = sub_actual (src, in, &t, formal_hash, '\'', out, 0); 84933965Sjdp } 85033965Sjdp } 85133965Sjdp else if ((macro_alternate || macro_mri) 852218822Sdim && is_name_beginner (in->ptr[src]) 85333965Sjdp && (! inquote 85433965Sjdp || ! macro_strip_at 85533965Sjdp || (src > 0 && in->ptr[src - 1] == '@'))) 85633965Sjdp { 857218822Sdim if (! macro 85833965Sjdp || src + 5 >= in->len 85933965Sjdp || strncasecmp (in->ptr + src, "LOCAL", 5) != 0 86033965Sjdp || ! ISWHITE (in->ptr[src + 5])) 86133965Sjdp { 86233965Sjdp sb_reset (&t); 86333965Sjdp src = sub_actual (src, in, &t, formal_hash, 86433965Sjdp (macro_strip_at && inquote) ? '@' : '\'', 86533965Sjdp out, 1); 86633965Sjdp } 86733965Sjdp else 86833965Sjdp { 86933965Sjdp src = sb_skip_white (src + 5, in); 870130561Sobrien while (in->ptr[src] != '\n') 87133965Sjdp { 872218822Sdim const char *name; 873218822Sdim formal_entry *f = new_formal (); 87433965Sjdp 87533965Sjdp src = get_token (src, in, &f->name); 876218822Sdim name = sb_terminate (&f->name); 877218822Sdim if (! hash_find (formal_hash, name)) 878218822Sdim { 879218822Sdim static int loccnt; 880218822Sdim char buf[20]; 88133965Sjdp 882218822Sdim f->index = LOCAL_INDEX; 883218822Sdim f->next = loclist; 884218822Sdim loclist = f; 88533965Sjdp 886218822Sdim sprintf (buf, IS_ELF ? ".LL%04x" : "LL%04x", ++loccnt); 887218822Sdim sb_add_string (&f->actual, buf); 888218822Sdim 889218822Sdim err = hash_jam (formal_hash, name, f); 890218822Sdim if (err != NULL) 891218822Sdim break; 892218822Sdim } 893218822Sdim else 894218822Sdim { 895218822Sdim as_bad_where (macro->file, 896218822Sdim macro->line + macro_line, 897218822Sdim _("`%s' was already used as parameter (or another local) name"), 898218822Sdim name); 899218822Sdim del_formal (f); 900218822Sdim } 901218822Sdim 90233965Sjdp src = sb_skip_comma (src, in); 90333965Sjdp } 90433965Sjdp } 90533965Sjdp } 90633965Sjdp else if (in->ptr[src] == '"' 90733965Sjdp || (macro_mri && in->ptr[src] == '\'')) 90833965Sjdp { 90933965Sjdp inquote = !inquote; 91033965Sjdp sb_add_char (out, in->ptr[src++]); 91133965Sjdp } 91233965Sjdp else if (in->ptr[src] == '@' && macro_strip_at) 91333965Sjdp { 91433965Sjdp ++src; 91533965Sjdp if (src < in->len 91633965Sjdp && in->ptr[src] == '@') 91733965Sjdp { 91833965Sjdp sb_add_char (out, '@'); 91933965Sjdp ++src; 92033965Sjdp } 92133965Sjdp } 92233965Sjdp else if (macro_mri 92333965Sjdp && in->ptr[src] == '=' 92433965Sjdp && src + 1 < in->len 92533965Sjdp && in->ptr[src + 1] == '=') 92633965Sjdp { 92733965Sjdp formal_entry *ptr; 92833965Sjdp 92933965Sjdp sb_reset (&t); 93033965Sjdp src = get_token (src + 2, in, &t); 93133965Sjdp ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t)); 93233965Sjdp if (ptr == NULL) 93333965Sjdp { 93433965Sjdp /* FIXME: We should really return a warning string here, 93533965Sjdp but we can't, because the == might be in the MRI 93633965Sjdp comment field, and, since the nature of the MRI 93733965Sjdp comment field depends upon the exact instruction 93833965Sjdp being used, we don't have enough information here to 93933965Sjdp figure out whether it is or not. Instead, we leave 94033965Sjdp the == in place, which should cause a syntax error if 94133965Sjdp it is not in a comment. */ 94233965Sjdp sb_add_char (out, '='); 94333965Sjdp sb_add_char (out, '='); 94433965Sjdp sb_add_sb (out, &t); 94533965Sjdp } 94633965Sjdp else 94733965Sjdp { 94833965Sjdp if (ptr->actual.len) 94933965Sjdp { 95033965Sjdp sb_add_string (out, "-1"); 95133965Sjdp } 95233965Sjdp else 95333965Sjdp { 95433965Sjdp sb_add_char (out, '0'); 95533965Sjdp } 95633965Sjdp } 95733965Sjdp } 95833965Sjdp else 95933965Sjdp { 960218822Sdim if (in->ptr[src] == '\n') 961218822Sdim ++macro_line; 96233965Sjdp sb_add_char (out, in->ptr[src++]); 96333965Sjdp } 96433965Sjdp } 96533965Sjdp 96633965Sjdp sb_kill (&t); 96733965Sjdp 96833965Sjdp while (loclist != NULL) 96933965Sjdp { 97033965Sjdp formal_entry *f; 97133965Sjdp 97233965Sjdp f = loclist->next; 97360484Sobrien /* Setting the value to NULL effectively deletes the entry. We 97460484Sobrien avoid calling hash_delete because it doesn't reclaim memory. */ 97560484Sobrien hash_jam (formal_hash, sb_terminate (&loclist->name), NULL); 976218822Sdim del_formal (loclist); 97733965Sjdp loclist = f; 97833965Sjdp } 97933965Sjdp 980218822Sdim return err; 98133965Sjdp} 98233965Sjdp 98333965Sjdp/* Assign values to the formal parameters of a macro, and expand the 98433965Sjdp body. */ 98533965Sjdp 98633965Sjdpstatic const char * 987130561Sobrienmacro_expand (int idx, sb *in, macro_entry *m, sb *out) 98833965Sjdp{ 98933965Sjdp sb t; 99033965Sjdp formal_entry *ptr; 99133965Sjdp formal_entry *f; 99233965Sjdp int is_keyword = 0; 99333965Sjdp int narg = 0; 994218822Sdim const char *err = NULL; 99533965Sjdp 99633965Sjdp sb_new (&t); 99777298Sobrien 99877298Sobrien /* Reset any old value the actuals may have. */ 99933965Sjdp for (f = m->formals; f; f = f->next) 100077298Sobrien sb_reset (&f->actual); 100133965Sjdp f = m->formals; 100233965Sjdp while (f != NULL && f->index < 0) 100333965Sjdp f = f->next; 100433965Sjdp 100533965Sjdp if (macro_mri) 100633965Sjdp { 100733965Sjdp /* The macro may be called with an optional qualifier, which may 100833965Sjdp be referred to in the macro body as \0. */ 100933965Sjdp if (idx < in->len && in->ptr[idx] == '.') 1010104834Sobrien { 1011104834Sobrien /* The Microtec assembler ignores this if followed by a white space. 1012104834Sobrien (Macro invocation with empty extension) */ 1013104834Sobrien idx++; 1014104834Sobrien if ( idx < in->len 1015104834Sobrien && in->ptr[idx] != ' ' 1016104834Sobrien && in->ptr[idx] != '\t') 1017104834Sobrien { 1018218822Sdim formal_entry *n = new_formal (); 101933965Sjdp 1020104834Sobrien n->index = QUAL_INDEX; 102133965Sjdp 1022104834Sobrien n->next = m->formals; 1023104834Sobrien m->formals = n; 102433965Sjdp 1025218822Sdim idx = get_any_string (idx, in, &n->actual); 1026104834Sobrien } 1027104834Sobrien } 1028104834Sobrien } 102933965Sjdp 103077298Sobrien /* Peel off the actuals and store them away in the hash tables' actuals. */ 103133965Sjdp idx = sb_skip_white (idx, in); 1032130561Sobrien while (idx < in->len) 103333965Sjdp { 103433965Sjdp int scan; 103533965Sjdp 103677298Sobrien /* Look and see if it's a positional or keyword arg. */ 103733965Sjdp scan = idx; 103833965Sjdp while (scan < in->len 103933965Sjdp && !ISSEP (in->ptr[scan]) 104038889Sjdp && !(macro_mri && in->ptr[scan] == '\'') 104133965Sjdp && (!macro_alternate && in->ptr[scan] != '=')) 104233965Sjdp scan++; 104333965Sjdp if (scan < in->len && !macro_alternate && in->ptr[scan] == '=') 104433965Sjdp { 104533965Sjdp is_keyword = 1; 104633965Sjdp 104738889Sjdp /* It's OK to go from positional to keyword. */ 104838889Sjdp 104933965Sjdp /* This is a keyword arg, fetch the formal name and 105077298Sobrien then the actual stuff. */ 105133965Sjdp sb_reset (&t); 105233965Sjdp idx = get_token (idx, in, &t); 105333965Sjdp if (in->ptr[idx] != '=') 1054218822Sdim { 1055218822Sdim err = _("confusion in formal parameters"); 1056218822Sdim break; 1057218822Sdim } 105833965Sjdp 105977298Sobrien /* Lookup the formal in the macro's list. */ 106033965Sjdp ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); 106133965Sjdp if (!ptr) 1062218822Sdim as_bad (_("Parameter named `%s' does not exist for macro `%s'"), 1063218822Sdim t.ptr, 1064218822Sdim m->name); 106533965Sjdp else 106633965Sjdp { 106777298Sobrien /* Insert this value into the right place. */ 1068218822Sdim if (ptr->actual.len) 1069218822Sdim { 1070218822Sdim as_warn (_("Value for parameter `%s' of macro `%s' was already specified"), 1071218822Sdim ptr->name.ptr, 1072218822Sdim m->name); 1073218822Sdim sb_reset (&ptr->actual); 1074218822Sdim } 1075218822Sdim idx = get_any_string (idx + 1, in, &ptr->actual); 107633965Sjdp if (ptr->actual.len > 0) 107733965Sjdp ++narg; 107833965Sjdp } 107933965Sjdp } 108033965Sjdp else 108133965Sjdp { 108233965Sjdp if (is_keyword) 1083218822Sdim { 1084218822Sdim err = _("can't mix positional and keyword arguments"); 1085218822Sdim break; 1086218822Sdim } 108733965Sjdp 108833965Sjdp if (!f) 108933965Sjdp { 109033965Sjdp formal_entry **pf; 109133965Sjdp int c; 109233965Sjdp 109333965Sjdp if (!macro_mri) 1094218822Sdim { 1095218822Sdim err = _("too many positional arguments"); 1096218822Sdim break; 1097218822Sdim } 109833965Sjdp 1099218822Sdim f = new_formal (); 110033965Sjdp 110133965Sjdp c = -1; 110233965Sjdp for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) 110333965Sjdp if ((*pf)->index >= c) 110433965Sjdp c = (*pf)->index + 1; 110533965Sjdp if (c == -1) 110633965Sjdp c = 0; 110733965Sjdp *pf = f; 110833965Sjdp f->index = c; 110933965Sjdp } 111033965Sjdp 1111218822Sdim if (f->type != FORMAL_VARARG) 1112218822Sdim idx = get_any_string (idx, in, &f->actual); 1113218822Sdim else 1114218822Sdim { 1115218822Sdim sb_add_buffer (&f->actual, in->ptr + idx, in->len - idx); 1116218822Sdim idx = in->len; 1117218822Sdim } 111833965Sjdp if (f->actual.len > 0) 111933965Sjdp ++narg; 112033965Sjdp do 112133965Sjdp { 112233965Sjdp f = f->next; 112333965Sjdp } 112433965Sjdp while (f != NULL && f->index < 0); 112533965Sjdp } 112633965Sjdp 112733965Sjdp if (! macro_mri) 112833965Sjdp idx = sb_skip_comma (idx, in); 112933965Sjdp else 113033965Sjdp { 113133965Sjdp if (in->ptr[idx] == ',') 113233965Sjdp ++idx; 113333965Sjdp if (ISWHITE (in->ptr[idx])) 113433965Sjdp break; 113533965Sjdp } 113633965Sjdp } 113733965Sjdp 1138218822Sdim if (! err) 113933965Sjdp { 1140218822Sdim for (ptr = m->formals; ptr; ptr = ptr->next) 1141218822Sdim { 1142218822Sdim if (ptr->type == FORMAL_REQUIRED && ptr->actual.len == 0) 1143218822Sdim as_bad (_("Missing value for required parameter `%s' of macro `%s'"), 1144218822Sdim ptr->name.ptr, 1145218822Sdim m->name); 1146218822Sdim } 114733965Sjdp 1148218822Sdim if (macro_mri) 1149218822Sdim { 1150218822Sdim char buffer[20]; 1151218822Sdim 1152218822Sdim sb_reset (&t); 1153218822Sdim sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG"); 1154218822Sdim ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); 1155218822Sdim sprintf (buffer, "%d", narg); 1156218822Sdim sb_add_string (&ptr->actual, buffer); 1157218822Sdim } 1158218822Sdim 1159218822Sdim err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, m); 116033965Sjdp } 116133965Sjdp 116233965Sjdp /* Discard any unnamed formal arguments. */ 116333965Sjdp if (macro_mri) 116433965Sjdp { 116533965Sjdp formal_entry **pf; 116633965Sjdp 116733965Sjdp pf = &m->formals; 116833965Sjdp while (*pf != NULL) 116933965Sjdp { 117033965Sjdp if ((*pf)->name.len != 0) 117133965Sjdp pf = &(*pf)->next; 117233965Sjdp else 117333965Sjdp { 117433965Sjdp f = (*pf)->next; 1175218822Sdim del_formal (*pf); 117633965Sjdp *pf = f; 117733965Sjdp } 117833965Sjdp } 117933965Sjdp } 118033965Sjdp 118133965Sjdp sb_kill (&t); 1182218822Sdim if (!err) 1183218822Sdim macro_number++; 118433965Sjdp 1185218822Sdim return err; 118633965Sjdp} 118733965Sjdp 118833965Sjdp/* Check for a macro. If one is found, put the expansion into 1189130561Sobrien *EXPAND. Return 1 if a macro is found, 0 otherwise. */ 119033965Sjdp 119133965Sjdpint 1192130561Sobriencheck_macro (const char *line, sb *expand, 1193130561Sobrien const char **error, macro_entry **info) 119433965Sjdp{ 119533965Sjdp const char *s; 119633965Sjdp char *copy, *cs; 119733965Sjdp macro_entry *macro; 119833965Sjdp sb line_sb; 119933965Sjdp 1200218822Sdim if (! is_name_beginner (*line) 120133965Sjdp && (! macro_mri || *line != '.')) 120233965Sjdp return 0; 120333965Sjdp 120433965Sjdp s = line + 1; 1205218822Sdim while (is_part_of_name (*s)) 120633965Sjdp ++s; 1207218822Sdim if (is_name_ender (*s)) 1208218822Sdim ++s; 120933965Sjdp 121038889Sjdp copy = (char *) alloca (s - line + 1); 121133965Sjdp memcpy (copy, line, s - line); 121233965Sjdp copy[s - line] = '\0'; 121333965Sjdp for (cs = copy; *cs != '\0'; cs++) 121489857Sobrien *cs = TOLOWER (*cs); 121533965Sjdp 121633965Sjdp macro = (macro_entry *) hash_find (macro_hash, copy); 121733965Sjdp 121833965Sjdp if (macro == NULL) 121933965Sjdp return 0; 122033965Sjdp 122133965Sjdp /* Wrap the line up in an sb. */ 122233965Sjdp sb_new (&line_sb); 122333965Sjdp while (*s != '\0' && *s != '\n' && *s != '\r') 122433965Sjdp sb_add_char (&line_sb, *s++); 122533965Sjdp 122633965Sjdp sb_new (expand); 1227130561Sobrien *error = macro_expand (0, &line_sb, macro, expand); 122833965Sjdp 122933965Sjdp sb_kill (&line_sb); 123033965Sjdp 123177298Sobrien /* Export the macro information if requested. */ 123260484Sobrien if (info) 123360484Sobrien *info = macro; 123460484Sobrien 123533965Sjdp return 1; 123633965Sjdp} 123733965Sjdp 1238218822Sdim/* Free the memory allocated to a macro. */ 1239218822Sdim 1240218822Sdimstatic void 1241218822Sdimfree_macro(macro_entry *macro) 1242218822Sdim{ 1243218822Sdim formal_entry *formal; 1244218822Sdim 1245218822Sdim for (formal = macro->formals; formal; ) 1246218822Sdim { 1247218822Sdim formal_entry *f; 1248218822Sdim 1249218822Sdim f = formal; 1250218822Sdim formal = formal->next; 1251218822Sdim del_formal (f); 1252218822Sdim } 1253218822Sdim hash_die (macro->formal_hash); 1254218822Sdim sb_kill (¯o->sub); 1255218822Sdim free (macro); 1256218822Sdim} 1257218822Sdim 125833965Sjdp/* Delete a macro. */ 125933965Sjdp 126033965Sjdpvoid 1261130561Sobriendelete_macro (const char *name) 126233965Sjdp{ 1263218822Sdim char *copy; 1264218822Sdim size_t i, len; 1265218822Sdim macro_entry *macro; 1266218822Sdim 1267218822Sdim len = strlen (name); 1268218822Sdim copy = (char *) alloca (len + 1); 1269218822Sdim for (i = 0; i < len; ++i) 1270218822Sdim copy[i] = TOLOWER (name[i]); 1271218822Sdim copy[i] = '\0'; 1272218822Sdim 1273218822Sdim /* Since hash_delete doesn't free memory, just clear out the entry. */ 1274218822Sdim if ((macro = hash_find (macro_hash, copy)) != NULL) 1275218822Sdim { 1276218822Sdim hash_jam (macro_hash, copy, NULL); 1277218822Sdim free_macro (macro); 1278218822Sdim } 1279218822Sdim else 1280218822Sdim as_warn (_("Attempt to purge non-existant macro `%s'"), copy); 128133965Sjdp} 128233965Sjdp 128333965Sjdp/* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a 128433965Sjdp combined macro definition and execution. This returns NULL on 128533965Sjdp success, or an error message otherwise. */ 128633965Sjdp 128733965Sjdpconst char * 1288130561Sobrienexpand_irp (int irpc, int idx, sb *in, sb *out, int (*get_line) (sb *)) 128933965Sjdp{ 129033965Sjdp sb sub; 129133965Sjdp formal_entry f; 129233965Sjdp struct hash_control *h; 129333965Sjdp const char *err; 129433965Sjdp 129533965Sjdp idx = sb_skip_white (idx, in); 129633965Sjdp 129733965Sjdp sb_new (&sub); 1298218822Sdim if (! buffer_and_nest (NULL, "ENDR", &sub, get_line)) 129960484Sobrien return _("unexpected end of file in irp or irpc"); 130077298Sobrien 130133965Sjdp sb_new (&f.name); 130233965Sjdp sb_new (&f.def); 130333965Sjdp sb_new (&f.actual); 130433965Sjdp 130533965Sjdp idx = get_token (idx, in, &f.name); 130633965Sjdp if (f.name.len == 0) 130760484Sobrien return _("missing model parameter"); 130833965Sjdp 130933965Sjdp h = hash_new (); 131033965Sjdp err = hash_jam (h, sb_terminate (&f.name), &f); 131133965Sjdp if (err != NULL) 131233965Sjdp return err; 131333965Sjdp 131433965Sjdp f.index = 1; 131533965Sjdp f.next = NULL; 1316218822Sdim f.type = FORMAL_OPTIONAL; 131733965Sjdp 131833965Sjdp sb_reset (out); 131933965Sjdp 132033965Sjdp idx = sb_skip_comma (idx, in); 1321130561Sobrien if (idx >= in->len) 132233965Sjdp { 132333965Sjdp /* Expand once with a null string. */ 1324130561Sobrien err = macro_expand_body (&sub, out, &f, h, 0); 132533965Sjdp } 132633965Sjdp else 132733965Sjdp { 1328218822Sdim bfd_boolean in_quotes = FALSE; 1329218822Sdim 133033965Sjdp if (irpc && in->ptr[idx] == '"') 1331218822Sdim { 1332218822Sdim in_quotes = TRUE; 1333218822Sdim ++idx; 1334218822Sdim } 1335218822Sdim 1336130561Sobrien while (idx < in->len) 133733965Sjdp { 133833965Sjdp if (!irpc) 1339218822Sdim idx = get_any_string (idx, in, &f.actual); 134033965Sjdp else 134133965Sjdp { 134233965Sjdp if (in->ptr[idx] == '"') 134333965Sjdp { 134433965Sjdp int nxt; 134533965Sjdp 1346218822Sdim if (irpc) 1347218822Sdim in_quotes = ! in_quotes; 1348218822Sdim 134933965Sjdp nxt = sb_skip_white (idx + 1, in); 1350130561Sobrien if (nxt >= in->len) 135133965Sjdp { 135233965Sjdp idx = nxt; 135333965Sjdp break; 135433965Sjdp } 135533965Sjdp } 135633965Sjdp sb_reset (&f.actual); 135733965Sjdp sb_add_char (&f.actual, in->ptr[idx]); 135833965Sjdp ++idx; 135933965Sjdp } 1360218822Sdim 1361130561Sobrien err = macro_expand_body (&sub, out, &f, h, 0); 136233965Sjdp if (err != NULL) 1363218822Sdim break; 136433965Sjdp if (!irpc) 136533965Sjdp idx = sb_skip_comma (idx, in); 1366218822Sdim else if (! in_quotes) 136733965Sjdp idx = sb_skip_white (idx, in); 136833965Sjdp } 136933965Sjdp } 137033965Sjdp 137133965Sjdp hash_die (h); 1372218822Sdim sb_kill (&f.actual); 1373218822Sdim sb_kill (&f.def); 1374218822Sdim sb_kill (&f.name); 137533965Sjdp sb_kill (&sub); 137633965Sjdp 1377218822Sdim return err; 137833965Sjdp} 1379