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