1/* $OpenBSD: reader.c,v 1.35 2024/05/21 05:00:48 jsg Exp $ */ 2/* $NetBSD: reader.c,v 1.5 1996/03/19 03:21:43 jtc Exp $ */ 3 4/* 5 * Copyright (c) 1989 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Robert Paul Corbett. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include <limits.h> 37#include "defs.h" 38 39/* The line size must be a positive integer. One hundred was chosen */ 40/* because few lines in Yacc input grammars exceed 100 characters. */ 41/* Note that if a line exceeds LINESIZE characters, the line buffer */ 42/* will be expanded to accommodate it. */ 43 44#define LINESIZE 100 45 46char *cache; 47int cinc, cache_size; 48 49int ntags, tagmax; 50char **tag_table; 51 52char saw_eof, unionized; 53char *cptr, *line; 54int linesize; 55 56bucket *goal; 57int prec; 58int gensym; 59char last_was_action; 60 61int maxitems; 62bucket **pitem; 63 64int maxrules; 65bucket **plhs; 66 67int name_pool_size; 68char *name_pool; 69 70void cachec(int); 71void get_line(void); 72char *dup_line(void); 73void skip_comment(void); 74int nextc(void); 75int keyword(void); 76void copy_ident(void); 77void copy_text(void); 78void copy_union(void); 79bucket *get_literal(void); 80int is_reserved(char *); 81bucket *get_name(void); 82int get_number(void); 83char *get_tag(void); 84void declare_tokens(int); 85void declare_types(void); 86void declare_start(void); 87void read_declarations(void); 88void initialize_grammar(void); 89void expand_items(void); 90void expand_rules(void); 91void advance_to_start(void); 92void start_rule(bucket *, int); 93void end_rule(void); 94void insert_empty_rule(void); 95void add_symbol(void); 96void copy_action(void); 97int mark_symbol(void); 98void read_grammar(void); 99void free_tags(void); 100void pack_names(void); 101void check_symbols(void); 102void pack_symbols(void); 103void pack_grammar(void); 104void print_grammar(void); 105 106char line_format[] = "#line %d \"%s\"\n"; 107 108void 109cachec(int c) 110{ 111 assert(cinc >= 0); 112 if (cinc >= cache_size) { 113 cache_size += 256; 114 cache = realloc(cache, cache_size); 115 if (cache == NULL) 116 no_space(); 117 } 118 cache[cinc] = c; 119 ++cinc; 120} 121 122 123void 124get_line(void) 125{ 126 FILE *f = input_file; 127 int c, i; 128 129 if (saw_eof || (c = getc(f)) == EOF) { 130 if (line) { 131 free(line); 132 line = 0; 133 } 134 cptr = 0; 135 saw_eof = 1; 136 return; 137 } 138 if (line == NULL || linesize != (LINESIZE + 1)) { 139 free(line); 140 linesize = LINESIZE + 1; 141 line = malloc(linesize); 142 if (line == NULL) 143 no_space(); 144 } 145 i = 0; 146 ++lineno; 147 for (;;) { 148 line[i] = c; 149 if (c == '\n') { 150 cptr = line; 151 return; 152 } 153 if (++i >= linesize) { 154 linesize += LINESIZE; 155 line = realloc(line, linesize); 156 if (line == NULL) 157 no_space(); 158 } 159 c = getc(f); 160 if (c == EOF) { 161 line[i] = '\n'; 162 saw_eof = 1; 163 cptr = line; 164 return; 165 } 166 } 167} 168 169 170char * 171dup_line(void) 172{ 173 char *p, *s, *t; 174 175 if (line == NULL) 176 return (0); 177 s = line; 178 while (*s != '\n') 179 ++s; 180 p = malloc(s - line + 1); 181 if (p == NULL) 182 no_space(); 183 184 s = line; 185 t = p; 186 while ((*t++ = *s++) != '\n') 187 continue; 188 return (p); 189} 190 191 192void 193skip_comment(void) 194{ 195 char *s; 196 int st_lineno = lineno; 197 char *st_line = dup_line(); 198 char *st_cptr = st_line + (cptr - line); 199 200 s = cptr + 2; 201 for (;;) { 202 if (*s == '*' && s[1] == '/') { 203 cptr = s + 2; 204 free(st_line); 205 return; 206 } 207 if (*s == '\n') { 208 get_line(); 209 if (line == NULL) 210 unterminated_comment(st_lineno, st_line, st_cptr); 211 s = cptr; 212 } else 213 ++s; 214 } 215} 216 217 218int 219nextc(void) 220{ 221 char *s; 222 223 if (line == NULL) { 224 get_line(); 225 if (line == NULL) 226 return (EOF); 227 } 228 s = cptr; 229 for (;;) { 230 switch (*s) { 231 case '\n': 232 get_line(); 233 if (line == NULL) 234 return (EOF); 235 s = cptr; 236 break; 237 238 case ' ': 239 case '\t': 240 case '\f': 241 case '\r': 242 case '\v': 243 case ',': 244 case ';': 245 ++s; 246 break; 247 248 case '\\': 249 cptr = s; 250 return ('%'); 251 252 case '/': 253 if (s[1] == '*') { 254 cptr = s; 255 skip_comment(); 256 s = cptr; 257 break; 258 } else if (s[1] == '/') { 259 get_line(); 260 if (line == NULL) 261 return (EOF); 262 s = cptr; 263 break; 264 } 265 /* fall through */ 266 267 default: 268 cptr = s; 269 return ((unsigned char) *s); 270 } 271 } 272} 273 274 275int 276keyword(void) 277{ 278 int c; 279 char *t_cptr = cptr; 280 281 c = (unsigned char) *++cptr; 282 if (isalpha(c)) { 283 cinc = 0; 284 for (;;) { 285 if (isalpha(c)) { 286 if (isupper(c)) 287 c = tolower(c); 288 cachec(c); 289 } else if (isdigit(c) || c == '_' || c == '.' || c == '$') 290 cachec(c); 291 else 292 break; 293 c = (unsigned char) *++cptr; 294 } 295 cachec(NUL); 296 297 if (strcmp(cache, "token") == 0 || strcmp(cache, "term") == 0) 298 return (TOKEN); 299 if (strcmp(cache, "type") == 0) 300 return (TYPE); 301 if (strcmp(cache, "left") == 0) 302 return (LEFT); 303 if (strcmp(cache, "right") == 0) 304 return (RIGHT); 305 if (strcmp(cache, "nonassoc") == 0 || strcmp(cache, "binary") == 0) 306 return (NONASSOC); 307 if (strcmp(cache, "start") == 0) 308 return (START); 309 if (strcmp(cache, "union") == 0) 310 return (UNION); 311 if (strcmp(cache, "ident") == 0) 312 return (IDENT); 313 if (strcmp(cache, "expect") == 0) 314 return (EXPECT); 315 } else { 316 ++cptr; 317 if (c == '{') 318 return (TEXT); 319 if (c == '%' || c == '\\') 320 return (MARK); 321 if (c == '<') 322 return (LEFT); 323 if (c == '>') 324 return (RIGHT); 325 if (c == '0') 326 return (TOKEN); 327 if (c == '2') 328 return (NONASSOC); 329 } 330 syntax_error(lineno, line, t_cptr); 331 /* NOTREACHED */ 332 return (0); 333} 334 335 336void 337copy_ident(void) 338{ 339 int c; 340 FILE *f = output_file; 341 342 c = nextc(); 343 if (c == EOF) 344 unexpected_EOF(); 345 if (c != '"') 346 syntax_error(lineno, line, cptr); 347 ++outline; 348 fprintf(f, "#ident \""); 349 for (;;) { 350 c = (unsigned char) *++cptr; 351 if (c == '\n') { 352 fprintf(f, "\"\n"); 353 return; 354 } 355 putc(c, f); 356 if (c == '"') { 357 putc('\n', f); 358 ++cptr; 359 return; 360 } 361 } 362} 363 364 365void 366copy_text(void) 367{ 368 int c; 369 int quote; 370 FILE *f = text_file; 371 int need_newline = 0; 372 int t_lineno = lineno; 373 char *t_line = dup_line(); 374 char *t_cptr = t_line + (cptr - line - 2); 375 376 if (*cptr == '\n') { 377 get_line(); 378 if (line == NULL) 379 unterminated_text(t_lineno, t_line, t_cptr); 380 } 381 if (!lflag) 382 fprintf(f, line_format, lineno, input_file_name); 383 384loop: 385 c = (unsigned char) *cptr++; 386 switch (c) { 387 case '\n': 388next_line: 389 putc('\n', f); 390 need_newline = 0; 391 get_line(); 392 if (line) 393 goto loop; 394 unterminated_text(t_lineno, t_line, t_cptr); 395 396 case '\'': 397 case '"': { 398 int s_lineno = lineno; 399 char *s_line = dup_line(); 400 char *s_cptr = s_line + (cptr - line - 1); 401 402 quote = c; 403 putc(c, f); 404 for (;;) { 405 c = (unsigned char) *cptr++; 406 putc(c, f); 407 if (c == quote) { 408 need_newline = 1; 409 free(s_line); 410 goto loop; 411 } 412 if (c == '\n') 413 unterminated_string(s_lineno, s_line, s_cptr); 414 if (c == '\\') { 415 c = (unsigned char) *cptr++; 416 putc(c, f); 417 if (c == '\n') { 418 get_line(); 419 if (line == NULL) 420 unterminated_string(s_lineno, s_line, s_cptr); 421 } 422 } 423 } 424 } 425 426 case '/': 427 putc(c, f); 428 need_newline = 1; 429 c = (unsigned char) *cptr; 430 if (c == '/') { 431 putc('*', f); 432 while ((c = (unsigned char) *++cptr) != '\n') { 433 if (c == '*' && cptr[1] == '/') 434 fprintf(f, "* "); 435 else 436 putc(c, f); 437 } 438 fprintf(f, "*/"); 439 goto next_line; 440 } 441 if (c == '*') { 442 int c_lineno = lineno; 443 char *c_line = dup_line(); 444 char *c_cptr = c_line + (cptr - line - 1); 445 446 putc('*', f); 447 ++cptr; 448 for (;;) { 449 c = (unsigned char) *cptr++; 450 putc(c, f); 451 if (c == '*' && *cptr == '/') { 452 putc('/', f); 453 ++cptr; 454 free(c_line); 455 goto loop; 456 } 457 if (c == '\n') { 458 get_line(); 459 if (line == NULL) 460 unterminated_comment(c_lineno, c_line, c_cptr); 461 } 462 } 463 } 464 need_newline = 1; 465 goto loop; 466 467 case '%': 468 case '\\': 469 if (*cptr == '}') { 470 if (need_newline) 471 putc('\n', f); 472 ++cptr; 473 free(t_line); 474 return; 475 } 476 /* fall through */ 477 478 default: 479 putc(c, f); 480 need_newline = 1; 481 goto loop; 482 } 483} 484 485 486void 487copy_union(void) 488{ 489 int c, quote, depth; 490 int u_lineno = lineno; 491 char *u_line = dup_line(); 492 char *u_cptr = u_line + (cptr - line - 6); 493 494 if (unionized) 495 over_unionized(cptr - 6); 496 unionized = 1; 497 498 if (!lflag) 499 fprintf(text_file, line_format, lineno, input_file_name); 500 501 fprintf(text_file, "#ifndef YYSTYPE_DEFINED\n"); 502 fprintf(text_file, "#define YYSTYPE_DEFINED\n"); 503 fprintf(text_file, "typedef union"); 504 if (dflag) { 505 fprintf(union_file, "#ifndef YYSTYPE_DEFINED\n"); 506 fprintf(union_file, "#define YYSTYPE_DEFINED\n"); 507 fprintf(union_file, "typedef union"); 508 } 509 510 depth = 0; 511loop: 512 c = (unsigned char) *cptr++; 513 putc(c, text_file); 514 if (dflag) 515 putc(c, union_file); 516 switch (c) { 517 case '\n': 518next_line: 519 get_line(); 520 if (line == NULL) 521 unterminated_union(u_lineno, u_line, u_cptr); 522 goto loop; 523 524 case '{': 525 ++depth; 526 goto loop; 527 528 case '}': 529 if (--depth == 0) { 530 fprintf(text_file, " YYSTYPE;\n"); 531 fprintf(text_file, "#endif /* YYSTYPE_DEFINED */\n"); 532 free(u_line); 533 return; 534 } 535 goto loop; 536 537 case '\'': 538 case '"': { 539 int s_lineno = lineno; 540 char *s_line = dup_line(); 541 char *s_cptr = s_line + (cptr - line - 1); 542 543 quote = c; 544 for (;;) { 545 c = (unsigned char) *cptr++; 546 putc(c, text_file); 547 if (dflag) 548 putc(c, union_file); 549 if (c == quote) { 550 free(s_line); 551 goto loop; 552 } 553 if (c == '\n') 554 unterminated_string(s_lineno, s_line, s_cptr); 555 if (c == '\\') { 556 c = (unsigned char) *cptr++; 557 putc(c, text_file); 558 if (dflag) 559 putc(c, union_file); 560 if (c == '\n') { 561 get_line(); 562 if (line == NULL) 563 unterminated_string(s_lineno, 564 s_line, s_cptr); 565 } 566 } 567 } 568 } 569 570 case '/': 571 c = (unsigned char) *cptr; 572 if (c == '/') { 573 putc('*', text_file); 574 if (dflag) 575 putc('*', union_file); 576 while ((c = (unsigned char) *++cptr) != '\n') { 577 if (c == '*' && cptr[1] == '/') { 578 fprintf(text_file, "* "); 579 if (dflag) 580 fprintf(union_file, "* "); 581 } else { 582 putc(c, text_file); 583 if (dflag) 584 putc(c, union_file); 585 } 586 } 587 fprintf(text_file, "*/\n"); 588 if (dflag) 589 fprintf(union_file, "*/\n"); 590 goto next_line; 591 } 592 if (c == '*') { 593 int c_lineno = lineno; 594 char *c_line = dup_line(); 595 char *c_cptr = c_line + (cptr - line - 1); 596 597 putc('*', text_file); 598 if (dflag) 599 putc('*', union_file); 600 ++cptr; 601 for (;;) { 602 c = (unsigned char) *cptr++; 603 putc(c, text_file); 604 if (dflag) 605 putc(c, union_file); 606 if (c == '*' && *cptr == '/') { 607 putc('/', text_file); 608 if (dflag) 609 putc('/', union_file); 610 ++cptr; 611 free(c_line); 612 goto loop; 613 } 614 if (c == '\n') { 615 get_line(); 616 if (line == NULL) 617 unterminated_comment(c_lineno, 618 c_line, c_cptr); 619 } 620 } 621 } 622 goto loop; 623 624 default: 625 goto loop; 626 } 627} 628 629 630bucket * 631get_literal(void) 632{ 633 int c, quote, i, n; 634 char *s; 635 bucket *bp; 636 int s_lineno = lineno; 637 char *s_line = dup_line(); 638 char *s_cptr = s_line + (cptr - line); 639 640 quote = (unsigned char) *cptr++; 641 cinc = 0; 642 for (;;) { 643 c = (unsigned char) *cptr++; 644 if (c == quote) 645 break; 646 if (c == '\n') 647 unterminated_string(s_lineno, s_line, s_cptr); 648 if (c == '\\') { 649 char *c_cptr = cptr - 1; 650 unsigned long ulval; 651 652 c = (unsigned char) *cptr++; 653 switch (c) { 654 case '\n': 655 get_line(); 656 if (line == NULL) 657 unterminated_string(s_lineno, s_line, 658 s_cptr); 659 continue; 660 661 case '0': 662 case '1': 663 case '2': 664 case '3': 665 case '4': 666 case '5': 667 case '6': 668 case '7': 669 ulval = strtoul(cptr - 1, &s, 8); 670 if (s == cptr - 1 || ulval > MAXCHAR) 671 illegal_character(c_cptr); 672 c = (int) ulval; 673 cptr = s; 674 break; 675 676 case 'x': 677 ulval = strtoul(cptr, &s, 16); 678 if (s == cptr || ulval > MAXCHAR) 679 illegal_character(c_cptr); 680 c = (int) ulval; 681 cptr = s; 682 break; 683 684 case 'a': 685 c = 7; 686 break; 687 case 'b': 688 c = '\b'; 689 break; 690 case 'f': 691 c = '\f'; 692 break; 693 case 'n': 694 c = '\n'; 695 break; 696 case 'r': 697 c = '\r'; 698 break; 699 case 't': 700 c = '\t'; 701 break; 702 case 'v': 703 c = '\v'; 704 break; 705 } 706 } 707 cachec(c); 708 } 709 free(s_line); 710 711 n = cinc; 712 s = malloc(n); 713 if (s == NULL) 714 no_space(); 715 716 memcpy(s, cache, n); 717 718 cinc = 0; 719 if (n == 1) 720 cachec('\''); 721 else 722 cachec('"'); 723 724 for (i = 0; i < n; ++i) { 725 c = ((unsigned char *) s)[i]; 726 if (c == '\\' || c == cache[0]) { 727 cachec('\\'); 728 cachec(c); 729 } else if (isprint(c)) 730 cachec(c); 731 else { 732 cachec('\\'); 733 switch (c) { 734 case 7: 735 cachec('a'); 736 break; 737 case '\b': 738 cachec('b'); 739 break; 740 case '\f': 741 cachec('f'); 742 break; 743 case '\n': 744 cachec('n'); 745 break; 746 case '\r': 747 cachec('r'); 748 break; 749 case '\t': 750 cachec('t'); 751 break; 752 case '\v': 753 cachec('v'); 754 break; 755 default: 756 cachec(((c >> 6) & 7) + '0'); 757 cachec(((c >> 3) & 7) + '0'); 758 cachec((c & 7) + '0'); 759 break; 760 } 761 } 762 } 763 764 if (n == 1) 765 cachec('\''); 766 else 767 cachec('"'); 768 769 cachec(NUL); 770 bp = lookup(cache); 771 bp->class = TERM; 772 if (n == 1 && bp->value == UNDEFINED) 773 bp->value = *(unsigned char *) s; 774 free(s); 775 776 return (bp); 777} 778 779 780int 781is_reserved(char *name) 782{ 783 char *s; 784 785 if (strcmp(name, ".") == 0 || 786 strcmp(name, "$accept") == 0 || 787 strcmp(name, "$end") == 0) 788 return (1); 789 790 if (name[0] == '$' && name[1] == '$' && isdigit((unsigned char) name[2])) { 791 s = name + 3; 792 while (isdigit((unsigned char) *s)) 793 ++s; 794 if (*s == NUL) 795 return (1); 796 } 797 return (0); 798} 799 800 801bucket * 802get_name(void) 803{ 804 int c; 805 806 cinc = 0; 807 for (c = (unsigned char) *cptr; IS_IDENT(c); c = (unsigned char) *++cptr) 808 cachec(c); 809 cachec(NUL); 810 811 if (is_reserved(cache)) 812 used_reserved(cache); 813 814 return (lookup(cache)); 815} 816 817 818int 819get_number(void) 820{ 821 unsigned long ul; 822 char *p; 823 824 ul = strtoul(cptr, &p, 10); 825 if (ul > INT_MAX) 826 syntax_error(lineno, line, cptr); 827 cptr = p; 828 return (ul); 829} 830 831 832char * 833get_tag(void) 834{ 835 int c, i; 836 char *s; 837 int t_lineno = lineno; 838 char *t_line = dup_line(); 839 char *t_cptr = t_line + (cptr - line); 840 841 ++cptr; 842 c = nextc(); 843 if (c == EOF) 844 unexpected_EOF(); 845 if (!isalpha(c) && c != '_' && c != '$') 846 illegal_tag(t_lineno, t_line, t_cptr); 847 848 cinc = 0; 849 do { 850 cachec(c); 851 c = (unsigned char) *++cptr; 852 } while (IS_IDENT(c)); 853 cachec(NUL); 854 855 c = nextc(); 856 if (c == EOF) 857 unexpected_EOF(); 858 if (c != '>') 859 illegal_tag(t_lineno, t_line, t_cptr); 860 free(t_line); 861 ++cptr; 862 863 for (i = 0; i < ntags; ++i) { 864 if (strcmp(cache, tag_table[i]) == 0) 865 return (tag_table[i]); 866 } 867 868 if (ntags >= tagmax) { 869 tagmax += 16; 870 tag_table = reallocarray(tag_table, tagmax, sizeof(char *)); 871 if (tag_table == NULL) 872 no_space(); 873 } 874 s = malloc(cinc); 875 if (s == NULL) 876 no_space(); 877 strlcpy(s, cache, cinc); 878 tag_table[ntags] = s; 879 ++ntags; 880 return (s); 881} 882 883 884void 885declare_tokens(int assoc) 886{ 887 int c; 888 bucket *bp; 889 int value; 890 char *tag = 0; 891 892 if (assoc != TOKEN) 893 ++prec; 894 895 c = nextc(); 896 if (c == EOF) 897 unexpected_EOF(); 898 if (c == '<') { 899 tag = get_tag(); 900 c = nextc(); 901 if (c == EOF) 902 unexpected_EOF(); 903 } 904 for (;;) { 905 if (isalpha(c) || c == '_' || c == '.' || c == '$') 906 bp = get_name(); 907 else if (c == '\'' || c == '"') 908 bp = get_literal(); 909 else 910 return; 911 912 if (bp == goal) 913 tokenized_start(bp->name); 914 bp->class = TERM; 915 916 if (tag) { 917 if (bp->tag && tag != bp->tag) 918 retyped_warning(bp->name); 919 bp->tag = tag; 920 } 921 if (assoc != TOKEN) { 922 if (bp->prec && prec != bp->prec) 923 reprec_warning(bp->name); 924 bp->assoc = assoc; 925 bp->prec = prec; 926 } 927 c = nextc(); 928 if (c == EOF) 929 unexpected_EOF(); 930 if (isdigit(c)) { 931 value = get_number(); 932 if (bp->value != UNDEFINED && value != bp->value) 933 revalued_warning(bp->name); 934 bp->value = value; 935 c = nextc(); 936 if (c == EOF) 937 unexpected_EOF(); 938 } 939 } 940} 941 942 943/* 944 * %expect requires special handling as it really isn't part of the yacc 945 * grammar only a flag for yacc proper. 946 */ 947static void 948declare_expect(int assoc) 949{ 950 int c; 951 952 if (assoc != EXPECT) 953 ++prec; 954 955 /* 956 * Stay away from nextc - doesn't detect EOL and will read to EOF. 957 */ 958 c = (unsigned char) *++cptr; 959 if (c == EOF) 960 unexpected_EOF(); 961 962 for (;;) { 963 if (isdigit(c)) { 964 SRexpect = get_number(); 965 break; 966 } 967 /* 968 * Looking for number before EOL. 969 * Spaces, tabs, and numbers are ok. 970 * Words, punc., etc. are syntax errors. 971 */ 972 else if (c == '\n' || isalpha(c) || !isspace(c)) { 973 syntax_error(lineno, line, cptr); 974 } else { 975 c = (unsigned char) *++cptr; 976 if (c == EOF) 977 unexpected_EOF(); 978 } 979 } 980} 981 982 983void 984declare_types(void) 985{ 986 int c; 987 bucket *bp; 988 char *tag; 989 990 c = nextc(); 991 if (c == EOF) 992 unexpected_EOF(); 993 if (c != '<') 994 syntax_error(lineno, line, cptr); 995 tag = get_tag(); 996 997 for (;;) { 998 c = nextc(); 999 if (isalpha(c) || c == '_' || c == '.' || c == '$') 1000 bp = get_name(); 1001 else if (c == '\'' || c == '"') 1002 bp = get_literal(); 1003 else 1004 return; 1005 1006 if (bp->tag && tag != bp->tag) 1007 retyped_warning(bp->name); 1008 bp->tag = tag; 1009 } 1010} 1011 1012 1013void 1014declare_start(void) 1015{ 1016 int c; 1017 bucket *bp; 1018 1019 c = nextc(); 1020 if (c == EOF) 1021 unexpected_EOF(); 1022 if (!isalpha(c) && c != '_' && c != '.' && c != '$') 1023 syntax_error(lineno, line, cptr); 1024 bp = get_name(); 1025 if (bp->class == TERM) 1026 terminal_start(bp->name); 1027 if (goal && goal != bp) 1028 restarted_warning(); 1029 goal = bp; 1030} 1031 1032 1033void 1034read_declarations(void) 1035{ 1036 int c, k; 1037 1038 cache_size = 256; 1039 cache = malloc(cache_size); 1040 if (cache == NULL) 1041 no_space(); 1042 1043 for (;;) { 1044 c = nextc(); 1045 if (c == EOF) 1046 unexpected_EOF(); 1047 if (c != '%') 1048 syntax_error(lineno, line, cptr); 1049 switch (k = keyword()) { 1050 case MARK: 1051 return; 1052 1053 case IDENT: 1054 copy_ident(); 1055 break; 1056 1057 case TEXT: 1058 copy_text(); 1059 break; 1060 1061 case UNION: 1062 copy_union(); 1063 break; 1064 1065 case TOKEN: 1066 case LEFT: 1067 case RIGHT: 1068 case NONASSOC: 1069 declare_tokens(k); 1070 break; 1071 1072 case EXPECT: 1073 declare_expect(k); 1074 break; 1075 1076 case TYPE: 1077 declare_types(); 1078 break; 1079 1080 case START: 1081 declare_start(); 1082 break; 1083 } 1084 } 1085} 1086 1087 1088void 1089initialize_grammar(void) 1090{ 1091 nitems = 4; 1092 maxitems = 300; 1093 pitem = calloc(maxitems, sizeof(bucket *)); 1094 if (pitem == NULL) 1095 no_space(); 1096 1097 nrules = 3; 1098 maxrules = 100; 1099 plhs = reallocarray(NULL, maxrules, sizeof(bucket *)); 1100 if (plhs == NULL) 1101 no_space(); 1102 plhs[0] = 0; 1103 plhs[1] = 0; 1104 plhs[2] = 0; 1105 rprec = reallocarray(NULL, maxrules, sizeof(short)); 1106 if (rprec == NULL) 1107 no_space(); 1108 rprec[0] = 0; 1109 rprec[1] = 0; 1110 rprec[2] = 0; 1111 rassoc = reallocarray(NULL, maxrules, sizeof(char)); 1112 if (rassoc == NULL) 1113 no_space(); 1114 rassoc[0] = TOKEN; 1115 rassoc[1] = TOKEN; 1116 rassoc[2] = TOKEN; 1117} 1118 1119 1120void 1121expand_items(void) 1122{ 1123 int olditems = maxitems; 1124 1125 maxitems += 300; 1126 pitem = reallocarray(pitem, maxitems, sizeof(bucket *)); 1127 if (pitem == NULL) 1128 no_space(); 1129 memset(pitem + olditems, 0, (maxitems - olditems) * sizeof(bucket *)); 1130} 1131 1132 1133void 1134expand_rules(void) 1135{ 1136 maxrules += 100; 1137 plhs = reallocarray(plhs, maxrules, sizeof(bucket *)); 1138 if (plhs == NULL) 1139 no_space(); 1140 rprec = reallocarray(rprec, maxrules, sizeof(short)); 1141 if (rprec == NULL) 1142 no_space(); 1143 rassoc = reallocarray(rassoc, maxrules, sizeof(char)); 1144 if (rassoc == NULL) 1145 no_space(); 1146} 1147 1148 1149void 1150advance_to_start(void) 1151{ 1152 int c; 1153 bucket *bp; 1154 char *s_cptr; 1155 int s_lineno; 1156 1157 for (;;) { 1158 c = nextc(); 1159 if (c != '%') 1160 break; 1161 s_cptr = cptr; 1162 switch (keyword()) { 1163 case MARK: 1164 no_grammar(); 1165 1166 case TEXT: 1167 copy_text(); 1168 break; 1169 1170 case START: 1171 declare_start(); 1172 break; 1173 1174 default: 1175 syntax_error(lineno, line, s_cptr); 1176 } 1177 } 1178 1179 c = nextc(); 1180 if (!isalpha(c) && c != '_' && c != '.' && c != '_') 1181 syntax_error(lineno, line, cptr); 1182 bp = get_name(); 1183 if (goal == NULL) { 1184 if (bp->class == TERM) 1185 terminal_start(bp->name); 1186 goal = bp; 1187 } 1188 s_lineno = lineno; 1189 c = nextc(); 1190 if (c == EOF) 1191 unexpected_EOF(); 1192 if (c != ':') 1193 syntax_error(lineno, line, cptr); 1194 start_rule(bp, s_lineno); 1195 ++cptr; 1196} 1197 1198 1199void 1200start_rule(bucket * bp, int s_lineno) 1201{ 1202 if (bp->class == TERM) 1203 terminal_lhs(s_lineno); 1204 bp->class = NONTERM; 1205 if (nrules >= maxrules) 1206 expand_rules(); 1207 plhs[nrules] = bp; 1208 rprec[nrules] = UNDEFINED; 1209 rassoc[nrules] = TOKEN; 1210} 1211 1212 1213void 1214end_rule(void) 1215{ 1216 int i; 1217 1218 if (!last_was_action && plhs[nrules]->tag) { 1219 for (i = nitems - 1; pitem[i]; --i) 1220 continue; 1221 if (i == maxitems - 1 || pitem[i + 1] == 0 || 1222 pitem[i + 1]->tag != plhs[nrules]->tag) 1223 default_action_warning(); 1224 } 1225 last_was_action = 0; 1226 if (nitems >= maxitems) 1227 expand_items(); 1228 pitem[nitems] = 0; 1229 ++nitems; 1230 ++nrules; 1231} 1232 1233 1234void 1235insert_empty_rule(void) 1236{ 1237 bucket *bp, **bpp; 1238 1239 assert(cache); 1240 snprintf(cache, cache_size, "$$%d", ++gensym); 1241 bp = make_bucket(cache); 1242 last_symbol->next = bp; 1243 last_symbol = bp; 1244 bp->tag = plhs[nrules]->tag; 1245 bp->class = NONTERM; 1246 1247 if ((nitems += 2) > maxitems) 1248 expand_items(); 1249 bpp = pitem + nitems - 1; 1250 *bpp-- = bp; 1251 while ((bpp[0] = bpp[-1])) 1252 --bpp; 1253 1254 if (++nrules >= maxrules) 1255 expand_rules(); 1256 plhs[nrules] = plhs[nrules - 1]; 1257 plhs[nrules - 1] = bp; 1258 rprec[nrules] = rprec[nrules - 1]; 1259 rprec[nrules - 1] = 0; 1260 rassoc[nrules] = rassoc[nrules - 1]; 1261 rassoc[nrules - 1] = TOKEN; 1262} 1263 1264 1265void 1266add_symbol(void) 1267{ 1268 int c; 1269 bucket *bp; 1270 int s_lineno = lineno; 1271 1272 c = (unsigned char) *cptr; 1273 if (c == '\'' || c == '"') 1274 bp = get_literal(); 1275 else 1276 bp = get_name(); 1277 1278 c = nextc(); 1279 if (c == ':') { 1280 end_rule(); 1281 start_rule(bp, s_lineno); 1282 ++cptr; 1283 return; 1284 } 1285 if (last_was_action) 1286 insert_empty_rule(); 1287 last_was_action = 0; 1288 1289 if (++nitems > maxitems) 1290 expand_items(); 1291 pitem[nitems - 1] = bp; 1292} 1293 1294 1295void 1296copy_action(void) 1297{ 1298 int c, i, n, depth, quote; 1299 char *tag; 1300 FILE *f = action_file; 1301 int a_lineno = lineno; 1302 char *a_line = dup_line(); 1303 char *a_cptr = a_line + (cptr - line); 1304 1305 if (last_was_action) 1306 insert_empty_rule(); 1307 last_was_action = 1; 1308 1309 fprintf(f, "case %d:\n", nrules - 2); 1310 if (!lflag) 1311 fprintf(f, line_format, lineno, input_file_name); 1312 if (*cptr == '=') 1313 ++cptr; 1314 1315 n = 0; 1316 for (i = nitems - 1; pitem[i]; --i) 1317 ++n; 1318 1319 depth = 0; 1320loop: 1321 c = (unsigned char) *cptr; 1322 if (c == '$') { 1323 if (cptr[1] == '<') { 1324 int d_lineno = lineno; 1325 char *d_line = dup_line(); 1326 char *d_cptr = d_line + (cptr - line); 1327 1328 ++cptr; 1329 tag = get_tag(); 1330 c = (unsigned char) *cptr; 1331 if (c == '$') { 1332 fprintf(f, "yyval.%s", tag); 1333 ++cptr; 1334 free(d_line); 1335 goto loop; 1336 } else if (isdigit(c)) { 1337 i = get_number(); 1338 if (i > n) 1339 dollar_warning(d_lineno, i); 1340 fprintf(f, "yyvsp[%d].%s", i - n, tag); 1341 free(d_line); 1342 goto loop; 1343 } else if (c == '-' && isdigit((unsigned char) cptr[1])) { 1344 ++cptr; 1345 i = -get_number() - n; 1346 fprintf(f, "yyvsp[%d].%s", i, tag); 1347 free(d_line); 1348 goto loop; 1349 } else 1350 dollar_error(d_lineno, d_line, d_cptr); 1351 } else if (cptr[1] == '$') { 1352 if (ntags) { 1353 tag = plhs[nrules]->tag; 1354 if (tag == NULL) 1355 untyped_lhs(); 1356 fprintf(f, "yyval.%s", tag); 1357 } else 1358 fprintf(f, "yyval"); 1359 cptr += 2; 1360 goto loop; 1361 } else if (isdigit((unsigned char) cptr[1])) { 1362 ++cptr; 1363 i = get_number(); 1364 if (ntags) { 1365 if (i <= 0 || i > n) 1366 unknown_rhs(i); 1367 tag = pitem[nitems + i - n - 1]->tag; 1368 if (tag == NULL) 1369 untyped_rhs(i, pitem[nitems + i - n - 1]->name); 1370 fprintf(f, "yyvsp[%d].%s", i - n, tag); 1371 } else { 1372 if (i > n) 1373 dollar_warning(lineno, i); 1374 fprintf(f, "yyvsp[%d]", i - n); 1375 } 1376 goto loop; 1377 } else if (cptr[1] == '-') { 1378 cptr += 2; 1379 i = get_number(); 1380 if (ntags) 1381 unknown_rhs(-i); 1382 fprintf(f, "yyvsp[%d]", -i - n); 1383 goto loop; 1384 } 1385 } 1386 if (isalpha(c) || c == '_' || c == '$') { 1387 do { 1388 putc(c, f); 1389 c = (unsigned char) *++cptr; 1390 } while (isalnum(c) || c == '_' || c == '$'); 1391 goto loop; 1392 } 1393 putc(c, f); 1394 ++cptr; 1395 switch (c) { 1396 case '\n': 1397next_line: 1398 get_line(); 1399 if (line) 1400 goto loop; 1401 unterminated_action(a_lineno, a_line, a_cptr); 1402 1403 case ';': 1404 if (depth > 0) 1405 goto loop; 1406 fprintf(f, "\nbreak;\n"); 1407 free(a_line); 1408 return; 1409 1410 case '{': 1411 ++depth; 1412 goto loop; 1413 1414 case '}': 1415 if (--depth > 0) 1416 goto loop; 1417 fprintf(f, "\nbreak;\n"); 1418 free(a_line); 1419 return; 1420 1421 case '\'': 1422 case '"': { 1423 int s_lineno = lineno; 1424 char *s_line = dup_line(); 1425 char *s_cptr = s_line + (cptr - line - 1); 1426 1427 quote = c; 1428 for (;;) { 1429 c = (unsigned char) *cptr++; 1430 putc(c, f); 1431 if (c == quote) { 1432 free(s_line); 1433 goto loop; 1434 } 1435 if (c == '\n') 1436 unterminated_string(s_lineno, s_line, s_cptr); 1437 if (c == '\\') { 1438 c = (unsigned char) *cptr++; 1439 putc(c, f); 1440 if (c == '\n') { 1441 get_line(); 1442 if (line == NULL) 1443 unterminated_string(s_lineno, s_line, s_cptr); 1444 } 1445 } 1446 } 1447 } 1448 1449 case '/': 1450 c = (unsigned char) *cptr; 1451 if (c == '/') { 1452 putc('*', f); 1453 while ((c = (unsigned char) *++cptr) != '\n') { 1454 if (c == '*' && cptr[1] == '/') 1455 fprintf(f, "* "); 1456 else 1457 putc(c, f); 1458 } 1459 fprintf(f, "*/\n"); 1460 goto next_line; 1461 } 1462 if (c == '*') { 1463 int c_lineno = lineno; 1464 char *c_line = dup_line(); 1465 char *c_cptr = c_line + (cptr - line - 1); 1466 1467 putc('*', f); 1468 ++cptr; 1469 for (;;) { 1470 c = (unsigned char) *cptr++; 1471 putc(c, f); 1472 if (c == '*' && *cptr == '/') { 1473 putc('/', f); 1474 ++cptr; 1475 free(c_line); 1476 goto loop; 1477 } 1478 if (c == '\n') { 1479 get_line(); 1480 if (line == NULL) 1481 unterminated_comment(c_lineno, c_line, c_cptr); 1482 } 1483 } 1484 } 1485 goto loop; 1486 1487 default: 1488 goto loop; 1489 } 1490} 1491 1492 1493int 1494mark_symbol(void) 1495{ 1496 int c; 1497 bucket *bp = NULL; 1498 1499 c = (unsigned char) cptr[1]; 1500 if (c == '%' || c == '\\') { 1501 cptr += 2; 1502 return (1); 1503 } 1504 if (c == '=') 1505 cptr += 2; 1506 else if ((c == 'p' || c == 'P') && 1507 ((c = cptr[2]) == 'r' || c == 'R') && 1508 ((c = cptr[3]) == 'e' || c == 'E') && 1509 ((c = cptr[4]) == 'c' || c == 'C') && 1510 ((c = (unsigned char) cptr[5], !IS_IDENT(c)))) 1511 cptr += 5; 1512 else 1513 syntax_error(lineno, line, cptr); 1514 1515 c = nextc(); 1516 if (isalpha(c) || c == '_' || c == '.' || c == '$') 1517 bp = get_name(); 1518 else if (c == '\'' || c == '"') 1519 bp = get_literal(); 1520 else { 1521 syntax_error(lineno, line, cptr); 1522 /* NOTREACHED */ 1523 } 1524 1525 if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules]) 1526 prec_redeclared(); 1527 1528 rprec[nrules] = bp->prec; 1529 rassoc[nrules] = bp->assoc; 1530 return (0); 1531} 1532 1533 1534void 1535read_grammar(void) 1536{ 1537 int c; 1538 1539 initialize_grammar(); 1540 advance_to_start(); 1541 1542 for (;;) { 1543 c = nextc(); 1544 if (c == EOF) 1545 break; 1546 if (isalpha(c) || c == '_' || c == '.' || c == '$' || c == '\'' || 1547 c == '"') 1548 add_symbol(); 1549 else if (c == '{' || c == '=') 1550 copy_action(); 1551 else if (c == '|') { 1552 end_rule(); 1553 start_rule(plhs[nrules - 1], 0); 1554 ++cptr; 1555 } else if (c == '%') { 1556 if (mark_symbol()) 1557 break; 1558 } else 1559 syntax_error(lineno, line, cptr); 1560 } 1561 end_rule(); 1562} 1563 1564 1565void 1566free_tags(void) 1567{ 1568 int i; 1569 1570 if (tag_table == NULL) 1571 return; 1572 1573 for (i = 0; i < ntags; ++i) { 1574 assert(tag_table[i]); 1575 free(tag_table[i]); 1576 } 1577 free(tag_table); 1578} 1579 1580 1581void 1582pack_names(void) 1583{ 1584 bucket *bp; 1585 char *p, *s, *t; 1586 1587 name_pool_size = 13; /* 13 == sizeof("$end") + sizeof("$accept") */ 1588 for (bp = first_symbol; bp; bp = bp->next) 1589 name_pool_size += strlen(bp->name) + 1; 1590 name_pool = malloc(name_pool_size); 1591 if (name_pool == NULL) 1592 no_space(); 1593 1594 strlcpy(name_pool, "$accept", name_pool_size); 1595 strlcpy(name_pool + 8, "$end", name_pool_size - 8); 1596 t = name_pool + 13; 1597 for (bp = first_symbol; bp; bp = bp->next) { 1598 p = t; 1599 s = bp->name; 1600 while ((*t++ = *s++)) 1601 continue; 1602 free(bp->name); 1603 bp->name = p; 1604 } 1605} 1606 1607 1608void 1609check_symbols(void) 1610{ 1611 bucket *bp; 1612 1613 if (goal->class == UNKNOWN) 1614 undefined_goal(goal->name); 1615 1616 for (bp = first_symbol; bp; bp = bp->next) { 1617 if (bp->class == UNKNOWN) { 1618 undefined_symbol_warning(bp->name); 1619 bp->class = TERM; 1620 } 1621 } 1622} 1623 1624 1625void 1626pack_symbols(void) 1627{ 1628 bucket *bp; 1629 bucket **v; 1630 int i, j, k, n; 1631 1632 nsyms = 2; 1633 ntokens = 1; 1634 for (bp = first_symbol; bp; bp = bp->next) { 1635 ++nsyms; 1636 if (bp->class == TERM) 1637 ++ntokens; 1638 } 1639 start_symbol = ntokens; 1640 nvars = nsyms - ntokens; 1641 1642 symbol_name = reallocarray(NULL, nsyms, sizeof(char *)); 1643 if (symbol_name == NULL) 1644 no_space(); 1645 symbol_value = reallocarray(NULL, nsyms, sizeof(short)); 1646 if (symbol_value == NULL) 1647 no_space(); 1648 symbol_prec = reallocarray(NULL, nsyms, sizeof(short)); 1649 if (symbol_prec == NULL) 1650 no_space(); 1651 symbol_assoc = malloc(nsyms); 1652 if (symbol_assoc == NULL) 1653 no_space(); 1654 1655 v = reallocarray(NULL, nsyms, sizeof(bucket *)); 1656 if (v == NULL) 1657 no_space(); 1658 1659 v[0] = 0; 1660 v[start_symbol] = 0; 1661 1662 i = 1; 1663 j = start_symbol + 1; 1664 for (bp = first_symbol; bp; bp = bp->next) { 1665 if (bp->class == TERM) 1666 v[i++] = bp; 1667 else 1668 v[j++] = bp; 1669 } 1670 assert(i == ntokens && j == nsyms); 1671 1672 for (i = 1; i < ntokens; ++i) 1673 v[i]->index = i; 1674 1675 goal->index = start_symbol + 1; 1676 k = start_symbol + 2; 1677 while (++i < nsyms) 1678 if (v[i] != goal) { 1679 v[i]->index = k; 1680 ++k; 1681 } 1682 goal->value = 0; 1683 k = 1; 1684 for (i = start_symbol + 1; i < nsyms; ++i) { 1685 if (v[i] != goal) { 1686 v[i]->value = k; 1687 ++k; 1688 } 1689 } 1690 1691 k = 0; 1692 for (i = 1; i < ntokens; ++i) { 1693 n = v[i]->value; 1694 if (n > 256) { 1695 for (j = k++; j > 0 && symbol_value[j - 1] > n; --j) 1696 symbol_value[j] = symbol_value[j - 1]; 1697 symbol_value[j] = n; 1698 } 1699 } 1700 1701 if (v[1]->value == UNDEFINED) 1702 v[1]->value = 256; 1703 1704 j = 0; 1705 n = 257; 1706 for (i = 2; i < ntokens; ++i) { 1707 if (v[i]->value == UNDEFINED) { 1708 while (j < k && n == symbol_value[j]) { 1709 while (++j < k && n == symbol_value[j]) 1710 continue; 1711 ++n; 1712 } 1713 v[i]->value = n; 1714 ++n; 1715 } 1716 } 1717 1718 symbol_name[0] = name_pool + 8; 1719 symbol_value[0] = 0; 1720 symbol_prec[0] = 0; 1721 symbol_assoc[0] = TOKEN; 1722 for (i = 1; i < ntokens; ++i) { 1723 symbol_name[i] = v[i]->name; 1724 symbol_value[i] = v[i]->value; 1725 symbol_prec[i] = v[i]->prec; 1726 symbol_assoc[i] = v[i]->assoc; 1727 } 1728 symbol_name[start_symbol] = name_pool; 1729 symbol_value[start_symbol] = -1; 1730 symbol_prec[start_symbol] = 0; 1731 symbol_assoc[start_symbol] = TOKEN; 1732 for (++i; i < nsyms; ++i) { 1733 k = v[i]->index; 1734 symbol_name[k] = v[i]->name; 1735 symbol_value[k] = v[i]->value; 1736 symbol_prec[k] = v[i]->prec; 1737 symbol_assoc[k] = v[i]->assoc; 1738 } 1739 1740 free(v); 1741} 1742 1743 1744void 1745pack_grammar(void) 1746{ 1747 int i, j; 1748 int assoc, pprec; 1749 1750 ritem = reallocarray(NULL, nitems, sizeof(short)); 1751 if (ritem == NULL) 1752 no_space(); 1753 rlhs = reallocarray(NULL, nrules, sizeof(short)); 1754 if (rlhs == NULL) 1755 no_space(); 1756 rrhs = reallocarray(NULL, nrules + 1, sizeof(short)); 1757 if (rrhs == NULL) 1758 no_space(); 1759 rprec = reallocarray(rprec, nrules, sizeof(short)); 1760 if (rprec == NULL) 1761 no_space(); 1762 rassoc = realloc(rassoc, nrules); 1763 if (rassoc == NULL) 1764 no_space(); 1765 1766 ritem[0] = -1; 1767 ritem[1] = goal->index; 1768 ritem[2] = 0; 1769 ritem[3] = -2; 1770 rlhs[0] = 0; 1771 rlhs[1] = 0; 1772 rlhs[2] = start_symbol; 1773 rrhs[0] = 0; 1774 rrhs[1] = 0; 1775 rrhs[2] = 1; 1776 1777 j = 4; 1778 for (i = 3; i < nrules; ++i) { 1779 rlhs[i] = plhs[i]->index; 1780 rrhs[i] = j; 1781 assoc = TOKEN; 1782 pprec = 0; 1783 while (pitem[j]) { 1784 ritem[j] = pitem[j]->index; 1785 if (pitem[j]->class == TERM) { 1786 pprec = pitem[j]->prec; 1787 assoc = pitem[j]->assoc; 1788 } 1789 ++j; 1790 } 1791 ritem[j] = -i; 1792 ++j; 1793 if (rprec[i] == UNDEFINED) { 1794 rprec[i] = pprec; 1795 rassoc[i] = assoc; 1796 } 1797 } 1798 rrhs[i] = j; 1799 1800 free(plhs); 1801 free(pitem); 1802} 1803 1804 1805void 1806print_grammar(void) 1807{ 1808 int i, j, k; 1809 int spacing = 0; 1810 FILE *f = verbose_file; 1811 1812 if (!vflag) 1813 return; 1814 1815 k = 1; 1816 for (i = 2; i < nrules; ++i) { 1817 if (rlhs[i] != rlhs[i - 1]) { 1818 if (i != 2) 1819 fprintf(f, "\n"); 1820 fprintf(f, "%4d %s :", i - 2, symbol_name[rlhs[i]]); 1821 spacing = strlen(symbol_name[rlhs[i]]) + 1; 1822 } else { 1823 fprintf(f, "%4d ", i - 2); 1824 j = spacing; 1825 while (--j >= 0) 1826 putc(' ', f); 1827 putc('|', f); 1828 } 1829 1830 while (ritem[k] >= 0) { 1831 fprintf(f, " %s", symbol_name[ritem[k]]); 1832 ++k; 1833 } 1834 ++k; 1835 putc('\n', f); 1836 } 1837} 1838 1839 1840void 1841reader(void) 1842{ 1843 write_section(banner); 1844 create_symbol_table(); 1845 read_declarations(); 1846 read_grammar(); 1847 free_symbol_table(); 1848 free_tags(); 1849 pack_names(); 1850 check_symbols(); 1851 pack_symbols(); 1852 pack_grammar(); 1853 free_symbols(); 1854 print_grammar(); 1855} 1856