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