macro.c revision 60484
1/* macro.c - macro support for gas and gasp 2 Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. 3 4 Written by Steve and Judy Chamberlain of Cygnus Support, 5 sac@cygnus.com 6 7 This file is part of GAS, the GNU Assembler. 8 9 GAS is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2, or (at your option) 12 any later version. 13 14 GAS is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with GAS; see the file COPYING. If not, write to the Free 21 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 22 02111-1307, USA. */ 23 24#include "config.h" 25 26/* AIX requires this to be the first thing in the file. */ 27#ifdef __GNUC__ 28# ifndef alloca 29# ifdef __STDC__ 30extern void *alloca (); 31# else 32extern char *alloca (); 33# endif 34# endif 35#else 36# if HAVE_ALLOCA_H 37# include <alloca.h> 38# else 39# ifdef _AIX 40 #pragma alloca 41# else 42# ifndef alloca /* predefined by HP cc +Olibcalls */ 43# if !defined (__STDC__) && !defined (__hpux) 44extern char *alloca (); 45# else 46extern void *alloca (); 47# endif /* __STDC__, __hpux */ 48# endif /* alloca */ 49# endif /* _AIX */ 50# endif /* HAVE_ALLOCA_H */ 51#endif 52 53#include <stdio.h> 54#ifdef HAVE_STRING_H 55#include <string.h> 56#else 57#include <strings.h> 58#endif 59#include <ctype.h> 60#ifdef HAVE_STDLIB_H 61#include <stdlib.h> 62#endif 63#include "libiberty.h" 64#include "sb.h" 65#include "hash.h" 66#include "macro.h" 67 68#include "asintl.h" 69 70/* The routines in this file handle macro definition and expansion. 71 They are called by both gasp and gas. */ 72 73/* Internal functions. */ 74 75static int get_token PARAMS ((int, sb *, sb *)); 76static int getstring PARAMS ((int, sb *, sb *)); 77static int get_any_string PARAMS ((int, sb *, sb *, int, int)); 78static int do_formals PARAMS ((macro_entry *, int, sb *)); 79static int get_apost_token PARAMS ((int, sb *, sb *, int)); 80static int sub_actual 81 PARAMS ((int, sb *, sb *, struct hash_control *, int, sb *, int)); 82static const char *macro_expand_body 83 PARAMS ((sb *, sb *, formal_entry *, struct hash_control *, int, int)); 84static const char *macro_expand PARAMS ((int, sb *, macro_entry *, sb *, int)); 85 86#define ISWHITE(x) ((x) == ' ' || (x) == '\t') 87 88#define ISSEP(x) \ 89 ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \ 90 || (x) == ')' || (x) == '(' \ 91 || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>'))) 92 93#define ISBASE(x) \ 94 ((x) == 'b' || (x) == 'B' \ 95 || (x) == 'q' || (x) == 'Q' \ 96 || (x) == 'h' || (x) == 'H' \ 97 || (x) == 'd' || (x) == 'D') 98 99/* The macro hash table. */ 100 101static struct hash_control *macro_hash; 102 103/* Whether any macros have been defined. */ 104 105int macro_defined; 106 107/* Whether we are in GASP alternate mode. */ 108 109static int macro_alternate; 110 111/* Whether we are in MRI mode. */ 112 113static int macro_mri; 114 115/* Whether we should strip '@' characters. */ 116 117static int macro_strip_at; 118 119/* Function to use to parse an expression. */ 120 121static int (*macro_expr) PARAMS ((const char *, int, sb *, int *)); 122 123/* Number of macro expansions that have been done. */ 124 125static int macro_number; 126 127/* Initialize macro processing. */ 128 129void 130macro_init (alternate, mri, strip_at, expr) 131 int alternate; 132 int mri; 133 int strip_at; 134 int (*expr) PARAMS ((const char *, int, sb *, int *)); 135{ 136 macro_hash = hash_new (); 137 macro_defined = 0; 138 macro_alternate = alternate; 139 macro_mri = mri; 140 macro_strip_at = strip_at; 141 macro_expr = expr; 142} 143 144/* Switch in and out of MRI mode on the fly. */ 145 146void 147macro_mri_mode (mri) 148 int mri; 149{ 150 macro_mri = mri; 151} 152 153/* Read input lines till we get to a TO string. 154 Increase nesting depth if we get a FROM string. 155 Put the results into sb at PTR. 156 Add a new input line to an sb using GET_LINE. 157 Return 1 on success, 0 on unexpected EOF. */ 158 159int 160buffer_and_nest (from, to, ptr, get_line) 161 const char *from; 162 const char *to; 163 sb *ptr; 164 int (*get_line) PARAMS ((sb *)); 165{ 166 int from_len = strlen (from); 167 int to_len = strlen (to); 168 int depth = 1; 169 int line_start = ptr->len; 170 171 int more = get_line (ptr); 172 173 while (more) 174 { 175 /* Try and find the first pseudo op on the line */ 176 int i = line_start; 177 178 if (! macro_alternate && ! macro_mri) 179 { 180 /* With normal syntax we can suck what we want till we get 181 to the dot. With the alternate, labels have to start in 182 the first column, since we cant tell what's a label and 183 whats a pseudoop */ 184 185 /* Skip leading whitespace */ 186 while (i < ptr->len && ISWHITE (ptr->ptr[i])) 187 i++; 188 189 /* Skip over a label */ 190 while (i < ptr->len 191 && (isalnum ((unsigned char) ptr->ptr[i]) 192 || ptr->ptr[i] == '_' 193 || ptr->ptr[i] == '$')) 194 i++; 195 196 /* And a colon */ 197 if (i < ptr->len 198 && ptr->ptr[i] == ':') 199 i++; 200 201 } 202 /* Skip trailing whitespace */ 203 while (i < ptr->len && ISWHITE (ptr->ptr[i])) 204 i++; 205 206 if (i < ptr->len && (ptr->ptr[i] == '.' 207 || macro_alternate 208 || macro_mri)) 209 { 210 if (ptr->ptr[i] == '.') 211 i++; 212 if (strncasecmp (ptr->ptr + i, from, from_len) == 0 213 && (ptr->len == (i + from_len) || ! isalnum (ptr->ptr[i + from_len]))) 214 depth++; 215 if (strncasecmp (ptr->ptr + i, to, to_len) == 0 216 && (ptr->len == (i + to_len) || ! isalnum (ptr->ptr[i + to_len]))) 217 { 218 depth--; 219 if (depth == 0) 220 { 221 /* Reset the string to not include the ending rune */ 222 ptr->len = line_start; 223 break; 224 } 225 } 226 } 227 228 /* Add a CR to the end and keep running */ 229 sb_add_char (ptr, '\n'); 230 line_start = ptr->len; 231 more = get_line (ptr); 232 } 233 234 /* Return 1 on success, 0 on unexpected EOF. */ 235 return depth == 0; 236} 237 238/* Pick up a token. */ 239 240static int 241get_token (idx, in, name) 242 int idx; 243 sb *in; 244 sb *name; 245{ 246 if (idx < in->len 247 && (isalpha ((unsigned char) in->ptr[idx]) 248 || in->ptr[idx] == '_' 249 || in->ptr[idx] == '$')) 250 { 251 sb_add_char (name, in->ptr[idx++]); 252 while (idx < in->len 253 && (isalnum ((unsigned char) in->ptr[idx]) 254 || in->ptr[idx] == '_' 255 || in->ptr[idx] == '$')) 256 { 257 sb_add_char (name, in->ptr[idx++]); 258 } 259 } 260 /* Ignore trailing & */ 261 if (macro_alternate && idx < in->len && in->ptr[idx] == '&') 262 idx++; 263 return idx; 264} 265 266/* Pick up a string. */ 267 268static int 269getstring (idx, in, acc) 270 int idx; 271 sb *in; 272 sb *acc; 273{ 274 idx = sb_skip_white (idx, in); 275 276 while (idx < in->len 277 && (in->ptr[idx] == '"' 278 || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) 279 || (in->ptr[idx] == '\'' && macro_alternate))) 280 { 281 if (in->ptr[idx] == '<') 282 { 283 int nest = 0; 284 idx++; 285 while ((in->ptr[idx] != '>' || nest) 286 && idx < in->len) 287 { 288 if (in->ptr[idx] == '!') 289 { 290 idx++ ; 291 sb_add_char (acc, in->ptr[idx++]); 292 } 293 else 294 { 295 if (in->ptr[idx] == '>') 296 nest--; 297 if (in->ptr[idx] == '<') 298 nest++; 299 sb_add_char (acc, in->ptr[idx++]); 300 } 301 } 302 idx++; 303 } 304 else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') 305 { 306 char tchar = in->ptr[idx]; 307 idx++; 308 while (idx < in->len) 309 { 310 if (macro_alternate && in->ptr[idx] == '!') 311 { 312 idx++ ; 313 sb_add_char (acc, in->ptr[idx++]); 314 } 315 else 316 { 317 if (in->ptr[idx] == tchar) 318 { 319 idx++; 320 if (idx >= in->len || in->ptr[idx] != tchar) 321 break; 322 } 323 sb_add_char (acc, in->ptr[idx]); 324 idx++; 325 } 326 } 327 } 328 } 329 330 return idx; 331} 332 333/* Fetch string from the input stream, 334 rules: 335 'Bxyx<whitespace> -> return 'Bxyza 336 %<char> -> return string of decimal value of x 337 "<string>" -> return string 338 xyx<whitespace> -> return xyz 339*/ 340 341static int 342get_any_string (idx, in, out, expand, pretend_quoted) 343 int idx; 344 sb *in; 345 sb *out; 346 int expand; 347 int pretend_quoted; 348{ 349 sb_reset (out); 350 idx = sb_skip_white (idx, in); 351 352 if (idx < in->len) 353 { 354 if (in->len > 2 && in->ptr[idx+1] == '\'' && ISBASE (in->ptr[idx])) 355 { 356 while (!ISSEP (in->ptr[idx])) 357 sb_add_char (out, in->ptr[idx++]); 358 } 359 else if (in->ptr[idx] == '%' 360 && macro_alternate 361 && expand) 362 { 363 int val; 364 char buf[20]; 365 /* Turns the next expression into a string */ 366 idx = (*macro_expr) (_("% operator needs absolute expression"), 367 idx + 1, 368 in, 369 &val); 370 sprintf(buf, "%d", val); 371 sb_add_string (out, buf); 372 } 373 else if (in->ptr[idx] == '"' 374 || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) 375 || (macro_alternate && in->ptr[idx] == '\'')) 376 { 377 if (macro_alternate 378 && ! macro_strip_at 379 && expand) 380 { 381 /* Keep the quotes */ 382 sb_add_char (out, '\"'); 383 384 idx = getstring (idx, in, out); 385 sb_add_char (out, '\"'); 386 } 387 else 388 { 389 idx = getstring (idx, in, out); 390 } 391 } 392 else 393 { 394 while (idx < in->len 395 && (in->ptr[idx] == '"' 396 || in->ptr[idx] == '\'' 397 || pretend_quoted 398 || (in->ptr[idx] != ' ' 399 && in->ptr[idx] != '\t' 400 && in->ptr[idx] != ',' 401 && (in->ptr[idx] != '<' 402 || (! macro_alternate && ! macro_mri))))) 403 { 404 if (in->ptr[idx] == '"' 405 || in->ptr[idx] == '\'') 406 { 407 char tchar = in->ptr[idx]; 408 sb_add_char (out, in->ptr[idx++]); 409 while (idx < in->len 410 && in->ptr[idx] != tchar) 411 sb_add_char (out, in->ptr[idx++]); 412 if (idx == in->len) 413 return idx; 414 } 415 sb_add_char (out, in->ptr[idx++]); 416 } 417 } 418 } 419 420 return idx; 421} 422 423/* Pick up the formal parameters of a macro definition. */ 424 425static int 426do_formals (macro, idx, in) 427 macro_entry *macro; 428 int idx; 429 sb *in; 430{ 431 formal_entry **p = ¯o->formals; 432 433 macro->formal_count = 0; 434 macro->formal_hash = hash_new (); 435 while (idx < in->len) 436 { 437 formal_entry *formal; 438 439 formal = (formal_entry *) xmalloc (sizeof (formal_entry)); 440 441 sb_new (&formal->name); 442 sb_new (&formal->def); 443 sb_new (&formal->actual); 444 445 idx = sb_skip_white (idx, in); 446 idx = get_token (idx, in, &formal->name); 447 if (formal->name.len == 0) 448 break; 449 idx = sb_skip_white (idx, in); 450 if (formal->name.len) 451 { 452 /* This is a formal */ 453 if (idx < in->len && in->ptr[idx] == '=') 454 { 455 /* Got a default */ 456 idx = get_any_string (idx + 1, in, &formal->def, 1, 0); 457 } 458 } 459 460 /* Add to macro's hash table */ 461 hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal); 462 463 formal->index = macro->formal_count; 464 idx = sb_skip_comma (idx, in); 465 macro->formal_count++; 466 *p = formal; 467 p = &formal->next; 468 *p = NULL; 469 } 470 471 if (macro_mri) 472 { 473 formal_entry *formal; 474 const char *name; 475 476 /* Add a special NARG formal, which macro_expand will set to the 477 number of arguments. */ 478 formal = (formal_entry *) xmalloc (sizeof (formal_entry)); 479 480 sb_new (&formal->name); 481 sb_new (&formal->def); 482 sb_new (&formal->actual); 483 484 /* The same MRI assemblers which treat '@' characters also use 485 the name $NARG. At least until we find an exception. */ 486 if (macro_strip_at) 487 name = "$NARG"; 488 else 489 name = "NARG"; 490 491 sb_add_string (&formal->name, name); 492 493 /* Add to macro's hash table */ 494 hash_jam (macro->formal_hash, name, formal); 495 496 formal->index = NARG_INDEX; 497 *p = formal; 498 formal->next = NULL; 499 } 500 501 return idx; 502} 503 504/* Define a new macro. Returns NULL on success, otherwise returns an 505 error message. If NAMEP is not NULL, *NAMEP is set to the name of 506 the macro which was defined. */ 507 508const char * 509define_macro (idx, in, label, get_line, namep) 510 int idx; 511 sb *in; 512 sb *label; 513 int (*get_line) PARAMS ((sb *)); 514 const char **namep; 515{ 516 macro_entry *macro; 517 sb name; 518 const char *namestr; 519 520 macro = (macro_entry *) xmalloc (sizeof (macro_entry)); 521 sb_new (¯o->sub); 522 sb_new (&name); 523 524 macro->formal_count = 0; 525 macro->formals = 0; 526 527 idx = sb_skip_white (idx, in); 528 if (! buffer_and_nest ("MACRO", "ENDM", ¯o->sub, get_line)) 529 return _("unexpected end of file in macro definition"); 530 if (label != NULL && label->len != 0) 531 { 532 sb_add_sb (&name, label); 533 if (idx < in->len && in->ptr[idx] == '(') 534 { 535 /* It's the label: MACRO (formals,...) sort */ 536 idx = do_formals (macro, idx + 1, in); 537 if (in->ptr[idx] != ')') 538 return _("missing ) after formals"); 539 } 540 else 541 { 542 /* It's the label: MACRO formals,... sort */ 543 idx = do_formals (macro, idx, in); 544 } 545 } 546 else 547 { 548 idx = get_token (idx, in, &name); 549 idx = sb_skip_comma (idx, in); 550 idx = do_formals (macro, idx, in); 551 } 552 553 /* and stick it in the macro hash table */ 554 for (idx = 0; idx < name.len; idx++) 555 if (isupper ((unsigned char) name.ptr[idx])) 556 name.ptr[idx] = tolower (name.ptr[idx]); 557 namestr = sb_terminate (&name); 558 hash_jam (macro_hash, namestr, (PTR) macro); 559 560 macro_defined = 1; 561 562 if (namep != NULL) 563 *namep = namestr; 564 565 return NULL; 566} 567 568/* Scan a token, and then skip KIND. */ 569 570static int 571get_apost_token (idx, in, name, kind) 572 int idx; 573 sb *in; 574 sb *name; 575 int kind; 576{ 577 idx = get_token (idx, in, name); 578 if (idx < in->len 579 && in->ptr[idx] == kind 580 && (! macro_mri || macro_strip_at) 581 && (! macro_strip_at || kind == '@')) 582 idx++; 583 return idx; 584} 585 586/* Substitute the actual value for a formal parameter. */ 587 588static int 589sub_actual (start, in, t, formal_hash, kind, out, copyifnotthere) 590 int start; 591 sb *in; 592 sb *t; 593 struct hash_control *formal_hash; 594 int kind; 595 sb *out; 596 int copyifnotthere; 597{ 598 int src; 599 formal_entry *ptr; 600 601 src = get_apost_token (start, in, t, kind); 602 /* See if it's in the macro's hash table, unless this is 603 macro_strip_at and kind is '@' and the token did not end in '@'. */ 604 if (macro_strip_at 605 && kind == '@' 606 && (src == start || in->ptr[src - 1] != '@')) 607 ptr = NULL; 608 else 609 ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t)); 610 if (ptr) 611 { 612 if (ptr->actual.len) 613 { 614 sb_add_sb (out, &ptr->actual); 615 } 616 else 617 { 618 sb_add_sb (out, &ptr->def); 619 } 620 } 621 else if (kind == '&') 622 { 623 /* Doing this permits people to use & in macro bodies. */ 624 sb_add_char (out, '&'); 625 } 626 else if (copyifnotthere) 627 { 628 sb_add_sb (out, t); 629 } 630 else 631 { 632 sb_add_char (out, '\\'); 633 sb_add_sb (out, t); 634 } 635 return src; 636} 637 638/* Expand the body of a macro. */ 639 640static const char * 641macro_expand_body (in, out, formals, formal_hash, comment_char, locals) 642 sb *in; 643 sb *out; 644 formal_entry *formals; 645 struct hash_control *formal_hash; 646 int comment_char; 647 int locals; 648{ 649 sb t; 650 int src = 0; 651 int inquote = 0; 652 formal_entry *loclist = NULL; 653 654 sb_new (&t); 655 656 while (src < in->len) 657 { 658 if (in->ptr[src] == '&') 659 { 660 sb_reset (&t); 661 if (macro_mri) 662 { 663 if (src + 1 < in->len && in->ptr[src + 1] == '&') 664 src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1); 665 else 666 sb_add_char (out, in->ptr[src++]); 667 } 668 else 669 { 670 /* FIXME: Why do we do this? */ 671 src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0); 672 } 673 } 674 else if (in->ptr[src] == '\\') 675 { 676 src++; 677 if (in->ptr[src] == comment_char && comment_char != '\0') 678 { 679 /* This is a comment, just drop the rest of the line */ 680 while (src < in->len 681 && in->ptr[src] != '\n') 682 src++; 683 } 684 else if (in->ptr[src] == '(') 685 { 686 /* Sub in till the next ')' literally */ 687 src++; 688 while (src < in->len && in->ptr[src] != ')') 689 { 690 sb_add_char (out, in->ptr[src++]); 691 } 692 if (in->ptr[src] == ')') 693 src++; 694 else 695 return _("missplaced )"); 696 } 697 else if (in->ptr[src] == '@') 698 { 699 /* Sub in the macro invocation number */ 700 701 char buffer[10]; 702 src++; 703 sprintf (buffer, "%05d", macro_number); 704 sb_add_string (out, buffer); 705 } 706 else if (in->ptr[src] == '&') 707 { 708 /* This is a preprocessor variable name, we don't do them 709 here */ 710 sb_add_char (out, '\\'); 711 sb_add_char (out, '&'); 712 src++; 713 } 714 else if (macro_mri 715 && isalnum ((unsigned char) in->ptr[src])) 716 { 717 int ind; 718 formal_entry *f; 719 720 if (isdigit ((unsigned char) in->ptr[src])) 721 ind = in->ptr[src] - '0'; 722 else if (isupper ((unsigned char) in->ptr[src])) 723 ind = in->ptr[src] - 'A' + 10; 724 else 725 ind = in->ptr[src] - 'a' + 10; 726 ++src; 727 for (f = formals; f != NULL; f = f->next) 728 { 729 if (f->index == ind - 1) 730 { 731 if (f->actual.len != 0) 732 sb_add_sb (out, &f->actual); 733 else 734 sb_add_sb (out, &f->def); 735 break; 736 } 737 } 738 } 739 else 740 { 741 sb_reset (&t); 742 src = sub_actual (src, in, &t, formal_hash, '\'', out, 0); 743 } 744 } 745 else if ((macro_alternate || macro_mri) 746 && (isalpha ((unsigned char) in->ptr[src]) 747 || in->ptr[src] == '_' 748 || in->ptr[src] == '$') 749 && (! inquote 750 || ! macro_strip_at 751 || (src > 0 && in->ptr[src - 1] == '@'))) 752 { 753 if (! locals 754 || src + 5 >= in->len 755 || strncasecmp (in->ptr + src, "LOCAL", 5) != 0 756 || ! ISWHITE (in->ptr[src + 5])) 757 { 758 sb_reset (&t); 759 src = sub_actual (src, in, &t, formal_hash, 760 (macro_strip_at && inquote) ? '@' : '\'', 761 out, 1); 762 } 763 else 764 { 765 formal_entry *f; 766 767 src = sb_skip_white (src + 5, in); 768 while (in->ptr[src] != '\n' && in->ptr[src] != comment_char) 769 { 770 static int loccnt; 771 char buf[20]; 772 const char *err; 773 774 f = (formal_entry *) xmalloc (sizeof (formal_entry)); 775 sb_new (&f->name); 776 sb_new (&f->def); 777 sb_new (&f->actual); 778 f->index = LOCAL_INDEX; 779 f->next = loclist; 780 loclist = f; 781 782 src = get_token (src, in, &f->name); 783 ++loccnt; 784 sprintf (buf, "LL%04x", loccnt); 785 sb_add_string (&f->actual, buf); 786 787 err = hash_jam (formal_hash, sb_terminate (&f->name), f); 788 if (err != NULL) 789 return err; 790 791 src = sb_skip_comma (src, in); 792 } 793 } 794 } 795 else if (comment_char != '\0' 796 && in->ptr[src] == comment_char 797 && src + 1 < in->len 798 && in->ptr[src + 1] == comment_char 799 && !inquote) 800 { 801 /* Two comment chars in a row cause the rest of the line to 802 be dropped. */ 803 while (src < in->len && in->ptr[src] != '\n') 804 src++; 805 } 806 else if (in->ptr[src] == '"' 807 || (macro_mri && in->ptr[src] == '\'')) 808 { 809 inquote = !inquote; 810 sb_add_char (out, in->ptr[src++]); 811 } 812 else if (in->ptr[src] == '@' && macro_strip_at) 813 { 814 ++src; 815 if (src < in->len 816 && in->ptr[src] == '@') 817 { 818 sb_add_char (out, '@'); 819 ++src; 820 } 821 } 822 else if (macro_mri 823 && in->ptr[src] == '=' 824 && src + 1 < in->len 825 && in->ptr[src + 1] == '=') 826 { 827 formal_entry *ptr; 828 829 sb_reset (&t); 830 src = get_token (src + 2, in, &t); 831 ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t)); 832 if (ptr == NULL) 833 { 834 /* FIXME: We should really return a warning string here, 835 but we can't, because the == might be in the MRI 836 comment field, and, since the nature of the MRI 837 comment field depends upon the exact instruction 838 being used, we don't have enough information here to 839 figure out whether it is or not. Instead, we leave 840 the == in place, which should cause a syntax error if 841 it is not in a comment. */ 842 sb_add_char (out, '='); 843 sb_add_char (out, '='); 844 sb_add_sb (out, &t); 845 } 846 else 847 { 848 if (ptr->actual.len) 849 { 850 sb_add_string (out, "-1"); 851 } 852 else 853 { 854 sb_add_char (out, '0'); 855 } 856 } 857 } 858 else 859 { 860 sb_add_char (out, in->ptr[src++]); 861 } 862 } 863 864 sb_kill (&t); 865 866 while (loclist != NULL) 867 { 868 formal_entry *f; 869 870 f = loclist->next; 871 /* Setting the value to NULL effectively deletes the entry. We 872 avoid calling hash_delete because it doesn't reclaim memory. */ 873 hash_jam (formal_hash, sb_terminate (&loclist->name), NULL); 874 sb_kill (&loclist->name); 875 sb_kill (&loclist->def); 876 sb_kill (&loclist->actual); 877 free (loclist); 878 loclist = f; 879 } 880 881 return NULL; 882} 883 884/* Assign values to the formal parameters of a macro, and expand the 885 body. */ 886 887static const char * 888macro_expand (idx, in, m, out, comment_char) 889 int idx; 890 sb *in; 891 macro_entry *m; 892 sb *out; 893 int comment_char; 894{ 895 sb t; 896 formal_entry *ptr; 897 formal_entry *f; 898 int is_positional = 0; 899 int is_keyword = 0; 900 int narg = 0; 901 const char *err; 902 903 sb_new (&t); 904 905 /* Reset any old value the actuals may have */ 906 for (f = m->formals; f; f = f->next) 907 sb_reset (&f->actual); 908 f = m->formals; 909 while (f != NULL && f->index < 0) 910 f = f->next; 911 912 if (macro_mri) 913 { 914 /* The macro may be called with an optional qualifier, which may 915 be referred to in the macro body as \0. */ 916 if (idx < in->len && in->ptr[idx] == '.') 917 { 918 formal_entry *n; 919 920 n = (formal_entry *) xmalloc (sizeof (formal_entry)); 921 sb_new (&n->name); 922 sb_new (&n->def); 923 sb_new (&n->actual); 924 n->index = QUAL_INDEX; 925 926 n->next = m->formals; 927 m->formals = n; 928 929 idx = get_any_string (idx + 1, in, &n->actual, 1, 0); 930 } 931 } 932 933 /* Peel off the actuals and store them away in the hash tables' actuals */ 934 idx = sb_skip_white (idx, in); 935 while (idx < in->len && in->ptr[idx] != comment_char) 936 { 937 int scan; 938 939 /* Look and see if it's a positional or keyword arg */ 940 scan = idx; 941 while (scan < in->len 942 && !ISSEP (in->ptr[scan]) 943 && !(macro_mri && in->ptr[scan] == '\'') 944 && (!macro_alternate && in->ptr[scan] != '=')) 945 scan++; 946 if (scan < in->len && !macro_alternate && in->ptr[scan] == '=') 947 { 948 is_keyword = 1; 949 950 /* It's OK to go from positional to keyword. */ 951 952 /* This is a keyword arg, fetch the formal name and 953 then the actual stuff */ 954 sb_reset (&t); 955 idx = get_token (idx, in, &t); 956 if (in->ptr[idx] != '=') 957 return _("confusion in formal parameters"); 958 959 /* Lookup the formal in the macro's list */ 960 ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); 961 if (!ptr) 962 return _("macro formal argument does not exist"); 963 else 964 { 965 /* Insert this value into the right place */ 966 sb_reset (&ptr->actual); 967 idx = get_any_string (idx + 1, in, &ptr->actual, 0, 0); 968 if (ptr->actual.len > 0) 969 ++narg; 970 } 971 } 972 else 973 { 974 /* This is a positional arg */ 975 is_positional = 1; 976 if (is_keyword) 977 return _("can't mix positional and keyword arguments"); 978 979 if (!f) 980 { 981 formal_entry **pf; 982 int c; 983 984 if (!macro_mri) 985 return _("too many positional arguments"); 986 987 f = (formal_entry *) xmalloc (sizeof (formal_entry)); 988 sb_new (&f->name); 989 sb_new (&f->def); 990 sb_new (&f->actual); 991 f->next = NULL; 992 993 c = -1; 994 for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) 995 if ((*pf)->index >= c) 996 c = (*pf)->index + 1; 997 if (c == -1) 998 c = 0; 999 *pf = f; 1000 f->index = c; 1001 } 1002 1003 sb_reset (&f->actual); 1004 idx = get_any_string (idx, in, &f->actual, 1, 0); 1005 if (f->actual.len > 0) 1006 ++narg; 1007 do 1008 { 1009 f = f->next; 1010 } 1011 while (f != NULL && f->index < 0); 1012 } 1013 1014 if (! macro_mri) 1015 idx = sb_skip_comma (idx, in); 1016 else 1017 { 1018 if (in->ptr[idx] == ',') 1019 ++idx; 1020 if (ISWHITE (in->ptr[idx])) 1021 break; 1022 } 1023 } 1024 1025 if (macro_mri) 1026 { 1027 char buffer[20]; 1028 1029 sb_reset (&t); 1030 sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG"); 1031 ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); 1032 sb_reset (&ptr->actual); 1033 sprintf (buffer, "%d", narg); 1034 sb_add_string (&ptr->actual, buffer); 1035 } 1036 1037 err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, 1038 comment_char, 1); 1039 if (err != NULL) 1040 return err; 1041 1042 /* Discard any unnamed formal arguments. */ 1043 if (macro_mri) 1044 { 1045 formal_entry **pf; 1046 1047 pf = &m->formals; 1048 while (*pf != NULL) 1049 { 1050 if ((*pf)->name.len != 0) 1051 pf = &(*pf)->next; 1052 else 1053 { 1054 sb_kill (&(*pf)->name); 1055 sb_kill (&(*pf)->def); 1056 sb_kill (&(*pf)->actual); 1057 f = (*pf)->next; 1058 free (*pf); 1059 *pf = f; 1060 } 1061 } 1062 } 1063 1064 sb_kill (&t); 1065 macro_number++; 1066 1067 return NULL; 1068} 1069 1070/* Check for a macro. If one is found, put the expansion into 1071 *EXPAND. COMMENT_CHAR is the comment character--this is used by 1072 gasp. Return 1 if a macro is found, 0 otherwise. */ 1073 1074int 1075check_macro (line, expand, comment_char, error, info) 1076 const char *line; 1077 sb *expand; 1078 int comment_char; 1079 const char **error; 1080 macro_entry **info; 1081{ 1082 const char *s; 1083 char *copy, *cs; 1084 macro_entry *macro; 1085 sb line_sb; 1086 1087 if (! isalpha ((unsigned char) *line) 1088 && *line != '_' 1089 && *line != '$' 1090 && (! macro_mri || *line != '.')) 1091 return 0; 1092 1093 s = line + 1; 1094 while (isalnum ((unsigned char) *s) 1095 || *s == '_' 1096 || *s == '$') 1097 ++s; 1098 1099 copy = (char *) alloca (s - line + 1); 1100 memcpy (copy, line, s - line); 1101 copy[s - line] = '\0'; 1102 for (cs = copy; *cs != '\0'; cs++) 1103 if (isupper ((unsigned char) *cs)) 1104 *cs = tolower (*cs); 1105 1106 macro = (macro_entry *) hash_find (macro_hash, copy); 1107 1108 if (macro == NULL) 1109 return 0; 1110 1111 /* Wrap the line up in an sb. */ 1112 sb_new (&line_sb); 1113 while (*s != '\0' && *s != '\n' && *s != '\r') 1114 sb_add_char (&line_sb, *s++); 1115 1116 sb_new (expand); 1117 *error = macro_expand (0, &line_sb, macro, expand, comment_char); 1118 1119 sb_kill (&line_sb); 1120 1121 /* export the macro information if requested */ 1122 if (info) 1123 *info = macro; 1124 1125 return 1; 1126} 1127 1128/* Delete a macro. */ 1129 1130void 1131delete_macro (name) 1132 const char *name; 1133{ 1134 hash_delete (macro_hash, name); 1135} 1136 1137/* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a 1138 combined macro definition and execution. This returns NULL on 1139 success, or an error message otherwise. */ 1140 1141const char * 1142expand_irp (irpc, idx, in, out, get_line, comment_char) 1143 int irpc; 1144 int idx; 1145 sb *in; 1146 sb *out; 1147 int (*get_line) PARAMS ((sb *)); 1148 int comment_char; 1149{ 1150 const char *mn; 1151 sb sub; 1152 formal_entry f; 1153 struct hash_control *h; 1154 const char *err; 1155 1156 if (irpc) 1157 mn = "IRPC"; 1158 else 1159 mn = "IRP"; 1160 1161 idx = sb_skip_white (idx, in); 1162 1163 sb_new (&sub); 1164 if (! buffer_and_nest (mn, "ENDR", &sub, get_line)) 1165 return _("unexpected end of file in irp or irpc"); 1166 1167 sb_new (&f.name); 1168 sb_new (&f.def); 1169 sb_new (&f.actual); 1170 1171 idx = get_token (idx, in, &f.name); 1172 if (f.name.len == 0) 1173 return _("missing model parameter"); 1174 1175 h = hash_new (); 1176 err = hash_jam (h, sb_terminate (&f.name), &f); 1177 if (err != NULL) 1178 return err; 1179 1180 f.index = 1; 1181 f.next = NULL; 1182 1183 sb_reset (out); 1184 1185 idx = sb_skip_comma (idx, in); 1186 if (idx >= in->len || in->ptr[idx] == comment_char) 1187 { 1188 /* Expand once with a null string. */ 1189 err = macro_expand_body (&sub, out, &f, h, comment_char, 0); 1190 if (err != NULL) 1191 return err; 1192 } 1193 else 1194 { 1195 if (irpc && in->ptr[idx] == '"') 1196 ++idx; 1197 while (idx < in->len && in->ptr[idx] != comment_char) 1198 { 1199 if (!irpc) 1200 idx = get_any_string (idx, in, &f.actual, 1, 0); 1201 else 1202 { 1203 if (in->ptr[idx] == '"') 1204 { 1205 int nxt; 1206 1207 nxt = sb_skip_white (idx + 1, in); 1208 if (nxt >= in->len || in->ptr[nxt] == comment_char) 1209 { 1210 idx = nxt; 1211 break; 1212 } 1213 } 1214 sb_reset (&f.actual); 1215 sb_add_char (&f.actual, in->ptr[idx]); 1216 ++idx; 1217 } 1218 err = macro_expand_body (&sub, out, &f, h, comment_char, 0); 1219 if (err != NULL) 1220 return err; 1221 if (!irpc) 1222 idx = sb_skip_comma (idx, in); 1223 else 1224 idx = sb_skip_white (idx, in); 1225 } 1226 } 1227 1228 hash_die (h); 1229 sb_kill (&sub); 1230 1231 return NULL; 1232} 1233