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