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