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
46char *cache;
47int cinc, cache_size;
48
49int ntags, tagmax;
50char **tag_table;
51
52char saw_eof, unionized;
53char *cptr, *line;
54int linesize;
55
56bucket *goal;
57int prec;
58int gensym;
59char last_was_action;
60
61int maxitems;
62bucket **pitem;
63
64int maxrules;
65bucket **plhs;
66
67int name_pool_size;
68char *name_pool;
69
70void cachec(int);
71void get_line(void);
72char *dup_line(void);
73void skip_comment(void);
74int nextc(void);
75int keyword(void);
76void copy_ident(void);
77void copy_text(void);
78void copy_union(void);
79bucket *get_literal(void);
80int is_reserved(char *);
81bucket *get_name(void);
82int get_number(void);
83char *get_tag(void);
84void declare_tokens(int);
85void declare_types(void);
86void declare_start(void);
87void read_declarations(void);
88void initialize_grammar(void);
89void expand_items(void);
90void expand_rules(void);
91void advance_to_start(void);
92void start_rule(bucket *, int);
93void end_rule(void);
94void insert_empty_rule(void);
95void add_symbol(void);
96void copy_action(void);
97int mark_symbol(void);
98void read_grammar(void);
99void free_tags(void);
100void pack_names(void);
101void check_symbols(void);
102void pack_symbols(void);
103void pack_grammar(void);
104void print_grammar(void);
105
106char line_format[] = "#line %d \"%s\"\n";
107
108void
109cachec(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
123void
124get_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
170char *
171dup_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
192void
193skip_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
218int
219nextc(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
275int
276keyword(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
336void
337copy_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
365void
366copy_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
384loop:
385	c = (unsigned char) *cptr++;
386	switch (c) {
387	case '\n':
388next_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
486void
487copy_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;
511loop:
512	c = (unsigned char) *cptr++;
513	putc(c, text_file);
514	if (dflag)
515		putc(c, union_file);
516	switch (c) {
517	case '\n':
518next_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
630bucket *
631get_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
780int
781is_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
801bucket *
802get_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
818int
819get_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
832char *
833get_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
884void
885declare_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 */
947static void
948declare_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
983void
984declare_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
1013void
1014declare_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
1033void
1034read_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
1088void
1089initialize_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
1120void
1121expand_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
1133void
1134expand_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
1149void
1150advance_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
1199void
1200start_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
1213void
1214end_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
1234void
1235insert_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
1265void
1266add_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
1295void
1296copy_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;
1320loop:
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':
1397next_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
1493int
1494mark_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
1534void
1535read_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
1565void
1566free_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
1581void
1582pack_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
1608void
1609check_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
1625void
1626pack_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
1744void
1745pack_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
1805void
1806print_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
1840void
1841reader(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