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