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