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