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