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