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