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