reader.c revision 235723
1234949Sbapt/* $Id: reader.c,v 1.33 2011/09/06 22:56:53 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
12234949Sbapt#define L_CURL '{'
13234949Sbapt#define R_CURL '}'
14234949Sbapt
15234949Sbaptstatic void start_rule(bucket *bp, int s_lineno);
16234949Sbapt
17234949Sbaptstatic char *cache;
18234949Sbaptstatic int cinc, cache_size;
19234949Sbapt
20234949Sbaptint ntags;
21234949Sbaptstatic int tagmax;
22234949Sbaptstatic char **tag_table;
23234949Sbapt
24234949Sbaptstatic char saw_eof;
25234949Sbaptchar unionized;
26234949Sbaptchar *cptr, *line;
27234949Sbaptstatic int linesize;
28234949Sbapt
29234949Sbaptstatic bucket *goal;
30234949Sbaptstatic Value_t prec;
31234949Sbaptstatic int gensym;
32234949Sbaptstatic char last_was_action;
33234949Sbapt
34234949Sbaptstatic int maxitems;
35234949Sbaptstatic bucket **pitem;
36234949Sbapt
37234949Sbaptstatic int maxrules;
38234949Sbaptstatic bucket **plhs;
39234949Sbapt
40234949Sbaptstatic size_t name_pool_size;
41234949Sbaptstatic char *name_pool;
42234949Sbapt
43234949Sbaptchar line_format[] = "#line %d \"%s\"\n";
44234949Sbapt
45234949Sbaptparam *lex_param;
46234949Sbaptparam *parse_param;
47234949Sbapt
48234949Sbaptstatic void
49234949Sbaptcachec(int c)
50234949Sbapt{
51234949Sbapt    assert(cinc >= 0);
52234949Sbapt    if (cinc >= cache_size)
53234949Sbapt    {
54234949Sbapt	cache_size += 256;
55234949Sbapt	cache = REALLOC(cache, cache_size);
56234949Sbapt	NO_SPACE(cache);
57234949Sbapt    }
58234949Sbapt    cache[cinc] = (char)c;
59234949Sbapt    ++cinc;
60234949Sbapt}
61234949Sbapt
62234949Sbaptstatic void
63234949Sbaptget_line(void)
64234949Sbapt{
65234949Sbapt    FILE *f = input_file;
66234949Sbapt    int c;
67234949Sbapt    int i;
68234949Sbapt
69234949Sbapt    if (saw_eof || (c = getc(f)) == EOF)
70234949Sbapt    {
71234949Sbapt	if (line)
72234949Sbapt	{
73234949Sbapt	    FREE(line);
74234949Sbapt	    line = 0;
75234949Sbapt	}
76234949Sbapt	cptr = 0;
77234949Sbapt	saw_eof = 1;
78234949Sbapt	return;
79234949Sbapt    }
80234949Sbapt
81234949Sbapt    if (line == 0 || linesize != (LINESIZE + 1))
82234949Sbapt    {
83234949Sbapt	if (line)
84234949Sbapt	    FREE(line);
85234949Sbapt	linesize = LINESIZE + 1;
86234949Sbapt	line = MALLOC(linesize);
87234949Sbapt	NO_SPACE(line);
88234949Sbapt    }
89234949Sbapt
90234949Sbapt    i = 0;
91234949Sbapt    ++lineno;
92234949Sbapt    for (;;)
93234949Sbapt    {
94234949Sbapt	line[i] = (char)c;
95234949Sbapt	if (c == '\n')
96234949Sbapt	{
97234949Sbapt	    cptr = line;
98234949Sbapt	    return;
99234949Sbapt	}
100234949Sbapt	if (++i >= linesize)
101234949Sbapt	{
102234949Sbapt	    linesize += LINESIZE;
103234949Sbapt	    line = REALLOC(line, linesize);
104234949Sbapt	    NO_SPACE(line);
105234949Sbapt	}
106234949Sbapt	c = getc(f);
107234949Sbapt	if (c == EOF)
108234949Sbapt	{
109234949Sbapt	    line[i] = '\n';
110234949Sbapt	    saw_eof = 1;
111234949Sbapt	    cptr = line;
112234949Sbapt	    return;
113234949Sbapt	}
114234949Sbapt    }
115234949Sbapt}
116234949Sbapt
117234949Sbaptstatic char *
118234949Sbaptdup_line(void)
119234949Sbapt{
120234949Sbapt    char *p, *s, *t;
121234949Sbapt
122234949Sbapt    if (line == 0)
123234949Sbapt	return (0);
124234949Sbapt    s = line;
125234949Sbapt    while (*s != '\n')
126234949Sbapt	++s;
127234949Sbapt    p = MALLOC(s - line + 1);
128234949Sbapt    NO_SPACE(p);
129234949Sbapt
130234949Sbapt    s = line;
131234949Sbapt    t = p;
132234949Sbapt    while ((*t++ = *s++) != '\n')
133234949Sbapt	continue;
134234949Sbapt    return (p);
135234949Sbapt}
136234949Sbapt
137234949Sbaptstatic void
138234949Sbaptskip_comment(void)
139234949Sbapt{
140234949Sbapt    char *s;
141234949Sbapt
142234949Sbapt    int st_lineno = lineno;
143234949Sbapt    char *st_line = dup_line();
144234949Sbapt    char *st_cptr = st_line + (cptr - line);
145234949Sbapt
146234949Sbapt    s = cptr + 2;
147234949Sbapt    for (;;)
148234949Sbapt    {
149234949Sbapt	if (*s == '*' && s[1] == '/')
150234949Sbapt	{
151234949Sbapt	    cptr = s + 2;
152234949Sbapt	    FREE(st_line);
153234949Sbapt	    return;
154234949Sbapt	}
155234949Sbapt	if (*s == '\n')
156234949Sbapt	{
157234949Sbapt	    get_line();
158234949Sbapt	    if (line == 0)
159234949Sbapt		unterminated_comment(st_lineno, st_line, st_cptr);
160234949Sbapt	    s = cptr;
161234949Sbapt	}
162234949Sbapt	else
163234949Sbapt	    ++s;
164234949Sbapt    }
165234949Sbapt}
166234949Sbapt
167234949Sbaptstatic int
168234949Sbaptnextc(void)
169234949Sbapt{
170234949Sbapt    char *s;
171234949Sbapt
172234949Sbapt    if (line == 0)
173234949Sbapt    {
174234949Sbapt	get_line();
175234949Sbapt	if (line == 0)
176234949Sbapt	    return (EOF);
177234949Sbapt    }
178234949Sbapt
179234949Sbapt    s = cptr;
180234949Sbapt    for (;;)
181234949Sbapt    {
182234949Sbapt	switch (*s)
183234949Sbapt	{
184234949Sbapt	case '\n':
185234949Sbapt	    get_line();
186234949Sbapt	    if (line == 0)
187234949Sbapt		return (EOF);
188234949Sbapt	    s = cptr;
189234949Sbapt	    break;
190234949Sbapt
191234949Sbapt	case ' ':
192234949Sbapt	case '\t':
193234949Sbapt	case '\f':
194234949Sbapt	case '\r':
195234949Sbapt	case '\v':
196234949Sbapt	case ',':
197234949Sbapt	case ';':
198234949Sbapt	    ++s;
199234949Sbapt	    break;
200234949Sbapt
201234949Sbapt	case '\\':
202234949Sbapt	    cptr = s;
203234949Sbapt	    return ('%');
204234949Sbapt
205234949Sbapt	case '/':
206234949Sbapt	    if (s[1] == '*')
207234949Sbapt	    {
208234949Sbapt		cptr = s;
209234949Sbapt		skip_comment();
210234949Sbapt		s = cptr;
211234949Sbapt		break;
212234949Sbapt	    }
213234949Sbapt	    else if (s[1] == '/')
214234949Sbapt	    {
215234949Sbapt		get_line();
216234949Sbapt		if (line == 0)
217234949Sbapt		    return (EOF);
218234949Sbapt		s = cptr;
219234949Sbapt		break;
220234949Sbapt	    }
221234949Sbapt	    /* FALLTHRU */
222234949Sbapt
223234949Sbapt	default:
224234949Sbapt	    cptr = s;
225234949Sbapt	    return (*s);
226234949Sbapt	}
227234949Sbapt    }
228234949Sbapt}
229234949Sbapt
230234949Sbapt/*
231234949Sbapt * Compare keyword to cached token, treating '_' and '-' the same.  Some
232234949Sbapt * grammars rely upon this misfeature.
233234949Sbapt */
234234949Sbaptstatic int
235234949Sbaptmatchec(const char *name)
236234949Sbapt{
237234949Sbapt    const char *p = cache;
238234949Sbapt    const char *q = name;
239234949Sbapt    int code = 0;	/* assume mismatch */
240234949Sbapt
241234949Sbapt    while (*p != '\0' && *q != '\0')
242234949Sbapt    {
243234949Sbapt	char a = *p++;
244234949Sbapt	char b = *q++;
245234949Sbapt	if (a == '_')
246234949Sbapt	    a = '-';
247234949Sbapt	if (b == '_')
248234949Sbapt	    b = '-';
249234949Sbapt	if (a != b)
250234949Sbapt	    break;
251234949Sbapt	if (*p == '\0' && *q == '\0')
252234949Sbapt	{
253234949Sbapt	    code = 1;
254234949Sbapt	    break;
255234949Sbapt	}
256234949Sbapt    }
257234949Sbapt    return code;
258234949Sbapt}
259234949Sbapt
260234949Sbaptstatic int
261234949Sbaptkeyword(void)
262234949Sbapt{
263234949Sbapt    int c;
264234949Sbapt    char *t_cptr = cptr;
265234949Sbapt
266234949Sbapt    c = *++cptr;
267234949Sbapt    if (isalpha(c))
268234949Sbapt    {
269234949Sbapt	cinc = 0;
270234949Sbapt	for (;;)
271234949Sbapt	{
272234949Sbapt	    if (isalpha(c))
273234949Sbapt	    {
274234949Sbapt		if (isupper(c))
275234949Sbapt		    c = tolower(c);
276234949Sbapt		cachec(c);
277234949Sbapt	    }
278234949Sbapt	    else if (isdigit(c)
279234949Sbapt		     || c == '-'
280234949Sbapt		     || c == '_'
281234949Sbapt		     || c == '.'
282234949Sbapt		     || c == '$')
283234949Sbapt	    {
284234949Sbapt		cachec(c);
285234949Sbapt	    }
286234949Sbapt	    else
287234949Sbapt	    {
288234949Sbapt		break;
289234949Sbapt	    }
290234949Sbapt	    c = *++cptr;
291234949Sbapt	}
292234949Sbapt	cachec(NUL);
293234949Sbapt
294234949Sbapt	if (matchec("token") || matchec("term"))
295234949Sbapt	    return (TOKEN);
296234949Sbapt	if (matchec("type"))
297234949Sbapt	    return (TYPE);
298234949Sbapt	if (matchec("left"))
299234949Sbapt	    return (LEFT);
300234949Sbapt	if (matchec("right"))
301234949Sbapt	    return (RIGHT);
302234949Sbapt	if (matchec("nonassoc") || matchec("binary"))
303234949Sbapt	    return (NONASSOC);
304234949Sbapt	if (matchec("start"))
305234949Sbapt	    return (START);
306234949Sbapt	if (matchec("union"))
307234949Sbapt	    return (UNION);
308234949Sbapt	if (matchec("ident"))
309234949Sbapt	    return (IDENT);
310234949Sbapt	if (matchec("expect"))
311234949Sbapt	    return (EXPECT);
312234949Sbapt	if (matchec("expect-rr"))
313234949Sbapt	    return (EXPECT_RR);
314234949Sbapt	if (matchec("pure-parser"))
315234949Sbapt	    return (PURE_PARSER);
316234949Sbapt	if (matchec("parse-param"))
317234949Sbapt	    return (PARSE_PARAM);
318234949Sbapt	if (matchec("lex-param"))
319234949Sbapt	    return (LEX_PARAM);
320234949Sbapt	if (matchec("yacc"))
321234949Sbapt	    return (POSIX_YACC);
322234949Sbapt    }
323234949Sbapt    else
324234949Sbapt    {
325234949Sbapt	++cptr;
326234949Sbapt	if (c == L_CURL)
327234949Sbapt	    return (TEXT);
328234949Sbapt	if (c == '%' || c == '\\')
329234949Sbapt	    return (MARK);
330234949Sbapt	if (c == '<')
331234949Sbapt	    return (LEFT);
332234949Sbapt	if (c == '>')
333234949Sbapt	    return (RIGHT);
334234949Sbapt	if (c == '0')
335234949Sbapt	    return (TOKEN);
336234949Sbapt	if (c == '2')
337234949Sbapt	    return (NONASSOC);
338234949Sbapt    }
339234949Sbapt    syntax_error(lineno, line, t_cptr);
340234949Sbapt    /*NOTREACHED */
341235723Sbapt    return (-1);
342234949Sbapt}
343234949Sbapt
344234949Sbaptstatic void
345234949Sbaptcopy_ident(void)
346234949Sbapt{
347234949Sbapt    int c;
348234949Sbapt    FILE *f = output_file;
349234949Sbapt
350234949Sbapt    c = nextc();
351234949Sbapt    if (c == EOF)
352234949Sbapt	unexpected_EOF();
353234949Sbapt    if (c != '"')
354234949Sbapt	syntax_error(lineno, line, cptr);
355234949Sbapt    ++outline;
356234949Sbapt    fprintf(f, "#ident \"");
357234949Sbapt    for (;;)
358234949Sbapt    {
359234949Sbapt	c = *++cptr;
360234949Sbapt	if (c == '\n')
361234949Sbapt	{
362234949Sbapt	    fprintf(f, "\"\n");
363234949Sbapt	    return;
364234949Sbapt	}
365234949Sbapt	putc(c, f);
366234949Sbapt	if (c == '"')
367234949Sbapt	{
368234949Sbapt	    putc('\n', f);
369234949Sbapt	    ++cptr;
370234949Sbapt	    return;
371234949Sbapt	}
372234949Sbapt    }
373234949Sbapt}
374234949Sbapt
375234949Sbaptstatic void
376234949Sbaptcopy_text(void)
377234949Sbapt{
378234949Sbapt    int c;
379234949Sbapt    int quote;
380234949Sbapt    FILE *f = text_file;
381234949Sbapt    int need_newline = 0;
382234949Sbapt    int t_lineno = lineno;
383234949Sbapt    char *t_line = dup_line();
384234949Sbapt    char *t_cptr = t_line + (cptr - line - 2);
385234949Sbapt
386234949Sbapt    if (*cptr == '\n')
387234949Sbapt    {
388234949Sbapt	get_line();
389234949Sbapt	if (line == 0)
390234949Sbapt	    unterminated_text(t_lineno, t_line, t_cptr);
391234949Sbapt    }
392234949Sbapt    if (!lflag)
393234949Sbapt	fprintf(f, line_format, lineno, input_file_name);
394234949Sbapt
395234949Sbapt  loop:
396234949Sbapt    c = *cptr++;
397234949Sbapt    switch (c)
398234949Sbapt    {
399234949Sbapt    case '\n':
400234949Sbapt      next_line:
401234949Sbapt	putc('\n', f);
402234949Sbapt	need_newline = 0;
403234949Sbapt	get_line();
404234949Sbapt	if (line)
405234949Sbapt	    goto loop;
406234949Sbapt	unterminated_text(t_lineno, t_line, t_cptr);
407234949Sbapt
408234949Sbapt    case '\'':
409234949Sbapt    case '"':
410234949Sbapt	{
411234949Sbapt	    int s_lineno = lineno;
412234949Sbapt	    char *s_line = dup_line();
413234949Sbapt	    char *s_cptr = s_line + (cptr - line - 1);
414234949Sbapt
415234949Sbapt	    quote = c;
416234949Sbapt	    putc(c, f);
417234949Sbapt	    for (;;)
418234949Sbapt	    {
419234949Sbapt		c = *cptr++;
420234949Sbapt		putc(c, f);
421234949Sbapt		if (c == quote)
422234949Sbapt		{
423234949Sbapt		    need_newline = 1;
424234949Sbapt		    FREE(s_line);
425234949Sbapt		    goto loop;
426234949Sbapt		}
427234949Sbapt		if (c == '\n')
428234949Sbapt		    unterminated_string(s_lineno, s_line, s_cptr);
429234949Sbapt		if (c == '\\')
430234949Sbapt		{
431234949Sbapt		    c = *cptr++;
432234949Sbapt		    putc(c, f);
433234949Sbapt		    if (c == '\n')
434234949Sbapt		    {
435234949Sbapt			get_line();
436234949Sbapt			if (line == 0)
437234949Sbapt			    unterminated_string(s_lineno, s_line, s_cptr);
438234949Sbapt		    }
439234949Sbapt		}
440234949Sbapt	    }
441234949Sbapt	}
442234949Sbapt
443234949Sbapt    case '/':
444234949Sbapt	putc(c, f);
445234949Sbapt	need_newline = 1;
446234949Sbapt	c = *cptr;
447234949Sbapt	if (c == '/')
448234949Sbapt	{
449234949Sbapt	    putc('*', f);
450234949Sbapt	    while ((c = *++cptr) != '\n')
451234949Sbapt	    {
452234949Sbapt		if (c == '*' && cptr[1] == '/')
453234949Sbapt		    fprintf(f, "* ");
454234949Sbapt		else
455234949Sbapt		    putc(c, f);
456234949Sbapt	    }
457234949Sbapt	    fprintf(f, "*/");
458234949Sbapt	    goto next_line;
459234949Sbapt	}
460234949Sbapt	if (c == '*')
461234949Sbapt	{
462234949Sbapt	    int c_lineno = lineno;
463234949Sbapt	    char *c_line = dup_line();
464234949Sbapt	    char *c_cptr = c_line + (cptr - line - 1);
465234949Sbapt
466234949Sbapt	    putc('*', f);
467234949Sbapt	    ++cptr;
468234949Sbapt	    for (;;)
469234949Sbapt	    {
470234949Sbapt		c = *cptr++;
471234949Sbapt		putc(c, f);
472234949Sbapt		if (c == '*' && *cptr == '/')
473234949Sbapt		{
474234949Sbapt		    putc('/', f);
475234949Sbapt		    ++cptr;
476234949Sbapt		    FREE(c_line);
477234949Sbapt		    goto loop;
478234949Sbapt		}
479234949Sbapt		if (c == '\n')
480234949Sbapt		{
481234949Sbapt		    get_line();
482234949Sbapt		    if (line == 0)
483234949Sbapt			unterminated_comment(c_lineno, c_line, c_cptr);
484234949Sbapt		}
485234949Sbapt	    }
486234949Sbapt	}
487234949Sbapt	need_newline = 1;
488234949Sbapt	goto loop;
489234949Sbapt
490234949Sbapt    case '%':
491234949Sbapt    case '\\':
492234949Sbapt	if (*cptr == R_CURL)
493234949Sbapt	{
494234949Sbapt	    if (need_newline)
495234949Sbapt		putc('\n', f);
496234949Sbapt	    ++cptr;
497234949Sbapt	    FREE(t_line);
498234949Sbapt	    return;
499234949Sbapt	}
500234949Sbapt	/* FALLTHRU */
501234949Sbapt
502234949Sbapt    default:
503234949Sbapt	putc(c, f);
504234949Sbapt	need_newline = 1;
505234949Sbapt	goto loop;
506234949Sbapt    }
507234949Sbapt}
508234949Sbapt
509234949Sbaptstatic void
510234949Sbaptputs_both(const char *s)
511234949Sbapt{
512234949Sbapt    fputs(s, text_file);
513234949Sbapt    if (dflag)
514234949Sbapt	fputs(s, union_file);
515234949Sbapt}
516234949Sbapt
517234949Sbaptstatic void
518234949Sbaptputc_both(int c)
519234949Sbapt{
520234949Sbapt    putc(c, text_file);
521234949Sbapt    if (dflag)
522234949Sbapt	putc(c, union_file);
523234949Sbapt}
524234949Sbapt
525234949Sbaptstatic void
526234949Sbaptcopy_union(void)
527234949Sbapt{
528234949Sbapt    int c;
529234949Sbapt    int quote;
530234949Sbapt    int depth;
531234949Sbapt    int u_lineno = lineno;
532234949Sbapt    char *u_line = dup_line();
533234949Sbapt    char *u_cptr = u_line + (cptr - line - 6);
534234949Sbapt
535234949Sbapt    if (unionized)
536234949Sbapt	over_unionized(cptr - 6);
537234949Sbapt    unionized = 1;
538234949Sbapt
539234949Sbapt    if (!lflag)
540234949Sbapt	fprintf(text_file, line_format, lineno, input_file_name);
541234949Sbapt
542234949Sbapt    puts_both("#ifdef YYSTYPE\n");
543234949Sbapt    puts_both("#undef  YYSTYPE_IS_DECLARED\n");
544234949Sbapt    puts_both("#define YYSTYPE_IS_DECLARED 1\n");
545234949Sbapt    puts_both("#endif\n");
546234949Sbapt    puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
547234949Sbapt    puts_both("#define YYSTYPE_IS_DECLARED 1\n");
548234949Sbapt    puts_both("typedef union");
549234949Sbapt
550234949Sbapt    depth = 0;
551234949Sbapt  loop:
552234949Sbapt    c = *cptr++;
553234949Sbapt    putc_both(c);
554234949Sbapt    switch (c)
555234949Sbapt    {
556234949Sbapt    case '\n':
557234949Sbapt      next_line:
558234949Sbapt	get_line();
559234949Sbapt	if (line == 0)
560234949Sbapt	    unterminated_union(u_lineno, u_line, u_cptr);
561234949Sbapt	goto loop;
562234949Sbapt
563234949Sbapt    case L_CURL:
564234949Sbapt	++depth;
565234949Sbapt	goto loop;
566234949Sbapt
567234949Sbapt    case R_CURL:
568234949Sbapt	if (--depth == 0)
569234949Sbapt	{
570234949Sbapt	    puts_both(" YYSTYPE;\n");
571234949Sbapt	    puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n");
572234949Sbapt	    FREE(u_line);
573234949Sbapt	    return;
574234949Sbapt	}
575234949Sbapt	goto loop;
576234949Sbapt
577234949Sbapt    case '\'':
578234949Sbapt    case '"':
579234949Sbapt	{
580234949Sbapt	    int s_lineno = lineno;
581234949Sbapt	    char *s_line = dup_line();
582234949Sbapt	    char *s_cptr = s_line + (cptr - line - 1);
583234949Sbapt
584234949Sbapt	    quote = c;
585234949Sbapt	    for (;;)
586234949Sbapt	    {
587234949Sbapt		c = *cptr++;
588234949Sbapt		putc_both(c);
589234949Sbapt		if (c == quote)
590234949Sbapt		{
591234949Sbapt		    FREE(s_line);
592234949Sbapt		    goto loop;
593234949Sbapt		}
594234949Sbapt		if (c == '\n')
595234949Sbapt		    unterminated_string(s_lineno, s_line, s_cptr);
596234949Sbapt		if (c == '\\')
597234949Sbapt		{
598234949Sbapt		    c = *cptr++;
599234949Sbapt		    putc_both(c);
600234949Sbapt		    if (c == '\n')
601234949Sbapt		    {
602234949Sbapt			get_line();
603234949Sbapt			if (line == 0)
604234949Sbapt			    unterminated_string(s_lineno, s_line, s_cptr);
605234949Sbapt		    }
606234949Sbapt		}
607234949Sbapt	    }
608234949Sbapt	}
609234949Sbapt
610234949Sbapt    case '/':
611234949Sbapt	c = *cptr;
612234949Sbapt	if (c == '/')
613234949Sbapt	{
614234949Sbapt	    putc_both('*');
615234949Sbapt	    while ((c = *++cptr) != '\n')
616234949Sbapt	    {
617234949Sbapt		if (c == '*' && cptr[1] == '/')
618234949Sbapt		{
619234949Sbapt		    puts_both("* ");
620234949Sbapt		}
621234949Sbapt		else
622234949Sbapt		{
623234949Sbapt		    putc_both(c);
624234949Sbapt		}
625234949Sbapt	    }
626234949Sbapt	    puts_both("*/\n");
627234949Sbapt	    goto next_line;
628234949Sbapt	}
629234949Sbapt	if (c == '*')
630234949Sbapt	{
631234949Sbapt	    int c_lineno = lineno;
632234949Sbapt	    char *c_line = dup_line();
633234949Sbapt	    char *c_cptr = c_line + (cptr - line - 1);
634234949Sbapt
635234949Sbapt	    putc_both('*');
636234949Sbapt	    ++cptr;
637234949Sbapt	    for (;;)
638234949Sbapt	    {
639234949Sbapt		c = *cptr++;
640234949Sbapt		putc_both(c);
641234949Sbapt		if (c == '*' && *cptr == '/')
642234949Sbapt		{
643234949Sbapt		    putc_both('/');
644234949Sbapt		    ++cptr;
645234949Sbapt		    FREE(c_line);
646234949Sbapt		    goto loop;
647234949Sbapt		}
648234949Sbapt		if (c == '\n')
649234949Sbapt		{
650234949Sbapt		    get_line();
651234949Sbapt		    if (line == 0)
652234949Sbapt			unterminated_comment(c_lineno, c_line, c_cptr);
653234949Sbapt		}
654234949Sbapt	    }
655234949Sbapt	}
656234949Sbapt	goto loop;
657234949Sbapt
658234949Sbapt    default:
659234949Sbapt	goto loop;
660234949Sbapt    }
661234949Sbapt}
662234949Sbapt
663234949Sbapt/*
664234949Sbapt * Keep a linked list of parameters
665234949Sbapt */
666234949Sbaptstatic void
667234949Sbaptcopy_param(int k)
668234949Sbapt{
669234949Sbapt    char *buf;
670234949Sbapt    int c;
671234949Sbapt    param *head, *p;
672234949Sbapt    int i;
673234949Sbapt    int name, type2;
674234949Sbapt
675234949Sbapt    c = nextc();
676234949Sbapt    if (c == EOF)
677234949Sbapt	unexpected_EOF();
678234949Sbapt    if (c != '{')
679234949Sbapt	goto out;
680234949Sbapt    cptr++;
681234949Sbapt
682234949Sbapt    c = nextc();
683234949Sbapt    if (c == EOF)
684234949Sbapt	unexpected_EOF();
685234949Sbapt    if (c == '}')
686234949Sbapt	goto out;
687234949Sbapt
688234949Sbapt    buf = MALLOC(linesize);
689234949Sbapt    NO_SPACE(buf);
690234949Sbapt
691234949Sbapt    for (i = 0; (c = *cptr++) != '}'; i++)
692234949Sbapt    {
693234949Sbapt	if (c == '\0')
694234949Sbapt	    missing_brace();
695234949Sbapt	if (c == EOF)
696234949Sbapt	    unexpected_EOF();
697234949Sbapt	buf[i] = (char)c;
698234949Sbapt    }
699234949Sbapt
700234949Sbapt    if (i == 0)
701234949Sbapt	goto out;
702234949Sbapt
703234949Sbapt    buf[i--] = '\0';
704234949Sbapt    while (i >= 0 && isspace(UCH(buf[i])))
705234949Sbapt	buf[i--] = '\0';
706234949Sbapt
707234949Sbapt    if (buf[i] == ']')
708234949Sbapt    {
709234949Sbapt	int level = 1;
710234949Sbapt	while (i >= 0 && level > 0 && buf[i] != '[')
711234949Sbapt	{
712234949Sbapt	    if (buf[i] == ']')
713234949Sbapt		++level;
714234949Sbapt	    else if (buf[i] == '[')
715234949Sbapt		--level;
716234949Sbapt	    i--;
717234949Sbapt	}
718234949Sbapt	if (i <= 0)
719234949Sbapt	    unexpected_EOF();
720234949Sbapt	type2 = i--;
721234949Sbapt    }
722234949Sbapt    else
723234949Sbapt    {
724234949Sbapt	type2 = i + 1;
725234949Sbapt    }
726234949Sbapt
727234949Sbapt    while (i >= 0 && (isalnum(UCH(buf[i])) ||
728234949Sbapt		      UCH(buf[i]) == '_'))
729234949Sbapt	i--;
730234949Sbapt
731234949Sbapt    if (!isspace(UCH(buf[i])) && buf[i] != '*')
732234949Sbapt	goto out;
733234949Sbapt
734234949Sbapt    name = i + 1;
735234949Sbapt
736234949Sbapt    p = MALLOC(sizeof(*p));
737234949Sbapt    NO_SPACE(p);
738234949Sbapt
739234949Sbapt    p->type2 = strdup(buf + type2);
740234949Sbapt    NO_SPACE(p->type2);
741234949Sbapt
742234949Sbapt    buf[type2] = '\0';
743234949Sbapt
744234949Sbapt    p->name = strdup(buf + name);
745234949Sbapt    NO_SPACE(p->name);
746234949Sbapt
747234949Sbapt    buf[name] = '\0';
748234949Sbapt    p->type = buf;
749234949Sbapt
750234949Sbapt    if (k == LEX_PARAM)
751234949Sbapt	head = lex_param;
752234949Sbapt    else
753234949Sbapt	head = parse_param;
754234949Sbapt
755234949Sbapt    if (head != NULL)
756234949Sbapt    {
757234949Sbapt	while (head->next)
758234949Sbapt	    head = head->next;
759234949Sbapt	head->next = p;
760234949Sbapt    }
761234949Sbapt    else
762234949Sbapt    {
763234949Sbapt	if (k == LEX_PARAM)
764234949Sbapt	    lex_param = p;
765234949Sbapt	else
766234949Sbapt	    parse_param = p;
767234949Sbapt    }
768234949Sbapt    p->next = NULL;
769234949Sbapt    return;
770234949Sbapt
771234949Sbapt  out:
772234949Sbapt    syntax_error(lineno, line, cptr);
773234949Sbapt}
774234949Sbapt
775234949Sbaptstatic int
776234949Sbapthexval(int c)
777234949Sbapt{
778234949Sbapt    if (c >= '0' && c <= '9')
779234949Sbapt	return (c - '0');
780234949Sbapt    if (c >= 'A' && c <= 'F')
781234949Sbapt	return (c - 'A' + 10);
782234949Sbapt    if (c >= 'a' && c <= 'f')
783234949Sbapt	return (c - 'a' + 10);
784234949Sbapt    return (-1);
785234949Sbapt}
786234949Sbapt
787234949Sbaptstatic bucket *
788234949Sbaptget_literal(void)
789234949Sbapt{
790234949Sbapt    int c, quote;
791234949Sbapt    int i;
792234949Sbapt    int n;
793234949Sbapt    char *s;
794234949Sbapt    bucket *bp;
795234949Sbapt    int s_lineno = lineno;
796234949Sbapt    char *s_line = dup_line();
797234949Sbapt    char *s_cptr = s_line + (cptr - line);
798234949Sbapt
799234949Sbapt    quote = *cptr++;
800234949Sbapt    cinc = 0;
801234949Sbapt    for (;;)
802234949Sbapt    {
803234949Sbapt	c = *cptr++;
804234949Sbapt	if (c == quote)
805234949Sbapt	    break;
806234949Sbapt	if (c == '\n')
807234949Sbapt	    unterminated_string(s_lineno, s_line, s_cptr);
808234949Sbapt	if (c == '\\')
809234949Sbapt	{
810234949Sbapt	    char *c_cptr = cptr - 1;
811234949Sbapt
812234949Sbapt	    c = *cptr++;
813234949Sbapt	    switch (c)
814234949Sbapt	    {
815234949Sbapt	    case '\n':
816234949Sbapt		get_line();
817234949Sbapt		if (line == 0)
818234949Sbapt		    unterminated_string(s_lineno, s_line, s_cptr);
819234949Sbapt		continue;
820234949Sbapt
821234949Sbapt	    case '0':
822234949Sbapt	    case '1':
823234949Sbapt	    case '2':
824234949Sbapt	    case '3':
825234949Sbapt	    case '4':
826234949Sbapt	    case '5':
827234949Sbapt	    case '6':
828234949Sbapt	    case '7':
829234949Sbapt		n = c - '0';
830234949Sbapt		c = *cptr;
831234949Sbapt		if (IS_OCTAL(c))
832234949Sbapt		{
833234949Sbapt		    n = (n << 3) + (c - '0');
834234949Sbapt		    c = *++cptr;
835234949Sbapt		    if (IS_OCTAL(c))
836234949Sbapt		    {
837234949Sbapt			n = (n << 3) + (c - '0');
838234949Sbapt			++cptr;
839234949Sbapt		    }
840234949Sbapt		}
841234949Sbapt		if (n > MAXCHAR)
842234949Sbapt		    illegal_character(c_cptr);
843234949Sbapt		c = n;
844234949Sbapt		break;
845234949Sbapt
846234949Sbapt	    case 'x':
847234949Sbapt		c = *cptr++;
848234949Sbapt		n = hexval(c);
849234949Sbapt		if (n < 0 || n >= 16)
850234949Sbapt		    illegal_character(c_cptr);
851234949Sbapt		for (;;)
852234949Sbapt		{
853234949Sbapt		    c = *cptr;
854234949Sbapt		    i = hexval(c);
855234949Sbapt		    if (i < 0 || i >= 16)
856234949Sbapt			break;
857234949Sbapt		    ++cptr;
858234949Sbapt		    n = (n << 4) + i;
859234949Sbapt		    if (n > MAXCHAR)
860234949Sbapt			illegal_character(c_cptr);
861234949Sbapt		}
862234949Sbapt		c = n;
863234949Sbapt		break;
864234949Sbapt
865234949Sbapt	    case 'a':
866234949Sbapt		c = 7;
867234949Sbapt		break;
868234949Sbapt	    case 'b':
869234949Sbapt		c = '\b';
870234949Sbapt		break;
871234949Sbapt	    case 'f':
872234949Sbapt		c = '\f';
873234949Sbapt		break;
874234949Sbapt	    case 'n':
875234949Sbapt		c = '\n';
876234949Sbapt		break;
877234949Sbapt	    case 'r':
878234949Sbapt		c = '\r';
879234949Sbapt		break;
880234949Sbapt	    case 't':
881234949Sbapt		c = '\t';
882234949Sbapt		break;
883234949Sbapt	    case 'v':
884234949Sbapt		c = '\v';
885234949Sbapt		break;
886234949Sbapt	    }
887234949Sbapt	}
888234949Sbapt	cachec(c);
889234949Sbapt    }
890234949Sbapt    FREE(s_line);
891234949Sbapt
892234949Sbapt    n = cinc;
893234949Sbapt    s = MALLOC(n);
894234949Sbapt    NO_SPACE(s);
895234949Sbapt
896234949Sbapt    for (i = 0; i < n; ++i)
897234949Sbapt	s[i] = cache[i];
898234949Sbapt
899234949Sbapt    cinc = 0;
900234949Sbapt    if (n == 1)
901234949Sbapt	cachec('\'');
902234949Sbapt    else
903234949Sbapt	cachec('"');
904234949Sbapt
905234949Sbapt    for (i = 0; i < n; ++i)
906234949Sbapt    {
907234949Sbapt	c = UCH(s[i]);
908234949Sbapt	if (c == '\\' || c == cache[0])
909234949Sbapt	{
910234949Sbapt	    cachec('\\');
911234949Sbapt	    cachec(c);
912234949Sbapt	}
913234949Sbapt	else if (isprint(c))
914234949Sbapt	    cachec(c);
915234949Sbapt	else
916234949Sbapt	{
917234949Sbapt	    cachec('\\');
918234949Sbapt	    switch (c)
919234949Sbapt	    {
920234949Sbapt	    case 7:
921234949Sbapt		cachec('a');
922234949Sbapt		break;
923234949Sbapt	    case '\b':
924234949Sbapt		cachec('b');
925234949Sbapt		break;
926234949Sbapt	    case '\f':
927234949Sbapt		cachec('f');
928234949Sbapt		break;
929234949Sbapt	    case '\n':
930234949Sbapt		cachec('n');
931234949Sbapt		break;
932234949Sbapt	    case '\r':
933234949Sbapt		cachec('r');
934234949Sbapt		break;
935234949Sbapt	    case '\t':
936234949Sbapt		cachec('t');
937234949Sbapt		break;
938234949Sbapt	    case '\v':
939234949Sbapt		cachec('v');
940234949Sbapt		break;
941234949Sbapt	    default:
942234949Sbapt		cachec(((c >> 6) & 7) + '0');
943234949Sbapt		cachec(((c >> 3) & 7) + '0');
944234949Sbapt		cachec((c & 7) + '0');
945234949Sbapt		break;
946234949Sbapt	    }
947234949Sbapt	}
948234949Sbapt    }
949234949Sbapt
950234949Sbapt    if (n == 1)
951234949Sbapt	cachec('\'');
952234949Sbapt    else
953234949Sbapt	cachec('"');
954234949Sbapt
955234949Sbapt    cachec(NUL);
956234949Sbapt    bp = lookup(cache);
957234949Sbapt    bp->class = TERM;
958234949Sbapt    if (n == 1 && bp->value == UNDEFINED)
959234949Sbapt	bp->value = UCH(*s);
960234949Sbapt    FREE(s);
961234949Sbapt
962234949Sbapt    return (bp);
963234949Sbapt}
964234949Sbapt
965234949Sbaptstatic int
966234949Sbaptis_reserved(char *name)
967234949Sbapt{
968234949Sbapt    char *s;
969234949Sbapt
970234949Sbapt    if (strcmp(name, ".") == 0 ||
971234949Sbapt	strcmp(name, "$accept") == 0 ||
972234949Sbapt	strcmp(name, "$end") == 0)
973234949Sbapt	return (1);
974234949Sbapt
975234949Sbapt    if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2])))
976234949Sbapt    {
977234949Sbapt	s = name + 3;
978234949Sbapt	while (isdigit(UCH(*s)))
979234949Sbapt	    ++s;
980234949Sbapt	if (*s == NUL)
981234949Sbapt	    return (1);
982234949Sbapt    }
983234949Sbapt
984234949Sbapt    return (0);
985234949Sbapt}
986234949Sbapt
987234949Sbaptstatic bucket *
988234949Sbaptget_name(void)
989234949Sbapt{
990234949Sbapt    int c;
991234949Sbapt
992234949Sbapt    cinc = 0;
993234949Sbapt    for (c = *cptr; IS_IDENT(c); c = *++cptr)
994234949Sbapt	cachec(c);
995234949Sbapt    cachec(NUL);
996234949Sbapt
997234949Sbapt    if (is_reserved(cache))
998234949Sbapt	used_reserved(cache);
999234949Sbapt
1000234949Sbapt    return (lookup(cache));
1001234949Sbapt}
1002234949Sbapt
1003234949Sbaptstatic Value_t
1004234949Sbaptget_number(void)
1005234949Sbapt{
1006234949Sbapt    int c;
1007234949Sbapt    Value_t n;
1008234949Sbapt
1009234949Sbapt    n = 0;
1010234949Sbapt    for (c = *cptr; isdigit(c); c = *++cptr)
1011234949Sbapt	n = (Value_t) (10 * n + (c - '0'));
1012234949Sbapt
1013234949Sbapt    return (n);
1014234949Sbapt}
1015234949Sbapt
1016234949Sbaptstatic char *
1017234949Sbaptget_tag(void)
1018234949Sbapt{
1019234949Sbapt    int c;
1020234949Sbapt    int i;
1021234949Sbapt    char *s;
1022234949Sbapt    int t_lineno = lineno;
1023234949Sbapt    char *t_line = dup_line();
1024234949Sbapt    char *t_cptr = t_line + (cptr - line);
1025234949Sbapt
1026234949Sbapt    ++cptr;
1027234949Sbapt    c = nextc();
1028234949Sbapt    if (c == EOF)
1029234949Sbapt	unexpected_EOF();
1030234949Sbapt    if (!isalpha(c) && c != '_' && c != '$')
1031234949Sbapt	illegal_tag(t_lineno, t_line, t_cptr);
1032234949Sbapt
1033234949Sbapt    cinc = 0;
1034234949Sbapt    do
1035234949Sbapt    {
1036234949Sbapt	cachec(c);
1037234949Sbapt	c = *++cptr;
1038234949Sbapt    }
1039234949Sbapt    while (IS_IDENT(c));
1040234949Sbapt    cachec(NUL);
1041234949Sbapt
1042234949Sbapt    c = nextc();
1043234949Sbapt    if (c == EOF)
1044234949Sbapt	unexpected_EOF();
1045234949Sbapt    if (c != '>')
1046234949Sbapt	illegal_tag(t_lineno, t_line, t_cptr);
1047234949Sbapt    ++cptr;
1048234949Sbapt
1049234949Sbapt    for (i = 0; i < ntags; ++i)
1050234949Sbapt    {
1051234949Sbapt	if (strcmp(cache, tag_table[i]) == 0)
1052234949Sbapt	{
1053234949Sbapt	    FREE(t_line);
1054234949Sbapt	    return (tag_table[i]);
1055234949Sbapt	}
1056234949Sbapt    }
1057234949Sbapt
1058234949Sbapt    if (ntags >= tagmax)
1059234949Sbapt    {
1060234949Sbapt	tagmax += 16;
1061234949Sbapt	tag_table = (char **)
1062234949Sbapt	    (tag_table
1063234949Sbapt	     ? REALLOC(tag_table, (unsigned)tagmax * sizeof(char *))
1064234949Sbapt	     : MALLOC((unsigned)tagmax * sizeof(char *)));
1065234949Sbapt	NO_SPACE(tag_table);
1066234949Sbapt    }
1067234949Sbapt
1068234949Sbapt    s = MALLOC(cinc);
1069234949Sbapt    NO_SPACE(s);
1070234949Sbapt
1071234949Sbapt    strcpy(s, cache);
1072234949Sbapt    tag_table[ntags] = s;
1073234949Sbapt    ++ntags;
1074234949Sbapt    FREE(t_line);
1075234949Sbapt    return (s);
1076234949Sbapt}
1077234949Sbapt
1078234949Sbaptstatic void
1079234949Sbaptdeclare_tokens(int assoc)
1080234949Sbapt{
1081234949Sbapt    int c;
1082234949Sbapt    bucket *bp;
1083234949Sbapt    Value_t value;
1084234949Sbapt    char *tag = 0;
1085234949Sbapt
1086234949Sbapt    if (assoc != TOKEN)
1087234949Sbapt	++prec;
1088234949Sbapt
1089234949Sbapt    c = nextc();
1090234949Sbapt    if (c == EOF)
1091234949Sbapt	unexpected_EOF();
1092234949Sbapt    if (c == '<')
1093234949Sbapt    {
1094234949Sbapt	tag = get_tag();
1095234949Sbapt	c = nextc();
1096234949Sbapt	if (c == EOF)
1097234949Sbapt	    unexpected_EOF();
1098234949Sbapt    }
1099234949Sbapt
1100234949Sbapt    for (;;)
1101234949Sbapt    {
1102234949Sbapt	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1103234949Sbapt	    bp = get_name();
1104234949Sbapt	else if (c == '\'' || c == '"')
1105234949Sbapt	    bp = get_literal();
1106234949Sbapt	else
1107234949Sbapt	    return;
1108234949Sbapt
1109234949Sbapt	if (bp == goal)
1110234949Sbapt	    tokenized_start(bp->name);
1111234949Sbapt	bp->class = TERM;
1112234949Sbapt
1113234949Sbapt	if (tag)
1114234949Sbapt	{
1115234949Sbapt	    if (bp->tag && tag != bp->tag)
1116234949Sbapt		retyped_warning(bp->name);
1117234949Sbapt	    bp->tag = tag;
1118234949Sbapt	}
1119234949Sbapt
1120234949Sbapt	if (assoc != TOKEN)
1121234949Sbapt	{
1122234949Sbapt	    if (bp->prec && prec != bp->prec)
1123234949Sbapt		reprec_warning(bp->name);
1124234949Sbapt	    bp->assoc = (Assoc_t) assoc;
1125234949Sbapt	    bp->prec = prec;
1126234949Sbapt	}
1127234949Sbapt
1128234949Sbapt	c = nextc();
1129234949Sbapt	if (c == EOF)
1130234949Sbapt	    unexpected_EOF();
1131234949Sbapt
1132234949Sbapt	if (isdigit(c))
1133234949Sbapt	{
1134234949Sbapt	    value = get_number();
1135234949Sbapt	    if (bp->value != UNDEFINED && value != bp->value)
1136234949Sbapt		revalued_warning(bp->name);
1137234949Sbapt	    bp->value = value;
1138234949Sbapt	    c = nextc();
1139234949Sbapt	    if (c == EOF)
1140234949Sbapt		unexpected_EOF();
1141234949Sbapt	}
1142234949Sbapt    }
1143234949Sbapt}
1144234949Sbapt
1145234949Sbapt/*
1146234949Sbapt * %expect requires special handling
1147234949Sbapt * as it really isn't part of the yacc
1148234949Sbapt * grammar only a flag for yacc proper.
1149234949Sbapt */
1150234949Sbaptstatic void
1151234949Sbaptdeclare_expect(int assoc)
1152234949Sbapt{
1153234949Sbapt    int c;
1154234949Sbapt
1155234949Sbapt    if (assoc != EXPECT && assoc != EXPECT_RR)
1156234949Sbapt	++prec;
1157234949Sbapt
1158234949Sbapt    /*
1159234949Sbapt     * Stay away from nextc - doesn't
1160234949Sbapt     * detect EOL and will read to EOF.
1161234949Sbapt     */
1162234949Sbapt    c = *++cptr;
1163234949Sbapt    if (c == EOF)
1164234949Sbapt	unexpected_EOF();
1165234949Sbapt
1166234949Sbapt    for (;;)
1167234949Sbapt    {
1168234949Sbapt	if (isdigit(c))
1169234949Sbapt	{
1170234949Sbapt	    if (assoc == EXPECT)
1171234949Sbapt		SRexpect = get_number();
1172234949Sbapt	    else
1173234949Sbapt		RRexpect = get_number();
1174234949Sbapt	    break;
1175234949Sbapt	}
1176234949Sbapt	/*
1177234949Sbapt	 * Looking for number before EOL.
1178234949Sbapt	 * Spaces, tabs, and numbers are ok,
1179234949Sbapt	 * words, punc., etc. are syntax errors.
1180234949Sbapt	 */
1181234949Sbapt	else if (c == '\n' || isalpha(c) || !isspace(c))
1182234949Sbapt	{
1183234949Sbapt	    syntax_error(lineno, line, cptr);
1184234949Sbapt	}
1185234949Sbapt	else
1186234949Sbapt	{
1187234949Sbapt	    c = *++cptr;
1188234949Sbapt	    if (c == EOF)
1189234949Sbapt		unexpected_EOF();
1190234949Sbapt	}
1191234949Sbapt    }
1192234949Sbapt}
1193234949Sbapt
1194234949Sbaptstatic void
1195234949Sbaptdeclare_types(void)
1196234949Sbapt{
1197234949Sbapt    int c;
1198234949Sbapt    bucket *bp;
1199234949Sbapt    char *tag;
1200234949Sbapt
1201234949Sbapt    c = nextc();
1202234949Sbapt    if (c == EOF)
1203234949Sbapt	unexpected_EOF();
1204234949Sbapt    if (c != '<')
1205234949Sbapt	syntax_error(lineno, line, cptr);
1206234949Sbapt    tag = get_tag();
1207234949Sbapt
1208234949Sbapt    for (;;)
1209234949Sbapt    {
1210234949Sbapt	c = nextc();
1211234949Sbapt	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1212234949Sbapt	    bp = get_name();
1213234949Sbapt	else if (c == '\'' || c == '"')
1214234949Sbapt	    bp = get_literal();
1215234949Sbapt	else
1216234949Sbapt	    return;
1217234949Sbapt
1218234949Sbapt	if (bp->tag && tag != bp->tag)
1219234949Sbapt	    retyped_warning(bp->name);
1220234949Sbapt	bp->tag = tag;
1221234949Sbapt    }
1222234949Sbapt}
1223234949Sbapt
1224234949Sbaptstatic void
1225234949Sbaptdeclare_start(void)
1226234949Sbapt{
1227234949Sbapt    int c;
1228234949Sbapt    bucket *bp;
1229234949Sbapt
1230234949Sbapt    c = nextc();
1231234949Sbapt    if (c == EOF)
1232234949Sbapt	unexpected_EOF();
1233234949Sbapt    if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1234234949Sbapt	syntax_error(lineno, line, cptr);
1235234949Sbapt    bp = get_name();
1236234949Sbapt    if (bp->class == TERM)
1237234949Sbapt	terminal_start(bp->name);
1238234949Sbapt    if (goal && goal != bp)
1239234949Sbapt	restarted_warning();
1240234949Sbapt    goal = bp;
1241234949Sbapt}
1242234949Sbapt
1243234949Sbaptstatic void
1244234949Sbaptread_declarations(void)
1245234949Sbapt{
1246234949Sbapt    int c, k;
1247234949Sbapt
1248234949Sbapt    cache_size = 256;
1249234949Sbapt    cache = MALLOC(cache_size);
1250234949Sbapt    NO_SPACE(cache);
1251234949Sbapt
1252234949Sbapt    for (;;)
1253234949Sbapt    {
1254234949Sbapt	c = nextc();
1255234949Sbapt	if (c == EOF)
1256234949Sbapt	    unexpected_EOF();
1257234949Sbapt	if (c != '%')
1258234949Sbapt	    syntax_error(lineno, line, cptr);
1259234949Sbapt	switch (k = keyword())
1260234949Sbapt	{
1261234949Sbapt	case MARK:
1262234949Sbapt	    return;
1263234949Sbapt
1264234949Sbapt	case IDENT:
1265234949Sbapt	    copy_ident();
1266234949Sbapt	    break;
1267234949Sbapt
1268234949Sbapt	case TEXT:
1269234949Sbapt	    copy_text();
1270234949Sbapt	    break;
1271234949Sbapt
1272234949Sbapt	case UNION:
1273234949Sbapt	    copy_union();
1274234949Sbapt	    break;
1275234949Sbapt
1276234949Sbapt	case TOKEN:
1277234949Sbapt	case LEFT:
1278234949Sbapt	case RIGHT:
1279234949Sbapt	case NONASSOC:
1280234949Sbapt	    declare_tokens(k);
1281234949Sbapt	    break;
1282234949Sbapt
1283234949Sbapt	case EXPECT:
1284234949Sbapt	case EXPECT_RR:
1285234949Sbapt	    declare_expect(k);
1286234949Sbapt	    break;
1287234949Sbapt
1288234949Sbapt	case TYPE:
1289234949Sbapt	    declare_types();
1290234949Sbapt	    break;
1291234949Sbapt
1292234949Sbapt	case START:
1293234949Sbapt	    declare_start();
1294234949Sbapt	    break;
1295234949Sbapt
1296234949Sbapt	case PURE_PARSER:
1297234949Sbapt	    pure_parser = 1;
1298234949Sbapt	    break;
1299234949Sbapt
1300234949Sbapt	case PARSE_PARAM:
1301234949Sbapt	case LEX_PARAM:
1302234949Sbapt	    copy_param(k);
1303234949Sbapt	    break;
1304234949Sbapt
1305234949Sbapt	case POSIX_YACC:
1306234949Sbapt	    /* noop for bison compatibility. byacc is already designed to be posix
1307234949Sbapt	     * yacc compatible. */
1308234949Sbapt	    break;
1309234949Sbapt	}
1310234949Sbapt    }
1311234949Sbapt}
1312234949Sbapt
1313234949Sbaptstatic void
1314234949Sbaptinitialize_grammar(void)
1315234949Sbapt{
1316234949Sbapt    nitems = 4;
1317234949Sbapt    maxitems = 300;
1318234949Sbapt
1319234949Sbapt    pitem = (bucket **)MALLOC((unsigned)maxitems * sizeof(bucket *));
1320234949Sbapt    NO_SPACE(pitem);
1321234949Sbapt
1322234949Sbapt    pitem[0] = 0;
1323234949Sbapt    pitem[1] = 0;
1324234949Sbapt    pitem[2] = 0;
1325234949Sbapt    pitem[3] = 0;
1326234949Sbapt
1327234949Sbapt    nrules = 3;
1328234949Sbapt    maxrules = 100;
1329234949Sbapt
1330234949Sbapt    plhs = (bucket **)MALLOC((unsigned)maxrules * sizeof(bucket *));
1331234949Sbapt    NO_SPACE(plhs);
1332234949Sbapt
1333234949Sbapt    plhs[0] = 0;
1334234949Sbapt    plhs[1] = 0;
1335234949Sbapt    plhs[2] = 0;
1336234949Sbapt
1337234949Sbapt    rprec = (short *)MALLOC((unsigned)maxrules * sizeof(short));
1338234949Sbapt    NO_SPACE(rprec);
1339234949Sbapt
1340234949Sbapt    rprec[0] = 0;
1341234949Sbapt    rprec[1] = 0;
1342234949Sbapt    rprec[2] = 0;
1343234949Sbapt
1344234949Sbapt    rassoc = (char *)MALLOC((unsigned)maxrules * sizeof(char));
1345234949Sbapt    NO_SPACE(rassoc);
1346234949Sbapt
1347234949Sbapt    rassoc[0] = TOKEN;
1348234949Sbapt    rassoc[1] = TOKEN;
1349234949Sbapt    rassoc[2] = TOKEN;
1350234949Sbapt}
1351234949Sbapt
1352234949Sbaptstatic void
1353234949Sbaptexpand_items(void)
1354234949Sbapt{
1355234949Sbapt    maxitems += 300;
1356234949Sbapt    pitem = (bucket **)REALLOC(pitem, (unsigned)maxitems * sizeof(bucket *));
1357234949Sbapt    NO_SPACE(pitem);
1358234949Sbapt}
1359234949Sbapt
1360234949Sbaptstatic void
1361234949Sbaptexpand_rules(void)
1362234949Sbapt{
1363234949Sbapt    maxrules += 100;
1364234949Sbapt
1365234949Sbapt    plhs = (bucket **)REALLOC(plhs, (unsigned)maxrules * sizeof(bucket *));
1366234949Sbapt    NO_SPACE(plhs);
1367234949Sbapt
1368234949Sbapt    rprec = (short *)REALLOC(rprec, (unsigned)maxrules * sizeof(short));
1369234949Sbapt    NO_SPACE(rprec);
1370234949Sbapt
1371234949Sbapt    rassoc = (char *)REALLOC(rassoc, (unsigned)maxrules * sizeof(char));
1372234949Sbapt    NO_SPACE(rassoc);
1373234949Sbapt}
1374234949Sbapt
1375234949Sbaptstatic void
1376234949Sbaptadvance_to_start(void)
1377234949Sbapt{
1378234949Sbapt    int c;
1379234949Sbapt    bucket *bp;
1380234949Sbapt    char *s_cptr;
1381234949Sbapt    int s_lineno;
1382234949Sbapt
1383234949Sbapt    for (;;)
1384234949Sbapt    {
1385234949Sbapt	c = nextc();
1386234949Sbapt	if (c != '%')
1387234949Sbapt	    break;
1388234949Sbapt	s_cptr = cptr;
1389234949Sbapt	switch (keyword())
1390234949Sbapt	{
1391234949Sbapt	case MARK:
1392234949Sbapt	    no_grammar();
1393234949Sbapt
1394234949Sbapt	case TEXT:
1395234949Sbapt	    copy_text();
1396234949Sbapt	    break;
1397234949Sbapt
1398234949Sbapt	case START:
1399234949Sbapt	    declare_start();
1400234949Sbapt	    break;
1401234949Sbapt
1402234949Sbapt	default:
1403234949Sbapt	    syntax_error(lineno, line, s_cptr);
1404234949Sbapt	}
1405234949Sbapt    }
1406234949Sbapt
1407234949Sbapt    c = nextc();
1408234949Sbapt    if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1409234949Sbapt	syntax_error(lineno, line, cptr);
1410234949Sbapt    bp = get_name();
1411234949Sbapt    if (goal == 0)
1412234949Sbapt    {
1413234949Sbapt	if (bp->class == TERM)
1414234949Sbapt	    terminal_start(bp->name);
1415234949Sbapt	goal = bp;
1416234949Sbapt    }
1417234949Sbapt
1418234949Sbapt    s_lineno = lineno;
1419234949Sbapt    c = nextc();
1420234949Sbapt    if (c == EOF)
1421234949Sbapt	unexpected_EOF();
1422234949Sbapt    if (c != ':')
1423234949Sbapt	syntax_error(lineno, line, cptr);
1424234949Sbapt    start_rule(bp, s_lineno);
1425234949Sbapt    ++cptr;
1426234949Sbapt}
1427234949Sbapt
1428234949Sbaptstatic void
1429234949Sbaptstart_rule(bucket *bp, int s_lineno)
1430234949Sbapt{
1431234949Sbapt    if (bp->class == TERM)
1432234949Sbapt	terminal_lhs(s_lineno);
1433234949Sbapt    bp->class = NONTERM;
1434234949Sbapt    if (nrules >= maxrules)
1435234949Sbapt	expand_rules();
1436234949Sbapt    plhs[nrules] = bp;
1437234949Sbapt    rprec[nrules] = UNDEFINED;
1438234949Sbapt    rassoc[nrules] = TOKEN;
1439234949Sbapt}
1440234949Sbapt
1441234949Sbaptstatic void
1442234949Sbaptend_rule(void)
1443234949Sbapt{
1444234949Sbapt    int i;
1445234949Sbapt
1446234949Sbapt    if (!last_was_action && plhs[nrules]->tag)
1447234949Sbapt    {
1448234949Sbapt	if (pitem[nitems - 1])
1449234949Sbapt	{
1450234949Sbapt	    for (i = nitems - 1; (i > 0) && pitem[i]; --i)
1451234949Sbapt		continue;
1452234949Sbapt	    if (pitem[i + 1] == 0 || pitem[i + 1]->tag != plhs[nrules]->tag)
1453234949Sbapt		default_action_warning();
1454234949Sbapt	}
1455234949Sbapt	else
1456234949Sbapt	{
1457234949Sbapt	    default_action_warning();
1458234949Sbapt	}
1459234949Sbapt    }
1460234949Sbapt
1461234949Sbapt    last_was_action = 0;
1462234949Sbapt    if (nitems >= maxitems)
1463234949Sbapt	expand_items();
1464234949Sbapt    pitem[nitems] = 0;
1465234949Sbapt    ++nitems;
1466234949Sbapt    ++nrules;
1467234949Sbapt}
1468234949Sbapt
1469234949Sbaptstatic void
1470234949Sbaptinsert_empty_rule(void)
1471234949Sbapt{
1472234949Sbapt    bucket *bp, **bpp;
1473234949Sbapt
1474234949Sbapt    assert(cache);
1475234949Sbapt    sprintf(cache, "$$%d", ++gensym);
1476234949Sbapt    bp = make_bucket(cache);
1477234949Sbapt    last_symbol->next = bp;
1478234949Sbapt    last_symbol = bp;
1479234949Sbapt    bp->tag = plhs[nrules]->tag;
1480234949Sbapt    bp->class = NONTERM;
1481234949Sbapt
1482234949Sbapt    if ((nitems += 2) > maxitems)
1483234949Sbapt	expand_items();
1484234949Sbapt    bpp = pitem + nitems - 1;
1485234949Sbapt    *bpp-- = bp;
1486234949Sbapt    while ((bpp[0] = bpp[-1]) != 0)
1487234949Sbapt	--bpp;
1488234949Sbapt
1489234949Sbapt    if (++nrules >= maxrules)
1490234949Sbapt	expand_rules();
1491234949Sbapt    plhs[nrules] = plhs[nrules - 1];
1492234949Sbapt    plhs[nrules - 1] = bp;
1493234949Sbapt    rprec[nrules] = rprec[nrules - 1];
1494234949Sbapt    rprec[nrules - 1] = 0;
1495234949Sbapt    rassoc[nrules] = rassoc[nrules - 1];
1496234949Sbapt    rassoc[nrules - 1] = TOKEN;
1497234949Sbapt}
1498234949Sbapt
1499234949Sbaptstatic void
1500234949Sbaptadd_symbol(void)
1501234949Sbapt{
1502234949Sbapt    int c;
1503234949Sbapt    bucket *bp;
1504234949Sbapt    int s_lineno = lineno;
1505234949Sbapt
1506234949Sbapt    c = *cptr;
1507234949Sbapt    if (c == '\'' || c == '"')
1508234949Sbapt	bp = get_literal();
1509234949Sbapt    else
1510234949Sbapt	bp = get_name();
1511234949Sbapt
1512234949Sbapt    c = nextc();
1513234949Sbapt    if (c == ':')
1514234949Sbapt    {
1515234949Sbapt	end_rule();
1516234949Sbapt	start_rule(bp, s_lineno);
1517234949Sbapt	++cptr;
1518234949Sbapt	return;
1519234949Sbapt    }
1520234949Sbapt
1521234949Sbapt    if (last_was_action)
1522234949Sbapt	insert_empty_rule();
1523234949Sbapt    last_was_action = 0;
1524234949Sbapt
1525234949Sbapt    if (++nitems > maxitems)
1526234949Sbapt	expand_items();
1527234949Sbapt    pitem[nitems - 1] = bp;
1528234949Sbapt}
1529234949Sbapt
1530234949Sbaptstatic char *
1531234949Sbaptafter_blanks(char *s)
1532234949Sbapt{
1533234949Sbapt    while (*s != '\0' && isspace(UCH(*s)))
1534234949Sbapt	++s;
1535234949Sbapt    return s;
1536234949Sbapt}
1537234949Sbapt
1538234949Sbaptstatic void
1539234949Sbaptcopy_action(void)
1540234949Sbapt{
1541234949Sbapt    int c;
1542234949Sbapt    int i, n;
1543234949Sbapt    int depth;
1544234949Sbapt    int quote;
1545234949Sbapt    char *tag;
1546234949Sbapt    FILE *f = action_file;
1547234949Sbapt    int a_lineno = lineno;
1548234949Sbapt    char *a_line = dup_line();
1549234949Sbapt    char *a_cptr = a_line + (cptr - line);
1550234949Sbapt
1551234949Sbapt    if (last_was_action)
1552234949Sbapt	insert_empty_rule();
1553234949Sbapt    last_was_action = 1;
1554234949Sbapt
1555234949Sbapt    fprintf(f, "case %d:\n", nrules - 2);
1556234949Sbapt    if (!lflag)
1557234949Sbapt	fprintf(f, line_format, lineno, input_file_name);
1558234949Sbapt    if (*cptr == '=')
1559234949Sbapt	++cptr;
1560234949Sbapt
1561234949Sbapt    /* avoid putting curly-braces in first column, to ease editing */
1562234949Sbapt    if (*after_blanks(cptr) == L_CURL)
1563234949Sbapt    {
1564234949Sbapt	putc('\t', f);
1565234949Sbapt	cptr = after_blanks(cptr);
1566234949Sbapt    }
1567234949Sbapt
1568234949Sbapt    n = 0;
1569234949Sbapt    for (i = nitems - 1; pitem[i]; --i)
1570234949Sbapt	++n;
1571234949Sbapt
1572234949Sbapt    depth = 0;
1573234949Sbapt  loop:
1574234949Sbapt    c = *cptr;
1575234949Sbapt    if (c == '$')
1576234949Sbapt    {
1577234949Sbapt	if (cptr[1] == '<')
1578234949Sbapt	{
1579234949Sbapt	    int d_lineno = lineno;
1580234949Sbapt	    char *d_line = dup_line();
1581234949Sbapt	    char *d_cptr = d_line + (cptr - line);
1582234949Sbapt
1583234949Sbapt	    ++cptr;
1584234949Sbapt	    tag = get_tag();
1585234949Sbapt	    c = *cptr;
1586234949Sbapt	    if (c == '$')
1587234949Sbapt	    {
1588234949Sbapt		fprintf(f, "yyval.%s", tag);
1589234949Sbapt		++cptr;
1590234949Sbapt		FREE(d_line);
1591234949Sbapt		goto loop;
1592234949Sbapt	    }
1593234949Sbapt	    else if (isdigit(c))
1594234949Sbapt	    {
1595234949Sbapt		i = get_number();
1596234949Sbapt		if (i > n)
1597234949Sbapt		    dollar_warning(d_lineno, i);
1598234949Sbapt		fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1599234949Sbapt		FREE(d_line);
1600234949Sbapt		goto loop;
1601234949Sbapt	    }
1602234949Sbapt	    else if (c == '-' && isdigit(UCH(cptr[1])))
1603234949Sbapt	    {
1604234949Sbapt		++cptr;
1605234949Sbapt		i = -get_number() - n;
1606234949Sbapt		fprintf(f, "yystack.l_mark[%d].%s", i, tag);
1607234949Sbapt		FREE(d_line);
1608234949Sbapt		goto loop;
1609234949Sbapt	    }
1610234949Sbapt	    else
1611234949Sbapt		dollar_error(d_lineno, d_line, d_cptr);
1612234949Sbapt	}
1613234949Sbapt	else if (cptr[1] == '$')
1614234949Sbapt	{
1615234949Sbapt	    if (ntags)
1616234949Sbapt	    {
1617234949Sbapt		tag = plhs[nrules]->tag;
1618234949Sbapt		if (tag == 0)
1619234949Sbapt		    untyped_lhs();
1620234949Sbapt		fprintf(f, "yyval.%s", tag);
1621234949Sbapt	    }
1622234949Sbapt	    else
1623234949Sbapt		fprintf(f, "yyval");
1624234949Sbapt	    cptr += 2;
1625234949Sbapt	    goto loop;
1626234949Sbapt	}
1627234949Sbapt	else if (isdigit(UCH(cptr[1])))
1628234949Sbapt	{
1629234949Sbapt	    ++cptr;
1630234949Sbapt	    i = get_number();
1631234949Sbapt	    if (ntags)
1632234949Sbapt	    {
1633234949Sbapt		if (i <= 0 || i > n)
1634234949Sbapt		    unknown_rhs(i);
1635234949Sbapt		tag = pitem[nitems + i - n - 1]->tag;
1636234949Sbapt		if (tag == 0)
1637234949Sbapt		    untyped_rhs(i, pitem[nitems + i - n - 1]->name);
1638234949Sbapt		fprintf(f, "yystack.l_mark[%d].%s", i - n, tag);
1639234949Sbapt	    }
1640234949Sbapt	    else
1641234949Sbapt	    {
1642234949Sbapt		if (i > n)
1643234949Sbapt		    dollar_warning(lineno, i);
1644234949Sbapt		fprintf(f, "yystack.l_mark[%d]", i - n);
1645234949Sbapt	    }
1646234949Sbapt	    goto loop;
1647234949Sbapt	}
1648234949Sbapt	else if (cptr[1] == '-')
1649234949Sbapt	{
1650234949Sbapt	    cptr += 2;
1651234949Sbapt	    i = get_number();
1652234949Sbapt	    if (ntags)
1653234949Sbapt		unknown_rhs(-i);
1654234949Sbapt	    fprintf(f, "yystack.l_mark[%d]", -i - n);
1655234949Sbapt	    goto loop;
1656234949Sbapt	}
1657234949Sbapt    }
1658234949Sbapt    if (isalpha(c) || c == '_' || c == '$')
1659234949Sbapt    {
1660234949Sbapt	do
1661234949Sbapt	{
1662234949Sbapt	    putc(c, f);
1663234949Sbapt	    c = *++cptr;
1664234949Sbapt	}
1665234949Sbapt	while (isalnum(c) || c == '_' || c == '$');
1666234949Sbapt	goto loop;
1667234949Sbapt    }
1668234949Sbapt    putc(c, f);
1669234949Sbapt    ++cptr;
1670234949Sbapt    switch (c)
1671234949Sbapt    {
1672234949Sbapt    case '\n':
1673234949Sbapt      next_line:
1674234949Sbapt	get_line();
1675234949Sbapt	if (line)
1676234949Sbapt	    goto loop;
1677234949Sbapt	unterminated_action(a_lineno, a_line, a_cptr);
1678234949Sbapt
1679234949Sbapt    case ';':
1680234949Sbapt	if (depth > 0)
1681234949Sbapt	    goto loop;
1682234949Sbapt	fprintf(f, "\nbreak;\n");
1683234949Sbapt	free(a_line);
1684234949Sbapt	return;
1685234949Sbapt
1686234949Sbapt    case L_CURL:
1687234949Sbapt	++depth;
1688234949Sbapt	goto loop;
1689234949Sbapt
1690234949Sbapt    case R_CURL:
1691234949Sbapt	if (--depth > 0)
1692234949Sbapt	    goto loop;
1693234949Sbapt	fprintf(f, "\nbreak;\n");
1694234949Sbapt	free(a_line);
1695234949Sbapt	return;
1696234949Sbapt
1697234949Sbapt    case '\'':
1698234949Sbapt    case '"':
1699234949Sbapt	{
1700234949Sbapt	    int s_lineno = lineno;
1701234949Sbapt	    char *s_line = dup_line();
1702234949Sbapt	    char *s_cptr = s_line + (cptr - line - 1);
1703234949Sbapt
1704234949Sbapt	    quote = c;
1705234949Sbapt	    for (;;)
1706234949Sbapt	    {
1707234949Sbapt		c = *cptr++;
1708234949Sbapt		putc(c, f);
1709234949Sbapt		if (c == quote)
1710234949Sbapt		{
1711234949Sbapt		    FREE(s_line);
1712234949Sbapt		    goto loop;
1713234949Sbapt		}
1714234949Sbapt		if (c == '\n')
1715234949Sbapt		    unterminated_string(s_lineno, s_line, s_cptr);
1716234949Sbapt		if (c == '\\')
1717234949Sbapt		{
1718234949Sbapt		    c = *cptr++;
1719234949Sbapt		    putc(c, f);
1720234949Sbapt		    if (c == '\n')
1721234949Sbapt		    {
1722234949Sbapt			get_line();
1723234949Sbapt			if (line == 0)
1724234949Sbapt			    unterminated_string(s_lineno, s_line, s_cptr);
1725234949Sbapt		    }
1726234949Sbapt		}
1727234949Sbapt	    }
1728234949Sbapt	}
1729234949Sbapt
1730234949Sbapt    case '/':
1731234949Sbapt	c = *cptr;
1732234949Sbapt	if (c == '/')
1733234949Sbapt	{
1734234949Sbapt	    putc('*', f);
1735234949Sbapt	    while ((c = *++cptr) != '\n')
1736234949Sbapt	    {
1737234949Sbapt		if (c == '*' && cptr[1] == '/')
1738234949Sbapt		    fprintf(f, "* ");
1739234949Sbapt		else
1740234949Sbapt		    putc(c, f);
1741234949Sbapt	    }
1742234949Sbapt	    fprintf(f, "*/\n");
1743234949Sbapt	    goto next_line;
1744234949Sbapt	}
1745234949Sbapt	if (c == '*')
1746234949Sbapt	{
1747234949Sbapt	    int c_lineno = lineno;
1748234949Sbapt	    char *c_line = dup_line();
1749234949Sbapt	    char *c_cptr = c_line + (cptr - line - 1);
1750234949Sbapt
1751234949Sbapt	    putc('*', f);
1752234949Sbapt	    ++cptr;
1753234949Sbapt	    for (;;)
1754234949Sbapt	    {
1755234949Sbapt		c = *cptr++;
1756234949Sbapt		putc(c, f);
1757234949Sbapt		if (c == '*' && *cptr == '/')
1758234949Sbapt		{
1759234949Sbapt		    putc('/', f);
1760234949Sbapt		    ++cptr;
1761234949Sbapt		    FREE(c_line);
1762234949Sbapt		    goto loop;
1763234949Sbapt		}
1764234949Sbapt		if (c == '\n')
1765234949Sbapt		{
1766234949Sbapt		    get_line();
1767234949Sbapt		    if (line == 0)
1768234949Sbapt			unterminated_comment(c_lineno, c_line, c_cptr);
1769234949Sbapt		}
1770234949Sbapt	    }
1771234949Sbapt	}
1772234949Sbapt	goto loop;
1773234949Sbapt
1774234949Sbapt    default:
1775234949Sbapt	goto loop;
1776234949Sbapt    }
1777234949Sbapt}
1778234949Sbapt
1779234949Sbaptstatic int
1780234949Sbaptmark_symbol(void)
1781234949Sbapt{
1782234949Sbapt    int c;
1783234949Sbapt    bucket *bp;
1784234949Sbapt
1785235723Sbapt    bp = NULL;
1786235723Sbapt
1787234949Sbapt    c = cptr[1];
1788234949Sbapt    if (c == '%' || c == '\\')
1789234949Sbapt    {
1790234949Sbapt	cptr += 2;
1791234949Sbapt	return (1);
1792234949Sbapt    }
1793234949Sbapt
1794234949Sbapt    if (c == '=')
1795234949Sbapt	cptr += 2;
1796234949Sbapt    else if ((c == 'p' || c == 'P') &&
1797234949Sbapt	     ((c = cptr[2]) == 'r' || c == 'R') &&
1798234949Sbapt	     ((c = cptr[3]) == 'e' || c == 'E') &&
1799234949Sbapt	     ((c = cptr[4]) == 'c' || c == 'C') &&
1800234949Sbapt	     ((c = cptr[5], !IS_IDENT(c))))
1801234949Sbapt	cptr += 5;
1802234949Sbapt    else
1803234949Sbapt	syntax_error(lineno, line, cptr);
1804234949Sbapt
1805234949Sbapt    c = nextc();
1806234949Sbapt    if (isalpha(c) || c == '_' || c == '.' || c == '$')
1807234949Sbapt	bp = get_name();
1808234949Sbapt    else if (c == '\'' || c == '"')
1809234949Sbapt	bp = get_literal();
1810234949Sbapt    else
1811234949Sbapt    {
1812234949Sbapt	syntax_error(lineno, line, cptr);
1813234949Sbapt	/*NOTREACHED */
1814234949Sbapt    }
1815234949Sbapt
1816234949Sbapt    if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1817234949Sbapt	prec_redeclared();
1818234949Sbapt
1819234949Sbapt    rprec[nrules] = bp->prec;
1820234949Sbapt    rassoc[nrules] = bp->assoc;
1821234949Sbapt    return (0);
1822234949Sbapt}
1823234949Sbapt
1824234949Sbaptstatic void
1825234949Sbaptread_grammar(void)
1826234949Sbapt{
1827234949Sbapt    int c;
1828234949Sbapt
1829234949Sbapt    initialize_grammar();
1830234949Sbapt    advance_to_start();
1831234949Sbapt
1832234949Sbapt    for (;;)
1833234949Sbapt    {
1834234949Sbapt	c = nextc();
1835234949Sbapt	if (c == EOF)
1836234949Sbapt	    break;
1837234949Sbapt	if (isalpha(c)
1838234949Sbapt	    || c == '_'
1839234949Sbapt	    || c == '.'
1840234949Sbapt	    || c == '$'
1841234949Sbapt	    || c == '\''
1842234949Sbapt	    || c == '"')
1843234949Sbapt	    add_symbol();
1844234949Sbapt	else if (c == L_CURL || c == '=')
1845234949Sbapt	    copy_action();
1846234949Sbapt	else if (c == '|')
1847234949Sbapt	{
1848234949Sbapt	    end_rule();
1849234949Sbapt	    start_rule(plhs[nrules - 1], 0);
1850234949Sbapt	    ++cptr;
1851234949Sbapt	}
1852234949Sbapt	else if (c == '%')
1853234949Sbapt	{
1854234949Sbapt	    if (mark_symbol())
1855234949Sbapt		break;
1856234949Sbapt	}
1857234949Sbapt	else
1858234949Sbapt	    syntax_error(lineno, line, cptr);
1859234949Sbapt    }
1860234949Sbapt    end_rule();
1861234949Sbapt}
1862234949Sbapt
1863234949Sbaptstatic void
1864234949Sbaptfree_tags(void)
1865234949Sbapt{
1866234949Sbapt    int i;
1867234949Sbapt
1868234949Sbapt    if (tag_table == 0)
1869234949Sbapt	return;
1870234949Sbapt
1871234949Sbapt    for (i = 0; i < ntags; ++i)
1872234949Sbapt    {
1873234949Sbapt	assert(tag_table[i]);
1874234949Sbapt	FREE(tag_table[i]);
1875234949Sbapt    }
1876234949Sbapt    FREE(tag_table);
1877234949Sbapt}
1878234949Sbapt
1879234949Sbaptstatic void
1880234949Sbaptpack_names(void)
1881234949Sbapt{
1882234949Sbapt    bucket *bp;
1883234949Sbapt    char *p, *s, *t;
1884234949Sbapt
1885234949Sbapt    name_pool_size = 13;	/* 13 == sizeof("$end") + sizeof("$accept") */
1886234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
1887234949Sbapt	name_pool_size += strlen(bp->name) + 1;
1888234949Sbapt
1889234949Sbapt    name_pool = MALLOC(name_pool_size);
1890234949Sbapt    NO_SPACE(name_pool);
1891234949Sbapt
1892234949Sbapt    strcpy(name_pool, "$accept");
1893234949Sbapt    strcpy(name_pool + 8, "$end");
1894234949Sbapt    t = name_pool + 13;
1895234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
1896234949Sbapt    {
1897234949Sbapt	p = t;
1898234949Sbapt	s = bp->name;
1899234949Sbapt	while ((*t++ = *s++) != 0)
1900234949Sbapt	    continue;
1901234949Sbapt	FREE(bp->name);
1902234949Sbapt	bp->name = p;
1903234949Sbapt    }
1904234949Sbapt}
1905234949Sbapt
1906234949Sbaptstatic void
1907234949Sbaptcheck_symbols(void)
1908234949Sbapt{
1909234949Sbapt    bucket *bp;
1910234949Sbapt
1911234949Sbapt    if (goal->class == UNKNOWN)
1912234949Sbapt	undefined_goal(goal->name);
1913234949Sbapt
1914234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
1915234949Sbapt    {
1916234949Sbapt	if (bp->class == UNKNOWN)
1917234949Sbapt	{
1918234949Sbapt	    undefined_symbol_warning(bp->name);
1919234949Sbapt	    bp->class = TERM;
1920234949Sbapt	}
1921234949Sbapt    }
1922234949Sbapt}
1923234949Sbapt
1924234949Sbaptstatic void
1925234949Sbaptprotect_string(char *src, char **des)
1926234949Sbapt{
1927234949Sbapt    unsigned len;
1928234949Sbapt    char *s;
1929234949Sbapt    char *d;
1930234949Sbapt
1931234949Sbapt    *des = src;
1932234949Sbapt    if (src)
1933234949Sbapt    {
1934234949Sbapt	len = 1;
1935234949Sbapt	s = src;
1936234949Sbapt	while (*s)
1937234949Sbapt	{
1938234949Sbapt	    if ('\\' == *s || '"' == *s)
1939234949Sbapt		len++;
1940234949Sbapt	    s++;
1941234949Sbapt	    len++;
1942234949Sbapt	}
1943234949Sbapt
1944234949Sbapt	*des = d = (char *)MALLOC(len);
1945234949Sbapt	NO_SPACE(d);
1946234949Sbapt
1947234949Sbapt	s = src;
1948234949Sbapt	while (*s)
1949234949Sbapt	{
1950234949Sbapt	    if ('\\' == *s || '"' == *s)
1951234949Sbapt		*d++ = '\\';
1952234949Sbapt	    *d++ = *s++;
1953234949Sbapt	}
1954234949Sbapt	*d = '\0';
1955234949Sbapt    }
1956234949Sbapt}
1957234949Sbapt
1958234949Sbaptstatic void
1959234949Sbaptpack_symbols(void)
1960234949Sbapt{
1961234949Sbapt    bucket *bp;
1962234949Sbapt    bucket **v;
1963234949Sbapt    Value_t i, j, k, n;
1964234949Sbapt
1965234949Sbapt    nsyms = 2;
1966234949Sbapt    ntokens = 1;
1967234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
1968234949Sbapt    {
1969234949Sbapt	++nsyms;
1970234949Sbapt	if (bp->class == TERM)
1971234949Sbapt	    ++ntokens;
1972234949Sbapt    }
1973234949Sbapt    start_symbol = (Value_t) ntokens;
1974234949Sbapt    nvars = nsyms - ntokens;
1975234949Sbapt
1976234949Sbapt    symbol_name = (char **)MALLOC((unsigned)nsyms * sizeof(char *));
1977234949Sbapt    NO_SPACE(symbol_name);
1978234949Sbapt
1979234949Sbapt    symbol_value = (short *)MALLOC((unsigned)nsyms * sizeof(short));
1980234949Sbapt    NO_SPACE(symbol_value);
1981234949Sbapt
1982234949Sbapt    symbol_prec = (short *)MALLOC((unsigned)nsyms * sizeof(short));
1983234949Sbapt    NO_SPACE(symbol_prec);
1984234949Sbapt
1985234949Sbapt    symbol_assoc = MALLOC(nsyms);
1986234949Sbapt    NO_SPACE(symbol_assoc);
1987234949Sbapt
1988234949Sbapt    v = (bucket **)MALLOC((unsigned)nsyms * sizeof(bucket *));
1989234949Sbapt    NO_SPACE(v);
1990234949Sbapt
1991234949Sbapt    v[0] = 0;
1992234949Sbapt    v[start_symbol] = 0;
1993234949Sbapt
1994234949Sbapt    i = 1;
1995234949Sbapt    j = (Value_t) (start_symbol + 1);
1996234949Sbapt    for (bp = first_symbol; bp; bp = bp->next)
1997234949Sbapt    {
1998234949Sbapt	if (bp->class == TERM)
1999234949Sbapt	    v[i++] = bp;
2000234949Sbapt	else
2001234949Sbapt	    v[j++] = bp;
2002234949Sbapt    }
2003234949Sbapt    assert(i == ntokens && j == nsyms);
2004234949Sbapt
2005234949Sbapt    for (i = 1; i < ntokens; ++i)
2006234949Sbapt	v[i]->index = i;
2007234949Sbapt
2008234949Sbapt    goal->index = (Index_t) (start_symbol + 1);
2009234949Sbapt    k = (Value_t) (start_symbol + 2);
2010234949Sbapt    while (++i < nsyms)
2011234949Sbapt	if (v[i] != goal)
2012234949Sbapt	{
2013234949Sbapt	    v[i]->index = k;
2014234949Sbapt	    ++k;
2015234949Sbapt	}
2016234949Sbapt
2017234949Sbapt    goal->value = 0;
2018234949Sbapt    k = 1;
2019234949Sbapt    for (i = (Value_t) (start_symbol + 1); i < nsyms; ++i)
2020234949Sbapt    {
2021234949Sbapt	if (v[i] != goal)
2022234949Sbapt	{
2023234949Sbapt	    v[i]->value = k;
2024234949Sbapt	    ++k;
2025234949Sbapt	}
2026234949Sbapt    }
2027234949Sbapt
2028234949Sbapt    k = 0;
2029234949Sbapt    for (i = 1; i < ntokens; ++i)
2030234949Sbapt    {
2031234949Sbapt	n = v[i]->value;
2032234949Sbapt	if (n > 256)
2033234949Sbapt	{
2034234949Sbapt	    for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
2035234949Sbapt		symbol_value[j] = symbol_value[j - 1];
2036234949Sbapt	    symbol_value[j] = n;
2037234949Sbapt	}
2038234949Sbapt    }
2039234949Sbapt
2040234949Sbapt    assert(v[1] != 0);
2041234949Sbapt
2042234949Sbapt    if (v[1]->value == UNDEFINED)
2043234949Sbapt	v[1]->value = 256;
2044234949Sbapt
2045234949Sbapt    j = 0;
2046234949Sbapt    n = 257;
2047234949Sbapt    for (i = 2; i < ntokens; ++i)
2048234949Sbapt    {
2049234949Sbapt	if (v[i]->value == UNDEFINED)
2050234949Sbapt	{
2051234949Sbapt	    while (j < k && n == symbol_value[j])
2052234949Sbapt	    {
2053234949Sbapt		while (++j < k && n == symbol_value[j])
2054234949Sbapt		    continue;
2055234949Sbapt		++n;
2056234949Sbapt	    }
2057234949Sbapt	    v[i]->value = n;
2058234949Sbapt	    ++n;
2059234949Sbapt	}
2060234949Sbapt    }
2061234949Sbapt
2062234949Sbapt    symbol_name[0] = name_pool + 8;
2063234949Sbapt    symbol_value[0] = 0;
2064234949Sbapt    symbol_prec[0] = 0;
2065234949Sbapt    symbol_assoc[0] = TOKEN;
2066234949Sbapt    for (i = 1; i < ntokens; ++i)
2067234949Sbapt    {
2068234949Sbapt	symbol_name[i] = v[i]->name;
2069234949Sbapt	symbol_value[i] = v[i]->value;
2070234949Sbapt	symbol_prec[i] = v[i]->prec;
2071234949Sbapt	symbol_assoc[i] = v[i]->assoc;
2072234949Sbapt    }
2073234949Sbapt    symbol_name[start_symbol] = name_pool;
2074234949Sbapt    symbol_value[start_symbol] = -1;
2075234949Sbapt    symbol_prec[start_symbol] = 0;
2076234949Sbapt    symbol_assoc[start_symbol] = TOKEN;
2077234949Sbapt    for (++i; i < nsyms; ++i)
2078234949Sbapt    {
2079234949Sbapt	k = v[i]->index;
2080234949Sbapt	symbol_name[k] = v[i]->name;
2081234949Sbapt	symbol_value[k] = v[i]->value;
2082234949Sbapt	symbol_prec[k] = v[i]->prec;
2083234949Sbapt	symbol_assoc[k] = v[i]->assoc;
2084234949Sbapt    }
2085234949Sbapt
2086234949Sbapt    if (gflag)
2087234949Sbapt    {
2088234949Sbapt	symbol_pname = (char **)MALLOC((unsigned)nsyms * sizeof(char *));
2089234949Sbapt	NO_SPACE(symbol_pname);
2090234949Sbapt
2091234949Sbapt	for (i = 0; i < nsyms; ++i)
2092234949Sbapt	    protect_string(symbol_name[i], &(symbol_pname[i]));
2093234949Sbapt    }
2094234949Sbapt
2095234949Sbapt    FREE(v);
2096234949Sbapt}
2097234949Sbapt
2098234949Sbaptstatic void
2099234949Sbaptpack_grammar(void)
2100234949Sbapt{
2101234949Sbapt    int i;
2102234949Sbapt    Value_t j;
2103234949Sbapt    Assoc_t assoc;
2104234949Sbapt    Value_t prec2;
2105234949Sbapt
2106234949Sbapt    ritem = (short *)MALLOC((unsigned)nitems * sizeof(short));
2107234949Sbapt    NO_SPACE(ritem);
2108234949Sbapt
2109234949Sbapt    rlhs = (short *)MALLOC((unsigned)nrules * sizeof(short));
2110234949Sbapt    NO_SPACE(rlhs);
2111234949Sbapt
2112234949Sbapt    rrhs = (short *)MALLOC((unsigned)(nrules + 1) * sizeof(short));
2113234949Sbapt    NO_SPACE(rrhs);
2114234949Sbapt
2115234949Sbapt    rprec = (short *)REALLOC(rprec, (unsigned)nrules * sizeof(short));
2116234949Sbapt    NO_SPACE(rprec);
2117234949Sbapt
2118234949Sbapt    rassoc = REALLOC(rassoc, nrules);
2119234949Sbapt    NO_SPACE(rassoc);
2120234949Sbapt
2121234949Sbapt    ritem[0] = -1;
2122234949Sbapt    ritem[1] = goal->index;
2123234949Sbapt    ritem[2] = 0;
2124234949Sbapt    ritem[3] = -2;
2125234949Sbapt    rlhs[0] = 0;
2126234949Sbapt    rlhs[1] = 0;
2127234949Sbapt    rlhs[2] = start_symbol;
2128234949Sbapt    rrhs[0] = 0;
2129234949Sbapt    rrhs[1] = 0;
2130234949Sbapt    rrhs[2] = 1;
2131234949Sbapt
2132234949Sbapt    j = 4;
2133234949Sbapt    for (i = 3; i < nrules; ++i)
2134234949Sbapt    {
2135234949Sbapt	rlhs[i] = plhs[i]->index;
2136234949Sbapt	rrhs[i] = j;
2137234949Sbapt	assoc = TOKEN;
2138234949Sbapt	prec2 = 0;
2139234949Sbapt	while (pitem[j])
2140234949Sbapt	{
2141234949Sbapt	    ritem[j] = pitem[j]->index;
2142234949Sbapt	    if (pitem[j]->class == TERM)
2143234949Sbapt	    {
2144234949Sbapt		prec2 = pitem[j]->prec;
2145234949Sbapt		assoc = pitem[j]->assoc;
2146234949Sbapt	    }
2147234949Sbapt	    ++j;
2148234949Sbapt	}
2149234949Sbapt	ritem[j] = (Value_t) - i;
2150234949Sbapt	++j;
2151234949Sbapt	if (rprec[i] == UNDEFINED)
2152234949Sbapt	{
2153234949Sbapt	    rprec[i] = prec2;
2154234949Sbapt	    rassoc[i] = assoc;
2155234949Sbapt	}
2156234949Sbapt    }
2157234949Sbapt    rrhs[i] = j;
2158234949Sbapt
2159234949Sbapt    FREE(plhs);
2160234949Sbapt    FREE(pitem);
2161234949Sbapt}
2162234949Sbapt
2163234949Sbaptstatic void
2164234949Sbaptprint_grammar(void)
2165234949Sbapt{
2166234949Sbapt    int i, k;
2167234949Sbapt    size_t j, spacing = 0;
2168234949Sbapt    FILE *f = verbose_file;
2169234949Sbapt
2170234949Sbapt    if (!vflag)
2171234949Sbapt	return;
2172234949Sbapt
2173234949Sbapt    k = 1;
2174234949Sbapt    for (i = 2; i < nrules; ++i)
2175234949Sbapt    {
2176234949Sbapt	if (rlhs[i] != rlhs[i - 1])
2177234949Sbapt	{
2178234949Sbapt	    if (i != 2)
2179234949Sbapt		fprintf(f, "\n");
2180234949Sbapt	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
2181234949Sbapt	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
2182234949Sbapt	}
2183234949Sbapt	else
2184234949Sbapt	{
2185234949Sbapt	    fprintf(f, "%4d  ", i - 2);
2186234949Sbapt	    j = spacing;
2187234949Sbapt	    while (j-- != 0)
2188234949Sbapt		putc(' ', f);
2189234949Sbapt	    putc('|', f);
2190234949Sbapt	}
2191234949Sbapt
2192234949Sbapt	while (ritem[k] >= 0)
2193234949Sbapt	{
2194234949Sbapt	    fprintf(f, " %s", symbol_name[ritem[k]]);
2195234949Sbapt	    ++k;
2196234949Sbapt	}
2197234949Sbapt	++k;
2198234949Sbapt	putc('\n', f);
2199234949Sbapt    }
2200234949Sbapt}
2201234949Sbapt
2202234949Sbaptvoid
2203234949Sbaptreader(void)
2204234949Sbapt{
2205234949Sbapt    write_section(code_file, banner);
2206234949Sbapt    create_symbol_table();
2207234949Sbapt    read_declarations();
2208234949Sbapt    read_grammar();
2209234949Sbapt    free_symbol_table();
2210234949Sbapt    free_tags();
2211234949Sbapt    pack_names();
2212234949Sbapt    check_symbols();
2213234949Sbapt    pack_symbols();
2214234949Sbapt    pack_grammar();
2215234949Sbapt    free_symbols();
2216234949Sbapt    print_grammar();
2217234949Sbapt}
2218234949Sbapt
2219234949Sbapt#ifdef NO_LEAKS
2220234949Sbaptstatic param *
2221234949Sbaptfree_declarations(param * list)
2222234949Sbapt{
2223234949Sbapt    while (list != 0)
2224234949Sbapt    {
2225234949Sbapt	param *next = list->next;
2226234949Sbapt	free(list->type);
2227234949Sbapt	free(list->name);
2228234949Sbapt	free(list->type2);
2229234949Sbapt	free(list);
2230234949Sbapt	list = next;
2231234949Sbapt    }
2232234949Sbapt    return list;
2233234949Sbapt}
2234234949Sbapt
2235234949Sbaptvoid
2236234949Sbaptreader_leaks(void)
2237234949Sbapt{
2238234949Sbapt    lex_param = free_declarations(lex_param);
2239234949Sbapt    parse_param = free_declarations(parse_param);
2240234949Sbapt
2241234949Sbapt    DO_FREE(line);
2242234949Sbapt    DO_FREE(rrhs);
2243234949Sbapt    DO_FREE(rlhs);
2244234949Sbapt    DO_FREE(rprec);
2245234949Sbapt    DO_FREE(ritem);
2246234949Sbapt    DO_FREE(rassoc);
2247234949Sbapt    DO_FREE(cache);
2248234949Sbapt    DO_FREE(name_pool);
2249234949Sbapt    DO_FREE(symbol_name);
2250234949Sbapt    DO_FREE(symbol_prec);
2251234949Sbapt    DO_FREE(symbol_assoc);
2252234949Sbapt    DO_FREE(symbol_value);
2253234949Sbapt}
2254234949Sbapt#endif
2255