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