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