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