1 /* $NetBSD: reader.c,v 1.20 2021/10/05 22:15:32 rillig Exp $ */ 2 3 /* Id: reader.c,v 1.84 2020/09/10 20:26:13 tom Exp */ 4 5 #include "defs.h" 6 7 #include <sys/cdefs.h> 8 __RCSID("$NetBSD: reader.c,v 1.20 2021/10/05 22:15:32 rillig Exp $"); 9 10 /* The line size must be a positive integer. One hundred was chosen */ 11 /* because few lines in Yacc input grammars exceed 100 characters. */ 12 /* Note that if a line exceeds LINESIZE characters, the line buffer */ 13 /* will be expanded to accommodate it. */ 14 15 #define LINESIZE 100 16 17 #define L_CURL '{' 18 #define R_CURL '}' 19 #define L_PAREN '(' 20 #define R_PAREN ')' 21 #define L_BRAC '[' 22 #define R_BRAC ']' 23 24 /* the maximum number of arguments (inherited attributes) to a non-terminal */ 25 /* this is a hard limit, but seems more than adequate */ 26 #define MAXARGS 20 27 28 static void start_rule(bucket *bp, int s_lineno); 29 #if defined(YYBTYACC) 30 static void copy_initial_action(void); 31 static void copy_destructor(void); 32 static char *process_destructor_XX(char *code, char *tag); 33 #endif 34 35 #define CACHE_SIZE 256 36 static char *cache; 37 static int cinc, cache_size; 38 39 int ntags; 40 static int tagmax, havetags; 41 static char **tag_table; 42 43 static char saw_eof; 44 char unionized; 45 char *cptr, *line; 46 static int linesize; 47 48 static bucket *goal; 49 static Value_t prec; 50 static int gensym; 51 static char last_was_action; 52 #if defined(YYBTYACC) 53 static int trialaction; 54 #endif 55 56 static int maxitems; 57 static bucket **pitem; 58 59 static int maxrules; 60 static bucket **plhs; 61 62 static size_t name_pool_size; 63 static char *name_pool; 64 65 char line_format[] = "#line %d \"%s\"\n"; 66 67 param *lex_param; 68 param *parse_param; 69 70 static const char *code_keys[] = 71 { 72 "", "requires", "provides", "top", "imports", 73 }; 74 75 struct code_lines code_lines[CODE_MAX]; 76 77 #if defined(YYBTYACC) 78 int destructor = 0; /* =1 if at least one %destructor */ 79 80 static bucket *default_destructor[3] = 81 {0, 0, 0}; 82 83 #define UNTYPED_DEFAULT 0 84 #define TYPED_DEFAULT 1 85 #define TYPE_SPECIFIED 2 86 87 static bucket * 88 lookup_type_destructor(char *tag) 89 { 90 const char fmt[] = "%.*s destructor"; 91 char name[1024] = "\0"; 92 bucket *bp, **bpp = &default_destructor[TYPE_SPECIFIED]; 93 94 while ((bp = *bpp) != NULL) 95 { 96 if (bp->tag == tag) 97 return (bp); 98 bpp = &bp->link; 99 } 100 101 sprintf(name, fmt, (int)(sizeof(name) - sizeof(fmt)), tag); 102 *bpp = bp = make_bucket(name); 103 bp->tag = tag; 104 105 return (bp); 106 } 107 #endif /* defined(YYBTYACC) */ 108 109 static void 110 cachec(int c) 111 { 112 assert(cinc >= 0); 113 if (cinc >= cache_size) 114 { 115 cache_size += CACHE_SIZE; 116 cache = TREALLOC(char, cache, cache_size); 117 NO_SPACE(cache); 118 } 119 cache[cinc] = (char)c; 120 ++cinc; 121 } 122 123 typedef enum 124 { 125 ldSPC1, 126 ldSPC2, 127 ldNAME, 128 ldSPC3, 129 ldNUM, 130 ldSPC4, 131 ldFILE, 132 ldOK, 133 ldERR 134 } 135 LINE_DIR; 136 137 /* 138 * Expect this pattern: 139 * /^[[:space:]]*#[[:space:]]* 140 * line[[:space:]]+ 141 * [[:digit:]]+ 142 * ([[:space:]]*|[[:space:]]+"[^"]+")/ 143 */ 144 static int 145 line_directive(void) 146 { 147 #define UNLESS(what) if (what) { ld = ldERR; break; } 148 int n; 149 int line_1st = -1; 150 int name_1st = -1; 151 int name_end = -1; 152 LINE_DIR ld = ldSPC1; 153 for (n = 0; (ld <= ldOK) && (line[n] != '\0'); ++n) 154 { 155 int ch = UCH(line[n]); 156 switch (ld) 157 { 158 case ldSPC1: 159 if (isspace(UCH(ch))) 160 { 161 break; 162 } 163 else 164 UNLESS(ch != '#'); 165 ld = ldSPC2; 166 break; 167 case ldSPC2: 168 if (isspace(UCH(ch))) 169 { 170 break; 171 } 172 /* FALLTHRU */ 173 case ldNAME: 174 UNLESS(strncmp(line + n, "line", 4)); 175 n += 4; 176 if (line[n] == '\0') 177 { 178 ld = ldOK; 179 break; 180 } 181 else 182 UNLESS(!isspace(UCH(line[n]))); 183 ld = ldSPC3; 184 break; 185 case ldSPC3: 186 if (isspace(UCH(ch))) 187 { 188 break; 189 } 190 else 191 UNLESS(!isdigit(UCH(ch))); 192 line_1st = n; 193 ld = ldNUM; /* this is needed, but cppcheck says no... */ 194 /* FALLTHRU */ 195 case ldNUM: 196 if (isdigit(UCH(ch))) 197 { 198 break; 199 } 200 else 201 UNLESS(!isspace(UCH(ch))); 202 ld = ldSPC4; 203 break; 204 case ldSPC4: 205 if (isspace(UCH(ch))) 206 { 207 break; 208 } 209 else 210 UNLESS(ch != '"'); 211 UNLESS(line[n + 1] == '"'); 212 ld = ldFILE; 213 name_1st = n; 214 break; 215 case ldFILE: 216 if (ch != '"') 217 { 218 break; 219 } 220 ld = ldOK; 221 name_end = n; 222 /* FALLTHRU */ 223 case ldERR: 224 case ldOK: 225 break; 226 } 227 } 228 229 if (ld == ldOK) 230 { 231 size_t need = (size_t) (name_end - name_1st); 232 if ((long)need > (long)input_file_name_len) 233 { 234 input_file_name_len = ((need + 1) * 3) / 2; 235 input_file_name = TREALLOC(char, input_file_name, input_file_name_len); 236 NO_SPACE(input_file_name); 237 } 238 if ((long)need > 0) 239 { 240 memcpy(input_file_name, line + name_1st + 1, need - 1); 241 input_file_name[need - 1] = '\0'; 242 } 243 else 244 { 245 input_file_name[0] = '\0'; 246 } 247 } 248 249 if (ld >= ldNUM && ld < ldERR) 250 { 251 if (line_1st >= 0) 252 { 253 lineno = (int)strtol(line + line_1st, NULL, 10) - 1; 254 } 255 else 256 { 257 lineno = 0; 258 } 259 } 260 261 return (ld == ldOK); 262 #undef UNLESS 263 } 264 265 static void 266 get_line(void) 267 { 268 FILE *f = input_file; 269 270 do 271 { 272 int c; 273 int i; 274 275 if (saw_eof || (c = getc(f)) == EOF) 276 { 277 if (line) 278 { 279 FREE(line); 280 line = 0; 281 } 282 cptr = 0; 283 saw_eof = 1; 284 return; 285 } 286 287 if (line == NULL || linesize != (LINESIZE + 1)) 288 { 289 if (line) 290 FREE(line); 291 linesize = LINESIZE + 1; 292 line = TMALLOC(char, linesize); 293 NO_SPACE(line); 294 } 295 296 i = 0; 297 ++lineno; 298 for (;;) 299 { 300 line[i++] = (char)c; 301 if (c == '\n') 302 break; 303 if ((i + 3) >= linesize) 304 { 305 linesize += LINESIZE; 306 line = TREALLOC(char, line, linesize); 307 NO_SPACE(line); 308 } 309 c = getc(f); 310 if (c == EOF) 311 { 312 line[i++] = '\n'; 313 saw_eof = 1; 314 break; 315 } 316 } 317 line[i] = '\0'; 318 } 319 while (line_directive()); 320 cptr = line; 321 return; 322 } 323 324 static char * 325 dup_line(void) 326 { 327 char *p, *s, *t; 328 329 if (line == NULL) 330 return (NULL); 331 s = line; 332 while (*s != '\n') 333 ++s; 334 p = TMALLOC(char, s - line + 1); 335 NO_SPACE(p); 336 337 s = line; 338 t = p; 339 while ((*t++ = *s++) != '\n') 340 continue; 341 return (p); 342 } 343 344 static void 345 skip_comment(void) 346 { 347 char *s; 348 struct ainfo a; 349 a.a_lineno = lineno; 350 a.a_line = dup_line(); 351 a.a_cptr = a.a_line + (cptr - line); 352 353 s = cptr + 2; 354 for (;;) 355 { 356 if (*s == '*' && s[1] == '/') 357 { 358 cptr = s + 2; 359 FREE(a.a_line); 360 return; 361 } 362 if (*s == '\n') 363 { 364 get_line(); 365 if (line == NULL) 366 unterminated_comment(&a); 367 s = cptr; 368 } 369 else 370 ++s; 371 } 372 } 373 374 static int 375 next_inline(void) 376 { 377 char *s; 378 379 if (line == NULL) 380 { 381 get_line(); 382 if (line == NULL) 383 return (EOF); 384 } 385 386 s = cptr; 387 for (;;) 388 { 389 switch (*s) 390 { 391 case '/': 392 if (s[1] == '*') 393 { 394 cptr = s; 395 skip_comment(); 396 s = cptr; 397 break; 398 } 399 else if (s[1] == '/') 400 { 401 get_line(); 402 if (line == NULL) 403 return (EOF); 404 s = cptr; 405 break; 406 } 407 /* FALLTHRU */ 408 409 default: 410 cptr = s; 411 return (*s); 412 } 413 } 414 } 415 416 static int 417 nextc(void) 418 { 419 int ch; 420 int finish = 0; 421 422 do 423 { 424 switch (ch = next_inline()) 425 { 426 case '\n': 427 get_line(); 428 break; 429 case ' ': 430 case '\t': 431 case '\f': 432 case '\r': 433 case '\v': 434 case ',': 435 case ';': 436 ++cptr; 437 break; 438 case '\\': 439 ch = '%'; 440 /* FALLTHRU */ 441 default: 442 finish = 1; 443 break; 444 } 445 } 446 while (!finish); 447 448 return ch; 449 } 450 /* *INDENT-OFF* */ 451 static struct keyword 452 { 453 char name[16]; 454 int token; 455 } 456 keywords[] = { 457 { "binary", NONASSOC }, 458 { "code", XCODE }, 459 { "debug", XXXDEBUG }, 460 #if defined(YYBTYACC) 461 { "destructor", DESTRUCTOR }, 462 #endif 463 { "error-verbose",ERROR_VERBOSE }, 464 { "expect", EXPECT }, 465 { "expect-rr", EXPECT_RR }, 466 { "ident", IDENT }, 467 #if defined(YYBTYACC) 468 { "initial-action", INITIAL_ACTION }, 469 #endif 470 { "left", LEFT }, 471 { "lex-param", LEX_PARAM }, 472 #if defined(YYBTYACC) 473 { "locations", LOCATIONS }, 474 #endif 475 { "nonassoc", NONASSOC }, 476 { "parse-param", PARSE_PARAM }, 477 { "pure-parser", PURE_PARSER }, 478 { "right", RIGHT }, 479 { "start", START }, 480 { "term", TOKEN }, 481 { "token", TOKEN }, 482 { "token-table", TOKEN_TABLE }, 483 { "type", TYPE }, 484 { "union", UNION }, 485 { "yacc", POSIX_YACC }, 486 }; 487 /* *INDENT-ON* */ 488 489 static int 490 compare_keys(const void *a, const void *b) 491 { 492 const struct keyword *p = (const struct keyword *)a; 493 const struct keyword *q = (const struct keyword *)b; 494 return strcmp(p->name, q->name); 495 } 496 497 static int 498 keyword(void) 499 { 500 int c; 501 char *t_cptr = cptr; 502 503 c = *++cptr; 504 if (isalpha(UCH(c))) 505 { 506 struct keyword *key; 507 508 cinc = 0; 509 for (;;) 510 { 511 if (isalpha(UCH(c))) 512 { 513 if (isupper(UCH(c))) 514 c = tolower(c); 515 cachec(c); 516 } 517 else if (isdigit(UCH(c)) 518 || c == '-' 519 || c == '.' 520 || c == '$') 521 { 522 cachec(c); 523 } 524 else if (c == '_') 525 { 526 /* treat keywords spelled with '_' as if it were '-' */ 527 cachec('-'); 528 } 529 else 530 { 531 break; 532 } 533 c = *++cptr; 534 } 535 cachec(NUL); 536 537 if ((key = bsearch(cache, keywords, 538 sizeof(keywords) / sizeof(*key), 539 sizeof(*key), compare_keys))) 540 return key->token; 541 } 542 else 543 { 544 ++cptr; 545 if (c == L_CURL) 546 return (TEXT); 547 if (c == '%' || c == '\\') 548 return (MARK); 549 if (c == '<') 550 return (LEFT); 551 if (c == '>') 552 return (RIGHT); 553 if (c == '0') 554 return (TOKEN); 555 if (c == '2') 556 return (NONASSOC); 557 } 558 syntax_error(lineno, line, t_cptr); 559 /*NOTREACHED */ 560 } 561 562 563 static void 564 copy_ident(void) 565 { 566 int c; 567 FILE *f = output_file; 568 569 c = nextc(); 570 if (c == EOF) 571 unexpected_EOF(); 572 if (c != '"') 573 syntax_error(lineno, line, cptr); 574 ++outline; 575 fprintf(f, "#ident \""); 576 for (;;) 577 { 578 c = *++cptr; 579 if (c == '\n') 580 { 581 fprintf(f, "\"\n"); 582 return; 583 } 584 putc(c, f); 585 if (c == '"') 586 { 587 putc('\n', f); 588 ++cptr; 589 return; 590 } 591 } 592 } 593 594 static char * 595 copy_string(int quote) 596 { 597 struct mstring *temp = msnew(); 598 struct ainfo a; 599 a.a_lineno = lineno; 600 a.a_line = dup_line(); 601 a.a_cptr = a.a_line + (cptr - line - 1); 602 603 for (;;) 604 { 605 int c = *cptr++; 606 607 mputc(temp, c); 608 if (c == quote) 609 { 610 FREE(a.a_line); 611 return msdone(temp); 612 } 613 if (c == '\n') 614 unterminated_string(&a); 615 if (c == '\\') 616 { 617 c = *cptr++; 618 mputc(temp, c); 619 if (c == '\n') 620 { 621 get_line(); 622 if (line == NULL) 623 unterminated_string(&a); 624 } 625 } 626 } 627 } 628 629 static char * 630 copy_comment(void) 631 { 632 struct mstring *temp = msnew(); 633 int c; 634 635 c = *cptr; 636 if (c == '/') 637 { 638 mputc(temp, '*'); 639 while ((c = *++cptr) != '\n') 640 { 641 mputc(temp, c); 642 if (c == '*' && cptr[1] == '/') 643 mputc(temp, ' '); 644 } 645 mputc(temp, '*'); 646 mputc(temp, '/'); 647 } 648 else if (c == '*') 649 { 650 struct ainfo a; 651 a.a_lineno = lineno; 652 a.a_line = dup_line(); 653 a.a_cptr = a.a_line + (cptr - line - 1); 654 655 mputc(temp, c); 656 ++cptr; 657 for (;;) 658 { 659 c = *cptr++; 660 mputc(temp, c); 661 if (c == '*' && *cptr == '/') 662 { 663 mputc(temp, '/'); 664 ++cptr; 665 FREE(a.a_line); 666 return msdone(temp); 667 } 668 if (c == '\n') 669 { 670 get_line(); 671 if (line == NULL) 672 unterminated_comment(&a); 673 } 674 } 675 } 676 return msdone(temp); 677 } 678 679 static int 680 check_key(int pos) 681 { 682 const char *key = code_keys[pos]; 683 while (*cptr && *key) 684 if (*key++ != *cptr++) 685 return 0; 686 if (*key || (!isspace(UCH(*cptr)) && *cptr != L_CURL)) 687 return 0; 688 cptr--; 689 return 1; 690 } 691 692 static void 693 copy_code(void) 694 { 695 int c; 696 int curl; 697 int cline; 698 int on_line = 0; 699 int pos = CODE_HEADER; 700 struct mstring *code_mstr; 701 702 /* read %code <keyword> { */ 703 for (;;) 704 { 705 c = *++cptr; 706 if (c == EOF) 707 unexpected_EOF(); 708 if (isspace(UCH(c))) 709 continue; 710 711 if (c == L_CURL) 712 break; 713 714 if (pos == CODE_HEADER) 715 { 716 switch (UCH(c)) 717 { 718 case 'r': 719 pos = CODE_REQUIRES; 720 break; 721 case 'p': 722 pos = CODE_PROVIDES; 723 break; 724 case 't': 725 pos = CODE_TOP; 726 break; 727 case 'i': 728 pos = CODE_IMPORTS; 729 break; 730 default: 731 break; 732 } 733 734 if (pos == -1 || !check_key(pos)) 735 { 736 syntax_error(lineno, line, cptr); 737 /*NOTREACHED */ 738 } 739 } 740 } 741 742 cptr++; /* skip initial curl */ 743 while (*cptr && isspace(UCH(*cptr))) /* skip space */ 744 cptr++; 745 curl = 1; /* nesting count */ 746 747 /* gather text */ 748 code_lines[pos].name = code_keys[pos]; 749 if ((cline = (int)code_lines[pos].num) != 0) 750 { 751 code_mstr = msrenew(code_lines[pos].lines); 752 } 753 else 754 { 755 code_mstr = msnew(); 756 } 757 cline++; 758 msprintf(code_mstr, line_format, lineno, input_file_name); 759 for (;;) 760 { 761 c = *cptr++; 762 switch (c) 763 { 764 case '\0': 765 get_line(); 766 if (line == NULL) 767 { 768 unexpected_EOF(); 769 /*NOTREACHED */ 770 } 771 continue; 772 case '\n': 773 cline++; 774 on_line = 0; 775 break; 776 case L_CURL: 777 curl++; 778 break; 779 case R_CURL: 780 if (--curl == 0) 781 { 782 if (on_line > 1) 783 { 784 mputc(code_mstr, '\n'); 785 cline++; 786 } 787 code_lines[pos].lines = msdone(code_mstr); 788 code_lines[pos].num = (size_t) cline; 789 return; 790 } 791 break; 792 default: 793 break; 794 } 795 mputc(code_mstr, c); 796 on_line++; 797 } 798 } 799 800 static void 801 copy_text(void) 802 { 803 int c; 804 FILE *f = text_file; 805 int need_newline = 0; 806 struct ainfo a; 807 a.a_lineno = lineno; 808 a.a_line = dup_line(); 809 a.a_cptr = a.a_line + (cptr - line - 2); 810 811 if (*cptr == '\n') 812 { 813 get_line(); 814 if (line == NULL) 815 unterminated_text(&a); 816 } 817 if (!lflag) 818 fprintf(f, line_format, lineno, input_file_name); 819 820 loop: 821 c = *cptr++; 822 switch (c) 823 { 824 case '\n': 825 putc('\n', f); 826 need_newline = 0; 827 get_line(); 828 if (line) 829 goto loop; 830 unterminated_text(&a); 831 832 case '\'': 833 case '"': 834 putc(c, f); 835 { 836 char *s = copy_string(c); 837 fputs(s, f); 838 free(s); 839 } 840 need_newline = 1; 841 goto loop; 842 843 case '/': 844 putc(c, f); 845 { 846 char *s = copy_comment(); 847 fputs(s, f); 848 free(s); 849 } 850 need_newline = 1; 851 goto loop; 852 853 case '%': 854 case '\\': 855 if (*cptr == R_CURL) 856 { 857 if (need_newline) 858 putc('\n', f); 859 ++cptr; 860 FREE(a.a_line); 861 return; 862 } 863 /* FALLTHRU */ 864 865 default: 866 putc(c, f); 867 need_newline = 1; 868 goto loop; 869 } 870 } 871 872 static void 873 puts_both(const char *s) 874 { 875 fputs(s, text_file); 876 if (dflag) 877 fputs(s, union_file); 878 } 879 880 static void 881 putc_both(int c) 882 { 883 putc(c, text_file); 884 if (dflag) 885 putc(c, union_file); 886 } 887 888 static void 889 copy_union(void) 890 { 891 int c; 892 int depth; 893 struct ainfo a; 894 a.a_lineno = lineno; 895 a.a_line = dup_line(); 896 a.a_cptr = a.a_line + (cptr - line - 6); 897 898 if (unionized) 899 over_unionized(cptr - 6); 900 unionized = 1; 901 902 puts_both("#ifdef YYSTYPE\n"); 903 puts_both("#undef YYSTYPE_IS_DECLARED\n"); 904 puts_both("#define YYSTYPE_IS_DECLARED 1\n"); 905 puts_both("#endif\n"); 906 puts_both("#ifndef YYSTYPE_IS_DECLARED\n"); 907 puts_both("#define YYSTYPE_IS_DECLARED 1\n"); 908 909 if (!lflag) 910 fprintf(text_file, line_format, lineno, input_file_name); 911 puts_both("typedef union"); 912 913 depth = 0; 914 loop: 915 c = *cptr++; 916 putc_both(c); 917 switch (c) 918 { 919 case '\n': 920 get_line(); 921 if (line == NULL) 922 unterminated_union(&a); 923 goto loop; 924 925 case L_CURL: 926 ++depth; 927 goto loop; 928 929 case R_CURL: 930 if (--depth == 0) 931 { 932 puts_both(" YYSTYPE;\n"); 933 puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n"); 934 FREE(a.a_line); 935 return; 936 } 937 goto loop; 938 939 case '\'': 940 case '"': 941 { 942 char *s = copy_string(c); 943 puts_both(s); 944 free(s); 945 } 946 goto loop; 947 948 case '/': 949 { 950 char *s = copy_comment(); 951 puts_both(s); 952 free(s); 953 } 954 goto loop; 955 956 default: 957 goto loop; 958 } 959 } 960 961 static char * 962 after_blanks(char *s) 963 { 964 while (*s != '\0' && isspace(UCH(*s))) 965 ++s; 966 return s; 967 } 968 969 /* 970 * Trim leading/trailing blanks, and collapse multiple embedded blanks to a 971 * single space. Return index to last character in the buffer. 972 */ 973 static int 974 trim_blanks(char *buffer) 975 { 976 if (*buffer != '\0') 977 { 978 char *d = buffer; 979 char *s = after_blanks(d); 980 981 while ((*d++ = *s++) != '\0') 982 { 983 ; 984 } 985 986 --d; 987 while ((--d != buffer) && isspace(UCH(*d))) 988 *d = '\0'; 989 990 for (s = d = buffer; (*d++ = *s++) != '\0';) 991 { 992 if (isspace(UCH(*s))) 993 { 994 *s = ' '; 995 while (isspace(UCH(*s))) 996 { 997 *s++ = ' '; 998 } 999 --s; 1000 } 1001 } 1002 } 1003 1004 return (int)strlen(buffer) - 1; 1005 } 1006 1007 /* 1008 * Scan forward in the current line-buffer looking for a right-curly bracket. 1009 * 1010 * Parameters begin with a left-curly bracket, and continue until there are no 1011 * more interesting characters after the last right-curly bracket on the 1012 * current line. Bison documents parameters as separated like this: 1013 * {type param1} {type2 param2} 1014 * but also accepts commas (although some versions of bison mishandle this) 1015 * {type param1, type2 param2} 1016 */ 1017 static int 1018 more_curly(void) 1019 { 1020 char *save = cptr; 1021 int result = 0; 1022 int finish = 0; 1023 do 1024 { 1025 switch (next_inline()) 1026 { 1027 case 0: 1028 case '\n': 1029 finish = 1; 1030 break; 1031 case R_CURL: 1032 finish = 1; 1033 result = 1; 1034 break; 1035 } 1036 ++cptr; 1037 } 1038 while (!finish); 1039 cptr = save; 1040 return result; 1041 } 1042 1043 static void 1044 save_param(int k, char *buffer, int name, int type2) 1045 { 1046 param *head, *p; 1047 1048 p = TMALLOC(param, 1); 1049 NO_SPACE(p); 1050 1051 p->type2 = strdup(buffer + type2); 1052 NO_SPACE(p->type2); 1053 buffer[type2] = '\0'; 1054 (void)trim_blanks(p->type2); 1055 1056 p->name = strdup(buffer + name); 1057 NO_SPACE(p->name); 1058 buffer[name] = '\0'; 1059 (void)trim_blanks(p->name); 1060 1061 p->type = strdup(buffer); 1062 NO_SPACE(p->type); 1063 (void)trim_blanks(p->type); 1064 1065 if (k == LEX_PARAM) 1066 head = lex_param; 1067 else 1068 head = parse_param; 1069 1070 if (head != NULL) 1071 { 1072 while (head->next) 1073 head = head->next; 1074 head->next = p; 1075 } 1076 else 1077 { 1078 if (k == LEX_PARAM) 1079 lex_param = p; 1080 else 1081 parse_param = p; 1082 } 1083 p->next = NULL; 1084 } 1085 1086 /* 1087 * Keep a linked list of parameters. This may be multi-line, if the trailing 1088 * right-curly bracket is absent. 1089 */ 1090 static void 1091 copy_param(int k) 1092 { 1093 int c; 1094 int name, type2; 1095 int curly = 0; 1096 char *buf = 0; 1097 int i = -1; 1098 size_t buf_size = 0; 1099 int st_lineno = lineno; 1100 char *comma; 1101 1102 do 1103 { 1104 int state = curly; 1105 c = next_inline(); 1106 switch (c) 1107 { 1108 case EOF: 1109 unexpected_EOF(); 1110 break; 1111 case L_CURL: 1112 if (curly == 1) 1113 { 1114 goto oops; 1115 } 1116 curly = 1; 1117 st_lineno = lineno; 1118 break; 1119 case R_CURL: 1120 if (curly != 1) 1121 { 1122 goto oops; 1123 } 1124 curly = 2; 1125 break; 1126 case '\n': 1127 if (curly == 0) 1128 { 1129 goto oops; 1130 } 1131 break; 1132 case '%': 1133 if ((curly == 1) && (cptr == line)) 1134 { 1135 lineno = st_lineno; 1136 missing_brace(); 1137 } 1138 /* FALLTHRU */ 1139 case '"': 1140 case '\'': 1141 goto oops; 1142 default: 1143 if (curly == 0 && !isspace(UCH(c))) 1144 { 1145 goto oops; 1146 } 1147 break; 1148 } 1149 if (buf == 0) 1150 { 1151 buf_size = (size_t) linesize; 1152 buf = TMALLOC(char, buf_size); 1153 NO_SPACE(buf); 1154 } 1155 else if (c == '\n') 1156 { 1157 char *tmp; 1158 1159 get_line(); 1160 if (line == NULL) 1161 unexpected_EOF(); 1162 --cptr; 1163 buf_size += (size_t) linesize; 1164 tmp = TREALLOC(char, buf, buf_size); 1165 NO_SPACE(tmp); 1166 buf = tmp; 1167 } 1168 if (curly) 1169 { 1170 if ((state == 2) && (c == L_CURL)) 1171 { 1172 buf[++i] = ','; 1173 } 1174 else if ((state == 2) && isspace(UCH(c))) 1175 { 1176 ; 1177 } 1178 else if ((c != L_CURL) && (c != R_CURL)) 1179 { 1180 buf[++i] = (char)c; 1181 } 1182 } 1183 cptr++; 1184 } 1185 while (curly < 2 || more_curly()); 1186 1187 if (i == 0) 1188 { 1189 if (curly == 1) 1190 { 1191 lineno = st_lineno; 1192 missing_brace(); 1193 } 1194 goto oops; 1195 } 1196 1197 buf[++i] = '\0'; 1198 (void)trim_blanks(buf); 1199 1200 comma = buf - 1; 1201 do 1202 { 1203 char *parms = (comma + 1); 1204 comma = strchr(parms, ','); 1205 if (comma != 0) 1206 *comma = '\0'; 1207 1208 (void)trim_blanks(parms); 1209 i = (int)strlen(parms) - 1; 1210 if (i < 0) 1211 { 1212 goto oops; 1213 } 1214 1215 if (parms[i] == ']') 1216 { 1217 int level = 1; 1218 while (i >= 0) 1219 { 1220 char ch = parms[i--]; 1221 if (ch == ']') 1222 { 1223 ++level; 1224 } 1225 else if (ch == '[') 1226 { 1227 if (--level <= 1) 1228 { 1229 ++i; 1230 break; 1231 } 1232 } 1233 } 1234 if (i <= 0) 1235 unexpected_EOF(); 1236 type2 = i--; 1237 } 1238 else 1239 { 1240 type2 = i + 1; 1241 } 1242 1243 while (i > 0 && (isalnum(UCH(parms[i])) || UCH(parms[i]) == '_')) 1244 i--; 1245 1246 if (!isspace(UCH(parms[i])) && parms[i] != '*') 1247 goto oops; 1248 1249 name = i + 1; 1250 1251 save_param(k, parms, name, type2); 1252 } 1253 while (comma != 0); 1254 FREE(buf); 1255 return; 1256 1257 oops: 1258 FREE(buf); 1259 syntax_error(lineno, line, cptr); 1260 } 1261 1262 static int 1263 hexval(int c) 1264 { 1265 if (c >= '0' && c <= '9') 1266 return (c - '0'); 1267 if (c >= 'A' && c <= 'F') 1268 return (c - 'A' + 10); 1269 if (c >= 'a' && c <= 'f') 1270 return (c - 'a' + 10); 1271 return (-1); 1272 } 1273 1274 static bucket * 1275 get_literal(void) 1276 { 1277 int c, quote; 1278 int i; 1279 int n; 1280 char *s; 1281 bucket *bp; 1282 struct ainfo a; 1283 a.a_lineno = lineno; 1284 a.a_line = dup_line(); 1285 a.a_cptr = a.a_line + (cptr - line); 1286 1287 quote = *cptr++; 1288 cinc = 0; 1289 for (;;) 1290 { 1291 c = *cptr++; 1292 if (c == quote) 1293 break; 1294 if (c == '\n') 1295 unterminated_string(&a); 1296 if (c == '\\') 1297 { 1298 char *c_cptr = cptr - 1; 1299 1300 c = *cptr++; 1301 switch (c) 1302 { 1303 case '\n': 1304 get_line(); 1305 if (line == NULL) 1306 unterminated_string(&a); 1307 continue; 1308 1309 case '0': 1310 case '1': 1311 case '2': 1312 case '3': 1313 case '4': 1314 case '5': 1315 case '6': 1316 case '7': 1317 n = c - '0'; 1318 c = *cptr; 1319 if (IS_OCTAL(c)) 1320 { 1321 n = (n << 3) + (c - '0'); 1322 c = *++cptr; 1323 if (IS_OCTAL(c)) 1324 { 1325 n = (n << 3) + (c - '0'); 1326 ++cptr; 1327 } 1328 } 1329 if (n > MAXCHAR) 1330 illegal_character(c_cptr); 1331 c = n; 1332 break; 1333 1334 case 'x': 1335 c = *cptr++; 1336 n = hexval(c); 1337 if (n < 0 || n >= 16) 1338 illegal_character(c_cptr); 1339 for (;;) 1340 { 1341 c = *cptr; 1342 i = hexval(c); 1343 if (i < 0 || i >= 16) 1344 break; 1345 ++cptr; 1346 n = (n << 4) + i; 1347 if (n > MAXCHAR) 1348 illegal_character(c_cptr); 1349 } 1350 c = n; 1351 break; 1352 1353 case 'a': 1354 c = 7; 1355 break; 1356 case 'b': 1357 c = '\b'; 1358 break; 1359 case 'f': 1360 c = '\f'; 1361 break; 1362 case 'n': 1363 c = '\n'; 1364 break; 1365 case 'r': 1366 c = '\r'; 1367 break; 1368 case 't': 1369 c = '\t'; 1370 break; 1371 case 'v': 1372 c = '\v'; 1373 break; 1374 } 1375 } 1376 cachec(c); 1377 } 1378 FREE(a.a_line); 1379 1380 n = cinc; 1381 s = TMALLOC(char, n); 1382 NO_SPACE(s); 1383 1384 for (i = 0; i < n; ++i) 1385 s[i] = cache[i]; 1386 1387 cinc = 0; 1388 if (n == 1) 1389 cachec('\''); 1390 else 1391 cachec('"'); 1392 1393 for (i = 0; i < n; ++i) 1394 { 1395 c = UCH(s[i]); 1396 if (c == '\\' || c == cache[0]) 1397 { 1398 cachec('\\'); 1399 cachec(c); 1400 } 1401 else if (isprint(UCH(c))) 1402 cachec(c); 1403 else 1404 { 1405 cachec('\\'); 1406 switch (c) 1407 { 1408 case 7: 1409 cachec('a'); 1410 break; 1411 case '\b': 1412 cachec('b'); 1413 break; 1414 case '\f': 1415 cachec('f'); 1416 break; 1417 case '\n': 1418 cachec('n'); 1419 break; 1420 case '\r': 1421 cachec('r'); 1422 break; 1423 case '\t': 1424 cachec('t'); 1425 break; 1426 case '\v': 1427 cachec('v'); 1428 break; 1429 default: 1430 cachec(((c >> 6) & 7) + '0'); 1431 cachec(((c >> 3) & 7) + '0'); 1432 cachec((c & 7) + '0'); 1433 break; 1434 } 1435 } 1436 } 1437 1438 if (n == 1) 1439 cachec('\''); 1440 else 1441 cachec('"'); 1442 1443 cachec(NUL); 1444 bp = lookup(cache); 1445 bp->class = TERM; 1446 if (n == 1 && bp->value == UNDEFINED) 1447 bp->value = UCH(*s); 1448 FREE(s); 1449 1450 return (bp); 1451 } 1452 1453 static int 1454 is_reserved(char *name) 1455 { 1456 if (strcmp(name, ".") == 0 || 1457 strcmp(name, "$accept") == 0 || 1458 strcmp(name, "$end") == 0) 1459 return (1); 1460 1461 if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2]))) 1462 { 1463 char *s = name + 3; 1464 1465 while (isdigit(UCH(*s))) 1466 ++s; 1467 if (*s == NUL) 1468 return (1); 1469 } 1470 1471 return (0); 1472 } 1473 1474 static bucket * 1475 get_name(void) 1476 { 1477 int c; 1478 1479 cinc = 0; 1480 for (c = *cptr; IS_IDENT(c); c = *++cptr) 1481 cachec(c); 1482 cachec(NUL); 1483 1484 if (is_reserved(cache)) 1485 used_reserved(cache); 1486 1487 return (lookup(cache)); 1488 } 1489 1490 static Value_t 1491 get_number(void) 1492 { 1493 int c; 1494 long n; 1495 char *base = cptr; 1496 1497 n = 0; 1498 for (c = *cptr; isdigit(UCH(c)); c = *++cptr) 1499 { 1500 n = (10 * n + (c - '0')); 1501 if (n > MAXYYINT) 1502 { 1503 syntax_error(lineno, line, base); 1504 /*NOTREACHED */ 1505 } 1506 } 1507 1508 return (Value_t)(n); 1509 } 1510 1511 static char * 1512 cache_tag(char *tag, size_t len) 1513 { 1514 int i; 1515 char *s; 1516 1517 for (i = 0; i < ntags; ++i) 1518 { 1519 if (strncmp(tag, tag_table[i], len) == 0 && 1520 tag_table[i][len] == NUL) 1521 return (tag_table[i]); 1522 } 1523 1524 if (ntags >= tagmax) 1525 { 1526 tagmax += 16; 1527 tag_table = 1528 (tag_table 1529 ? TREALLOC(char *, tag_table, tagmax) 1530 : TMALLOC(char *, tagmax)); 1531 NO_SPACE(tag_table); 1532 } 1533 1534 s = TMALLOC(char, len + 1); 1535 NO_SPACE(s); 1536 1537 strncpy(s, tag, len); 1538 s[len] = 0; 1539 tag_table[ntags++] = s; 1540 return s; 1541 } 1542 1543 static char * 1544 get_tag(void) 1545 { 1546 int c; 1547 int t_lineno = lineno; 1548 char *t_line = dup_line(); 1549 char *t_cptr = t_line + (cptr - line); 1550 1551 ++cptr; 1552 c = nextc(); 1553 if (c == EOF) 1554 unexpected_EOF(); 1555 if (!IS_NAME1(c)) 1556 illegal_tag(t_lineno, t_line, t_cptr); 1557 1558 cinc = 0; 1559 do 1560 { 1561 cachec(c); 1562 c = *++cptr; 1563 } 1564 while (IS_IDENT(c)); 1565 cachec(NUL); 1566 1567 c = nextc(); 1568 if (c == EOF) 1569 unexpected_EOF(); 1570 if (c != '>') 1571 illegal_tag(t_lineno, t_line, t_cptr); 1572 ++cptr; 1573 1574 FREE(t_line); 1575 havetags = 1; 1576 return cache_tag(cache, (size_t) cinc); 1577 } 1578 1579 #if defined(YYBTYACC) 1580 static char * 1581 scan_id(void) 1582 { 1583 char *b = cptr; 1584 1585 while (IS_NAME2(UCH(*cptr))) 1586 cptr++; 1587 return cache_tag(b, (size_t) (cptr - b)); 1588 } 1589 #endif 1590 1591 static void 1592 declare_tokens(int assoc) 1593 { 1594 int c; 1595 bucket *bp; 1596 Value_t value; 1597 char *tag = 0; 1598 1599 if (assoc != TOKEN) 1600 ++prec; 1601 1602 c = nextc(); 1603 if (c == EOF) 1604 unexpected_EOF(); 1605 if (c == '<') 1606 { 1607 tag = get_tag(); 1608 c = nextc(); 1609 if (c == EOF) 1610 unexpected_EOF(); 1611 } 1612 1613 for (;;) 1614 { 1615 if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$') 1616 bp = get_name(); 1617 else if (c == '\'' || c == '"') 1618 bp = get_literal(); 1619 else 1620 return; 1621 1622 if (bp == goal) 1623 tokenized_start(bp->name); 1624 bp->class = TERM; 1625 1626 if (tag) 1627 { 1628 if (bp->tag && tag != bp->tag) 1629 retyped_warning(bp->name); 1630 bp->tag = tag; 1631 } 1632 1633 if (assoc != TOKEN) 1634 { 1635 if (bp->prec && prec != bp->prec) 1636 reprec_warning(bp->name); 1637 bp->assoc = (Assoc_t)assoc; 1638 bp->prec = prec; 1639 } 1640 1641 c = nextc(); 1642 if (c == EOF) 1643 unexpected_EOF(); 1644 1645 if (isdigit(UCH(c))) 1646 { 1647 value = get_number(); 1648 if (bp->value != UNDEFINED && value != bp->value) 1649 revalued_warning(bp->name); 1650 bp->value = value; 1651 c = nextc(); 1652 if (c == EOF) 1653 unexpected_EOF(); 1654 } 1655 } 1656 } 1657 1658 /* 1659 * %expect requires special handling 1660 * as it really isn't part of the yacc 1661 * grammar only a flag for yacc proper. 1662 */ 1663 static void 1664 declare_expect(int assoc) 1665 { 1666 int c; 1667 1668 if (assoc != EXPECT && assoc != EXPECT_RR) 1669 ++prec; 1670 1671 /* 1672 * Stay away from nextc - doesn't 1673 * detect EOL and will read to EOF. 1674 */ 1675 c = *++cptr; 1676 if (c == EOF) 1677 unexpected_EOF(); 1678 1679 for (;;) 1680 { 1681 if (isdigit(UCH(c))) 1682 { 1683 if (assoc == EXPECT) 1684 SRexpect = get_number(); 1685 else 1686 RRexpect = get_number(); 1687 break; 1688 } 1689 /* 1690 * Looking for number before EOL. 1691 * Spaces, tabs, and numbers are ok, 1692 * words, punc., etc. are syntax errors. 1693 */ 1694 else if (c == '\n' || isalpha(UCH(c)) || !isspace(UCH(c))) 1695 { 1696 syntax_error(lineno, line, cptr); 1697 } 1698 else 1699 { 1700 c = *++cptr; 1701 if (c == EOF) 1702 unexpected_EOF(); 1703 } 1704 } 1705 } 1706 1707 #if defined(YYBTYACC) 1708 static void 1709 declare_argtypes(bucket *bp) 1710 { 1711 char *tags[MAXARGS]; 1712 int args = 0; 1713 1714 if (bp->args >= 0) 1715 retyped_warning(bp->name); 1716 cptr++; /* skip open paren */ 1717 for (;;) 1718 { 1719 int c = nextc(); 1720 if (c == EOF) 1721 unexpected_EOF(); 1722 if (c != '<') 1723 syntax_error(lineno, line, cptr); 1724 tags[args++] = get_tag(); 1725 c = nextc(); 1726 if (c == R_PAREN) 1727 break; 1728 if (c == EOF) 1729 unexpected_EOF(); 1730 } 1731 cptr++; /* skip close paren */ 1732 bp->args = args; 1733 bp->argnames = TMALLOC(char *, args); 1734 NO_SPACE(bp->argnames); 1735 bp->argtags = CALLOC(sizeof(char *), args + 1); 1736 NO_SPACE(bp->argtags); 1737 while (--args >= 0) 1738 { 1739 bp->argtags[args] = tags[args]; 1740 bp->argnames[args] = NULL; 1741 } 1742 } 1743 #endif 1744 1745 static void 1746 declare_types(void) 1747 { 1748 int c; 1749 bucket *bp = NULL; 1750 char *tag = NULL; 1751 1752 c = nextc(); 1753 if (c == EOF) 1754 unexpected_EOF(); 1755 if (c == '<') 1756 tag = get_tag(); 1757 1758 for (;;) 1759 { 1760 c = nextc(); 1761 if (c == EOF) 1762 unexpected_EOF(); 1763 if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$') 1764 { 1765 bp = get_name(); 1766 #if defined(YYBTYACC) 1767 if (nextc() == L_PAREN) 1768 declare_argtypes(bp); 1769 else 1770 bp->args = 0; 1771 #endif 1772 } 1773 else if (c == '\'' || c == '"') 1774 { 1775 bp = get_literal(); 1776 #if defined(YYBTYACC) 1777 bp->args = 0; 1778 #endif 1779 } 1780 else 1781 return; 1782 1783 if (tag) 1784 { 1785 if (bp->tag && tag != bp->tag) 1786 retyped_warning(bp->name); 1787 bp->tag = tag; 1788 } 1789 } 1790 } 1791 1792 static void 1793 declare_start(void) 1794 { 1795 int c; 1796 bucket *bp; 1797 1798 c = nextc(); 1799 if (c == EOF) 1800 unexpected_EOF(); 1801 if (!isalpha(UCH(c)) && c != '_' && c != '.' && c != '$') 1802 syntax_error(lineno, line, cptr); 1803 bp = get_name(); 1804 if (bp->class == TERM) 1805 terminal_start(bp->name); 1806 if (goal && goal != bp) 1807 restarted_warning(); 1808 goal = bp; 1809 } 1810 1811 static void 1812 read_declarations(void) 1813 { 1814 cache_size = CACHE_SIZE; 1815 cache = TMALLOC(char, cache_size); 1816 NO_SPACE(cache); 1817 1818 for (;;) 1819 { 1820 int k; 1821 int c = nextc(); 1822 1823 if (c == EOF) 1824 unexpected_EOF(); 1825 if (c != '%') 1826 syntax_error(lineno, line, cptr); 1827 switch (k = keyword()) 1828 { 1829 case MARK: 1830 return; 1831 1832 case IDENT: 1833 copy_ident(); 1834 break; 1835 1836 case XCODE: 1837 copy_code(); 1838 break; 1839 1840 case TEXT: 1841 copy_text(); 1842 break; 1843 1844 case UNION: 1845 copy_union(); 1846 break; 1847 1848 case TOKEN: 1849 case LEFT: 1850 case RIGHT: 1851 case NONASSOC: 1852 declare_tokens(k); 1853 break; 1854 1855 case EXPECT: 1856 case EXPECT_RR: 1857 declare_expect(k); 1858 break; 1859 1860 case TYPE: 1861 declare_types(); 1862 break; 1863 1864 case START: 1865 declare_start(); 1866 break; 1867 1868 case PURE_PARSER: 1869 pure_parser = 1; 1870 break; 1871 1872 case PARSE_PARAM: 1873 case LEX_PARAM: 1874 copy_param(k); 1875 break; 1876 1877 case TOKEN_TABLE: 1878 token_table = 1; 1879 break; 1880 1881 case ERROR_VERBOSE: 1882 error_verbose = 1; 1883 break; 1884 1885 #if defined(YYBTYACC) 1886 case LOCATIONS: 1887 locations = 1; 1888 break; 1889 1890 case DESTRUCTOR: 1891 destructor = 1; 1892 copy_destructor(); 1893 break; 1894 case INITIAL_ACTION: 1895 copy_initial_action(); 1896 break; 1897 #endif 1898 1899 case XXXDEBUG: 1900 /* XXX: FIXME */ 1901 break; 1902 1903 case POSIX_YACC: 1904 /* noop for bison compatibility. byacc is already designed to be posix 1905 * yacc compatible. */ 1906 break; 1907 } 1908 } 1909 } 1910 1911 static void 1912 initialize_grammar(void) 1913 { 1914 nitems = 4; 1915 maxitems = 300; 1916 1917 pitem = TMALLOC(bucket *, maxitems); 1918 NO_SPACE(pitem); 1919 1920 pitem[0] = 0; 1921 pitem[1] = 0; 1922 pitem[2] = 0; 1923 pitem[3] = 0; 1924 1925 nrules = 3; 1926 maxrules = 100; 1927 1928 plhs = TMALLOC(bucket *, maxrules); 1929 NO_SPACE(plhs); 1930 1931 plhs[0] = 0; 1932 plhs[1] = 0; 1933 plhs[2] = 0; 1934 1935 rprec = TMALLOC(Value_t, maxrules); 1936 NO_SPACE(rprec); 1937 1938 rprec[0] = 0; 1939 rprec[1] = 0; 1940 rprec[2] = 0; 1941 1942 rassoc = TMALLOC(Assoc_t, maxrules); 1943 NO_SPACE(rassoc); 1944 1945 rassoc[0] = TOKEN; 1946 rassoc[1] = TOKEN; 1947 rassoc[2] = TOKEN; 1948 } 1949 1950 static void 1951 expand_items(void) 1952 { 1953 maxitems += 300; 1954 pitem = TREALLOC(bucket *, pitem, maxitems); 1955 NO_SPACE(pitem); 1956 } 1957 1958 static void 1959 expand_rules(void) 1960 { 1961 maxrules += 100; 1962 1963 plhs = TREALLOC(bucket *, plhs, maxrules); 1964 NO_SPACE(plhs); 1965 1966 rprec = TREALLOC(Value_t, rprec, maxrules); 1967 NO_SPACE(rprec); 1968 1969 rassoc = TREALLOC(Assoc_t, rassoc, maxrules); 1970 NO_SPACE(rassoc); 1971 } 1972 1973 /* set immediately prior to where copy_args() could be called, and incremented by 1974 the various routines that will rescan the argument list as appropriate */ 1975 static int rescan_lineno; 1976 #if defined(YYBTYACC) 1977 1978 static char * 1979 copy_args(int *alen) 1980 { 1981 struct mstring *s = msnew(); 1982 int depth = 0, len = 1; 1983 char c, quote = 0; 1984 struct ainfo a; 1985 1986 a.a_lineno = lineno; 1987 a.a_line = dup_line(); 1988 a.a_cptr = a.a_line + (cptr - line - 1); 1989 1990 while ((c = *cptr++) != R_PAREN || depth || quote) 1991 { 1992 if (c == ',' && !quote && !depth) 1993 { 1994 len++; 1995 mputc(s, 0); 1996 continue; 1997 } 1998 mputc(s, c); 1999 if (c == '\n') 2000 { 2001 get_line(); 2002 if (!line) 2003 { 2004 if (quote) 2005 unterminated_string(&a); 2006 else 2007 unterminated_arglist(&a); 2008 } 2009 } 2010 else if (quote) 2011 { 2012 if (c == quote) 2013 quote = 0; 2014 else if (c == '\\') 2015 { 2016 if (*cptr != '\n') 2017 mputc(s, *cptr++); 2018 } 2019 } 2020 else 2021 { 2022 if (c == L_PAREN) 2023 depth++; 2024 else if (c == R_PAREN) 2025 depth--; 2026 else if (c == '\"' || c == '\'') 2027 quote = c; 2028 } 2029 } 2030 if (alen) 2031 *alen = len; 2032 FREE(a.a_line); 2033 return msdone(s); 2034 } 2035 2036 static char * 2037 parse_id(char *p, char **save) 2038 { 2039 char *b; 2040 2041 while (isspace(UCH(*p))) 2042 if (*p++ == '\n') 2043 rescan_lineno++; 2044 if (!isalpha(UCH(*p)) && *p != '_') 2045 return NULL; 2046 b = p; 2047 while (IS_NAME2(UCH(*p))) 2048 p++; 2049 if (save) 2050 { 2051 *save = cache_tag(b, (size_t) (p - b)); 2052 } 2053 return p; 2054 } 2055 2056 static char * 2057 parse_int(char *p, int *save) 2058 { 2059 int neg = 0, val = 0; 2060 2061 while (isspace(UCH(*p))) 2062 if (*p++ == '\n') 2063 rescan_lineno++; 2064 if (*p == '-') 2065 { 2066 neg = 1; 2067 p++; 2068 } 2069 if (!isdigit(UCH(*p))) 2070 return NULL; 2071 while (isdigit(UCH(*p))) 2072 val = val * 10 + *p++ - '0'; 2073 if (neg) 2074 val = -val; 2075 if (save) 2076 *save = val; 2077 return p; 2078 } 2079 2080 static void 2081 parse_arginfo(bucket *a, char *args, int argslen) 2082 { 2083 char *p = args, *tmp; 2084 int i, redec = 0; 2085 2086 if (a->args >= 0) 2087 { 2088 if (a->args != argslen) 2089 arg_number_disagree_warning(rescan_lineno, a->name); 2090 redec = 1; 2091 } 2092 else 2093 { 2094 if ((a->args = argslen) == 0) 2095 return; 2096 a->argnames = TMALLOC(char *, argslen); 2097 NO_SPACE(a->argnames); 2098 a->argtags = TMALLOC(char *, argslen); 2099 NO_SPACE(a->argtags); 2100 } 2101 if (!args) 2102 return; 2103 for (i = 0; i < argslen; i++) 2104 { 2105 while (isspace(UCH(*p))) 2106 if (*p++ == '\n') 2107 rescan_lineno++; 2108 if (*p++ != '$') 2109 bad_formals(); 2110 while (isspace(UCH(*p))) 2111 if (*p++ == '\n') 2112 rescan_lineno++; 2113 if (*p == '<') 2114 { 2115 havetags = 1; 2116 if (!(p = parse_id(p + 1, &tmp))) 2117 bad_formals(); 2118 while (isspace(UCH(*p))) 2119 if (*p++ == '\n') 2120 rescan_lineno++; 2121 if (*p++ != '>') 2122 bad_formals(); 2123 if (redec) 2124 { 2125 if (a->argtags[i] != tmp) 2126 arg_type_disagree_warning(rescan_lineno, i + 1, a->name); 2127 } 2128 else 2129 a->argtags[i] = tmp; 2130 } 2131 else if (!redec) 2132 a->argtags[i] = NULL; 2133 if (!(p = parse_id(p, &a->argnames[i]))) 2134 bad_formals(); 2135 while (isspace(UCH(*p))) 2136 if (*p++ == '\n') 2137 rescan_lineno++; 2138 if (*p++) 2139 bad_formals(); 2140 } 2141 free(args); 2142 } 2143 2144 static char * 2145 compile_arg(char **theptr, char *yyvaltag) 2146 { 2147 char *p = *theptr; 2148 struct mstring *c = msnew(); 2149 int i, n; 2150 Value_t *offsets = NULL, maxoffset; 2151 bucket **rhs; 2152 2153 maxoffset = 0; 2154 n = 0; 2155 for (i = nitems - 1; pitem[i]; --i) 2156 { 2157 n++; 2158 if (pitem[i]->class != ARGUMENT) 2159 maxoffset++; 2160 } 2161 if (maxoffset > 0) 2162 { 2163 int j; 2164 2165 offsets = TMALLOC(Value_t, maxoffset + 1); 2166 NO_SPACE(offsets); 2167 2168 for (j = 0, i++; i < nitems; i++) 2169 if (pitem[i]->class != ARGUMENT) 2170 offsets[++j] = (Value_t)(i - nitems + 1); 2171 } 2172 rhs = pitem + nitems - 1; 2173 2174 if (yyvaltag) 2175 msprintf(c, "yyval.%s = ", yyvaltag); 2176 else 2177 msprintf(c, "yyval = "); 2178 while (*p) 2179 { 2180 if (*p == '$') 2181 { 2182 char *tag = NULL; 2183 if (*++p == '<') 2184 if (!(p = parse_id(++p, &tag)) || *p++ != '>') 2185 illegal_tag(rescan_lineno, NULL, NULL); 2186 if (isdigit(UCH(*p)) || *p == '-') 2187 { 2188 int val; 2189 if (!(p = parse_int(p, &val))) 2190 dollar_error(rescan_lineno, NULL, NULL); 2191 if (val <= 0) 2192 i = val - n; 2193 else if (val > maxoffset) 2194 { 2195 dollar_warning(rescan_lineno, val); 2196 i = val - maxoffset; 2197 } 2198 else if (maxoffset > 0) 2199 { 2200 i = offsets[val]; 2201 if (!tag && !(tag = rhs[i]->tag) && havetags) 2202 untyped_rhs(val, rhs[i]->name); 2203 } 2204 msprintf(c, "yystack.l_mark[%d]", i); 2205 if (tag) 2206 msprintf(c, ".%s", tag); 2207 else if (havetags) 2208 unknown_rhs(val); 2209 } 2210 else if (isalpha(UCH(*p)) || *p == '_') 2211 { 2212 char *arg; 2213 if (!(p = parse_id(p, &arg))) 2214 dollar_error(rescan_lineno, NULL, NULL); 2215 for (i = plhs[nrules]->args - 1; i >= 0; i--) 2216 if (arg == plhs[nrules]->argnames[i]) 2217 break; 2218 if (i < 0) 2219 unknown_arg_warning(rescan_lineno, "$", arg, NULL, NULL); 2220 else if (!tag) 2221 tag = plhs[nrules]->argtags[i]; 2222 msprintf(c, "yystack.l_mark[%d]", 2223 i - plhs[nrules]->args + 1 - n); 2224 if (tag) 2225 msprintf(c, ".%s", tag); 2226 else if (havetags) 2227 untyped_arg_warning(rescan_lineno, "$", arg); 2228 } 2229 else 2230 dollar_error(rescan_lineno, NULL, NULL); 2231 } 2232 else if (*p == '@') 2233 { 2234 at_error(rescan_lineno, NULL, NULL); 2235 } 2236 else 2237 { 2238 if (*p == '\n') 2239 rescan_lineno++; 2240 mputc(c, *p++); 2241 } 2242 } 2243 *theptr = p; 2244 if (maxoffset > 0) 2245 FREE(offsets); 2246 return msdone(c); 2247 } 2248 2249 static int 2250 can_elide_arg(char **theptr, char *yyvaltag) 2251 { 2252 char *p = *theptr; 2253 int rv = 0; 2254 int i, n = 0; 2255 Value_t *offsets = NULL, maxoffset = 0; 2256 bucket **rhs; 2257 char *tag = 0; 2258 2259 if (*p++ != '$') 2260 return 0; 2261 if (*p == '<') 2262 { 2263 if (!(p = parse_id(++p, &tag)) || *p++ != '>') 2264 return 0; 2265 } 2266 for (i = nitems - 1; pitem[i]; --i) 2267 { 2268 n++; 2269 if (pitem[i]->class != ARGUMENT) 2270 maxoffset++; 2271 } 2272 if (maxoffset > 0) 2273 { 2274 int j; 2275 2276 offsets = TMALLOC(Value_t, maxoffset + 1); 2277 NO_SPACE(offsets); 2278 2279 for (j = 0, i++; i < nitems; i++) 2280 if (pitem[i]->class != ARGUMENT) 2281 offsets[++j] = (Value_t)(i - nitems + 1); 2282 } 2283 rhs = pitem + nitems - 1; 2284 2285 if (isdigit(UCH(*p)) || *p == '-') 2286 { 2287 int val; 2288 if (!(p = parse_int(p, &val))) 2289 rv = 0; 2290 else 2291 { 2292 if (val <= 0) 2293 rv = 1 - val + n; 2294 else if (val > maxoffset) 2295 rv = 0; 2296 else 2297 { 2298 i = offsets[val]; 2299 rv = 1 - i; 2300 if (!tag) 2301 tag = rhs[i]->tag; 2302 } 2303 } 2304 } 2305 else if (isalpha(UCH(*p)) || *p == '_') 2306 { 2307 char *arg; 2308 if (!(p = parse_id(p, &arg))) 2309 { 2310 FREE(offsets); 2311 return 0; 2312 } 2313 for (i = plhs[nrules]->args - 1; i >= 0; i--) 2314 if (arg == plhs[nrules]->argnames[i]) 2315 break; 2316 if (i >= 0) 2317 { 2318 if (!tag) 2319 tag = plhs[nrules]->argtags[i]; 2320 rv = plhs[nrules]->args + n - i; 2321 } 2322 } 2323 if (tag && yyvaltag) 2324 { 2325 if (strcmp(tag, yyvaltag)) 2326 rv = 0; 2327 } 2328 else if (tag || yyvaltag) 2329 rv = 0; 2330 if (maxoffset > 0) 2331 FREE(offsets); 2332 if (p == 0 || *p || rv <= 0) 2333 return 0; 2334 *theptr = p + 1; 2335 return rv; 2336 } 2337 2338 #define ARG_CACHE_SIZE 1024 2339 static struct arg_cache 2340 { 2341 struct arg_cache *next; 2342 char *code; 2343 int rule; 2344 } 2345 *arg_cache[ARG_CACHE_SIZE]; 2346 2347 static int 2348 lookup_arg_cache(char *code) 2349 { 2350 struct arg_cache *entry; 2351 2352 entry = arg_cache[strnshash(code) % ARG_CACHE_SIZE]; 2353 while (entry) 2354 { 2355 if (!strnscmp(entry->code, code)) 2356 return entry->rule; 2357 entry = entry->next; 2358 } 2359 return -1; 2360 } 2361 2362 static void 2363 insert_arg_cache(char *code, int rule) 2364 { 2365 struct arg_cache *entry = NEW(struct arg_cache); 2366 int i; 2367 2368 NO_SPACE(entry); 2369 i = strnshash(code) % ARG_CACHE_SIZE; 2370 entry->code = code; 2371 entry->rule = rule; 2372 entry->next = arg_cache[i]; 2373 arg_cache[i] = entry; 2374 } 2375 2376 static void 2377 clean_arg_cache(void) 2378 { 2379 struct arg_cache *e, *t; 2380 int i; 2381 2382 for (i = 0; i < ARG_CACHE_SIZE; i++) 2383 { 2384 for (e = arg_cache[i]; (t = e); e = e->next, FREE(t)) 2385 free(e->code); 2386 arg_cache[i] = NULL; 2387 } 2388 } 2389 #endif /* defined(YYBTYACC) */ 2390 2391 static void 2392 advance_to_start(void) 2393 { 2394 int c; 2395 bucket *bp; 2396 int s_lineno; 2397 #if defined(YYBTYACC) 2398 char *args = NULL; 2399 int argslen = 0; 2400 #endif 2401 2402 for (;;) 2403 { 2404 char *s_cptr; 2405 2406 c = nextc(); 2407 if (c != '%') 2408 break; 2409 s_cptr = cptr; 2410 switch (keyword()) 2411 { 2412 case XCODE: 2413 copy_code(); 2414 break; 2415 2416 case MARK: 2417 no_grammar(); 2418 2419 case TEXT: 2420 copy_text(); 2421 break; 2422 2423 case START: 2424 declare_start(); 2425 break; 2426 2427 default: 2428 syntax_error(lineno, line, s_cptr); 2429 } 2430 } 2431 2432 c = nextc(); 2433 if (!isalpha(UCH(c)) && c != '_' && c != '.' && c != '_') 2434 syntax_error(lineno, line, cptr); 2435 bp = get_name(); 2436 if (goal == 0) 2437 { 2438 if (bp->class == TERM) 2439 terminal_start(bp->name); 2440 goal = bp; 2441 } 2442 2443 s_lineno = lineno; 2444 c = nextc(); 2445 if (c == EOF) 2446 unexpected_EOF(); 2447 rescan_lineno = lineno; /* line# for possible inherited args rescan */ 2448 #if defined(YYBTYACC) 2449 if (c == L_PAREN) 2450 { 2451 ++cptr; 2452 args = copy_args(&argslen); 2453 NO_SPACE(args); 2454 c = nextc(); 2455 } 2456 #endif 2457 if (c != ':') 2458 syntax_error(lineno, line, cptr); 2459 start_rule(bp, s_lineno); 2460 #if defined(YYBTYACC) 2461 parse_arginfo(bp, args, argslen); 2462 #endif 2463 ++cptr; 2464 } 2465 2466 static void 2467 start_rule(bucket *bp, int s_lineno) 2468 { 2469 if (bp->class == TERM) 2470 terminal_lhs(s_lineno); 2471 bp->class = NONTERM; 2472 if (!bp->index) 2473 bp->index = nrules; 2474 if (nrules >= maxrules) 2475 expand_rules(); 2476 plhs[nrules] = bp; 2477 rprec[nrules] = UNDEFINED; 2478 rassoc[nrules] = TOKEN; 2479 } 2480 2481 static void 2482 end_rule(void) 2483 { 2484 if (!last_was_action && plhs[nrules]->tag) 2485 { 2486 if (pitem[nitems - 1]) 2487 { 2488 int i; 2489 2490 for (i = nitems - 1; (i > 0) && pitem[i]; --i) 2491 continue; 2492 if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag) 2493 default_action_warning(plhs[nrules]->name); 2494 } 2495 else 2496 default_action_warning(plhs[nrules]->name); 2497 } 2498 2499 last_was_action = 0; 2500 if (nitems >= maxitems) 2501 expand_items(); 2502 pitem[nitems] = 0; 2503 ++nitems; 2504 ++nrules; 2505 } 2506 2507 static void 2508 insert_empty_rule(void) 2509 { 2510 bucket *bp, **bpp; 2511 2512 assert(cache); 2513 assert(cache_size >= CACHE_SIZE); 2514 sprintf(cache, "$$%d", ++gensym); 2515 bp = make_bucket(cache); 2516 last_symbol->next = bp; 2517 last_symbol = bp; 2518 bp->tag = plhs[nrules]->tag; 2519 bp->class = ACTION; 2520 #if defined(YYBTYACC) 2521 bp->args = 0; 2522 #endif 2523 2524 nitems = (Value_t)(nitems + 2); 2525 if (nitems > maxitems) 2526 expand_items(); 2527 bpp = pitem + nitems - 1; 2528 *bpp-- = bp; 2529 while ((bpp[0] = bpp[-1]) != 0) 2530 --bpp; 2531 2532 if (++nrules >= maxrules) 2533 expand_rules(); 2534 plhs[nrules] = plhs[nrules - 1]; 2535 plhs[nrules - 1] = bp; 2536 rprec[nrules] = rprec[nrules - 1]; 2537 rprec[nrules - 1] = 0; 2538 rassoc[nrules] = rassoc[nrules - 1]; 2539 rassoc[nrules - 1] = TOKEN; 2540 } 2541 2542 #if defined(YYBTYACC) 2543 static char * 2544 insert_arg_rule(char *arg, char *tag) 2545 { 2546 int line_number = rescan_lineno; 2547 char *code = compile_arg(&arg, tag); 2548 int rule = lookup_arg_cache(code); 2549 FILE *f = action_file; 2550 2551 if (rule < 0) 2552 { 2553 rule = nrules; 2554 insert_arg_cache(code, rule); 2555 trialaction = 1; /* arg rules always run in trial mode */ 2556 fprintf(f, "case %d:\n", rule - 2); 2557 if (!lflag) 2558 fprintf(f, line_format, line_number, input_file_name); 2559 fprintf(f, "%s;\n", code); 2560 fprintf(f, "break;\n"); 2561 insert_empty_rule(); 2562 plhs[rule]->tag = cache_tag(tag, strlen(tag)); 2563 plhs[rule]->class = ARGUMENT; 2564 } 2565 else 2566 { 2567 if (++nitems > maxitems) 2568 expand_items(); 2569 pitem[nitems - 1] = plhs[rule]; 2570 free(code); 2571 } 2572 return arg + 1; 2573 } 2574 #endif 2575 2576 static void 2577 add_symbol(void) 2578 { 2579 int c; 2580 bucket *bp; 2581 int s_lineno = lineno; 2582 #if defined(YYBTYACC) 2583 char *args = NULL; 2584 int argslen = 0; 2585 #endif 2586 2587 c = *cptr; 2588 if (c == '\'' || c == '"') 2589 bp = get_literal(); 2590 else 2591 bp = get_name(); 2592 2593 c = nextc(); 2594 rescan_lineno = lineno; /* line# for possible inherited args rescan */ 2595 #if defined(YYBTYACC) 2596 if (c == L_PAREN) 2597 { 2598 ++cptr; 2599 args = copy_args(&argslen); 2600 NO_SPACE(args); 2601 c = nextc(); 2602 } 2603 #endif 2604 if (c == ':') 2605 { 2606 end_rule(); 2607 start_rule(bp, s_lineno); 2608 #if defined(YYBTYACC) 2609 parse_arginfo(bp, args, argslen); 2610 #endif 2611 ++cptr; 2612 return; 2613 } 2614 2615 if (last_was_action) 2616 insert_empty_rule(); 2617 last_was_action = 0; 2618 2619 #if defined(YYBTYACC) 2620 if (bp->args < 0) 2621 bp->args = argslen; 2622 if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL) 2623 { 2624 int i; 2625 if (plhs[nrules]->args != bp->args) 2626 wrong_number_args_warning("default ", bp->name); 2627 for (i = bp->args - 1; i >= 0; i--) 2628 if (plhs[nrules]->argtags[i] != bp->argtags[i]) 2629 wrong_type_for_arg_warning(i + 1, bp->name); 2630 } 2631 else if (bp->args != argslen) 2632 wrong_number_args_warning("", bp->name); 2633 if (args != 0) 2634 { 2635 char *ap = args; 2636 int i = 0; 2637 int elide_cnt = can_elide_arg(&ap, bp->argtags[0]); 2638 2639 if (elide_cnt > argslen) 2640 elide_cnt = 0; 2641 if (elide_cnt) 2642 { 2643 for (i = 1; i < elide_cnt; i++) 2644 if (can_elide_arg(&ap, bp->argtags[i]) != elide_cnt - i) 2645 { 2646 elide_cnt = 0; 2647 break; 2648 } 2649 } 2650 if (elide_cnt) 2651 { 2652 assert(i == elide_cnt); 2653 } 2654 else 2655 { 2656 ap = args; 2657 i = 0; 2658 } 2659 for (; i < argslen; i++) 2660 ap = insert_arg_rule(ap, bp->argtags[i]); 2661 free(args); 2662 } 2663 #endif /* defined(YYBTYACC) */ 2664 2665 if (++nitems > maxitems) 2666 expand_items(); 2667 pitem[nitems - 1] = bp; 2668 } 2669 2670 static void 2671 copy_action(void) 2672 { 2673 int c; 2674 int i, j, n; 2675 int depth; 2676 #if defined(YYBTYACC) 2677 int haveyyval = 0; 2678 #endif 2679 char *tag; 2680 FILE *f = action_file; 2681 struct ainfo a; 2682 Value_t *offsets = NULL, maxoffset; 2683 bucket **rhs; 2684 2685 a.a_lineno = lineno; 2686 a.a_line = dup_line(); 2687 a.a_cptr = a.a_line + (cptr - line); 2688 2689 if (last_was_action) 2690 insert_empty_rule(); 2691 last_was_action = 1; 2692 #if defined(YYBTYACC) 2693 trialaction = (*cptr == L_BRAC); 2694 #endif 2695 2696 fprintf(f, "case %d:\n", nrules - 2); 2697 #if defined(YYBTYACC) 2698 if (backtrack) 2699 { 2700 if (!trialaction) 2701 fprintf(f, " if (!yytrial)\n"); 2702 } 2703 #endif 2704 if (!lflag) 2705 fprintf(f, line_format, lineno, input_file_name); 2706 if (*cptr == '=') 2707 ++cptr; 2708 2709 /* avoid putting curly-braces in first column, to ease editing */ 2710 if (*after_blanks(cptr) == L_CURL) 2711 { 2712 putc('\t', f); 2713 cptr = after_blanks(cptr); 2714 } 2715 2716 maxoffset = 0; 2717 n = 0; 2718 for (i = nitems - 1; pitem[i]; --i) 2719 { 2720 ++n; 2721 if (pitem[i]->class != ARGUMENT) 2722 maxoffset++; 2723 } 2724 if (maxoffset > 0) 2725 { 2726 offsets = TMALLOC(Value_t, maxoffset + 1); 2727 NO_SPACE(offsets); 2728 2729 for (j = 0, i++; i < nitems; i++) 2730 { 2731 if (pitem[i]->class != ARGUMENT) 2732 { 2733 offsets[++j] = (Value_t)(i - nitems + 1); 2734 } 2735 } 2736 } 2737 rhs = pitem + nitems - 1; 2738 2739 depth = 0; 2740 loop: 2741 c = *cptr; 2742 if (c == '$') 2743 { 2744 if (cptr[1] == '<') 2745 { 2746 int d_lineno = lineno; 2747 char *d_line = dup_line(); 2748 char *d_cptr = d_line + (cptr - line); 2749 2750 ++cptr; 2751 tag = get_tag(); 2752 c = *cptr; 2753 if (c == '$') 2754 { 2755 fprintf(f, "yyval.%s", tag); 2756 ++cptr; 2757 FREE(d_line); 2758 goto loop; 2759 } 2760 else if (isdigit(UCH(c))) 2761 { 2762 i = get_number(); 2763 if (i == 0) 2764 fprintf(f, "yystack.l_mark[%d].%s", -n, tag); 2765 else if (i > maxoffset) 2766 { 2767 dollar_warning(d_lineno, i); 2768 fprintf(f, "yystack.l_mark[%d].%s", i - maxoffset, tag); 2769 } 2770 else if (offsets) 2771 fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag); 2772 FREE(d_line); 2773 goto loop; 2774 } 2775 else if (c == '-' && isdigit(UCH(cptr[1]))) 2776 { 2777 ++cptr; 2778 i = -get_number() - n; 2779 fprintf(f, "yystack.l_mark[%d].%s", i, tag); 2780 FREE(d_line); 2781 goto loop; 2782 } 2783 #if defined(YYBTYACC) 2784 else if (isalpha(UCH(c)) || c == '_') 2785 { 2786 char *arg = scan_id(); 2787 for (i = plhs[nrules]->args - 1; i >= 0; i--) 2788 if (arg == plhs[nrules]->argnames[i]) 2789 break; 2790 if (i < 0) 2791 unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr); 2792 fprintf(f, "yystack.l_mark[%d].%s", 2793 i - plhs[nrules]->args + 1 - n, tag); 2794 FREE(d_line); 2795 goto loop; 2796 } 2797 #endif 2798 else 2799 dollar_error(d_lineno, d_line, d_cptr); 2800 } 2801 else if (cptr[1] == '$') 2802 { 2803 if (havetags) 2804 { 2805 tag = plhs[nrules]->tag; 2806 if (tag == 0) 2807 untyped_lhs(); 2808 fprintf(f, "yyval.%s", tag); 2809 } 2810 else 2811 fprintf(f, "yyval"); 2812 cptr += 2; 2813 #if defined(YYBTYACC) 2814 haveyyval = 1; 2815 #endif 2816 goto loop; 2817 } 2818 else if (isdigit(UCH(cptr[1]))) 2819 { 2820 ++cptr; 2821 i = get_number(); 2822 if (havetags && offsets) 2823 { 2824 if (i <= 0 || i > maxoffset) 2825 unknown_rhs(i); 2826 tag = rhs[offsets[i]]->tag; 2827 if (tag == 0) 2828 untyped_rhs(i, rhs[offsets[i]]->name); 2829 fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag); 2830 } 2831 else 2832 { 2833 if (i == 0) 2834 fprintf(f, "yystack.l_mark[%d]", -n); 2835 else if (i > maxoffset) 2836 { 2837 dollar_warning(lineno, i); 2838 fprintf(f, "yystack.l_mark[%d]", i - maxoffset); 2839 } 2840 else if (offsets) 2841 fprintf(f, "yystack.l_mark[%d]", offsets[i]); 2842 } 2843 goto loop; 2844 } 2845 else if (cptr[1] == '-') 2846 { 2847 cptr += 2; 2848 i = get_number(); 2849 if (havetags) 2850 unknown_rhs(-i); 2851 fprintf(f, "yystack.l_mark[%d]", -i - n); 2852 goto loop; 2853 } 2854 #if defined(YYBTYACC) 2855 else if (isalpha(UCH(cptr[1])) || cptr[1] == '_') 2856 { 2857 char *arg; 2858 ++cptr; 2859 arg = scan_id(); 2860 for (i = plhs[nrules]->args - 1; i >= 0; i--) 2861 if (arg == plhs[nrules]->argnames[i]) 2862 break; 2863 if (i < 0) 2864 unknown_arg_warning(lineno, "$", arg, line, cptr); 2865 tag = (i < 0 ? NULL : plhs[nrules]->argtags[i]); 2866 fprintf(f, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 - n); 2867 if (tag) 2868 fprintf(f, ".%s", tag); 2869 else if (havetags) 2870 untyped_arg_warning(lineno, "$", arg); 2871 goto loop; 2872 } 2873 #endif 2874 } 2875 #if defined(YYBTYACC) 2876 if (c == '@') 2877 { 2878 if (!locations) 2879 { 2880 int l_lineno = lineno; 2881 char *l_line = dup_line(); 2882 char *l_cptr = l_line + (cptr - line); 2883 syntax_error(l_lineno, l_line, l_cptr); 2884 } 2885 if (cptr[1] == '$') 2886 { 2887 fprintf(f, "yyloc"); 2888 cptr += 2; 2889 goto loop; 2890 } 2891 else if (isdigit(UCH(cptr[1]))) 2892 { 2893 ++cptr; 2894 i = get_number(); 2895 if (i == 0) 2896 fprintf(f, "yystack.p_mark[%d]", -n); 2897 else if (i > maxoffset) 2898 { 2899 at_warning(lineno, i); 2900 fprintf(f, "yystack.p_mark[%d]", i - maxoffset); 2901 } 2902 else if (offsets) 2903 fprintf(f, "yystack.p_mark[%d]", offsets[i]); 2904 goto loop; 2905 } 2906 else if (cptr[1] == '-') 2907 { 2908 cptr += 2; 2909 i = get_number(); 2910 fprintf(f, "yystack.p_mark[%d]", -i - n); 2911 goto loop; 2912 } 2913 } 2914 #endif 2915 if (IS_NAME1(c)) 2916 { 2917 do 2918 { 2919 putc(c, f); 2920 c = *++cptr; 2921 } 2922 while (IS_NAME2(c)); 2923 goto loop; 2924 } 2925 ++cptr; 2926 #if defined(YYBTYACC) 2927 if (backtrack) 2928 { 2929 if (trialaction && c == L_BRAC && depth == 0) 2930 { 2931 ++depth; 2932 putc(L_CURL, f); 2933 goto loop; 2934 } 2935 if (trialaction && c == R_BRAC && depth == 1) 2936 { 2937 --depth; 2938 putc(R_CURL, f); 2939 c = nextc(); 2940 if (c == L_BRAC && !haveyyval) 2941 { 2942 goto loop; 2943 } 2944 if (c == L_CURL && !haveyyval) 2945 { 2946 fprintf(f, " if (!yytrial)\n"); 2947 if (!lflag) 2948 fprintf(f, line_format, lineno, input_file_name); 2949 trialaction = 0; 2950 goto loop; 2951 } 2952 fprintf(f, "\n"); 2953 if (!lflag) 2954 fprintf(f, line_format, 1, ""); 2955 fprintf(f, "break;\n"); 2956 FREE(a.a_line); 2957 if (maxoffset > 0) 2958 FREE(offsets); 2959 return; 2960 } 2961 } 2962 #endif 2963 putc(c, f); 2964 switch (c) 2965 { 2966 case '\n': 2967 get_line(); 2968 if (line) 2969 goto loop; 2970 unterminated_action(&a); 2971 2972 case ';': 2973 if (depth > 0) 2974 goto loop; 2975 fprintf(f, "\n"); 2976 if (!lflag) 2977 fprintf(f, line_format, 1, ""); 2978 fprintf(f, "break;\n"); 2979 free(a.a_line); 2980 if (maxoffset > 0) 2981 FREE(offsets); 2982 return; 2983 2984 #if defined(YYBTYACC) 2985 case L_BRAC: 2986 if (backtrack) 2987 ++depth; 2988 goto loop; 2989 2990 case R_BRAC: 2991 if (backtrack) 2992 --depth; 2993 goto loop; 2994 #endif 2995 2996 case L_CURL: 2997 ++depth; 2998 goto loop; 2999 3000 case R_CURL: 3001 if (--depth > 0) 3002 goto loop; 3003 #if defined(YYBTYACC) 3004 if (backtrack) 3005 { 3006 c = nextc(); 3007 if (c == L_BRAC && !haveyyval) 3008 { 3009 trialaction = 1; 3010 goto loop; 3011 } 3012 if (c == L_CURL && !haveyyval) 3013 { 3014 fprintf(f, " if (!yytrial)\n"); 3015 if (!lflag) 3016 fprintf(f, line_format, lineno, input_file_name); 3017 goto loop; 3018 } 3019 } 3020 #endif 3021 fprintf(f, "\n"); 3022 if (!lflag) 3023 fprintf(f, line_format, 1, ""); 3024 fprintf(f, "break;\n"); 3025 free(a.a_line); 3026 if (maxoffset > 0) 3027 FREE(offsets); 3028 return; 3029 3030 case '\'': 3031 case '"': 3032 { 3033 char *s = copy_string(c); 3034 fputs(s, f); 3035 free(s); 3036 } 3037 goto loop; 3038 3039 case '/': 3040 { 3041 char *s = copy_comment(); 3042 fputs(s, f); 3043 free(s); 3044 } 3045 goto loop; 3046 3047 default: 3048 goto loop; 3049 } 3050 } 3051 3052 #if defined(YYBTYACC) 3053 static char * 3054 get_code(struct ainfo *a, const char *loc) 3055 { 3056 int c; 3057 int depth; 3058 char *tag; 3059 struct mstring *code_mstr = msnew(); 3060 3061 if (!lflag) 3062 msprintf(code_mstr, line_format, lineno, input_file_name); 3063 3064 cptr = after_blanks(cptr); 3065 if (*cptr == L_CURL) 3066 /* avoid putting curly-braces in first column, to ease editing */ 3067 mputc(code_mstr, '\t'); 3068 else 3069 syntax_error(lineno, line, cptr); 3070 3071 a->a_lineno = lineno; 3072 a->a_line = dup_line(); 3073 a->a_cptr = a->a_line + (cptr - line); 3074 3075 depth = 0; 3076 loop: 3077 c = *cptr; 3078 if (c == '$') 3079 { 3080 if (cptr[1] == '<') 3081 { 3082 int d_lineno = lineno; 3083 char *d_line = dup_line(); 3084 char *d_cptr = d_line + (cptr - line); 3085 3086 ++cptr; 3087 tag = get_tag(); 3088 c = *cptr; 3089 if (c == '$') 3090 { 3091 msprintf(code_mstr, "(*val).%s", tag); 3092 ++cptr; 3093 FREE(d_line); 3094 goto loop; 3095 } 3096 else 3097 dollar_error(d_lineno, d_line, d_cptr); 3098 } 3099 else if (cptr[1] == '$') 3100 { 3101 /* process '$$' later; replacement is context dependent */ 3102 msprintf(code_mstr, "$$"); 3103 cptr += 2; 3104 goto loop; 3105 } 3106 } 3107 if (c == '@' && cptr[1] == '$') 3108 { 3109 if (!locations) 3110 { 3111 int l_lineno = lineno; 3112 char *l_line = dup_line(); 3113 char *l_cptr = l_line + (cptr - line); 3114 syntax_error(l_lineno, l_line, l_cptr); 3115 } 3116 msprintf(code_mstr, "%s", loc); 3117 cptr += 2; 3118 goto loop; 3119 } 3120 if (IS_NAME1(c)) 3121 { 3122 do 3123 { 3124 mputc(code_mstr, c); 3125 c = *++cptr; 3126 } 3127 while (IS_NAME2(c)); 3128 goto loop; 3129 } 3130 ++cptr; 3131 mputc(code_mstr, c); 3132 switch (c) 3133 { 3134 case '\n': 3135 get_line(); 3136 if (line) 3137 goto loop; 3138 unterminated_action(a); 3139 3140 case L_CURL: 3141 ++depth; 3142 goto loop; 3143 3144 case R_CURL: 3145 if (--depth > 0) 3146 goto loop; 3147 goto out; 3148 3149 case '\'': 3150 case '"': 3151 { 3152 char *s = copy_string(c); 3153 msprintf(code_mstr, "%s", s); 3154 free(s); 3155 } 3156 goto loop; 3157 3158 case '/': 3159 { 3160 char *s = copy_comment(); 3161 msprintf(code_mstr, "%s", s); 3162 free(s); 3163 } 3164 goto loop; 3165 3166 default: 3167 goto loop; 3168 } 3169 out: 3170 return msdone(code_mstr); 3171 } 3172 3173 static void 3174 copy_initial_action(void) 3175 { 3176 struct ainfo a; 3177 3178 initial_action = get_code(&a, "yyloc"); 3179 free(a.a_line); 3180 } 3181 3182 static void 3183 copy_destructor(void) 3184 { 3185 char *code_text; 3186 struct ainfo a; 3187 bucket *bp; 3188 3189 code_text = get_code(&a, "(*loc)"); 3190 3191 for (;;) 3192 { 3193 int c = nextc(); 3194 if (c == EOF) 3195 unexpected_EOF(); 3196 if (c == '<') 3197 { 3198 if (cptr[1] == '>') 3199 { /* "no semantic type" default destructor */ 3200 cptr += 2; 3201 if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL) 3202 { 3203 static char untyped_default[] = "<>"; 3204 bp = make_bucket("untyped default"); 3205 bp->tag = untyped_default; 3206 default_destructor[UNTYPED_DEFAULT] = bp; 3207 } 3208 if (bp->destructor != NULL) 3209 destructor_redeclared_warning(&a); 3210 else 3211 /* replace "$$" with "(*val)" in destructor code */ 3212 bp->destructor = process_destructor_XX(code_text, NULL); 3213 } 3214 else if (cptr[1] == '*' && cptr[2] == '>') 3215 { /* "no per-symbol or per-type" default destructor */ 3216 cptr += 3; 3217 if ((bp = default_destructor[TYPED_DEFAULT]) == NULL) 3218 { 3219 static char typed_default[] = "<*>"; 3220 bp = make_bucket("typed default"); 3221 bp->tag = typed_default; 3222 default_destructor[TYPED_DEFAULT] = bp; 3223 } 3224 if (bp->destructor != NULL) 3225 destructor_redeclared_warning(&a); 3226 else 3227 { 3228 /* postpone re-processing destructor $$s until end of grammar spec */ 3229 bp->destructor = TMALLOC(char, strlen(code_text) + 1); 3230 NO_SPACE(bp->destructor); 3231 strcpy(bp->destructor, code_text); 3232 } 3233 } 3234 else 3235 { /* "semantic type" default destructor */ 3236 char *tag = get_tag(); 3237 bp = lookup_type_destructor(tag); 3238 if (bp->destructor != NULL) 3239 destructor_redeclared_warning(&a); 3240 else 3241 /* replace "$$" with "(*val).tag" in destructor code */ 3242 bp->destructor = process_destructor_XX(code_text, tag); 3243 } 3244 } 3245 else if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$') 3246 { /* "symbol" destructor */ 3247 bp = get_name(); 3248 if (bp->destructor != NULL) 3249 destructor_redeclared_warning(&a); 3250 else 3251 { 3252 /* postpone re-processing destructor $$s until end of grammar spec */ 3253 bp->destructor = TMALLOC(char, strlen(code_text) + 1); 3254 NO_SPACE(bp->destructor); 3255 strcpy(bp->destructor, code_text); 3256 } 3257 } 3258 else 3259 break; 3260 } 3261 free(a.a_line); 3262 free(code_text); 3263 } 3264 3265 static char * 3266 process_destructor_XX(char *code, char *tag) 3267 { 3268 int c; 3269 int quote; 3270 int depth; 3271 struct mstring *new_code = msnew(); 3272 char *codeptr = code; 3273 3274 depth = 0; 3275 loop: /* step thru code */ 3276 c = *codeptr; 3277 if (c == '$' && codeptr[1] == '$') 3278 { 3279 codeptr += 2; 3280 if (tag == NULL) 3281 msprintf(new_code, "(*val)"); 3282 else 3283 msprintf(new_code, "(*val).%s", tag); 3284 goto loop; 3285 } 3286 if (IS_NAME1(c)) 3287 { 3288 do 3289 { 3290 mputc(new_code, c); 3291 c = *++codeptr; 3292 } 3293 while (IS_NAME2(c)); 3294 goto loop; 3295 } 3296 ++codeptr; 3297 mputc(new_code, c); 3298 switch (c) 3299 { 3300 case L_CURL: 3301 ++depth; 3302 goto loop; 3303 3304 case R_CURL: 3305 if (--depth > 0) 3306 goto loop; 3307 return msdone(new_code); 3308 3309 case '\'': 3310 case '"': 3311 quote = c; 3312 for (;;) 3313 { 3314 c = *codeptr++; 3315 mputc(new_code, c); 3316 if (c == quote) 3317 goto loop; 3318 if (c == '\\') 3319 { 3320 c = *codeptr++; 3321 mputc(new_code, c); 3322 } 3323 } 3324 3325 case '/': 3326 c = *codeptr; 3327 if (c == '*') 3328 { 3329 mputc(new_code, c); 3330 ++codeptr; 3331 for (;;) 3332 { 3333 c = *codeptr++; 3334 mputc(new_code, c); 3335 if (c == '*' && *codeptr == '/') 3336 { 3337 mputc(new_code, '/'); 3338 ++codeptr; 3339 goto loop; 3340 } 3341 } 3342 } 3343 goto loop; 3344 3345 default: 3346 goto loop; 3347 } 3348 } 3349 #endif /* defined(YYBTYACC) */ 3350 3351 static int 3352 mark_symbol(void) 3353 { 3354 int c; 3355 bucket *bp = NULL; 3356 3357 c = cptr[1]; 3358 if (c == '%' || c == '\\') 3359 { 3360 cptr += 2; 3361 return (1); 3362 } 3363 3364 if (c == '=') 3365 cptr += 2; 3366 else if ((c == 'p' || c == 'P') && 3367 ((c = cptr[2]) == 'r' || c == 'R') && 3368 ((c = cptr[3]) == 'e' || c == 'E') && 3369 ((c = cptr[4]) == 'c' || c == 'C') && 3370 ((c = cptr[5], !IS_IDENT(c)))) 3371 cptr += 5; 3372 else 3373 syntax_error(lineno, line, cptr); 3374 3375 c = nextc(); 3376 if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$') 3377 bp = get_name(); 3378 else if (c == '\'' || c == '"') 3379 bp = get_literal(); 3380 else 3381 { 3382 syntax_error(lineno, line, cptr); 3383 /*NOTREACHED */ 3384 } 3385 3386 if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules]) 3387 prec_redeclared(); 3388 3389 rprec[nrules] = bp->prec; 3390 rassoc[nrules] = bp->assoc; 3391 return (0); 3392 } 3393 3394 static void 3395 read_grammar(void) 3396 { 3397 initialize_grammar(); 3398 advance_to_start(); 3399 3400 for (;;) 3401 { 3402 int c = nextc(); 3403 3404 if (c == EOF) 3405 break; 3406 if (isalpha(UCH(c)) 3407 || c == '_' 3408 || c == '.' 3409 || c == '$' 3410 || c == '\'' 3411 || c == '"') 3412 add_symbol(); 3413 #if defined(YYBTYACC) 3414 else if (c == L_CURL || c == '=' || (backtrack && c == L_BRAC)) 3415 #else 3416 else if (c == L_CURL || c == '=') 3417 #endif 3418 copy_action(); 3419 else if (c == '|') 3420 { 3421 end_rule(); 3422 start_rule(plhs[nrules - 1], 0); 3423 ++cptr; 3424 } 3425 else if (c == '%') 3426 { 3427 if (mark_symbol()) 3428 break; 3429 } 3430 else 3431 syntax_error(lineno, line, cptr); 3432 } 3433 end_rule(); 3434 #if defined(YYBTYACC) 3435 if (goal->args > 0) 3436 start_requires_args(goal->name); 3437 #endif 3438 } 3439 3440 static void 3441 free_tags(void) 3442 { 3443 int i; 3444 3445 if (tag_table == 0) 3446 return; 3447 3448 for (i = 0; i < ntags; ++i) 3449 { 3450 assert(tag_table[i]); 3451 FREE(tag_table[i]); 3452 } 3453 FREE(tag_table); 3454 } 3455 3456 static void 3457 pack_names(void) 3458 { 3459 bucket *bp; 3460 char *p; 3461 char *t; 3462 3463 name_pool_size = 13; /* 13 == sizeof("$end") + sizeof("$accept") */ 3464 for (bp = first_symbol; bp; bp = bp->next) 3465 name_pool_size += strlen(bp->name) + 1; 3466 3467 name_pool = TMALLOC(char, name_pool_size); 3468 NO_SPACE(name_pool); 3469 3470 strlcpy(name_pool, "$accept", name_pool_size); 3471 strlcpy(name_pool + 8, "$end", name_pool_size - 8); 3472 t = name_pool + 13; 3473 for (bp = first_symbol; bp; bp = bp->next) 3474 { 3475 char *s = bp->name; 3476 3477 p = t; 3478 while ((*t++ = *s++) != 0) 3479 continue; 3480 FREE(bp->name); 3481 bp->name = p; 3482 } 3483 } 3484 3485 static void 3486 check_symbols(void) 3487 { 3488 bucket *bp; 3489 3490 if (goal->class == UNKNOWN) 3491 undefined_goal(goal->name); 3492 3493 for (bp = first_symbol; bp; bp = bp->next) 3494 { 3495 if (bp->class == UNKNOWN) 3496 { 3497 undefined_symbol_warning(bp->name); 3498 bp->class = TERM; 3499 } 3500 } 3501 } 3502 3503 static void 3504 protect_string(char *src, char **des) 3505 { 3506 *des = src; 3507 if (src) 3508 { 3509 char *s; 3510 char *d; 3511 3512 unsigned len = 1; 3513 3514 s = src; 3515 while (*s) 3516 { 3517 if ('\\' == *s || '"' == *s) 3518 len++; 3519 s++; 3520 len++; 3521 } 3522 3523 *des = d = TMALLOC(char, len); 3524 NO_SPACE(d); 3525 3526 s = src; 3527 while (*s) 3528 { 3529 if ('\\' == *s || '"' == *s) 3530 *d++ = '\\'; 3531 *d++ = *s++; 3532 } 3533 *d = '\0'; 3534 } 3535 } 3536 3537 static void 3538 pack_symbols(void) 3539 { 3540 bucket *bp; 3541 bucket **v; 3542 Value_t i, j, k, n; 3543 #if defined(YYBTYACC) 3544 Value_t max_tok_pval; 3545 #endif 3546 3547 nsyms = 2; 3548 ntokens = 1; 3549 for (bp = first_symbol; bp; bp = bp->next) 3550 { 3551 ++nsyms; 3552 if (bp->class == TERM) 3553 ++ntokens; 3554 } 3555 start_symbol = (Value_t)ntokens; 3556 nvars = (Value_t)(nsyms - ntokens); 3557 3558 symbol_name = TMALLOC(char *, nsyms); 3559 NO_SPACE(symbol_name); 3560 3561 symbol_value = TMALLOC(Value_t, nsyms); 3562 NO_SPACE(symbol_value); 3563 3564 symbol_prec = TMALLOC(Value_t, nsyms); 3565 NO_SPACE(symbol_prec); 3566 3567 symbol_assoc = TMALLOC(char, nsyms); 3568 NO_SPACE(symbol_assoc); 3569 3570 #if defined(YYBTYACC) 3571 symbol_pval = TMALLOC(Value_t, nsyms); 3572 NO_SPACE(symbol_pval); 3573 3574 if (destructor) 3575 { 3576 symbol_destructor = CALLOC(sizeof(char *), nsyms); 3577 NO_SPACE(symbol_destructor); 3578 3579 symbol_type_tag = CALLOC(sizeof(char *), nsyms); 3580 NO_SPACE(symbol_type_tag); 3581 } 3582 #endif 3583 3584 v = TMALLOC(bucket *, nsyms); 3585 NO_SPACE(v); 3586 3587 v[0] = 0; 3588 v[start_symbol] = 0; 3589 3590 i = 1; 3591 j = (Value_t)(start_symbol + 1); 3592 for (bp = first_symbol; bp; bp = bp->next) 3593 { 3594 if (bp->class == TERM) 3595 v[i++] = bp; 3596 else 3597 v[j++] = bp; 3598 } 3599 assert(i == ntokens && j == nsyms); 3600 3601 for (i = 1; i < ntokens; ++i) 3602 v[i]->index = i; 3603 3604 goal->index = (Index_t)(start_symbol + 1); 3605 k = (Value_t)(start_symbol + 2); 3606 while (++i < nsyms) 3607 if (v[i] != goal) 3608 { 3609 v[i]->index = k; 3610 ++k; 3611 } 3612 3613 goal->value = 0; 3614 k = 1; 3615 for (i = (Value_t)(start_symbol + 1); i < nsyms; ++i) 3616 { 3617 if (v[i] != goal) 3618 { 3619 v[i]->value = k; 3620 ++k; 3621 } 3622 } 3623 3624 k = 0; 3625 for (i = 1; i < ntokens; ++i) 3626 { 3627 n = v[i]->value; 3628 if (n > 256) 3629 { 3630 for (j = k++; j > 0 && symbol_value[j - 1] > n; --j) 3631 symbol_value[j] = symbol_value[j - 1]; 3632 symbol_value[j] = n; 3633 } 3634 } 3635 3636 assert(v[1] != 0); 3637 3638 if (v[1]->value == UNDEFINED) 3639 v[1]->value = 256; 3640 3641 j = 0; 3642 n = 257; 3643 for (i = 2; i < ntokens; ++i) 3644 { 3645 if (v[i]->value == UNDEFINED) 3646 { 3647 while (j < k && n == symbol_value[j]) 3648 { 3649 while (++j < k && n == symbol_value[j]) 3650 continue; 3651 ++n; 3652 } 3653 v[i]->value = n; 3654 ++n; 3655 } 3656 } 3657 3658 symbol_name[0] = name_pool + 8; 3659 symbol_value[0] = 0; 3660 symbol_prec[0] = 0; 3661 symbol_assoc[0] = TOKEN; 3662 #if defined(YYBTYACC) 3663 symbol_pval[0] = 0; 3664 max_tok_pval = 0; 3665 #endif 3666 for (i = 1; i < ntokens; ++i) 3667 { 3668 symbol_name[i] = v[i]->name; 3669 symbol_value[i] = v[i]->value; 3670 symbol_prec[i] = v[i]->prec; 3671 symbol_assoc[i] = v[i]->assoc; 3672 #if defined(YYBTYACC) 3673 symbol_pval[i] = v[i]->value; 3674 if (symbol_pval[i] > max_tok_pval) 3675 max_tok_pval = symbol_pval[i]; 3676 if (destructor) 3677 { 3678 symbol_destructor[i] = v[i]->destructor; 3679 symbol_type_tag[i] = v[i]->tag; 3680 } 3681 #endif 3682 } 3683 symbol_name[start_symbol] = name_pool; 3684 symbol_value[start_symbol] = -1; 3685 symbol_prec[start_symbol] = 0; 3686 symbol_assoc[start_symbol] = TOKEN; 3687 #if defined(YYBTYACC) 3688 symbol_pval[start_symbol] = (Value_t)(max_tok_pval + 1); 3689 #endif 3690 for (++i; i < nsyms; ++i) 3691 { 3692 k = v[i]->index; 3693 symbol_name[k] = v[i]->name; 3694 symbol_value[k] = v[i]->value; 3695 symbol_prec[k] = v[i]->prec; 3696 symbol_assoc[k] = v[i]->assoc; 3697 #if defined(YYBTYACC) 3698 symbol_pval[k] = (Value_t)((max_tok_pval + 1) + v[i]->value + 1); 3699 if (destructor) 3700 { 3701 symbol_destructor[k] = v[i]->destructor; 3702 symbol_type_tag[k] = v[i]->tag; 3703 } 3704 #endif 3705 } 3706 3707 if (gflag) 3708 { 3709 symbol_pname = TMALLOC(char *, nsyms); 3710 NO_SPACE(symbol_pname); 3711 3712 for (i = 0; i < nsyms; ++i) 3713 protect_string(symbol_name[i], &(symbol_pname[i])); 3714 } 3715 3716 FREE(v); 3717 } 3718 3719 static void 3720 pack_grammar(void) 3721 { 3722 int i; 3723 Value_t j; 3724 3725 ritem = TMALLOC(Value_t, nitems); 3726 NO_SPACE(ritem); 3727 3728 rlhs = TMALLOC(Value_t, nrules); 3729 NO_SPACE(rlhs); 3730 3731 rrhs = TMALLOC(Value_t, nrules + 1); 3732 NO_SPACE(rrhs); 3733 3734 rprec = TREALLOC(Value_t, rprec, nrules); 3735 NO_SPACE(rprec); 3736 3737 rassoc = TREALLOC(Assoc_t, rassoc, nrules); 3738 NO_SPACE(rassoc); 3739 3740 ritem[0] = -1; 3741 ritem[1] = goal->index; 3742 ritem[2] = 0; 3743 ritem[3] = -2; 3744 rlhs[0] = 0; 3745 rlhs[1] = 0; 3746 rlhs[2] = start_symbol; 3747 rrhs[0] = 0; 3748 rrhs[1] = 0; 3749 rrhs[2] = 1; 3750 3751 j = 4; 3752 for (i = 3; i < nrules; ++i) 3753 { 3754 Assoc_t assoc; 3755 Value_t prec2; 3756 3757 #if defined(YYBTYACC) 3758 if (plhs[i]->args > 0) 3759 { 3760 if (plhs[i]->argnames) 3761 { 3762 FREE(plhs[i]->argnames); 3763 plhs[i]->argnames = NULL; 3764 } 3765 if (plhs[i]->argtags) 3766 { 3767 FREE(plhs[i]->argtags); 3768 plhs[i]->argtags = NULL; 3769 } 3770 } 3771 #endif /* defined(YYBTYACC) */ 3772 rlhs[i] = plhs[i]->index; 3773 rrhs[i] = j; 3774 assoc = TOKEN; 3775 prec2 = 0; 3776 while (pitem[j]) 3777 { 3778 ritem[j] = pitem[j]->index; 3779 if (pitem[j]->class == TERM) 3780 { 3781 prec2 = pitem[j]->prec; 3782 assoc = pitem[j]->assoc; 3783 } 3784 ++j; 3785 } 3786 ritem[j] = (Value_t)-i; 3787 ++j; 3788 if (rprec[i] == UNDEFINED) 3789 { 3790 rprec[i] = prec2; 3791 rassoc[i] = assoc; 3792 } 3793 } 3794 rrhs[i] = j; 3795 3796 FREE(plhs); 3797 FREE(pitem); 3798 #if defined(YYBTYACC) 3799 clean_arg_cache(); 3800 #endif 3801 } 3802 3803 static void 3804 print_grammar(void) 3805 { 3806 int i, k; 3807 size_t j, spacing = 0; 3808 FILE *f = verbose_file; 3809 3810 if (!vflag) 3811 return; 3812 3813 k = 1; 3814 for (i = 2; i < nrules; ++i) 3815 { 3816 if (rlhs[i] != rlhs[i - 1]) 3817 { 3818 if (i != 2) 3819 fprintf(f, "\n"); 3820 fprintf(f, "%4d %s :", i - 2, symbol_name[rlhs[i]]); 3821 spacing = strlen(symbol_name[rlhs[i]]) + 1; 3822 } 3823 else 3824 { 3825 fprintf(f, "%4d ", i - 2); 3826 j = spacing; 3827 while (j-- != 0) 3828 putc(' ', f); 3829 putc('|', f); 3830 } 3831 3832 while (ritem[k] >= 0) 3833 { 3834 fprintf(f, " %s", symbol_name[ritem[k]]); 3835 ++k; 3836 } 3837 ++k; 3838 putc('\n', f); 3839 } 3840 } 3841 3842 #if defined(YYBTYACC) 3843 static void 3844 finalize_destructors(void) 3845 { 3846 int i; 3847 bucket *bp; 3848 3849 for (i = 2; i < nsyms; ++i) 3850 { 3851 char *tag = symbol_type_tag[i]; 3852 3853 if (symbol_destructor[i] == NULL) 3854 { 3855 if (tag == NULL) 3856 { /* use <> destructor, if there is one */ 3857 if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL) 3858 { 3859 symbol_destructor[i] = TMALLOC(char, 3860 strlen(bp->destructor) + 1); 3861 NO_SPACE(symbol_destructor[i]); 3862 strcpy(symbol_destructor[i], bp->destructor); 3863 } 3864 } 3865 else 3866 { /* use type destructor for this tag, if there is one */ 3867 bp = lookup_type_destructor(tag); 3868 if (bp->destructor != NULL) 3869 { 3870 symbol_destructor[i] = TMALLOC(char, 3871 strlen(bp->destructor) + 1); 3872 NO_SPACE(symbol_destructor[i]); 3873 strcpy(symbol_destructor[i], bp->destructor); 3874 } 3875 else 3876 { /* use <*> destructor, if there is one */ 3877 if ((bp = default_destructor[TYPED_DEFAULT]) != NULL) 3878 /* replace "$$" with "(*val).tag" in destructor code */ 3879 symbol_destructor[i] 3880 = process_destructor_XX(bp->destructor, tag); 3881 } 3882 } 3883 } 3884 else 3885 { /* replace "$$" with "(*val)[.tag]" in destructor code */ 3886 symbol_destructor[i] 3887 = process_destructor_XX(symbol_destructor[i], tag); 3888 } 3889 } 3890 /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */ 3891 DO_FREE(symbol_type_tag); /* no longer needed */ 3892 if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL) 3893 { 3894 FREE(bp->name); 3895 /* 'bp->tag' is a static value, don't free */ 3896 FREE(bp->destructor); 3897 FREE(bp); 3898 } 3899 if ((bp = default_destructor[TYPED_DEFAULT]) != NULL) 3900 { 3901 FREE(bp->name); 3902 /* 'bp->tag' is a static value, don't free */ 3903 FREE(bp->destructor); 3904 FREE(bp); 3905 } 3906 if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL) 3907 { 3908 bucket *p; 3909 for (; bp; bp = p) 3910 { 3911 p = bp->link; 3912 FREE(bp->name); 3913 /* 'bp->tag' freed by 'free_tags()' */ 3914 FREE(bp->destructor); 3915 FREE(bp); 3916 } 3917 } 3918 } 3919 #endif /* defined(YYBTYACC) */ 3920 3921 void 3922 reader(void) 3923 { 3924 write_section(code_file, banner); 3925 create_symbol_table(); 3926 read_declarations(); 3927 read_grammar(); 3928 free_symbol_table(); 3929 pack_names(); 3930 check_symbols(); 3931 pack_symbols(); 3932 pack_grammar(); 3933 free_symbols(); 3934 print_grammar(); 3935 #if defined(YYBTYACC) 3936 if (destructor) 3937 finalize_destructors(); 3938 #endif 3939 free_tags(); 3940 } 3941 3942 #ifdef NO_LEAKS 3943 static param * 3944 free_declarations(param *list) 3945 { 3946 while (list != 0) 3947 { 3948 param *next = list->next; 3949 free(list->type); 3950 free(list->name); 3951 free(list->type2); 3952 free(list); 3953 list = next; 3954 } 3955 return list; 3956 } 3957 3958 void 3959 reader_leaks(void) 3960 { 3961 lex_param = free_declarations(lex_param); 3962 parse_param = free_declarations(parse_param); 3963 3964 DO_FREE(line); 3965 DO_FREE(rrhs); 3966 DO_FREE(rlhs); 3967 DO_FREE(rprec); 3968 DO_FREE(ritem); 3969 DO_FREE(rassoc); 3970 DO_FREE(cache); 3971 DO_FREE(name_pool); 3972 DO_FREE(symbol_name); 3973 DO_FREE(symbol_prec); 3974 DO_FREE(symbol_assoc); 3975 DO_FREE(symbol_value); 3976 #if defined(YYBTYACC) 3977 DO_FREE(symbol_pval); 3978 DO_FREE(symbol_destructor); 3979 DO_FREE(symbol_type_tag); 3980 #endif 3981 } 3982 #endif 3983