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