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