xref: /netbsd-src/external/bsd/byacc/dist/reader.c (revision 567219e1d7461bff1b180e494a9674a287b057a7)
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 
19 static void start_rule(bucket *bp, int s_lineno);
20 
21 static char *cache;
22 static int cinc, cache_size;
23 
24 int ntags;
25 static int tagmax;
26 static char **tag_table;
27 
28 static char saw_eof;
29 char unionized;
30 char *cptr, *line;
31 static int linesize;
32 
33 static bucket *goal;
34 static Value_t prec;
35 static int gensym;
36 static char last_was_action;
37 
38 static int maxitems;
39 static bucket **pitem;
40 
41 static int maxrules;
42 static bucket **plhs;
43 
44 static size_t name_pool_size;
45 static char *name_pool;
46 
47 char line_format[] = "#line %d \"%s\"\n";
48 
49 param *lex_param;
50 param *parse_param;
51 
52 static void
53 cachec(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 
66 static void
67 get_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 
121 static char *
122 dup_line(void)
123 {
124     char *p, *s, *t;
125 
126     if (line == 0)
127 	return (0);
128     s = line;
129     while (*s != '\n')
130 	++s;
131     p = MALLOC(s - line + 1);
132     NO_SPACE(p);
133 
134     s = line;
135     t = p;
136     while ((*t++ = *s++) != '\n')
137 	continue;
138     return (p);
139 }
140 
141 static void
142 skip_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 
171 static int
172 nextc(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  */
238 static int
239 matchec(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 
264 static int
265 keyword(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 
348 static void
349 copy_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 
379 static void
380 copy_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 
513 static void
514 puts_both(const char *s)
515 {
516     fputs(s, text_file);
517     if (dflag)
518 	fputs(s, union_file);
519 }
520 
521 static void
522 putc_both(int c)
523 {
524     putc(c, text_file);
525     if (dflag)
526 	putc(c, union_file);
527 }
528 
529 static void
530 copy_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  */
670 static void
671 copy_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 
779 static int
780 hexval(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 
791 static bucket *
792 get_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 
969 static int
970 is_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 
991 static bucket *
992 get_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 
1007 static Value_t
1008 get_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 
1020 static char *
1021 get_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 
1082 static void
1083 declare_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  */
1154 static void
1155 declare_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 
1198 static void
1199 declare_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 
1228 static void
1229 declare_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 
1247 static void
1248 read_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 
1317 static void
1318 initialize_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 
1356 static void
1357 expand_items(void)
1358 {
1359     maxitems += 300;
1360     pitem = (bucket **)REALLOC(pitem, (unsigned)maxitems * sizeof(bucket *));
1361     NO_SPACE(pitem);
1362 }
1363 
1364 static void
1365 expand_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 
1379 static void
1380 advance_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 
1432 static void
1433 start_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 
1445 static void
1446 end_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 
1473 static void
1474 insert_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 
1503 static void
1504 add_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 
1534 static char *
1535 after_blanks(char *s)
1536 {
1537     while (*s != '\0' && isspace(UCH(*s)))
1538 	++s;
1539     return s;
1540 }
1541 
1542 static void
1543 copy_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 
1783 static int
1784 mark_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 
1826 static void
1827 read_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 
1865 static void
1866 free_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 
1881 static void
1882 pack_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 
1908 static void
1909 check_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 
1926 static void
1927 protect_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 
1960 static void
1961 pack_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 
2100 static void
2101 pack_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 
2165 static void
2166 print_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 
2204 void
2205 reader(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
2222 static param *
2223 free_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 
2237 void
2238 reader_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