11590Srgrimes/*
21590Srgrimes * Copyright (c) 1989 The Regents of the University of California.
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * This code is derived from software contributed to Berkeley by
61590Srgrimes * Robert Paul Corbett.
71590Srgrimes *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
161590Srgrimes * 4. Neither the name of the University nor the names of its contributors
171590Srgrimes *    may be used to endorse or promote products derived from this software
181590Srgrimes *    without specific prior written permission.
191590Srgrimes *
201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301590Srgrimes * SUCH DAMAGE.
311590Srgrimes */
321590Srgrimes
3387628Sdwmalone#if 0
3487628Sdwmalone#ifndef lint
3587628Sdwmalonestatic char sccsid[] = "@(#)reader.c	5.7 (Berkeley) 1/20/91";
3687628Sdwmalone#endif
3787628Sdwmalone#endif
3887628Sdwmalone
3987234Smarkm#include <sys/cdefs.h>
4087234Smarkm__FBSDID("$FreeBSD$");
4187234Smarkm
4298116Srobert#include <limits.h>
4321622Ssteve#include <stdlib.h>
4421622Ssteve#include <string.h>
451590Srgrimes#include "defs.h"
461590Srgrimes
471590Srgrimes/*  The line size must be a positive integer.  One hundred was chosen	*/
481590Srgrimes/*  because few lines in Yacc input grammars exceed 100 characters.	*/
491590Srgrimes/*  Note that if a line exceeds LINESIZE characters, the line buffer	*/
501590Srgrimes/*  will be expanded to accomodate it.					*/
511590Srgrimes
521590Srgrimes#define LINESIZE 100
531590Srgrimes
541590Srgrimeschar *cache;
551590Srgrimesint cinc, cache_size;
561590Srgrimes
571590Srgrimesint ntags, tagmax;
581590Srgrimeschar **tag_table;
591590Srgrimes
601590Srgrimeschar saw_eof, unionized;
611590Srgrimeschar *cptr, *line;
621590Srgrimesint linesize;
631590Srgrimes
641590Srgrimesbucket *goal;
651590Srgrimesint prec;
661590Srgrimesint gensym;
671590Srgrimeschar last_was_action;
681590Srgrimes
691590Srgrimesint maxitems;
701590Srgrimesbucket **pitem;
711590Srgrimes
721590Srgrimesint maxrules;
731590Srgrimesbucket **plhs;
741590Srgrimes
751590Srgrimesint name_pool_size;
761590Srgrimeschar *name_pool;
771590Srgrimes
7869204Skrisstatic const char line_format[] = "#line %d \"%s\"\n";
791590Srgrimes
8092922Simpstatic void add_symbol(void);
8192922Simpstatic void advance_to_start(void);
8292922Simpstatic void cachec(int);
8392922Simpstatic void check_symbols(void);
8492922Simpstatic void copy_action(void);
8592922Simpstatic void copy_ident(void);
8692922Simpstatic void copy_text(void);
8792922Simpstatic void copy_union(void);
8892922Simpstatic void declare_expect(int);
8992922Simpstatic void declare_start(void);
9092922Simpstatic void declare_tokens(int);
9192922Simpstatic void declare_types(void);
9292922Simpstatic char *dup_line(void);
9392922Simpstatic void end_rule(void);
9492922Simpstatic void expand_items(void);
9592922Simpstatic void expand_rules(void);
9692922Simpstatic void free_tags(void);
9792922Simpstatic void get_line(void);
9892922Simpstatic bucket *get_literal(void);
9992922Simpstatic bucket *get_name(void);
10092922Simpstatic int get_number(void);
10192922Simpstatic char *get_tag(void);
10292922Simpstatic int hexval(int);
10392922Simpstatic void initialize_grammar(void);
10492922Simpstatic void insert_empty_rule(void);
10592922Simpstatic int is_reserved(char *);
10692922Simpstatic int keyword(void);
10792922Simpstatic int mark_symbol(void);
10892922Simpstatic int nextc(void);
10992922Simpstatic void pack_grammar(void);
11092922Simpstatic void pack_names(void);
11192922Simpstatic void pack_symbols(void);
11292922Simpstatic void print_grammar(void);
11392922Simpstatic void read_declarations(void);
11492922Simpstatic void read_grammar(void);
11592922Simpstatic void skip_comment(void);
11692922Simpstatic void start_rule(bucket *, int);
1171590Srgrimes
11821622Sstevestatic void
119214959Sobriencachec(int c)
1201590Srgrimes{
1211590Srgrimes    assert(cinc >= 0);
1221590Srgrimes    if (cinc >= cache_size)
1231590Srgrimes    {
1241590Srgrimes	cache_size += 256;
125214961Sobrien	cache = realloc(cache, cache_size);
1261590Srgrimes	if (cache == 0) no_space();
1271590Srgrimes    }
1281590Srgrimes    cache[cinc] = c;
1291590Srgrimes    ++cinc;
1301590Srgrimes}
1311590Srgrimes
1321590Srgrimes
13321622Sstevestatic void
134214959Sobrienget_line(void)
1351590Srgrimes{
13687171Smarkm    FILE *f = input_file;
13787171Smarkm    int c;
13887171Smarkm    int i;
1391590Srgrimes
1401590Srgrimes    if (saw_eof || (c = getc(f)) == EOF)
1411590Srgrimes    {
142214961Sobrien	if (line) { free(line); line = 0; }
1431590Srgrimes	cptr = 0;
1441590Srgrimes	saw_eof = 1;
1451590Srgrimes	return;
1461590Srgrimes    }
1471590Srgrimes
1481590Srgrimes    if (line == 0 || linesize != (LINESIZE + 1))
1491590Srgrimes    {
150214961Sobrien	if (line) free(line);
1511590Srgrimes	linesize = LINESIZE + 1;
152214961Sobrien	line = malloc(linesize);
1531590Srgrimes	if (line == 0) no_space();
1541590Srgrimes    }
1551590Srgrimes
1561590Srgrimes    i = 0;
1571590Srgrimes    ++lineno;
1581590Srgrimes    for (;;)
1591590Srgrimes    {
1601590Srgrimes	line[i]  =  c;
1611590Srgrimes	if (c == '\n') { cptr = line; return; }
1621590Srgrimes	if (++i >= linesize)
1631590Srgrimes	{
1641590Srgrimes	    linesize += LINESIZE;
165214961Sobrien	    line = realloc(line, linesize);
1661590Srgrimes	    if (line ==  0) no_space();
1671590Srgrimes	}
1681590Srgrimes	c = getc(f);
1691590Srgrimes	if (c ==  EOF)
1701590Srgrimes	{
1711590Srgrimes	    line[i] = '\n';
1721590Srgrimes	    saw_eof = 1;
1731590Srgrimes	    cptr = line;
1741590Srgrimes	    return;
1751590Srgrimes	}
1761590Srgrimes    }
1771590Srgrimes}
1781590Srgrimes
1791590Srgrimes
18021622Sstevestatic char *
181214959Sobriendup_line(void)
1821590Srgrimes{
18387171Smarkm    char *p, *s, *t;
1841590Srgrimes
1851590Srgrimes    if (line == 0) return (0);
1861590Srgrimes    s = line;
1871590Srgrimes    while (*s != '\n') ++s;
188214961Sobrien    p = malloc(s - line + 1);
1891590Srgrimes    if (p == 0) no_space();
1901590Srgrimes
1911590Srgrimes    s = line;
1921590Srgrimes    t = p;
1931590Srgrimes    while ((*t++ = *s++) != '\n') continue;
1941590Srgrimes    return (p);
1951590Srgrimes}
1961590Srgrimes
1971590Srgrimes
19821622Sstevestatic void
199214959Sobrienskip_comment(void)
2001590Srgrimes{
20187171Smarkm    char *s;
2021590Srgrimes
2031590Srgrimes    int st_lineno = lineno;
2041590Srgrimes    char *st_line = dup_line();
2051590Srgrimes    char *st_cptr = st_line + (cptr - line);
2061590Srgrimes
2071590Srgrimes    s = cptr + 2;
2081590Srgrimes    for (;;)
2091590Srgrimes    {
2101590Srgrimes	if (*s == '*' && s[1] == '/')
2111590Srgrimes	{
2121590Srgrimes	    cptr = s + 2;
213214961Sobrien	    free(st_line);
2141590Srgrimes	    return;
2151590Srgrimes	}
2161590Srgrimes	if (*s == '\n')
2171590Srgrimes	{
2181590Srgrimes	    get_line();
2191590Srgrimes	    if (line == 0)
2201590Srgrimes		unterminated_comment(st_lineno, st_line, st_cptr);
2211590Srgrimes	    s = cptr;
2221590Srgrimes	}
2231590Srgrimes	else
2241590Srgrimes	    ++s;
2251590Srgrimes    }
2261590Srgrimes}
2271590Srgrimes
2281590Srgrimes
22921622Sstevestatic int
230214959Sobriennextc(void)
2311590Srgrimes{
23287171Smarkm    char *s;
2331590Srgrimes
2341590Srgrimes    if (line == 0)
2351590Srgrimes    {
2361590Srgrimes	get_line();
2371590Srgrimes	if (line == 0)
2381590Srgrimes	    return (EOF);
2391590Srgrimes    }
2401590Srgrimes
2411590Srgrimes    s = cptr;
2421590Srgrimes    for (;;)
2431590Srgrimes    {
2441590Srgrimes	switch (*s)
2451590Srgrimes	{
2461590Srgrimes	case '\n':
2471590Srgrimes	    get_line();
2481590Srgrimes	    if (line == 0) return (EOF);
2491590Srgrimes	    s = cptr;
2501590Srgrimes	    break;
2511590Srgrimes
2521590Srgrimes	case ' ':
2531590Srgrimes	case '\t':
2541590Srgrimes	case '\f':
2551590Srgrimes	case '\r':
2561590Srgrimes	case '\v':
2571590Srgrimes	case ',':
2581590Srgrimes	case ';':
2591590Srgrimes	    ++s;
2601590Srgrimes	    break;
2611590Srgrimes
2621590Srgrimes	case '\\':
2631590Srgrimes	    cptr = s;
2641590Srgrimes	    return ('%');
2651590Srgrimes
2661590Srgrimes	case '/':
2671590Srgrimes	    if (s[1] == '*')
2681590Srgrimes	    {
2691590Srgrimes		cptr = s;
2701590Srgrimes		skip_comment();
2711590Srgrimes		s = cptr;
2721590Srgrimes		break;
2731590Srgrimes	    }
2741590Srgrimes	    else if (s[1] == '/')
2751590Srgrimes	    {
2761590Srgrimes		get_line();
2771590Srgrimes		if (line == 0) return (EOF);
2781590Srgrimes		s = cptr;
2791590Srgrimes		break;
2801590Srgrimes	    }
281102412Scharnier	    /* FALLTHROUGH */
2821590Srgrimes
2831590Srgrimes	default:
2841590Srgrimes	    cptr = s;
2851590Srgrimes	    return (*s);
2861590Srgrimes	}
2871590Srgrimes    }
2881590Srgrimes}
2891590Srgrimes
2901590Srgrimes
29121622Sstevestatic int
292214959Sobrienkeyword(void)
2931590Srgrimes{
29487171Smarkm    int c;
2951590Srgrimes    char *t_cptr = cptr;
2961590Srgrimes
2971590Srgrimes    c = *++cptr;
2981590Srgrimes    if (isalpha(c))
2991590Srgrimes    {
3001590Srgrimes	cinc = 0;
3011590Srgrimes	for (;;)
3021590Srgrimes	{
3031590Srgrimes	    if (isalpha(c))
3041590Srgrimes	    {
3051590Srgrimes		if (isupper(c)) c = tolower(c);
3061590Srgrimes		cachec(c);
3071590Srgrimes	    }
3081590Srgrimes	    else if (isdigit(c) || c == '_' || c == '.' || c == '$')
3091590Srgrimes		cachec(c);
3101590Srgrimes	    else
3111590Srgrimes		break;
3121590Srgrimes	    c = *++cptr;
3131590Srgrimes	}
3141590Srgrimes	cachec(NUL);
3151590Srgrimes
3161590Srgrimes	if (strcmp(cache, "token") == 0 || strcmp(cache, "term") == 0)
3171590Srgrimes	    return (TOKEN);
3181590Srgrimes	if (strcmp(cache, "type") == 0)
3191590Srgrimes	    return (TYPE);
3201590Srgrimes	if (strcmp(cache, "left") == 0)
3211590Srgrimes	    return (LEFT);
3221590Srgrimes	if (strcmp(cache, "right") == 0)
3231590Srgrimes	    return (RIGHT);
3241590Srgrimes	if (strcmp(cache, "nonassoc") == 0 || strcmp(cache, "binary") == 0)
3251590Srgrimes	    return (NONASSOC);
3261590Srgrimes	if (strcmp(cache, "start") == 0)
3271590Srgrimes	    return (START);
3281590Srgrimes	if (strcmp(cache, "union") == 0)
3291590Srgrimes	    return (UNION);
3301590Srgrimes	if (strcmp(cache, "ident") == 0)
3311590Srgrimes	    return (IDENT);
33249208Sobrien	if (strcmp(cache, "expect") == 0)
33349208Sobrien	    return (EXPECT);
3341590Srgrimes    }
3351590Srgrimes    else
3361590Srgrimes    {
3371590Srgrimes	++cptr;
3381590Srgrimes	if (c == '{')
3391590Srgrimes	    return (TEXT);
3401590Srgrimes	if (c == '%' || c == '\\')
3411590Srgrimes	    return (MARK);
3421590Srgrimes	if (c == '<')
3431590Srgrimes	    return (LEFT);
3441590Srgrimes	if (c == '>')
3451590Srgrimes	    return (RIGHT);
3461590Srgrimes	if (c == '0')
3471590Srgrimes	    return (TOKEN);
3481590Srgrimes	if (c == '2')
3491590Srgrimes	    return (NONASSOC);
3501590Srgrimes    }
3511590Srgrimes    syntax_error(lineno, line, t_cptr);
3521590Srgrimes    /*NOTREACHED*/
35321622Ssteve    return (0);
3541590Srgrimes}
3551590Srgrimes
3561590Srgrimes
35721622Sstevestatic void
358214959Sobriencopy_ident(void)
3591590Srgrimes{
36087171Smarkm    int c;
36187171Smarkm    FILE *f = output_file;
3621590Srgrimes
3631590Srgrimes    c = nextc();
3641590Srgrimes    if (c == EOF) unexpected_EOF();
3651590Srgrimes    if (c != '"') syntax_error(lineno, line, cptr);
3661590Srgrimes    ++outline;
3671590Srgrimes    fprintf(f, "#ident \"");
3681590Srgrimes    for (;;)
3691590Srgrimes    {
3701590Srgrimes	c = *++cptr;
3711590Srgrimes	if (c == '\n')
3721590Srgrimes	{
3731590Srgrimes	    fprintf(f, "\"\n");
3741590Srgrimes	    return;
3751590Srgrimes	}
3761590Srgrimes	putc(c, f);
3771590Srgrimes	if (c == '"')
3781590Srgrimes	{
3791590Srgrimes	    putc('\n', f);
3801590Srgrimes	    ++cptr;
3811590Srgrimes	    return;
3821590Srgrimes	}
3831590Srgrimes    }
3841590Srgrimes}
3851590Srgrimes
3861590Srgrimes
38721622Sstevestatic void
388214959Sobriencopy_text(void)
3891590Srgrimes{
39087171Smarkm    int c;
3911590Srgrimes    int quote;
39287171Smarkm    FILE *f = text_file;
3931590Srgrimes    int need_newline = 0;
3941590Srgrimes    int t_lineno = lineno;
3951590Srgrimes    char *t_line = dup_line();
3961590Srgrimes    char *t_cptr = t_line + (cptr - line - 2);
3971590Srgrimes
3981590Srgrimes    if (*cptr == '\n')
3991590Srgrimes    {
4001590Srgrimes	get_line();
4011590Srgrimes	if (line == 0)
4021590Srgrimes	    unterminated_text(t_lineno, t_line, t_cptr);
4031590Srgrimes    }
4041590Srgrimes    if (!lflag) fprintf(f, line_format, lineno, input_file_name);
4051590Srgrimes
4061590Srgrimesloop:
4071590Srgrimes    c = *cptr++;
4081590Srgrimes    switch (c)
4091590Srgrimes    {
4101590Srgrimes    case '\n':
4111590Srgrimes    next_line:
4121590Srgrimes	putc('\n', f);
4131590Srgrimes	need_newline = 0;
4141590Srgrimes	get_line();
4151590Srgrimes	if (line) goto loop;
4161590Srgrimes	unterminated_text(t_lineno, t_line, t_cptr);
4171590Srgrimes
4181590Srgrimes    case '\'':
4191590Srgrimes    case '"':
4201590Srgrimes	{
4211590Srgrimes	    int s_lineno = lineno;
4221590Srgrimes	    char *s_line = dup_line();
4231590Srgrimes	    char *s_cptr = s_line + (cptr - line - 1);
4241590Srgrimes
4251590Srgrimes	    quote = c;
4261590Srgrimes	    putc(c, f);
4271590Srgrimes	    for (;;)
4281590Srgrimes	    {
4291590Srgrimes		c = *cptr++;
4301590Srgrimes		putc(c, f);
4311590Srgrimes		if (c == quote)
4321590Srgrimes		{
4331590Srgrimes		    need_newline = 1;
434214961Sobrien		    free(s_line);
4351590Srgrimes		    goto loop;
4361590Srgrimes		}
4371590Srgrimes		if (c == '\n')
4381590Srgrimes		    unterminated_string(s_lineno, s_line, s_cptr);
4391590Srgrimes		if (c == '\\')
4401590Srgrimes		{
4411590Srgrimes		    c = *cptr++;
4421590Srgrimes		    putc(c, f);
4431590Srgrimes		    if (c == '\n')
4441590Srgrimes		    {
4451590Srgrimes			get_line();
4461590Srgrimes			if (line == 0)
4471590Srgrimes			    unterminated_string(s_lineno, s_line, s_cptr);
4481590Srgrimes		    }
4491590Srgrimes		}
4501590Srgrimes	    }
4511590Srgrimes	}
4521590Srgrimes
4531590Srgrimes    case '/':
4541590Srgrimes	putc(c, f);
4551590Srgrimes	need_newline = 1;
4561590Srgrimes	c = *cptr;
4571590Srgrimes	if (c == '/')
4581590Srgrimes	{
4591590Srgrimes	    putc('*', f);
4601590Srgrimes	    while ((c = *++cptr) != '\n')
4611590Srgrimes	    {
4621590Srgrimes		if (c == '*' && cptr[1] == '/')
4631590Srgrimes		    fprintf(f, "* ");
4641590Srgrimes		else
4651590Srgrimes		    putc(c, f);
4661590Srgrimes	    }
4671590Srgrimes	    fprintf(f, "*/");
4681590Srgrimes	    goto next_line;
4691590Srgrimes	}
4701590Srgrimes	if (c == '*')
4711590Srgrimes	{
4721590Srgrimes	    int c_lineno = lineno;
4731590Srgrimes	    char *c_line = dup_line();
4741590Srgrimes	    char *c_cptr = c_line + (cptr - line - 1);
4751590Srgrimes
4761590Srgrimes	    putc('*', f);
4771590Srgrimes	    ++cptr;
4781590Srgrimes	    for (;;)
4791590Srgrimes	    {
4801590Srgrimes		c = *cptr++;
4811590Srgrimes		putc(c, f);
4821590Srgrimes		if (c == '*' && *cptr == '/')
4831590Srgrimes		{
4841590Srgrimes		    putc('/', f);
4851590Srgrimes		    ++cptr;
486214961Sobrien		    free(c_line);
4871590Srgrimes		    goto loop;
4881590Srgrimes		}
4891590Srgrimes		if (c == '\n')
4901590Srgrimes		{
4911590Srgrimes		    get_line();
4921590Srgrimes		    if (line == 0)
4931590Srgrimes			unterminated_comment(c_lineno, c_line, c_cptr);
4941590Srgrimes		}
4951590Srgrimes	    }
4961590Srgrimes	}
4971590Srgrimes	need_newline = 1;
4981590Srgrimes	goto loop;
4991590Srgrimes
5001590Srgrimes    case '%':
5011590Srgrimes    case '\\':
5021590Srgrimes	if (*cptr == '}')
5031590Srgrimes	{
5041590Srgrimes	    if (need_newline) putc('\n', f);
5051590Srgrimes	    ++cptr;
506214961Sobrien	    free(t_line);
5071590Srgrimes	    return;
5081590Srgrimes	}
509102412Scharnier	/* FALLTHROUGH */
5101590Srgrimes
5111590Srgrimes    default:
5121590Srgrimes	putc(c, f);
5131590Srgrimes	need_newline = 1;
5141590Srgrimes	goto loop;
5151590Srgrimes    }
5161590Srgrimes}
5171590Srgrimes
5181590Srgrimes
51921622Sstevestatic void
520214959Sobriencopy_union(void)
5211590Srgrimes{
52287171Smarkm    int c;
5231590Srgrimes    int quote;
5241590Srgrimes    int depth;
5251590Srgrimes    int u_lineno = lineno;
5261590Srgrimes    char *u_line = dup_line();
5271590Srgrimes    char *u_cptr = u_line + (cptr - line - 6);
5281590Srgrimes
5291590Srgrimes    if (unionized) over_unionized(cptr - 6);
5301590Srgrimes    unionized = 1;
5311590Srgrimes
5321590Srgrimes    if (!lflag)
5331590Srgrimes	fprintf(text_file, line_format, lineno, input_file_name);
5341590Srgrimes
5351590Srgrimes    fprintf(text_file, "typedef union");
5361590Srgrimes    if (dflag) fprintf(union_file, "typedef union");
5371590Srgrimes
5381590Srgrimes    depth = 0;
5391590Srgrimesloop:
5401590Srgrimes    c = *cptr++;
5411590Srgrimes    putc(c, text_file);
5421590Srgrimes    if (dflag) putc(c, union_file);
5431590Srgrimes    switch (c)
5441590Srgrimes    {
5451590Srgrimes    case '\n':
5461590Srgrimes    next_line:
5471590Srgrimes	get_line();
5481590Srgrimes	if (line == 0) unterminated_union(u_lineno, u_line, u_cptr);
5491590Srgrimes	goto loop;
5501590Srgrimes
5511590Srgrimes    case '{':
5521590Srgrimes	++depth;
5531590Srgrimes	goto loop;
5541590Srgrimes
5551590Srgrimes    case '}':
5561590Srgrimes	if (--depth == 0)
5571590Srgrimes	{
5581590Srgrimes	    fprintf(text_file, " YYSTYPE;\n");
559214961Sobrien	    free(u_line);
5601590Srgrimes	    return;
5611590Srgrimes	}
5621590Srgrimes	goto loop;
5631590Srgrimes
5641590Srgrimes    case '\'':
5651590Srgrimes    case '"':
5661590Srgrimes	{
5671590Srgrimes	    int s_lineno = lineno;
5681590Srgrimes	    char *s_line = dup_line();
5691590Srgrimes	    char *s_cptr = s_line + (cptr - line - 1);
5701590Srgrimes
5711590Srgrimes	    quote = c;
5721590Srgrimes	    for (;;)
5731590Srgrimes	    {
5741590Srgrimes		c = *cptr++;
5751590Srgrimes		putc(c, text_file);
5761590Srgrimes		if (dflag) putc(c, union_file);
5771590Srgrimes		if (c == quote)
5781590Srgrimes		{
579214961Sobrien		    free(s_line);
5801590Srgrimes		    goto loop;
5811590Srgrimes		}
5821590Srgrimes		if (c == '\n')
5831590Srgrimes		    unterminated_string(s_lineno, s_line, s_cptr);
5841590Srgrimes		if (c == '\\')
5851590Srgrimes		{
5861590Srgrimes		    c = *cptr++;
5871590Srgrimes		    putc(c, text_file);
5881590Srgrimes		    if (dflag) putc(c, union_file);
5891590Srgrimes		    if (c == '\n')
5901590Srgrimes		    {
5911590Srgrimes			get_line();
5921590Srgrimes			if (line == 0)
5931590Srgrimes			    unterminated_string(s_lineno, s_line, s_cptr);
5941590Srgrimes		    }
5951590Srgrimes		}
5961590Srgrimes	    }
5971590Srgrimes	}
5981590Srgrimes
5991590Srgrimes    case '/':
6001590Srgrimes	c = *cptr;
6011590Srgrimes	if (c == '/')
6021590Srgrimes	{
6031590Srgrimes	    putc('*', text_file);
6041590Srgrimes	    if (dflag) putc('*', union_file);
6051590Srgrimes	    while ((c = *++cptr) != '\n')
6061590Srgrimes	    {
6071590Srgrimes		if (c == '*' && cptr[1] == '/')
6081590Srgrimes		{
6091590Srgrimes		    fprintf(text_file, "* ");
6101590Srgrimes		    if (dflag) fprintf(union_file, "* ");
6111590Srgrimes		}
6121590Srgrimes		else
6131590Srgrimes		{
6141590Srgrimes		    putc(c, text_file);
6151590Srgrimes		    if (dflag) putc(c, union_file);
6161590Srgrimes		}
6171590Srgrimes	    }
6181590Srgrimes	    fprintf(text_file, "*/\n");
6191590Srgrimes	    if (dflag) fprintf(union_file, "*/\n");
6201590Srgrimes	    goto next_line;
6211590Srgrimes	}
6221590Srgrimes	if (c == '*')
6231590Srgrimes	{
6241590Srgrimes	    int c_lineno = lineno;
6251590Srgrimes	    char *c_line = dup_line();
6261590Srgrimes	    char *c_cptr = c_line + (cptr - line - 1);
6271590Srgrimes
6281590Srgrimes	    putc('*', text_file);
6291590Srgrimes	    if (dflag) putc('*', union_file);
6301590Srgrimes	    ++cptr;
6311590Srgrimes	    for (;;)
6321590Srgrimes	    {
6331590Srgrimes		c = *cptr++;
6341590Srgrimes		putc(c, text_file);
6351590Srgrimes		if (dflag) putc(c, union_file);
6361590Srgrimes		if (c == '*' && *cptr == '/')
6371590Srgrimes		{
6381590Srgrimes		    putc('/', text_file);
6391590Srgrimes		    if (dflag) putc('/', union_file);
6401590Srgrimes		    ++cptr;
641214961Sobrien		    free(c_line);
6421590Srgrimes		    goto loop;
6431590Srgrimes		}
6441590Srgrimes		if (c == '\n')
6451590Srgrimes		{
6461590Srgrimes		    get_line();
6471590Srgrimes		    if (line == 0)
6481590Srgrimes			unterminated_comment(c_lineno, c_line, c_cptr);
6491590Srgrimes		}
6501590Srgrimes	    }
6511590Srgrimes	}
6521590Srgrimes	goto loop;
6531590Srgrimes
6541590Srgrimes    default:
6551590Srgrimes	goto loop;
6561590Srgrimes    }
6571590Srgrimes}
6581590Srgrimes
6591590Srgrimes
66021622Sstevestatic int
661214959Sobrienhexval(int c)
6621590Srgrimes{
6631590Srgrimes    if (c >= '0' && c <= '9')
6641590Srgrimes	return (c - '0');
6651590Srgrimes    if (c >= 'A' && c <= 'F')
6661590Srgrimes	return (c - 'A' + 10);
6671590Srgrimes    if (c >= 'a' && c <= 'f')
6681590Srgrimes	return (c - 'a' + 10);
6691590Srgrimes    return (-1);
6701590Srgrimes}
6711590Srgrimes
6721590Srgrimes
67321622Sstevestatic bucket *
674214959Sobrienget_literal(void)
6751590Srgrimes{
67687171Smarkm    int c, quote;
67787171Smarkm    int i;
67887171Smarkm    int n;
67987171Smarkm    char *s;
68087171Smarkm    bucket *bp;
6811590Srgrimes    int s_lineno = lineno;
6821590Srgrimes    char *s_line = dup_line();
6831590Srgrimes    char *s_cptr = s_line + (cptr - line);
6841590Srgrimes
6851590Srgrimes    quote = *cptr++;
6861590Srgrimes    cinc = 0;
6871590Srgrimes    for (;;)
6881590Srgrimes    {
6891590Srgrimes	c = *cptr++;
6901590Srgrimes	if (c == quote) break;
6911590Srgrimes	if (c == '\n') unterminated_string(s_lineno, s_line, s_cptr);
6921590Srgrimes	if (c == '\\')
6931590Srgrimes	{
6941590Srgrimes	    char *c_cptr = cptr - 1;
6951590Srgrimes
6961590Srgrimes	    c = *cptr++;
6971590Srgrimes	    switch (c)
6981590Srgrimes	    {
6991590Srgrimes	    case '\n':
7001590Srgrimes		get_line();
7011590Srgrimes		if (line == 0) unterminated_string(s_lineno, s_line, s_cptr);
7021590Srgrimes		continue;
7031590Srgrimes
7041590Srgrimes	    case '0': case '1': case '2': case '3':
7051590Srgrimes	    case '4': case '5': case '6': case '7':
7061590Srgrimes		n = c - '0';
7071590Srgrimes		c = *cptr;
7081590Srgrimes		if (IS_OCTAL(c))
7091590Srgrimes		{
7101590Srgrimes		    n = (n << 3) + (c - '0');
7111590Srgrimes		    c = *++cptr;
7121590Srgrimes		    if (IS_OCTAL(c))
7131590Srgrimes		    {
7141590Srgrimes			n = (n << 3) + (c - '0');
7151590Srgrimes			++cptr;
7161590Srgrimes		    }
7171590Srgrimes		}
718215027Sobrien		if (n > (int)UCHAR_MAX) illegal_character(c_cptr);
7191590Srgrimes		c = n;
7201590Srgrimes	    	break;
7211590Srgrimes
7221590Srgrimes	    case 'x':
7231590Srgrimes		c = *cptr++;
7241590Srgrimes		n = hexval(c);
7251590Srgrimes		if (n < 0 || n >= 16)
7261590Srgrimes		    illegal_character(c_cptr);
7271590Srgrimes		for (;;)
7281590Srgrimes		{
7291590Srgrimes		    c = *cptr;
7301590Srgrimes		    i = hexval(c);
7311590Srgrimes		    if (i < 0 || i >= 16) break;
7321590Srgrimes		    ++cptr;
7331590Srgrimes		    n = (n << 4) + i;
734215027Sobrien		    if (n > (int)UCHAR_MAX) illegal_character(c_cptr);
7351590Srgrimes		}
7361590Srgrimes		c = n;
7371590Srgrimes		break;
7381590Srgrimes
7391590Srgrimes	    case 'a': c = 7; break;
7401590Srgrimes	    case 'b': c = '\b'; break;
7411590Srgrimes	    case 'f': c = '\f'; break;
7421590Srgrimes	    case 'n': c = '\n'; break;
7431590Srgrimes	    case 'r': c = '\r'; break;
7441590Srgrimes	    case 't': c = '\t'; break;
7451590Srgrimes	    case 'v': c = '\v'; break;
7461590Srgrimes	    }
7471590Srgrimes	}
7481590Srgrimes	cachec(c);
7491590Srgrimes    }
750214961Sobrien    free(s_line);
7511590Srgrimes
7521590Srgrimes    n = cinc;
753214961Sobrien    s = malloc(n);
7541590Srgrimes    if (s == 0) no_space();
7558874Srgrimes
7561590Srgrimes    for (i = 0; i < n; ++i)
7571590Srgrimes	s[i] = cache[i];
7581590Srgrimes
7591590Srgrimes    cinc = 0;
7601590Srgrimes    if (n == 1)
7611590Srgrimes	cachec('\'');
7621590Srgrimes    else
7631590Srgrimes	cachec('"');
7641590Srgrimes
7651590Srgrimes    for (i = 0; i < n; ++i)
7661590Srgrimes    {
7671590Srgrimes	c = ((unsigned char *)s)[i];
7681590Srgrimes	if (c == '\\' || c == cache[0])
7691590Srgrimes	{
7701590Srgrimes	    cachec('\\');
7711590Srgrimes	    cachec(c);
7721590Srgrimes	}
7731590Srgrimes	else if (isprint(c))
7741590Srgrimes	    cachec(c);
7751590Srgrimes	else
7761590Srgrimes	{
7771590Srgrimes	    cachec('\\');
7781590Srgrimes	    switch (c)
7791590Srgrimes	    {
7801590Srgrimes	    case 7: cachec('a'); break;
7811590Srgrimes	    case '\b': cachec('b'); break;
7821590Srgrimes	    case '\f': cachec('f'); break;
7831590Srgrimes	    case '\n': cachec('n'); break;
7841590Srgrimes	    case '\r': cachec('r'); break;
7851590Srgrimes	    case '\t': cachec('t'); break;
7861590Srgrimes	    case '\v': cachec('v'); break;
7871590Srgrimes	    default:
7881590Srgrimes		cachec(((c >> 6) & 7) + '0');
7891590Srgrimes		cachec(((c >> 3) & 7) + '0');
7901590Srgrimes		cachec((c & 7) + '0');
7911590Srgrimes		break;
7921590Srgrimes	    }
7931590Srgrimes	}
7941590Srgrimes    }
7951590Srgrimes
7961590Srgrimes    if (n == 1)
7971590Srgrimes	cachec('\'');
7981590Srgrimes    else
7991590Srgrimes	cachec('"');
8001590Srgrimes
8011590Srgrimes    cachec(NUL);
8021590Srgrimes    bp = lookup(cache);
8031590Srgrimes    bp->class = TERM;
8041590Srgrimes    if (n == 1 && bp->value == UNDEFINED)
8051590Srgrimes	bp->value = *(unsigned char *)s;
806214961Sobrien    free(s);
8071590Srgrimes
8081590Srgrimes    return (bp);
8091590Srgrimes}
8101590Srgrimes
8111590Srgrimes
81221622Sstevestatic int
813214959Sobrienis_reserved(char *name)
8141590Srgrimes{
8151590Srgrimes    char *s;
8161590Srgrimes
8171590Srgrimes    if (strcmp(name, ".") == 0 ||
8181590Srgrimes	    strcmp(name, "$accept") == 0 ||
8191590Srgrimes	    strcmp(name, "$end") == 0)
8201590Srgrimes	return (1);
8211590Srgrimes
8221590Srgrimes    if (name[0] == '$' && name[1] == '$' && isdigit(name[2]))
8231590Srgrimes    {
8241590Srgrimes	s = name + 3;
8251590Srgrimes	while (isdigit(*s)) ++s;
8261590Srgrimes	if (*s == NUL) return (1);
8271590Srgrimes    }
8281590Srgrimes
8291590Srgrimes    return (0);
8301590Srgrimes}
8311590Srgrimes
8321590Srgrimes
83321622Sstevestatic bucket *
834214959Sobrienget_name(void)
8351590Srgrimes{
83687171Smarkm    int c;
8371590Srgrimes
8381590Srgrimes    cinc = 0;
8391590Srgrimes    for (c = *cptr; IS_IDENT(c); c = *++cptr)
8401590Srgrimes	cachec(c);
8411590Srgrimes    cachec(NUL);
8421590Srgrimes
8431590Srgrimes    if (is_reserved(cache)) used_reserved(cache);
8441590Srgrimes
8451590Srgrimes    return (lookup(cache));
8461590Srgrimes}
8471590Srgrimes
8481590Srgrimes
84921622Sstevestatic int
850214959Sobrienget_number(void)
8511590Srgrimes{
85287171Smarkm    int c;
85387171Smarkm    int n;
8541590Srgrimes
8551590Srgrimes    n = 0;
8561590Srgrimes    for (c = *cptr; isdigit(c); c = *++cptr)
8571590Srgrimes	n = 10*n + (c - '0');
8581590Srgrimes
8591590Srgrimes    return (n);
8601590Srgrimes}
8611590Srgrimes
8621590Srgrimes
86321622Sstevestatic char *
864214959Sobrienget_tag(void)
8651590Srgrimes{
86687171Smarkm    int c;
86787171Smarkm    int i;
86887171Smarkm    char *s;
8691590Srgrimes    int t_lineno = lineno;
8701590Srgrimes    char *t_line = dup_line();
8711590Srgrimes    char *t_cptr = t_line + (cptr - line);
8721590Srgrimes
8731590Srgrimes    ++cptr;
8741590Srgrimes    c = nextc();
8751590Srgrimes    if (c == EOF) unexpected_EOF();
8761590Srgrimes    if (!isalpha(c) && c != '_' && c != '$')
8771590Srgrimes	illegal_tag(t_lineno, t_line, t_cptr);
8781590Srgrimes
8791590Srgrimes    cinc = 0;
8801590Srgrimes    do { cachec(c); c = *++cptr; } while (IS_IDENT(c));
8811590Srgrimes    cachec(NUL);
8821590Srgrimes
8831590Srgrimes    c = nextc();
8841590Srgrimes    if (c == EOF) unexpected_EOF();
8851590Srgrimes    if (c != '>')
8861590Srgrimes	illegal_tag(t_lineno, t_line, t_cptr);
8871590Srgrimes    ++cptr;
8881590Srgrimes
8891590Srgrimes    for (i = 0; i < ntags; ++i)
8901590Srgrimes    {
8911590Srgrimes	if (strcmp(cache, tag_table[i]) == 0)
8921590Srgrimes	    return (tag_table[i]);
8931590Srgrimes    }
8941590Srgrimes
8951590Srgrimes    if (ntags >= tagmax)
8961590Srgrimes    {
8971590Srgrimes	tagmax += 16;
8981590Srgrimes	tag_table = (char **)
899214961Sobrien			(tag_table ? realloc(tag_table, tagmax*sizeof(char *))
900214961Sobrien				   : malloc(tagmax*sizeof(char *)));
9011590Srgrimes	if (tag_table == 0) no_space();
9021590Srgrimes    }
9031590Srgrimes
904214961Sobrien    s = malloc(cinc);
9051590Srgrimes    if  (s == 0) no_space();
9061590Srgrimes    strcpy(s, cache);
9071590Srgrimes    tag_table[ntags] = s;
9081590Srgrimes    ++ntags;
909214961Sobrien    free(t_line);
9101590Srgrimes    return (s);
9111590Srgrimes}
9121590Srgrimes
9131590Srgrimes
91421622Sstevestatic void
915214959Sobriendeclare_tokens(int assoc)
9161590Srgrimes{
91787171Smarkm    int c;
91887171Smarkm    bucket *bp;
9191590Srgrimes    int value;
9201590Srgrimes    char *tag = 0;
9211590Srgrimes
9221590Srgrimes    if (assoc != TOKEN) ++prec;
9231590Srgrimes
9241590Srgrimes    c = nextc();
9251590Srgrimes    if (c == EOF) unexpected_EOF();
9261590Srgrimes    if (c == '<')
9271590Srgrimes    {
9281590Srgrimes	tag = get_tag();
9291590Srgrimes	c = nextc();
9301590Srgrimes	if (c == EOF) unexpected_EOF();
9311590Srgrimes    }
9321590Srgrimes
9331590Srgrimes    for (;;)
9341590Srgrimes    {
9351590Srgrimes	if (isalpha(c) || c == '_' || c == '.' || c == '$')
9361590Srgrimes	    bp = get_name();
9371590Srgrimes	else if (c == '\'' || c == '"')
9381590Srgrimes	    bp = get_literal();
9391590Srgrimes	else
9401590Srgrimes	    return;
9411590Srgrimes
9421590Srgrimes	if (bp == goal) tokenized_start(bp->name);
9431590Srgrimes	bp->class = TERM;
9441590Srgrimes
9451590Srgrimes	if (tag)
9461590Srgrimes	{
9471590Srgrimes	    if (bp->tag && tag != bp->tag)
9481590Srgrimes		retyped_warning(bp->name);
9491590Srgrimes	    bp->tag = tag;
9501590Srgrimes	}
9511590Srgrimes
9521590Srgrimes	if (assoc != TOKEN)
9531590Srgrimes	{
9541590Srgrimes	    if (bp->prec && prec != bp->prec)
9551590Srgrimes		reprec_warning(bp->name);
9561590Srgrimes	    bp->assoc = assoc;
9571590Srgrimes	    bp->prec = prec;
9581590Srgrimes	}
9591590Srgrimes
9601590Srgrimes	c = nextc();
9611590Srgrimes	if (c == EOF) unexpected_EOF();
9621590Srgrimes	value = UNDEFINED;
9631590Srgrimes	if (isdigit(c))
9641590Srgrimes	{
9651590Srgrimes	    value = get_number();
9661590Srgrimes	    if (bp->value != UNDEFINED && value != bp->value)
9671590Srgrimes		revalued_warning(bp->name);
9681590Srgrimes	    bp->value = value;
9691590Srgrimes	    c = nextc();
9701590Srgrimes	    if (c == EOF) unexpected_EOF();
9711590Srgrimes	}
9721590Srgrimes    }
9731590Srgrimes}
9741590Srgrimes
9751590Srgrimes
97649208Sobrien/*
97749208Sobrien * %expect requires special handling
97849208Sobrien * as it really isn't part of the yacc
97949208Sobrien * grammar only a flag for yacc proper.
98049208Sobrien */
98121622Sstevestatic void
982214959Sobriendeclare_expect(int assoc)
98349208Sobrien{
98487171Smarkm    int c;
98549208Sobrien
98649208Sobrien    if (assoc != EXPECT) ++prec;
98749208Sobrien
98849208Sobrien    /*
98949208Sobrien     * Stay away from nextc - doesn't
99049208Sobrien     * detect EOL and will read to EOF.
99149208Sobrien     */
99249208Sobrien    c = *++cptr;
99349208Sobrien    if (c == EOF) unexpected_EOF();
99449208Sobrien
99549208Sobrien    for(;;)
99649208Sobrien    {
99749208Sobrien	if (isdigit(c))
99849208Sobrien	{
99949208Sobrien	    SRexpect = get_number();
100049208Sobrien	    break;
100149208Sobrien	}
100249208Sobrien	/*
100349208Sobrien	 * Looking for number before EOL.
100449208Sobrien	 * Spaces, tabs, and numbers are ok,
100549208Sobrien	 * words, punc., etc. are syntax errors.
100649208Sobrien	 */
100749208Sobrien	else if (c == '\n' || isalpha(c) || !isspace(c))
100849208Sobrien	{
100949208Sobrien	    syntax_error(lineno, line, cptr);
101049208Sobrien	}
101149208Sobrien	else
101249208Sobrien	{
101349208Sobrien	    c = *++cptr;
101449208Sobrien	    if (c == EOF) unexpected_EOF();
101549208Sobrien	}
101649208Sobrien    }
101749208Sobrien}
101849208Sobrien
101949208Sobrien
102049208Sobrienstatic void
1021214959Sobriendeclare_types(void)
10221590Srgrimes{
102387171Smarkm    int c;
102487171Smarkm    bucket *bp;
10251590Srgrimes    char *tag;
10261590Srgrimes
10271590Srgrimes    c = nextc();
10281590Srgrimes    if (c == EOF) unexpected_EOF();
10291590Srgrimes    if (c != '<') syntax_error(lineno, line, cptr);
10301590Srgrimes    tag = get_tag();
10311590Srgrimes
10321590Srgrimes    for (;;)
10331590Srgrimes    {
10341590Srgrimes	c = nextc();
10351590Srgrimes	if (isalpha(c) || c == '_' || c == '.' || c == '$')
10361590Srgrimes	    bp = get_name();
10371590Srgrimes	else if (c == '\'' || c == '"')
10381590Srgrimes	    bp = get_literal();
10391590Srgrimes	else
10401590Srgrimes	    return;
10411590Srgrimes
10421590Srgrimes	if (bp->tag && tag != bp->tag)
10431590Srgrimes	    retyped_warning(bp->name);
10441590Srgrimes	bp->tag = tag;
10451590Srgrimes    }
10461590Srgrimes}
10471590Srgrimes
10481590Srgrimes
104921622Sstevestatic void
1050214959Sobriendeclare_start(void)
10511590Srgrimes{
105287171Smarkm    int c;
105387171Smarkm    bucket *bp;
10541590Srgrimes
10551590Srgrimes    c = nextc();
10561590Srgrimes    if (c == EOF) unexpected_EOF();
10571590Srgrimes    if (!isalpha(c) && c != '_' && c != '.' && c != '$')
10581590Srgrimes	syntax_error(lineno, line, cptr);
10591590Srgrimes    bp = get_name();
10601590Srgrimes    if (bp->class == TERM)
10611590Srgrimes	terminal_start(bp->name);
10621590Srgrimes    if (goal && goal != bp)
10631590Srgrimes	restarted_warning();
10641590Srgrimes    goal = bp;
10651590Srgrimes}
10661590Srgrimes
10671590Srgrimes
106821622Sstevestatic void
1069214959Sobrienread_declarations(void)
10701590Srgrimes{
107187171Smarkm    int c, k;
10721590Srgrimes
10731590Srgrimes    cache_size = 256;
1074214961Sobrien    cache = malloc(cache_size);
10751590Srgrimes    if (cache == 0) no_space();
10761590Srgrimes
10771590Srgrimes    for (;;)
10781590Srgrimes    {
10791590Srgrimes	c = nextc();
10801590Srgrimes	if (c == EOF) unexpected_EOF();
10811590Srgrimes	if (c != '%') syntax_error(lineno, line, cptr);
10821590Srgrimes	switch (k = keyword())
10831590Srgrimes	{
10841590Srgrimes	case MARK:
10851590Srgrimes	    return;
10861590Srgrimes
10871590Srgrimes	case IDENT:
10881590Srgrimes	    copy_ident();
10891590Srgrimes	    break;
10901590Srgrimes
10911590Srgrimes	case TEXT:
10921590Srgrimes	    copy_text();
10931590Srgrimes	    break;
10941590Srgrimes
10951590Srgrimes	case UNION:
10961590Srgrimes	    copy_union();
10971590Srgrimes	    break;
10981590Srgrimes
10991590Srgrimes	case TOKEN:
11001590Srgrimes	case LEFT:
11011590Srgrimes	case RIGHT:
11021590Srgrimes	case NONASSOC:
11031590Srgrimes	    declare_tokens(k);
11041590Srgrimes	    break;
11051590Srgrimes
110649208Sobrien	case EXPECT:
110749208Sobrien	    declare_expect(k);
110849208Sobrien	    break;
110949208Sobrien
11101590Srgrimes	case TYPE:
11111590Srgrimes	    declare_types();
11121590Srgrimes	    break;
11131590Srgrimes
11141590Srgrimes	case START:
11151590Srgrimes	    declare_start();
11161590Srgrimes	    break;
11171590Srgrimes	}
11181590Srgrimes    }
11191590Srgrimes}
11201590Srgrimes
11211590Srgrimes
112221622Sstevestatic void
1123214959Sobrieninitialize_grammar(void)
11241590Srgrimes{
11251590Srgrimes    nitems = 4;
11261590Srgrimes    maxitems = 300;
1127214961Sobrien    pitem = malloc(maxitems*sizeof(bucket *));
11281590Srgrimes    if (pitem == 0) no_space();
11291590Srgrimes    pitem[0] = 0;
11301590Srgrimes    pitem[1] = 0;
11311590Srgrimes    pitem[2] = 0;
11321590Srgrimes    pitem[3] = 0;
11331590Srgrimes
11341590Srgrimes    nrules = 3;
11351590Srgrimes    maxrules = 100;
1136214961Sobrien    plhs = malloc(maxrules*sizeof(bucket *));
11371590Srgrimes    if (plhs == 0) no_space();
11381590Srgrimes    plhs[0] = 0;
11391590Srgrimes    plhs[1] = 0;
11401590Srgrimes    plhs[2] = 0;
1141214961Sobrien    rprec = malloc(maxrules*sizeof(short));
11421590Srgrimes    if (rprec == 0) no_space();
11431590Srgrimes    rprec[0] = 0;
11441590Srgrimes    rprec[1] = 0;
11451590Srgrimes    rprec[2] = 0;
1146214961Sobrien    rassoc = malloc(maxrules*sizeof(char));
11471590Srgrimes    if (rassoc == 0) no_space();
11481590Srgrimes    rassoc[0] = TOKEN;
11491590Srgrimes    rassoc[1] = TOKEN;
11501590Srgrimes    rassoc[2] = TOKEN;
11511590Srgrimes}
11521590Srgrimes
11531590Srgrimes
115421622Sstevestatic void
1155214959Sobrienexpand_items(void)
11561590Srgrimes{
11571590Srgrimes    maxitems += 300;
1158214961Sobrien    pitem = realloc(pitem, maxitems*sizeof(bucket *));
11591590Srgrimes    if (pitem == 0) no_space();
11601590Srgrimes}
11611590Srgrimes
11621590Srgrimes
116321622Sstevestatic void
1164214959Sobrienexpand_rules(void)
11651590Srgrimes{
11661590Srgrimes    maxrules += 100;
1167214961Sobrien    plhs = realloc(plhs, maxrules*sizeof(bucket *));
11681590Srgrimes    if (plhs == 0) no_space();
1169214961Sobrien    rprec = realloc(rprec, maxrules*sizeof(short));
11701590Srgrimes    if (rprec == 0) no_space();
1171214961Sobrien    rassoc = realloc(rassoc, maxrules*sizeof(char));
11721590Srgrimes    if (rassoc == 0) no_space();
11731590Srgrimes}
11741590Srgrimes
11751590Srgrimes
117621622Sstevestatic void
1177214959Sobrienadvance_to_start(void)
11781590Srgrimes{
117987171Smarkm    int c;
118087171Smarkm    bucket *bp;
11811590Srgrimes    char *s_cptr;
11821590Srgrimes    int s_lineno;
11831590Srgrimes
11841590Srgrimes    for (;;)
11851590Srgrimes    {
11861590Srgrimes	c = nextc();
11871590Srgrimes	if (c != '%') break;
11881590Srgrimes	s_cptr = cptr;
11891590Srgrimes	switch (keyword())
11901590Srgrimes	{
11911590Srgrimes	case MARK:
11921590Srgrimes	    no_grammar();
11931590Srgrimes
11941590Srgrimes	case TEXT:
11951590Srgrimes	    copy_text();
11961590Srgrimes	    break;
11971590Srgrimes
11981590Srgrimes	case START:
11991590Srgrimes	    declare_start();
12001590Srgrimes	    break;
12011590Srgrimes
12021590Srgrimes	default:
12031590Srgrimes	    syntax_error(lineno, line, s_cptr);
12041590Srgrimes	}
12051590Srgrimes    }
12061590Srgrimes
12071590Srgrimes    c = nextc();
12081590Srgrimes    if (!isalpha(c) && c != '_' && c != '.' && c != '_')
12091590Srgrimes	syntax_error(lineno, line, cptr);
12101590Srgrimes    bp = get_name();
12111590Srgrimes    if (goal == 0)
12121590Srgrimes    {
12131590Srgrimes	if (bp->class == TERM)
12141590Srgrimes	    terminal_start(bp->name);
12151590Srgrimes	goal = bp;
12161590Srgrimes    }
12171590Srgrimes
12181590Srgrimes    s_lineno = lineno;
12191590Srgrimes    c = nextc();
12201590Srgrimes    if (c == EOF) unexpected_EOF();
12211590Srgrimes    if (c != ':') syntax_error(lineno, line, cptr);
12221590Srgrimes    start_rule(bp, s_lineno);
12231590Srgrimes    ++cptr;
12241590Srgrimes}
12251590Srgrimes
12261590Srgrimes
122721622Sstevestatic void
1228214959Sobrienstart_rule(bucket *bp, int s_lineno)
12291590Srgrimes{
12301590Srgrimes    if (bp->class == TERM)
12311590Srgrimes	terminal_lhs(s_lineno);
12321590Srgrimes    bp->class = NONTERM;
12331590Srgrimes    if (nrules >= maxrules)
12341590Srgrimes	expand_rules();
12351590Srgrimes    plhs[nrules] = bp;
12361590Srgrimes    rprec[nrules] = UNDEFINED;
12371590Srgrimes    rassoc[nrules] = TOKEN;
12381590Srgrimes}
12391590Srgrimes
12401590Srgrimes
124121622Sstevestatic void
1242214959Sobrienend_rule(void)
12431590Srgrimes{
124487171Smarkm    int i;
12451590Srgrimes
12461590Srgrimes    if (!last_was_action && plhs[nrules]->tag)
12471590Srgrimes    {
12481590Srgrimes	for (i = nitems - 1; pitem[i]; --i) continue;
12491590Srgrimes	if (pitem[i+1] == 0 || pitem[i+1]->tag != plhs[nrules]->tag)
12501590Srgrimes	    default_action_warning();
12511590Srgrimes    }
12521590Srgrimes
12531590Srgrimes    last_was_action = 0;
12541590Srgrimes    if (nitems >= maxitems) expand_items();
12551590Srgrimes    pitem[nitems] = 0;
12561590Srgrimes    ++nitems;
12571590Srgrimes    ++nrules;
12581590Srgrimes}
12591590Srgrimes
12601590Srgrimes
126121622Sstevestatic void
1262214959Sobrieninsert_empty_rule(void)
12631590Srgrimes{
126487171Smarkm    bucket *bp, **bpp;
12651590Srgrimes
12661590Srgrimes    assert(cache);
12671590Srgrimes    sprintf(cache, "$$%d", ++gensym);
12681590Srgrimes    bp = make_bucket(cache);
12691590Srgrimes    last_symbol->next = bp;
12701590Srgrimes    last_symbol = bp;
12711590Srgrimes    bp->tag = plhs[nrules]->tag;
12721590Srgrimes    bp->class = NONTERM;
12731590Srgrimes
12741590Srgrimes    if ((nitems += 2) > maxitems)
12751590Srgrimes	expand_items();
12761590Srgrimes    bpp = pitem + nitems - 1;
12771590Srgrimes    *bpp-- = bp;
127821622Ssteve    while ((bpp[0] = bpp[-1])) --bpp;
12791590Srgrimes
12801590Srgrimes    if (++nrules >= maxrules)
12811590Srgrimes	expand_rules();
12821590Srgrimes    plhs[nrules] = plhs[nrules-1];
12831590Srgrimes    plhs[nrules-1] = bp;
12841590Srgrimes    rprec[nrules] = rprec[nrules-1];
12851590Srgrimes    rprec[nrules-1] = 0;
12861590Srgrimes    rassoc[nrules] = rassoc[nrules-1];
12871590Srgrimes    rassoc[nrules-1] = TOKEN;
12881590Srgrimes}
12891590Srgrimes
12901590Srgrimes
129121622Sstevestatic void
1292214959Sobrienadd_symbol(void)
12931590Srgrimes{
129487171Smarkm    int c;
129587171Smarkm    bucket *bp;
12961590Srgrimes    int s_lineno = lineno;
12971590Srgrimes
12981590Srgrimes    c = *cptr;
12991590Srgrimes    if (c == '\'' || c == '"')
13001590Srgrimes	bp = get_literal();
13011590Srgrimes    else
13021590Srgrimes	bp = get_name();
13031590Srgrimes
13041590Srgrimes    c = nextc();
13051590Srgrimes    if (c == ':')
13061590Srgrimes    {
13071590Srgrimes	end_rule();
13081590Srgrimes	start_rule(bp, s_lineno);
13091590Srgrimes	++cptr;
13101590Srgrimes	return;
13111590Srgrimes    }
13121590Srgrimes
13131590Srgrimes    if (last_was_action)
13141590Srgrimes	insert_empty_rule();
13151590Srgrimes    last_was_action = 0;
13161590Srgrimes
13171590Srgrimes    if (++nitems > maxitems)
13181590Srgrimes	expand_items();
13191590Srgrimes    pitem[nitems-1] = bp;
13201590Srgrimes}
13211590Srgrimes
13221590Srgrimes
132321622Sstevestatic void
1324214959Sobriencopy_action(void)
13251590Srgrimes{
132687171Smarkm    int c;
132787171Smarkm    int i, n;
13281590Srgrimes    int depth;
13291590Srgrimes    int quote;
13301590Srgrimes    char *tag;
133187171Smarkm    FILE *f = action_file;
13321590Srgrimes    int a_lineno = lineno;
13331590Srgrimes    char *a_line = dup_line();
13341590Srgrimes    char *a_cptr = a_line + (cptr - line);
13351590Srgrimes
13361590Srgrimes    if (last_was_action)
13371590Srgrimes	insert_empty_rule();
13381590Srgrimes    last_was_action = 1;
13391590Srgrimes
13401590Srgrimes    fprintf(f, "case %d:\n", nrules - 2);
13411590Srgrimes    if (!lflag)
13421590Srgrimes	fprintf(f, line_format, lineno, input_file_name);
13431590Srgrimes    if (*cptr == '=') ++cptr;
13441590Srgrimes
13451590Srgrimes    n = 0;
13461590Srgrimes    for (i = nitems - 1; pitem[i]; --i) ++n;
13471590Srgrimes
13481590Srgrimes    depth = 0;
13491590Srgrimesloop:
13501590Srgrimes    c = *cptr;
13511590Srgrimes    if (c == '$')
13521590Srgrimes    {
13531590Srgrimes	if (cptr[1] == '<')
13541590Srgrimes	{
13551590Srgrimes	    int d_lineno = lineno;
13561590Srgrimes	    char *d_line = dup_line();
13571590Srgrimes	    char *d_cptr = d_line + (cptr - line);
13581590Srgrimes
13591590Srgrimes	    ++cptr;
13601590Srgrimes	    tag = get_tag();
13611590Srgrimes	    c = *cptr;
13621590Srgrimes	    if (c == '$')
13631590Srgrimes	    {
13641590Srgrimes		fprintf(f, "yyval.%s", tag);
13651590Srgrimes		++cptr;
1366214961Sobrien		free(d_line);
13671590Srgrimes		goto loop;
13681590Srgrimes	    }
13691590Srgrimes	    else if (isdigit(c))
13701590Srgrimes	    {
13711590Srgrimes		i = get_number();
13721590Srgrimes		if (i > n) dollar_warning(d_lineno, i);
13731590Srgrimes		fprintf(f, "yyvsp[%d].%s", i - n, tag);
1374214961Sobrien		free(d_line);
13751590Srgrimes		goto loop;
13761590Srgrimes	    }
13771590Srgrimes	    else if (c == '-' && isdigit(cptr[1]))
13781590Srgrimes	    {
13791590Srgrimes		++cptr;
13801590Srgrimes		i = -get_number() - n;
13811590Srgrimes		fprintf(f, "yyvsp[%d].%s", i, tag);
1382214961Sobrien		free(d_line);
13831590Srgrimes		goto loop;
13841590Srgrimes	    }
13851590Srgrimes	    else
13861590Srgrimes		dollar_error(d_lineno, d_line, d_cptr);
13871590Srgrimes	}
13881590Srgrimes	else if (cptr[1] == '$')
13891590Srgrimes	{
13901590Srgrimes	    if (ntags)
13911590Srgrimes	    {
13921590Srgrimes		tag = plhs[nrules]->tag;
13931590Srgrimes		if (tag == 0) untyped_lhs();
13941590Srgrimes		fprintf(f, "yyval.%s", tag);
13951590Srgrimes	    }
13961590Srgrimes	    else
13971590Srgrimes		fprintf(f, "yyval");
13981590Srgrimes	    cptr += 2;
13991590Srgrimes	    goto loop;
14001590Srgrimes	}
14011590Srgrimes	else if (isdigit(cptr[1]))
14021590Srgrimes	{
14031590Srgrimes	    ++cptr;
14041590Srgrimes	    i = get_number();
14051590Srgrimes	    if (ntags)
14061590Srgrimes	    {
14071590Srgrimes		if (i <= 0 || i > n)
14081590Srgrimes		    unknown_rhs(i);
14091590Srgrimes		tag = pitem[nitems + i - n - 1]->tag;
14101590Srgrimes		if (tag == 0) untyped_rhs(i, pitem[nitems + i - n - 1]->name);
14111590Srgrimes		fprintf(f, "yyvsp[%d].%s", i - n, tag);
14121590Srgrimes	    }
14131590Srgrimes	    else
14141590Srgrimes	    {
14151590Srgrimes		if (i > n)
14161590Srgrimes		    dollar_warning(lineno, i);
14171590Srgrimes		fprintf(f, "yyvsp[%d]", i - n);
14181590Srgrimes	    }
14191590Srgrimes	    goto loop;
14201590Srgrimes	}
14211590Srgrimes	else if (cptr[1] == '-')
14221590Srgrimes	{
14231590Srgrimes	    cptr += 2;
14241590Srgrimes	    i = get_number();
14251590Srgrimes	    if (ntags)
14261590Srgrimes		unknown_rhs(-i);
14271590Srgrimes	    fprintf(f, "yyvsp[%d]", -i - n);
14281590Srgrimes	    goto loop;
14291590Srgrimes	}
14301590Srgrimes    }
14311590Srgrimes    if (isalpha(c) || c == '_' || c == '$')
14321590Srgrimes    {
14331590Srgrimes	do
14341590Srgrimes	{
14351590Srgrimes	    putc(c, f);
14361590Srgrimes	    c = *++cptr;
14371590Srgrimes	} while (isalnum(c) || c == '_' || c == '$');
14381590Srgrimes	goto loop;
14391590Srgrimes    }
14401590Srgrimes    putc(c, f);
14411590Srgrimes    ++cptr;
14421590Srgrimes    switch (c)
14431590Srgrimes    {
14441590Srgrimes    case '\n':
14451590Srgrimes    next_line:
14461590Srgrimes	get_line();
14471590Srgrimes	if (line) goto loop;
14481590Srgrimes	unterminated_action(a_lineno, a_line, a_cptr);
14491590Srgrimes
14501590Srgrimes    case ';':
14511590Srgrimes	if (depth > 0) goto loop;
14521590Srgrimes	fprintf(f, "\nbreak;\n");
14531590Srgrimes	return;
14541590Srgrimes
14551590Srgrimes    case '{':
14561590Srgrimes	++depth;
14571590Srgrimes	goto loop;
14581590Srgrimes
14591590Srgrimes    case '}':
14601590Srgrimes	if (--depth > 0) goto loop;
14611590Srgrimes	fprintf(f, "\nbreak;\n");
14621590Srgrimes	return;
14631590Srgrimes
14641590Srgrimes    case '\'':
14651590Srgrimes    case '"':
14661590Srgrimes	{
14671590Srgrimes	    int s_lineno = lineno;
14681590Srgrimes	    char *s_line = dup_line();
14691590Srgrimes	    char *s_cptr = s_line + (cptr - line - 1);
14701590Srgrimes
14711590Srgrimes	    quote = c;
14721590Srgrimes	    for (;;)
14731590Srgrimes	    {
14741590Srgrimes		c = *cptr++;
14751590Srgrimes		putc(c, f);
14761590Srgrimes		if (c == quote)
14771590Srgrimes		{
1478214961Sobrien		    free(s_line);
14791590Srgrimes		    goto loop;
14801590Srgrimes		}
14811590Srgrimes		if (c == '\n')
14821590Srgrimes		    unterminated_string(s_lineno, s_line, s_cptr);
14831590Srgrimes		if (c == '\\')
14841590Srgrimes		{
14851590Srgrimes		    c = *cptr++;
14861590Srgrimes		    putc(c, f);
14871590Srgrimes		    if (c == '\n')
14881590Srgrimes		    {
14891590Srgrimes			get_line();
14901590Srgrimes			if (line == 0)
14911590Srgrimes			    unterminated_string(s_lineno, s_line, s_cptr);
14921590Srgrimes		    }
14931590Srgrimes		}
14941590Srgrimes	    }
14951590Srgrimes	}
14961590Srgrimes
14971590Srgrimes    case '/':
14981590Srgrimes	c = *cptr;
14991590Srgrimes	if (c == '/')
15001590Srgrimes	{
15011590Srgrimes	    putc('*', f);
15021590Srgrimes	    while ((c = *++cptr) != '\n')
15031590Srgrimes	    {
15041590Srgrimes		if (c == '*' && cptr[1] == '/')
15051590Srgrimes		    fprintf(f, "* ");
15061590Srgrimes		else
15071590Srgrimes		    putc(c, f);
15081590Srgrimes	    }
15091590Srgrimes	    fprintf(f, "*/\n");
15101590Srgrimes	    goto next_line;
15111590Srgrimes	}
15121590Srgrimes	if (c == '*')
15131590Srgrimes	{
15141590Srgrimes	    int c_lineno = lineno;
15151590Srgrimes	    char *c_line = dup_line();
15161590Srgrimes	    char *c_cptr = c_line + (cptr - line - 1);
15171590Srgrimes
15181590Srgrimes	    putc('*', f);
15191590Srgrimes	    ++cptr;
15201590Srgrimes	    for (;;)
15211590Srgrimes	    {
15221590Srgrimes		c = *cptr++;
15231590Srgrimes		putc(c, f);
15241590Srgrimes		if (c == '*' && *cptr == '/')
15251590Srgrimes		{
15261590Srgrimes		    putc('/', f);
15271590Srgrimes		    ++cptr;
1528214961Sobrien		    free(c_line);
15291590Srgrimes		    goto loop;
15301590Srgrimes		}
15311590Srgrimes		if (c == '\n')
15321590Srgrimes		{
15331590Srgrimes		    get_line();
15341590Srgrimes		    if (line == 0)
15351590Srgrimes			unterminated_comment(c_lineno, c_line, c_cptr);
15361590Srgrimes		}
15371590Srgrimes	    }
15381590Srgrimes	}
15391590Srgrimes	goto loop;
15401590Srgrimes
15411590Srgrimes    default:
15421590Srgrimes	goto loop;
15431590Srgrimes    }
15441590Srgrimes}
15451590Srgrimes
15461590Srgrimes
154721622Sstevestatic int
1548214959Sobrienmark_symbol(void)
15491590Srgrimes{
155087171Smarkm    int c;
155187171Smarkm    bucket *bp = NULL;
15521590Srgrimes
15531590Srgrimes    c = cptr[1];
15541590Srgrimes    if (c == '%' || c == '\\')
15551590Srgrimes    {
15561590Srgrimes	cptr += 2;
15571590Srgrimes	return (1);
15581590Srgrimes    }
15591590Srgrimes
15601590Srgrimes    if (c == '=')
15611590Srgrimes	cptr += 2;
15621590Srgrimes    else if ((c == 'p' || c == 'P') &&
15631590Srgrimes	     ((c = cptr[2]) == 'r' || c == 'R') &&
15641590Srgrimes	     ((c = cptr[3]) == 'e' || c == 'E') &&
15651590Srgrimes	     ((c = cptr[4]) == 'c' || c == 'C') &&
15661590Srgrimes	     ((c = cptr[5], !IS_IDENT(c))))
15671590Srgrimes	cptr += 5;
15681590Srgrimes    else
15691590Srgrimes	syntax_error(lineno, line, cptr);
15701590Srgrimes
15711590Srgrimes    c = nextc();
15721590Srgrimes    if (isalpha(c) || c == '_' || c == '.' || c == '$')
15731590Srgrimes	bp = get_name();
15741590Srgrimes    else if (c == '\'' || c == '"')
15751590Srgrimes	bp = get_literal();
15761590Srgrimes    else
15771590Srgrimes    {
15781590Srgrimes	syntax_error(lineno, line, cptr);
15791590Srgrimes	/*NOTREACHED*/
15801590Srgrimes    }
15811590Srgrimes
15821590Srgrimes    if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
15831590Srgrimes	prec_redeclared();
15841590Srgrimes
15851590Srgrimes    rprec[nrules] = bp->prec;
15861590Srgrimes    rassoc[nrules] = bp->assoc;
15871590Srgrimes    return (0);
15881590Srgrimes}
15891590Srgrimes
15901590Srgrimes
159121622Sstevestatic void
1592214959Sobrienread_grammar(void)
15931590Srgrimes{
159487171Smarkm    int c;
15951590Srgrimes
15961590Srgrimes    initialize_grammar();
15971590Srgrimes    advance_to_start();
15981590Srgrimes
15991590Srgrimes    for (;;)
16001590Srgrimes    {
16011590Srgrimes	c = nextc();
16021590Srgrimes	if (c == EOF) break;
16031590Srgrimes	if (isalpha(c) || c == '_' || c == '.' || c == '$' || c == '\'' ||
16041590Srgrimes		c == '"')
16051590Srgrimes	    add_symbol();
16061590Srgrimes	else if (c == '{' || c == '=')
16071590Srgrimes	    copy_action();
16081590Srgrimes	else if (c == '|')
16091590Srgrimes	{
16101590Srgrimes	    end_rule();
16111590Srgrimes	    start_rule(plhs[nrules-1], 0);
16121590Srgrimes	    ++cptr;
16131590Srgrimes	}
16141590Srgrimes	else if (c == '%')
16151590Srgrimes	{
16161590Srgrimes	    if (mark_symbol()) break;
16171590Srgrimes	}
16181590Srgrimes	else
16191590Srgrimes	    syntax_error(lineno, line, cptr);
16201590Srgrimes    }
16211590Srgrimes    end_rule();
16221590Srgrimes}
16231590Srgrimes
16241590Srgrimes
162521622Sstevestatic void
1626214959Sobrienfree_tags(void)
16271590Srgrimes{
162887171Smarkm    int i;
16291590Srgrimes
16301590Srgrimes    if (tag_table == 0) return;
16311590Srgrimes
16321590Srgrimes    for (i = 0; i < ntags; ++i)
16331590Srgrimes    {
16341590Srgrimes	assert(tag_table[i]);
1635214961Sobrien	free(tag_table[i]);
16361590Srgrimes    }
1637214961Sobrien    free(tag_table);
16381590Srgrimes}
16391590Srgrimes
16401590Srgrimes
164121622Sstevestatic void
1642214959Sobrienpack_names(void)
16431590Srgrimes{
164487171Smarkm    bucket *bp;
164587171Smarkm    char *p, *s, *t;
16461590Srgrimes
16471590Srgrimes    name_pool_size = 13;  /* 13 == sizeof("$end") + sizeof("$accept") */
16481590Srgrimes    for (bp = first_symbol; bp; bp = bp->next)
16491590Srgrimes	name_pool_size += strlen(bp->name) + 1;
1650214961Sobrien    name_pool = malloc(name_pool_size);
16511590Srgrimes    if (name_pool == 0) no_space();
16521590Srgrimes
16531590Srgrimes    strcpy(name_pool, "$accept");
16541590Srgrimes    strcpy(name_pool+8, "$end");
16551590Srgrimes    t = name_pool + 13;
16561590Srgrimes    for (bp = first_symbol; bp; bp = bp->next)
16571590Srgrimes    {
16581590Srgrimes	p = t;
16591590Srgrimes	s = bp->name;
166021622Ssteve	while ((*t++ = *s++)) continue;
1661214961Sobrien	free(bp->name);
16621590Srgrimes	bp->name = p;
16631590Srgrimes    }
16641590Srgrimes}
16651590Srgrimes
16661590Srgrimes
166721622Sstevestatic void
1668214959Sobriencheck_symbols(void)
16691590Srgrimes{
167087171Smarkm    bucket *bp;
16711590Srgrimes
16721590Srgrimes    if (goal->class == UNKNOWN)
16731590Srgrimes	undefined_goal(goal->name);
16741590Srgrimes
16751590Srgrimes    for (bp = first_symbol; bp; bp = bp->next)
16761590Srgrimes    {
16771590Srgrimes	if (bp->class == UNKNOWN)
16781590Srgrimes	{
16791590Srgrimes	    undefined_symbol_warning(bp->name);
16801590Srgrimes	    bp->class = TERM;
16811590Srgrimes	}
16821590Srgrimes    }
16831590Srgrimes}
16841590Srgrimes
16851590Srgrimes
168621622Sstevestatic void
1687214959Sobrienpack_symbols(void)
16881590Srgrimes{
168987171Smarkm    bucket *bp;
169087171Smarkm    bucket **v;
169187171Smarkm    int i, j, k, n;
16921590Srgrimes
16931590Srgrimes    nsyms = 2;
16941590Srgrimes    ntokens = 1;
16951590Srgrimes    for (bp = first_symbol; bp; bp = bp->next)
16961590Srgrimes    {
16971590Srgrimes	++nsyms;
16981590Srgrimes	if (bp->class == TERM) ++ntokens;
16991590Srgrimes    }
17001590Srgrimes    start_symbol = ntokens;
17011590Srgrimes    nvars = nsyms - ntokens;
17021590Srgrimes
1703214961Sobrien    symbol_name = malloc(nsyms*sizeof(char *));
17041590Srgrimes    if (symbol_name == 0) no_space();
1705214961Sobrien    symbol_value = malloc(nsyms*sizeof(short));
17061590Srgrimes    if (symbol_value == 0) no_space();
1707214961Sobrien    symbol_prec = malloc(nsyms*sizeof(short));
17081590Srgrimes    if (symbol_prec == 0) no_space();
1709214961Sobrien    symbol_assoc = malloc(nsyms);
17101590Srgrimes    if (symbol_assoc == 0) no_space();
17111590Srgrimes
1712214961Sobrien    v = malloc(nsyms*sizeof(bucket *));
17131590Srgrimes    if (v == 0) no_space();
17141590Srgrimes
17151590Srgrimes    v[0] = 0;
17161590Srgrimes    v[start_symbol] = 0;
17171590Srgrimes
17181590Srgrimes    i = 1;
17191590Srgrimes    j = start_symbol + 1;
17201590Srgrimes    for (bp = first_symbol; bp; bp = bp->next)
17211590Srgrimes    {
17221590Srgrimes	if (bp->class == TERM)
17231590Srgrimes	    v[i++] = bp;
17241590Srgrimes	else
17251590Srgrimes	    v[j++] = bp;
17261590Srgrimes    }
17271590Srgrimes    assert(i == ntokens && j == nsyms);
17281590Srgrimes
17291590Srgrimes    for (i = 1; i < ntokens; ++i)
17301590Srgrimes	v[i]->index = i;
17311590Srgrimes
17321590Srgrimes    goal->index = start_symbol + 1;
17331590Srgrimes    k = start_symbol + 2;
17341590Srgrimes    while (++i < nsyms)
17351590Srgrimes	if (v[i] != goal)
17361590Srgrimes	{
17371590Srgrimes	    v[i]->index = k;
17381590Srgrimes	    ++k;
17391590Srgrimes	}
17401590Srgrimes
17411590Srgrimes    goal->value = 0;
17421590Srgrimes    k = 1;
17431590Srgrimes    for (i = start_symbol + 1; i < nsyms; ++i)
17441590Srgrimes    {
17451590Srgrimes	if (v[i] != goal)
17461590Srgrimes	{
17471590Srgrimes	    v[i]->value = k;
17481590Srgrimes	    ++k;
17491590Srgrimes	}
17501590Srgrimes    }
17511590Srgrimes
17521590Srgrimes    k = 0;
17531590Srgrimes    for (i = 1; i < ntokens; ++i)
17541590Srgrimes    {
17551590Srgrimes	n = v[i]->value;
17561590Srgrimes	if (n > 256)
17571590Srgrimes	{
17581590Srgrimes	    for (j = k++; j > 0 && symbol_value[j-1] > n; --j)
17591590Srgrimes		symbol_value[j] = symbol_value[j-1];
17601590Srgrimes	    symbol_value[j] = n;
17611590Srgrimes	}
17621590Srgrimes    }
17631590Srgrimes
17641590Srgrimes    if (v[1]->value == UNDEFINED)
17651590Srgrimes	v[1]->value = 256;
17661590Srgrimes
17671590Srgrimes    j = 0;
17681590Srgrimes    n = 257;
17691590Srgrimes    for (i = 2; i < ntokens; ++i)
17701590Srgrimes    {
17711590Srgrimes	if (v[i]->value == UNDEFINED)
17721590Srgrimes	{
17731590Srgrimes	    while (j < k && n == symbol_value[j])
17741590Srgrimes	    {
17751590Srgrimes		while (++j < k && n == symbol_value[j]) continue;
17761590Srgrimes		++n;
17771590Srgrimes	    }
17781590Srgrimes	    v[i]->value = n;
17791590Srgrimes	    ++n;
17801590Srgrimes	}
17811590Srgrimes    }
17821590Srgrimes
17831590Srgrimes    symbol_name[0] = name_pool + 8;
17841590Srgrimes    symbol_value[0] = 0;
17851590Srgrimes    symbol_prec[0] = 0;
17861590Srgrimes    symbol_assoc[0] = TOKEN;
17871590Srgrimes    for (i = 1; i < ntokens; ++i)
17881590Srgrimes    {
17891590Srgrimes	symbol_name[i] = v[i]->name;
17901590Srgrimes	symbol_value[i] = v[i]->value;
17911590Srgrimes	symbol_prec[i] = v[i]->prec;
17921590Srgrimes	symbol_assoc[i] = v[i]->assoc;
17931590Srgrimes    }
17941590Srgrimes    symbol_name[start_symbol] = name_pool;
17951590Srgrimes    symbol_value[start_symbol] = -1;
17961590Srgrimes    symbol_prec[start_symbol] = 0;
17971590Srgrimes    symbol_assoc[start_symbol] = TOKEN;
17981590Srgrimes    for (++i; i < nsyms; ++i)
17991590Srgrimes    {
18001590Srgrimes	k = v[i]->index;
18011590Srgrimes	symbol_name[k] = v[i]->name;
18021590Srgrimes	symbol_value[k] = v[i]->value;
18031590Srgrimes	symbol_prec[k] = v[i]->prec;
18041590Srgrimes	symbol_assoc[k] = v[i]->assoc;
18051590Srgrimes    }
18061590Srgrimes
1807214961Sobrien    free(v);
18081590Srgrimes}
18091590Srgrimes
18101590Srgrimes
181121622Sstevestatic void
1812214959Sobrienpack_grammar(void)
18131590Srgrimes{
181487171Smarkm    int i, j;
181587171Smarkm    int assoc, preced;
18161590Srgrimes
1817214961Sobrien    ritem = malloc(nitems*sizeof(short));
18181590Srgrimes    if (ritem == 0) no_space();
1819214961Sobrien    rlhs = malloc(nrules*sizeof(short));
18201590Srgrimes    if (rlhs == 0) no_space();
1821214961Sobrien    rrhs = malloc((nrules+1)*sizeof(short));
18221590Srgrimes    if (rrhs == 0) no_space();
1823214961Sobrien    rprec = realloc(rprec, nrules*sizeof(short));
18241590Srgrimes    if (rprec == 0) no_space();
1825214961Sobrien    rassoc = realloc(rassoc, nrules);
18261590Srgrimes    if (rassoc == 0) no_space();
18271590Srgrimes
18281590Srgrimes    ritem[0] = -1;
18291590Srgrimes    ritem[1] = goal->index;
18301590Srgrimes    ritem[2] = 0;
18311590Srgrimes    ritem[3] = -2;
18321590Srgrimes    rlhs[0] = 0;
18331590Srgrimes    rlhs[1] = 0;
18341590Srgrimes    rlhs[2] = start_symbol;
18351590Srgrimes    rrhs[0] = 0;
18361590Srgrimes    rrhs[1] = 0;
18371590Srgrimes    rrhs[2] = 1;
18381590Srgrimes
18391590Srgrimes    j = 4;
18401590Srgrimes    for (i = 3; i < nrules; ++i)
18411590Srgrimes    {
18421590Srgrimes	rlhs[i] = plhs[i]->index;
18431590Srgrimes	rrhs[i] = j;
18441590Srgrimes	assoc = TOKEN;
184587171Smarkm	preced = 0;
18461590Srgrimes	while (pitem[j])
18471590Srgrimes	{
18481590Srgrimes	    ritem[j] = pitem[j]->index;
18491590Srgrimes	    if (pitem[j]->class == TERM)
18501590Srgrimes	    {
185187171Smarkm		preced = pitem[j]->prec;
18521590Srgrimes		assoc = pitem[j]->assoc;
18531590Srgrimes	    }
18541590Srgrimes	    ++j;
18551590Srgrimes	}
18561590Srgrimes	ritem[j] = -i;
18571590Srgrimes	++j;
18581590Srgrimes	if (rprec[i] == UNDEFINED)
18591590Srgrimes	{
186087171Smarkm	    rprec[i] = preced;
18611590Srgrimes	    rassoc[i] = assoc;
18621590Srgrimes	}
18631590Srgrimes    }
18641590Srgrimes    rrhs[i] = j;
18651590Srgrimes
1866214961Sobrien    free(plhs);
1867214961Sobrien    free(pitem);
18681590Srgrimes}
18691590Srgrimes
18701590Srgrimes
187121622Sstevestatic void
1872214959Sobrienprint_grammar(void)
18731590Srgrimes{
187487171Smarkm    int i, j, k;
187593830Sobrien    int spacing;
187687171Smarkm    FILE *f = verbose_file;
18771590Srgrimes
18781590Srgrimes    if (!vflag) return;
18791590Srgrimes
18801590Srgrimes    k = 1;
188194333Sobrien    spacing = 0;
18821590Srgrimes    for (i = 2; i < nrules; ++i)
18831590Srgrimes    {
18841590Srgrimes	if (rlhs[i] != rlhs[i-1])
18851590Srgrimes	{
18861590Srgrimes	    if (i != 2) fprintf(f, "\n");
18871590Srgrimes	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
18881590Srgrimes	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
18891590Srgrimes	}
18901590Srgrimes	else
18911590Srgrimes	{
18921590Srgrimes	    fprintf(f, "%4d  ", i - 2);
18931590Srgrimes	    j = spacing;
18941590Srgrimes	    while (--j >= 0) putc(' ', f);
18951590Srgrimes	    putc('|', f);
18961590Srgrimes	}
18971590Srgrimes
18981590Srgrimes	while (ritem[k] >= 0)
18991590Srgrimes	{
19001590Srgrimes	    fprintf(f, " %s", symbol_name[ritem[k]]);
19011590Srgrimes	    ++k;
19021590Srgrimes	}
19031590Srgrimes	++k;
19041590Srgrimes	putc('\n', f);
19051590Srgrimes    }
19061590Srgrimes}
19071590Srgrimes
19081590Srgrimes
190921622Sstevevoid
1910214959Sobrienreader(void)
19111590Srgrimes{
19121590Srgrimes    write_section(banner);
19131590Srgrimes    create_symbol_table();
19141590Srgrimes    read_declarations();
19151590Srgrimes    read_grammar();
19161590Srgrimes    free_symbol_table();
19171590Srgrimes    free_tags();
19181590Srgrimes    pack_names();
19191590Srgrimes    check_symbols();
19201590Srgrimes    pack_symbols();
19211590Srgrimes    pack_grammar();
19221590Srgrimes    free_symbols();
19231590Srgrimes    print_grammar();
19241590Srgrimes}
1925