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