1272957Srodrigc/* $Id: reader.c,v 1.58 2014/10/06 22:15:08 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{
73272955Srodrigc    const char fmt[] = "%.*s destructor";
74268899Sbapt    char name[1024] = "\0";
75268899Sbapt    bucket *bp, **bpp = &default_destructor[TYPE_SPECIFIED];
76268899Sbapt
77268899Sbapt    while ((bp = *bpp) != NULL)
78268899Sbapt    {
79268899Sbapt	if (bp->tag == tag)
80268899Sbapt	    return (bp);
81268899Sbapt	bpp = &bp->link;
82268899Sbapt    }
83268899Sbapt
84272955Srodrigc    sprintf(name, fmt, (int)(sizeof(name) - sizeof(fmt)), tag);
85272955Srodrigc    *bpp = bp = make_bucket(name);
86268899Sbapt    bp->tag = tag;
87268899Sbapt
88268899Sbapt    return (bp);
89268899Sbapt}
90268899Sbapt#endif /* defined(YYBTYACC) */
91268899Sbapt
92234949Sbaptstatic void
93234949Sbaptcachec(int c)
94234949Sbapt{
95234949Sbapt    assert(cinc >= 0);
96234949Sbapt    if (cinc >= cache_size)
97234949Sbapt    {
98234949Sbapt	cache_size += 256;
99240517Sbapt	cache = TREALLOC(char, cache, cache_size);
100234949Sbapt	NO_SPACE(cache);
101234949Sbapt    }
102234949Sbapt    cache[cinc] = (char)c;
103234949Sbapt    ++cinc;
104234949Sbapt}
105234949Sbapt
106234949Sbaptstatic void
107234949Sbaptget_line(void)
108234949Sbapt{
109234949Sbapt    FILE *f = input_file;
110234949Sbapt    int c;
111234949Sbapt    int i;
112234949Sbapt
113234949Sbapt    if (saw_eof || (c = getc(f)) == EOF)
114234949Sbapt    {
115234949Sbapt	if (line)
116234949Sbapt	{
117234949Sbapt	    FREE(line);
118234949Sbapt	    line = 0;
119234949Sbapt	}
120234949Sbapt	cptr = 0;
121234949Sbapt	saw_eof = 1;
122234949Sbapt	return;
123234949Sbapt    }
124234949Sbapt
125234949Sbapt    if (line == 0 || linesize != (LINESIZE + 1))
126234949Sbapt    {
127234949Sbapt	if (line)
128234949Sbapt	    FREE(line);
129234949Sbapt	linesize = LINESIZE + 1;
130272957Srodrigc	line = TMALLOC(char, linesize);
131234949Sbapt	NO_SPACE(line);
132234949Sbapt    }
133234949Sbapt
134234949Sbapt    i = 0;
135234949Sbapt    ++lineno;
136234949Sbapt    for (;;)
137234949Sbapt    {
138272957Srodrigc	line[i++] = (char)c;
139234949Sbapt	if (c == '\n')
140268899Sbapt	    break;
141272957Srodrigc	if ((i + 3) >= linesize)
142234949Sbapt	{
143234949Sbapt	    linesize += LINESIZE;
144240517Sbapt	    line = TREALLOC(char, line, linesize);
145234949Sbapt	    NO_SPACE(line);
146234949Sbapt	}
147234949Sbapt	c = getc(f);
148234949Sbapt	if (c == EOF)
149234949Sbapt	{
150272957Srodrigc	    line[i++] = '\n';
151234949Sbapt	    saw_eof = 1;
152268899Sbapt	    break;
153234949Sbapt	}
154234949Sbapt    }
155272957Srodrigc    line[i] = '\0';
156268899Sbapt    cptr = line;
157268899Sbapt    return;
158234949Sbapt}
159234949Sbapt
160234949Sbaptstatic char *
161234949Sbaptdup_line(void)
162234949Sbapt{
163234949Sbapt    char *p, *s, *t;
164234949Sbapt
165234949Sbapt    if (line == 0)
166234949Sbapt	return (0);
167234949Sbapt    s = line;
168234949Sbapt    while (*s != '\n')
169234949Sbapt	++s;
170240517Sbapt    p = TMALLOC(char, s - line + 1);
171234949Sbapt    NO_SPACE(p);
172234949Sbapt
173234949Sbapt    s = line;
174234949Sbapt    t = p;
175234949Sbapt    while ((*t++ = *s++) != '\n')
176234949Sbapt	continue;
177234949Sbapt    return (p);
178234949Sbapt}
179234949Sbapt
180234949Sbaptstatic void
181234949Sbaptskip_comment(void)
182234949Sbapt{
183234949Sbapt    char *s;
184234949Sbapt
185234949Sbapt    int st_lineno = lineno;
186234949Sbapt    char *st_line = dup_line();
187234949Sbapt    char *st_cptr = st_line + (cptr - line);
188234949Sbapt
189234949Sbapt    s = cptr + 2;
190234949Sbapt    for (;;)
191234949Sbapt    {
192234949Sbapt	if (*s == '*' && s[1] == '/')
193234949Sbapt	{
194234949Sbapt	    cptr = s + 2;
195234949Sbapt	    FREE(st_line);
196234949Sbapt	    return;
197234949Sbapt	}
198234949Sbapt	if (*s == '\n')
199234949Sbapt	{
200234949Sbapt	    get_line();
201234949Sbapt	    if (line == 0)
202234949Sbapt		unterminated_comment(st_lineno, st_line, st_cptr);
203234949Sbapt	    s = cptr;
204234949Sbapt	}
205234949Sbapt	else
206234949Sbapt	    ++s;
207234949Sbapt    }
208234949Sbapt}
209234949Sbapt
210234949Sbaptstatic int
211272955Srodrigcnext_inline(void)
212234949Sbapt{
213234949Sbapt    char *s;
214234949Sbapt
215234949Sbapt    if (line == 0)
216234949Sbapt    {
217234949Sbapt	get_line();
218234949Sbapt	if (line == 0)
219234949Sbapt	    return (EOF);
220234949Sbapt    }
221234949Sbapt
222234949Sbapt    s = cptr;
223234949Sbapt    for (;;)
224234949Sbapt    {
225234949Sbapt	switch (*s)
226234949Sbapt	{
227234949Sbapt	case '/':
228234949Sbapt	    if (s[1] == '*')
229234949Sbapt	    {
230234949Sbapt		cptr = s;
231234949Sbapt		skip_comment();
232234949Sbapt		s = cptr;
233234949Sbapt		break;
234234949Sbapt	    }
235234949Sbapt	    else if (s[1] == '/')
236234949Sbapt	    {
237234949Sbapt		get_line();
238234949Sbapt		if (line == 0)
239234949Sbapt		    return (EOF);
240234949Sbapt		s = cptr;
241234949Sbapt		break;
242234949Sbapt	    }
243234949Sbapt	    /* FALLTHRU */
244234949Sbapt
245234949Sbapt	default:
246234949Sbapt	    cptr = s;
247234949Sbapt	    return (*s);
248234949Sbapt	}
249234949Sbapt    }
250234949Sbapt}
251272955Srodrigc
252272955Srodrigcstatic int
253272955Srodrigcnextc(void)
254272955Srodrigc{
255272955Srodrigc    int ch;
256272955Srodrigc    int finish = 0;
257272955Srodrigc
258272955Srodrigc    do
259272955Srodrigc    {
260272955Srodrigc	switch (ch = next_inline())
261272955Srodrigc	{
262272955Srodrigc	case '\n':
263272955Srodrigc	    get_line();
264272955Srodrigc	    break;
265272955Srodrigc	case ' ':
266272955Srodrigc	case '\t':
267272955Srodrigc	case '\f':
268272955Srodrigc	case '\r':
269272955Srodrigc	case '\v':
270272955Srodrigc	case ',':
271272955Srodrigc	case ';':
272272955Srodrigc	    ++cptr;
273272955Srodrigc	    break;
274272955Srodrigc	case '\\':
275272955Srodrigc	    ch = '%';
276272955Srodrigc	    /* FALLTHRU */
277272955Srodrigc	default:
278272955Srodrigc	    finish = 1;
279272955Srodrigc	    break;
280272955Srodrigc	}
281272955Srodrigc    }
282272955Srodrigc    while (!finish);
283272955Srodrigc
284272955Srodrigc    return ch;
285272955Srodrigc}
286268899Sbapt/* *INDENT-OFF* */
287268899Sbaptstatic struct keyword
288268899Sbapt{
289268899Sbapt    char name[13];
290268899Sbapt    int token;
291268899Sbapt}
292268899Sbaptkeywords[] = {
293268899Sbapt    { "binary",      NONASSOC },
294268899Sbapt#if defined(YYBTYACC)
295268899Sbapt    { "destructor",  DESTRUCTOR },
296268899Sbapt#endif
297268899Sbapt    { "expect",      EXPECT },
298268899Sbapt    { "expect-rr",   EXPECT_RR },
299268899Sbapt    { "ident",       IDENT },
300268899Sbapt    { "left",        LEFT },
301268899Sbapt    { "lex-param",   LEX_PARAM },
302268899Sbapt#if defined(YYBTYACC)
303268899Sbapt    { "locations",   LOCATIONS },
304268899Sbapt#endif
305268899Sbapt    { "nonassoc",    NONASSOC },
306268899Sbapt    { "parse-param", PARSE_PARAM },
307268899Sbapt    { "pure-parser", PURE_PARSER },
308268899Sbapt    { "right",       RIGHT },
309268899Sbapt    { "start",       START },
310268899Sbapt    { "term",        TOKEN },
311268899Sbapt    { "token",       TOKEN },
312268899Sbapt    { "token-table", TOKEN_TABLE },
313268899Sbapt    { "type",        TYPE },
314268899Sbapt    { "union",       UNION },
315268899Sbapt    { "yacc",        POSIX_YACC },
316268899Sbapt};
317268899Sbapt/* *INDENT-ON* */
318234949Sbapt
319234949Sbaptstatic int
320268899Sbaptcompare_keys(const void *a, const void *b)
321234949Sbapt{
322268899Sbapt    const struct keyword *p = (const struct keyword *)a;
323268899Sbapt    const struct keyword *q = (const struct keyword *)b;
324268899Sbapt    return strcmp(p->name, q->name);
325234949Sbapt}
326234949Sbapt
327234949Sbaptstatic int
328234949Sbaptkeyword(void)
329234949Sbapt{
330234949Sbapt    int c;
331234949Sbapt    char *t_cptr = cptr;
332268899Sbapt    struct keyword *key;
333234949Sbapt
334234949Sbapt    c = *++cptr;
335234949Sbapt    if (isalpha(c))
336234949Sbapt    {
337234949Sbapt	cinc = 0;
338234949Sbapt	for (;;)
339234949Sbapt	{
340234949Sbapt	    if (isalpha(c))
341234949Sbapt	    {
342234949Sbapt		if (isupper(c))
343234949Sbapt		    c = tolower(c);
344234949Sbapt		cachec(c);
345234949Sbapt	    }
346234949Sbapt	    else if (isdigit(c)
347234949Sbapt		     || c == '-'
348234949Sbapt		     || c == '.'
349234949Sbapt		     || c == '$')
350234949Sbapt	    {
351234949Sbapt		cachec(c);
352234949Sbapt	    }
353268899Sbapt	    else if (c == '_')
354268899Sbapt	    {
355268899Sbapt		/* treat keywords spelled with '_' as if it were '-' */
356268899Sbapt		cachec('-');
357268899Sbapt	    }
358234949Sbapt	    else
359234949Sbapt	    {
360234949Sbapt		break;
361234949Sbapt	    }
362234949Sbapt	    c = *++cptr;
363234949Sbapt	}
364234949Sbapt	cachec(NUL);
365234949Sbapt
366268899Sbapt	if ((key = bsearch(cache, keywords,
367268899Sbapt			   sizeof(keywords) / sizeof(*key),
368268899Sbapt			   sizeof(*key), compare_keys)))
369268899Sbapt	    return key->token;
370234949Sbapt    }
371234949Sbapt    else
372234949Sbapt    {
373234949Sbapt	++cptr;
374234949Sbapt	if (c == L_CURL)
375234949Sbapt	    return (TEXT);
376234949Sbapt	if (c == '%' || c == '\\')
377234949Sbapt	    return (MARK);
378234949Sbapt	if (c == '<')
379234949Sbapt	    return (LEFT);
380234949Sbapt	if (c == '>')
381234949Sbapt	    return (RIGHT);
382234949Sbapt	if (c == '0')
383234949Sbapt	    return (TOKEN);
384234949Sbapt	if (c == '2')
385234949Sbapt	    return (NONASSOC);
386234949Sbapt    }
387234949Sbapt    syntax_error(lineno, line, t_cptr);
388235723Sbapt    return (-1);
389234949Sbapt}
390234949Sbapt
391234949Sbaptstatic void
392234949Sbaptcopy_ident(void)
393234949Sbapt{
394234949Sbapt    int c;
395234949Sbapt    FILE *f = output_file;
396234949Sbapt
397234949Sbapt    c = nextc();
398234949Sbapt    if (c == EOF)
399234949Sbapt	unexpected_EOF();
400234949Sbapt    if (c != '"')
401234949Sbapt	syntax_error(lineno, line, cptr);
402234949Sbapt    ++outline;
403234949Sbapt    fprintf(f, "#ident \"");
404234949Sbapt    for (;;)
405234949Sbapt    {
406234949Sbapt	c = *++cptr;
407234949Sbapt	if (c == '\n')
408234949Sbapt	{
409234949Sbapt	    fprintf(f, "\"\n");
410234949Sbapt	    return;
411234949Sbapt	}
412234949Sbapt	putc(c, f);
413234949Sbapt	if (c == '"')
414234949Sbapt	{
415234949Sbapt	    putc('\n', f);
416234949Sbapt	    ++cptr;
417234949Sbapt	    return;
418234949Sbapt	}
419234949Sbapt    }
420234949Sbapt}
421234949Sbapt
422268899Sbaptstatic char *
423268899Sbaptcopy_string(int quote)
424268899Sbapt{
425268899Sbapt    struct mstring *temp = msnew();
426268899Sbapt    int c;
427268899Sbapt    int s_lineno = lineno;
428268899Sbapt    char *s_line = dup_line();
429268899Sbapt    char *s_cptr = s_line + (cptr - line - 1);
430268899Sbapt
431268899Sbapt    for (;;)
432268899Sbapt    {
433268899Sbapt	c = *cptr++;
434268899Sbapt	mputc(temp, c);
435268899Sbapt	if (c == quote)
436268899Sbapt	{
437268899Sbapt	    FREE(s_line);
438268899Sbapt	    return msdone(temp);
439268899Sbapt	}
440268899Sbapt	if (c == '\n')
441268899Sbapt	    unterminated_string(s_lineno, s_line, s_cptr);
442268899Sbapt	if (c == '\\')
443268899Sbapt	{
444268899Sbapt	    c = *cptr++;
445268899Sbapt	    mputc(temp, c);
446268899Sbapt	    if (c == '\n')
447268899Sbapt	    {
448268899Sbapt		get_line();
449268899Sbapt		if (line == 0)
450268899Sbapt		    unterminated_string(s_lineno, s_line, s_cptr);
451268899Sbapt	    }
452268899Sbapt	}
453268899Sbapt    }
454268899Sbapt}
455268899Sbapt
456268899Sbaptstatic char *
457268899Sbaptcopy_comment(void)
458268899Sbapt{
459268899Sbapt    struct mstring *temp = msnew();
460268899Sbapt    int c;
461268899Sbapt
462268899Sbapt    c = *cptr;
463268899Sbapt    if (c == '/')
464268899Sbapt    {
465268899Sbapt	mputc(temp, '*');
466268899Sbapt	while ((c = *++cptr) != '\n')
467268899Sbapt	{
468268899Sbapt	    mputc(temp, c);
469268899Sbapt	    if (c == '*' && cptr[1] == '/')
470268899Sbapt		mputc(temp, ' ');
471268899Sbapt	}
472268899Sbapt	mputc(temp, '*');
473268899Sbapt	mputc(temp, '/');
474268899Sbapt    }
475268899Sbapt    else if (c == '*')
476268899Sbapt    {
477268899Sbapt	int c_lineno = lineno;
478268899Sbapt	char *c_line = dup_line();
479268899Sbapt	char *c_cptr = c_line + (cptr - line - 1);
480268899Sbapt
481268899Sbapt	mputc(temp, c);
482268899Sbapt	++cptr;
483268899Sbapt	for (;;)
484268899Sbapt	{
485268899Sbapt	    c = *cptr++;
486268899Sbapt	    mputc(temp, c);
487268899Sbapt	    if (c == '*' && *cptr == '/')
488268899Sbapt	    {
489268899Sbapt		mputc(temp, '/');
490268899Sbapt		++cptr;
491268899Sbapt		FREE(c_line);
492268899Sbapt		return msdone(temp);
493268899Sbapt	    }
494268899Sbapt	    if (c == '\n')
495268899Sbapt	    {
496268899Sbapt		get_line();
497268899Sbapt		if (line == 0)
498268899Sbapt		    unterminated_comment(c_lineno, c_line, c_cptr);
499268899Sbapt	    }
500268899Sbapt	}
501268899Sbapt    }
502268899Sbapt    return msdone(temp);
503268899Sbapt}
504268899Sbapt
505234949Sbaptstatic void
506234949Sbaptcopy_text(void)
507234949Sbapt{
508234949Sbapt    int c;
509234949Sbapt    FILE *f = text_file;
510234949Sbapt    int need_newline = 0;
511234949Sbapt    int t_lineno = lineno;
512234949Sbapt    char *t_line = dup_line();
513234949Sbapt    char *t_cptr = t_line + (cptr - line - 2);
514234949Sbapt
515234949Sbapt    if (*cptr == '\n')
516234949Sbapt    {
517234949Sbapt	get_line();
518234949Sbapt	if (line == 0)
519234949Sbapt	    unterminated_text(t_lineno, t_line, t_cptr);
520234949Sbapt    }
521234949Sbapt    if (!lflag)
522234949Sbapt	fprintf(f, line_format, lineno, input_file_name);
523234949Sbapt
524234949Sbapt  loop:
525234949Sbapt    c = *cptr++;
526234949Sbapt    switch (c)
527234949Sbapt    {
528234949Sbapt    case '\n':
529234949Sbapt	putc('\n', f);
530234949Sbapt	need_newline = 0;
531234949Sbapt	get_line();
532234949Sbapt	if (line)
533234949Sbapt	    goto loop;
534234949Sbapt	unterminated_text(t_lineno, t_line, t_cptr);
535234949Sbapt
536234949Sbapt    case '\'':
537234949Sbapt    case '"':
538268899Sbapt	putc(c, f);
539234949Sbapt	{
540268899Sbapt	    char *s = copy_string(c);
541268899Sbapt	    fputs(s, f);
542268899Sbapt	    free(s);
543234949Sbapt	}
544268899Sbapt	need_newline = 1;
545268899Sbapt	goto loop;
546234949Sbapt
547234949Sbapt    case '/':
548234949Sbapt	putc(c, f);
549234949Sbapt	{
550268899Sbapt	    char *s = copy_comment();
551268899Sbapt	    fputs(s, f);
552268899Sbapt	    free(s);
553234949Sbapt	}
554234949Sbapt	need_newline = 1;
555234949Sbapt	goto loop;
556234949Sbapt
557234949Sbapt    case '%':
558234949Sbapt    case '\\':
559234949Sbapt	if (*cptr == R_CURL)
560234949Sbapt	{
561234949Sbapt	    if (need_newline)
562234949Sbapt		putc('\n', f);
563234949Sbapt	    ++cptr;
564234949Sbapt	    FREE(t_line);
565234949Sbapt	    return;
566234949Sbapt	}
567234949Sbapt	/* FALLTHRU */
568234949Sbapt
569234949Sbapt    default:
570234949Sbapt	putc(c, f);
571234949Sbapt	need_newline = 1;
572234949Sbapt	goto loop;
573234949Sbapt    }
574234949Sbapt}
575234949Sbapt
576234949Sbaptstatic void
577234949Sbaptputs_both(const char *s)
578234949Sbapt{
579234949Sbapt    fputs(s, text_file);
580234949Sbapt    if (dflag)
581234949Sbapt	fputs(s, union_file);
582234949Sbapt}
583234949Sbapt
584234949Sbaptstatic void
585234949Sbaptputc_both(int c)
586234949Sbapt{
587234949Sbapt    putc(c, text_file);
588234949Sbapt    if (dflag)
589234949Sbapt	putc(c, union_file);
590234949Sbapt}
591234949Sbapt
592234949Sbaptstatic void
593234949Sbaptcopy_union(void)
594234949Sbapt{
595234949Sbapt    int c;
596234949Sbapt    int depth;
597234949Sbapt    int u_lineno = lineno;
598234949Sbapt    char *u_line = dup_line();
599234949Sbapt    char *u_cptr = u_line + (cptr - line - 6);
600234949Sbapt
601234949Sbapt    if (unionized)
602234949Sbapt	over_unionized(cptr - 6);
603234949Sbapt    unionized = 1;
604234949Sbapt
605234949Sbapt    if (!lflag)
606234949Sbapt	fprintf(text_file, line_format, lineno, input_file_name);
607234949Sbapt
608234949Sbapt    puts_both("#ifdef YYSTYPE\n");
609234949Sbapt    puts_both("#undef  YYSTYPE_IS_DECLARED\n");
610234949Sbapt    puts_both("#define YYSTYPE_IS_DECLARED 1\n");
611234949Sbapt    puts_both("#endif\n");
612234949Sbapt    puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
613234949Sbapt    puts_both("#define YYSTYPE_IS_DECLARED 1\n");
614234949Sbapt    puts_both("typedef union");
615234949Sbapt
616234949Sbapt    depth = 0;
617234949Sbapt  loop:
618234949Sbapt    c = *cptr++;
619234949Sbapt    putc_both(c);
620234949Sbapt    switch (c)
621234949Sbapt    {
622234949Sbapt    case '\n':
623234949Sbapt	get_line();
624234949Sbapt	if (line == 0)
625234949Sbapt	    unterminated_union(u_lineno, u_line, u_cptr);
626234949Sbapt	goto loop;
627234949Sbapt
628234949Sbapt    case L_CURL:
629234949Sbapt	++depth;
630234949Sbapt	goto loop;
631234949Sbapt
632234949Sbapt    case R_CURL:
633234949Sbapt	if (--depth == 0)
634234949Sbapt	{
635234949Sbapt	    puts_both(" YYSTYPE;\n");
636234949Sbapt	    puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n");
637234949Sbapt	    FREE(u_line);
638234949Sbapt	    return;
639234949Sbapt	}
640234949Sbapt	goto loop;
641234949Sbapt
642234949Sbapt    case '\'':
643234949Sbapt    case '"':
644234949Sbapt	{
645268899Sbapt	    char *s = copy_string(c);
646268899Sbapt	    puts_both(s);
647268899Sbapt	    free(s);
648234949Sbapt	}
649268899Sbapt	goto loop;
650234949Sbapt
651234949Sbapt    case '/':
652234949Sbapt	{
653268899Sbapt	    char *s = copy_comment();
654268899Sbapt	    puts_both(s);
655268899Sbapt	    free(s);
656234949Sbapt	}
657234949Sbapt	goto loop;
658234949Sbapt
659234949Sbapt    default:
660234949Sbapt	goto loop;
661234949Sbapt    }
662234949Sbapt}
663234949Sbapt
664272955Srodrigcstatic char *
665272955Srodrigcafter_blanks(char *s)
666272955Srodrigc{
667272955Srodrigc    while (*s != '\0' && isspace(UCH(*s)))
668272955Srodrigc	++s;
669272955Srodrigc    return s;
670272955Srodrigc}
671272955Srodrigc
672234949Sbapt/*
673272955Srodrigc * Trim leading/trailing blanks, and collapse multiple embedded blanks to a
674272955Srodrigc * single space.  Return index to last character in the buffer.
675234949Sbapt */
676272955Srodrigcstatic int
677272955Srodrigctrim_blanks(char *buffer)
678234949Sbapt{
679272955Srodrigc    if (*buffer != '\0')
680272955Srodrigc    {
681272955Srodrigc	char *d = buffer;
682272955Srodrigc	char *s = after_blanks(d);
683234949Sbapt
684272955Srodrigc	while ((*d++ = *s++) != '\0')
685272955Srodrigc	{
686272955Srodrigc	    ;
687272955Srodrigc	}
688234949Sbapt
689272955Srodrigc	--d;
690272955Srodrigc	while ((--d != buffer) && isspace(UCH(*d)))
691272955Srodrigc	    *d = '\0';
692234949Sbapt
693272955Srodrigc	for (s = d = buffer; (*d++ = *s++) != '\0';)
694272955Srodrigc	{
695272955Srodrigc	    if (isspace(UCH(*s)))
696272955Srodrigc	    {
697272955Srodrigc		*s = ' ';
698272955Srodrigc		while (isspace(UCH(*s)))
699272955Srodrigc		{
700272955Srodrigc		    *s++ = ' ';
701272955Srodrigc		}
702272955Srodrigc		--s;
703272955Srodrigc	    }
704272955Srodrigc	}
705234949Sbapt    }
706234949Sbapt
707272955Srodrigc    return (int)strlen(buffer) - 1;
708272955Srodrigc}
709234949Sbapt
710272955Srodrigc/*
711272955Srodrigc * Scan forward in the current line-buffer looking for a right-curly bracket.
712272955Srodrigc *
713272955Srodrigc * Parameters begin with a left-curly bracket, and continue until there are no
714272955Srodrigc * more interesting characters after the last right-curly bracket on the
715272955Srodrigc * current line.  Bison documents parameters as separated like this:
716272955Srodrigc *	{type param1} {type2 param2}
717272955Srodrigc * but also accepts commas (although some versions of bison mishandle this)
718272955Srodrigc *	{type param1,  type2 param2}
719272955Srodrigc */
720272955Srodrigcstatic int
721272955Srodrigcmore_curly(void)
722272955Srodrigc{
723272955Srodrigc    char *save = cptr;
724272955Srodrigc    int result = 0;
725272955Srodrigc    int finish = 0;
726272955Srodrigc    do
727234949Sbapt    {
728272955Srodrigc	switch (next_inline())
729234949Sbapt	{
730272955Srodrigc	case 0:
731272955Srodrigc	case '\n':
732272955Srodrigc	    finish = 1;
733272955Srodrigc	    break;
734272955Srodrigc	case R_CURL:
735272955Srodrigc	    finish = 1;
736272955Srodrigc	    result = 1;
737272955Srodrigc	    break;
738234949Sbapt	}
739272955Srodrigc	++cptr;
740234949Sbapt    }
741272955Srodrigc    while (!finish);
742272955Srodrigc    cptr = save;
743272955Srodrigc    return result;
744272955Srodrigc}
745234949Sbapt
746272955Srodrigcstatic void
747272955Srodrigcsave_param(int k, char *buffer, int name, int type2)
748272955Srodrigc{
749272955Srodrigc    param *head, *p;
750234949Sbapt
751240517Sbapt    p = TMALLOC(param, 1);
752234949Sbapt    NO_SPACE(p);
753234949Sbapt
754272955Srodrigc    p->type2 = strdup(buffer + type2);
755234949Sbapt    NO_SPACE(p->type2);
756272955Srodrigc    buffer[type2] = '\0';
757272955Srodrigc    (void)trim_blanks(p->type2);
758234949Sbapt
759272955Srodrigc    p->name = strdup(buffer + name);
760234949Sbapt    NO_SPACE(p->name);
761272955Srodrigc    buffer[name] = '\0';
762272955Srodrigc    (void)trim_blanks(p->name);
763234949Sbapt
764272955Srodrigc    p->type = strdup(buffer);
765272955Srodrigc    NO_SPACE(p->type);
766272955Srodrigc    (void)trim_blanks(p->type);
767234949Sbapt
768234949Sbapt    if (k == LEX_PARAM)
769234949Sbapt	head = lex_param;
770234949Sbapt    else
771234949Sbapt	head = parse_param;
772234949Sbapt
773234949Sbapt    if (head != NULL)
774234949Sbapt    {
775234949Sbapt	while (head->next)
776234949Sbapt	    head = head->next;
777234949Sbapt	head->next = p;
778234949Sbapt    }
779234949Sbapt    else
780234949Sbapt    {
781234949Sbapt	if (k == LEX_PARAM)
782234949Sbapt	    lex_param = p;
783234949Sbapt	else
784234949Sbapt	    parse_param = p;
785234949Sbapt    }
786234949Sbapt    p->next = NULL;
787272955Srodrigc}
788272955Srodrigc
789272955Srodrigc/*
790272955Srodrigc * Keep a linked list of parameters.  This may be multi-line, if the trailing
791272955Srodrigc * right-curly bracket is absent.
792272955Srodrigc */
793272955Srodrigcstatic void
794272955Srodrigccopy_param(int k)
795272955Srodrigc{
796272955Srodrigc    int c;
797272955Srodrigc    int name, type2;
798272955Srodrigc    int curly = 0;
799272955Srodrigc    char *buf = 0;
800272955Srodrigc    int i = -1;
801272955Srodrigc    size_t buf_size = 0;
802272955Srodrigc    int st_lineno = lineno;
803272955Srodrigc    char *comma;
804272955Srodrigc
805272955Srodrigc    do
806272955Srodrigc    {
807272955Srodrigc	int state = curly;
808272955Srodrigc	c = next_inline();
809272955Srodrigc	switch (c)
810272955Srodrigc	{
811272955Srodrigc	case EOF:
812272955Srodrigc	    unexpected_EOF();
813272955Srodrigc	    break;
814272955Srodrigc	case L_CURL:
815272955Srodrigc	    if (curly == 1)
816272955Srodrigc	    {
817272955Srodrigc		goto oops;
818272955Srodrigc	    }
819272955Srodrigc	    curly = 1;
820272955Srodrigc	    st_lineno = lineno;
821272955Srodrigc	    break;
822272955Srodrigc	case R_CURL:
823272955Srodrigc	    if (curly != 1)
824272955Srodrigc	    {
825272955Srodrigc		goto oops;
826272955Srodrigc	    }
827272955Srodrigc	    curly = 2;
828272955Srodrigc	    break;
829272955Srodrigc	case '\n':
830272955Srodrigc	    if (curly == 0)
831272955Srodrigc	    {
832272955Srodrigc		goto oops;
833272955Srodrigc	    }
834272955Srodrigc	    break;
835272955Srodrigc	case '%':
836272955Srodrigc	    if ((curly == 1) && (cptr == line))
837272955Srodrigc	    {
838272955Srodrigc		lineno = st_lineno;
839272955Srodrigc		missing_brace();
840272955Srodrigc	    }
841272955Srodrigc	    /* FALLTHRU */
842272955Srodrigc	case '"':
843272955Srodrigc	case '\'':
844272955Srodrigc	    goto oops;
845272955Srodrigc	default:
846272955Srodrigc	    if (curly == 0 && !isspace(UCH(c)))
847272955Srodrigc	    {
848272955Srodrigc		goto oops;
849272955Srodrigc	    }
850272955Srodrigc	    break;
851272955Srodrigc	}
852272955Srodrigc	if (buf == 0)
853272955Srodrigc	{
854272955Srodrigc	    buf_size = (size_t) linesize;
855272955Srodrigc	    buf = TMALLOC(char, buf_size);
856272955Srodrigc	}
857272955Srodrigc	else if (c == '\n')
858272955Srodrigc	{
859272955Srodrigc	    get_line();
860272955Srodrigc	    if (line == 0)
861272955Srodrigc		unexpected_EOF();
862272955Srodrigc	    --cptr;
863272955Srodrigc	    buf_size += (size_t) linesize;
864272955Srodrigc	    buf = TREALLOC(char, buf, buf_size);
865272955Srodrigc	}
866272955Srodrigc	NO_SPACE(buf);
867272955Srodrigc	if (curly)
868272955Srodrigc	{
869272955Srodrigc	    if ((state == 2) && (c == L_CURL))
870272955Srodrigc	    {
871272955Srodrigc		buf[++i] = ',';
872272955Srodrigc	    }
873272955Srodrigc	    else if ((state == 2) && isspace(UCH(c)))
874272955Srodrigc	    {
875272955Srodrigc		;
876272955Srodrigc	    }
877272955Srodrigc	    else if ((c != L_CURL) && (c != R_CURL))
878272955Srodrigc	    {
879272955Srodrigc		buf[++i] = (char)c;
880272955Srodrigc	    }
881272955Srodrigc	}
882272955Srodrigc	cptr++;
883272955Srodrigc    }
884272955Srodrigc    while (curly < 2 || more_curly());
885272955Srodrigc
886272955Srodrigc    if (i == 0)
887272955Srodrigc    {
888272955Srodrigc	if (curly == 1)
889272955Srodrigc	{
890272955Srodrigc	    lineno = st_lineno;
891272955Srodrigc	    missing_brace();
892272955Srodrigc	}
893272955Srodrigc	goto oops;
894272955Srodrigc    }
895272955Srodrigc
896272955Srodrigc    buf[i--] = '\0';
897272955Srodrigc    i = trim_blanks(buf);
898272955Srodrigc
899272955Srodrigc    comma = buf - 1;
900272955Srodrigc    do
901272955Srodrigc    {
902272955Srodrigc	char *parms = (comma + 1);
903272955Srodrigc	comma = strchr(parms, ',');
904272955Srodrigc	if (comma != 0)
905272955Srodrigc	    *comma = '\0';
906272955Srodrigc
907272955Srodrigc	(void)trim_blanks(parms);
908272955Srodrigc	i = (int)strlen(parms) - 1;
909272955Srodrigc	if (i < 0)
910272955Srodrigc	{
911272955Srodrigc	    goto oops;
912272955Srodrigc	}
913272955Srodrigc
914272955Srodrigc	if (parms[i] == ']')
915272955Srodrigc	{
916272955Srodrigc	    int level = 1;
917272955Srodrigc	    while (i >= 0 && level > 0 && parms[i] != '[')
918272955Srodrigc	    {
919272955Srodrigc		if (parms[i] == ']')
920272955Srodrigc		    ++level;
921272955Srodrigc		else if (parms[i] == '[')
922272955Srodrigc		    --level;
923272955Srodrigc		i--;
924272955Srodrigc	    }
925272955Srodrigc	    if (i <= 0)
926272955Srodrigc		unexpected_EOF();
927272955Srodrigc	    type2 = i--;
928272955Srodrigc	}
929272955Srodrigc	else
930272955Srodrigc	{
931272955Srodrigc	    type2 = i + 1;
932272955Srodrigc	}
933272955Srodrigc
934272955Srodrigc	while (i > 0 && (isalnum(UCH(parms[i])) || UCH(parms[i]) == '_'))
935272955Srodrigc	    i--;
936272955Srodrigc
937272955Srodrigc	if (!isspace(UCH(parms[i])) && parms[i] != '*')
938272955Srodrigc	    goto oops;
939272955Srodrigc
940272955Srodrigc	name = i + 1;
941272955Srodrigc
942272955Srodrigc	save_param(k, parms, name, type2);
943272955Srodrigc    }
944272955Srodrigc    while (comma != 0);
945272955Srodrigc    FREE(buf);
946234949Sbapt    return;
947234949Sbapt
948272955Srodrigc  oops:
949272955Srodrigc    FREE(buf);
950234949Sbapt    syntax_error(lineno, line, cptr);
951234949Sbapt}
952234949Sbapt
953234949Sbaptstatic int
954234949Sbapthexval(int c)
955234949Sbapt{
956234949Sbapt    if (c >= '0' && c <= '9')
957234949Sbapt	return (c - '0');
958234949Sbapt    if (c >= 'A' && c <= 'F')
959234949Sbapt	return (c - 'A' + 10);
960234949Sbapt    if (c >= 'a' && c <= 'f')
961234949Sbapt	return (c - 'a' + 10);
962234949Sbapt    return (-1);
963234949Sbapt}
964234949Sbapt
965234949Sbaptstatic bucket *
966234949Sbaptget_literal(void)
967234949Sbapt{
968234949Sbapt    int c, quote;
969234949Sbapt    int i;
970234949Sbapt    int n;
971234949Sbapt    char *s;
972234949Sbapt    bucket *bp;
973234949Sbapt    int s_lineno = lineno;
974234949Sbapt    char *s_line = dup_line();
975234949Sbapt    char *s_cptr = s_line + (cptr - line);
976234949Sbapt
977234949Sbapt    quote = *cptr++;
978234949Sbapt    cinc = 0;
979234949Sbapt    for (;;)
980234949Sbapt    {
981234949Sbapt	c = *cptr++;
982234949Sbapt	if (c == quote)
983234949Sbapt	    break;
984234949Sbapt	if (c == '\n')
985234949Sbapt	    unterminated_string(s_lineno, s_line, s_cptr);
986234949Sbapt	if (c == '\\')
987234949Sbapt	{
988234949Sbapt	    char *c_cptr = cptr - 1;
989234949Sbapt
990234949Sbapt	    c = *cptr++;
991234949Sbapt	    switch (c)
992234949Sbapt	    {
993234949Sbapt	    case '\n':
994234949Sbapt		get_line();
995234949Sbapt		if (line == 0)
996234949Sbapt		    unterminated_string(s_lineno, s_line, s_cptr);
997234949Sbapt		continue;
998234949Sbapt
999234949Sbapt	    case '0':
1000234949Sbapt	    case '1':
1001234949Sbapt	    case '2':
1002234949Sbapt	    case '3':
1003234949Sbapt	    case '4':
1004234949Sbapt	    case '5':
1005234949Sbapt	    case '6':
1006234949Sbapt	    case '7':
1007234949Sbapt		n = c - '0';
1008234949Sbapt		c = *cptr;
1009234949Sbapt		if (IS_OCTAL(c))
1010234949Sbapt		{
1011234949Sbapt		    n = (n << 3) + (c - '0');
1012234949Sbapt		    c = *++cptr;
1013234949Sbapt		    if (IS_OCTAL(c))
1014234949Sbapt		    {
1015234949Sbapt			n = (n << 3) + (c - '0');
1016234949Sbapt			++cptr;
1017234949Sbapt		    }
1018234949Sbapt		}
1019234949Sbapt		if (n > MAXCHAR)
1020234949Sbapt		    illegal_character(c_cptr);
1021234949Sbapt		c = n;
1022234949Sbapt		break;
1023234949Sbapt
1024234949Sbapt	    case 'x':
1025234949Sbapt		c = *cptr++;
1026234949Sbapt		n = hexval(c);
1027234949Sbapt		if (n < 0 || n >= 16)
1028234949Sbapt		    illegal_character(c_cptr);
1029234949Sbapt		for (;;)
1030234949Sbapt		{
1031234949Sbapt		    c = *cptr;
1032234949Sbapt		    i = hexval(c);
1033234949Sbapt		    if (i < 0 || i >= 16)
1034234949Sbapt			break;
1035234949Sbapt		    ++cptr;
1036234949Sbapt		    n = (n << 4) + i;
1037234949Sbapt		    if (n > MAXCHAR)
1038234949Sbapt			illegal_character(c_cptr);
1039234949Sbapt		}
1040234949Sbapt		c = n;
1041234949Sbapt		break;
1042234949Sbapt
1043234949Sbapt	    case 'a':
1044234949Sbapt		c = 7;
1045234949Sbapt		break;
1046234949Sbapt	    case 'b':
1047234949Sbapt		c = '\b';
1048234949Sbapt		break;
1049234949Sbapt	    case 'f':
1050234949Sbapt		c = '\f';
1051234949Sbapt		break;
1052234949Sbapt	    case 'n':
1053234949Sbapt		c = '\n';
1054234949Sbapt		break;
1055234949Sbapt	    case 'r':
1056234949Sbapt		c = '\r';
1057234949Sbapt		break;
1058234949Sbapt	    case 't':
1059234949Sbapt		c = '\t';
1060234949Sbapt		break;
1061234949Sbapt	    case 'v':
1062234949Sbapt		c = '\v';
1063234949Sbapt		break;
1064234949Sbapt	    }
1065234949Sbapt	}
1066234949Sbapt	cachec(c);
1067234949Sbapt    }
1068234949Sbapt    FREE(s_line);
1069234949Sbapt
1070234949Sbapt    n = cinc;
1071240517Sbapt    s = TMALLOC(char, n);
1072234949Sbapt    NO_SPACE(s);
1073234949Sbapt
1074234949Sbapt    for (i = 0; i < n; ++i)
1075234949Sbapt	s[i] = cache[i];
1076234949Sbapt
1077234949Sbapt    cinc = 0;
1078234949Sbapt    if (n == 1)
1079234949Sbapt	cachec('\'');
1080234949Sbapt    else
1081234949Sbapt	cachec('"');
1082234949Sbapt
1083234949Sbapt    for (i = 0; i < n; ++i)
1084234949Sbapt    {
1085234949Sbapt	c = UCH(s[i]);
1086234949Sbapt	if (c == '\\' || c == cache[0])
1087234949Sbapt	{
1088234949Sbapt	    cachec('\\');
1089234949Sbapt	    cachec(c);
1090234949Sbapt	}
1091234949Sbapt	else if (isprint(c))
1092234949Sbapt	    cachec(c);
1093234949Sbapt	else
1094234949Sbapt	{
1095234949Sbapt	    cachec('\\');
1096234949Sbapt	    switch (c)
1097234949Sbapt	    {
1098234949Sbapt	    case 7:
1099234949Sbapt		cachec('a');
1100234949Sbapt		break;
1101234949Sbapt	    case '\b':
1102234949Sbapt		cachec('b');
1103234949Sbapt		break;
1104234949Sbapt	    case '\f':
1105234949Sbapt		cachec('f');
1106234949Sbapt		break;
1107234949Sbapt	    case '\n':
1108234949Sbapt		cachec('n');
1109234949Sbapt		break;
1110234949Sbapt	    case '\r':
1111234949Sbapt		cachec('r');
1112234949Sbapt		break;
1113234949Sbapt	    case '\t':
1114234949Sbapt		cachec('t');
1115234949Sbapt		break;
1116234949Sbapt	    case '\v':
1117234949Sbapt		cachec('v');
1118234949Sbapt		break;
1119234949Sbapt	    default:
1120234949Sbapt		cachec(((c >> 6) & 7) + '0');
1121234949Sbapt		cachec(((c >> 3) & 7) + '0');
1122234949Sbapt		cachec((c & 7) + '0');
1123234949Sbapt		break;
1124234949Sbapt	    }
1125234949Sbapt	}
1126234949Sbapt    }
1127234949Sbapt
1128234949Sbapt    if (n == 1)
1129234949Sbapt	cachec('\'');
1130234949Sbapt    else
1131234949Sbapt	cachec('"');
1132234949Sbapt
1133234949Sbapt    cachec(NUL);
1134234949Sbapt    bp = lookup(cache);
1135234949Sbapt    bp->class = TERM;
1136234949Sbapt    if (n == 1 && bp->value == UNDEFINED)
1137234949Sbapt	bp->value = UCH(*s);
1138234949Sbapt    FREE(s);
1139234949Sbapt
1140234949Sbapt    return (bp);
1141234949Sbapt}
1142234949Sbapt
1143234949Sbaptstatic int
1144234949Sbaptis_reserved(char *name)
1145234949Sbapt{
1146234949Sbapt    char *s;
1147234949Sbapt
1148234949Sbapt    if (strcmp(name, ".") == 0 ||
1149234949Sbapt	strcmp(name, "$accept") == 0 ||
1150234949Sbapt	strcmp(name, "$end") == 0)
1151234949Sbapt	return (1);
1152234949Sbapt
1153234949Sbapt    if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2])))
1154234949Sbapt    {
1155234949Sbapt	s = name + 3;
1156234949Sbapt	while (isdigit(UCH(*s)))
1157234949Sbapt	    ++s;
1158234949Sbapt	if (*s == NUL)
1159234949Sbapt	    return (1);
1160234949Sbapt    }
1161234949Sbapt
1162234949Sbapt    return (0);
1163234949Sbapt}
1164234949Sbapt
1165234949Sbaptstatic bucket *
1166234949Sbaptget_name(void)
1167234949Sbapt{
1168234949Sbapt    int c;
1169234949Sbapt
1170234949Sbapt    cinc = 0;
1171234949Sbapt    for (c = *cptr; IS_IDENT(c); c = *++cptr)
1172234949Sbapt	cachec(c);
1173234949Sbapt    cachec(NUL);
1174234949Sbapt
1175234949Sbapt    if (is_reserved(cache))
1176234949Sbapt	used_reserved(cache);
1177234949Sbapt
1178234949Sbapt    return (lookup(cache));
1179234949Sbapt}
1180234949Sbapt
1181234949Sbaptstatic Value_t
1182234949Sbaptget_number(void)
1183234949Sbapt{
1184234949Sbapt    int c;
1185234949Sbapt    Value_t n;
1186234949Sbapt
1187234949Sbapt    n = 0;
1188234949Sbapt    for (c = *cptr; isdigit(c); c = *++cptr)
1189234949Sbapt	n = (Value_t) (10 * n + (c - '0'));
1190234949Sbapt
1191234949Sbapt    return (n);
1192234949Sbapt}
1193234949Sbapt
1194234949Sbaptstatic char *
1195268899Sbaptcache_tag(char *tag, size_t len)
1196268899Sbapt{
1197268899Sbapt    int i;
1198268899Sbapt    char *s;
1199268899Sbapt
1200268899Sbapt    for (i = 0; i < ntags; ++i)
1201268899Sbapt    {
1202268899Sbapt	if (strncmp(tag, tag_table[i], len) == 0 &&
1203268899Sbapt	    tag_table[i][len] == NUL)
1204268899Sbapt	    return (tag_table[i]);
1205268899Sbapt    }
1206268899Sbapt
1207268899Sbapt    if (ntags >= tagmax)
1208268899Sbapt    {
1209268899Sbapt	tagmax += 16;
1210268899Sbapt	tag_table =
1211268899Sbapt	    (tag_table
1212268899Sbapt	     ? TREALLOC(char *, tag_table, tagmax)
1213268899Sbapt	     : TMALLOC(char *, tagmax));
1214268899Sbapt	NO_SPACE(tag_table);
1215268899Sbapt    }
1216268899Sbapt
1217268899Sbapt    s = TMALLOC(char, len + 1);
1218268899Sbapt    NO_SPACE(s);
1219268899Sbapt
1220268899Sbapt    strncpy(s, tag, len);
1221268899Sbapt    s[len] = 0;
1222268899Sbapt    tag_table[ntags++] = s;
1223268899Sbapt    return s;
1224268899Sbapt}
1225268899Sbapt
1226268899Sbaptstatic char *
1227234949Sbaptget_tag(void)
1228234949Sbapt{
1229234949Sbapt    int c;
1230234949Sbapt    int t_lineno = lineno;
1231234949Sbapt    char *t_line = dup_line();
1232234949Sbapt    char *t_cptr = t_line + (cptr - line);
1233234949Sbapt
1234234949Sbapt    ++cptr;
1235234949Sbapt    c = nextc();
1236234949Sbapt    if (c == EOF)
1237234949Sbapt	unexpected_EOF();
1238234949Sbapt    if (!isalpha(c) && c != '_' && c != '$')
1239234949Sbapt	illegal_tag(t_lineno, t_line, t_cptr);
1240234949Sbapt
1241234949Sbapt    cinc = 0;
1242234949Sbapt    do
1243234949Sbapt    {
1244234949Sbapt	cachec(c);
1245234949Sbapt	c = *++cptr;
1246234949Sbapt    }
1247234949Sbapt    while (IS_IDENT(c));
1248234949Sbapt    cachec(NUL);
1249234949Sbapt
1250234949Sbapt    c = nextc();
1251234949Sbapt    if (c == EOF)
1252234949Sbapt	unexpected_EOF();
1253234949Sbapt    if (c != '>')
1254234949Sbapt	illegal_tag(t_lineno, t_line, t_cptr);
1255234949Sbapt    ++cptr;
1256234949Sbapt
1257268899Sbapt    FREE(t_line);
1258268899Sbapt    havetags = 1;
1259268899Sbapt    return cache_tag(cache, (size_t) cinc);
1260268899Sbapt}
1261234949Sbapt
1262268899Sbapt#if defined(YYBTYACC)
1263268899Sbaptstatic char *
1264268899Sbaptscan_id(void)
1265268899Sbapt{
1266268899Sbapt    char *b = cptr;
1267234949Sbapt
1268268899Sbapt    while (isalnum(*cptr) || *cptr == '_' || *cptr == '$')
1269268899Sbapt	cptr++;
1270268899Sbapt    return cache_tag(b, (size_t) (cptr - b));
1271234949Sbapt}
1272268899Sbapt#endif
1273234949Sbapt
1274234949Sbaptstatic void
1275234949Sbaptdeclare_tokens(int assoc)
1276234949Sbapt{
1277234949Sbapt    int c;
1278234949Sbapt    bucket *bp;
1279234949Sbapt    Value_t value;
1280234949Sbapt    char *tag = 0;
1281234949Sbapt
1282234949Sbapt    if (assoc != TOKEN)
1283234949Sbapt	++prec;
1284234949Sbapt
1285234949Sbapt    c = nextc();
1286234949Sbapt    if (c == EOF)
1287234949Sbapt	unexpected_EOF();
1288234949Sbapt    if (c == '<')
1289234949Sbapt    {
1290234949Sbapt	tag = get_tag();
1291234949Sbapt	c = nextc();
1292234949Sbapt	if (c == EOF)
1293234949Sbapt	    unexpected_EOF();
1294234949Sbapt    }
1295234949Sbapt
1296234949Sbapt    for (;;)
1297234949Sbapt    {
1298234949Sbapt	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1299234949Sbapt	    bp = get_name();
1300234949Sbapt	else if (c == '\'' || c == '"')
1301234949Sbapt	    bp = get_literal();
1302234949Sbapt	else
1303234949Sbapt	    return;
1304234949Sbapt
1305234949Sbapt	if (bp == goal)
1306234949Sbapt	    tokenized_start(bp->name);
1307234949Sbapt	bp->class = TERM;
1308234949Sbapt
1309234949Sbapt	if (tag)
1310234949Sbapt	{
1311234949Sbapt	    if (bp->tag && tag != bp->tag)
1312234949Sbapt		retyped_warning(bp->name);
1313234949Sbapt	    bp->tag = tag;
1314234949Sbapt	}
1315234949Sbapt
1316234949Sbapt	if (assoc != TOKEN)
1317234949Sbapt	{
1318234949Sbapt	    if (bp->prec && prec != bp->prec)
1319234949Sbapt		reprec_warning(bp->name);
1320234949Sbapt	    bp->assoc = (Assoc_t) assoc;
1321234949Sbapt	    bp->prec = prec;
1322234949Sbapt	}
1323234949Sbapt
1324234949Sbapt	c = nextc();
1325234949Sbapt	if (c == EOF)
1326234949Sbapt	    unexpected_EOF();
1327234949Sbapt
1328234949Sbapt	if (isdigit(c))
1329234949Sbapt	{
1330234949Sbapt	    value = get_number();
1331234949Sbapt	    if (bp->value != UNDEFINED && value != bp->value)
1332234949Sbapt		revalued_warning(bp->name);
1333234949Sbapt	    bp->value = value;
1334234949Sbapt	    c = nextc();
1335234949Sbapt	    if (c == EOF)
1336234949Sbapt		unexpected_EOF();
1337234949Sbapt	}
1338234949Sbapt    }
1339234949Sbapt}
1340234949Sbapt
1341234949Sbapt/*
1342234949Sbapt * %expect requires special handling
1343234949Sbapt * as it really isn't part of the yacc
1344234949Sbapt * grammar only a flag for yacc proper.
1345234949Sbapt */
1346234949Sbaptstatic void
1347234949Sbaptdeclare_expect(int assoc)
1348234949Sbapt{
1349234949Sbapt    int c;
1350234949Sbapt
1351234949Sbapt    if (assoc != EXPECT && assoc != EXPECT_RR)
1352234949Sbapt	++prec;
1353234949Sbapt
1354234949Sbapt    /*
1355234949Sbapt     * Stay away from nextc - doesn't
1356234949Sbapt     * detect EOL and will read to EOF.
1357234949Sbapt     */
1358234949Sbapt    c = *++cptr;
1359234949Sbapt    if (c == EOF)
1360234949Sbapt	unexpected_EOF();
1361234949Sbapt
1362234949Sbapt    for (;;)
1363234949Sbapt    {
1364234949Sbapt	if (isdigit(c))
1365234949Sbapt	{
1366234949Sbapt	    if (assoc == EXPECT)
1367234949Sbapt		SRexpect = get_number();
1368234949Sbapt	    else
1369234949Sbapt		RRexpect = get_number();
1370234949Sbapt	    break;
1371234949Sbapt	}
1372234949Sbapt	/*
1373234949Sbapt	 * Looking for number before EOL.
1374234949Sbapt	 * Spaces, tabs, and numbers are ok,
1375234949Sbapt	 * words, punc., etc. are syntax errors.
1376234949Sbapt	 */
1377234949Sbapt	else if (c == '\n' || isalpha(c) || !isspace(c))
1378234949Sbapt	{
1379234949Sbapt	    syntax_error(lineno, line, cptr);
1380234949Sbapt	}
1381234949Sbapt	else
1382234949Sbapt	{
1383234949Sbapt	    c = *++cptr;
1384234949Sbapt	    if (c == EOF)
1385234949Sbapt		unexpected_EOF();
1386234949Sbapt	}
1387234949Sbapt    }
1388234949Sbapt}
1389234949Sbapt
1390268899Sbapt#if defined(YYBTYACC)
1391234949Sbaptstatic void
1392268899Sbaptdeclare_argtypes(bucket *bp)
1393268899Sbapt{
1394268899Sbapt    char *tags[MAXARGS];
1395268899Sbapt    int args = 0, c;
1396268899Sbapt
1397268899Sbapt    if (bp->args >= 0)
1398268899Sbapt	retyped_warning(bp->name);
1399268899Sbapt    cptr++;			/* skip open paren */
1400268899Sbapt    for (;;)
1401268899Sbapt    {
1402268899Sbapt	c = nextc();
1403268899Sbapt	if (c == EOF)
1404268899Sbapt	    unexpected_EOF();
1405268899Sbapt	if (c != '<')
1406268899Sbapt	    syntax_error(lineno, line, cptr);
1407268899Sbapt	tags[args++] = get_tag();
1408268899Sbapt	c = nextc();
1409268899Sbapt	if (c == R_PAREN)
1410268899Sbapt	    break;
1411268899Sbapt	if (c == EOF)
1412268899Sbapt	    unexpected_EOF();
1413268899Sbapt    }
1414268899Sbapt    cptr++;			/* skip close paren */
1415268899Sbapt    bp->args = args;
1416268899Sbapt    bp->argnames = TMALLOC(char *, args);
1417268899Sbapt    NO_SPACE(bp->argnames);
1418268899Sbapt    bp->argtags = CALLOC(sizeof(char *), args + 1);
1419268899Sbapt    NO_SPACE(bp->argtags);
1420268899Sbapt    while (--args >= 0)
1421268899Sbapt    {
1422268899Sbapt	bp->argtags[args] = tags[args];
1423268899Sbapt	bp->argnames[args] = NULL;
1424268899Sbapt    }
1425268899Sbapt}
1426268899Sbapt#endif
1427268899Sbapt
1428268899Sbaptstatic void
1429234949Sbaptdeclare_types(void)
1430234949Sbapt{
1431234949Sbapt    int c;
1432234949Sbapt    bucket *bp;
1433268899Sbapt    char *tag = NULL;
1434234949Sbapt
1435234949Sbapt    c = nextc();
1436234949Sbapt    if (c == EOF)
1437234949Sbapt	unexpected_EOF();
1438268899Sbapt    if (c == '<')
1439268899Sbapt	tag = get_tag();
1440234949Sbapt
1441234949Sbapt    for (;;)
1442234949Sbapt    {
1443234949Sbapt	c = nextc();
1444268899Sbapt	if (c == EOF)
1445268899Sbapt	    unexpected_EOF();
1446234949Sbapt	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1447268899Sbapt	{
1448234949Sbapt	    bp = get_name();
1449268899Sbapt#if defined(YYBTYACC)
1450268899Sbapt	    if (nextc() == L_PAREN)
1451268899Sbapt		declare_argtypes(bp);
1452268899Sbapt	    else
1453268899Sbapt		bp->args = 0;
1454268899Sbapt#endif
1455268899Sbapt	}
1456234949Sbapt	else if (c == '\'' || c == '"')
1457268899Sbapt	{
1458234949Sbapt	    bp = get_literal();
1459268899Sbapt#if defined(YYBTYACC)
1460268899Sbapt	    bp->args = 0;
1461268899Sbapt#endif
1462268899Sbapt	}
1463234949Sbapt	else
1464234949Sbapt	    return;
1465234949Sbapt
1466268899Sbapt	if (tag)
1467268899Sbapt	{
1468268899Sbapt	    if (bp->tag && tag != bp->tag)
1469268899Sbapt		retyped_warning(bp->name);
1470268899Sbapt	    bp->tag = tag;
1471268899Sbapt	}
1472234949Sbapt    }
1473234949Sbapt}
1474234949Sbapt
1475234949Sbaptstatic void
1476234949Sbaptdeclare_start(void)
1477234949Sbapt{
1478234949Sbapt    int c;
1479234949Sbapt    bucket *bp;
1480234949Sbapt
1481234949Sbapt    c = nextc();
1482234949Sbapt    if (c == EOF)
1483234949Sbapt	unexpected_EOF();
1484234949Sbapt    if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1485234949Sbapt	syntax_error(lineno, line, cptr);
1486234949Sbapt    bp = get_name();
1487234949Sbapt    if (bp->class == TERM)
1488234949Sbapt	terminal_start(bp->name);
1489234949Sbapt    if (goal && goal != bp)
1490234949Sbapt	restarted_warning();
1491234949Sbapt    goal = bp;
1492234949Sbapt}
1493234949Sbapt
1494234949Sbaptstatic void
1495234949Sbaptread_declarations(void)
1496234949Sbapt{
1497234949Sbapt    int c, k;
1498234949Sbapt
1499234949Sbapt    cache_size = 256;
1500240517Sbapt    cache = TMALLOC(char, cache_size);
1501234949Sbapt    NO_SPACE(cache);
1502234949Sbapt
1503234949Sbapt    for (;;)
1504234949Sbapt    {
1505234949Sbapt	c = nextc();
1506234949Sbapt	if (c == EOF)
1507234949Sbapt	    unexpected_EOF();
1508234949Sbapt	if (c != '%')
1509234949Sbapt	    syntax_error(lineno, line, cptr);
1510234949Sbapt	switch (k = keyword())
1511234949Sbapt	{
1512234949Sbapt	case MARK:
1513234949Sbapt	    return;
1514234949Sbapt
1515234949Sbapt	case IDENT:
1516234949Sbapt	    copy_ident();
1517234949Sbapt	    break;
1518234949Sbapt
1519234949Sbapt	case TEXT:
1520234949Sbapt	    copy_text();
1521234949Sbapt	    break;
1522234949Sbapt
1523234949Sbapt	case UNION:
1524234949Sbapt	    copy_union();
1525234949Sbapt	    break;
1526234949Sbapt
1527234949Sbapt	case TOKEN:
1528234949Sbapt	case LEFT:
1529234949Sbapt	case RIGHT:
1530234949Sbapt	case NONASSOC:
1531234949Sbapt	    declare_tokens(k);
1532234949Sbapt	    break;
1533234949Sbapt
1534234949Sbapt	case EXPECT:
1535234949Sbapt	case EXPECT_RR:
1536234949Sbapt	    declare_expect(k);
1537234949Sbapt	    break;
1538234949Sbapt
1539234949Sbapt	case TYPE:
1540234949Sbapt	    declare_types();
1541234949Sbapt	    break;
1542234949Sbapt
1543234949Sbapt	case START:
1544234949Sbapt	    declare_start();
1545234949Sbapt	    break;
1546234949Sbapt
1547234949Sbapt	case PURE_PARSER:
1548234949Sbapt	    pure_parser = 1;
1549234949Sbapt	    break;
1550234949Sbapt
1551234949Sbapt	case PARSE_PARAM:
1552234949Sbapt	case LEX_PARAM:
1553234949Sbapt	    copy_param(k);
1554234949Sbapt	    break;
1555234949Sbapt
1556268899Sbapt	case TOKEN_TABLE:
1557268899Sbapt	    token_table = 1;
1558268899Sbapt	    break;
1559268899Sbapt
1560268899Sbapt#if defined(YYBTYACC)
1561268899Sbapt	case LOCATIONS:
1562268899Sbapt	    locations = 1;
1563268899Sbapt	    break;
1564268899Sbapt
1565268899Sbapt	case DESTRUCTOR:
1566268899Sbapt	    destructor = 1;
1567268899Sbapt	    copy_destructor();
1568268899Sbapt	    break;
1569268899Sbapt#endif
1570268899Sbapt
1571234949Sbapt	case POSIX_YACC:
1572234949Sbapt	    /* noop for bison compatibility. byacc is already designed to be posix
1573234949Sbapt	     * yacc compatible. */
1574234949Sbapt	    break;
1575234949Sbapt	}
1576234949Sbapt    }
1577234949Sbapt}
1578234949Sbapt
1579234949Sbaptstatic void
1580234949Sbaptinitialize_grammar(void)
1581234949Sbapt{
1582234949Sbapt    nitems = 4;
1583234949Sbapt    maxitems = 300;
1584234949Sbapt
1585240517Sbapt    pitem = TMALLOC(bucket *, maxitems);
1586234949Sbapt    NO_SPACE(pitem);
1587234949Sbapt
1588234949Sbapt    pitem[0] = 0;
1589234949Sbapt    pitem[1] = 0;
1590234949Sbapt    pitem[2] = 0;
1591234949Sbapt    pitem[3] = 0;
1592234949Sbapt
1593234949Sbapt    nrules = 3;
1594234949Sbapt    maxrules = 100;
1595234949Sbapt
1596240517Sbapt    plhs = TMALLOC(bucket *, maxrules);
1597234949Sbapt    NO_SPACE(plhs);
1598234949Sbapt
1599234949Sbapt    plhs[0] = 0;
1600234949Sbapt    plhs[1] = 0;
1601234949Sbapt    plhs[2] = 0;
1602234949Sbapt
1603240517Sbapt    rprec = TMALLOC(Value_t, maxrules);
1604234949Sbapt    NO_SPACE(rprec);
1605234949Sbapt
1606234949Sbapt    rprec[0] = 0;
1607234949Sbapt    rprec[1] = 0;
1608234949Sbapt    rprec[2] = 0;
1609234949Sbapt
1610240517Sbapt    rassoc = TMALLOC(Assoc_t, maxrules);
1611234949Sbapt    NO_SPACE(rassoc);
1612234949Sbapt
1613234949Sbapt    rassoc[0] = TOKEN;
1614234949Sbapt    rassoc[1] = TOKEN;
1615234949Sbapt    rassoc[2] = TOKEN;
1616234949Sbapt}
1617234949Sbapt
1618234949Sbaptstatic void
1619234949Sbaptexpand_items(void)
1620234949Sbapt{
1621234949Sbapt    maxitems += 300;
1622240517Sbapt    pitem = TREALLOC(bucket *, pitem, maxitems);
1623234949Sbapt    NO_SPACE(pitem);
1624234949Sbapt}
1625234949Sbapt
1626234949Sbaptstatic void
1627234949Sbaptexpand_rules(void)
1628234949Sbapt{
1629234949Sbapt    maxrules += 100;
1630234949Sbapt
1631240517Sbapt    plhs = TREALLOC(bucket *, plhs, maxrules);
1632234949Sbapt    NO_SPACE(plhs);
1633234949Sbapt
1634240517Sbapt    rprec = TREALLOC(Value_t, rprec, maxrules);
1635234949Sbapt    NO_SPACE(rprec);
1636234949Sbapt
1637240517Sbapt    rassoc = TREALLOC(Assoc_t, rassoc, maxrules);
1638234949Sbapt    NO_SPACE(rassoc);
1639234949Sbapt}
1640234949Sbapt
1641268899Sbapt/* set immediately prior to where copy_args() could be called, and incremented by
1642268899Sbapt   the various routines that will rescan the argument list as appropriate */
1643268899Sbaptstatic int rescan_lineno;
1644268899Sbapt#if defined(YYBTYACC)
1645268899Sbapt
1646268899Sbaptstatic char *
1647268899Sbaptcopy_args(int *alen)
1648268899Sbapt{
1649268899Sbapt    struct mstring *s = msnew();
1650268899Sbapt    int depth = 0, len = 1;
1651268899Sbapt    char c, quote = 0;
1652268899Sbapt    int a_lineno = lineno;
1653268899Sbapt    char *a_line = dup_line();
1654268899Sbapt    char *a_cptr = a_line + (cptr - line - 1);
1655268899Sbapt
1656268899Sbapt    while ((c = *cptr++) != R_PAREN || depth || quote)
1657268899Sbapt    {
1658268899Sbapt	if (c == ',' && !quote && !depth)
1659268899Sbapt	{
1660268899Sbapt	    len++;
1661268899Sbapt	    mputc(s, 0);
1662268899Sbapt	    continue;
1663268899Sbapt	}
1664268899Sbapt	mputc(s, c);
1665268899Sbapt	if (c == '\n')
1666268899Sbapt	{
1667268899Sbapt	    get_line();
1668268899Sbapt	    if (!line)
1669268899Sbapt	    {
1670268899Sbapt		if (quote)
1671268899Sbapt		    unterminated_string(a_lineno, a_line, a_cptr);
1672268899Sbapt		else
1673268899Sbapt		    unterminated_arglist(a_lineno, a_line, a_cptr);
1674268899Sbapt	    }
1675268899Sbapt	}
1676268899Sbapt	else if (quote)
1677268899Sbapt	{
1678268899Sbapt	    if (c == quote)
1679268899Sbapt		quote = 0;
1680268899Sbapt	    else if (c == '\\')
1681268899Sbapt	    {
1682268899Sbapt		if (*cptr != '\n')
1683268899Sbapt		    mputc(s, *cptr++);
1684268899Sbapt	    }
1685268899Sbapt	}
1686268899Sbapt	else
1687268899Sbapt	{
1688268899Sbapt	    if (c == L_PAREN)
1689268899Sbapt		depth++;
1690268899Sbapt	    else if (c == R_PAREN)
1691268899Sbapt		depth--;
1692268899Sbapt	    else if (c == '\"' || c == '\'')
1693268899Sbapt		quote = c;
1694268899Sbapt	}
1695268899Sbapt    }
1696268899Sbapt    if (alen)
1697268899Sbapt	*alen = len;
1698268899Sbapt    FREE(a_line);
1699268899Sbapt    return msdone(s);
1700268899Sbapt}
1701268899Sbapt
1702268899Sbaptstatic char *
1703268899Sbaptparse_id(char *p, char **save)
1704268899Sbapt{
1705268899Sbapt    char *b;
1706268899Sbapt
1707268899Sbapt    while (isspace(*p))
1708268899Sbapt	if (*p++ == '\n')
1709268899Sbapt	    rescan_lineno++;
1710268899Sbapt    if (!isalpha(*p) && *p != '_')
1711268899Sbapt	return NULL;
1712268899Sbapt    b = p;
1713268899Sbapt    while (isalnum(*p) || *p == '_' || *p == '$')
1714268899Sbapt	p++;
1715268899Sbapt    if (save)
1716268899Sbapt    {
1717268899Sbapt	*save = cache_tag(b, (size_t) (p - b));
1718268899Sbapt    }
1719268899Sbapt    return p;
1720268899Sbapt}
1721268899Sbapt
1722268899Sbaptstatic char *
1723268899Sbaptparse_int(char *p, int *save)
1724268899Sbapt{
1725268899Sbapt    int neg = 0, val = 0;
1726268899Sbapt
1727268899Sbapt    while (isspace(*p))
1728268899Sbapt	if (*p++ == '\n')
1729268899Sbapt	    rescan_lineno++;
1730268899Sbapt    if (*p == '-')
1731268899Sbapt    {
1732268899Sbapt	neg = 1;
1733268899Sbapt	p++;
1734268899Sbapt    }
1735268899Sbapt    if (!isdigit(*p))
1736268899Sbapt	return NULL;
1737268899Sbapt    while (isdigit(*p))
1738268899Sbapt	val = val * 10 + *p++ - '0';
1739268899Sbapt    if (neg)
1740268899Sbapt	val = -val;
1741268899Sbapt    if (save)
1742268899Sbapt	*save = val;
1743268899Sbapt    return p;
1744268899Sbapt}
1745268899Sbapt
1746234949Sbaptstatic void
1747268899Sbaptparse_arginfo(bucket *a, char *args, int argslen)
1748268899Sbapt{
1749268899Sbapt    char *p = args, *tmp;
1750268899Sbapt    int i, redec = 0;
1751268899Sbapt
1752268899Sbapt    if (a->args > 0)
1753268899Sbapt    {
1754268899Sbapt	if (a->args != argslen)
1755268899Sbapt	    arg_number_disagree_warning(rescan_lineno, a->name);
1756268899Sbapt	redec = 1;
1757268899Sbapt    }
1758268899Sbapt    else
1759268899Sbapt    {
1760268899Sbapt	if ((a->args = argslen) == 0)
1761268899Sbapt	    return;
1762268899Sbapt	a->argnames = TMALLOC(char *, argslen);
1763268899Sbapt	NO_SPACE(a->argnames);
1764268899Sbapt	a->argtags = TMALLOC(char *, argslen);
1765268899Sbapt	NO_SPACE(a->argtags);
1766268899Sbapt    }
1767268899Sbapt    if (!args)
1768268899Sbapt	return;
1769268899Sbapt    for (i = 0; i < argslen; i++)
1770268899Sbapt    {
1771268899Sbapt	while (isspace(*p))
1772268899Sbapt	    if (*p++ == '\n')
1773268899Sbapt		rescan_lineno++;
1774268899Sbapt	if (*p++ != '$')
1775268899Sbapt	    bad_formals();
1776268899Sbapt	while (isspace(*p))
1777268899Sbapt	    if (*p++ == '\n')
1778268899Sbapt		rescan_lineno++;
1779268899Sbapt	if (*p == '<')
1780268899Sbapt	{
1781268899Sbapt	    havetags = 1;
1782268899Sbapt	    if (!(p = parse_id(p + 1, &tmp)))
1783268899Sbapt		bad_formals();
1784268899Sbapt	    while (isspace(*p))
1785268899Sbapt		if (*p++ == '\n')
1786268899Sbapt		    rescan_lineno++;
1787268899Sbapt	    if (*p++ != '>')
1788268899Sbapt		bad_formals();
1789268899Sbapt	    if (redec)
1790268899Sbapt	    {
1791268899Sbapt		if (a->argtags[i] != tmp)
1792268899Sbapt		    arg_type_disagree_warning(rescan_lineno, i + 1, a->name);
1793268899Sbapt	    }
1794268899Sbapt	    else
1795268899Sbapt		a->argtags[i] = tmp;
1796268899Sbapt	}
1797268899Sbapt	else if (!redec)
1798268899Sbapt	    a->argtags[i] = NULL;
1799268899Sbapt	if (!(p = parse_id(p, &a->argnames[i])))
1800268899Sbapt	    bad_formals();
1801268899Sbapt	while (isspace(*p))
1802268899Sbapt	    if (*p++ == '\n')
1803268899Sbapt		rescan_lineno++;
1804268899Sbapt	if (*p++)
1805268899Sbapt	    bad_formals();
1806268899Sbapt    }
1807268899Sbapt    free(args);
1808268899Sbapt}
1809268899Sbapt
1810268899Sbaptstatic char *
1811268899Sbaptcompile_arg(char **theptr, char *yyvaltag)
1812268899Sbapt{
1813268899Sbapt    char *p = *theptr;
1814268899Sbapt    struct mstring *c = msnew();
1815268899Sbapt    int i, j, n;
1816268899Sbapt    Value_t *offsets = NULL, maxoffset;
1817268899Sbapt    bucket **rhs;
1818268899Sbapt
1819268899Sbapt    maxoffset = 0;
1820268899Sbapt    n = 0;
1821268899Sbapt    for (i = nitems - 1; pitem[i]; --i)
1822268899Sbapt    {
1823268899Sbapt	n++;
1824268899Sbapt	if (pitem[i]->class != ARGUMENT)
1825268899Sbapt	    maxoffset++;
1826268899Sbapt    }
1827268899Sbapt    if (maxoffset > 0)
1828268899Sbapt    {
1829268899Sbapt	offsets = TMALLOC(Value_t, maxoffset + 1);
1830268899Sbapt	NO_SPACE(offsets);
1831272955Srodrigc
1832272955Srodrigc	for (j = 0, i++; i < nitems; i++)
1833272955Srodrigc	    if (pitem[i]->class != ARGUMENT)
1834272955Srodrigc		offsets[++j] = (Value_t) (i - nitems + 1);
1835268899Sbapt    }
1836268899Sbapt    rhs = pitem + nitems - 1;
1837268899Sbapt
1838268899Sbapt    if (yyvaltag)
1839268899Sbapt	msprintf(c, "yyval.%s = ", yyvaltag);
1840268899Sbapt    else
1841268899Sbapt	msprintf(c, "yyval = ");
1842268899Sbapt    while (*p)
1843268899Sbapt    {
1844268899Sbapt	if (*p == '$')
1845268899Sbapt	{
1846268899Sbapt	    char *tag = NULL;
1847268899Sbapt	    if (*++p == '<')
1848268899Sbapt		if (!(p = parse_id(++p, &tag)) || *p++ != '>')
1849268899Sbapt		    illegal_tag(rescan_lineno, NULL, NULL);
1850268899Sbapt	    if (isdigit(*p) || *p == '-')
1851268899Sbapt	    {
1852268899Sbapt		int val;
1853268899Sbapt		if (!(p = parse_int(p, &val)))
1854268899Sbapt		    dollar_error(rescan_lineno, NULL, NULL);
1855268899Sbapt		if (val <= 0)
1856268899Sbapt		    i = val - n;
1857268899Sbapt		else if (val > maxoffset)
1858268899Sbapt		{
1859268899Sbapt		    dollar_warning(rescan_lineno, val);
1860268899Sbapt		    i = val - maxoffset;
1861268899Sbapt		}
1862272955Srodrigc		else if (maxoffset > 0)
1863268899Sbapt		{
1864268899Sbapt		    i = offsets[val];
1865268899Sbapt		    if (!tag && !(tag = rhs[i]->tag) && havetags)
1866268899Sbapt			untyped_rhs(val, rhs[i]->name);
1867268899Sbapt		}
1868268899Sbapt		msprintf(c, "yystack.l_mark[%d]", i);
1869268899Sbapt		if (tag)
1870268899Sbapt		    msprintf(c, ".%s", tag);
1871268899Sbapt		else if (havetags)
1872268899Sbapt		    unknown_rhs(val);
1873268899Sbapt	    }
1874268899Sbapt	    else if (isalpha(*p) || *p == '_')
1875268899Sbapt	    {
1876268899Sbapt		char *arg;
1877268899Sbapt		if (!(p = parse_id(p, &arg)))
1878268899Sbapt		    dollar_error(rescan_lineno, NULL, NULL);
1879268899Sbapt		for (i = plhs[nrules]->args - 1; i >= 0; i--)
1880268899Sbapt		    if (arg == plhs[nrules]->argnames[i])
1881268899Sbapt			break;
1882268899Sbapt		if (i < 0)
1883268899Sbapt		    unknown_arg_warning(rescan_lineno, "$", arg, NULL, NULL);
1884268899Sbapt		else if (!tag)
1885268899Sbapt		    tag = plhs[nrules]->argtags[i];
1886268899Sbapt		msprintf(c, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1
1887268899Sbapt			 - n);
1888268899Sbapt		if (tag)
1889268899Sbapt		    msprintf(c, ".%s", tag);
1890268899Sbapt		else if (havetags)
1891268899Sbapt		    untyped_arg_warning(rescan_lineno, "$", arg);
1892268899Sbapt	    }
1893268899Sbapt	    else
1894268899Sbapt		dollar_error(rescan_lineno, NULL, NULL);
1895268899Sbapt	}
1896268899Sbapt	else if (*p == '@')
1897268899Sbapt	{
1898268899Sbapt	    at_error(rescan_lineno, NULL, NULL);
1899268899Sbapt	}
1900268899Sbapt	else
1901268899Sbapt	{
1902268899Sbapt	    if (*p == '\n')
1903268899Sbapt		rescan_lineno++;
1904268899Sbapt	    mputc(c, *p++);
1905268899Sbapt	}
1906268899Sbapt    }
1907268899Sbapt    *theptr = p;
1908268899Sbapt    if (maxoffset > 0)
1909268899Sbapt	FREE(offsets);
1910268899Sbapt    return msdone(c);
1911268899Sbapt}
1912268899Sbapt
1913268899Sbapt#define ARG_CACHE_SIZE	1024
1914268899Sbaptstatic struct arg_cache
1915268899Sbapt{
1916268899Sbapt    struct arg_cache *next;
1917268899Sbapt    char *code;
1918268899Sbapt    int rule;
1919268899Sbapt}
1920268899Sbapt *arg_cache[ARG_CACHE_SIZE];
1921268899Sbapt
1922268899Sbaptstatic int
1923268899Sbaptlookup_arg_cache(char *code)
1924268899Sbapt{
1925268899Sbapt    struct arg_cache *entry;
1926268899Sbapt
1927268899Sbapt    entry = arg_cache[strnshash(code) % ARG_CACHE_SIZE];
1928268899Sbapt    while (entry)
1929268899Sbapt    {
1930268899Sbapt	if (!strnscmp(entry->code, code))
1931268899Sbapt	    return entry->rule;
1932268899Sbapt	entry = entry->next;
1933268899Sbapt    }
1934268899Sbapt    return -1;
1935268899Sbapt}
1936268899Sbapt
1937268899Sbaptstatic void
1938268899Sbaptinsert_arg_cache(char *code, int rule)
1939268899Sbapt{
1940268899Sbapt    struct arg_cache *entry = NEW(struct arg_cache);
1941268899Sbapt    int i;
1942268899Sbapt
1943268899Sbapt    NO_SPACE(entry);
1944268899Sbapt    i = strnshash(code) % ARG_CACHE_SIZE;
1945268899Sbapt    entry->code = code;
1946268899Sbapt    entry->rule = rule;
1947268899Sbapt    entry->next = arg_cache[i];
1948268899Sbapt    arg_cache[i] = entry;
1949268899Sbapt}
1950268899Sbapt
1951268899Sbaptstatic void
1952268899Sbaptclean_arg_cache(void)
1953268899Sbapt{
1954268899Sbapt    struct arg_cache *e, *t;
1955268899Sbapt    int i;
1956268899Sbapt
1957268899Sbapt    for (i = 0; i < ARG_CACHE_SIZE; i++)
1958268899Sbapt    {
1959268899Sbapt	for (e = arg_cache[i]; (t = e); e = e->next, FREE(t))
1960268899Sbapt	    free(e->code);
1961268899Sbapt	arg_cache[i] = NULL;
1962268899Sbapt    }
1963268899Sbapt}
1964268899Sbapt#endif
1965268899Sbapt
1966268899Sbaptstatic void
1967234949Sbaptadvance_to_start(void)
1968234949Sbapt{
1969234949Sbapt    int c;
1970234949Sbapt    bucket *bp;
1971234949Sbapt    char *s_cptr;
1972234949Sbapt    int s_lineno;
1973268899Sbapt#if defined(YYBTYACC)
1974268899Sbapt    char *args = NULL;
1975268899Sbapt    int argslen = 0;
1976268899Sbapt#endif
1977234949Sbapt
1978234949Sbapt    for (;;)
1979234949Sbapt    {
1980234949Sbapt	c = nextc();
1981234949Sbapt	if (c != '%')
1982234949Sbapt	    break;
1983234949Sbapt	s_cptr = cptr;
1984234949Sbapt	switch (keyword())
1985234949Sbapt	{
1986234949Sbapt	case MARK:
1987234949Sbapt	    no_grammar();
1988234949Sbapt
1989234949Sbapt	case TEXT:
1990234949Sbapt	    copy_text();
1991234949Sbapt	    break;
1992234949Sbapt
1993234949Sbapt	case START:
1994234949Sbapt	    declare_start();
1995234949Sbapt	    break;
1996234949Sbapt
1997234949Sbapt	default:
1998234949Sbapt	    syntax_error(lineno, line, s_cptr);
1999234949Sbapt	}
2000234949Sbapt    }
2001234949Sbapt
2002234949Sbapt    c = nextc();
2003234949Sbapt    if (!isalpha(c) && c != '_' && c != '.' && c != '_')
2004234949Sbapt	syntax_error(lineno, line, cptr);
2005234949Sbapt    bp = get_name();
2006234949Sbapt    if (goal == 0)
2007234949Sbapt    {
2008234949Sbapt	if (bp->class == TERM)
2009234949Sbapt	    terminal_start(bp->name);
2010234949Sbapt	goal = bp;
2011234949Sbapt    }
2012234949Sbapt
2013234949Sbapt    s_lineno = lineno;
2014234949Sbapt    c = nextc();
2015234949Sbapt    if (c == EOF)
2016234949Sbapt	unexpected_EOF();
2017268899Sbapt    rescan_lineno = lineno;	/* line# for possible inherited args rescan */
2018268899Sbapt#if defined(YYBTYACC)
2019268899Sbapt    if (c == L_PAREN)
2020268899Sbapt    {
2021268899Sbapt	++cptr;
2022268899Sbapt	args = copy_args(&argslen);
2023268899Sbapt	NO_SPACE(args);
2024268899Sbapt	c = nextc();
2025268899Sbapt    }
2026268899Sbapt#endif
2027234949Sbapt    if (c != ':')
2028234949Sbapt	syntax_error(lineno, line, cptr);
2029234949Sbapt    start_rule(bp, s_lineno);
2030268899Sbapt#if defined(YYBTYACC)
2031268899Sbapt    parse_arginfo(bp, args, argslen);
2032268899Sbapt#endif
2033234949Sbapt    ++cptr;
2034234949Sbapt}
2035234949Sbapt
2036234949Sbaptstatic void
2037234949Sbaptstart_rule(bucket *bp, int s_lineno)
2038234949Sbapt{
2039234949Sbapt    if (bp->class == TERM)
2040234949Sbapt	terminal_lhs(s_lineno);
2041234949Sbapt    bp->class = NONTERM;
2042268899Sbapt    if (!bp->index)
2043268899Sbapt	bp->index = nrules;
2044234949Sbapt    if (nrules >= maxrules)
2045234949Sbapt	expand_rules();
2046234949Sbapt    plhs[nrules] = bp;
2047234949Sbapt    rprec[nrules] = UNDEFINED;
2048234949Sbapt    rassoc[nrules] = TOKEN;
2049234949Sbapt}
2050234949Sbapt
2051234949Sbaptstatic void
2052234949Sbaptend_rule(void)
2053234949Sbapt{
2054234949Sbapt    int i;
2055234949Sbapt
2056234949Sbapt    if (!last_was_action && plhs[nrules]->tag)
2057234949Sbapt    {
2058234949Sbapt	if (pitem[nitems - 1])
2059234949Sbapt	{
2060234949Sbapt	    for (i = nitems - 1; (i > 0) && pitem[i]; --i)
2061234949Sbapt		continue;
2062234949Sbapt	    if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
2063234949Sbapt		default_action_warning();
2064234949Sbapt	}
2065234949Sbapt	else
2066234949Sbapt	{
2067234949Sbapt	    default_action_warning();
2068234949Sbapt	}
2069234949Sbapt    }
2070234949Sbapt
2071234949Sbapt    last_was_action = 0;
2072234949Sbapt    if (nitems >= maxitems)
2073234949Sbapt	expand_items();
2074234949Sbapt    pitem[nitems] = 0;
2075234949Sbapt    ++nitems;
2076234949Sbapt    ++nrules;
2077234949Sbapt}
2078234949Sbapt
2079234949Sbaptstatic void
2080234949Sbaptinsert_empty_rule(void)
2081234949Sbapt{
2082234949Sbapt    bucket *bp, **bpp;
2083234949Sbapt
2084234949Sbapt    assert(cache);
2085234949Sbapt    sprintf(cache, "$$%d", ++gensym);
2086234949Sbapt    bp = make_bucket(cache);
2087234949Sbapt    last_symbol->next = bp;
2088234949Sbapt    last_symbol = bp;
2089234949Sbapt    bp->tag = plhs[nrules]->tag;
2090268899Sbapt    bp->class = ACTION;
2091268899Sbapt#if defined(YYBTYACC)
2092268899Sbapt    bp->args = 0;
2093268899Sbapt#endif
2094234949Sbapt
2095268899Sbapt    nitems = (Value_t) (nitems + 2);
2096268899Sbapt    if (nitems > maxitems)
2097234949Sbapt	expand_items();
2098234949Sbapt    bpp = pitem + nitems - 1;
2099234949Sbapt    *bpp-- = bp;
2100234949Sbapt    while ((bpp[0] = bpp[-1]) != 0)
2101234949Sbapt	--bpp;
2102234949Sbapt
2103234949Sbapt    if (++nrules >= maxrules)
2104234949Sbapt	expand_rules();
2105234949Sbapt    plhs[nrules] = plhs[nrules - 1];
2106234949Sbapt    plhs[nrules - 1] = bp;
2107234949Sbapt    rprec[nrules] = rprec[nrules - 1];
2108234949Sbapt    rprec[nrules - 1] = 0;
2109234949Sbapt    rassoc[nrules] = rassoc[nrules - 1];
2110234949Sbapt    rassoc[nrules - 1] = TOKEN;
2111234949Sbapt}
2112234949Sbapt
2113268899Sbapt#if defined(YYBTYACC)
2114268899Sbaptstatic char *
2115268899Sbaptinsert_arg_rule(char *arg, char *tag)
2116268899Sbapt{
2117268899Sbapt    int line_number = rescan_lineno;
2118268899Sbapt    char *code = compile_arg(&arg, tag);
2119268899Sbapt    int rule = lookup_arg_cache(code);
2120268899Sbapt    FILE *f = action_file;
2121268899Sbapt
2122268899Sbapt    if (rule < 0)
2123268899Sbapt    {
2124268899Sbapt	rule = nrules;
2125268899Sbapt	insert_arg_cache(code, rule);
2126268899Sbapt	fprintf(f, "case %d:\n", rule - 2);
2127268899Sbapt	if (!lflag)
2128268899Sbapt	    fprintf(f, line_format, line_number, input_file_name);
2129268899Sbapt	fprintf(f, "%s;\n", code);
2130268899Sbapt	fprintf(f, "break;\n");
2131268899Sbapt	insert_empty_rule();
2132268899Sbapt	plhs[rule]->tag = tag;
2133268899Sbapt	plhs[rule]->class = ARGUMENT;
2134268899Sbapt    }
2135268899Sbapt    else
2136268899Sbapt    {
2137268899Sbapt	if (++nitems > maxitems)
2138268899Sbapt	    expand_items();
2139268899Sbapt	pitem[nitems - 1] = plhs[rule];
2140268899Sbapt	free(code);
2141268899Sbapt    }
2142268899Sbapt    return arg + 1;
2143268899Sbapt}
2144268899Sbapt#endif
2145268899Sbapt
2146234949Sbaptstatic void
2147234949Sbaptadd_symbol(void)
2148234949Sbapt{
2149234949Sbapt    int c;
2150234949Sbapt    bucket *bp;
2151234949Sbapt    int s_lineno = lineno;
2152268899Sbapt#if defined(YYBTYACC)
2153268899Sbapt    char *args = NULL;
2154268899Sbapt    int argslen = 0;
2155268899Sbapt#endif
2156234949Sbapt
2157234949Sbapt    c = *cptr;
2158234949Sbapt    if (c == '\'' || c == '"')
2159234949Sbapt	bp = get_literal();
2160234949Sbapt    else
2161234949Sbapt	bp = get_name();
2162234949Sbapt
2163234949Sbapt    c = nextc();
2164268899Sbapt    rescan_lineno = lineno;	/* line# for possible inherited args rescan */
2165268899Sbapt#if defined(YYBTYACC)
2166268899Sbapt    if (c == L_PAREN)
2167268899Sbapt    {
2168268899Sbapt	++cptr;
2169268899Sbapt	args = copy_args(&argslen);
2170268899Sbapt	NO_SPACE(args);
2171268899Sbapt	c = nextc();
2172268899Sbapt    }
2173268899Sbapt#endif
2174234949Sbapt    if (c == ':')
2175234949Sbapt    {
2176234949Sbapt	end_rule();
2177234949Sbapt	start_rule(bp, s_lineno);
2178268899Sbapt#if defined(YYBTYACC)
2179268899Sbapt	parse_arginfo(bp, args, argslen);
2180268899Sbapt#endif
2181234949Sbapt	++cptr;
2182234949Sbapt	return;
2183234949Sbapt    }
2184234949Sbapt
2185234949Sbapt    if (last_was_action)
2186234949Sbapt	insert_empty_rule();
2187234949Sbapt    last_was_action = 0;
2188234949Sbapt
2189268899Sbapt#if defined(YYBTYACC)
2190268899Sbapt    if (bp->args < 0)
2191268899Sbapt	bp->args = argslen;
2192268899Sbapt    if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL)
2193268899Sbapt    {
2194268899Sbapt	int i;
2195268899Sbapt	if (plhs[nrules]->args != bp->args)
2196268899Sbapt	    wrong_number_args_warning("default ", bp->name);
2197268899Sbapt	for (i = bp->args - 1; i >= 0; i--)
2198268899Sbapt	    if (plhs[nrules]->argtags[i] != bp->argtags[i])
2199268899Sbapt		wrong_type_for_arg_warning(i + 1, bp->name);
2200268899Sbapt    }
2201268899Sbapt    else if (bp->args != argslen)
2202268899Sbapt	wrong_number_args_warning("", bp->name);
2203268899Sbapt    if (bp->args > 0 && argslen > 0)
2204268899Sbapt    {
2205268899Sbapt	char *ap;
2206268899Sbapt	int i;
2207268899Sbapt	for (ap = args, i = 0; i < argslen; i++)
2208268899Sbapt	    ap = insert_arg_rule(ap, bp->argtags[i]);
2209268899Sbapt	free(args);
2210268899Sbapt    }
2211268899Sbapt#endif /* defined(YYBTYACC) */
2212268899Sbapt
2213234949Sbapt    if (++nitems > maxitems)
2214234949Sbapt	expand_items();
2215234949Sbapt    pitem[nitems - 1] = bp;
2216234949Sbapt}
2217234949Sbapt
2218234949Sbaptstatic void
2219234949Sbaptcopy_action(void)
2220234949Sbapt{
2221234949Sbapt    int c;
2222268899Sbapt    int i, j, n;
2223234949Sbapt    int depth;
2224268899Sbapt#if defined(YYBTYACC)
2225268899Sbapt    int trialaction = 0;
2226268899Sbapt    int haveyyval = 0;
2227268899Sbapt#endif
2228234949Sbapt    char *tag;
2229234949Sbapt    FILE *f = action_file;
2230234949Sbapt    int a_lineno = lineno;
2231234949Sbapt    char *a_line = dup_line();
2232234949Sbapt    char *a_cptr = a_line + (cptr - line);
2233268899Sbapt    Value_t *offsets = NULL, maxoffset;
2234268899Sbapt    bucket **rhs;
2235234949Sbapt
2236234949Sbapt    if (last_was_action)
2237234949Sbapt	insert_empty_rule();
2238234949Sbapt    last_was_action = 1;
2239234949Sbapt
2240234949Sbapt    fprintf(f, "case %d:\n", nrules - 2);
2241268899Sbapt#if defined(YYBTYACC)
2242268899Sbapt    if (backtrack)
2243268899Sbapt    {
2244268899Sbapt	if (*cptr != L_BRAC)
2245268899Sbapt	    fprintf(f, "  if (!yytrial)\n");
2246268899Sbapt	else
2247268899Sbapt	    trialaction = 1;
2248268899Sbapt    }
2249268899Sbapt#endif
2250234949Sbapt    if (!lflag)
2251234949Sbapt	fprintf(f, line_format, lineno, input_file_name);
2252234949Sbapt    if (*cptr == '=')
2253234949Sbapt	++cptr;
2254234949Sbapt
2255234949Sbapt    /* avoid putting curly-braces in first column, to ease editing */
2256234949Sbapt    if (*after_blanks(cptr) == L_CURL)
2257234949Sbapt    {
2258234949Sbapt	putc('\t', f);
2259234949Sbapt	cptr = after_blanks(cptr);
2260234949Sbapt    }
2261234949Sbapt
2262268899Sbapt    maxoffset = 0;
2263234949Sbapt    n = 0;
2264234949Sbapt    for (i = nitems - 1; pitem[i]; --i)
2265268899Sbapt    {
2266234949Sbapt	++n;
2267268899Sbapt	if (pitem[i]->class != ARGUMENT)
2268268899Sbapt	    maxoffset++;
2269268899Sbapt    }
2270268899Sbapt    if (maxoffset > 0)
2271268899Sbapt    {
2272268899Sbapt	offsets = TMALLOC(Value_t, maxoffset + 1);
2273268899Sbapt	NO_SPACE(offsets);
2274272955Srodrigc
2275272955Srodrigc	for (j = 0, i++; i < nitems; i++)
2276268899Sbapt	{
2277272955Srodrigc	    if (pitem[i]->class != ARGUMENT)
2278272955Srodrigc	    {
2279272955Srodrigc		offsets[++j] = (Value_t) (i - nitems + 1);
2280272955Srodrigc	    }
2281268899Sbapt	}
2282268899Sbapt    }
2283268899Sbapt    rhs = pitem + nitems - 1;
2284234949Sbapt
2285234949Sbapt    depth = 0;
2286234949Sbapt  loop:
2287234949Sbapt    c = *cptr;
2288234949Sbapt    if (c == '$')
2289234949Sbapt    {
2290234949Sbapt	if (cptr[1] == '<')
2291234949Sbapt	{
2292234949Sbapt	    int d_lineno = lineno;
2293234949Sbapt	    char *d_line = dup_line();
2294234949Sbapt	    char *d_cptr = d_line + (cptr - line);
2295234949Sbapt
2296234949Sbapt	    ++cptr;
2297234949Sbapt	    tag = get_tag();
2298234949Sbapt	    c = *cptr;
2299234949Sbapt	    if (c == '$')
2300234949Sbapt	    {
2301234949Sbapt		fprintf(f, "yyval.%s", tag);
2302234949Sbapt		++cptr;
2303234949Sbapt		FREE(d_line);
2304234949Sbapt		goto loop;
2305234949Sbapt	    }
2306234949Sbapt	    else if (isdigit(c))
2307234949Sbapt	    {
2308234949Sbapt		i = get_number();
2309268899Sbapt		if (i == 0)
2310268899Sbapt		    fprintf(f, "yystack.l_mark[%d].%s", -n, tag);
2311268899Sbapt		else if (i > maxoffset)
2312268899Sbapt		{
2313234949Sbapt		    dollar_warning(d_lineno, i);
2314268899Sbapt		    fprintf(f, "yystack.l_mark[%d].%s", i - maxoffset, tag);
2315268899Sbapt		}
2316268899Sbapt		else if (offsets)
2317268899Sbapt		    fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2318234949Sbapt		FREE(d_line);
2319234949Sbapt		goto loop;
2320234949Sbapt	    }
2321234949Sbapt	    else if (c == '-' && isdigit(UCH(cptr[1])))
2322234949Sbapt	    {
2323234949Sbapt		++cptr;
2324234949Sbapt		i = -get_number() - n;
2325234949Sbapt		fprintf(f, "yystack.l_mark[%d].%s", i, tag);
2326234949Sbapt		FREE(d_line);
2327234949Sbapt		goto loop;
2328234949Sbapt	    }
2329268899Sbapt#if defined(YYBTYACC)
2330268899Sbapt	    else if (isalpha(c) || c == '_')
2331268899Sbapt	    {
2332268899Sbapt		char *arg = scan_id();
2333268899Sbapt		for (i = plhs[nrules]->args - 1; i >= 0; i--)
2334268899Sbapt		    if (arg == plhs[nrules]->argnames[i])
2335268899Sbapt			break;
2336268899Sbapt		if (i < 0)
2337268899Sbapt		    unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr);
2338268899Sbapt		fprintf(f, "yystack.l_mark[%d].%s", i - plhs[nrules]->args +
2339268899Sbapt			1 - n, tag);
2340268899Sbapt		FREE(d_line);
2341268899Sbapt		goto loop;
2342268899Sbapt	    }
2343268899Sbapt#endif
2344234949Sbapt	    else
2345234949Sbapt		dollar_error(d_lineno, d_line, d_cptr);
2346234949Sbapt	}
2347234949Sbapt	else if (cptr[1] == '$')
2348234949Sbapt	{
2349268899Sbapt	    if (havetags)
2350234949Sbapt	    {
2351234949Sbapt		tag = plhs[nrules]->tag;
2352234949Sbapt		if (tag == 0)
2353234949Sbapt		    untyped_lhs();
2354234949Sbapt		fprintf(f, "yyval.%s", tag);
2355234949Sbapt	    }
2356234949Sbapt	    else
2357234949Sbapt		fprintf(f, "yyval");
2358234949Sbapt	    cptr += 2;
2359268899Sbapt#if defined(YYBTYACC)
2360268899Sbapt	    haveyyval = 1;
2361268899Sbapt#endif
2362234949Sbapt	    goto loop;
2363234949Sbapt	}
2364234949Sbapt	else if (isdigit(UCH(cptr[1])))
2365234949Sbapt	{
2366234949Sbapt	    ++cptr;
2367234949Sbapt	    i = get_number();
2368272955Srodrigc	    if (havetags && offsets)
2369234949Sbapt	    {
2370268899Sbapt		if (i <= 0 || i > maxoffset)
2371234949Sbapt		    unknown_rhs(i);
2372268899Sbapt		tag = rhs[offsets[i]]->tag;
2373234949Sbapt		if (tag == 0)
2374268899Sbapt		    untyped_rhs(i, rhs[offsets[i]]->name);
2375268899Sbapt		fprintf(f, "yystack.l_mark[%d].%s", offsets[i], tag);
2376234949Sbapt	    }
2377234949Sbapt	    else
2378234949Sbapt	    {
2379268899Sbapt		if (i == 0)
2380268899Sbapt		    fprintf(f, "yystack.l_mark[%d]", -n);
2381268899Sbapt		else if (i > maxoffset)
2382268899Sbapt		{
2383234949Sbapt		    dollar_warning(lineno, i);
2384268899Sbapt		    fprintf(f, "yystack.l_mark[%d]", i - maxoffset);
2385268899Sbapt		}
2386268899Sbapt		else if (offsets)
2387268899Sbapt		    fprintf(f, "yystack.l_mark[%d]", offsets[i]);
2388234949Sbapt	    }
2389234949Sbapt	    goto loop;
2390234949Sbapt	}
2391234949Sbapt	else if (cptr[1] == '-')
2392234949Sbapt	{
2393234949Sbapt	    cptr += 2;
2394234949Sbapt	    i = get_number();
2395268899Sbapt	    if (havetags)
2396234949Sbapt		unknown_rhs(-i);
2397234949Sbapt	    fprintf(f, "yystack.l_mark[%d]", -i - n);
2398234949Sbapt	    goto loop;
2399234949Sbapt	}
2400268899Sbapt#if defined(YYBTYACC)
2401268899Sbapt	else if (isalpha(cptr[1]) || cptr[1] == '_')
2402268899Sbapt	{
2403268899Sbapt	    char *arg;
2404268899Sbapt	    ++cptr;
2405268899Sbapt	    arg = scan_id();
2406268899Sbapt	    for (i = plhs[nrules]->args - 1; i >= 0; i--)
2407268899Sbapt		if (arg == plhs[nrules]->argnames[i])
2408268899Sbapt		    break;
2409268899Sbapt	    if (i < 0)
2410268899Sbapt		unknown_arg_warning(lineno, "$", arg, line, cptr);
2411268899Sbapt	    tag = (i < 0 ? NULL : plhs[nrules]->argtags[i]);
2412268899Sbapt	    fprintf(f, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 - n);
2413268899Sbapt	    if (tag)
2414268899Sbapt		fprintf(f, ".%s", tag);
2415268899Sbapt	    else if (havetags)
2416268899Sbapt		untyped_arg_warning(lineno, "$", arg);
2417268899Sbapt	    goto loop;
2418268899Sbapt	}
2419268899Sbapt#endif
2420234949Sbapt    }
2421268899Sbapt#if defined(YYBTYACC)
2422268899Sbapt    if (c == '@')
2423268899Sbapt    {
2424268899Sbapt	if (!locations)
2425268899Sbapt	{
2426268899Sbapt	    int l_lineno = lineno;
2427268899Sbapt	    char *l_line = dup_line();
2428268899Sbapt	    char *l_cptr = l_line + (cptr - line);
2429268899Sbapt	    syntax_error(l_lineno, l_line, l_cptr);
2430268899Sbapt	}
2431268899Sbapt	if (cptr[1] == '$')
2432268899Sbapt	{
2433268899Sbapt	    fprintf(f, "yyloc");
2434268899Sbapt	    cptr += 2;
2435268899Sbapt	    goto loop;
2436268899Sbapt	}
2437268899Sbapt	else if (isdigit(UCH(cptr[1])))
2438268899Sbapt	{
2439268899Sbapt	    ++cptr;
2440268899Sbapt	    i = get_number();
2441268899Sbapt	    if (i == 0)
2442268899Sbapt		fprintf(f, "yystack.p_mark[%d]", -n);
2443268899Sbapt	    else if (i > maxoffset)
2444268899Sbapt	    {
2445268899Sbapt		at_warning(lineno, i);
2446268899Sbapt		fprintf(f, "yystack.p_mark[%d]", i - maxoffset);
2447268899Sbapt	    }
2448268899Sbapt	    else if (offsets)
2449268899Sbapt		fprintf(f, "yystack.p_mark[%d]", offsets[i]);
2450268899Sbapt	    goto loop;
2451268899Sbapt	}
2452268899Sbapt    }
2453268899Sbapt#endif
2454234949Sbapt    if (isalpha(c) || c == '_' || c == '$')
2455234949Sbapt    {
2456234949Sbapt	do
2457234949Sbapt	{
2458234949Sbapt	    putc(c, f);
2459234949Sbapt	    c = *++cptr;
2460234949Sbapt	}
2461234949Sbapt	while (isalnum(c) || c == '_' || c == '$');
2462234949Sbapt	goto loop;
2463234949Sbapt    }
2464268899Sbapt    ++cptr;
2465268899Sbapt#if defined(YYBTYACC)
2466268899Sbapt    if (backtrack)
2467268899Sbapt    {
2468268899Sbapt	if (trialaction && c == L_BRAC && depth == 0)
2469268899Sbapt	{
2470268899Sbapt	    ++depth;
2471268899Sbapt	    putc(L_CURL, f);
2472268899Sbapt	    goto loop;
2473268899Sbapt	}
2474268899Sbapt	if (trialaction && c == R_BRAC && depth == 1)
2475268899Sbapt	{
2476268899Sbapt	    --depth;
2477268899Sbapt	    putc(R_CURL, f);
2478268899Sbapt	    c = nextc();
2479268899Sbapt	    if (c == L_BRAC && !haveyyval)
2480268899Sbapt	    {
2481268899Sbapt		goto loop;
2482268899Sbapt	    }
2483268899Sbapt	    if (c == L_CURL && !haveyyval)
2484268899Sbapt	    {
2485268899Sbapt		fprintf(f, "  if (!yytrial)\n");
2486268899Sbapt		if (!lflag)
2487268899Sbapt		    fprintf(f, line_format, lineno, input_file_name);
2488268899Sbapt		trialaction = 0;
2489268899Sbapt		goto loop;
2490268899Sbapt	    }
2491268899Sbapt	    fprintf(f, "\nbreak;\n");
2492268899Sbapt	    FREE(a_line);
2493268899Sbapt	    if (maxoffset > 0)
2494268899Sbapt		FREE(offsets);
2495268899Sbapt	    return;
2496268899Sbapt	}
2497268899Sbapt    }
2498268899Sbapt#endif
2499234949Sbapt    putc(c, f);
2500234949Sbapt    switch (c)
2501234949Sbapt    {
2502234949Sbapt    case '\n':
2503234949Sbapt	get_line();
2504234949Sbapt	if (line)
2505234949Sbapt	    goto loop;
2506234949Sbapt	unterminated_action(a_lineno, a_line, a_cptr);
2507234949Sbapt
2508234949Sbapt    case ';':
2509234949Sbapt	if (depth > 0)
2510234949Sbapt	    goto loop;
2511234949Sbapt	fprintf(f, "\nbreak;\n");
2512234949Sbapt	free(a_line);
2513268899Sbapt	if (maxoffset > 0)
2514268899Sbapt	    FREE(offsets);
2515234949Sbapt	return;
2516234949Sbapt
2517268899Sbapt#if defined(YYBTYACC)
2518268899Sbapt    case L_BRAC:
2519268899Sbapt	if (backtrack)
2520268899Sbapt	    ++depth;
2521268899Sbapt	goto loop;
2522268899Sbapt
2523268899Sbapt    case R_BRAC:
2524268899Sbapt	if (backtrack)
2525268899Sbapt	    --depth;
2526268899Sbapt	goto loop;
2527268899Sbapt#endif
2528268899Sbapt
2529234949Sbapt    case L_CURL:
2530234949Sbapt	++depth;
2531234949Sbapt	goto loop;
2532234949Sbapt
2533234949Sbapt    case R_CURL:
2534234949Sbapt	if (--depth > 0)
2535234949Sbapt	    goto loop;
2536268899Sbapt#if defined(YYBTYACC)
2537268899Sbapt	if (backtrack)
2538268899Sbapt	{
2539268899Sbapt	    c = nextc();
2540268899Sbapt	    if (c == L_BRAC && !haveyyval)
2541268899Sbapt	    {
2542268899Sbapt		trialaction = 1;
2543268899Sbapt		goto loop;
2544268899Sbapt	    }
2545268899Sbapt	    if (c == L_CURL && !haveyyval)
2546268899Sbapt	    {
2547268899Sbapt		fprintf(f, "  if (!yytrial)\n");
2548268899Sbapt		if (!lflag)
2549268899Sbapt		    fprintf(f, line_format, lineno, input_file_name);
2550268899Sbapt		goto loop;
2551268899Sbapt	    }
2552268899Sbapt	}
2553268899Sbapt#endif
2554234949Sbapt	fprintf(f, "\nbreak;\n");
2555234949Sbapt	free(a_line);
2556268899Sbapt	if (maxoffset > 0)
2557268899Sbapt	    FREE(offsets);
2558234949Sbapt	return;
2559234949Sbapt
2560234949Sbapt    case '\'':
2561234949Sbapt    case '"':
2562234949Sbapt	{
2563268899Sbapt	    char *s = copy_string(c);
2564268899Sbapt	    fputs(s, f);
2565268899Sbapt	    free(s);
2566268899Sbapt	}
2567268899Sbapt	goto loop;
2568234949Sbapt
2569268899Sbapt    case '/':
2570268899Sbapt	{
2571268899Sbapt	    char *s = copy_comment();
2572268899Sbapt	    fputs(s, f);
2573268899Sbapt	    free(s);
2574268899Sbapt	}
2575268899Sbapt	goto loop;
2576268899Sbapt
2577268899Sbapt    default:
2578268899Sbapt	goto loop;
2579268899Sbapt    }
2580268899Sbapt}
2581268899Sbapt
2582268899Sbapt#if defined(YYBTYACC)
2583268899Sbaptstatic void
2584268899Sbaptcopy_destructor(void)
2585268899Sbapt{
2586268899Sbapt    int c;
2587268899Sbapt    int depth;
2588268899Sbapt    char *tag;
2589268899Sbapt    bucket *bp;
2590268899Sbapt    struct mstring *destructor_text = msnew();
2591268899Sbapt    char *code_text;
2592268899Sbapt    int a_lineno;
2593268899Sbapt    char *a_line;
2594268899Sbapt    char *a_cptr;
2595268899Sbapt
2596268899Sbapt    if (!lflag)
2597268899Sbapt	msprintf(destructor_text, line_format, lineno, input_file_name);
2598268899Sbapt
2599268899Sbapt    cptr = after_blanks(cptr);
2600268899Sbapt    if (*cptr == L_CURL)
2601268899Sbapt	/* avoid putting curly-braces in first column, to ease editing */
2602268899Sbapt	mputc(destructor_text, '\t');
2603268899Sbapt    else
2604268899Sbapt	syntax_error(lineno, line, cptr);
2605268899Sbapt
2606268899Sbapt    a_lineno = lineno;
2607268899Sbapt    a_line = dup_line();
2608268899Sbapt    a_cptr = a_line + (cptr - line);
2609268899Sbapt
2610268899Sbapt    depth = 0;
2611268899Sbapt  loop:
2612268899Sbapt    c = *cptr;
2613268899Sbapt    if (c == '$')
2614268899Sbapt    {
2615268899Sbapt	if (cptr[1] == '<')
2616268899Sbapt	{
2617268899Sbapt	    int d_lineno = lineno;
2618268899Sbapt	    char *d_line = dup_line();
2619268899Sbapt	    char *d_cptr = d_line + (cptr - line);
2620268899Sbapt
2621268899Sbapt	    ++cptr;
2622268899Sbapt	    tag = get_tag();
2623268899Sbapt	    c = *cptr;
2624268899Sbapt	    if (c == '$')
2625234949Sbapt	    {
2626268899Sbapt		msprintf(destructor_text, "(*val).%s", tag);
2627268899Sbapt		++cptr;
2628268899Sbapt		FREE(d_line);
2629268899Sbapt		goto loop;
2630268899Sbapt	    }
2631268899Sbapt	    else
2632268899Sbapt		dollar_error(d_lineno, d_line, d_cptr);
2633268899Sbapt	}
2634268899Sbapt	else if (cptr[1] == '$')
2635268899Sbapt	{
2636268899Sbapt	    /* process '$$' later; replacement is context dependent */
2637268899Sbapt	    msprintf(destructor_text, "$$");
2638268899Sbapt	    cptr += 2;
2639268899Sbapt	    goto loop;
2640268899Sbapt	}
2641268899Sbapt    }
2642268899Sbapt    if (c == '@' && cptr[1] == '$')
2643268899Sbapt    {
2644268899Sbapt	if (!locations)
2645268899Sbapt	{
2646268899Sbapt	    int l_lineno = lineno;
2647268899Sbapt	    char *l_line = dup_line();
2648268899Sbapt	    char *l_cptr = l_line + (cptr - line);
2649268899Sbapt	    syntax_error(l_lineno, l_line, l_cptr);
2650268899Sbapt	}
2651268899Sbapt	msprintf(destructor_text, "(*loc)");
2652268899Sbapt	cptr += 2;
2653268899Sbapt	goto loop;
2654268899Sbapt    }
2655268899Sbapt    if (isalpha(c) || c == '_' || c == '$')
2656268899Sbapt    {
2657268899Sbapt	do
2658268899Sbapt	{
2659268899Sbapt	    mputc(destructor_text, c);
2660268899Sbapt	    c = *++cptr;
2661268899Sbapt	}
2662268899Sbapt	while (isalnum(c) || c == '_' || c == '$');
2663268899Sbapt	goto loop;
2664268899Sbapt    }
2665268899Sbapt    ++cptr;
2666268899Sbapt    mputc(destructor_text, c);
2667268899Sbapt    switch (c)
2668268899Sbapt    {
2669268899Sbapt    case '\n':
2670268899Sbapt	get_line();
2671268899Sbapt	if (line)
2672268899Sbapt	    goto loop;
2673268899Sbapt	unterminated_action(a_lineno, a_line, a_cptr);
2674268899Sbapt
2675268899Sbapt    case L_CURL:
2676268899Sbapt	++depth;
2677268899Sbapt	goto loop;
2678268899Sbapt
2679268899Sbapt    case R_CURL:
2680268899Sbapt	if (--depth > 0)
2681268899Sbapt	    goto loop;
2682268899Sbapt	goto process_symbols;
2683268899Sbapt
2684268899Sbapt    case '\'':
2685268899Sbapt    case '"':
2686268899Sbapt	{
2687268899Sbapt	    char *s = copy_string(c);
2688268899Sbapt	    msprintf(destructor_text, "%s", s);
2689268899Sbapt	    free(s);
2690268899Sbapt	}
2691268899Sbapt	goto loop;
2692268899Sbapt
2693268899Sbapt    case '/':
2694268899Sbapt	{
2695268899Sbapt	    char *s = copy_comment();
2696268899Sbapt	    msprintf(destructor_text, "%s", s);
2697268899Sbapt	    free(s);
2698268899Sbapt	}
2699268899Sbapt	goto loop;
2700268899Sbapt
2701268899Sbapt    default:
2702268899Sbapt	goto loop;
2703268899Sbapt    }
2704268899Sbapt  process_symbols:
2705268899Sbapt    code_text = msdone(destructor_text);
2706268899Sbapt    for (;;)
2707268899Sbapt    {
2708268899Sbapt	c = nextc();
2709268899Sbapt	if (c == EOF)
2710268899Sbapt	    unexpected_EOF();
2711268899Sbapt	if (c == '<')
2712268899Sbapt	{
2713268899Sbapt	    if (cptr[1] == '>')
2714268899Sbapt	    {			/* "no semantic type" default destructor */
2715268899Sbapt		cptr += 2;
2716268899Sbapt		if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL)
2717234949Sbapt		{
2718268899Sbapt		    static char untyped_default[] = "<>";
2719268899Sbapt		    bp = make_bucket("untyped default");
2720268899Sbapt		    bp->tag = untyped_default;
2721268899Sbapt		    default_destructor[UNTYPED_DEFAULT] = bp;
2722234949Sbapt		}
2723268899Sbapt		if (bp->destructor != NULL)
2724268899Sbapt		    destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2725268899Sbapt		else
2726268899Sbapt		    /* replace "$$" with "(*val)" in destructor code */
2727268899Sbapt		    bp->destructor = process_destructor_XX(code_text, NULL);
2728268899Sbapt	    }
2729268899Sbapt	    else if (cptr[1] == '*' && cptr[2] == '>')
2730268899Sbapt	    {			/* "no per-symbol or per-type" default destructor */
2731268899Sbapt		cptr += 3;
2732268899Sbapt		if ((bp = default_destructor[TYPED_DEFAULT]) == NULL)
2733234949Sbapt		{
2734268899Sbapt		    static char typed_default[] = "<*>";
2735268899Sbapt		    bp = make_bucket("typed default");
2736268899Sbapt		    bp->tag = typed_default;
2737268899Sbapt		    default_destructor[TYPED_DEFAULT] = bp;
2738234949Sbapt		}
2739268899Sbapt		if (bp->destructor != NULL)
2740268899Sbapt		    destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2741268899Sbapt		else
2742268899Sbapt		{
2743268899Sbapt		    /* postpone re-processing destructor $$s until end of grammar spec */
2744268899Sbapt		    bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2745268899Sbapt		    NO_SPACE(bp->destructor);
2746268899Sbapt		    strcpy(bp->destructor, code_text);
2747268899Sbapt		}
2748234949Sbapt	    }
2749268899Sbapt	    else
2750268899Sbapt	    {			/* "semantic type" default destructor */
2751268899Sbapt		tag = get_tag();
2752268899Sbapt		bp = lookup_type_destructor(tag);
2753268899Sbapt		if (bp->destructor != NULL)
2754268899Sbapt		    destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2755268899Sbapt		else
2756268899Sbapt		    /* replace "$$" with "(*val).tag" in destructor code */
2757268899Sbapt		    bp->destructor = process_destructor_XX(code_text, tag);
2758268899Sbapt	    }
2759234949Sbapt	}
2760268899Sbapt	else if (isalpha(c) || c == '_' || c == '.' || c == '$')
2761268899Sbapt	{			/* "symbol" destructor */
2762268899Sbapt	    bp = get_name();
2763268899Sbapt	    if (bp->destructor != NULL)
2764268899Sbapt		destructor_redeclared_warning(a_lineno, a_line, a_cptr);
2765268899Sbapt	    else
2766268899Sbapt	    {
2767268899Sbapt		/* postpone re-processing destructor $$s until end of grammar spec */
2768268899Sbapt		bp->destructor = TMALLOC(char, strlen(code_text) + 1);
2769268899Sbapt		NO_SPACE(bp->destructor);
2770268899Sbapt		strcpy(bp->destructor, code_text);
2771268899Sbapt	    }
2772268899Sbapt	}
2773268899Sbapt	else
2774268899Sbapt	    break;
2775268899Sbapt    }
2776268899Sbapt    free(a_line);
2777268899Sbapt    free(code_text);
2778268899Sbapt}
2779234949Sbapt
2780268899Sbaptstatic char *
2781268899Sbaptprocess_destructor_XX(char *code, char *tag)
2782268899Sbapt{
2783268899Sbapt    int c;
2784268899Sbapt    int quote;
2785268899Sbapt    int depth;
2786268899Sbapt    struct mstring *new_code = msnew();
2787268899Sbapt    char *codeptr = code;
2788268899Sbapt
2789268899Sbapt    depth = 0;
2790268899Sbapt  loop:			/* step thru code */
2791268899Sbapt    c = *codeptr;
2792268899Sbapt    if (c == '$' && codeptr[1] == '$')
2793268899Sbapt    {
2794268899Sbapt	codeptr += 2;
2795268899Sbapt	if (tag == NULL)
2796268899Sbapt	    msprintf(new_code, "(*val)");
2797268899Sbapt	else
2798268899Sbapt	    msprintf(new_code, "(*val).%s", tag);
2799268899Sbapt	goto loop;
2800268899Sbapt    }
2801268899Sbapt    if (isalpha(c) || c == '_' || c == '$')
2802268899Sbapt    {
2803268899Sbapt	do
2804234949Sbapt	{
2805268899Sbapt	    mputc(new_code, c);
2806268899Sbapt	    c = *++codeptr;
2807268899Sbapt	}
2808268899Sbapt	while (isalnum(c) || c == '_' || c == '$');
2809268899Sbapt	goto loop;
2810268899Sbapt    }
2811268899Sbapt    ++codeptr;
2812268899Sbapt    mputc(new_code, c);
2813268899Sbapt    switch (c)
2814268899Sbapt    {
2815268899Sbapt    case L_CURL:
2816268899Sbapt	++depth;
2817268899Sbapt	goto loop;
2818268899Sbapt
2819268899Sbapt    case R_CURL:
2820268899Sbapt	if (--depth > 0)
2821268899Sbapt	    goto loop;
2822268899Sbapt	return msdone(new_code);
2823268899Sbapt
2824268899Sbapt    case '\'':
2825268899Sbapt    case '"':
2826268899Sbapt	quote = c;
2827268899Sbapt	for (;;)
2828268899Sbapt	{
2829268899Sbapt	    c = *codeptr++;
2830268899Sbapt	    mputc(new_code, c);
2831268899Sbapt	    if (c == quote)
2832268899Sbapt		goto loop;
2833268899Sbapt	    if (c == '\\')
2834234949Sbapt	    {
2835268899Sbapt		c = *codeptr++;
2836268899Sbapt		mputc(new_code, c);
2837234949Sbapt	    }
2838234949Sbapt	}
2839268899Sbapt
2840268899Sbapt    case '/':
2841268899Sbapt	c = *codeptr;
2842234949Sbapt	if (c == '*')
2843234949Sbapt	{
2844268899Sbapt	    mputc(new_code, c);
2845268899Sbapt	    ++codeptr;
2846234949Sbapt	    for (;;)
2847234949Sbapt	    {
2848268899Sbapt		c = *codeptr++;
2849268899Sbapt		mputc(new_code, c);
2850268899Sbapt		if (c == '*' && *codeptr == '/')
2851234949Sbapt		{
2852268899Sbapt		    mputc(new_code, '/');
2853268899Sbapt		    ++codeptr;
2854234949Sbapt		    goto loop;
2855234949Sbapt		}
2856234949Sbapt	    }
2857234949Sbapt	}
2858234949Sbapt	goto loop;
2859234949Sbapt
2860234949Sbapt    default:
2861234949Sbapt	goto loop;
2862234949Sbapt    }
2863234949Sbapt}
2864268899Sbapt#endif /* defined(YYBTYACC) */
2865234949Sbapt
2866234949Sbaptstatic int
2867234949Sbaptmark_symbol(void)
2868234949Sbapt{
2869234949Sbapt    int c;
2870240517Sbapt    bucket *bp = NULL;
2871234949Sbapt
2872234949Sbapt    c = cptr[1];
2873234949Sbapt    if (c == '%' || c == '\\')
2874234949Sbapt    {
2875234949Sbapt	cptr += 2;
2876234949Sbapt	return (1);
2877234949Sbapt    }
2878234949Sbapt
2879234949Sbapt    if (c == '=')
2880234949Sbapt	cptr += 2;
2881234949Sbapt    else if ((c == 'p' || c == 'P') &&
2882234949Sbapt	     ((c = cptr[2]) == 'r' || c == 'R') &&
2883234949Sbapt	     ((c = cptr[3]) == 'e' || c == 'E') &&
2884234949Sbapt	     ((c = cptr[4]) == 'c' || c == 'C') &&
2885234949Sbapt	     ((c = cptr[5], !IS_IDENT(c))))
2886234949Sbapt	cptr += 5;
2887234949Sbapt    else
2888234949Sbapt	syntax_error(lineno, line, cptr);
2889234949Sbapt
2890234949Sbapt    c = nextc();
2891234949Sbapt    if (isalpha(c) || c == '_' || c == '.' || c == '$')
2892234949Sbapt	bp = get_name();
2893234949Sbapt    else if (c == '\'' || c == '"')
2894234949Sbapt	bp = get_literal();
2895234949Sbapt    else
2896234949Sbapt    {
2897234949Sbapt	syntax_error(lineno, line, cptr);
2898234949Sbapt    }
2899234949Sbapt
2900234949Sbapt    if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
2901234949Sbapt	prec_redeclared();
2902234949Sbapt
2903234949Sbapt    rprec[nrules] = bp->prec;
2904234949Sbapt    rassoc[nrules] = bp->assoc;
2905234949Sbapt    return (0);
2906234949Sbapt}
2907234949Sbapt
2908234949Sbaptstatic void
2909234949Sbaptread_grammar(void)
2910234949Sbapt{
2911234949Sbapt    int c;
2912234949Sbapt
2913234949Sbapt    initialize_grammar();
2914234949Sbapt    advance_to_start();
2915234949Sbapt
2916234949Sbapt    for (;;)
2917234949Sbapt    {
2918234949Sbapt	c = nextc();
2919234949Sbapt	if (c == EOF)
2920234949Sbapt	    break;
2921234949Sbapt	if (isalpha(c)
2922234949Sbapt	    || c == '_'
2923234949Sbapt	    || c == '.'
2924234949Sbapt	    || c == '$'
2925234949Sbapt	    || c == '\''
2926234949Sbapt	    || c == '"')
2927234949Sbapt	    add_symbol();
2928268899Sbapt#if defined(YYBTYACC)
2929268899Sbapt	else if (c == L_CURL || c == '=' || (backtrack && c == L_BRAC))
2930268899Sbapt#else
2931234949Sbapt	else if (c == L_CURL || c == '=')
2932268899Sbapt#endif
2933234949Sbapt	    copy_action();
2934234949Sbapt	else if (c == '|')
2935234949Sbapt	{
2936234949Sbapt	    end_rule();
2937234949Sbapt	    start_rule(plhs[nrules - 1], 0);
2938234949Sbapt	    ++cptr;
2939234949Sbapt	}
2940234949Sbapt	else if (c == '%')
2941234949Sbapt	{
2942234949Sbapt	    if (mark_symbol())
2943234949Sbapt		break;
2944234949Sbapt	}
2945234949Sbapt	else
2946234949Sbapt	    syntax_error(lineno, line, cptr);
2947234949Sbapt    }
2948234949Sbapt    end_rule();
2949268899Sbapt#if defined(YYBTYACC)
2950268899Sbapt    if (goal->args > 0)
2951268899Sbapt	start_requires_args(goal->name);
2952268899Sbapt#endif
2953234949Sbapt}
2954234949Sbapt
2955234949Sbaptstatic void
2956234949Sbaptfree_tags(void)
2957234949Sbapt{
2958234949Sbapt    int i;
2959234949Sbapt
2960234949Sbapt    if (tag_table == 0)
2961234949Sbapt	return;
2962234949Sbapt
2963234949Sbapt    for (i = 0; i < ntags; ++i)
2964234949Sbapt    {
2965234949Sbapt	assert(tag_table[i]);
2966234949Sbapt	FREE(tag_table[i]);
2967234949Sbapt    }
2968234949Sbapt    FREE(tag_table);
2969234949Sbapt}
2970234949Sbapt
2971234949Sbaptstatic void
2972234949Sbaptpack_names(void)
2973234949Sbapt{
2974234949Sbapt    bucket *bp;
2975234949Sbapt    char *p, *s, *t;
2976234949Sbapt
2977234949Sbapt    name_pool_size = 13;	/* 13 == sizeof("$end") + sizeof("$accept") */
2978234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
2979234949Sbapt	name_pool_size += strlen(bp->name) + 1;
2980234949Sbapt
2981240517Sbapt    name_pool = TMALLOC(char, name_pool_size);
2982234949Sbapt    NO_SPACE(name_pool);
2983234949Sbapt
2984234949Sbapt    strcpy(name_pool, "$accept");
2985234949Sbapt    strcpy(name_pool + 8, "$end");
2986234949Sbapt    t = name_pool + 13;
2987234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
2988234949Sbapt    {
2989234949Sbapt	p = t;
2990234949Sbapt	s = bp->name;
2991234949Sbapt	while ((*t++ = *s++) != 0)
2992234949Sbapt	    continue;
2993234949Sbapt	FREE(bp->name);
2994234949Sbapt	bp->name = p;
2995234949Sbapt    }
2996234949Sbapt}
2997234949Sbapt
2998234949Sbaptstatic void
2999234949Sbaptcheck_symbols(void)
3000234949Sbapt{
3001234949Sbapt    bucket *bp;
3002234949Sbapt
3003234949Sbapt    if (goal->class == UNKNOWN)
3004234949Sbapt	undefined_goal(goal->name);
3005234949Sbapt
3006234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
3007234949Sbapt    {
3008234949Sbapt	if (bp->class == UNKNOWN)
3009234949Sbapt	{
3010234949Sbapt	    undefined_symbol_warning(bp->name);
3011234949Sbapt	    bp->class = TERM;
3012234949Sbapt	}
3013234949Sbapt    }
3014234949Sbapt}
3015234949Sbapt
3016234949Sbaptstatic void
3017234949Sbaptprotect_string(char *src, char **des)
3018234949Sbapt{
3019234949Sbapt    unsigned len;
3020234949Sbapt    char *s;
3021234949Sbapt    char *d;
3022234949Sbapt
3023234949Sbapt    *des = src;
3024234949Sbapt    if (src)
3025234949Sbapt    {
3026234949Sbapt	len = 1;
3027234949Sbapt	s = src;
3028234949Sbapt	while (*s)
3029234949Sbapt	{
3030234949Sbapt	    if ('\\' == *s || '"' == *s)
3031234949Sbapt		len++;
3032234949Sbapt	    s++;
3033234949Sbapt	    len++;
3034234949Sbapt	}
3035234949Sbapt
3036240517Sbapt	*des = d = TMALLOC(char, len);
3037234949Sbapt	NO_SPACE(d);
3038234949Sbapt
3039234949Sbapt	s = src;
3040234949Sbapt	while (*s)
3041234949Sbapt	{
3042234949Sbapt	    if ('\\' == *s || '"' == *s)
3043234949Sbapt		*d++ = '\\';
3044234949Sbapt	    *d++ = *s++;
3045234949Sbapt	}
3046234949Sbapt	*d = '\0';
3047234949Sbapt    }
3048234949Sbapt}
3049234949Sbapt
3050234949Sbaptstatic void
3051234949Sbaptpack_symbols(void)
3052234949Sbapt{
3053234949Sbapt    bucket *bp;
3054234949Sbapt    bucket **v;
3055234949Sbapt    Value_t i, j, k, n;
3056268899Sbapt#if defined(YYBTYACC)
3057268899Sbapt    Value_t max_tok_pval;
3058268899Sbapt#endif
3059234949Sbapt
3060234949Sbapt    nsyms = 2;
3061234949Sbapt    ntokens = 1;
3062234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
3063234949Sbapt    {
3064234949Sbapt	++nsyms;
3065234949Sbapt	if (bp->class == TERM)
3066234949Sbapt	    ++ntokens;
3067234949Sbapt    }
3068234949Sbapt    start_symbol = (Value_t) ntokens;
3069268899Sbapt    nvars = (Value_t) (nsyms - ntokens);
3070234949Sbapt
3071240517Sbapt    symbol_name = TMALLOC(char *, nsyms);
3072234949Sbapt    NO_SPACE(symbol_name);
3073234949Sbapt
3074240517Sbapt    symbol_value = TMALLOC(Value_t, nsyms);
3075234949Sbapt    NO_SPACE(symbol_value);
3076234949Sbapt
3077268899Sbapt    symbol_prec = TMALLOC(Value_t, nsyms);
3078234949Sbapt    NO_SPACE(symbol_prec);
3079234949Sbapt
3080240517Sbapt    symbol_assoc = TMALLOC(char, nsyms);
3081234949Sbapt    NO_SPACE(symbol_assoc);
3082234949Sbapt
3083268899Sbapt#if defined(YYBTYACC)
3084268899Sbapt    symbol_pval = TMALLOC(Value_t, nsyms);
3085268899Sbapt    NO_SPACE(symbol_pval);
3086268899Sbapt
3087268899Sbapt    if (destructor)
3088268899Sbapt    {
3089268899Sbapt	symbol_destructor = CALLOC(sizeof(char *), nsyms);
3090268899Sbapt	NO_SPACE(symbol_destructor);
3091268899Sbapt
3092268899Sbapt	symbol_type_tag = CALLOC(sizeof(char *), nsyms);
3093268899Sbapt	NO_SPACE(symbol_type_tag);
3094268899Sbapt    }
3095268899Sbapt#endif
3096268899Sbapt
3097240517Sbapt    v = TMALLOC(bucket *, nsyms);
3098234949Sbapt    NO_SPACE(v);
3099234949Sbapt
3100234949Sbapt    v[0] = 0;
3101234949Sbapt    v[start_symbol] = 0;
3102234949Sbapt
3103234949Sbapt    i = 1;
3104234949Sbapt    j = (Value_t) (start_symbol + 1);
3105234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
3106234949Sbapt    {
3107234949Sbapt	if (bp->class == TERM)
3108234949Sbapt	    v[i++] = bp;
3109234949Sbapt	else
3110234949Sbapt	    v[j++] = bp;
3111234949Sbapt    }
3112234949Sbapt    assert(i == ntokens && j == nsyms);
3113234949Sbapt
3114234949Sbapt    for (i = 1; i < ntokens; ++i)
3115234949Sbapt	v[i]->index = i;
3116234949Sbapt
3117234949Sbapt    goal->index = (Index_t) (start_symbol + 1);
3118234949Sbapt    k = (Value_t) (start_symbol + 2);
3119234949Sbapt    while (++i < nsyms)
3120234949Sbapt	if (v[i] != goal)
3121234949Sbapt	{
3122234949Sbapt	    v[i]->index = k;
3123234949Sbapt	    ++k;
3124234949Sbapt	}
3125234949Sbapt
3126234949Sbapt    goal->value = 0;
3127234949Sbapt    k = 1;
3128234949Sbapt    for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
3129234949Sbapt    {
3130234949Sbapt	if (v[i] != goal)
3131234949Sbapt	{
3132234949Sbapt	    v[i]->value = k;
3133234949Sbapt	    ++k;
3134234949Sbapt	}
3135234949Sbapt    }
3136234949Sbapt
3137234949Sbapt    k = 0;
3138234949Sbapt    for (i = 1; i < ntokens; ++i)
3139234949Sbapt    {
3140234949Sbapt	n = v[i]->value;
3141234949Sbapt	if (n > 256)
3142234949Sbapt	{
3143234949Sbapt	    for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
3144234949Sbapt		symbol_value[j] = symbol_value[j - 1];
3145234949Sbapt	    symbol_value[j] = n;
3146234949Sbapt	}
3147234949Sbapt    }
3148234949Sbapt
3149234949Sbapt    assert(v[1] != 0);
3150234949Sbapt
3151234949Sbapt    if (v[1]->value == UNDEFINED)
3152234949Sbapt	v[1]->value = 256;
3153234949Sbapt
3154234949Sbapt    j = 0;
3155234949Sbapt    n = 257;
3156234949Sbapt    for (i = 2; i < ntokens; ++i)
3157234949Sbapt    {
3158234949Sbapt	if (v[i]->value == UNDEFINED)
3159234949Sbapt	{
3160234949Sbapt	    while (j < k && n == symbol_value[j])
3161234949Sbapt	    {
3162234949Sbapt		while (++j < k && n == symbol_value[j])
3163234949Sbapt		    continue;
3164234949Sbapt		++n;
3165234949Sbapt	    }
3166234949Sbapt	    v[i]->value = n;
3167234949Sbapt	    ++n;
3168234949Sbapt	}
3169234949Sbapt    }
3170234949Sbapt
3171234949Sbapt    symbol_name[0] = name_pool + 8;
3172234949Sbapt    symbol_value[0] = 0;
3173234949Sbapt    symbol_prec[0] = 0;
3174234949Sbapt    symbol_assoc[0] = TOKEN;
3175268899Sbapt#if defined(YYBTYACC)
3176268899Sbapt    symbol_pval[0] = 0;
3177268899Sbapt    max_tok_pval = 0;
3178268899Sbapt#endif
3179234949Sbapt    for (i = 1; i < ntokens; ++i)
3180234949Sbapt    {
3181234949Sbapt	symbol_name[i] = v[i]->name;
3182234949Sbapt	symbol_value[i] = v[i]->value;
3183234949Sbapt	symbol_prec[i] = v[i]->prec;
3184234949Sbapt	symbol_assoc[i] = v[i]->assoc;
3185268899Sbapt#if defined(YYBTYACC)
3186268899Sbapt	symbol_pval[i] = v[i]->value;
3187268899Sbapt	if (symbol_pval[i] > max_tok_pval)
3188268899Sbapt	    max_tok_pval = symbol_pval[i];
3189268899Sbapt	if (destructor)
3190268899Sbapt	{
3191268899Sbapt	    symbol_destructor[i] = v[i]->destructor;
3192268899Sbapt	    symbol_type_tag[i] = v[i]->tag;
3193268899Sbapt	}
3194268899Sbapt#endif
3195234949Sbapt    }
3196234949Sbapt    symbol_name[start_symbol] = name_pool;
3197234949Sbapt    symbol_value[start_symbol] = -1;
3198234949Sbapt    symbol_prec[start_symbol] = 0;
3199234949Sbapt    symbol_assoc[start_symbol] = TOKEN;
3200268899Sbapt#if defined(YYBTYACC)
3201268899Sbapt    symbol_pval[start_symbol] = (Value_t) (max_tok_pval + 1);
3202268899Sbapt#endif
3203234949Sbapt    for (++i; i < nsyms; ++i)
3204234949Sbapt    {
3205234949Sbapt	k = v[i]->index;
3206234949Sbapt	symbol_name[k] = v[i]->name;
3207234949Sbapt	symbol_value[k] = v[i]->value;
3208234949Sbapt	symbol_prec[k] = v[i]->prec;
3209234949Sbapt	symbol_assoc[k] = v[i]->assoc;
3210268899Sbapt#if defined(YYBTYACC)
3211268899Sbapt	symbol_pval[k] = (Value_t) ((max_tok_pval + 1) + v[i]->value + 1);
3212268899Sbapt	if (destructor)
3213268899Sbapt	{
3214268899Sbapt	    symbol_destructor[k] = v[i]->destructor;
3215268899Sbapt	    symbol_type_tag[k] = v[i]->tag;
3216268899Sbapt	}
3217268899Sbapt#endif
3218234949Sbapt    }
3219234949Sbapt
3220234949Sbapt    if (gflag)
3221234949Sbapt    {
3222240517Sbapt	symbol_pname = TMALLOC(char *, nsyms);
3223234949Sbapt	NO_SPACE(symbol_pname);
3224234949Sbapt
3225234949Sbapt	for (i = 0; i < nsyms; ++i)
3226234949Sbapt	    protect_string(symbol_name[i], &(symbol_pname[i]));
3227234949Sbapt    }
3228234949Sbapt
3229234949Sbapt    FREE(v);
3230234949Sbapt}
3231234949Sbapt
3232234949Sbaptstatic void
3233234949Sbaptpack_grammar(void)
3234234949Sbapt{
3235234949Sbapt    int i;
3236234949Sbapt    Value_t j;
3237234949Sbapt    Assoc_t assoc;
3238234949Sbapt    Value_t prec2;
3239234949Sbapt
3240240517Sbapt    ritem = TMALLOC(Value_t, nitems);
3241234949Sbapt    NO_SPACE(ritem);
3242234949Sbapt
3243240517Sbapt    rlhs = TMALLOC(Value_t, nrules);
3244234949Sbapt    NO_SPACE(rlhs);
3245234949Sbapt
3246240517Sbapt    rrhs = TMALLOC(Value_t, nrules + 1);
3247234949Sbapt    NO_SPACE(rrhs);
3248234949Sbapt
3249240517Sbapt    rprec = TREALLOC(Value_t, rprec, nrules);
3250234949Sbapt    NO_SPACE(rprec);
3251234949Sbapt
3252240517Sbapt    rassoc = TREALLOC(Assoc_t, rassoc, nrules);
3253234949Sbapt    NO_SPACE(rassoc);
3254234949Sbapt
3255234949Sbapt    ritem[0] = -1;
3256234949Sbapt    ritem[1] = goal->index;
3257234949Sbapt    ritem[2] = 0;
3258234949Sbapt    ritem[3] = -2;
3259234949Sbapt    rlhs[0] = 0;
3260234949Sbapt    rlhs[1] = 0;
3261234949Sbapt    rlhs[2] = start_symbol;
3262234949Sbapt    rrhs[0] = 0;
3263234949Sbapt    rrhs[1] = 0;
3264234949Sbapt    rrhs[2] = 1;
3265234949Sbapt
3266234949Sbapt    j = 4;
3267234949Sbapt    for (i = 3; i < nrules; ++i)
3268234949Sbapt    {
3269268899Sbapt#if defined(YYBTYACC)
3270268899Sbapt	if (plhs[i]->args > 0)
3271268899Sbapt	{
3272268899Sbapt	    if (plhs[i]->argnames)
3273268899Sbapt	    {
3274268899Sbapt		FREE(plhs[i]->argnames);
3275268899Sbapt		plhs[i]->argnames = NULL;
3276268899Sbapt	    }
3277268899Sbapt	    if (plhs[i]->argtags)
3278268899Sbapt	    {
3279268899Sbapt		FREE(plhs[i]->argtags);
3280268899Sbapt		plhs[i]->argtags = NULL;
3281268899Sbapt	    }
3282268899Sbapt	}
3283268899Sbapt#endif /* defined(YYBTYACC) */
3284234949Sbapt	rlhs[i] = plhs[i]->index;
3285234949Sbapt	rrhs[i] = j;
3286234949Sbapt	assoc = TOKEN;
3287234949Sbapt	prec2 = 0;
3288234949Sbapt	while (pitem[j])
3289234949Sbapt	{
3290234949Sbapt	    ritem[j] = pitem[j]->index;
3291234949Sbapt	    if (pitem[j]->class == TERM)
3292234949Sbapt	    {
3293234949Sbapt		prec2 = pitem[j]->prec;
3294234949Sbapt		assoc = pitem[j]->assoc;
3295234949Sbapt	    }
3296234949Sbapt	    ++j;
3297234949Sbapt	}
3298234949Sbapt	ritem[j] = (Value_t) - i;
3299234949Sbapt	++j;
3300234949Sbapt	if (rprec[i] == UNDEFINED)
3301234949Sbapt	{
3302234949Sbapt	    rprec[i] = prec2;
3303234949Sbapt	    rassoc[i] = assoc;
3304234949Sbapt	}
3305234949Sbapt    }
3306234949Sbapt    rrhs[i] = j;
3307234949Sbapt
3308234949Sbapt    FREE(plhs);
3309234949Sbapt    FREE(pitem);
3310268899Sbapt#if defined(YYBTYACC)
3311268899Sbapt    clean_arg_cache();
3312268899Sbapt#endif
3313234949Sbapt}
3314234949Sbapt
3315234949Sbaptstatic void
3316234949Sbaptprint_grammar(void)
3317234949Sbapt{
3318234949Sbapt    int i, k;
3319234949Sbapt    size_t j, spacing = 0;
3320234949Sbapt    FILE *f = verbose_file;
3321234949Sbapt
3322234949Sbapt    if (!vflag)
3323234949Sbapt	return;
3324234949Sbapt
3325234949Sbapt    k = 1;
3326234949Sbapt    for (i = 2; i < nrules; ++i)
3327234949Sbapt    {
3328234949Sbapt	if (rlhs[i] != rlhs[i - 1])
3329234949Sbapt	{
3330234949Sbapt	    if (i != 2)
3331234949Sbapt		fprintf(f, "\n");
3332234949Sbapt	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
3333234949Sbapt	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
3334234949Sbapt	}
3335234949Sbapt	else
3336234949Sbapt	{
3337234949Sbapt	    fprintf(f, "%4d  ", i - 2);
3338234949Sbapt	    j = spacing;
3339234949Sbapt	    while (j-- != 0)
3340234949Sbapt		putc(' ', f);
3341234949Sbapt	    putc('|', f);
3342234949Sbapt	}
3343234949Sbapt
3344234949Sbapt	while (ritem[k] >= 0)
3345234949Sbapt	{
3346234949Sbapt	    fprintf(f, " %s", symbol_name[ritem[k]]);
3347234949Sbapt	    ++k;
3348234949Sbapt	}
3349234949Sbapt	++k;
3350234949Sbapt	putc('\n', f);
3351234949Sbapt    }
3352234949Sbapt}
3353234949Sbapt
3354268899Sbapt#if defined(YYBTYACC)
3355268899Sbaptstatic void
3356268899Sbaptfinalize_destructors(void)
3357268899Sbapt{
3358268899Sbapt    int i;
3359268899Sbapt    bucket *bp;
3360268899Sbapt    char *tag;
3361268899Sbapt
3362268899Sbapt    for (i = 2; i < nsyms; ++i)
3363268899Sbapt    {
3364268899Sbapt	tag = symbol_type_tag[i];
3365268899Sbapt	if (symbol_destructor[i] == NULL)
3366268899Sbapt	{
3367268899Sbapt	    if (tag == NULL)
3368268899Sbapt	    {			/* use <> destructor, if there is one */
3369268899Sbapt		if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3370268899Sbapt		{
3371268899Sbapt		    symbol_destructor[i] = TMALLOC(char,
3372268899Sbapt						   strlen(bp->destructor) + 1);
3373268899Sbapt		    NO_SPACE(symbol_destructor[i]);
3374268899Sbapt		    strcpy(symbol_destructor[i], bp->destructor);
3375268899Sbapt		}
3376268899Sbapt	    }
3377268899Sbapt	    else
3378268899Sbapt	    {			/* use type destructor for this tag, if there is one */
3379268899Sbapt		bp = lookup_type_destructor(tag);
3380268899Sbapt		if (bp->destructor != NULL)
3381268899Sbapt		{
3382268899Sbapt		    symbol_destructor[i] = TMALLOC(char,
3383268899Sbapt						   strlen(bp->destructor) + 1);
3384268899Sbapt		    NO_SPACE(symbol_destructor[i]);
3385268899Sbapt		    strcpy(symbol_destructor[i], bp->destructor);
3386268899Sbapt		}
3387268899Sbapt		else
3388268899Sbapt		{		/* use <*> destructor, if there is one */
3389268899Sbapt		    if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3390268899Sbapt			/* replace "$$" with "(*val).tag" in destructor code */
3391268899Sbapt			symbol_destructor[i]
3392268899Sbapt			    = process_destructor_XX(bp->destructor, tag);
3393268899Sbapt		}
3394268899Sbapt	    }
3395268899Sbapt	}
3396268899Sbapt	else
3397268899Sbapt	{			/* replace "$$" with "(*val)[.tag]" in destructor code */
3398268899Sbapt	    symbol_destructor[i]
3399268899Sbapt		= process_destructor_XX(symbol_destructor[i], tag);
3400268899Sbapt	}
3401268899Sbapt    }
3402268899Sbapt    /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */
3403268899Sbapt    DO_FREE(symbol_type_tag);	/* no longer needed */
3404268899Sbapt    if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
3405268899Sbapt    {
3406268899Sbapt	FREE(bp->name);
3407268899Sbapt	/* 'bp->tag' is a static value, don't free */
3408268899Sbapt	FREE(bp->destructor);
3409268899Sbapt	FREE(bp);
3410268899Sbapt    }
3411268899Sbapt    if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
3412268899Sbapt    {
3413268899Sbapt	FREE(bp->name);
3414268899Sbapt	/* 'bp->tag' is a static value, don't free */
3415268899Sbapt	FREE(bp->destructor);
3416268899Sbapt	FREE(bp);
3417268899Sbapt    }
3418268899Sbapt    if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL)
3419268899Sbapt    {
3420268899Sbapt	bucket *p;
3421268899Sbapt	for (; bp; bp = p)
3422268899Sbapt	{
3423268899Sbapt	    p = bp->link;
3424268899Sbapt	    FREE(bp->name);
3425268899Sbapt	    /* 'bp->tag' freed by 'free_tags()' */
3426268899Sbapt	    FREE(bp->destructor);
3427268899Sbapt	    FREE(bp);
3428268899Sbapt	}
3429268899Sbapt    }
3430268899Sbapt}
3431268899Sbapt#endif /* defined(YYBTYACC) */
3432268899Sbapt
3433234949Sbaptvoid
3434234949Sbaptreader(void)
3435234949Sbapt{
3436234949Sbapt    write_section(code_file, banner);
3437234949Sbapt    create_symbol_table();
3438234949Sbapt    read_declarations();
3439234949Sbapt    read_grammar();
3440234949Sbapt    free_symbol_table();
3441234949Sbapt    pack_names();
3442234949Sbapt    check_symbols();
3443234949Sbapt    pack_symbols();
3444234949Sbapt    pack_grammar();
3445234949Sbapt    free_symbols();
3446234949Sbapt    print_grammar();
3447268899Sbapt#if defined(YYBTYACC)
3448268899Sbapt    if (destructor)
3449268899Sbapt	finalize_destructors();
3450268899Sbapt#endif
3451268899Sbapt    free_tags();
3452234949Sbapt}
3453234949Sbapt
3454234949Sbapt#ifdef NO_LEAKS
3455234949Sbaptstatic param *
3456234949Sbaptfree_declarations(param * list)
3457234949Sbapt{
3458234949Sbapt    while (list != 0)
3459234949Sbapt    {
3460234949Sbapt	param *next = list->next;
3461234949Sbapt	free(list->type);
3462234949Sbapt	free(list->name);
3463234949Sbapt	free(list->type2);
3464234949Sbapt	free(list);
3465234949Sbapt	list = next;
3466234949Sbapt    }
3467234949Sbapt    return list;
3468234949Sbapt}
3469234949Sbapt
3470234949Sbaptvoid
3471234949Sbaptreader_leaks(void)
3472234949Sbapt{
3473234949Sbapt    lex_param = free_declarations(lex_param);
3474234949Sbapt    parse_param = free_declarations(parse_param);
3475234949Sbapt
3476234949Sbapt    DO_FREE(line);
3477234949Sbapt    DO_FREE(rrhs);
3478234949Sbapt    DO_FREE(rlhs);
3479234949Sbapt    DO_FREE(rprec);
3480234949Sbapt    DO_FREE(ritem);
3481234949Sbapt    DO_FREE(rassoc);
3482234949Sbapt    DO_FREE(cache);
3483234949Sbapt    DO_FREE(name_pool);
3484234949Sbapt    DO_FREE(symbol_name);
3485234949Sbapt    DO_FREE(symbol_prec);
3486234949Sbapt    DO_FREE(symbol_assoc);
3487234949Sbapt    DO_FREE(symbol_value);
3488268899Sbapt#if defined(YYBTYACC)
3489268899Sbapt    DO_FREE(symbol_pval);
3490268899Sbapt    DO_FREE(symbol_destructor);
3491268899Sbapt    DO_FREE(symbol_type_tag);
3492268899Sbapt#endif
3493234949Sbapt}
3494234949Sbapt#endif
3495