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