1268899Sbapt/* $Id: reader.c,v 1.47 2014/04/09 21:09:27 tom Exp $ */
2234949Sbapt
3234949Sbapt#include "defs.h"
4234949Sbapt
5234949Sbapt/*  The line size must be a positive integer.  One hundred was chosen	*/
6234949Sbapt/*  because few lines in Yacc input grammars exceed 100 characters.	*/
7234949Sbapt/*  Note that if a line exceeds LINESIZE characters, the line buffer	*/
8234949Sbapt/*  will be expanded to accomodate it.					*/
9234949Sbapt
10234949Sbapt#define LINESIZE 100
11234949Sbapt
12268899Sbapt#define L_CURL  '{'
13268899Sbapt#define R_CURL  '}'
14268899Sbapt#define L_PAREN '('
15268899Sbapt#define R_PAREN ')'
16268899Sbapt#define L_BRAC  '['
17268899Sbapt#define R_BRAC  ']'
18234949Sbapt
19268899Sbapt/* the maximum number of arguments (inherited attributes) to a non-terminal */
20268899Sbapt/* this is a hard limit, but seems more than adequate */
21268899Sbapt#define MAXARGS	20
22268899Sbapt
23234949Sbaptstatic void start_rule(bucket *bp, int s_lineno);
24268899Sbapt#if defined(YYBTYACC)
25268899Sbaptstatic void copy_destructor(void);
26268899Sbaptstatic char *process_destructor_XX(char *code, char *tag);
27268899Sbapt#endif
28234949Sbapt
29234949Sbaptstatic char *cache;
30234949Sbaptstatic int cinc, cache_size;
31234949Sbapt
32234949Sbaptint ntags;
33268899Sbaptstatic int tagmax, havetags;
34234949Sbaptstatic char **tag_table;
35234949Sbapt
36234949Sbaptstatic char saw_eof;
37234949Sbaptchar unionized;
38234949Sbaptchar *cptr, *line;
39234949Sbaptstatic int linesize;
40234949Sbapt
41234949Sbaptstatic bucket *goal;
42234949Sbaptstatic Value_t prec;
43234949Sbaptstatic int gensym;
44234949Sbaptstatic char last_was_action;
45234949Sbapt
46234949Sbaptstatic int maxitems;
47234949Sbaptstatic bucket **pitem;
48234949Sbapt
49234949Sbaptstatic int maxrules;
50234949Sbaptstatic bucket **plhs;
51234949Sbapt
52234949Sbaptstatic size_t name_pool_size;
53234949Sbaptstatic char *name_pool;
54234949Sbapt
55234949Sbaptchar line_format[] = "#line %d \"%s\"\n";
56234949Sbapt
57234949Sbaptparam *lex_param;
58234949Sbaptparam *parse_param;
59234949Sbapt
60268899Sbapt#if defined(YYBTYACC)
61268899Sbaptint destructor = 0;	/* =1 if at least one %destructor */
62268899Sbapt
63268899Sbaptstatic bucket *default_destructor[3] =
64268899Sbapt{0, 0, 0};
65268899Sbapt
66268899Sbapt#define UNTYPED_DEFAULT 0
67268899Sbapt#define TYPED_DEFAULT   1
68268899Sbapt#define TYPE_SPECIFIED  2
69268899Sbapt
70268899Sbaptstatic bucket *
71268899Sbaptlookup_type_destructor(char *tag)
72268899Sbapt{
73268899Sbapt    char name[1024] = "\0";
74268899Sbapt    bucket *bp, **bpp = &default_destructor[TYPE_SPECIFIED];
75268899Sbapt
76268899Sbapt    while ((bp = *bpp) != NULL)
77268899Sbapt    {
78268899Sbapt	if (bp->tag == tag)
79268899Sbapt	    return (bp);
80268899Sbapt	bpp = &bp->link;
81268899Sbapt    }
82268899Sbapt
83268899Sbapt    *bpp = bp = make_bucket(strcat(strcpy(name, tag), " destructor"));
84268899Sbapt    bp->tag = tag;
85268899Sbapt
86268899Sbapt    return (bp);
87268899Sbapt}
88268899Sbapt#endif /* defined(YYBTYACC) */
89268899Sbapt
90234949Sbaptstatic void
91234949Sbaptcachec(int c)
92234949Sbapt{
93234949Sbapt    assert(cinc >= 0);
94234949Sbapt    if (cinc >= cache_size)
95234949Sbapt    {
96234949Sbapt	cache_size += 256;
97240517Sbapt	cache = TREALLOC(char, cache, cache_size);
98234949Sbapt	NO_SPACE(cache);
99234949Sbapt    }
100234949Sbapt    cache[cinc] = (char)c;
101234949Sbapt    ++cinc;
102234949Sbapt}
103234949Sbapt
104234949Sbaptstatic void
105234949Sbaptget_line(void)
106234949Sbapt{
107234949Sbapt    FILE *f = input_file;
108234949Sbapt    int c;
109234949Sbapt    int i;
110234949Sbapt
111234949Sbapt    if (saw_eof || (c = getc(f)) == EOF)
112234949Sbapt    {
113234949Sbapt	if (line)
114234949Sbapt	{
115234949Sbapt	    FREE(line);
116234949Sbapt	    line = 0;
117234949Sbapt	}
118234949Sbapt	cptr = 0;
119234949Sbapt	saw_eof = 1;
120234949Sbapt	return;
121234949Sbapt    }
122234949Sbapt
123234949Sbapt    if (line == 0 || linesize != (LINESIZE + 1))
124234949Sbapt    {
125234949Sbapt	if (line)
126234949Sbapt	    FREE(line);
127234949Sbapt	linesize = LINESIZE + 1;
128240517Sbapt	line = TMALLOC(char, linesize);
129234949Sbapt	NO_SPACE(line);
130234949Sbapt    }
131234949Sbapt
132234949Sbapt    i = 0;
133234949Sbapt    ++lineno;
134234949Sbapt    for (;;)
135234949Sbapt    {
136234949Sbapt	line[i] = (char)c;
137234949Sbapt	if (c == '\n')
138268899Sbapt	    break;
139234949Sbapt	if (++i >= linesize)
140234949Sbapt	{
141234949Sbapt	    linesize += LINESIZE;
142240517Sbapt	    line = TREALLOC(char, line, linesize);
143234949Sbapt	    NO_SPACE(line);
144234949Sbapt	}
145234949Sbapt	c = getc(f);
146234949Sbapt	if (c == EOF)
147234949Sbapt	{
148234949Sbapt	    line[i] = '\n';
149234949Sbapt	    saw_eof = 1;
150268899Sbapt	    break;
151234949Sbapt	}
152234949Sbapt    }
153268899Sbapt    cptr = line;
154268899Sbapt    return;
155234949Sbapt}
156234949Sbapt
157234949Sbaptstatic char *
158234949Sbaptdup_line(void)
159234949Sbapt{
160234949Sbapt    char *p, *s, *t;
161234949Sbapt
162234949Sbapt    if (line == 0)
163234949Sbapt	return (0);
164234949Sbapt    s = line;
165234949Sbapt    while (*s != '\n')
166234949Sbapt	++s;
167240517Sbapt    p = TMALLOC(char, s - line + 1);
168234949Sbapt    NO_SPACE(p);
169234949Sbapt
170234949Sbapt    s = line;
171234949Sbapt    t = p;
172234949Sbapt    while ((*t++ = *s++) != '\n')
173234949Sbapt	continue;
174234949Sbapt    return (p);
175234949Sbapt}
176234949Sbapt
177234949Sbaptstatic void
178234949Sbaptskip_comment(void)
179234949Sbapt{
180234949Sbapt    char *s;
181234949Sbapt
182234949Sbapt    int st_lineno = lineno;
183234949Sbapt    char *st_line = dup_line();
184234949Sbapt    char *st_cptr = st_line + (cptr - line);
185234949Sbapt
186234949Sbapt    s = cptr + 2;
187234949Sbapt    for (;;)
188234949Sbapt    {
189234949Sbapt	if (*s == '*' && s[1] == '/')
190234949Sbapt	{
191234949Sbapt	    cptr = s + 2;
192234949Sbapt	    FREE(st_line);
193234949Sbapt	    return;
194234949Sbapt	}
195234949Sbapt	if (*s == '\n')
196234949Sbapt	{
197234949Sbapt	    get_line();
198234949Sbapt	    if (line == 0)
199234949Sbapt		unterminated_comment(st_lineno, st_line, st_cptr);
200234949Sbapt	    s = cptr;
201234949Sbapt	}
202234949Sbapt	else
203234949Sbapt	    ++s;
204234949Sbapt    }
205234949Sbapt}
206234949Sbapt
207234949Sbaptstatic int
208234949Sbaptnextc(void)
209234949Sbapt{
210234949Sbapt    char *s;
211234949Sbapt
212234949Sbapt    if (line == 0)
213234949Sbapt    {
214234949Sbapt	get_line();
215234949Sbapt	if (line == 0)
216234949Sbapt	    return (EOF);
217234949Sbapt    }
218234949Sbapt
219234949Sbapt    s = cptr;
220234949Sbapt    for (;;)
221234949Sbapt    {
222234949Sbapt	switch (*s)
223234949Sbapt	{
224234949Sbapt	case '\n':
225234949Sbapt	    get_line();
226234949Sbapt	    if (line == 0)
227234949Sbapt		return (EOF);
228234949Sbapt	    s = cptr;
229234949Sbapt	    break;
230234949Sbapt
231234949Sbapt	case ' ':
232234949Sbapt	case '\t':
233234949Sbapt	case '\f':
234234949Sbapt	case '\r':
235234949Sbapt	case '\v':
236234949Sbapt	case ',':
237234949Sbapt	case ';':
238234949Sbapt	    ++s;
239234949Sbapt	    break;
240234949Sbapt
241234949Sbapt	case '\\':
242234949Sbapt	    cptr = s;
243234949Sbapt	    return ('%');
244234949Sbapt
245234949Sbapt	case '/':
246234949Sbapt	    if (s[1] == '*')
247234949Sbapt	    {
248234949Sbapt		cptr = s;
249234949Sbapt		skip_comment();
250234949Sbapt		s = cptr;
251234949Sbapt		break;
252234949Sbapt	    }
253234949Sbapt	    else if (s[1] == '/')
254234949Sbapt	    {
255234949Sbapt		get_line();
256234949Sbapt		if (line == 0)
257234949Sbapt		    return (EOF);
258234949Sbapt		s = cptr;
259234949Sbapt		break;
260234949Sbapt	    }
261234949Sbapt	    /* FALLTHRU */
262234949Sbapt
263234949Sbapt	default:
264234949Sbapt	    cptr = s;
265234949Sbapt	    return (*s);
266234949Sbapt	}
267234949Sbapt    }
268234949Sbapt}
269268899Sbapt/* *INDENT-OFF* */
270268899Sbaptstatic struct keyword
271268899Sbapt{
272268899Sbapt    char name[13];
273268899Sbapt    int token;
274268899Sbapt}
275268899Sbaptkeywords[] = {
276268899Sbapt    { "binary",      NONASSOC },
277268899Sbapt#if defined(YYBTYACC)
278268899Sbapt    { "destructor",  DESTRUCTOR },
279268899Sbapt#endif
280268899Sbapt    { "expect",      EXPECT },
281268899Sbapt    { "expect-rr",   EXPECT_RR },
282268899Sbapt    { "ident",       IDENT },
283268899Sbapt    { "left",        LEFT },
284268899Sbapt    { "lex-param",   LEX_PARAM },
285268899Sbapt#if defined(YYBTYACC)
286268899Sbapt    { "locations",   LOCATIONS },
287268899Sbapt#endif
288268899Sbapt    { "nonassoc",    NONASSOC },
289268899Sbapt    { "parse-param", PARSE_PARAM },
290268899Sbapt    { "pure-parser", PURE_PARSER },
291268899Sbapt    { "right",       RIGHT },
292268899Sbapt    { "start",       START },
293268899Sbapt    { "term",        TOKEN },
294268899Sbapt    { "token",       TOKEN },
295268899Sbapt    { "token-table", TOKEN_TABLE },
296268899Sbapt    { "type",        TYPE },
297268899Sbapt    { "union",       UNION },
298268899Sbapt    { "yacc",        POSIX_YACC },
299268899Sbapt};
300268899Sbapt/* *INDENT-ON* */
301234949Sbapt
302234949Sbaptstatic int
303268899Sbaptcompare_keys(const void *a, const void *b)
304234949Sbapt{
305268899Sbapt    const struct keyword *p = (const struct keyword *)a;
306268899Sbapt    const struct keyword *q = (const struct keyword *)b;
307268899Sbapt    return strcmp(p->name, q->name);
308234949Sbapt}
309234949Sbapt
310234949Sbaptstatic int
311234949Sbaptkeyword(void)
312234949Sbapt{
313234949Sbapt    int c;
314234949Sbapt    char *t_cptr = cptr;
315268899Sbapt    struct keyword *key;
316234949Sbapt
317234949Sbapt    c = *++cptr;
318234949Sbapt    if (isalpha(c))
319234949Sbapt    {
320234949Sbapt	cinc = 0;
321234949Sbapt	for (;;)
322234949Sbapt	{
323234949Sbapt	    if (isalpha(c))
324234949Sbapt	    {
325234949Sbapt		if (isupper(c))
326234949Sbapt		    c = tolower(c);
327234949Sbapt		cachec(c);
328234949Sbapt	    }
329234949Sbapt	    else if (isdigit(c)
330234949Sbapt		     || c == '-'
331234949Sbapt		     || c == '.'
332234949Sbapt		     || c == '$')
333234949Sbapt	    {
334234949Sbapt		cachec(c);
335234949Sbapt	    }
336268899Sbapt	    else if (c == '_')
337268899Sbapt	    {
338268899Sbapt		/* treat keywords spelled with '_' as if it were '-' */
339268899Sbapt		cachec('-');
340268899Sbapt	    }
341234949Sbapt	    else
342234949Sbapt	    {
343234949Sbapt		break;
344234949Sbapt	    }
345234949Sbapt	    c = *++cptr;
346234949Sbapt	}
347234949Sbapt	cachec(NUL);
348234949Sbapt
349268899Sbapt	if ((key = bsearch(cache, keywords,
350268899Sbapt			   sizeof(keywords) / sizeof(*key),
351268899Sbapt			   sizeof(*key), compare_keys)))
352268899Sbapt	    return key->token;
353234949Sbapt    }
354234949Sbapt    else
355234949Sbapt    {
356234949Sbapt	++cptr;
357234949Sbapt	if (c == L_CURL)
358234949Sbapt	    return (TEXT);
359234949Sbapt	if (c == '%' || c == '\\')
360234949Sbapt	    return (MARK);
361234949Sbapt	if (c == '<')
362234949Sbapt	    return (LEFT);
363234949Sbapt	if (c == '>')
364234949Sbapt	    return (RIGHT);
365234949Sbapt	if (c == '0')
366234949Sbapt	    return (TOKEN);
367234949Sbapt	if (c == '2')
368234949Sbapt	    return (NONASSOC);
369234949Sbapt    }
370234949Sbapt    syntax_error(lineno, line, t_cptr);
371235723Sbapt    return (-1);
372234949Sbapt}
373234949Sbapt
374234949Sbaptstatic void
375234949Sbaptcopy_ident(void)
376234949Sbapt{
377234949Sbapt    int c;
378234949Sbapt    FILE *f = output_file;
379234949Sbapt
380234949Sbapt    c = nextc();
381234949Sbapt    if (c == EOF)
382234949Sbapt	unexpected_EOF();
383234949Sbapt    if (c != '"')
384234949Sbapt	syntax_error(lineno, line, cptr);
385234949Sbapt    ++outline;
386234949Sbapt    fprintf(f, "#ident \"");
387234949Sbapt    for (;;)
388234949Sbapt    {
389234949Sbapt	c = *++cptr;
390234949Sbapt	if (c == '\n')
391234949Sbapt	{
392234949Sbapt	    fprintf(f, "\"\n");
393234949Sbapt	    return;
394234949Sbapt	}
395234949Sbapt	putc(c, f);
396234949Sbapt	if (c == '"')
397234949Sbapt	{
398234949Sbapt	    putc('\n', f);
399234949Sbapt	    ++cptr;
400234949Sbapt	    return;
401234949Sbapt	}
402234949Sbapt    }
403234949Sbapt}
404234949Sbapt
405268899Sbaptstatic char *
406268899Sbaptcopy_string(int quote)
407268899Sbapt{
408268899Sbapt    struct mstring *temp = msnew();
409268899Sbapt    int c;
410268899Sbapt    int s_lineno = lineno;
411268899Sbapt    char *s_line = dup_line();
412268899Sbapt    char *s_cptr = s_line + (cptr - line - 1);
413268899Sbapt
414268899Sbapt    for (;;)
415268899Sbapt    {
416268899Sbapt	c = *cptr++;
417268899Sbapt	mputc(temp, c);
418268899Sbapt	if (c == quote)
419268899Sbapt	{
420268899Sbapt	    FREE(s_line);
421268899Sbapt	    return msdone(temp);
422268899Sbapt	}
423268899Sbapt	if (c == '\n')
424268899Sbapt	    unterminated_string(s_lineno, s_line, s_cptr);
425268899Sbapt	if (c == '\\')
426268899Sbapt	{
427268899Sbapt	    c = *cptr++;
428268899Sbapt	    mputc(temp, c);
429268899Sbapt	    if (c == '\n')
430268899Sbapt	    {
431268899Sbapt		get_line();
432268899Sbapt		if (line == 0)
433268899Sbapt		    unterminated_string(s_lineno, s_line, s_cptr);
434268899Sbapt	    }
435268899Sbapt	}
436268899Sbapt    }
437268899Sbapt}
438268899Sbapt
439268899Sbaptstatic char *
440268899Sbaptcopy_comment(void)
441268899Sbapt{
442268899Sbapt    struct mstring *temp = msnew();
443268899Sbapt    int c;
444268899Sbapt
445268899Sbapt    c = *cptr;
446268899Sbapt    if (c == '/')
447268899Sbapt    {
448268899Sbapt	mputc(temp, '*');
449268899Sbapt	while ((c = *++cptr) != '\n')
450268899Sbapt	{
451268899Sbapt	    mputc(temp, c);
452268899Sbapt	    if (c == '*' && cptr[1] == '/')
453268899Sbapt		mputc(temp, ' ');
454268899Sbapt	}
455268899Sbapt	mputc(temp, '*');
456268899Sbapt	mputc(temp, '/');
457268899Sbapt    }
458268899Sbapt    else if (c == '*')
459268899Sbapt    {
460268899Sbapt	int c_lineno = lineno;
461268899Sbapt	char *c_line = dup_line();
462268899Sbapt	char *c_cptr = c_line + (cptr - line - 1);
463268899Sbapt
464268899Sbapt	mputc(temp, c);
465268899Sbapt	++cptr;
466268899Sbapt	for (;;)
467268899Sbapt	{
468268899Sbapt	    c = *cptr++;
469268899Sbapt	    mputc(temp, c);
470268899Sbapt	    if (c == '*' && *cptr == '/')
471268899Sbapt	    {
472268899Sbapt		mputc(temp, '/');
473268899Sbapt		++cptr;
474268899Sbapt		FREE(c_line);
475268899Sbapt		return msdone(temp);
476268899Sbapt	    }
477268899Sbapt	    if (c == '\n')
478268899Sbapt	    {
479268899Sbapt		get_line();
480268899Sbapt		if (line == 0)
481268899Sbapt		    unterminated_comment(c_lineno, c_line, c_cptr);
482268899Sbapt	    }
483268899Sbapt	}
484268899Sbapt    }
485268899Sbapt    return msdone(temp);
486268899Sbapt}
487268899Sbapt
488234949Sbaptstatic void
489234949Sbaptcopy_text(void)
490234949Sbapt{
491234949Sbapt    int c;
492234949Sbapt    FILE *f = text_file;
493234949Sbapt    int need_newline = 0;
494234949Sbapt    int t_lineno = lineno;
495234949Sbapt    char *t_line = dup_line();
496234949Sbapt    char *t_cptr = t_line + (cptr - line - 2);
497234949Sbapt
498234949Sbapt    if (*cptr == '\n')
499234949Sbapt    {
500234949Sbapt	get_line();
501234949Sbapt	if (line == 0)
502234949Sbapt	    unterminated_text(t_lineno, t_line, t_cptr);
503234949Sbapt    }
504234949Sbapt    if (!lflag)
505234949Sbapt	fprintf(f, line_format, lineno, input_file_name);
506234949Sbapt
507234949Sbapt  loop:
508234949Sbapt    c = *cptr++;
509234949Sbapt    switch (c)
510234949Sbapt    {
511234949Sbapt    case '\n':
512234949Sbapt	putc('\n', f);
513234949Sbapt	need_newline = 0;
514234949Sbapt	get_line();
515234949Sbapt	if (line)
516234949Sbapt	    goto loop;
517234949Sbapt	unterminated_text(t_lineno, t_line, t_cptr);
518234949Sbapt
519234949Sbapt    case '\'':
520234949Sbapt    case '"':
521268899Sbapt	putc(c, f);
522234949Sbapt	{
523268899Sbapt	    char *s = copy_string(c);
524268899Sbapt	    fputs(s, f);
525268899Sbapt	    free(s);
526234949Sbapt	}
527268899Sbapt	need_newline = 1;
528268899Sbapt	goto loop;
529234949Sbapt
530234949Sbapt    case '/':
531234949Sbapt	putc(c, f);
532234949Sbapt	{
533268899Sbapt	    char *s = copy_comment();
534268899Sbapt	    fputs(s, f);
535268899Sbapt	    free(s);
536234949Sbapt	}
537234949Sbapt	need_newline = 1;
538234949Sbapt	goto loop;
539234949Sbapt
540234949Sbapt    case '%':
541234949Sbapt    case '\\':
542234949Sbapt	if (*cptr == R_CURL)
543234949Sbapt	{
544234949Sbapt	    if (need_newline)
545234949Sbapt		putc('\n', f);
546234949Sbapt	    ++cptr;
547234949Sbapt	    FREE(t_line);
548234949Sbapt	    return;
549234949Sbapt	}
550234949Sbapt	/* FALLTHRU */
551234949Sbapt
552234949Sbapt    default:
553234949Sbapt	putc(c, f);
554234949Sbapt	need_newline = 1;
555234949Sbapt	goto loop;
556234949Sbapt    }
557234949Sbapt}
558234949Sbapt
559234949Sbaptstatic void
560234949Sbaptputs_both(const char *s)
561234949Sbapt{
562234949Sbapt    fputs(s, text_file);
563234949Sbapt    if (dflag)
564234949Sbapt	fputs(s, union_file);
565234949Sbapt}
566234949Sbapt
567234949Sbaptstatic void
568234949Sbaptputc_both(int c)
569234949Sbapt{
570234949Sbapt    putc(c, text_file);
571234949Sbapt    if (dflag)
572234949Sbapt	putc(c, union_file);
573234949Sbapt}
574234949Sbapt
575234949Sbaptstatic void
576234949Sbaptcopy_union(void)
577234949Sbapt{
578234949Sbapt    int c;
579234949Sbapt    int depth;
580234949Sbapt    int u_lineno = lineno;
581234949Sbapt    char *u_line = dup_line();
582234949Sbapt    char *u_cptr = u_line + (cptr - line - 6);
583234949Sbapt
584234949Sbapt    if (unionized)
585234949Sbapt	over_unionized(cptr - 6);
586234949Sbapt    unionized = 1;
587234949Sbapt
588234949Sbapt    if (!lflag)
589234949Sbapt	fprintf(text_file, line_format, lineno, input_file_name);
590234949Sbapt
591234949Sbapt    puts_both("#ifdef YYSTYPE\n");
592234949Sbapt    puts_both("#undef  YYSTYPE_IS_DECLARED\n");
593234949Sbapt    puts_both("#define YYSTYPE_IS_DECLARED 1\n");
594234949Sbapt    puts_both("#endif\n");
595234949Sbapt    puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
596234949Sbapt    puts_both("#define YYSTYPE_IS_DECLARED 1\n");
597234949Sbapt    puts_both("typedef union");
598234949Sbapt
599234949Sbapt    depth = 0;
600234949Sbapt  loop:
601234949Sbapt    c = *cptr++;
602234949Sbapt    putc_both(c);
603234949Sbapt    switch (c)
604234949Sbapt    {
605234949Sbapt    case '\n':
606234949Sbapt	get_line();
607234949Sbapt	if (line == 0)
608234949Sbapt	    unterminated_union(u_lineno, u_line, u_cptr);
609234949Sbapt	goto loop;
610234949Sbapt
611234949Sbapt    case L_CURL:
612234949Sbapt	++depth;
613234949Sbapt	goto loop;
614234949Sbapt
615234949Sbapt    case R_CURL:
616234949Sbapt	if (--depth == 0)
617234949Sbapt	{
618234949Sbapt	    puts_both(" YYSTYPE;\n");
619234949Sbapt	    puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n");
620234949Sbapt	    FREE(u_line);
621234949Sbapt	    return;
622234949Sbapt	}
623234949Sbapt	goto loop;
624234949Sbapt
625234949Sbapt    case '\'':
626234949Sbapt    case '"':
627234949Sbapt	{
628268899Sbapt	    char *s = copy_string(c);
629268899Sbapt	    puts_both(s);
630268899Sbapt	    free(s);
631234949Sbapt	}
632268899Sbapt	goto loop;
633234949Sbapt
634234949Sbapt    case '/':
635234949Sbapt	{
636268899Sbapt	    char *s = copy_comment();
637268899Sbapt	    puts_both(s);
638268899Sbapt	    free(s);
639234949Sbapt	}
640234949Sbapt	goto loop;
641234949Sbapt
642234949Sbapt    default:
643234949Sbapt	goto loop;
644234949Sbapt    }
645234949Sbapt}
646234949Sbapt
647234949Sbapt/*
648234949Sbapt * Keep a linked list of parameters
649234949Sbapt */
650234949Sbaptstatic void
651234949Sbaptcopy_param(int k)
652234949Sbapt{
653234949Sbapt    char *buf;
654234949Sbapt    int c;
655234949Sbapt    param *head, *p;
656234949Sbapt    int i;
657234949Sbapt    int name, type2;
658234949Sbapt
659234949Sbapt    c = nextc();
660234949Sbapt    if (c == EOF)
661234949Sbapt	unexpected_EOF();
662268899Sbapt    if (c != L_CURL)
663234949Sbapt	goto out;
664234949Sbapt    cptr++;
665234949Sbapt
666234949Sbapt    c = nextc();
667234949Sbapt    if (c == EOF)
668234949Sbapt	unexpected_EOF();
669268899Sbapt    if (c == R_CURL)
670234949Sbapt	goto out;
671234949Sbapt
672240517Sbapt    buf = TMALLOC(char, linesize);
673234949Sbapt    NO_SPACE(buf);
674234949Sbapt
675268899Sbapt    for (i = 0; (c = *cptr++) != R_CURL; i++)
676234949Sbapt    {
677234949Sbapt	if (c == '\0')
678234949Sbapt	    missing_brace();
679234949Sbapt	if (c == EOF)
680234949Sbapt	    unexpected_EOF();
681234949Sbapt	buf[i] = (char)c;
682234949Sbapt    }
683234949Sbapt
684234949Sbapt    if (i == 0)
685234949Sbapt	goto out;
686234949Sbapt
687234949Sbapt    buf[i--] = '\0';
688268899Sbapt    while (i > 0 && isspace(UCH(buf[i])))
689234949Sbapt	buf[i--] = '\0';
690234949Sbapt
691234949Sbapt    if (buf[i] == ']')
692234949Sbapt    {
693234949Sbapt	int level = 1;
694234949Sbapt	while (i >= 0 && level > 0 && buf[i] != '[')
695234949Sbapt	{
696234949Sbapt	    if (buf[i] == ']')
697234949Sbapt		++level;
698234949Sbapt	    else if (buf[i] == '[')
699234949Sbapt		--level;
700234949Sbapt	    i--;
701234949Sbapt	}
702234949Sbapt	if (i <= 0)
703234949Sbapt	    unexpected_EOF();
704234949Sbapt	type2 = i--;
705234949Sbapt    }
706234949Sbapt    else
707234949Sbapt    {
708234949Sbapt	type2 = i + 1;
709234949Sbapt    }
710234949Sbapt
711268899Sbapt    while (i > 0 && (isalnum(UCH(buf[i])) ||
712268899Sbapt		     UCH(buf[i]) == '_'))
713234949Sbapt	i--;
714234949Sbapt
715234949Sbapt    if (!isspace(UCH(buf[i])) && buf[i] != '*')
716234949Sbapt	goto out;
717234949Sbapt
718234949Sbapt    name = i + 1;
719234949Sbapt
720240517Sbapt    p = TMALLOC(param, 1);
721234949Sbapt    NO_SPACE(p);
722234949Sbapt
723234949Sbapt    p->type2 = strdup(buf + type2);
724234949Sbapt    NO_SPACE(p->type2);
725234949Sbapt
726234949Sbapt    buf[type2] = '\0';
727234949Sbapt
728234949Sbapt    p->name = strdup(buf + name);
729234949Sbapt    NO_SPACE(p->name);
730234949Sbapt
731234949Sbapt    buf[name] = '\0';
732234949Sbapt    p->type = buf;
733234949Sbapt
734234949Sbapt    if (k == LEX_PARAM)
735234949Sbapt	head = lex_param;
736234949Sbapt    else
737234949Sbapt	head = parse_param;
738234949Sbapt
739234949Sbapt    if (head != NULL)
740234949Sbapt    {
741234949Sbapt	while (head->next)
742234949Sbapt	    head = head->next;
743234949Sbapt	head->next = p;
744234949Sbapt    }
745234949Sbapt    else
746234949Sbapt    {
747234949Sbapt	if (k == LEX_PARAM)
748234949Sbapt	    lex_param = p;
749234949Sbapt	else
750234949Sbapt	    parse_param = p;
751234949Sbapt    }
752234949Sbapt    p->next = NULL;
753234949Sbapt    return;
754234949Sbapt
755234949Sbapt  out:
756234949Sbapt    syntax_error(lineno, line, cptr);
757234949Sbapt}
758234949Sbapt
759234949Sbaptstatic int
760234949Sbapthexval(int c)
761234949Sbapt{
762234949Sbapt    if (c >= '0' && c <= '9')
763234949Sbapt	return (c - '0');
764234949Sbapt    if (c >= 'A' && c <= 'F')
765234949Sbapt	return (c - 'A' + 10);
766234949Sbapt    if (c >= 'a' && c <= 'f')
767234949Sbapt	return (c - 'a' + 10);
768234949Sbapt    return (-1);
769234949Sbapt}
770234949Sbapt
771234949Sbaptstatic bucket *
772234949Sbaptget_literal(void)
773234949Sbapt{
774234949Sbapt    int c, quote;
775234949Sbapt    int i;
776234949Sbapt    int n;
777234949Sbapt    char *s;
778234949Sbapt    bucket *bp;
779234949Sbapt    int s_lineno = lineno;
780234949Sbapt    char *s_line = dup_line();
781234949Sbapt    char *s_cptr = s_line + (cptr - line);
782234949Sbapt
783234949Sbapt    quote = *cptr++;
784234949Sbapt    cinc = 0;
785234949Sbapt    for (;;)
786234949Sbapt    {
787234949Sbapt	c = *cptr++;
788234949Sbapt	if (c == quote)
789234949Sbapt	    break;
790234949Sbapt	if (c == '\n')
791234949Sbapt	    unterminated_string(s_lineno, s_line, s_cptr);
792234949Sbapt	if (c == '\\')
793234949Sbapt	{
794234949Sbapt	    char *c_cptr = cptr - 1;
795234949Sbapt
796234949Sbapt	    c = *cptr++;
797234949Sbapt	    switch (c)
798234949Sbapt	    {
799234949Sbapt	    case '\n':
800234949Sbapt		get_line();
801234949Sbapt		if (line == 0)
802234949Sbapt		    unterminated_string(s_lineno, s_line, s_cptr);
803234949Sbapt		continue;
804234949Sbapt
805234949Sbapt	    case '0':
806234949Sbapt	    case '1':
807234949Sbapt	    case '2':
808234949Sbapt	    case '3':
809234949Sbapt	    case '4':
810234949Sbapt	    case '5':
811234949Sbapt	    case '6':
812234949Sbapt	    case '7':
813234949Sbapt		n = c - '0';
814234949Sbapt		c = *cptr;
815234949Sbapt		if (IS_OCTAL(c))
816234949Sbapt		{
817234949Sbapt		    n = (n << 3) + (c - '0');
818234949Sbapt		    c = *++cptr;
819234949Sbapt		    if (IS_OCTAL(c))
820234949Sbapt		    {
821234949Sbapt			n = (n << 3) + (c - '0');
822234949Sbapt			++cptr;
823234949Sbapt		    }
824234949Sbapt		}
825234949Sbapt		if (n > MAXCHAR)
826234949Sbapt		    illegal_character(c_cptr);
827234949Sbapt		c = n;
828234949Sbapt		break;
829234949Sbapt
830234949Sbapt	    case 'x':
831234949Sbapt		c = *cptr++;
832234949Sbapt		n = hexval(c);
833234949Sbapt		if (n < 0 || n >= 16)
834234949Sbapt		    illegal_character(c_cptr);
835234949Sbapt		for (;;)
836234949Sbapt		{
837234949Sbapt		    c = *cptr;
838234949Sbapt		    i = hexval(c);
839234949Sbapt		    if (i < 0 || i >= 16)
840234949Sbapt			break;
841234949Sbapt		    ++cptr;
842234949Sbapt		    n = (n << 4) + i;
843234949Sbapt		    if (n > MAXCHAR)
844234949Sbapt			illegal_character(c_cptr);
845234949Sbapt		}
846234949Sbapt		c = n;
847234949Sbapt		break;
848234949Sbapt
849234949Sbapt	    case 'a':
850234949Sbapt		c = 7;
851234949Sbapt		break;
852234949Sbapt	    case 'b':
853234949Sbapt		c = '\b';
854234949Sbapt		break;
855234949Sbapt	    case 'f':
856234949Sbapt		c = '\f';
857234949Sbapt		break;
858234949Sbapt	    case 'n':
859234949Sbapt		c = '\n';
860234949Sbapt		break;
861234949Sbapt	    case 'r':
862234949Sbapt		c = '\r';
863234949Sbapt		break;
864234949Sbapt	    case 't':
865234949Sbapt		c = '\t';
866234949Sbapt		break;
867234949Sbapt	    case 'v':
868234949Sbapt		c = '\v';
869234949Sbapt		break;
870234949Sbapt	    }
871234949Sbapt	}
872234949Sbapt	cachec(c);
873234949Sbapt    }
874234949Sbapt    FREE(s_line);
875234949Sbapt
876234949Sbapt    n = cinc;
877240517Sbapt    s = TMALLOC(char, n);
878234949Sbapt    NO_SPACE(s);
879234949Sbapt
880234949Sbapt    for (i = 0; i < n; ++i)
881234949Sbapt	s[i] = cache[i];
882234949Sbapt
883234949Sbapt    cinc = 0;
884234949Sbapt    if (n == 1)
885234949Sbapt	cachec('\'');
886234949Sbapt    else
887234949Sbapt	cachec('"');
888234949Sbapt
889234949Sbapt    for (i = 0; i < n; ++i)
890234949Sbapt    {
891234949Sbapt	c = UCH(s[i]);
892234949Sbapt	if (c == '\\' || c == cache[0])
893234949Sbapt	{
894234949Sbapt	    cachec('\\');
895234949Sbapt	    cachec(c);
896234949Sbapt	}
897234949Sbapt	else if (isprint(c))
898234949Sbapt	    cachec(c);
899234949Sbapt	else
900234949Sbapt	{
901234949Sbapt	    cachec('\\');
902234949Sbapt	    switch (c)
903234949Sbapt	    {
904234949Sbapt	    case 7:
905234949Sbapt		cachec('a');
906234949Sbapt		break;
907234949Sbapt	    case '\b':
908234949Sbapt		cachec('b');
909234949Sbapt		break;
910234949Sbapt	    case '\f':
911234949Sbapt		cachec('f');
912234949Sbapt		break;
913234949Sbapt	    case '\n':
914234949Sbapt		cachec('n');
915234949Sbapt		break;
916234949Sbapt	    case '\r':
917234949Sbapt		cachec('r');
918234949Sbapt		break;
919234949Sbapt	    case '\t':
920234949Sbapt		cachec('t');
921234949Sbapt		break;
922234949Sbapt	    case '\v':
923234949Sbapt		cachec('v');
924234949Sbapt		break;
925234949Sbapt	    default:
926234949Sbapt		cachec(((c >> 6) & 7) + '0');
927234949Sbapt		cachec(((c >> 3) & 7) + '0');
928234949Sbapt		cachec((c & 7) + '0');
929234949Sbapt		break;
930234949Sbapt	    }
931234949Sbapt	}
932234949Sbapt    }
933234949Sbapt
934234949Sbapt    if (n == 1)
935234949Sbapt	cachec('\'');
936234949Sbapt    else
937234949Sbapt	cachec('"');
938234949Sbapt
939234949Sbapt    cachec(NUL);
940234949Sbapt    bp = lookup(cache);
941234949Sbapt    bp->class = TERM;
942234949Sbapt    if (n == 1 && bp->value == UNDEFINED)
943234949Sbapt	bp->value = UCH(*s);
944234949Sbapt    FREE(s);
945234949Sbapt
946234949Sbapt    return (bp);
947234949Sbapt}
948234949Sbapt
949234949Sbaptstatic int
950234949Sbaptis_reserved(char *name)
951234949Sbapt{
952234949Sbapt    char *s;
953234949Sbapt
954234949Sbapt    if (strcmp(name, ".") == 0 ||
955234949Sbapt	strcmp(name, "$accept") == 0 ||
956234949Sbapt	strcmp(name, "$end") == 0)
957234949Sbapt	return (1);
958234949Sbapt
959234949Sbapt    if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2])))
960234949Sbapt    {
961234949Sbapt	s = name + 3;
962234949Sbapt	while (isdigit(UCH(*s)))
963234949Sbapt	    ++s;
964234949Sbapt	if (*s == NUL)
965234949Sbapt	    return (1);
966234949Sbapt    }
967234949Sbapt
968234949Sbapt    return (0);
969234949Sbapt}
970234949Sbapt
971234949Sbaptstatic bucket *
972234949Sbaptget_name(void)
973234949Sbapt{
974234949Sbapt    int c;
975234949Sbapt
976234949Sbapt    cinc = 0;
977234949Sbapt    for (c = *cptr; IS_IDENT(c); c = *++cptr)
978234949Sbapt	cachec(c);
979234949Sbapt    cachec(NUL);
980234949Sbapt
981234949Sbapt    if (is_reserved(cache))
982234949Sbapt	used_reserved(cache);
983234949Sbapt
984234949Sbapt    return (lookup(cache));
985234949Sbapt}
986234949Sbapt
987234949Sbaptstatic Value_t
988234949Sbaptget_number(void)
989234949Sbapt{
990234949Sbapt    int c;
991234949Sbapt    Value_t n;
992234949Sbapt
993234949Sbapt    n = 0;
994234949Sbapt    for (c = *cptr; isdigit(c); c = *++cptr)
995234949Sbapt	n = (Value_t) (10 * n + (c - '0'));
996234949Sbapt
997234949Sbapt    return (n);
998234949Sbapt}
999234949Sbapt
1000234949Sbaptstatic char *
1001268899Sbaptcache_tag(char *tag, size_t len)
1002268899Sbapt{
1003268899Sbapt    int i;
1004268899Sbapt    char *s;
1005268899Sbapt
1006268899Sbapt    for (i = 0; i < ntags; ++i)
1007268899Sbapt    {
1008268899Sbapt	if (strncmp(tag, tag_table[i], len) == 0 &&
1009268899Sbapt	    tag_table[i][len] == NUL)
1010268899Sbapt	    return (tag_table[i]);
1011268899Sbapt    }
1012268899Sbapt
1013268899Sbapt    if (ntags >= tagmax)
1014268899Sbapt    {
1015268899Sbapt	tagmax += 16;
1016268899Sbapt	tag_table =
1017268899Sbapt	    (tag_table
1018268899Sbapt	     ? TREALLOC(char *, tag_table, tagmax)
1019268899Sbapt	     : TMALLOC(char *, tagmax));
1020268899Sbapt	NO_SPACE(tag_table);
1021268899Sbapt    }
1022268899Sbapt
1023268899Sbapt    s = TMALLOC(char, len + 1);
1024268899Sbapt    NO_SPACE(s);
1025268899Sbapt
1026268899Sbapt    strncpy(s, tag, len);
1027268899Sbapt    s[len] = 0;
1028268899Sbapt    tag_table[ntags++] = s;
1029268899Sbapt    return s;
1030268899Sbapt}
1031268899Sbapt
1032268899Sbaptstatic char *
1033234949Sbaptget_tag(void)
1034234949Sbapt{
1035234949Sbapt    int c;
1036234949Sbapt    int t_lineno = lineno;
1037234949Sbapt    char *t_line = dup_line();
1038234949Sbapt    char *t_cptr = t_line + (cptr - line);
1039234949Sbapt
1040234949Sbapt    ++cptr;
1041234949Sbapt    c = nextc();
1042234949Sbapt    if (c == EOF)
1043234949Sbapt	unexpected_EOF();
1044234949Sbapt    if (!isalpha(c) && c != '_' && c != '$')
1045234949Sbapt	illegal_tag(t_lineno, t_line, t_cptr);
1046234949Sbapt
1047234949Sbapt    cinc = 0;
1048234949Sbapt    do
1049234949Sbapt    {
1050234949Sbapt	cachec(c);
1051234949Sbapt	c = *++cptr;
1052234949Sbapt    }
1053234949Sbapt    while (IS_IDENT(c));
1054234949Sbapt    cachec(NUL);
1055234949Sbapt
1056234949Sbapt    c = nextc();
1057234949Sbapt    if (c == EOF)
1058234949Sbapt	unexpected_EOF();
1059234949Sbapt    if (c != '>')
1060234949Sbapt	illegal_tag(t_lineno, t_line, t_cptr);
1061234949Sbapt    ++cptr;
1062234949Sbapt
1063268899Sbapt    FREE(t_line);
1064268899Sbapt    havetags = 1;
1065268899Sbapt    return cache_tag(cache, (size_t) cinc);
1066268899Sbapt}
1067234949Sbapt
1068268899Sbapt#if defined(YYBTYACC)
1069268899Sbaptstatic char *
1070268899Sbaptscan_id(void)
1071268899Sbapt{
1072268899Sbapt    char *b = cptr;
1073234949Sbapt
1074268899Sbapt    while (isalnum(*cptr) || *cptr == '_' || *cptr == '$')
1075268899Sbapt	cptr++;
1076268899Sbapt    return cache_tag(b, (size_t) (cptr - b));
1077234949Sbapt}
1078268899Sbapt#endif
1079234949Sbapt
1080234949Sbaptstatic void
1081234949Sbaptdeclare_tokens(int assoc)
1082234949Sbapt{
1083234949Sbapt    int c;
1084234949Sbapt    bucket *bp;
1085234949Sbapt    Value_t value;
1086234949Sbapt    char *tag = 0;
1087234949Sbapt
1088234949Sbapt    if (assoc != TOKEN)
1089234949Sbapt	++prec;
1090234949Sbapt
1091234949Sbapt    c = nextc();
1092234949Sbapt    if (c == EOF)
1093234949Sbapt	unexpected_EOF();
1094234949Sbapt    if (c == '<')
1095234949Sbapt    {
1096234949Sbapt	tag = get_tag();
1097234949Sbapt	c = nextc();
1098234949Sbapt	if (c == EOF)
1099234949Sbapt	    unexpected_EOF();
1100234949Sbapt    }
1101234949Sbapt
1102234949Sbapt    for (;;)
1103234949Sbapt    {
1104234949Sbapt	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1105234949Sbapt	    bp = get_name();
1106234949Sbapt	else if (c == '\'' || c == '"')
1107234949Sbapt	    bp = get_literal();
1108234949Sbapt	else
1109234949Sbapt	    return;
1110234949Sbapt
1111234949Sbapt	if (bp == goal)
1112234949Sbapt	    tokenized_start(bp->name);
1113234949Sbapt	bp->class = TERM;
1114234949Sbapt
1115234949Sbapt	if (tag)
1116234949Sbapt	{
1117234949Sbapt	    if (bp->tag && tag != bp->tag)
1118234949Sbapt		retyped_warning(bp->name);
1119234949Sbapt	    bp->tag = tag;
1120234949Sbapt	}
1121234949Sbapt
1122234949Sbapt	if (assoc != TOKEN)
1123234949Sbapt	{
1124234949Sbapt	    if (bp->prec && prec != bp->prec)
1125234949Sbapt		reprec_warning(bp->name);
1126234949Sbapt	    bp->assoc = (Assoc_t) assoc;
1127234949Sbapt	    bp->prec = prec;
1128234949Sbapt	}
1129234949Sbapt
1130234949Sbapt	c = nextc();
1131234949Sbapt	if (c == EOF)
1132234949Sbapt	    unexpected_EOF();
1133234949Sbapt
1134234949Sbapt	if (isdigit(c))
1135234949Sbapt	{
1136234949Sbapt	    value = get_number();
1137234949Sbapt	    if (bp->value != UNDEFINED && value != bp->value)
1138234949Sbapt		revalued_warning(bp->name);
1139234949Sbapt	    bp->value = value;
1140234949Sbapt	    c = nextc();
1141234949Sbapt	    if (c == EOF)
1142234949Sbapt		unexpected_EOF();
1143234949Sbapt	}
1144234949Sbapt    }
1145234949Sbapt}
1146234949Sbapt
1147234949Sbapt/*
1148234949Sbapt * %expect requires special handling
1149234949Sbapt * as it really isn't part of the yacc
1150234949Sbapt * grammar only a flag for yacc proper.
1151234949Sbapt */
1152234949Sbaptstatic void
1153234949Sbaptdeclare_expect(int assoc)
1154234949Sbapt{
1155234949Sbapt    int c;
1156234949Sbapt
1157234949Sbapt    if (assoc != EXPECT && assoc != EXPECT_RR)
1158234949Sbapt	++prec;
1159234949Sbapt
1160234949Sbapt    /*
1161234949Sbapt     * Stay away from nextc - doesn't
1162234949Sbapt     * detect EOL and will read to EOF.
1163234949Sbapt     */
1164234949Sbapt    c = *++cptr;
1165234949Sbapt    if (c == EOF)
1166234949Sbapt	unexpected_EOF();
1167234949Sbapt
1168234949Sbapt    for (;;)
1169234949Sbapt    {
1170234949Sbapt	if (isdigit(c))
1171234949Sbapt	{
1172234949Sbapt	    if (assoc == EXPECT)
1173234949Sbapt		SRexpect = get_number();
1174234949Sbapt	    else
1175234949Sbapt		RRexpect = get_number();
1176234949Sbapt	    break;
1177234949Sbapt	}
1178234949Sbapt	/*
1179234949Sbapt	 * Looking for number before EOL.
1180234949Sbapt	 * Spaces, tabs, and numbers are ok,
1181234949Sbapt	 * words, punc., etc. are syntax errors.
1182234949Sbapt	 */
1183234949Sbapt	else if (c == '\n' || isalpha(c) || !isspace(c))
1184234949Sbapt	{
1185234949Sbapt	    syntax_error(lineno, line, cptr);
1186234949Sbapt	}
1187234949Sbapt	else
1188234949Sbapt	{
1189234949Sbapt	    c = *++cptr;
1190234949Sbapt	    if (c == EOF)
1191234949Sbapt		unexpected_EOF();
1192234949Sbapt	}
1193234949Sbapt    }
1194234949Sbapt}
1195234949Sbapt
1196268899Sbapt#if defined(YYBTYACC)
1197234949Sbaptstatic void
1198268899Sbaptdeclare_argtypes(bucket *bp)
1199268899Sbapt{
1200268899Sbapt    char *tags[MAXARGS];
1201268899Sbapt    int args = 0, c;
1202268899Sbapt
1203268899Sbapt    if (bp->args >= 0)
1204268899Sbapt	retyped_warning(bp->name);
1205268899Sbapt    cptr++;			/* skip open paren */
1206268899Sbapt    for (;;)
1207268899Sbapt    {
1208268899Sbapt	c = nextc();
1209268899Sbapt	if (c == EOF)
1210268899Sbapt	    unexpected_EOF();
1211268899Sbapt	if (c != '<')
1212268899Sbapt	    syntax_error(lineno, line, cptr);
1213268899Sbapt	tags[args++] = get_tag();
1214268899Sbapt	c = nextc();
1215268899Sbapt	if (c == R_PAREN)
1216268899Sbapt	    break;
1217268899Sbapt	if (c == EOF)
1218268899Sbapt	    unexpected_EOF();
1219268899Sbapt    }
1220268899Sbapt    cptr++;			/* skip close paren */
1221268899Sbapt    bp->args = args;
1222268899Sbapt    bp->argnames = TMALLOC(char *, args);
1223268899Sbapt    NO_SPACE(bp->argnames);
1224268899Sbapt    bp->argtags = CALLOC(sizeof(char *), args + 1);
1225268899Sbapt    NO_SPACE(bp->argtags);
1226268899Sbapt    while (--args >= 0)
1227268899Sbapt    {
1228268899Sbapt	bp->argtags[args] = tags[args];
1229268899Sbapt	bp->argnames[args] = NULL;
1230268899Sbapt    }
1231268899Sbapt}
1232268899Sbapt#endif
1233268899Sbapt
1234268899Sbaptstatic void
1235234949Sbaptdeclare_types(void)
1236234949Sbapt{
1237234949Sbapt    int c;
1238234949Sbapt    bucket *bp;
1239268899Sbapt    char *tag = NULL;
1240234949Sbapt
1241234949Sbapt    c = nextc();
1242234949Sbapt    if (c == EOF)
1243234949Sbapt	unexpected_EOF();
1244268899Sbapt    if (c == '<')
1245268899Sbapt	tag = get_tag();
1246234949Sbapt
1247234949Sbapt    for (;;)
1248234949Sbapt    {
1249234949Sbapt	c = nextc();
1250268899Sbapt	if (c == EOF)
1251268899Sbapt	    unexpected_EOF();
1252234949Sbapt	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1253268899Sbapt	{
1254234949Sbapt	    bp = get_name();
1255268899Sbapt#if defined(YYBTYACC)
1256268899Sbapt	    if (nextc() == L_PAREN)
1257268899Sbapt		declare_argtypes(bp);
1258268899Sbapt	    else
1259268899Sbapt		bp->args = 0;
1260268899Sbapt#endif
1261268899Sbapt	}
1262234949Sbapt	else if (c == '\'' || c == '"')
1263268899Sbapt	{
1264234949Sbapt	    bp = get_literal();
1265268899Sbapt#if defined(YYBTYACC)
1266268899Sbapt	    bp->args = 0;
1267268899Sbapt#endif
1268268899Sbapt	}
1269234949Sbapt	else
1270234949Sbapt	    return;
1271234949Sbapt
1272268899Sbapt	if (tag)
1273268899Sbapt	{
1274268899Sbapt	    if (bp->tag && tag != bp->tag)
1275268899Sbapt		retyped_warning(bp->name);
1276268899Sbapt	    bp->tag = tag;
1277268899Sbapt	}
1278234949Sbapt    }
1279234949Sbapt}
1280234949Sbapt
1281234949Sbaptstatic void
1282234949Sbaptdeclare_start(void)
1283234949Sbapt{
1284234949Sbapt    int c;
1285234949Sbapt    bucket *bp;
1286234949Sbapt
1287234949Sbapt    c = nextc();
1288234949Sbapt    if (c == EOF)
1289234949Sbapt	unexpected_EOF();
1290234949Sbapt    if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1291234949Sbapt	syntax_error(lineno, line, cptr);
1292234949Sbapt    bp = get_name();
1293234949Sbapt    if (bp->class == TERM)
1294234949Sbapt	terminal_start(bp->name);
1295234949Sbapt    if (goal && goal != bp)
1296234949Sbapt	restarted_warning();
1297234949Sbapt    goal = bp;
1298234949Sbapt}
1299234949Sbapt
1300234949Sbaptstatic void
1301234949Sbaptread_declarations(void)
1302234949Sbapt{
1303234949Sbapt    int c, k;
1304234949Sbapt
1305234949Sbapt    cache_size = 256;
1306240517Sbapt    cache = TMALLOC(char, cache_size);
1307234949Sbapt    NO_SPACE(cache);
1308234949Sbapt
1309234949Sbapt    for (;;)
1310234949Sbapt    {
1311234949Sbapt	c = nextc();
1312234949Sbapt	if (c == EOF)
1313234949Sbapt	    unexpected_EOF();
1314234949Sbapt	if (c != '%')
1315234949Sbapt	    syntax_error(lineno, line, cptr);
1316234949Sbapt	switch (k = keyword())
1317234949Sbapt	{
1318234949Sbapt	case MARK:
1319234949Sbapt	    return;
1320234949Sbapt
1321234949Sbapt	case IDENT:
1322234949Sbapt	    copy_ident();
1323234949Sbapt	    break;
1324234949Sbapt
1325234949Sbapt	case TEXT:
1326234949Sbapt	    copy_text();
1327234949Sbapt	    break;
1328234949Sbapt
1329234949Sbapt	case UNION:
1330234949Sbapt	    copy_union();
1331234949Sbapt	    break;
1332234949Sbapt
1333234949Sbapt	case TOKEN:
1334234949Sbapt	case LEFT:
1335234949Sbapt	case RIGHT:
1336234949Sbapt	case NONASSOC:
1337234949Sbapt	    declare_tokens(k);
1338234949Sbapt	    break;
1339234949Sbapt
1340234949Sbapt	case EXPECT:
1341234949Sbapt	case EXPECT_RR:
1342234949Sbapt	    declare_expect(k);
1343234949Sbapt	    break;
1344234949Sbapt
1345234949Sbapt	case TYPE:
1346234949Sbapt	    declare_types();
1347234949Sbapt	    break;
1348234949Sbapt
1349234949Sbapt	case START:
1350234949Sbapt	    declare_start();
1351234949Sbapt	    break;
1352234949Sbapt
1353234949Sbapt	case PURE_PARSER:
1354234949Sbapt	    pure_parser = 1;
1355234949Sbapt	    break;
1356234949Sbapt
1357234949Sbapt	case PARSE_PARAM:
1358234949Sbapt	case LEX_PARAM:
1359234949Sbapt	    copy_param(k);
1360234949Sbapt	    break;
1361234949Sbapt
1362268899Sbapt	case TOKEN_TABLE:
1363268899Sbapt	    token_table = 1;
1364268899Sbapt	    break;
1365268899Sbapt
1366268899Sbapt#if defined(YYBTYACC)
1367268899Sbapt	case LOCATIONS:
1368268899Sbapt	    locations = 1;
1369268899Sbapt	    break;
1370268899Sbapt
1371268899Sbapt	case DESTRUCTOR:
1372268899Sbapt	    destructor = 1;
1373268899Sbapt	    copy_destructor();
1374268899Sbapt	    break;
1375268899Sbapt#endif
1376268899Sbapt
1377234949Sbapt	case POSIX_YACC:
1378234949Sbapt	    /* noop for bison compatibility. byacc is already designed to be posix
1379234949Sbapt	     * yacc compatible. */
1380234949Sbapt	    break;
1381234949Sbapt	}
1382234949Sbapt    }
1383234949Sbapt}
1384234949Sbapt
1385234949Sbaptstatic void
1386234949Sbaptinitialize_grammar(void)
1387234949Sbapt{
1388234949Sbapt    nitems = 4;
1389234949Sbapt    maxitems = 300;
1390234949Sbapt
1391240517Sbapt    pitem = TMALLOC(bucket *, maxitems);
1392234949Sbapt    NO_SPACE(pitem);
1393234949Sbapt
1394234949Sbapt    pitem[0] = 0;
1395234949Sbapt    pitem[1] = 0;
1396234949Sbapt    pitem[2] = 0;
1397234949Sbapt    pitem[3] = 0;
1398234949Sbapt
1399234949Sbapt    nrules = 3;
1400234949Sbapt    maxrules = 100;
1401234949Sbapt
1402240517Sbapt    plhs = TMALLOC(bucket *, maxrules);
1403234949Sbapt    NO_SPACE(plhs);
1404234949Sbapt
1405234949Sbapt    plhs[0] = 0;
1406234949Sbapt    plhs[1] = 0;
1407234949Sbapt    plhs[2] = 0;
1408234949Sbapt
1409240517Sbapt    rprec = TMALLOC(Value_t, maxrules);
1410234949Sbapt    NO_SPACE(rprec);
1411234949Sbapt
1412234949Sbapt    rprec[0] = 0;
1413234949Sbapt    rprec[1] = 0;
1414234949Sbapt    rprec[2] = 0;
1415234949Sbapt
1416240517Sbapt    rassoc = TMALLOC(Assoc_t, maxrules);
1417234949Sbapt    NO_SPACE(rassoc);
1418234949Sbapt
1419234949Sbapt    rassoc[0] = TOKEN;
1420234949Sbapt    rassoc[1] = TOKEN;
1421234949Sbapt    rassoc[2] = TOKEN;
1422234949Sbapt}
1423234949Sbapt
1424234949Sbaptstatic void
1425234949Sbaptexpand_items(void)
1426234949Sbapt{
1427234949Sbapt    maxitems += 300;
1428240517Sbapt    pitem = TREALLOC(bucket *, pitem, maxitems);
1429234949Sbapt    NO_SPACE(pitem);
1430234949Sbapt}
1431234949Sbapt
1432234949Sbaptstatic void
1433234949Sbaptexpand_rules(void)
1434234949Sbapt{
1435234949Sbapt    maxrules += 100;
1436234949Sbapt
1437240517Sbapt    plhs = TREALLOC(bucket *, plhs, maxrules);
1438234949Sbapt    NO_SPACE(plhs);
1439234949Sbapt
1440240517Sbapt    rprec = TREALLOC(Value_t, rprec, maxrules);
1441234949Sbapt    NO_SPACE(rprec);
1442234949Sbapt
1443240517Sbapt    rassoc = TREALLOC(Assoc_t, rassoc, maxrules);
1444234949Sbapt    NO_SPACE(rassoc);
1445234949Sbapt}
1446234949Sbapt
1447268899Sbapt/* set immediately prior to where copy_args() could be called, and incremented by
1448268899Sbapt   the various routines that will rescan the argument list as appropriate */
1449268899Sbaptstatic int rescan_lineno;
1450268899Sbapt#if defined(YYBTYACC)
1451268899Sbapt
1452268899Sbaptstatic char *
1453268899Sbaptcopy_args(int *alen)
1454268899Sbapt{
1455268899Sbapt    struct mstring *s = msnew();
1456268899Sbapt    int depth = 0, len = 1;
1457268899Sbapt    char c, quote = 0;
1458268899Sbapt    int a_lineno = lineno;
1459268899Sbapt    char *a_line = dup_line();
1460268899Sbapt    char *a_cptr = a_line + (cptr - line - 1);
1461268899Sbapt
1462268899Sbapt    while ((c = *cptr++) != R_PAREN || depth || quote)
1463268899Sbapt    {
1464268899Sbapt	if (c == ',' && !quote && !depth)
1465268899Sbapt	{
1466268899Sbapt	    len++;
1467268899Sbapt	    mputc(s, 0);
1468268899Sbapt	    continue;
1469268899Sbapt	}
1470268899Sbapt	mputc(s, c);
1471268899Sbapt	if (c == '\n')
1472268899Sbapt	{
1473268899Sbapt	    get_line();
1474268899Sbapt	    if (!line)
1475268899Sbapt	    {
1476268899Sbapt		if (quote)
1477268899Sbapt		    unterminated_string(a_lineno, a_line, a_cptr);
1478268899Sbapt		else
1479268899Sbapt		    unterminated_arglist(a_lineno, a_line, a_cptr);
1480268899Sbapt	    }
1481268899Sbapt	}
1482268899Sbapt	else if (quote)
1483268899Sbapt	{
1484268899Sbapt	    if (c == quote)
1485268899Sbapt		quote = 0;
1486268899Sbapt	    else if (c == '\\')
1487268899Sbapt	    {
1488268899Sbapt		if (*cptr != '\n')
1489268899Sbapt		    mputc(s, *cptr++);
1490268899Sbapt	    }
1491268899Sbapt	}
1492268899Sbapt	else
1493268899Sbapt	{
1494268899Sbapt	    if (c == L_PAREN)
1495268899Sbapt		depth++;
1496268899Sbapt	    else if (c == R_PAREN)
1497268899Sbapt		depth--;
1498268899Sbapt	    else if (c == '\"' || c == '\'')
1499268899Sbapt		quote = c;
1500268899Sbapt	}
1501268899Sbapt    }
1502268899Sbapt    if (alen)
1503268899Sbapt	*alen = len;
1504268899Sbapt    FREE(a_line);
1505268899Sbapt    return msdone(s);
1506268899Sbapt}
1507268899Sbapt
1508268899Sbaptstatic char *
1509268899Sbaptparse_id(char *p, char **save)
1510268899Sbapt{
1511268899Sbapt    char *b;
1512268899Sbapt
1513268899Sbapt    while (isspace(*p))
1514268899Sbapt	if (*p++ == '\n')
1515268899Sbapt	    rescan_lineno++;
1516268899Sbapt    if (!isalpha(*p) && *p != '_')
1517268899Sbapt	return NULL;
1518268899Sbapt    b = p;
1519268899Sbapt    while (isalnum(*p) || *p == '_' || *p == '$')
1520268899Sbapt	p++;
1521268899Sbapt    if (save)
1522268899Sbapt    {
1523268899Sbapt	*save = cache_tag(b, (size_t) (p - b));
1524268899Sbapt    }
1525268899Sbapt    return p;
1526268899Sbapt}
1527268899Sbapt
1528268899Sbaptstatic char *
1529268899Sbaptparse_int(char *p, int *save)
1530268899Sbapt{
1531268899Sbapt    int neg = 0, val = 0;
1532268899Sbapt
1533268899Sbapt    while (isspace(*p))
1534268899Sbapt	if (*p++ == '\n')
1535268899Sbapt	    rescan_lineno++;
1536268899Sbapt    if (*p == '-')
1537268899Sbapt    {
1538268899Sbapt	neg = 1;
1539268899Sbapt	p++;
1540268899Sbapt    }
1541268899Sbapt    if (!isdigit(*p))
1542268899Sbapt	return NULL;
1543268899Sbapt    while (isdigit(*p))
1544268899Sbapt	val = val * 10 + *p++ - '0';
1545268899Sbapt    if (neg)
1546268899Sbapt	val = -val;
1547268899Sbapt    if (save)
1548268899Sbapt	*save = val;
1549268899Sbapt    return p;
1550268899Sbapt}
1551268899Sbapt
1552234949Sbaptstatic void
1553268899Sbaptparse_arginfo(bucket *a, char *args, int argslen)
1554268899Sbapt{
1555268899Sbapt    char *p = args, *tmp;
1556268899Sbapt    int i, redec = 0;
1557268899Sbapt
1558268899Sbapt    if (a->args > 0)
1559268899Sbapt    {
1560268899Sbapt	if (a->args != argslen)
1561268899Sbapt	    arg_number_disagree_warning(rescan_lineno, a->name);
1562268899Sbapt	redec = 1;
1563268899Sbapt    }
1564268899Sbapt    else
1565268899Sbapt    {
1566268899Sbapt	if ((a->args = argslen) == 0)
1567268899Sbapt	    return;
1568268899Sbapt	a->argnames = TMALLOC(char *, argslen);
1569268899Sbapt	NO_SPACE(a->argnames);
1570268899Sbapt	a->argtags = TMALLOC(char *, argslen);
1571268899Sbapt	NO_SPACE(a->argtags);
1572268899Sbapt    }
1573268899Sbapt    if (!args)
1574268899Sbapt	return;
1575268899Sbapt    for (i = 0; i < argslen; i++)
1576268899Sbapt    {
1577268899Sbapt	while (isspace(*p))
1578268899Sbapt	    if (*p++ == '\n')
1579268899Sbapt		rescan_lineno++;
1580268899Sbapt	if (*p++ != '$')
1581268899Sbapt	    bad_formals();
1582268899Sbapt	while (isspace(*p))
1583268899Sbapt	    if (*p++ == '\n')
1584268899Sbapt		rescan_lineno++;
1585268899Sbapt	if (*p == '<')
1586268899Sbapt	{
1587268899Sbapt	    havetags = 1;
1588268899Sbapt	    if (!(p = parse_id(p + 1, &tmp)))
1589268899Sbapt		bad_formals();
1590268899Sbapt	    while (isspace(*p))
1591268899Sbapt		if (*p++ == '\n')
1592268899Sbapt		    rescan_lineno++;
1593268899Sbapt	    if (*p++ != '>')
1594268899Sbapt		bad_formals();
1595268899Sbapt	    if (redec)
1596268899Sbapt	    {
1597268899Sbapt		if (a->argtags[i] != tmp)
1598268899Sbapt		    arg_type_disagree_warning(rescan_lineno, i + 1, a->name);
1599268899Sbapt	    }
1600268899Sbapt	    else
1601268899Sbapt		a->argtags[i] = tmp;
1602268899Sbapt	}
1603268899Sbapt	else if (!redec)
1604268899Sbapt	    a->argtags[i] = NULL;
1605268899Sbapt	if (!(p = parse_id(p, &a->argnames[i])))
1606268899Sbapt	    bad_formals();
1607268899Sbapt	while (isspace(*p))
1608268899Sbapt	    if (*p++ == '\n')
1609268899Sbapt		rescan_lineno++;
1610268899Sbapt	if (*p++)
1611268899Sbapt	    bad_formals();
1612268899Sbapt    }
1613268899Sbapt    free(args);
1614268899Sbapt}
1615268899Sbapt
1616268899Sbaptstatic char *
1617268899Sbaptcompile_arg(char **theptr, char *yyvaltag)
1618268899Sbapt{
1619268899Sbapt    char *p = *theptr;
1620268899Sbapt    struct mstring *c = msnew();
1621268899Sbapt    int i, j, n;
1622268899Sbapt    Value_t *offsets = NULL, maxoffset;
1623268899Sbapt    bucket **rhs;
1624268899Sbapt
1625268899Sbapt    maxoffset = 0;
1626268899Sbapt    n = 0;
1627268899Sbapt    for (i = nitems - 1; pitem[i]; --i)
1628268899Sbapt    {
1629268899Sbapt	n++;
1630268899Sbapt	if (pitem[i]->class != ARGUMENT)
1631268899Sbapt	    maxoffset++;
1632268899Sbapt    }
1633268899Sbapt    if (maxoffset > 0)
1634268899Sbapt    {
1635268899Sbapt	offsets = TMALLOC(Value_t, maxoffset + 1);
1636268899Sbapt	NO_SPACE(offsets);
1637268899Sbapt    }
1638268899Sbapt    for (j = 0, i++; i < nitems; i++)
1639268899Sbapt	if (pitem[i]->class != ARGUMENT)
1640268899Sbapt	    offsets[++j] = (Value_t) (i - nitems + 1);
1641268899Sbapt    rhs = pitem + nitems - 1;
1642268899Sbapt
1643268899Sbapt    if (yyvaltag)
1644268899Sbapt	msprintf(c, "yyval.%s = ", yyvaltag);
1645268899Sbapt    else
1646268899Sbapt	msprintf(c, "yyval = ");
1647268899Sbapt    while (*p)
1648268899Sbapt    {
1649268899Sbapt	if (*p == '$')
1650268899Sbapt	{
1651268899Sbapt	    char *tag = NULL;
1652268899Sbapt	    if (*++p == '<')
1653268899Sbapt		if (!(p = parse_id(++p, &tag)) || *p++ != '>')
1654268899Sbapt		    illegal_tag(rescan_lineno, NULL, NULL);
1655268899Sbapt	    if (isdigit(*p) || *p == '-')
1656268899Sbapt	    {
1657268899Sbapt		int val;
1658268899Sbapt		if (!(p = parse_int(p, &val)))
1659268899Sbapt		    dollar_error(rescan_lineno, NULL, NULL);
1660268899Sbapt		if (val <= 0)
1661268899Sbapt		    i = val - n;
1662268899Sbapt		else if (val > maxoffset)
1663268899Sbapt		{
1664268899Sbapt		    dollar_warning(rescan_lineno, val);
1665268899Sbapt		    i = val - maxoffset;
1666268899Sbapt		}
1667268899Sbapt		else
1668268899Sbapt		{
1669268899Sbapt		    i = offsets[val];
1670268899Sbapt		    if (!tag && !(tag = rhs[i]->tag) && havetags)
1671268899Sbapt			untyped_rhs(val, rhs[i]->name);
1672268899Sbapt		}
1673268899Sbapt		msprintf(c, "yystack.l_mark[%d]", i);
1674268899Sbapt		if (tag)
1675268899Sbapt		    msprintf(c, ".%s", tag);
1676268899Sbapt		else if (havetags)
1677268899Sbapt		    unknown_rhs(val);
1678268899Sbapt	    }
1679268899Sbapt	    else if (isalpha(*p) || *p == '_')
1680268899Sbapt	    {
1681268899Sbapt		char *arg;
1682268899Sbapt		if (!(p = parse_id(p, &arg)))
1683268899Sbapt		    dollar_error(rescan_lineno, NULL, NULL);
1684268899Sbapt		for (i = plhs[nrules]->args - 1; i >= 0; i--)
1685268899Sbapt		    if (arg == plhs[nrules]->argnames[i])
1686268899Sbapt			break;
1687268899Sbapt		if (i < 0)
1688268899Sbapt		    unknown_arg_warning(rescan_lineno, "$", arg, NULL, NULL);
1689268899Sbapt		else if (!tag)
1690268899Sbapt		    tag = plhs[nrules]->argtags[i];
1691268899Sbapt		msprintf(c, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1
1692268899Sbapt			 - n);
1693268899Sbapt		if (tag)
1694268899Sbapt		    msprintf(c, ".%s", tag);
1695268899Sbapt		else if (havetags)
1696268899Sbapt		    untyped_arg_warning(rescan_lineno, "$", arg);
1697268899Sbapt	    }
1698268899Sbapt	    else
1699268899Sbapt		dollar_error(rescan_lineno, NULL, NULL);
1700268899Sbapt	}
1701268899Sbapt	else if (*p == '@')
1702268899Sbapt	{
1703268899Sbapt	    at_error(rescan_lineno, NULL, NULL);
1704268899Sbapt	}
1705268899Sbapt	else
1706268899Sbapt	{
1707268899Sbapt	    if (*p == '\n')
1708268899Sbapt		rescan_lineno++;
1709268899Sbapt	    mputc(c, *p++);
1710268899Sbapt	}
1711268899Sbapt    }
1712268899Sbapt    *theptr = p;
1713268899Sbapt    if (maxoffset > 0)
1714268899Sbapt	FREE(offsets);
1715268899Sbapt    return msdone(c);
1716268899Sbapt}
1717268899Sbapt
1718268899Sbapt#define ARG_CACHE_SIZE	1024
1719268899Sbaptstatic struct arg_cache
1720268899Sbapt{
1721268899Sbapt    struct arg_cache *next;
1722268899Sbapt    char *code;
1723268899Sbapt    int rule;
1724268899Sbapt}
1725268899Sbapt *arg_cache[ARG_CACHE_SIZE];
1726268899Sbapt
1727268899Sbaptstatic int
1728268899Sbaptlookup_arg_cache(char *code)
1729268899Sbapt{
1730268899Sbapt    struct arg_cache *entry;
1731268899Sbapt
1732268899Sbapt    entry = arg_cache[strnshash(code) % ARG_CACHE_SIZE];
1733268899Sbapt    while (entry)
1734268899Sbapt    {
1735268899Sbapt	if (!strnscmp(entry->code, code))
1736268899Sbapt	    return entry->rule;
1737268899Sbapt	entry = entry->next;
1738268899Sbapt    }
1739268899Sbapt    return -1;
1740268899Sbapt}
1741268899Sbapt
1742268899Sbaptstatic void
1743268899Sbaptinsert_arg_cache(char *code, int rule)
1744268899Sbapt{
1745268899Sbapt    struct arg_cache *entry = NEW(struct arg_cache);
1746268899Sbapt    int i;
1747268899Sbapt
1748268899Sbapt    NO_SPACE(entry);
1749268899Sbapt    i = strnshash(code) % ARG_CACHE_SIZE;
1750268899Sbapt    entry->code = code;
1751268899Sbapt    entry->rule = rule;
1752268899Sbapt    entry->next = arg_cache[i];
1753268899Sbapt    arg_cache[i] = entry;
1754268899Sbapt}
1755268899Sbapt
1756268899Sbaptstatic void
1757268899Sbaptclean_arg_cache(void)
1758268899Sbapt{
1759268899Sbapt    struct arg_cache *e, *t;
1760268899Sbapt    int i;
1761268899Sbapt
1762268899Sbapt    for (i = 0; i < ARG_CACHE_SIZE; i++)
1763268899Sbapt    {
1764268899Sbapt	for (e = arg_cache[i]; (t = e); e = e->next, FREE(t))
1765268899Sbapt	    free(e->code);
1766268899Sbapt	arg_cache[i] = NULL;
1767268899Sbapt    }
1768268899Sbapt}
1769268899Sbapt#endif
1770268899Sbapt
1771268899Sbaptstatic void
1772234949Sbaptadvance_to_start(void)
1773234949Sbapt{
1774234949Sbapt    int c;
1775234949Sbapt    bucket *bp;
1776234949Sbapt    char *s_cptr;
1777234949Sbapt    int s_lineno;
1778268899Sbapt#if defined(YYBTYACC)
1779268899Sbapt    char *args = NULL;
1780268899Sbapt    int argslen = 0;
1781268899Sbapt#endif
1782234949Sbapt
1783234949Sbapt    for (;;)
1784234949Sbapt    {
1785234949Sbapt	c = nextc();
1786234949Sbapt	if (c != '%')
1787234949Sbapt	    break;
1788234949Sbapt	s_cptr = cptr;
1789234949Sbapt	switch (keyword())
1790234949Sbapt	{
1791234949Sbapt	case MARK:
1792234949Sbapt	    no_grammar();
1793234949Sbapt
1794234949Sbapt	case TEXT:
1795234949Sbapt	    copy_text();
1796234949Sbapt	    break;
1797234949Sbapt
1798234949Sbapt	case START:
1799234949Sbapt	    declare_start();
1800234949Sbapt	    break;
1801234949Sbapt
1802234949Sbapt	default:
1803234949Sbapt	    syntax_error(lineno, line, s_cptr);
1804234949Sbapt	}
1805234949Sbapt    }
1806234949Sbapt
1807234949Sbapt    c = nextc();
1808234949Sbapt    if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1809234949Sbapt	syntax_error(lineno, line, cptr);
1810234949Sbapt    bp = get_name();
1811234949Sbapt    if (goal == 0)
1812234949Sbapt    {
1813234949Sbapt	if (bp->class == TERM)
1814234949Sbapt	    terminal_start(bp->name);
1815234949Sbapt	goal = bp;
1816234949Sbapt    }
1817234949Sbapt
1818234949Sbapt    s_lineno = lineno;
1819234949Sbapt    c = nextc();
1820234949Sbapt    if (c == EOF)
1821234949Sbapt	unexpected_EOF();
1822268899Sbapt    rescan_lineno = lineno;	/* line# for possible inherited args rescan */
1823268899Sbapt#if defined(YYBTYACC)
1824268899Sbapt    if (c == L_PAREN)
1825268899Sbapt    {
1826268899Sbapt	++cptr;
1827268899Sbapt	args = copy_args(&argslen);
1828268899Sbapt	NO_SPACE(args);
1829268899Sbapt	c = nextc();
1830268899Sbapt    }
1831268899Sbapt#endif
1832234949Sbapt    if (c != ':')
1833234949Sbapt	syntax_error(lineno, line, cptr);
1834234949Sbapt    start_rule(bp, s_lineno);
1835268899Sbapt#if defined(YYBTYACC)
1836268899Sbapt    parse_arginfo(bp, args, argslen);
1837268899Sbapt#endif
1838234949Sbapt    ++cptr;
1839234949Sbapt}
1840234949Sbapt
1841234949Sbaptstatic void
1842234949Sbaptstart_rule(bucket *bp, int s_lineno)
1843234949Sbapt{
1844234949Sbapt    if (bp->class == TERM)
1845234949Sbapt	terminal_lhs(s_lineno);
1846234949Sbapt    bp->class = NONTERM;
1847268899Sbapt    if (!bp->index)
1848268899Sbapt	bp->index = nrules;
1849234949Sbapt    if (nrules >= maxrules)
1850234949Sbapt	expand_rules();
1851234949Sbapt    plhs[nrules] = bp;
1852234949Sbapt    rprec[nrules] = UNDEFINED;
1853234949Sbapt    rassoc[nrules] = TOKEN;
1854234949Sbapt}
1855234949Sbapt
1856234949Sbaptstatic void
1857234949Sbaptend_rule(void)
1858234949Sbapt{
1859234949Sbapt    int i;
1860234949Sbapt
1861234949Sbapt    if (!last_was_action && plhs[nrules]->tag)
1862234949Sbapt    {
1863234949Sbapt	if (pitem[nitems - 1])
1864234949Sbapt	{
1865234949Sbapt	    for (i = nitems - 1; (i > 0) && pitem[i]; --i)
1866234949Sbapt		continue;
1867234949Sbapt	    if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
1868234949Sbapt		default_action_warning();
1869234949Sbapt	}
1870234949Sbapt	else
1871234949Sbapt	{
1872234949Sbapt	    default_action_warning();
1873234949Sbapt	}
1874234949Sbapt    }
1875234949Sbapt
1876234949Sbapt    last_was_action = 0;
1877234949Sbapt    if (nitems >= maxitems)
1878234949Sbapt	expand_items();
1879234949Sbapt    pitem[nitems] = 0;
1880234949Sbapt    ++nitems;
1881234949Sbapt    ++nrules;
1882234949Sbapt}
1883234949Sbapt
1884234949Sbaptstatic void
1885234949Sbaptinsert_empty_rule(void)
1886234949Sbapt{
1887234949Sbapt    bucket *bp, **bpp;
1888234949Sbapt
1889234949Sbapt    assert(cache);
1890234949Sbapt    sprintf(cache, "$$%d", ++gensym);
1891234949Sbapt    bp = make_bucket(cache);
1892234949Sbapt    last_symbol->next = bp;
1893234949Sbapt    last_symbol = bp;
1894234949Sbapt    bp->tag = plhs[nrules]->tag;
1895268899Sbapt    bp->class = ACTION;
1896268899Sbapt#if defined(YYBTYACC)
1897268899Sbapt    bp->args = 0;
1898268899Sbapt#endif
1899234949Sbapt
1900268899Sbapt    nitems = (Value_t) (nitems + 2);
1901268899Sbapt    if (nitems > maxitems)
1902234949Sbapt	expand_items();
1903234949Sbapt    bpp = pitem + nitems - 1;
1904234949Sbapt    *bpp-- = bp;
1905234949Sbapt    while ((bpp[0] = bpp[-1]) != 0)
1906234949Sbapt	--bpp;
1907234949Sbapt
1908234949Sbapt    if (++nrules >= maxrules)
1909234949Sbapt	expand_rules();
1910234949Sbapt    plhs[nrules] = plhs[nrules - 1];
1911234949Sbapt    plhs[nrules - 1] = bp;
1912234949Sbapt    rprec[nrules] = rprec[nrules - 1];
1913234949Sbapt    rprec[nrules - 1] = 0;
1914234949Sbapt    rassoc[nrules] = rassoc[nrules - 1];
1915234949Sbapt    rassoc[nrules - 1] = TOKEN;
1916234949Sbapt}
1917234949Sbapt
1918268899Sbapt#if defined(YYBTYACC)
1919268899Sbaptstatic char *
1920268899Sbaptinsert_arg_rule(char *arg, char *tag)
1921268899Sbapt{
1922268899Sbapt    int line_number = rescan_lineno;
1923268899Sbapt    char *code = compile_arg(&arg, tag);
1924268899Sbapt    int rule = lookup_arg_cache(code);
1925268899Sbapt    FILE *f = action_file;
1926268899Sbapt
1927268899Sbapt    if (rule < 0)
1928268899Sbapt    {
1929268899Sbapt	rule = nrules;
1930268899Sbapt	insert_arg_cache(code, rule);
1931268899Sbapt	fprintf(f, "case %d:\n", rule - 2);
1932268899Sbapt	if (!lflag)
1933268899Sbapt	    fprintf(f, line_format, line_number, input_file_name);
1934268899Sbapt	fprintf(f, "%s;\n", code);
1935268899Sbapt	fprintf(f, "break;\n");
1936268899Sbapt	insert_empty_rule();
1937268899Sbapt	plhs[rule]->tag = tag;
1938268899Sbapt	plhs[rule]->class = ARGUMENT;
1939268899Sbapt    }
1940268899Sbapt    else
1941268899Sbapt    {
1942268899Sbapt	if (++nitems > maxitems)
1943268899Sbapt	    expand_items();
1944268899Sbapt	pitem[nitems - 1] = plhs[rule];
1945268899Sbapt	free(code);
1946268899Sbapt    }
1947268899Sbapt    return arg + 1;
1948268899Sbapt}
1949268899Sbapt#endif
1950268899Sbapt
1951234949Sbaptstatic void
1952234949Sbaptadd_symbol(void)
1953234949Sbapt{
1954234949Sbapt    int c;
1955234949Sbapt    bucket *bp;
1956234949Sbapt    int s_lineno = lineno;
1957268899Sbapt#if defined(YYBTYACC)
1958268899Sbapt    char *args = NULL;
1959268899Sbapt    int argslen = 0;
1960268899Sbapt#endif
1961234949Sbapt
1962234949Sbapt    c = *cptr;
1963234949Sbapt    if (c == '\'' || c == '"')
1964234949Sbapt	bp = get_literal();
1965234949Sbapt    else
1966234949Sbapt	bp = get_name();
1967234949Sbapt
1968234949Sbapt    c = nextc();
1969268899Sbapt    rescan_lineno = lineno;	/* line# for possible inherited args rescan */
1970268899Sbapt#if defined(YYBTYACC)
1971268899Sbapt    if (c == L_PAREN)
1972268899Sbapt    {
1973268899Sbapt	++cptr;
1974268899Sbapt	args = copy_args(&argslen);
1975268899Sbapt	NO_SPACE(args);
1976268899Sbapt	c = nextc();
1977268899Sbapt    }
1978268899Sbapt#endif
1979234949Sbapt    if (c == ':')
1980234949Sbapt    {
1981234949Sbapt	end_rule();
1982234949Sbapt	start_rule(bp, s_lineno);
1983268899Sbapt#if defined(YYBTYACC)
1984268899Sbapt	parse_arginfo(bp, args, argslen);
1985268899Sbapt#endif
1986234949Sbapt	++cptr;
1987234949Sbapt	return;
1988234949Sbapt    }
1989234949Sbapt
1990234949Sbapt    if (last_was_action)
1991234949Sbapt	insert_empty_rule();
1992234949Sbapt    last_was_action = 0;
1993234949Sbapt
1994268899Sbapt#if defined(YYBTYACC)
1995268899Sbapt    if (bp->args < 0)
1996268899Sbapt	bp->args = argslen;
1997268899Sbapt    if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL)
1998268899Sbapt    {
1999268899Sbapt	int i;
2000268899Sbapt	if (plhs[nrules]->args != bp->args)
2001268899Sbapt	    wrong_number_args_warning("default ", bp->name);
2002268899Sbapt	for (i = bp->args - 1; i >= 0; i--)
2003268899Sbapt	    if (plhs[nrules]->argtags[i] != bp->argtags[i])
2004268899Sbapt		wrong_type_for_arg_warning(i + 1, bp->name);
2005268899Sbapt    }
2006268899Sbapt    else if (bp->args != argslen)
2007268899Sbapt	wrong_number_args_warning("", bp->name);
2008268899Sbapt    if (bp->args > 0 && argslen > 0)
2009268899Sbapt    {
2010268899Sbapt	char *ap;
2011268899Sbapt	int i;
2012268899Sbapt	for (ap = args, i = 0; i < argslen; i++)
2013268899Sbapt	    ap = insert_arg_rule(ap, bp->argtags[i]);
2014268899Sbapt	free(args);
2015268899Sbapt    }
2016268899Sbapt#endif /* defined(YYBTYACC) */
2017268899Sbapt
2018234949Sbapt    if (++nitems > maxitems)
2019234949Sbapt	expand_items();
2020234949Sbapt    pitem[nitems - 1] = bp;
2021234949Sbapt}
2022234949Sbapt
2023234949Sbaptstatic char *
2024234949Sbaptafter_blanks(char *s)
2025234949Sbapt{
2026234949Sbapt    while (*s != '\0' && isspace(UCH(*s)))
2027234949Sbapt	++s;
2028234949Sbapt    return s;
2029234949Sbapt}
2030234949Sbapt
2031234949Sbaptstatic void
2032234949Sbaptcopy_action(void)
2033234949Sbapt{
2034234949Sbapt    int c;
2035268899Sbapt    int i, j, n;
2036234949Sbapt    int depth;
2037268899Sbapt#if defined(YYBTYACC)
2038268899Sbapt    int trialaction = 0;
2039268899Sbapt    int haveyyval = 0;
2040268899Sbapt#endif
2041234949Sbapt    char *tag;
2042234949Sbapt    FILE *f = action_file;
2043234949Sbapt    int a_lineno = lineno;
2044234949Sbapt    char *a_line = dup_line();
2045234949Sbapt    char *a_cptr = a_line + (cptr - line);
2046268899Sbapt    Value_t *offsets = NULL, maxoffset;
2047268899Sbapt    bucket **rhs;
2048234949Sbapt
2049234949Sbapt    if (last_was_action)
2050234949Sbapt	insert_empty_rule();
2051234949Sbapt    last_was_action = 1;
2052234949Sbapt
2053234949Sbapt    fprintf(f, "case %d:\n", nrules - 2);
2054268899Sbapt#if defined(YYBTYACC)
2055268899Sbapt    if (backtrack)
2056268899Sbapt    {
2057268899Sbapt	if (*cptr != L_BRAC)
2058268899Sbapt	    fprintf(f, "  if (!yytrial)\n");
2059268899Sbapt	else
2060268899Sbapt	    trialaction = 1;
2061268899Sbapt    }
2062268899Sbapt#endif
2063234949Sbapt    if (!lflag)
2064234949Sbapt	fprintf(f, line_format, lineno, input_file_name);
2065234949Sbapt    if (*cptr == '=')
2066234949Sbapt	++cptr;
2067234949Sbapt
2068234949Sbapt    /* avoid putting curly-braces in first column, to ease editing */
2069234949Sbapt    if (*after_blanks(cptr) == L_CURL)
2070234949Sbapt    {
2071234949Sbapt	putc('\t', f);
2072234949Sbapt	cptr = after_blanks(cptr);
2073234949Sbapt    }
2074234949Sbapt
2075268899Sbapt    maxoffset = 0;
2076234949Sbapt    n = 0;
2077234949Sbapt    for (i = nitems - 1; pitem[i]; --i)
2078268899Sbapt    {
2079234949Sbapt	++n;
2080268899Sbapt	if (pitem[i]->class != ARGUMENT)
2081268899Sbapt	    maxoffset++;
2082268899Sbapt    }
2083268899Sbapt    if (maxoffset > 0)
2084268899Sbapt    {
2085268899Sbapt	offsets = TMALLOC(Value_t, maxoffset + 1);
2086268899Sbapt	NO_SPACE(offsets);
2087268899Sbapt    }
2088268899Sbapt    for (j = 0, i++; i < nitems; i++)
2089268899Sbapt    {
2090268899Sbapt	if (pitem[i]->class != ARGUMENT)
2091268899Sbapt	{
2092268899Sbapt	    offsets[++j] = (Value_t) (i - nitems + 1);
2093268899Sbapt	}
2094268899Sbapt    }
2095268899Sbapt    rhs = pitem + nitems - 1;
2096234949Sbapt
2097234949Sbapt    depth = 0;
2098234949Sbapt  loop:
2099234949Sbapt    c = *cptr;
2100234949Sbapt    if (c == '$')
2101234949Sbapt    {
2102234949Sbapt	if (cptr[1] == '<')
2103234949Sbapt	{
2104234949Sbapt	    int d_lineno = lineno;
2105234949Sbapt	    char *d_line = dup_line();
2106234949Sbapt	    char *d_cptr = d_line + (cptr - line);
2107234949Sbapt
2108234949Sbapt	    ++cptr;
2109234949Sbapt	    tag = get_tag();
2110234949Sbapt	    c = *cptr;
2111234949Sbapt	    if (c == '$')
2112234949Sbapt	    {
2113234949Sbapt		fprintf(f, "yyval.%s", tag);
2114234949Sbapt		++cptr;
2115234949Sbapt		FREE(d_line);
2116234949Sbapt		goto loop;
2117234949Sbapt	    }
2118234949Sbapt	    else if (isdigit(c))
2119234949Sbapt	    {
2120234949Sbapt		i = get_number();
2121268899Sbapt		if (i == 0)
2122268899Sbapt		    fprintf(f, "yystack.l_mark[%d].%s", -n, tag);
2123268899Sbapt		else if (i > maxoffset)
2124268899Sbapt		{
2125234949Sbapt		    dollar_warning(d_lineno, i);
2126268899Sbapt		    fprintf(f, "yystack.l_mark[%d].%s", i - maxoffset, tag);
2127268899Sbapt		}
2128268899Sbapt		else if (offsets)
2129268899Sbapt		    fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2130234949Sbapt		FREE(d_line);
2131234949Sbapt		goto loop;
2132234949Sbapt	    }
2133234949Sbapt	    else if (c == '-' && isdigit(UCH(cptr[1])))
2134234949Sbapt	    {
2135234949Sbapt		++cptr;
2136234949Sbapt		i = -get_number() - n;
2137234949Sbapt		fprintf(f, "yystack.l_mark[%d].%s", i, tag);
2138234949Sbapt		FREE(d_line);
2139234949Sbapt		goto loop;
2140234949Sbapt	    }
2141268899Sbapt#if defined(YYBTYACC)
2142268899Sbapt	    else if (isalpha(c) || c == '_')
2143268899Sbapt	    {
2144268899Sbapt		char *arg = scan_id();
2145268899Sbapt		for (i = plhs[nrules]->args - 1; i >= 0; i--)
2146268899Sbapt		    if (arg == plhs[nrules]->argnames[i])
2147268899Sbapt			break;
2148268899Sbapt		if (i < 0)
2149268899Sbapt		    unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr);
2150268899Sbapt		fprintf(f, "yystack.l_mark[%d].%s", i - plhs[nrules]->args +
2151268899Sbapt			1 - n, tag);
2152268899Sbapt		FREE(d_line);
2153268899Sbapt		goto loop;
2154268899Sbapt	    }
2155268899Sbapt#endif
2156234949Sbapt	    else
2157234949Sbapt		dollar_error(d_lineno, d_line, d_cptr);
2158234949Sbapt	}
2159234949Sbapt	else if (cptr[1] == '$')
2160234949Sbapt	{
2161268899Sbapt	    if (havetags)
2162234949Sbapt	    {
2163234949Sbapt		tag = plhs[nrules]->tag;
2164234949Sbapt		if (tag == 0)
2165234949Sbapt		    untyped_lhs();
2166234949Sbapt		fprintf(f, "yyval.%s", tag);
2167234949Sbapt	    }
2168234949Sbapt	    else
2169234949Sbapt		fprintf(f, "yyval");
2170234949Sbapt	    cptr += 2;
2171268899Sbapt#if defined(YYBTYACC)
2172268899Sbapt	    haveyyval = 1;
2173268899Sbapt#endif
2174234949Sbapt	    goto loop;
2175234949Sbapt	}
2176234949Sbapt	else if (isdigit(UCH(cptr[1])))
2177234949Sbapt	{
2178234949Sbapt	    ++cptr;
2179234949Sbapt	    i = get_number();
2180268899Sbapt	    if (havetags)
2181234949Sbapt	    {
2182268899Sbapt		if (i <= 0 || i > maxoffset)
2183234949Sbapt		    unknown_rhs(i);
2184268899Sbapt		tag = rhs[offsets[i]]->tag;
2185234949Sbapt		if (tag == 0)
2186268899Sbapt		    untyped_rhs(i, rhs[offsets[i]]->name);
2187268899Sbapt		fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2188234949Sbapt	    }
2189234949Sbapt	    else
2190234949Sbapt	    {
2191268899Sbapt		if (i == 0)
2192268899Sbapt		    fprintf(f, "yystack.l_mark[%d]", -n);
2193268899Sbapt		else if (i > maxoffset)
2194268899Sbapt		{
2195234949Sbapt		    dollar_warning(lineno, i);
2196268899Sbapt		    fprintf(f, "yystack.l_mark[%d]", i - maxoffset);
2197268899Sbapt		}
2198268899Sbapt		else if (offsets)
2199268899Sbapt		    fprintf(f, "yystack.l_mark[%d]", offsets[i]);
2200234949Sbapt	    }
2201234949Sbapt	    goto loop;
2202234949Sbapt	}
2203234949Sbapt	else if (cptr[1] == '-')
2204234949Sbapt	{
2205234949Sbapt	    cptr += 2;
2206234949Sbapt	    i = get_number();
2207268899Sbapt	    if (havetags)
2208234949Sbapt		unknown_rhs(-i);
2209234949Sbapt	    fprintf(f, "yystack.l_mark[%d]", -i - n);
2210234949Sbapt	    goto loop;
2211234949Sbapt	}
2212268899Sbapt#if defined(YYBTYACC)
2213268899Sbapt	else if (isalpha(cptr[1]) || cptr[1] == '_')
2214268899Sbapt	{
2215268899Sbapt	    char *arg;
2216268899Sbapt	    ++cptr;
2217268899Sbapt	    arg = scan_id();
2218268899Sbapt	    for (i = plhs[nrules]->args - 1; i >= 0; i--)
2219268899Sbapt		if (arg == plhs[nrules]->argnames[i])
2220268899Sbapt		    break;
2221268899Sbapt	    if (i < 0)
2222268899Sbapt		unknown_arg_warning(lineno, "$", arg, line, cptr);
2223268899Sbapt	    tag = (i < 0 ? NULL : plhs[nrules]->argtags[i]);
2224268899Sbapt	    fprintf(f, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 - n);
2225268899Sbapt	    if (tag)
2226268899Sbapt		fprintf(f, ".%s", tag);
2227268899Sbapt	    else if (havetags)
2228268899Sbapt		untyped_arg_warning(lineno, "$", arg);
2229268899Sbapt	    goto loop;
2230268899Sbapt	}
2231268899Sbapt#endif
2232234949Sbapt    }
2233268899Sbapt#if defined(YYBTYACC)
2234268899Sbapt    if (c == '@')
2235268899Sbapt    {
2236268899Sbapt	if (!locations)
2237268899Sbapt	{
2238268899Sbapt	    int l_lineno = lineno;
2239268899Sbapt	    char *l_line = dup_line();
2240268899Sbapt	    char *l_cptr = l_line + (cptr - line);
2241268899Sbapt	    syntax_error(l_lineno, l_line, l_cptr);
2242268899Sbapt	}
2243268899Sbapt	if (cptr[1] == '$')
2244268899Sbapt	{
2245268899Sbapt	    fprintf(f, "yyloc");
2246268899Sbapt	    cptr += 2;
2247268899Sbapt	    goto loop;
2248268899Sbapt	}
2249268899Sbapt	else if (isdigit(UCH(cptr[1])))
2250268899Sbapt	{
2251268899Sbapt	    ++cptr;
2252268899Sbapt	    i = get_number();
2253268899Sbapt	    if (i == 0)
2254268899Sbapt		fprintf(f, "yystack.p_mark[%d]", -n);
2255268899Sbapt	    else if (i > maxoffset)
2256268899Sbapt	    {
2257268899Sbapt		at_warning(lineno, i);
2258268899Sbapt		fprintf(f, "yystack.p_mark[%d]", i - maxoffset);
2259268899Sbapt	    }
2260268899Sbapt	    else if (offsets)
2261268899Sbapt		fprintf(f, "yystack.p_mark[%d]", offsets[i]);
2262268899Sbapt	    goto loop;
2263268899Sbapt	}
2264268899Sbapt    }
2265268899Sbapt#endif
2266234949Sbapt    if (isalpha(c) || c == '_' || c == '$')
2267234949Sbapt    {
2268234949Sbapt	do
2269234949Sbapt	{
2270234949Sbapt	    putc(c, f);
2271234949Sbapt	    c = *++cptr;
2272234949Sbapt	}
2273234949Sbapt	while (isalnum(c) || c == '_' || c == '$');
2274234949Sbapt	goto loop;
2275234949Sbapt    }
2276268899Sbapt    ++cptr;
2277268899Sbapt#if defined(YYBTYACC)
2278268899Sbapt    if (backtrack)
2279268899Sbapt    {
2280268899Sbapt	if (trialaction && c == L_BRAC && depth == 0)
2281268899Sbapt	{
2282268899Sbapt	    ++depth;
2283268899Sbapt	    putc(L_CURL, f);
2284268899Sbapt	    goto loop;
2285268899Sbapt	}
2286268899Sbapt	if (trialaction && c == R_BRAC && depth == 1)
2287268899Sbapt	{
2288268899Sbapt	    --depth;
2289268899Sbapt	    putc(R_CURL, f);
2290268899Sbapt	    c = nextc();
2291268899Sbapt	    if (c == L_BRAC && !haveyyval)
2292268899Sbapt	    {
2293268899Sbapt		goto loop;
2294268899Sbapt	    }
2295268899Sbapt	    if (c == L_CURL && !haveyyval)
2296268899Sbapt	    {
2297268899Sbapt		fprintf(f, "  if (!yytrial)\n");
2298268899Sbapt		if (!lflag)
2299268899Sbapt		    fprintf(f, line_format, lineno, input_file_name);
2300268899Sbapt		trialaction = 0;
2301268899Sbapt		goto loop;
2302268899Sbapt	    }
2303268899Sbapt	    fprintf(f, "\nbreak;\n");
2304268899Sbapt	    FREE(a_line);
2305268899Sbapt	    if (maxoffset > 0)
2306268899Sbapt		FREE(offsets);
2307268899Sbapt	    return;
2308268899Sbapt	}
2309268899Sbapt    }
2310268899Sbapt#endif
2311234949Sbapt    putc(c, f);
2312234949Sbapt    switch (c)
2313234949Sbapt    {
2314234949Sbapt    case '\n':
2315234949Sbapt	get_line();
2316234949Sbapt	if (line)
2317234949Sbapt	    goto loop;
2318234949Sbapt	unterminated_action(a_lineno, a_line, a_cptr);
2319234949Sbapt
2320234949Sbapt    case ';':
2321234949Sbapt	if (depth > 0)
2322234949Sbapt	    goto loop;
2323234949Sbapt	fprintf(f, "\nbreak;\n");
2324234949Sbapt	free(a_line);
2325268899Sbapt	if (maxoffset > 0)
2326268899Sbapt	    FREE(offsets);
2327234949Sbapt	return;
2328234949Sbapt
2329268899Sbapt#if defined(YYBTYACC)
2330268899Sbapt    case L_BRAC:
2331268899Sbapt	if (backtrack)
2332268899Sbapt	    ++depth;
2333268899Sbapt	goto loop;
2334268899Sbapt
2335268899Sbapt    case R_BRAC:
2336268899Sbapt	if (backtrack)
2337268899Sbapt	    --depth;
2338268899Sbapt	goto loop;
2339268899Sbapt#endif
2340268899Sbapt
2341234949Sbapt    case L_CURL:
2342234949Sbapt	++depth;
2343234949Sbapt	goto loop;
2344234949Sbapt
2345234949Sbapt    case R_CURL:
2346234949Sbapt	if (--depth > 0)
2347234949Sbapt	    goto loop;
2348268899Sbapt#if defined(YYBTYACC)
2349268899Sbapt	if (backtrack)
2350268899Sbapt	{
2351268899Sbapt	    c = nextc();
2352268899Sbapt	    if (c == L_BRAC && !haveyyval)
2353268899Sbapt	    {
2354268899Sbapt		trialaction = 1;
2355268899Sbapt		goto loop;
2356268899Sbapt	    }
2357268899Sbapt	    if (c == L_CURL && !haveyyval)
2358268899Sbapt	    {
2359268899Sbapt		fprintf(f, "  if (!yytrial)\n");
2360268899Sbapt		if (!lflag)
2361268899Sbapt		    fprintf(f, line_format, lineno, input_file_name);
2362268899Sbapt		goto loop;
2363268899Sbapt	    }
2364268899Sbapt	}
2365268899Sbapt#endif
2366234949Sbapt	fprintf(f, "\nbreak;\n");
2367234949Sbapt	free(a_line);
2368268899Sbapt	if (maxoffset > 0)
2369268899Sbapt	    FREE(offsets);
2370234949Sbapt	return;
2371234949Sbapt
2372234949Sbapt    case '\'':
2373234949Sbapt    case '"':
2374234949Sbapt	{
2375268899Sbapt	    char *s = copy_string(c);
2376268899Sbapt	    fputs(s, f);
2377268899Sbapt	    free(s);
2378268899Sbapt	}
2379268899Sbapt	goto loop;
2380234949Sbapt
2381268899Sbapt    case '/':
2382268899Sbapt	{
2383268899Sbapt	    char *s = copy_comment();
2384268899Sbapt	    fputs(s, f);
2385268899Sbapt	    free(s);
2386268899Sbapt	}
2387268899Sbapt	goto loop;
2388268899Sbapt
2389268899Sbapt    default:
2390268899Sbapt	goto loop;
2391268899Sbapt    }
2392268899Sbapt}
2393268899Sbapt
2394268899Sbapt#if defined(YYBTYACC)
2395268899Sbaptstatic void
2396268899Sbaptcopy_destructor(void)
2397268899Sbapt{
2398268899Sbapt    int c;
2399268899Sbapt    int depth;
2400268899Sbapt    char *tag;
2401268899Sbapt    bucket *bp;
2402268899Sbapt    struct mstring *destructor_text = msnew();
2403268899Sbapt    char *code_text;
2404268899Sbapt    int a_lineno;
2405268899Sbapt    char *a_line;
2406268899Sbapt    char *a_cptr;
2407268899Sbapt
2408268899Sbapt    if (!lflag)
2409268899Sbapt	msprintf(destructor_text, line_format, lineno, input_file_name);
2410268899Sbapt
2411268899Sbapt    cptr = after_blanks(cptr);
2412268899Sbapt    if (*cptr == L_CURL)
2413268899Sbapt	/* avoid putting curly-braces in first column, to ease editing */
2414268899Sbapt	mputc(destructor_text, '\t');
2415268899Sbapt    else
2416268899Sbapt	syntax_error(lineno, line, cptr);
2417268899Sbapt
2418268899Sbapt    a_lineno = lineno;
2419268899Sbapt    a_line = dup_line();
2420268899Sbapt    a_cptr = a_line + (cptr - line);
2421268899Sbapt
2422268899Sbapt    depth = 0;
2423268899Sbapt  loop:
2424268899Sbapt    c = *cptr;
2425268899Sbapt    if (c == '$')
2426268899Sbapt    {
2427268899Sbapt	if (cptr[1] == '<')
2428268899Sbapt	{
2429268899Sbapt	    int d_lineno = lineno;
2430268899Sbapt	    char *d_line = dup_line();
2431268899Sbapt	    char *d_cptr = d_line + (cptr - line);
2432268899Sbapt
2433268899Sbapt	    ++cptr;
2434268899Sbapt	    tag = get_tag();
2435268899Sbapt	    c = *cptr;
2436268899Sbapt	    if (c == '$')
2437234949Sbapt	    {
2438268899Sbapt		msprintf(destructor_text, "(*val).%s", tag);
2439268899Sbapt		++cptr;
2440268899Sbapt		FREE(d_line);
2441268899Sbapt		goto loop;
2442268899Sbapt	    }
2443268899Sbapt	    else
2444268899Sbapt		dollar_error(d_lineno, d_line, d_cptr);
2445268899Sbapt	}
2446268899Sbapt	else if (cptr[1] == '$')
2447268899Sbapt	{
2448268899Sbapt	    /* process '$$' later; replacement is context dependent */
2449268899Sbapt	    msprintf(destructor_text, "$$");
2450268899Sbapt	    cptr += 2;
2451268899Sbapt	    goto loop;
2452268899Sbapt	}
2453268899Sbapt    }
2454268899Sbapt    if (c == '@' && cptr[1] == '$')
2455268899Sbapt    {
2456268899Sbapt	if (!locations)
2457268899Sbapt	{
2458268899Sbapt	    int l_lineno = lineno;
2459268899Sbapt	    char *l_line = dup_line();
2460268899Sbapt	    char *l_cptr = l_line + (cptr - line);
2461268899Sbapt	    syntax_error(l_lineno, l_line, l_cptr);
2462268899Sbapt	}
2463268899Sbapt	msprintf(destructor_text, "(*loc)");
2464268899Sbapt	cptr += 2;
2465268899Sbapt	goto loop;
2466268899Sbapt    }
2467268899Sbapt    if (isalpha(c) || c == '_' || c == '$')
2468268899Sbapt    {
2469268899Sbapt	do
2470268899Sbapt	{
2471268899Sbapt	    mputc(destructor_text, c);
2472268899Sbapt	    c = *++cptr;
2473268899Sbapt	}
2474268899Sbapt	while (isalnum(c) || c == '_' || c == '$');
2475268899Sbapt	goto loop;
2476268899Sbapt    }
2477268899Sbapt    ++cptr;
2478268899Sbapt    mputc(destructor_text, c);
2479268899Sbapt    switch (c)
2480268899Sbapt    {
2481268899Sbapt    case '\n':
2482268899Sbapt	get_line();
2483268899Sbapt	if (line)
2484268899Sbapt	    goto loop;
2485268899Sbapt	unterminated_action(a_lineno, a_line, a_cptr);
2486268899Sbapt
2487268899Sbapt    case L_CURL:
2488268899Sbapt	++depth;
2489268899Sbapt	goto loop;
2490268899Sbapt
2491268899Sbapt    case R_CURL:
2492268899Sbapt	if (--depth > 0)
2493268899Sbapt	    goto loop;
2494268899Sbapt	goto process_symbols;
2495268899Sbapt
2496268899Sbapt    case '\'':
2497268899Sbapt    case '"':
2498268899Sbapt	{
2499268899Sbapt	    char *s = copy_string(c);
2500268899Sbapt	    msprintf(destructor_text, "%s", s);
2501268899Sbapt	    free(s);
2502268899Sbapt	}
2503268899Sbapt	goto loop;
2504268899Sbapt
2505268899Sbapt    case '/':
2506268899Sbapt	{
2507268899Sbapt	    char *s = copy_comment();
2508268899Sbapt	    msprintf(destructor_text, "%s", s);
2509268899Sbapt	    free(s);
2510268899Sbapt	}
2511268899Sbapt	goto loop;
2512268899Sbapt
2513268899Sbapt    default:
2514268899Sbapt	goto loop;
2515268899Sbapt    }
2516268899Sbapt  process_symbols:
2517268899Sbapt    code_text = msdone(destructor_text);
2518268899Sbapt    for (;;)
2519268899Sbapt    {
2520268899Sbapt	c = nextc();
2521268899Sbapt	if (c == EOF)
2522268899Sbapt	    unexpected_EOF();
2523268899Sbapt	if (c == '<')
2524268899Sbapt	{
2525268899Sbapt	    if (cptr[1] == '>')
2526268899Sbapt	    {			/* "no semantic type" default destructor */
2527268899Sbapt		cptr += 2;
2528268899Sbapt		if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL)
2529234949Sbapt		{
2530268899Sbapt		    static char untyped_default[] = "<>";
2531268899Sbapt		    bp = make_bucket("untyped default");
2532268899Sbapt		    bp->tag = untyped_default;
2533268899Sbapt		    default_destructor[UNTYPED_DEFAULT] = bp;
2534234949Sbapt		}
2535268899Sbapt		if (bp->destructor != NULL)
2536268899Sbapt		    destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2537268899Sbapt		else
2538268899Sbapt		    /* replace "$$" with "(*val)" in destructor code */
2539268899Sbapt		    bp->destructor = process_destructor_XX(code_text, NULL);
2540268899Sbapt	    }
2541268899Sbapt	    else if (cptr[1] == '*' && cptr[2] == '>')
2542268899Sbapt	    {			/* "no per-symbol or per-type" default destructor */
2543268899Sbapt		cptr += 3;
2544268899Sbapt		if ((bp = default_destructor[TYPED_DEFAULT]) == NULL)
2545234949Sbapt		{
2546268899Sbapt		    static char typed_default[] = "<*>";
2547268899Sbapt		    bp = make_bucket("typed default");
2548268899Sbapt		    bp->tag = typed_default;
2549268899Sbapt		    default_destructor[TYPED_DEFAULT] = bp;
2550234949Sbapt		}
2551268899Sbapt		if (bp->destructor != NULL)
2552268899Sbapt		    destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2553268899Sbapt		else
2554268899Sbapt		{
2555268899Sbapt		    /* postpone re-processing destructor $$s until end of grammar spec */
2556268899Sbapt		    bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2557268899Sbapt		    NO_SPACE(bp->destructor);
2558268899Sbapt		    strcpy(bp->destructor, code_text);
2559268899Sbapt		}
2560234949Sbapt	    }
2561268899Sbapt	    else
2562268899Sbapt	    {			/* "semantic type" default destructor */
2563268899Sbapt		tag = get_tag();
2564268899Sbapt		bp = lookup_type_destructor(tag);
2565268899Sbapt		if (bp->destructor != NULL)
2566268899Sbapt		    destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2567268899Sbapt		else
2568268899Sbapt		    /* replace "$$" with "(*val).tag" in destructor code */
2569268899Sbapt		    bp->destructor = process_destructor_XX(code_text, tag);
2570268899Sbapt	    }
2571234949Sbapt	}
2572268899Sbapt	else if (isalpha(c) || c == '_' || c == '.' || c == '$')
2573268899Sbapt	{			/* "symbol" destructor */
2574268899Sbapt	    bp = get_name();
2575268899Sbapt	    if (bp->destructor != NULL)
2576268899Sbapt		destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2577268899Sbapt	    else
2578268899Sbapt	    {
2579268899Sbapt		/* postpone re-processing destructor $$s until end of grammar spec */
2580268899Sbapt		bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2581268899Sbapt		NO_SPACE(bp->destructor);
2582268899Sbapt		strcpy(bp->destructor, code_text);
2583268899Sbapt	    }
2584268899Sbapt	}
2585268899Sbapt	else
2586268899Sbapt	    break;
2587268899Sbapt    }
2588268899Sbapt    free(a_line);
2589268899Sbapt    free(code_text);
2590268899Sbapt}
2591234949Sbapt
2592268899Sbaptstatic char *
2593268899Sbaptprocess_destructor_XX(char *code, char *tag)
2594268899Sbapt{
2595268899Sbapt    int c;
2596268899Sbapt    int quote;
2597268899Sbapt    int depth;
2598268899Sbapt    struct mstring *new_code = msnew();
2599268899Sbapt    char *codeptr = code;
2600268899Sbapt
2601268899Sbapt    depth = 0;
2602268899Sbapt  loop:			/* step thru code */
2603268899Sbapt    c = *codeptr;
2604268899Sbapt    if (c == '$' && codeptr[1] == '$')
2605268899Sbapt    {
2606268899Sbapt	codeptr += 2;
2607268899Sbapt	if (tag == NULL)
2608268899Sbapt	    msprintf(new_code, "(*val)");
2609268899Sbapt	else
2610268899Sbapt	    msprintf(new_code, "(*val).%s", tag);
2611268899Sbapt	goto loop;
2612268899Sbapt    }
2613268899Sbapt    if (isalpha(c) || c == '_' || c == '$')
2614268899Sbapt    {
2615268899Sbapt	do
2616234949Sbapt	{
2617268899Sbapt	    mputc(new_code, c);
2618268899Sbapt	    c = *++codeptr;
2619268899Sbapt	}
2620268899Sbapt	while (isalnum(c) || c == '_' || c == '$');
2621268899Sbapt	goto loop;
2622268899Sbapt    }
2623268899Sbapt    ++codeptr;
2624268899Sbapt    mputc(new_code, c);
2625268899Sbapt    switch (c)
2626268899Sbapt    {
2627268899Sbapt    case L_CURL:
2628268899Sbapt	++depth;
2629268899Sbapt	goto loop;
2630268899Sbapt
2631268899Sbapt    case R_CURL:
2632268899Sbapt	if (--depth > 0)
2633268899Sbapt	    goto loop;
2634268899Sbapt	return msdone(new_code);
2635268899Sbapt
2636268899Sbapt    case '\'':
2637268899Sbapt    case '"':
2638268899Sbapt	quote = c;
2639268899Sbapt	for (;;)
2640268899Sbapt	{
2641268899Sbapt	    c = *codeptr++;
2642268899Sbapt	    mputc(new_code, c);
2643268899Sbapt	    if (c == quote)
2644268899Sbapt		goto loop;
2645268899Sbapt	    if (c == '\\')
2646234949Sbapt	    {
2647268899Sbapt		c = *codeptr++;
2648268899Sbapt		mputc(new_code, c);
2649234949Sbapt	    }
2650234949Sbapt	}
2651268899Sbapt
2652268899Sbapt    case '/':
2653268899Sbapt	c = *codeptr;
2654234949Sbapt	if (c == '*')
2655234949Sbapt	{
2656268899Sbapt	    mputc(new_code, c);
2657268899Sbapt	    ++codeptr;
2658234949Sbapt	    for (;;)
2659234949Sbapt	    {
2660268899Sbapt		c = *codeptr++;
2661268899Sbapt		mputc(new_code, c);
2662268899Sbapt		if (c == '*' && *codeptr == '/')
2663234949Sbapt		{
2664268899Sbapt		    mputc(new_code, '/');
2665268899Sbapt		    ++codeptr;
2666234949Sbapt		    goto loop;
2667234949Sbapt		}
2668234949Sbapt	    }
2669234949Sbapt	}
2670234949Sbapt	goto loop;
2671234949Sbapt
2672234949Sbapt    default:
2673234949Sbapt	goto loop;
2674234949Sbapt    }
2675234949Sbapt}
2676268899Sbapt#endif /* defined(YYBTYACC) */
2677234949Sbapt
2678234949Sbaptstatic int
2679234949Sbaptmark_symbol(void)
2680234949Sbapt{
2681234949Sbapt    int c;
2682240517Sbapt    bucket *bp = NULL;
2683234949Sbapt
2684234949Sbapt    c = cptr[1];
2685234949Sbapt    if (c == '%' || c == '\\')
2686234949Sbapt    {
2687234949Sbapt	cptr += 2;
2688234949Sbapt	return (1);
2689234949Sbapt    }
2690234949Sbapt
2691234949Sbapt    if (c == '=')
2692234949Sbapt	cptr += 2;
2693234949Sbapt    else if ((c == 'p' || c == 'P') &&
2694234949Sbapt	     ((c = cptr[2]) == 'r' || c == 'R') &&
2695234949Sbapt	     ((c = cptr[3]) == 'e' || c == 'E') &&
2696234949Sbapt	     ((c = cptr[4]) == 'c' || c == 'C') &&
2697234949Sbapt	     ((c = cptr[5], !IS_IDENT(c))))
2698234949Sbapt	cptr += 5;
2699234949Sbapt    else
2700234949Sbapt	syntax_error(lineno, line, cptr);
2701234949Sbapt
2702234949Sbapt    c = nextc();
2703234949Sbapt    if (isalpha(c) || c == '_' || c == '.' || c == '$')
2704234949Sbapt	bp = get_name();
2705234949Sbapt    else if (c == '\'' || c == '"')
2706234949Sbapt	bp = get_literal();
2707234949Sbapt    else
2708234949Sbapt    {
2709234949Sbapt	syntax_error(lineno, line, cptr);
2710234949Sbapt    }
2711234949Sbapt
2712234949Sbapt    if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
2713234949Sbapt	prec_redeclared();
2714234949Sbapt
2715234949Sbapt    rprec[nrules] = bp->prec;
2716234949Sbapt    rassoc[nrules] = bp->assoc;
2717234949Sbapt    return (0);
2718234949Sbapt}
2719234949Sbapt
2720234949Sbaptstatic void
2721234949Sbaptread_grammar(void)
2722234949Sbapt{
2723234949Sbapt    int c;
2724234949Sbapt
2725234949Sbapt    initialize_grammar();
2726234949Sbapt    advance_to_start();
2727234949Sbapt
2728234949Sbapt    for (;;)
2729234949Sbapt    {
2730234949Sbapt	c = nextc();
2731234949Sbapt	if (c == EOF)
2732234949Sbapt	    break;
2733234949Sbapt	if (isalpha(c)
2734234949Sbapt	    || c == '_'
2735234949Sbapt	    || c == '.'
2736234949Sbapt	    || c == '$'
2737234949Sbapt	    || c == '\''
2738234949Sbapt	    || c == '"')
2739234949Sbapt	    add_symbol();
2740268899Sbapt#if defined(YYBTYACC)
2741268899Sbapt	else if (c == L_CURL || c == '=' || (backtrack && c == L_BRAC))
2742268899Sbapt#else
2743234949Sbapt	else if (c == L_CURL || c == '=')
2744268899Sbapt#endif
2745234949Sbapt	    copy_action();
2746234949Sbapt	else if (c == '|')
2747234949Sbapt	{
2748234949Sbapt	    end_rule();
2749234949Sbapt	    start_rule(plhs[nrules - 1], 0);
2750234949Sbapt	    ++cptr;
2751234949Sbapt	}
2752234949Sbapt	else if (c == '%')
2753234949Sbapt	{
2754234949Sbapt	    if (mark_symbol())
2755234949Sbapt		break;
2756234949Sbapt	}
2757234949Sbapt	else
2758234949Sbapt	    syntax_error(lineno, line, cptr);
2759234949Sbapt    }
2760234949Sbapt    end_rule();
2761268899Sbapt#if defined(YYBTYACC)
2762268899Sbapt    if (goal->args > 0)
2763268899Sbapt	start_requires_args(goal->name);
2764268899Sbapt#endif
2765234949Sbapt}
2766234949Sbapt
2767234949Sbaptstatic void
2768234949Sbaptfree_tags(void)
2769234949Sbapt{
2770234949Sbapt    int i;
2771234949Sbapt
2772234949Sbapt    if (tag_table == 0)
2773234949Sbapt	return;
2774234949Sbapt
2775234949Sbapt    for (i = 0; i < ntags; ++i)
2776234949Sbapt    {
2777234949Sbapt	assert(tag_table[i]);
2778234949Sbapt	FREE(tag_table[i]);
2779234949Sbapt    }
2780234949Sbapt    FREE(tag_table);
2781234949Sbapt}
2782234949Sbapt
2783234949Sbaptstatic void
2784234949Sbaptpack_names(void)
2785234949Sbapt{
2786234949Sbapt    bucket *bp;
2787234949Sbapt    char *p, *s, *t;
2788234949Sbapt
2789234949Sbapt    name_pool_size = 13;	/* 13 == sizeof("$end") + sizeof("$accept") */
2790234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
2791234949Sbapt	name_pool_size += strlen(bp->name) + 1;
2792234949Sbapt
2793240517Sbapt    name_pool = TMALLOC(char, name_pool_size);
2794234949Sbapt    NO_SPACE(name_pool);
2795234949Sbapt
2796234949Sbapt    strcpy(name_pool, "$accept");
2797234949Sbapt    strcpy(name_pool + 8, "$end");
2798234949Sbapt    t = name_pool + 13;
2799234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
2800234949Sbapt    {
2801234949Sbapt	p = t;
2802234949Sbapt	s = bp->name;
2803234949Sbapt	while ((*t++ = *s++) != 0)
2804234949Sbapt	    continue;
2805234949Sbapt	FREE(bp->name);
2806234949Sbapt	bp->name = p;
2807234949Sbapt    }
2808234949Sbapt}
2809234949Sbapt
2810234949Sbaptstatic void
2811234949Sbaptcheck_symbols(void)
2812234949Sbapt{
2813234949Sbapt    bucket *bp;
2814234949Sbapt
2815234949Sbapt    if (goal->class == UNKNOWN)
2816234949Sbapt	undefined_goal(goal->name);
2817234949Sbapt
2818234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
2819234949Sbapt    {
2820234949Sbapt	if (bp->class == UNKNOWN)
2821234949Sbapt	{
2822234949Sbapt	    undefined_symbol_warning(bp->name);
2823234949Sbapt	    bp->class = TERM;
2824234949Sbapt	}
2825234949Sbapt    }
2826234949Sbapt}
2827234949Sbapt
2828234949Sbaptstatic void
2829234949Sbaptprotect_string(char *src, char **des)
2830234949Sbapt{
2831234949Sbapt    unsigned len;
2832234949Sbapt    char *s;
2833234949Sbapt    char *d;
2834234949Sbapt
2835234949Sbapt    *des = src;
2836234949Sbapt    if (src)
2837234949Sbapt    {
2838234949Sbapt	len = 1;
2839234949Sbapt	s = src;
2840234949Sbapt	while (*s)
2841234949Sbapt	{
2842234949Sbapt	    if ('\\' == *s || '"' == *s)
2843234949Sbapt		len++;
2844234949Sbapt	    s++;
2845234949Sbapt	    len++;
2846234949Sbapt	}
2847234949Sbapt
2848240517Sbapt	*des = d = TMALLOC(char, len);
2849234949Sbapt	NO_SPACE(d);
2850234949Sbapt
2851234949Sbapt	s = src;
2852234949Sbapt	while (*s)
2853234949Sbapt	{
2854234949Sbapt	    if ('\\' == *s || '"' == *s)
2855234949Sbapt		*d++ = '\\';
2856234949Sbapt	    *d++ = *s++;
2857234949Sbapt	}
2858234949Sbapt	*d = '\0';
2859234949Sbapt    }
2860234949Sbapt}
2861234949Sbapt
2862234949Sbaptstatic void
2863234949Sbaptpack_symbols(void)
2864234949Sbapt{
2865234949Sbapt    bucket *bp;
2866234949Sbapt    bucket **v;
2867234949Sbapt    Value_t i, j, k, n;
2868268899Sbapt#if defined(YYBTYACC)
2869268899Sbapt    Value_t max_tok_pval;
2870268899Sbapt#endif
2871234949Sbapt
2872234949Sbapt    nsyms = 2;
2873234949Sbapt    ntokens = 1;
2874234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
2875234949Sbapt    {
2876234949Sbapt	++nsyms;
2877234949Sbapt	if (bp->class == TERM)
2878234949Sbapt	    ++ntokens;
2879234949Sbapt    }
2880234949Sbapt    start_symbol = (Value_t) ntokens;
2881268899Sbapt    nvars = (Value_t) (nsyms - ntokens);
2882234949Sbapt
2883240517Sbapt    symbol_name = TMALLOC(char *, nsyms);
2884234949Sbapt    NO_SPACE(symbol_name);
2885234949Sbapt
2886240517Sbapt    symbol_value = TMALLOC(Value_t, nsyms);
2887234949Sbapt    NO_SPACE(symbol_value);
2888234949Sbapt
2889268899Sbapt    symbol_prec = TMALLOC(Value_t, nsyms);
2890234949Sbapt    NO_SPACE(symbol_prec);
2891234949Sbapt
2892240517Sbapt    symbol_assoc = TMALLOC(char, nsyms);
2893234949Sbapt    NO_SPACE(symbol_assoc);
2894234949Sbapt
2895268899Sbapt#if defined(YYBTYACC)
2896268899Sbapt    symbol_pval = TMALLOC(Value_t, nsyms);
2897268899Sbapt    NO_SPACE(symbol_pval);
2898268899Sbapt
2899268899Sbapt    if (destructor)
2900268899Sbapt    {
2901268899Sbapt	symbol_destructor = CALLOC(sizeof(char *), nsyms);
2902268899Sbapt	NO_SPACE(symbol_destructor);
2903268899Sbapt
2904268899Sbapt	symbol_type_tag = CALLOC(sizeof(char *), nsyms);
2905268899Sbapt	NO_SPACE(symbol_type_tag);
2906268899Sbapt    }
2907268899Sbapt#endif
2908268899Sbapt
2909240517Sbapt    v = TMALLOC(bucket *, nsyms);
2910234949Sbapt    NO_SPACE(v);
2911234949Sbapt
2912234949Sbapt    v[0] = 0;
2913234949Sbapt    v[start_symbol] = 0;
2914234949Sbapt
2915234949Sbapt    i = 1;
2916234949Sbapt    j = (Value_t) (start_symbol + 1);
2917234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
2918234949Sbapt    {
2919234949Sbapt	if (bp->class == TERM)
2920234949Sbapt	    v[i++] = bp;
2921234949Sbapt	else
2922234949Sbapt	    v[j++] = bp;
2923234949Sbapt    }
2924234949Sbapt    assert(i == ntokens && j == nsyms);
2925234949Sbapt
2926234949Sbapt    for (i = 1; i < ntokens; ++i)
2927234949Sbapt	v[i]->index = i;
2928234949Sbapt
2929234949Sbapt    goal->index = (Index_t) (start_symbol + 1);
2930234949Sbapt    k = (Value_t) (start_symbol + 2);
2931234949Sbapt    while (++i < nsyms)
2932234949Sbapt	if (v[i] != goal)
2933234949Sbapt	{
2934234949Sbapt	    v[i]->index = k;
2935234949Sbapt	    ++k;
2936234949Sbapt	}
2937234949Sbapt
2938234949Sbapt    goal->value = 0;
2939234949Sbapt    k = 1;
2940234949Sbapt    for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
2941234949Sbapt    {
2942234949Sbapt	if (v[i] != goal)
2943234949Sbapt	{
2944234949Sbapt	    v[i]->value = k;
2945234949Sbapt	    ++k;
2946234949Sbapt	}
2947234949Sbapt    }
2948234949Sbapt
2949234949Sbapt    k = 0;
2950234949Sbapt    for (i = 1; i < ntokens; ++i)
2951234949Sbapt    {
2952234949Sbapt	n = v[i]->value;
2953234949Sbapt	if (n > 256)
2954234949Sbapt	{
2955234949Sbapt	    for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
2956234949Sbapt		symbol_value[j] = symbol_value[j - 1];
2957234949Sbapt	    symbol_value[j] = n;
2958234949Sbapt	}
2959234949Sbapt    }
2960234949Sbapt
2961234949Sbapt    assert(v[1] != 0);
2962234949Sbapt
2963234949Sbapt    if (v[1]->value == UNDEFINED)
2964234949Sbapt	v[1]->value = 256;
2965234949Sbapt
2966234949Sbapt    j = 0;
2967234949Sbapt    n = 257;
2968234949Sbapt    for (i = 2; i < ntokens; ++i)
2969234949Sbapt    {
2970234949Sbapt	if (v[i]->value == UNDEFINED)
2971234949Sbapt	{
2972234949Sbapt	    while (j < k && n == symbol_value[j])
2973234949Sbapt	    {
2974234949Sbapt		while (++j < k && n == symbol_value[j])
2975234949Sbapt		    continue;
2976234949Sbapt		++n;
2977234949Sbapt	    }
2978234949Sbapt	    v[i]->value = n;
2979234949Sbapt	    ++n;
2980234949Sbapt	}
2981234949Sbapt    }
2982234949Sbapt
2983234949Sbapt    symbol_name[0] = name_pool + 8;
2984234949Sbapt    symbol_value[0] = 0;
2985234949Sbapt    symbol_prec[0] = 0;
2986234949Sbapt    symbol_assoc[0] = TOKEN;
2987268899Sbapt#if defined(YYBTYACC)
2988268899Sbapt    symbol_pval[0] = 0;
2989268899Sbapt    max_tok_pval = 0;
2990268899Sbapt#endif
2991234949Sbapt    for (i = 1; i < ntokens; ++i)
2992234949Sbapt    {
2993234949Sbapt	symbol_name[i] = v[i]->name;
2994234949Sbapt	symbol_value[i] = v[i]->value;
2995234949Sbapt	symbol_prec[i] = v[i]->prec;
2996234949Sbapt	symbol_assoc[i] = v[i]->assoc;
2997268899Sbapt#if defined(YYBTYACC)
2998268899Sbapt	symbol_pval[i] = v[i]->value;
2999268899Sbapt	if (symbol_pval[i] > max_tok_pval)
3000268899Sbapt	    max_tok_pval = symbol_pval[i];
3001268899Sbapt	if (destructor)
3002268899Sbapt	{
3003268899Sbapt	    symbol_destructor[i] = v[i]->destructor;
3004268899Sbapt	    symbol_type_tag[i] = v[i]->tag;
3005268899Sbapt	}
3006268899Sbapt#endif
3007234949Sbapt    }
3008234949Sbapt    symbol_name[start_symbol] = name_pool;
3009234949Sbapt    symbol_value[start_symbol] = -1;
3010234949Sbapt    symbol_prec[start_symbol] = 0;
3011234949Sbapt    symbol_assoc[start_symbol] = TOKEN;
3012268899Sbapt#if defined(YYBTYACC)
3013268899Sbapt    symbol_pval[start_symbol] = (Value_t) (max_tok_pval + 1);
3014268899Sbapt#endif
3015234949Sbapt    for (++i; i < nsyms; ++i)
3016234949Sbapt    {
3017234949Sbapt	k = v[i]->index;
3018234949Sbapt	symbol_name[k] = v[i]->name;
3019234949Sbapt	symbol_value[k] = v[i]->value;
3020234949Sbapt	symbol_prec[k] = v[i]->prec;
3021234949Sbapt	symbol_assoc[k] = v[i]->assoc;
3022268899Sbapt#if defined(YYBTYACC)
3023268899Sbapt	symbol_pval[k] = (Value_t) ((max_tok_pval + 1) + v[i]->value + 1);
3024268899Sbapt	if (destructor)
3025268899Sbapt	{
3026268899Sbapt	    symbol_destructor[k] = v[i]->destructor;
3027268899Sbapt	    symbol_type_tag[k] = v[i]->tag;
3028268899Sbapt	}
3029268899Sbapt#endif
3030234949Sbapt    }
3031234949Sbapt
3032234949Sbapt    if (gflag)
3033234949Sbapt    {
3034240517Sbapt	symbol_pname = TMALLOC(char *, nsyms);
3035234949Sbapt	NO_SPACE(symbol_pname);
3036234949Sbapt
3037234949Sbapt	for (i = 0; i < nsyms; ++i)
3038234949Sbapt	    protect_string(symbol_name[i], &(symbol_pname[i]));
3039234949Sbapt    }
3040234949Sbapt
3041234949Sbapt    FREE(v);
3042234949Sbapt}
3043234949Sbapt
3044234949Sbaptstatic void
3045234949Sbaptpack_grammar(void)
3046234949Sbapt{
3047234949Sbapt    int i;
3048234949Sbapt    Value_t j;
3049234949Sbapt    Assoc_t assoc;
3050234949Sbapt    Value_t prec2;
3051234949Sbapt
3052240517Sbapt    ritem = TMALLOC(Value_t, nitems);
3053234949Sbapt    NO_SPACE(ritem);
3054234949Sbapt
3055240517Sbapt    rlhs = TMALLOC(Value_t, nrules);
3056234949Sbapt    NO_SPACE(rlhs);
3057234949Sbapt
3058240517Sbapt    rrhs = TMALLOC(Value_t, nrules + 1);
3059234949Sbapt    NO_SPACE(rrhs);
3060234949Sbapt
3061240517Sbapt    rprec = TREALLOC(Value_t, rprec, nrules);
3062234949Sbapt    NO_SPACE(rprec);
3063234949Sbapt
3064240517Sbapt    rassoc = TREALLOC(Assoc_t, rassoc, nrules);
3065234949Sbapt    NO_SPACE(rassoc);
3066234949Sbapt
3067234949Sbapt    ritem[0] = -1;
3068234949Sbapt    ritem[1] = goal->index;
3069234949Sbapt    ritem[2] = 0;
3070234949Sbapt    ritem[3] = -2;
3071234949Sbapt    rlhs[0] = 0;
3072234949Sbapt    rlhs[1] = 0;
3073234949Sbapt    rlhs[2] = start_symbol;
3074234949Sbapt    rrhs[0] = 0;
3075234949Sbapt    rrhs[1] = 0;
3076234949Sbapt    rrhs[2] = 1;
3077234949Sbapt
3078234949Sbapt    j = 4;
3079234949Sbapt    for (i = 3; i < nrules; ++i)
3080234949Sbapt    {
3081268899Sbapt#if defined(YYBTYACC)
3082268899Sbapt	if (plhs[i]->args > 0)
3083268899Sbapt	{
3084268899Sbapt	    if (plhs[i]->argnames)
3085268899Sbapt	    {
3086268899Sbapt		FREE(plhs[i]->argnames);
3087268899Sbapt		plhs[i]->argnames = NULL;
3088268899Sbapt	    }
3089268899Sbapt	    if (plhs[i]->argtags)
3090268899Sbapt	    {
3091268899Sbapt		FREE(plhs[i]->argtags);
3092268899Sbapt		plhs[i]->argtags = NULL;
3093268899Sbapt	    }
3094268899Sbapt	}
3095268899Sbapt#endif /* defined(YYBTYACC) */
3096234949Sbapt	rlhs[i] = plhs[i]->index;
3097234949Sbapt	rrhs[i] = j;
3098234949Sbapt	assoc = TOKEN;
3099234949Sbapt	prec2 = 0;
3100234949Sbapt	while (pitem[j])
3101234949Sbapt	{
3102234949Sbapt	    ritem[j] = pitem[j]->index;
3103234949Sbapt	    if (pitem[j]->class == TERM)
3104234949Sbapt	    {
3105234949Sbapt		prec2 = pitem[j]->prec;
3106234949Sbapt		assoc = pitem[j]->assoc;
3107234949Sbapt	    }
3108234949Sbapt	    ++j;
3109234949Sbapt	}
3110234949Sbapt	ritem[j] = (Value_t) - i;
3111234949Sbapt	++j;
3112234949Sbapt	if (rprec[i] == UNDEFINED)
3113234949Sbapt	{
3114234949Sbapt	    rprec[i] = prec2;
3115234949Sbapt	    rassoc[i] = assoc;
3116234949Sbapt	}
3117234949Sbapt    }
3118234949Sbapt    rrhs[i] = j;
3119234949Sbapt
3120234949Sbapt    FREE(plhs);
3121234949Sbapt    FREE(pitem);
3122268899Sbapt#if defined(YYBTYACC)
3123268899Sbapt    clean_arg_cache();
3124268899Sbapt#endif
3125234949Sbapt}
3126234949Sbapt
3127234949Sbaptstatic void
3128234949Sbaptprint_grammar(void)
3129234949Sbapt{
3130234949Sbapt    int i, k;
3131234949Sbapt    size_t j, spacing = 0;
3132234949Sbapt    FILE *f = verbose_file;
3133234949Sbapt
3134234949Sbapt    if (!vflag)
3135234949Sbapt	return;
3136234949Sbapt
3137234949Sbapt    k = 1;
3138234949Sbapt    for (i = 2; i < nrules; ++i)
3139234949Sbapt    {
3140234949Sbapt	if (rlhs[i] != rlhs[i - 1])
3141234949Sbapt	{
3142234949Sbapt	    if (i != 2)
3143234949Sbapt		fprintf(f, "\n");
3144234949Sbapt	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
3145234949Sbapt	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
3146234949Sbapt	}
3147234949Sbapt	else
3148234949Sbapt	{
3149234949Sbapt	    fprintf(f, "%4d  ", i - 2);
3150234949Sbapt	    j = spacing;
3151234949Sbapt	    while (j-- != 0)
3152234949Sbapt		putc(' ', f);
3153234949Sbapt	    putc('|', f);
3154234949Sbapt	}
3155234949Sbapt
3156234949Sbapt	while (ritem[k] >= 0)
3157234949Sbapt	{
3158234949Sbapt	    fprintf(f, " %s", symbol_name[ritem[k]]);
3159234949Sbapt	    ++k;
3160234949Sbapt	}
3161234949Sbapt	++k;
3162234949Sbapt	putc('\n', f);
3163234949Sbapt    }
3164234949Sbapt}
3165234949Sbapt
3166268899Sbapt#if defined(YYBTYACC)
3167268899Sbaptstatic void
3168268899Sbaptfinalize_destructors(void)
3169268899Sbapt{
3170268899Sbapt    int i;
3171268899Sbapt    bucket *bp;
3172268899Sbapt    char *tag;
3173268899Sbapt
3174268899Sbapt    for (i = 2; i < nsyms; ++i)
3175268899Sbapt    {
3176268899Sbapt	tag = symbol_type_tag[i];
3177268899Sbapt	if (symbol_destructor[i] == NULL)
3178268899Sbapt	{
3179268899Sbapt	    if (tag == NULL)
3180268899Sbapt	    {			/* use <> destructor, if there is one */
3181268899Sbapt		if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3182268899Sbapt		{
3183268899Sbapt		    symbol_destructor[i] = TMALLOC(char,
3184268899Sbapt						   strlen(bp->destructor) + 1);
3185268899Sbapt		    NO_SPACE(symbol_destructor[i]);
3186268899Sbapt		    strcpy(symbol_destructor[i], bp->destructor);
3187268899Sbapt		}
3188268899Sbapt	    }
3189268899Sbapt	    else
3190268899Sbapt	    {			/* use type destructor for this tag, if there is one */
3191268899Sbapt		bp = lookup_type_destructor(tag);
3192268899Sbapt		if (bp->destructor != NULL)
3193268899Sbapt		{
3194268899Sbapt		    symbol_destructor[i] = TMALLOC(char,
3195268899Sbapt						   strlen(bp->destructor) + 1);
3196268899Sbapt		    NO_SPACE(symbol_destructor[i]);
3197268899Sbapt		    strcpy(symbol_destructor[i], bp->destructor);
3198268899Sbapt		}
3199268899Sbapt		else
3200268899Sbapt		{		/* use <*> destructor, if there is one */
3201268899Sbapt		    if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3202268899Sbapt			/* replace "$$" with "(*val).tag" in destructor code */
3203268899Sbapt			symbol_destructor[i]
3204268899Sbapt			    = process_destructor_XX(bp->destructor, tag);
3205268899Sbapt		}
3206268899Sbapt	    }
3207268899Sbapt	}
3208268899Sbapt	else
3209268899Sbapt	{			/* replace "$$" with "(*val)[.tag]" in destructor code */
3210268899Sbapt	    symbol_destructor[i]
3211268899Sbapt		= process_destructor_XX(symbol_destructor[i], tag);
3212268899Sbapt	}
3213268899Sbapt    }
3214268899Sbapt    /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */
3215268899Sbapt    DO_FREE(symbol_type_tag);	/* no longer needed */
3216268899Sbapt    if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3217268899Sbapt    {
3218268899Sbapt	FREE(bp->name);
3219268899Sbapt	/* 'bp->tag' is a static value, don't free */
3220268899Sbapt	FREE(bp->destructor);
3221268899Sbapt	FREE(bp);
3222268899Sbapt    }
3223268899Sbapt    if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3224268899Sbapt    {
3225268899Sbapt	FREE(bp->name);
3226268899Sbapt	/* 'bp->tag' is a static value, don't free */
3227268899Sbapt	FREE(bp->destructor);
3228268899Sbapt	FREE(bp);
3229268899Sbapt    }
3230268899Sbapt    if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL)
3231268899Sbapt    {
3232268899Sbapt	bucket *p;
3233268899Sbapt	for (; bp; bp = p)
3234268899Sbapt	{
3235268899Sbapt	    p = bp->link;
3236268899Sbapt	    FREE(bp->name);
3237268899Sbapt	    /* 'bp->tag' freed by 'free_tags()' */
3238268899Sbapt	    FREE(bp->destructor);
3239268899Sbapt	    FREE(bp);
3240268899Sbapt	}
3241268899Sbapt    }
3242268899Sbapt}
3243268899Sbapt#endif /* defined(YYBTYACC) */
3244268899Sbapt
3245234949Sbaptvoid
3246234949Sbaptreader(void)
3247234949Sbapt{
3248234949Sbapt    write_section(code_file, banner);
3249234949Sbapt    create_symbol_table();
3250234949Sbapt    read_declarations();
3251234949Sbapt    read_grammar();
3252234949Sbapt    free_symbol_table();
3253234949Sbapt    pack_names();
3254234949Sbapt    check_symbols();
3255234949Sbapt    pack_symbols();
3256234949Sbapt    pack_grammar();
3257234949Sbapt    free_symbols();
3258234949Sbapt    print_grammar();
3259268899Sbapt#if defined(YYBTYACC)
3260268899Sbapt    if (destructor)
3261268899Sbapt	finalize_destructors();
3262268899Sbapt#endif
3263268899Sbapt    free_tags();
3264234949Sbapt}
3265234949Sbapt
3266234949Sbapt#ifdef NO_LEAKS
3267234949Sbaptstatic param *
3268234949Sbaptfree_declarations(param * list)
3269234949Sbapt{
3270234949Sbapt    while (list != 0)
3271234949Sbapt    {
3272234949Sbapt	param *next = list->next;
3273234949Sbapt	free(list->type);
3274234949Sbapt	free(list->name);
3275234949Sbapt	free(list->type2);
3276234949Sbapt	free(list);
3277234949Sbapt	list = next;
3278234949Sbapt    }
3279234949Sbapt    return list;
3280234949Sbapt}
3281234949Sbapt
3282234949Sbaptvoid
3283234949Sbaptreader_leaks(void)
3284234949Sbapt{
3285234949Sbapt    lex_param = free_declarations(lex_param);
3286234949Sbapt    parse_param = free_declarations(parse_param);
3287234949Sbapt
3288234949Sbapt    DO_FREE(line);
3289234949Sbapt    DO_FREE(rrhs);
3290234949Sbapt    DO_FREE(rlhs);
3291234949Sbapt    DO_FREE(rprec);
3292234949Sbapt    DO_FREE(ritem);
3293234949Sbapt    DO_FREE(rassoc);
3294234949Sbapt    DO_FREE(cache);
3295234949Sbapt    DO_FREE(name_pool);
3296234949Sbapt    DO_FREE(symbol_name);
3297234949Sbapt    DO_FREE(symbol_prec);
3298234949Sbapt    DO_FREE(symbol_assoc);
3299234949Sbapt    DO_FREE(symbol_value);
3300268899Sbapt#if defined(YYBTYACC)
3301268899Sbapt    DO_FREE(symbol_pval);
3302268899Sbapt    DO_FREE(symbol_destructor);
3303268899Sbapt    DO_FREE(symbol_type_tag);
3304268899Sbapt#endif
3305234949Sbapt}
3306234949Sbapt#endif
3307