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