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