Home | History | Annotate | Line # | Download | only in dist
      1 /*	$NetBSD: reader.c,v 1.23 2026/05/03 15:29:20 christos Exp $	*/
      2 
      3 /* Id: reader.c,v 1.108 2026/01/24 13:45:39 tom Exp  */
      4 
      5 #include "defs.h"
      6 
      7 #include <sys/cdefs.h>
      8 __RCSID("$NetBSD: reader.c,v 1.23 2026/05/03 15:29:20 christos Exp $");
      9 
     10 /*  The line size must be a positive integer.  One hundred was chosen	*/
     11 /*  because few lines in Yacc input grammars exceed 100 characters.	*/
     12 /*  Note that if a line exceeds LINESIZE characters, the line buffer	*/
     13 /*  will be expanded to accommodate it.					*/
     14 
     15 #define LINESIZE 100
     16 
     17 #define L_CURL  '{'
     18 #define R_CURL  '}'
     19 #define L_PAREN '('
     20 #define R_PAREN ')'
     21 #define L_BRAC  '['
     22 #define R_BRAC  ']'
     23 
     24 /* the maximum number of arguments (inherited attributes) to a non-terminal */
     25 /* this is a hard limit, but seems more than adequate */
     26 #define MAXARGS	20
     27 
     28 /* limit the size of optional names for %union */
     29 #define NAME_LEN 32
     30 
     31 #define IS_ALNUM(c) (isalnum(UCH(c)) || (c) == '_')
     32 
     33 #define begin_case(f,n) fprintf(f, "case %d:\n", (int)(n))
     34 
     35 #define end_case(f) \
     36 	    fprintf(f, "\n"); \
     37 	    fprintf_lineno(f, 1, ""); \
     38 	    fprintf(f, "break;\n")
     39 
     40 #define begin_ainfo(data, offset) do { \
     41 	    data.a_lineno = lineno; \
     42 	    data.a_line = dup_line(); \
     43 	    data.a_cptr = data.a_line + (cptr - line - offset); \
     44 	} while (0)
     45 
     46 #define end_ainfo(data) do { \
     47 	    FREE(data.a_line); \
     48 	    memset(&data, 0, sizeof(data)); \
     49 	} while (0)
     50 
     51 static void start_rule(bucket *bp, int s_lineno);
     52 #if defined(YYBTYACC)
     53 static void copy_initial_action(void);
     54 static void copy_destructor(void);
     55 static char *process_destructor_XX(char *code, char *tag);
     56 #endif
     57 
     58 #define CACHE_SIZE 256
     59 static char *cache;
     60 static int cinc, cache_size;
     61 
     62 int ntags;
     63 static int tagmax, havetags;
     64 static char **tag_table;
     65 
     66 static char saw_eof;
     67 char unionized;
     68 
     69 char *line;		/* current input-line */
     70 char *cptr;		/* position within current input-line */
     71 static size_t linesize;	/* length of current input-line */
     72 
     73 typedef struct
     74 {
     75     char *line_data;	/* saved input-line */
     76     size_t line_used;	/* position within saved input-line */
     77     size_t line_size;	/* length of saved input-line */
     78     fpos_t line_fpos;	/* pointer before reading past saved input-line */
     79 }
     80 SAVE_LINE;
     81 
     82 static SAVE_LINE save_area;
     83 static int must_save;	/* request > 0, triggered < 0, inactive 0 */
     84 
     85 static bucket *goal;
     86 static Value_t prec;
     87 static int gensym;
     88 static char last_was_action;
     89 #if defined(YYBTYACC)
     90 static int trialaction;
     91 #endif
     92 
     93 static int maxitems;
     94 static bucket **pitem;
     95 
     96 static int maxrules;
     97 static bucket **plhs;
     98 
     99 static size_t name_pool_size;
    100 static char *name_pool;
    101 
    102 char line_format[] = "#line %d \"%s\"\n";
    103 
    104 param *lex_param;
    105 param *parse_param;
    106 
    107 static const char *code_keys[] =
    108 {
    109     "", "requires", "provides", "top", "imports",
    110 };
    111 
    112 struct code_lines code_lines[CODE_MAX];
    113 
    114 #if defined(YYBTYACC)
    115 int destructor = 0;	/* =1 if at least one %destructor */
    116 
    117 static bucket *default_destructor[3] =
    118 {NULL, NULL, NULL};
    119 
    120 #define UNTYPED_DEFAULT 0
    121 #define TYPED_DEFAULT   1
    122 #define TYPE_SPECIFIED  2
    123 
    124 static bucket *
    125 lookup_type_destructor(char *tag)
    126 {
    127     const char fmt[] = "%.*s destructor";
    128     char name[1024] = "\0";
    129     bucket *bp, **bpp = &default_destructor[TYPE_SPECIFIED];
    130 
    131     while ((bp = *bpp) != NULL)
    132     {
    133 	if (bp->tag == tag)
    134 	    return (bp);
    135 	bpp = &bp->link;
    136     }
    137 
    138     sprintf(name, fmt, (int)(sizeof(name) - sizeof(fmt)), tag);
    139     *bpp = bp = make_bucket(name);
    140     bp->tag = tag;
    141 
    142     return (bp);
    143 }
    144 #endif /* defined(YYBTYACC) */
    145 
    146 static void
    147 cachec(int c)
    148 {
    149     assert(cinc >= 0);
    150     if (cinc >= cache_size)
    151     {
    152 	cache_size += CACHE_SIZE;
    153 	cache = TREALLOC(char, cache, cache_size);
    154 	NO_SPACE(cache);
    155     }
    156     cache[cinc] = (char)c;
    157     ++cinc;
    158 }
    159 
    160 typedef enum
    161 {
    162     ldSPC1,
    163     ldSPC2,
    164     ldNAME,
    165     ldSPC3,
    166     ldNUM,
    167     ldSPC4,
    168     ldFILE,
    169     ldOK,
    170     ldERR
    171 }
    172 LINE_DIR;
    173 
    174 /*
    175  * Expect this pattern:
    176  *	/^[[:space:]]*#[[:space:]]*
    177  *	  line[[:space:]]+
    178  *	  [[:digit:]]+
    179  *	  ([[:space:]]*|[[:space:]]+"[^"]+")/
    180  */
    181 static int
    182 line_directive(void)
    183 {
    184 #define UNLESS(what) if (what) { ld = ldERR; break; }
    185     int n;
    186     int line_1st = -1;
    187     int name_1st = -1;
    188     int name_end = -1;
    189     LINE_DIR ld = ldSPC1;
    190     for (n = 0; (ld <= ldOK) && (line[n] != '\0'); ++n)
    191     {
    192 	int ch = UCH(line[n]);
    193 	switch (ld)
    194 	{
    195 	case ldSPC1:
    196 	    if (isspace(UCH(ch)))
    197 	    {
    198 		break;
    199 	    }
    200 	    else
    201 		UNLESS(ch != '#');
    202 	    ld = ldSPC2;
    203 	    break;
    204 	case ldSPC2:
    205 	    if (isspace(UCH(ch)))
    206 	    {
    207 		break;
    208 	    }
    209 	    /* FALLTHRU */
    210 	case ldNAME:
    211 	    UNLESS(strncmp(line + n, "line", 4));
    212 	    n += 4;
    213 	    if (line[n] == '\0')
    214 	    {
    215 		ld = ldOK;
    216 		break;
    217 	    }
    218 	    else
    219 		UNLESS(!isspace(UCH(line[n])));
    220 	    ld = ldSPC3;
    221 	    break;
    222 	case ldSPC3:
    223 	    if (isspace(UCH(ch)))
    224 	    {
    225 		break;
    226 	    }
    227 	    else
    228 		UNLESS(!isdigit(UCH(ch)));
    229 	    line_1st = n;
    230 	    ld = ldNUM;		/* this is needed, but cppcheck says no... */
    231 	    /* FALLTHRU */
    232 	case ldNUM:
    233 	    if (isdigit(UCH(ch)))
    234 	    {
    235 		break;
    236 	    }
    237 	    else
    238 		UNLESS(!isspace(UCH(ch)));
    239 	    ld = ldSPC4;
    240 	    break;
    241 	case ldSPC4:
    242 	    if (isspace(UCH(ch)))
    243 	    {
    244 		break;
    245 	    }
    246 	    else
    247 		UNLESS(ch != '"');
    248 	    UNLESS(line[n + 1] == '"');
    249 	    ld = ldFILE;
    250 	    name_1st = n;
    251 	    break;
    252 	case ldFILE:
    253 	    if (ch != '"')
    254 	    {
    255 		break;
    256 	    }
    257 	    ld = ldOK;
    258 	    name_end = n;
    259 	    /* FALLTHRU */
    260 	case ldERR:
    261 	case ldOK:
    262 	    break;
    263 	}
    264     }
    265 
    266     if (ld == ldOK)
    267     {
    268 	size_t need = (size_t)(name_end - name_1st);
    269 	if ((long)need > (long)input_file_name_len)
    270 	{
    271 	    input_file_name_len = ((need + 1) * 3) / 2;
    272 	    input_file_name = TREALLOC(char, input_file_name, input_file_name_len);
    273 	    NO_SPACE(input_file_name);
    274 	}
    275 	if ((long)need > 0)
    276 	{
    277 	    memcpy(input_file_name, line + name_1st + 1, need - 1);
    278 	    input_file_name[need - 1] = '\0';
    279 	}
    280 	else
    281 	{
    282 	    input_file_name[0] = '\0';
    283 	}
    284     }
    285 
    286     if (ld >= ldNUM && ld < ldERR)
    287     {
    288 	if (line_1st >= 0)
    289 	{
    290 	    lineno = (int)strtol(line + line_1st, NULL, 10) - 1;
    291 	}
    292 	else
    293 	{
    294 	    lineno = 0;
    295 	}
    296     }
    297 
    298     return (ld == ldOK);
    299 #undef UNLESS
    300 }
    301 
    302 static void
    303 save_line(void)
    304 {
    305     /* remember to save the input-line if we call get_line() */
    306     if (!must_save)
    307     {
    308 	must_save = 1;
    309 	save_area.line_used = (size_t)(cptr - line);
    310     }
    311 }
    312 
    313 static void
    314 restore_line(void)
    315 {
    316     /* if we saved the line, restore it */
    317     if (must_save < 0)
    318     {
    319 	free(line);
    320 	line = save_area.line_data;
    321 	cptr = save_area.line_used + line;
    322 	linesize = save_area.line_size;
    323 	if (fsetpos(input_file, &save_area.line_fpos) != 0)
    324 	    on_error();
    325 	memset(&save_area, 0, sizeof(save_area));
    326     }
    327     else if (must_save > 0)
    328     {
    329 	cptr = line + save_area.line_used;
    330     }
    331     must_save = 0;
    332 }
    333 
    334 static void
    335 get_line(void)
    336 {
    337     FILE *f = input_file;
    338 
    339     if (must_save > 0)
    340     {
    341 	save_area.line_data = TMALLOC(char, linesize);
    342 	save_area.line_used = (size_t)(cptr - line);
    343 	save_area.line_size = linesize;
    344 	NO_SPACE(save_area.line_data);
    345 	memcpy(save_area.line_data, line, linesize);
    346 	if (fgetpos(f, &save_area.line_fpos) != 0)
    347 	    on_error();
    348 	must_save = -must_save;
    349     }
    350 
    351     do
    352     {
    353 	int c;
    354 	size_t i;
    355 
    356 	if (saw_eof || (c = getc(f)) == EOF)
    357 	{
    358 	    if (line)
    359 	    {
    360 		FREE(line);
    361 		line = NULL;
    362 	    }
    363 	    cptr = NULL;
    364 	    saw_eof = 1;
    365 	    return;
    366 	}
    367 
    368 	if (line == NULL || linesize != (LINESIZE + 1))
    369 	{
    370 	    if (line)
    371 		FREE(line);
    372 	    linesize = LINESIZE + 1;
    373 	    line = TMALLOC(char, linesize);
    374 	    NO_SPACE(line);
    375 	}
    376 
    377 	i = 0;
    378 	++lineno;
    379 	for (;;)
    380 	{
    381 	    line[i++] = (char)c;
    382 	    if (c == '\n')
    383 		break;
    384 	    if ((i + 3) >= linesize)
    385 	    {
    386 		linesize += LINESIZE;
    387 		line = TREALLOC(char, line, linesize);
    388 		NO_SPACE(line);
    389 	    }
    390 	    c = getc(f);
    391 	    if (c == EOF)
    392 	    {
    393 		line[i++] = '\n';
    394 		saw_eof = 1;
    395 		break;
    396 	    }
    397 	}
    398 	line[i] = '\0';
    399     }
    400     while (line_directive());
    401     cptr = line;
    402     return;
    403 }
    404 
    405 static char *
    406 dup_line(void)
    407 {
    408     const char *s;
    409     char *p, *t;
    410 
    411     if (line == NULL)
    412 	return (NULL);
    413     s = line;
    414     while (*s != '\n')
    415 	++s;
    416     p = TMALLOC(char, s - line + 1);
    417     NO_SPACE(p);
    418 
    419     s = line;
    420     t = p;
    421     while ((*t++ = *s++) != '\n')
    422     {
    423 	;
    424     }
    425     return (p);
    426 }
    427 
    428 static void
    429 skip_comment(void)
    430 {
    431     char *s;
    432     struct ainfo a;
    433 
    434     begin_ainfo(a, 0);
    435 
    436     s = cptr + 2;
    437     for (;;)
    438     {
    439 	if (*s == '*' && s[1] == '/')
    440 	{
    441 	    cptr = s + 2;
    442 	    end_ainfo(a);
    443 	    return;
    444 	}
    445 	if (*s == '\n')
    446 	{
    447 	    get_line();
    448 	    if (line == NULL)
    449 		unterminated_comment(&a);
    450 	    s = cptr;
    451 	}
    452 	else
    453 	    ++s;
    454     }
    455 }
    456 
    457 static int
    458 next_inline(void)
    459 {
    460     char *s;
    461 
    462     if (line == NULL)
    463     {
    464 	get_line();
    465 	if (line == NULL)
    466 	    return (EOF);
    467     }
    468 
    469     s = cptr;
    470     for (;;)
    471     {
    472 	switch (*s)
    473 	{
    474 	case '/':
    475 	    if (s[1] == '*')
    476 	    {
    477 		cptr = s;
    478 		skip_comment();
    479 		s = cptr;
    480 		break;
    481 	    }
    482 	    else if (s[1] == '/')
    483 	    {
    484 		get_line();
    485 		if (line == NULL)
    486 		    return (EOF);
    487 		s = cptr;
    488 		break;
    489 	    }
    490 	    /* FALLTHRU */
    491 
    492 	default:
    493 	    cptr = s;
    494 	    return (*s);
    495 	}
    496     }
    497 }
    498 
    499 static int
    500 nextc(void)
    501 {
    502     int ch;
    503     int finish = 0;
    504 
    505     do
    506     {
    507 	switch (ch = next_inline())
    508 	{
    509 	case '\0':
    510 	case '\n':
    511 	    get_line();
    512 	    break;
    513 	case ' ':
    514 	case '\t':
    515 	case '\f':
    516 	case '\r':
    517 	case '\v':
    518 	case ',':
    519 	case ';':
    520 	    ++cptr;
    521 	    break;
    522 	case '\\':
    523 	    ch = '%';
    524 	    /* FALLTHRU */
    525 	default:
    526 	    finish = 1;
    527 	    break;
    528 	}
    529     }
    530     while (!finish);
    531 
    532     return ch;
    533 }
    534 /* *INDENT-OFF* */
    535 static struct keyword
    536 {
    537     char name[16];
    538     int token;
    539 }
    540 keywords[] = {
    541     { "binary",      NONASSOC },
    542     { "code",        XCODE },
    543     { "debug",       NONPOSIX_DEBUG },
    544     { "define",      HACK_DEFINE },
    545 #if defined(YYBTYACC)
    546     { "destructor",  DESTRUCTOR },
    547 #endif
    548     { "error-verbose",ERROR_VERBOSE },
    549     { "expect",      EXPECT },
    550     { "expect-rr",   EXPECT_RR },
    551     { "ident",       IDENT },
    552 #if defined(YYBTYACC)
    553     { "initial-action", INITIAL_ACTION },
    554 #endif
    555     { "left",        LEFT },
    556     { "lex-param",   LEX_PARAM },
    557 #if defined(YYBTYACC)
    558     { "locations",   LOCATIONS },
    559 #endif
    560     { "nonassoc",    NONASSOC },
    561     { "nterm",       TYPE },
    562     { "parse-param", PARSE_PARAM },
    563     { "pure-parser", PURE_PARSER },
    564     { "right",       RIGHT },
    565     { "start",       START },
    566     { "term",        TOKEN },
    567     { "token",       TOKEN },
    568     { "token-table", TOKEN_TABLE },
    569     { "type",        TYPE },
    570     { "union",       UNION },
    571     { "yacc",        POSIX_YACC },
    572 };
    573 /* *INDENT-ON* */
    574 
    575 static int
    576 compare_keys(const void *a, const void *b)
    577 {
    578     const struct keyword *p = (const struct keyword *)a;
    579     const struct keyword *q = (const struct keyword *)b;
    580     return strcmp(p->name, q->name);
    581 }
    582 
    583 static int
    584 keyword(void)
    585 {
    586     int c;
    587     const char *t_cptr = cptr;
    588 
    589     c = *++cptr;
    590     if (isalpha(UCH(c)))
    591     {
    592 	struct keyword *key;
    593 
    594 	cinc = 0;
    595 	for (;;)
    596 	{
    597 	    if (isalpha(UCH(c)))
    598 	    {
    599 		if (isupper(UCH(c)))
    600 		    c = tolower(c);
    601 		cachec(c);
    602 	    }
    603 	    else if (isdigit(UCH(c))
    604 		     || c == '-'
    605 		     || c == '.'
    606 		     || c == '$')
    607 	    {
    608 		cachec(c);
    609 	    }
    610 	    else if (c == '_')
    611 	    {
    612 		/* treat keywords spelled with '_' as if it were '-' */
    613 		cachec('-');
    614 	    }
    615 	    else
    616 	    {
    617 		break;
    618 	    }
    619 	    c = *++cptr;
    620 	}
    621 	cachec(NUL);
    622 
    623 	if ((key = bsearch(cache, keywords,
    624 			   sizeof(keywords) / sizeof(*key),
    625 			   sizeof(*key), compare_keys)))
    626 	    return key->token;
    627     }
    628     else
    629     {
    630 	++cptr;
    631 	if (c == L_CURL)
    632 	    return (TEXT);
    633 	if (c == '%' || c == '\\')
    634 	    return (MARK);
    635 	if (c == '<')
    636 	    return (LEFT);
    637 	if (c == '>')
    638 	    return (RIGHT);
    639 	if (c == '0')
    640 	    return (TOKEN);
    641 	if (c == '2')
    642 	    return (NONASSOC);
    643     }
    644     syntax_error(lineno, line, t_cptr);
    645     /*NOTREACHED */
    646 }
    647 
    648 
    649 static void
    650 copy_ident(void)
    651 {
    652     int c;
    653     FILE *f = output_file;
    654 
    655     c = nextc();
    656     if (c == EOF)
    657 	unexpected_EOF();
    658     if (c != '"')
    659 	syntax_error(lineno, line, cptr);
    660     ++outline;
    661     fprintf(f, "#ident \"");
    662     for (;;)
    663     {
    664 	c = *++cptr;
    665 	if (c == '\n')
    666 	{
    667 	    fprintf(f, "\"\n");
    668 	    return;
    669 	}
    670 	putc(c, f);
    671 	if (c == '"')
    672 	{
    673 	    putc('\n', f);
    674 	    ++cptr;
    675 	    return;
    676 	}
    677     }
    678 }
    679 
    680 static char *
    681 copy_string(int quote)
    682 {
    683     struct mstring *temp = msnew();
    684     struct ainfo a;
    685 
    686     begin_ainfo(a, 1);
    687 
    688     for (;;)
    689     {
    690 	int c = *cptr++;
    691 
    692 	mputc(temp, c);
    693 	if (c == quote)
    694 	{
    695 	    end_ainfo(a);
    696 	    return msdone(temp);
    697 	}
    698 	if (c == '\n')
    699 	    unterminated_string(&a);
    700 	if (c == '\\')
    701 	{
    702 	    c = *cptr++;
    703 	    mputc(temp, c);
    704 	    if (c == '\n')
    705 	    {
    706 		get_line();
    707 		if (line == NULL)
    708 		    unterminated_string(&a);
    709 	    }
    710 	}
    711     }
    712 }
    713 
    714 static char *
    715 copy_comment(void)
    716 {
    717     struct mstring *temp = msnew();
    718     int c;
    719 
    720     c = *cptr;
    721     if (c == '/')
    722     {
    723 	mputc(temp, '*');
    724 	while ((c = *++cptr) != '\n')
    725 	{
    726 	    mputc(temp, c);
    727 	    if (c == '*' && cptr[1] == '/')
    728 		mputc(temp, ' ');
    729 	}
    730 	mputc(temp, '*');
    731 	mputc(temp, '/');
    732     }
    733     else if (c == '*')
    734     {
    735 	struct ainfo a;
    736 
    737 	begin_ainfo(a, 1);
    738 
    739 	mputc(temp, c);
    740 	++cptr;
    741 	for (;;)
    742 	{
    743 	    c = *cptr++;
    744 	    mputc(temp, c);
    745 	    if (c == '*' && *cptr == '/')
    746 	    {
    747 		mputc(temp, '/');
    748 		++cptr;
    749 		end_ainfo(a);
    750 		return msdone(temp);
    751 	    }
    752 	    if (c == '\n')
    753 	    {
    754 		get_line();
    755 		if (line == NULL)
    756 		    unterminated_comment(&a);
    757 	    }
    758 	}
    759     }
    760     return msdone(temp);
    761 }
    762 
    763 static int
    764 check_key(int pos)
    765 {
    766     const char *key = code_keys[pos];
    767     while (*cptr && *key)
    768 	if (*key++ != *cptr++)
    769 	    return 0;
    770     if (*key || (!isspace(UCH(*cptr)) && *cptr != L_CURL))
    771 	return 0;
    772     cptr--;
    773     return 1;
    774 }
    775 
    776 static void
    777 copy_code(void)
    778 {
    779     int c;
    780     int curl;
    781     int cline;
    782     int on_line = 0;
    783     int pos = CODE_HEADER;
    784     struct mstring *code_mstr;
    785 
    786     /* read %code <keyword> { */
    787     for (;;)
    788     {
    789 	c = *++cptr;
    790 	if (c == EOF)
    791 	    unexpected_EOF();
    792 	if (c == '\0')
    793 	{
    794 	    get_line();
    795 	    if (line == NULL)
    796 	    {
    797 		unexpected_EOF();
    798 		/*NOTREACHED */
    799 	    }
    800 	    c = *cptr;
    801 	}
    802 	if (isspace(UCH(c)))
    803 	    continue;
    804 
    805 	if (c == L_CURL)
    806 	    break;
    807 
    808 	if (pos == CODE_HEADER)
    809 	{
    810 	    switch (UCH(c))
    811 	    {
    812 	    case 'r':
    813 		pos = CODE_REQUIRES;
    814 		break;
    815 	    case 'p':
    816 		pos = CODE_PROVIDES;
    817 		break;
    818 	    case 't':
    819 		pos = CODE_TOP;
    820 		break;
    821 	    case 'i':
    822 		pos = CODE_IMPORTS;
    823 		break;
    824 	    default:
    825 		break;
    826 	    }
    827 
    828 	    if (pos == -1 || !check_key(pos))
    829 	    {
    830 		syntax_error(lineno, line, cptr);
    831 		/*NOTREACHED */
    832 	    }
    833 	}
    834     }
    835 
    836     cptr++;			/* skip initial curl */
    837     while (*cptr && isspace(UCH(*cptr)))	/* skip space */
    838 	cptr++;
    839     curl = 1;			/* nesting count */
    840 
    841     /* gather text */
    842     code_lines[pos].name = code_keys[pos];
    843     if ((cline = (int)code_lines[pos].num) != 0)
    844     {
    845 	code_mstr = msrenew(code_lines[pos].lines);
    846     }
    847     else
    848     {
    849 	code_mstr = msnew();
    850     }
    851     cline++;
    852     if (!lflag)
    853 	msprintf(code_mstr, line_format, lineno, input_file_name);
    854     for (;;)
    855     {
    856 	c = *cptr++;
    857 	switch (c)
    858 	{
    859 	case '\0':
    860 	    get_line();
    861 	    if (line == NULL)
    862 	    {
    863 		unexpected_EOF();
    864 		/*NOTREACHED */
    865 	    }
    866 	    continue;
    867 	case '\n':
    868 	    cline++;
    869 	    on_line = 0;
    870 	    break;
    871 	case L_CURL:
    872 	    curl++;
    873 	    break;
    874 	case R_CURL:
    875 	    if (--curl == 0)
    876 	    {
    877 		if (on_line > 1)
    878 		{
    879 		    mputc(code_mstr, '\n');
    880 		    cline++;
    881 		}
    882 		code_lines[pos].lines = msdone(code_mstr);
    883 		code_lines[pos].num = (size_t)cline;
    884 		return;
    885 	    }
    886 	    break;
    887 	default:
    888 	    break;
    889 	}
    890 	mputc(code_mstr, c);
    891 	on_line++;
    892     }
    893 }
    894 
    895 static void
    896 copy_text(void)
    897 {
    898     int c;
    899     FILE *f = text_file;
    900     int need_newline = 0;
    901     struct ainfo a;
    902 
    903     begin_ainfo(a, 2);
    904 
    905     if (*cptr == '\n')
    906     {
    907 	get_line();
    908 	if (line == NULL)
    909 	    unterminated_text(&a);
    910     }
    911     fprintf_lineno(f, lineno, input_file_name);
    912 
    913   loop:
    914     c = *cptr++;
    915     switch (c)
    916     {
    917     case '\n':
    918 	putc('\n', f);
    919 	need_newline = 0;
    920 	get_line();
    921 	if (line)
    922 	    goto loop;
    923 	unterminated_text(&a);
    924 
    925     case '\'':
    926     case '"':
    927 	putc(c, f);
    928 	{
    929 	    char *s = copy_string(c);
    930 	    fputs(s, f);
    931 	    free(s);
    932 	}
    933 	need_newline = 1;
    934 	goto loop;
    935 
    936     case '/':
    937 	putc(c, f);
    938 	{
    939 	    char *s = copy_comment();
    940 	    puts_trim(s, f);
    941 	    free(s);
    942 	}
    943 	need_newline = 1;
    944 	goto loop;
    945 
    946     case '%':
    947     case '\\':
    948 	if (*cptr == R_CURL)
    949 	{
    950 	    if (need_newline)
    951 		putc('\n', f);
    952 	    ++cptr;
    953 	    end_ainfo(a);
    954 	    return;
    955 	}
    956 	/* FALLTHRU */
    957 
    958     default:
    959 	putc(c, f);
    960 	need_newline = 1;
    961 	goto loop;
    962     }
    963 }
    964 
    965 static void
    966 puts_both(const char *s)
    967 {
    968     if (s && *s)
    969     {
    970 	puts_trim(s, text_file);
    971 	if (dflag)
    972 	    puts_trim(s, union_file);
    973     }
    974 }
    975 
    976 static void
    977 putc_both(int c)
    978 {
    979     putc(c, text_file);
    980     if (dflag)
    981 	putc(c, union_file);
    982 }
    983 
    984 static void
    985 copy_union(void)
    986 {
    987     int c;
    988     int depth;
    989     struct ainfo a;
    990     char prefix_buf[NAME_LEN + 1];
    991     size_t prefix_len = 0;
    992     char filler_buf[NAME_LEN + 1];
    993     size_t filler_len = 0;
    994     int in_prefix = 1;
    995 
    996     prefix_buf[0] = '\0';
    997     filler_buf[0] = '\0';
    998 
    999     begin_ainfo(a, 6);
   1000 
   1001     if (unionized)
   1002 	over_unionized(cptr - 6);
   1003     unionized = 1;
   1004 
   1005     puts_both("#ifdef YYSTYPE\n");
   1006     puts_both("#undef  YYSTYPE_IS_DECLARED\n");
   1007     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
   1008     puts_both("#endif\n");
   1009     puts_both("#ifndef YYSTYPE_IS_DECLARED\n");
   1010     puts_both("#define YYSTYPE_IS_DECLARED 1\n");
   1011 
   1012     fprintf_lineno(text_file, lineno, input_file_name);
   1013 
   1014     depth = 0;
   1015   loop:
   1016     c = *cptr++;
   1017     if (in_prefix)
   1018     {
   1019 	if (c == L_CURL)
   1020 	{
   1021 	    in_prefix = 0;
   1022 	    if (prefix_len)
   1023 	    {
   1024 		puts_both("union ");
   1025 		puts_both(prefix_buf);
   1026 		puts_both(filler_buf);
   1027 	    }
   1028 	    else
   1029 	    {
   1030 		puts_both("typedef union YYSTYPE");
   1031 		puts_both(filler_buf);
   1032 	    }
   1033 	}
   1034 	else if (isspace(c))
   1035 	{
   1036 	    if (filler_len >= sizeof(filler_buf) - 1)
   1037 	    {
   1038 		puts_both(filler_buf);
   1039 		filler_len = 0;
   1040 	    }
   1041 	    filler_buf[filler_len++] = (char)c;
   1042 	    filler_buf[filler_len] = 0;
   1043 	    if (c != '\n')
   1044 		goto loop;
   1045 	}
   1046 	else if (IS_IDENT(c))
   1047 	{
   1048 	    if (prefix_len < NAME_LEN)
   1049 	    {
   1050 		prefix_buf[prefix_len++] = (char)c;
   1051 		prefix_buf[prefix_len] = 0;
   1052 	    }
   1053 	    goto loop;
   1054 	}
   1055     }
   1056     if (c != '\n' || !in_prefix)
   1057 	putc_both(c);
   1058     switch (c)
   1059     {
   1060     case '\n':
   1061 	get_line();
   1062 	if (line == NULL)
   1063 	    unterminated_union(&a);
   1064 	goto loop;
   1065 
   1066     case L_CURL:
   1067 	++depth;
   1068 	goto loop;
   1069 
   1070     case R_CURL:
   1071 	if (--depth == 0)
   1072 	{
   1073 	    puts_both(prefix_len ? "; " : " YYSTYPE;\n");
   1074 	    if (prefix_len)
   1075 	    {
   1076 		puts_both("typedef union ");
   1077 		puts_both(prefix_buf);
   1078 		puts_both(" YYSTYPE;\n");
   1079 	    }
   1080 	    puts_both("#endif /* !YYSTYPE_IS_DECLARED */\n");
   1081 	    end_ainfo(a);
   1082 	    return;
   1083 	}
   1084 	goto loop;
   1085 
   1086     case '\'':
   1087     case '"':
   1088 	{
   1089 	    char *s = copy_string(c);
   1090 	    puts_both(s);
   1091 	    free(s);
   1092 	}
   1093 	goto loop;
   1094 
   1095     case '/':
   1096 	{
   1097 	    char *s = copy_comment();
   1098 	    puts_both(s);
   1099 	    free(s);
   1100 	}
   1101 	goto loop;
   1102 
   1103     default:
   1104 	goto loop;
   1105     }
   1106 }
   1107 
   1108 static char *
   1109 after_blanks(char *s)
   1110 {
   1111     while (*s != '\0' && isspace(UCH(*s)))
   1112 	++s;
   1113     return s;
   1114 }
   1115 
   1116 /*
   1117  * Trim leading/trailing blanks, and collapse multiple embedded blanks to a
   1118  * single space.  Return index to last character in the buffer.
   1119  */
   1120 static int
   1121 trim_blanks(char *buffer)
   1122 {
   1123     if (*buffer != '\0')
   1124     {
   1125 	char *d = buffer;
   1126 	char *s = after_blanks(d);
   1127 
   1128 	while ((*d++ = *s++) != '\0')
   1129 	{
   1130 	    ;
   1131 	}
   1132 
   1133 	--d;
   1134 	while ((--d != buffer) && isspace(UCH(*d)))
   1135 	    *d = '\0';
   1136 
   1137 	for (s = d = buffer; (*d++ = *s++) != '\0';)
   1138 	{
   1139 	    if (isspace(UCH(*s)))
   1140 	    {
   1141 		*s = ' ';
   1142 		while (isspace(UCH(*s)))
   1143 		{
   1144 		    *s++ = ' ';
   1145 		}
   1146 		--s;
   1147 	    }
   1148 	}
   1149     }
   1150 
   1151     return (int)strlen(buffer) - 1;
   1152 }
   1153 
   1154 /*
   1155  * Scan forward in the current line-buffer looking for a right-curly bracket.
   1156  *
   1157  * Parameters begin with a left-curly bracket, and continue until there are no
   1158  * more interesting characters after the last right-curly bracket on the
   1159  * current line.  Bison documents parameters as separated like this:
   1160  *	{type param1} {type2 param2}
   1161  * but also accepts commas (although some versions of bison mishandle this)
   1162  *	{type param1,  type2 param2}
   1163  */
   1164 static int
   1165 more_curly(void)
   1166 {
   1167     int result = 0;
   1168     int finish = 0;
   1169     save_line();
   1170     do
   1171     {
   1172 	switch (next_inline())
   1173 	{
   1174 	case 0:
   1175 	case '\n':
   1176 	    finish = 1;
   1177 	    break;
   1178 	case R_CURL:
   1179 	    finish = 1;
   1180 	    result = 1;
   1181 	    break;
   1182 	}
   1183 	++cptr;
   1184     }
   1185     while (!finish);
   1186     restore_line();
   1187     return result;
   1188 }
   1189 
   1190 static void
   1191 save_param(int k, char *buffer, int name, int type2)
   1192 {
   1193     param *head, *p;
   1194 
   1195     p = TMALLOC(param, 1);
   1196     NO_SPACE(p);
   1197 
   1198     p->type2 = strdup(buffer + type2);
   1199     NO_SPACE(p->type2);
   1200     buffer[type2] = '\0';
   1201     (void)trim_blanks(p->type2);
   1202 
   1203     if (!IS_ALNUM(UCH(buffer[name])))
   1204     {
   1205 	int n;
   1206 	for (n = name - 1; n >= 0; --n)
   1207 	{
   1208 	    if (!isspace(UCH(buffer[n])))
   1209 	    {
   1210 		break;
   1211 	    }
   1212 	}
   1213 	while (n > 0)
   1214 	{
   1215 	    if (!IS_ALNUM(buffer[n - 1]))
   1216 		break;
   1217 	    --n;
   1218 	}
   1219 	name = n;
   1220     }
   1221     p->name = strdup(buffer + name);
   1222     NO_SPACE(p->name);
   1223     buffer[name] = '\0';
   1224     (void)trim_blanks(p->name);
   1225 
   1226     p->type = strdup(buffer);
   1227     NO_SPACE(p->type);
   1228     (void)trim_blanks(p->type);
   1229 
   1230     if (k == LEX_PARAM)
   1231 	head = lex_param;
   1232     else
   1233 	head = parse_param;
   1234 
   1235     if (head != NULL)
   1236     {
   1237 	while (head->next)
   1238 	    head = head->next;
   1239 	head->next = p;
   1240     }
   1241     else
   1242     {
   1243 	if (k == LEX_PARAM)
   1244 	    lex_param = p;
   1245 	else
   1246 	    parse_param = p;
   1247     }
   1248     p->next = NULL;
   1249 }
   1250 
   1251 /*
   1252  * Keep a linked list of parameters.  This may be multi-line, if the trailing
   1253  * right-curly bracket is absent.
   1254  */
   1255 static void
   1256 copy_param(int k)
   1257 {
   1258     int c;
   1259     int name, type2;
   1260     int curly = 0;
   1261     char *buf = NULL;
   1262     int i = -1;
   1263     size_t buf_size = 0;
   1264     int st_lineno = lineno;
   1265     char *comma;
   1266 
   1267     do
   1268     {
   1269 	int state = curly;
   1270 	c = next_inline();
   1271 	switch (c)
   1272 	{
   1273 	case EOF:
   1274 	    unexpected_EOF();
   1275 	    break;
   1276 	case L_CURL:
   1277 	    if (curly == 1)
   1278 	    {
   1279 		goto oops;
   1280 	    }
   1281 	    curly = 1;
   1282 	    st_lineno = lineno;
   1283 	    break;
   1284 	case R_CURL:
   1285 	    if (curly != 1)
   1286 	    {
   1287 		goto oops;
   1288 	    }
   1289 	    curly = 2;
   1290 	    break;
   1291 	case '\n':
   1292 	    if (curly == 0)
   1293 	    {
   1294 		goto oops;
   1295 	    }
   1296 	    break;
   1297 	case '%':
   1298 	    if ((curly == 1) && (cptr == line))
   1299 	    {
   1300 		lineno = st_lineno;
   1301 		missing_brace();
   1302 	    }
   1303 	    /* FALLTHRU */
   1304 	case '"':
   1305 	case '\'':
   1306 	    goto oops;
   1307 	default:
   1308 	    if (curly == 0 && !isspace(UCH(c)))
   1309 	    {
   1310 		goto oops;
   1311 	    }
   1312 	    break;
   1313 	}
   1314 	if (buf == NULL)
   1315 	{
   1316 	    buf_size = (size_t)linesize;
   1317 	    buf = TMALLOC(char, buf_size);
   1318 	    NO_SPACE(buf);
   1319 	}
   1320 	else if (c == '\n')
   1321 	{
   1322 	    char *tmp;
   1323 
   1324 	    get_line();
   1325 	    if (line == NULL)
   1326 		unexpected_EOF();
   1327 	    --cptr;
   1328 	    buf_size += (size_t)linesize;
   1329 	    tmp = TREALLOC(char, buf, buf_size);
   1330 	    NO_SPACE(tmp);
   1331 	    buf = tmp;
   1332 	}
   1333 	if (curly)
   1334 	{
   1335 	    if ((state == 2) && (c == L_CURL))
   1336 	    {
   1337 		buf[++i] = ',';
   1338 	    }
   1339 	    else if ((state == 2) && isspace(UCH(c)))
   1340 	    {
   1341 		;
   1342 	    }
   1343 	    else if ((c != L_CURL) && (c != R_CURL))
   1344 	    {
   1345 		buf[++i] = (char)c;
   1346 	    }
   1347 	}
   1348 	cptr++;
   1349     }
   1350     while (curly < 2 || more_curly());
   1351 
   1352     if (i == 0)
   1353     {
   1354 	if (curly == 1)
   1355 	{
   1356 	    lineno = st_lineno;
   1357 	    missing_brace();
   1358 	}
   1359 	goto oops;
   1360     }
   1361 
   1362     buf[++i] = '\0';
   1363     (void)trim_blanks(buf);
   1364 
   1365     comma = buf - 1;
   1366     do
   1367     {
   1368 	char *parms = (comma + 1);
   1369 	comma = strchr(parms, ',');
   1370 	if (comma != NULL)
   1371 	    *comma = '\0';
   1372 
   1373 	(void)trim_blanks(parms);
   1374 	i = (int)strlen(parms) - 1;
   1375 	if (i < 0)
   1376 	{
   1377 	    goto oops;
   1378 	}
   1379 
   1380 	if (parms[i] == ']')
   1381 	{
   1382 	    int level = 1;
   1383 	    while (i >= 0)
   1384 	    {
   1385 		char ch = parms[i--];
   1386 		if (ch == ']')
   1387 		{
   1388 		    ++level;
   1389 		}
   1390 		else if (ch == '[')
   1391 		{
   1392 		    if (--level <= 1)
   1393 		    {
   1394 			++i;
   1395 			break;
   1396 		    }
   1397 		}
   1398 	    }
   1399 	    if (i <= 0)
   1400 		unexpected_EOF();
   1401 	    type2 = i--;
   1402 	}
   1403 	else
   1404 	{
   1405 	    type2 = i + 1;
   1406 	}
   1407 
   1408 	while (i > 0 && IS_ALNUM(parms[i]))
   1409 	    i--;
   1410 
   1411 	if (!isspace(UCH(parms[i])) && parms[i] != '*')
   1412 	    goto oops;
   1413 
   1414 	name = i + 1;
   1415 
   1416 	save_param(k, parms, name, type2);
   1417     }
   1418     while (comma != NULL);
   1419     FREE(buf);
   1420     return;
   1421 
   1422   oops:
   1423     FREE(buf);
   1424     syntax_error(lineno, line, cptr);
   1425 }
   1426 
   1427 static int
   1428 hexval(int c)
   1429 {
   1430     if (c >= '0' && c <= '9')
   1431 	return (c - '0');
   1432     if (c >= 'A' && c <= 'F')
   1433 	return (c - 'A' + 10);
   1434     if (c >= 'a' && c <= 'f')
   1435 	return (c - 'a' + 10);
   1436     return (-1);
   1437 }
   1438 
   1439 static bucket *
   1440 get_literal(void)
   1441 {
   1442     int c, quote;
   1443     int i;
   1444     int n;
   1445     char *s;
   1446     bucket *bp;
   1447     struct ainfo a;
   1448 
   1449     begin_ainfo(a, 0);
   1450 
   1451     quote = *cptr++;
   1452     cinc = 0;
   1453     for (;;)
   1454     {
   1455 	c = *cptr++;
   1456 	if (c == quote)
   1457 	    break;
   1458 	if (c == '\n')
   1459 	    unterminated_string(&a);
   1460 	if (c == '\\')
   1461 	{
   1462 	    const char *c_cptr = cptr - 1;
   1463 
   1464 	    c = *cptr++;
   1465 	    switch (c)
   1466 	    {
   1467 	    case '\n':
   1468 		get_line();
   1469 		if (line == NULL)
   1470 		    unterminated_string(&a);
   1471 		continue;
   1472 
   1473 	    case '0':
   1474 	    case '1':
   1475 	    case '2':
   1476 	    case '3':
   1477 	    case '4':
   1478 	    case '5':
   1479 	    case '6':
   1480 	    case '7':
   1481 		n = c - '0';
   1482 		c = *cptr;
   1483 		if (IS_OCTAL(c))
   1484 		{
   1485 		    n = (n << 3) + (c - '0');
   1486 		    c = *++cptr;
   1487 		    if (IS_OCTAL(c))
   1488 		    {
   1489 			n = (n << 3) + (c - '0');
   1490 			++cptr;
   1491 		    }
   1492 		}
   1493 		if (n > MAXCHAR)
   1494 		    illegal_character(c_cptr);
   1495 		c = n;
   1496 		break;
   1497 
   1498 	    case 'x':
   1499 		c = *cptr++;
   1500 		n = hexval(c);
   1501 		if (n < 0 || n >= 16)
   1502 		    illegal_character(c_cptr);
   1503 		for (;;)
   1504 		{
   1505 		    c = *cptr;
   1506 		    i = hexval(c);
   1507 		    if (i < 0 || i >= 16)
   1508 			break;
   1509 		    ++cptr;
   1510 		    n = (n << 4) + i;
   1511 		    if (n > MAXCHAR)
   1512 			illegal_character(c_cptr);
   1513 		}
   1514 		c = n;
   1515 		break;
   1516 
   1517 	    case 'a':
   1518 		c = 7;
   1519 		break;
   1520 	    case 'b':
   1521 		c = '\b';
   1522 		break;
   1523 	    case 'f':
   1524 		c = '\f';
   1525 		break;
   1526 	    case 'n':
   1527 		c = '\n';
   1528 		break;
   1529 	    case 'r':
   1530 		c = '\r';
   1531 		break;
   1532 	    case 't':
   1533 		c = '\t';
   1534 		break;
   1535 	    case 'v':
   1536 		c = '\v';
   1537 		break;
   1538 	    }
   1539 	}
   1540 	cachec(c);
   1541     }
   1542     end_ainfo(a);
   1543 
   1544     n = cinc ? cinc : 1;
   1545     s = TMALLOC(char, n);
   1546     NO_SPACE(s);
   1547 
   1548     for (i = 0; i < n; ++i)
   1549 	s[i] = cache[i];
   1550 
   1551     cinc = 0;
   1552     if (n == 1)
   1553 	cachec('\'');
   1554     else
   1555 	cachec('"');
   1556 
   1557     for (i = 0; i < n; ++i)
   1558     {
   1559 	c = UCH(s[i]);
   1560 	if (c == '\\' || c == cache[0])
   1561 	{
   1562 	    cachec('\\');
   1563 	    cachec(c);
   1564 	}
   1565 	else if (isprint(UCH(c)))
   1566 	    cachec(c);
   1567 	else
   1568 	{
   1569 	    cachec('\\');
   1570 	    switch (c)
   1571 	    {
   1572 	    case 7:
   1573 		cachec('a');
   1574 		break;
   1575 	    case '\b':
   1576 		cachec('b');
   1577 		break;
   1578 	    case '\f':
   1579 		cachec('f');
   1580 		break;
   1581 	    case '\n':
   1582 		cachec('n');
   1583 		break;
   1584 	    case '\r':
   1585 		cachec('r');
   1586 		break;
   1587 	    case '\t':
   1588 		cachec('t');
   1589 		break;
   1590 	    case '\v':
   1591 		cachec('v');
   1592 		break;
   1593 	    default:
   1594 		cachec(((c >> 6) & 7) + '0');
   1595 		cachec(((c >> 3) & 7) + '0');
   1596 		cachec((c & 7) + '0');
   1597 		break;
   1598 	    }
   1599 	}
   1600     }
   1601 
   1602     if (n == 1)
   1603 	cachec('\'');
   1604     else
   1605 	cachec('"');
   1606 
   1607     cachec(NUL);
   1608     bp = lookup(cache);
   1609     bp->class = TERM;
   1610     if (n == 1 && bp->value == UNDEFINED)
   1611 	bp->value = UCH(*s);
   1612     FREE(s);
   1613 
   1614     return (bp);
   1615 }
   1616 
   1617 static int
   1618 is_reserved(char *name)
   1619 {
   1620     if (strcmp(name, ".") == 0 ||
   1621 	strcmp(name, "$accept") == 0 ||
   1622 	strcmp(name, "$end") == 0)
   1623 	return (1);
   1624 
   1625     if (name[0] == '$' && name[1] == '$' && isdigit(UCH(name[2])))
   1626     {
   1627 	const char *s = name + 3;
   1628 
   1629 	while (isdigit(UCH(*s)))
   1630 	    ++s;
   1631 	if (*s == NUL)
   1632 	    return (1);
   1633     }
   1634 
   1635     return (0);
   1636 }
   1637 
   1638 static bucket *
   1639 get_name(void)
   1640 {
   1641     int c;
   1642 
   1643     cinc = 0;
   1644     for (c = *cptr; IS_IDENT(c); c = *++cptr)
   1645 	cachec(c);
   1646     cachec(NUL);
   1647 
   1648     if (is_reserved(cache))
   1649 	used_reserved(cache);
   1650 
   1651     return (lookup(cache));
   1652 }
   1653 
   1654 static Value_t
   1655 get_number(void)
   1656 {
   1657     int c;
   1658     long n;
   1659     const char *base = cptr;
   1660 
   1661     n = 0;
   1662     for (c = *cptr; isdigit(UCH(c)); c = *++cptr)
   1663     {
   1664 	n = (10 * n + (c - '0'));
   1665 	if (n > MAXYYINT)
   1666 	{
   1667 	    syntax_error(lineno, line, base);
   1668 	    /*NOTREACHED */
   1669 	}
   1670     }
   1671 
   1672     return (Value_t)(n);
   1673 }
   1674 
   1675 static char *
   1676 cache_tag(const char *tag, size_t len)
   1677 {
   1678     int i;
   1679     char *s;
   1680 
   1681     for (i = 0; i < ntags; ++i)
   1682     {
   1683 	if (strncmp(tag, tag_table[i], len) == 0 &&
   1684 	    tag_table[i][len] == NUL)
   1685 	    return (tag_table[i]);
   1686     }
   1687 
   1688     if (ntags >= tagmax)
   1689     {
   1690 	tagmax += 16;
   1691 	tag_table =
   1692 	    (tag_table
   1693 	     ? TREALLOC(char *, tag_table, tagmax)
   1694 	     : TMALLOC(char *, tagmax));
   1695 	NO_SPACE(tag_table);
   1696     }
   1697 
   1698     s = TMALLOC(char, len + 1);
   1699     NO_SPACE(s);
   1700 
   1701     strncpy(s, tag, len);
   1702     s[len] = 0;
   1703     tag_table[ntags++] = s;
   1704     return s;
   1705 }
   1706 
   1707 static char *
   1708 get_tag(void)
   1709 {
   1710     int c;
   1711     int t_lineno = lineno;
   1712     char *t_line = dup_line();
   1713     const char *t_cptr = t_line + (cptr - line);
   1714 
   1715     ++cptr;
   1716     c = nextc();
   1717     if (c == EOF)
   1718 	unexpected_EOF();
   1719     if (!IS_NAME1(c))
   1720 	illegal_tag(t_lineno, t_line, t_cptr);
   1721 
   1722     cinc = 0;
   1723     do
   1724     {
   1725 	cachec(c);
   1726 	c = *++cptr;
   1727     }
   1728     while (IS_IDENT(c));
   1729     cachec(NUL);
   1730 
   1731     c = nextc();
   1732     if (c == EOF)
   1733 	unexpected_EOF();
   1734     if (c != '>')
   1735 	illegal_tag(t_lineno, t_line, t_cptr);
   1736     ++cptr;
   1737 
   1738     FREE(t_line);
   1739     havetags = 1;
   1740     return cache_tag(cache, (size_t)cinc);
   1741 }
   1742 
   1743 #if defined(YYBTYACC)
   1744 static char *
   1745 scan_id(void)
   1746 {
   1747     const char *b = cptr;
   1748 
   1749     while (IS_NAME2(*cptr))
   1750 	cptr++;
   1751     return cache_tag(b, (size_t)(cptr - b));
   1752 }
   1753 #endif
   1754 
   1755 static void
   1756 declare_tokens(int assoc)
   1757 {
   1758     int c;
   1759     bucket *bp;
   1760     Value_t value;
   1761     char *tag = NULL;
   1762 
   1763     if (assoc != TOKEN)
   1764 	++prec;
   1765 
   1766     c = nextc();
   1767     if (c == EOF)
   1768 	unexpected_EOF();
   1769     if (c == '<')
   1770     {
   1771 	tag = get_tag();
   1772 	c = nextc();
   1773 	if (c == EOF)
   1774 	    unexpected_EOF();
   1775     }
   1776 
   1777     for (;;)
   1778     {
   1779 	if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
   1780 	    bp = get_name();
   1781 	else if (c == '\'' || c == '"')
   1782 	    bp = get_literal();
   1783 	else
   1784 	    return;
   1785 
   1786 	if (bp == goal)
   1787 	    tokenized_start(bp->name);
   1788 	bp->class = TERM;
   1789 
   1790 	if (tag)
   1791 	{
   1792 	    if (bp->tag && tag != bp->tag)
   1793 		retyped_warning(bp->name);
   1794 	    bp->tag = tag;
   1795 	}
   1796 
   1797 	if (assoc != TOKEN)
   1798 	{
   1799 	    if (bp->prec && prec != bp->prec)
   1800 		reprec_warning(bp->name);
   1801 	    bp->assoc = (Assoc_t)assoc;
   1802 	    bp->prec = prec;
   1803 	}
   1804 
   1805 	c = nextc();
   1806 	if (c == EOF)
   1807 	    unexpected_EOF();
   1808 
   1809 	if (isdigit(UCH(c)))
   1810 	{
   1811 	    value = get_number();
   1812 	    if (bp->value != UNDEFINED && value != bp->value)
   1813 		revalued_warning(bp->name);
   1814 	    bp->value = value;
   1815 	    c = nextc();
   1816 	    if (c == EOF)
   1817 		unexpected_EOF();
   1818 	}
   1819     }
   1820 }
   1821 
   1822 /*
   1823  * %expect requires special handling
   1824  * as it really isn't part of the yacc
   1825  * grammar only a flag for yacc proper.
   1826  */
   1827 static void
   1828 declare_expect(int assoc)
   1829 {
   1830     int c;
   1831 
   1832     if (assoc != EXPECT && assoc != EXPECT_RR)
   1833 	++prec;
   1834 
   1835     /*
   1836      * Stay away from nextc - doesn't
   1837      * detect EOL and will read to EOF.
   1838      */
   1839     c = *++cptr;
   1840     if (c == EOF)
   1841 	unexpected_EOF();
   1842 
   1843     for (;;)
   1844     {
   1845 	if (isdigit(UCH(c)))
   1846 	{
   1847 	    if (assoc == EXPECT)
   1848 		SRexpect = get_number();
   1849 	    else
   1850 		RRexpect = get_number();
   1851 	    break;
   1852 	}
   1853 	/*
   1854 	 * Looking for number before EOL.
   1855 	 * Spaces, tabs, and numbers are ok,
   1856 	 * words, punc., etc. are syntax errors.
   1857 	 */
   1858 	else if (c == '\n' || isalpha(UCH(c)) || !isspace(UCH(c)))
   1859 	{
   1860 	    syntax_error(lineno, line, cptr);
   1861 	}
   1862 	else
   1863 	{
   1864 	    c = *++cptr;
   1865 	    if (c == EOF)
   1866 		unexpected_EOF();
   1867 	}
   1868     }
   1869 }
   1870 
   1871 #if defined(YYBTYACC)
   1872 static void
   1873 declare_argtypes(bucket *bp)
   1874 {
   1875     char *tags[MAXARGS];
   1876     int args = 0;
   1877 
   1878     if (bp->args >= 0)
   1879 	retyped_warning(bp->name);
   1880     cptr++;			/* skip open paren */
   1881     for (;;)
   1882     {
   1883 	int c = nextc();
   1884 	if (c == EOF)
   1885 	    unexpected_EOF();
   1886 	if (c != '<')
   1887 	    syntax_error(lineno, line, cptr);
   1888 	tags[args++] = get_tag();
   1889 	c = nextc();
   1890 	if (c == R_PAREN)
   1891 	    break;
   1892 	if (c == EOF)
   1893 	    unexpected_EOF();
   1894     }
   1895     cptr++;			/* skip close paren */
   1896     bp->args = args;
   1897     bp->argnames = TMALLOC(char *, args);
   1898     NO_SPACE(bp->argnames);
   1899     bp->argtags = CALLOC(sizeof(char *), args + 1);
   1900     NO_SPACE(bp->argtags);
   1901     while (--args >= 0)
   1902     {
   1903 	bp->argtags[args] = tags[args];
   1904 	bp->argnames[args] = NULL;
   1905     }
   1906 }
   1907 #endif
   1908 
   1909 static int
   1910 scan_blanks(void)
   1911 {
   1912     int c;
   1913 
   1914     do
   1915     {
   1916 	c = next_inline();
   1917 	if (c == '\n')
   1918 	{
   1919 	    ++cptr;
   1920 	    return 0;
   1921 	}
   1922 	else if (c == ' ' || c == '\t')
   1923 	    ++cptr;
   1924 	else
   1925 	    break;
   1926     }
   1927     while (c == ' ' || c == '\t');
   1928 
   1929     return 1;
   1930 }
   1931 
   1932 static int
   1933 scan_ident(void)
   1934 {
   1935     int c;
   1936 
   1937     cinc = 0;
   1938     for (c = *cptr; IS_IDENT(c); c = *++cptr)
   1939 	cachec(c);
   1940     cachec(NUL);
   1941 
   1942     return cinc;
   1943 }
   1944 
   1945 static void
   1946 hack_defines(void)
   1947 {
   1948     struct ainfo a;
   1949 
   1950     if (!scan_blanks())
   1951 	return;
   1952 
   1953     begin_ainfo(a, 0);
   1954     if (!scan_ident())
   1955     {
   1956 	end_ainfo(a);
   1957     }
   1958 
   1959     if (!strcmp(cache, "api.pure"))
   1960     {
   1961 	end_ainfo(a);
   1962 	scan_blanks();
   1963 	begin_ainfo(a, 0);
   1964 	scan_ident();
   1965 
   1966 	if (!strcmp(cache, "false"))
   1967 	    pure_parser = 0;
   1968 	else if (!strcmp(cache, "true")
   1969 		 || !strcmp(cache, "full")
   1970 		 || *cache == 0)
   1971 	    pure_parser = 1;
   1972 	else
   1973 	    unexpected_value(&a);
   1974 	end_ainfo(a);
   1975     }
   1976     else
   1977     {
   1978 	unexpected_value(&a);
   1979     }
   1980 
   1981     while (next_inline() != '\n')
   1982 	++cptr;
   1983 }
   1984 
   1985 static void
   1986 declare_types(void)
   1987 {
   1988     int c;
   1989     bucket *bp = NULL;
   1990     char *tag = NULL;
   1991 
   1992     c = nextc();
   1993     if (c == EOF)
   1994 	unexpected_EOF();
   1995     if (c == '<')
   1996 	tag = get_tag();
   1997 
   1998     for (;;)
   1999     {
   2000 	c = nextc();
   2001 	if (c == EOF)
   2002 	    unexpected_EOF();
   2003 	if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
   2004 	{
   2005 	    bp = get_name();
   2006 #if defined(YYBTYACC)
   2007 	    if (nextc() == L_PAREN)
   2008 		declare_argtypes(bp);
   2009 	    else
   2010 		bp->args = 0;
   2011 #endif
   2012 	}
   2013 	else if (c == '\'' || c == '"')
   2014 	{
   2015 	    bp = get_literal();
   2016 #if defined(YYBTYACC)
   2017 	    bp->args = 0;
   2018 #endif
   2019 	}
   2020 	else
   2021 	    return;
   2022 
   2023 	if (tag)
   2024 	{
   2025 	    if (bp->tag && tag != bp->tag)
   2026 		retyped_warning(bp->name);
   2027 	    bp->tag = tag;
   2028 	}
   2029     }
   2030 }
   2031 
   2032 static void
   2033 declare_start(void)
   2034 {
   2035     int c;
   2036     bucket *bp;
   2037 
   2038     c = nextc();
   2039     if (c == EOF)
   2040 	unexpected_EOF();
   2041     if (!isalpha(UCH(c)) && c != '_' && c != '.' && c != '$')
   2042 	syntax_error(lineno, line, cptr);
   2043     bp = get_name();
   2044     if (bp->class == TERM)
   2045 	terminal_start(bp->name);
   2046     if (goal && goal != bp)
   2047 	restarted_warning();
   2048     goal = bp;
   2049 }
   2050 
   2051 static void
   2052 read_declarations(void)
   2053 {
   2054     cache_size = CACHE_SIZE;
   2055     cache = TMALLOC(char, cache_size);
   2056     NO_SPACE(cache);
   2057 
   2058     for (;;)
   2059     {
   2060 	int k;
   2061 	int c = nextc();
   2062 
   2063 	if (c == EOF)
   2064 	    unexpected_EOF();
   2065 	if (c != '%')
   2066 	    syntax_error(lineno, line, cptr);
   2067 	switch (k = keyword())
   2068 	{
   2069 	case MARK:
   2070 	    return;
   2071 
   2072 	case IDENT:
   2073 	    copy_ident();
   2074 	    break;
   2075 
   2076 	case XCODE:
   2077 	    copy_code();
   2078 	    break;
   2079 
   2080 	case TEXT:
   2081 	    copy_text();
   2082 	    break;
   2083 
   2084 	case UNION:
   2085 	    copy_union();
   2086 	    break;
   2087 
   2088 	case TOKEN:
   2089 	case LEFT:
   2090 	case RIGHT:
   2091 	case NONASSOC:
   2092 	    declare_tokens(k);
   2093 	    break;
   2094 
   2095 	case EXPECT:
   2096 	case EXPECT_RR:
   2097 	    declare_expect(k);
   2098 	    break;
   2099 
   2100 	case TYPE:
   2101 	    declare_types();
   2102 	    break;
   2103 
   2104 	case START:
   2105 	    declare_start();
   2106 	    break;
   2107 
   2108 	case PURE_PARSER:
   2109 	    pure_parser = 1;
   2110 	    break;
   2111 
   2112 	case PARSE_PARAM:
   2113 	case LEX_PARAM:
   2114 	    copy_param(k);
   2115 	    break;
   2116 
   2117 	case TOKEN_TABLE:
   2118 	    token_table = 1;
   2119 	    break;
   2120 
   2121 	case ERROR_VERBOSE:
   2122 	    error_verbose = 1;
   2123 	    break;
   2124 
   2125 #if defined(YYBTYACC)
   2126 	case LOCATIONS:
   2127 	    locations = 1;
   2128 	    break;
   2129 
   2130 	case DESTRUCTOR:
   2131 	    destructor = 1;
   2132 	    copy_destructor();
   2133 	    break;
   2134 	case INITIAL_ACTION:
   2135 	    copy_initial_action();
   2136 	    break;
   2137 #endif
   2138 
   2139 	case NONPOSIX_DEBUG:
   2140 	    tflag = 1;
   2141 	    break;
   2142 
   2143 	case HACK_DEFINE:
   2144 	    hack_defines();
   2145 	    break;
   2146 
   2147 	case POSIX_YACC:
   2148 	    /* noop for bison compatibility. byacc is already designed to be posix
   2149 	     * yacc compatible. */
   2150 	    break;
   2151 	}
   2152     }
   2153 }
   2154 
   2155 static void
   2156 initialize_grammar(void)
   2157 {
   2158     nitems = 4;
   2159     maxitems = 300;
   2160 
   2161     pitem = TMALLOC(bucket *, maxitems);
   2162     NO_SPACE(pitem);
   2163 
   2164     pitem[0] = NULL;
   2165     pitem[1] = NULL;
   2166     pitem[2] = NULL;
   2167     pitem[3] = NULL;
   2168 
   2169     nrules = 3;
   2170     maxrules = 100;
   2171 
   2172     plhs = TMALLOC(bucket *, maxrules);
   2173     NO_SPACE(plhs);
   2174 
   2175     plhs[0] = NULL;
   2176     plhs[1] = NULL;
   2177     plhs[2] = NULL;
   2178 
   2179     rprec = TMALLOC(Value_t, maxrules);
   2180     NO_SPACE(rprec);
   2181 
   2182     rprec[0] = 0;
   2183     rprec[1] = 0;
   2184     rprec[2] = 0;
   2185 
   2186     rassoc = TMALLOC(Assoc_t, maxrules);
   2187     NO_SPACE(rassoc);
   2188 
   2189     rassoc[0] = TOKEN;
   2190     rassoc[1] = TOKEN;
   2191     rassoc[2] = TOKEN;
   2192 }
   2193 
   2194 static void
   2195 expand_items(void)
   2196 {
   2197     maxitems += 300;
   2198     pitem = TREALLOC(bucket *, pitem, maxitems);
   2199     NO_SPACE(pitem);
   2200 }
   2201 
   2202 static void
   2203 expand_rules(void)
   2204 {
   2205     maxrules += 100;
   2206 
   2207     plhs = TREALLOC(bucket *, plhs, maxrules);
   2208     NO_SPACE(plhs);
   2209 
   2210     rprec = TREALLOC(Value_t, rprec, maxrules);
   2211     NO_SPACE(rprec);
   2212 
   2213     rassoc = TREALLOC(Assoc_t, rassoc, maxrules);
   2214     NO_SPACE(rassoc);
   2215 }
   2216 
   2217 /* set immediately prior to where copy_args() could be called, and incremented by
   2218    the various routines that will rescan the argument list as appropriate */
   2219 static int rescan_lineno;
   2220 #if defined(YYBTYACC)
   2221 
   2222 static char *
   2223 copy_args(int *alen)
   2224 {
   2225     struct mstring *s = msnew();
   2226     int depth = 0, len = 1;
   2227     char c, quote = 0;
   2228     struct ainfo a;
   2229 
   2230     begin_ainfo(a, 1);
   2231 
   2232     while ((c = *cptr++) != R_PAREN || depth || quote)
   2233     {
   2234 	if (c == ',' && !quote && !depth)
   2235 	{
   2236 	    len++;
   2237 	    mputc(s, 0);
   2238 	    continue;
   2239 	}
   2240 	mputc(s, c);
   2241 	if (c == '\n')
   2242 	{
   2243 	    get_line();
   2244 	    if (!line)
   2245 	    {
   2246 		if (quote)
   2247 		    unterminated_string(&a);
   2248 		else
   2249 		    unterminated_arglist(&a);
   2250 	    }
   2251 	}
   2252 	else if (quote)
   2253 	{
   2254 	    if (c == quote)
   2255 		quote = 0;
   2256 	    else if (c == '\\')
   2257 	    {
   2258 		if (*cptr != '\n')
   2259 		    mputc(s, *cptr++);
   2260 	    }
   2261 	}
   2262 	else
   2263 	{
   2264 	    if (c == L_PAREN)
   2265 		depth++;
   2266 	    else if (c == R_PAREN)
   2267 		depth--;
   2268 	    else if (c == '\"' || c == '\'')
   2269 		quote = c;
   2270 	}
   2271     }
   2272     if (alen)
   2273 	*alen = len;
   2274     end_ainfo(a);
   2275     return msdone(s);
   2276 }
   2277 
   2278 static char *
   2279 parse_id(char *p, char **save)
   2280 {
   2281     const char *b;
   2282 
   2283     while (isspace(UCH(*p)))
   2284 	if (*p++ == '\n')
   2285 	    rescan_lineno++;
   2286     if (!isalpha(UCH(*p)) && *p != '_')
   2287 	return NULL;
   2288     b = p;
   2289     while (IS_NAME2(*p))
   2290 	p++;
   2291     if (save)
   2292     {
   2293 	*save = cache_tag(b, (size_t)(p - b));
   2294     }
   2295     return p;
   2296 }
   2297 
   2298 static char *
   2299 parse_int(char *p, int *save)
   2300 {
   2301     int neg = 0, val = 0;
   2302 
   2303     while (isspace(UCH(*p)))
   2304 	if (*p++ == '\n')
   2305 	    rescan_lineno++;
   2306     if (*p == '-')
   2307     {
   2308 	neg = 1;
   2309 	p++;
   2310     }
   2311     if (!isdigit(UCH(*p)))
   2312 	return NULL;
   2313     while (isdigit(UCH(*p)))
   2314 	val = val * 10 + *p++ - '0';
   2315     if (neg)
   2316 	val = -val;
   2317     if (save)
   2318 	*save = val;
   2319     return p;
   2320 }
   2321 
   2322 static void
   2323 parse_arginfo(bucket *a, char *args, int argslen)
   2324 {
   2325     char *p = args, *tmp;
   2326     int i, redec = 0;
   2327 
   2328     if (a->args >= 0)
   2329     {
   2330 	if (a->args != argslen)
   2331 	    arg_number_disagree_warning(rescan_lineno, a->name);
   2332 	redec = 1;
   2333     }
   2334     else
   2335     {
   2336 	if ((a->args = argslen) == 0)
   2337 	    return;
   2338 	a->argnames = TMALLOC(char *, argslen);
   2339 	NO_SPACE(a->argnames);
   2340 	a->argtags = TMALLOC(char *, argslen);
   2341 	NO_SPACE(a->argtags);
   2342     }
   2343     if (!args)
   2344 	return;
   2345     for (i = 0; i < argslen; i++)
   2346     {
   2347 	while (isspace(UCH(*p)))
   2348 	    if (*p++ == '\n')
   2349 		rescan_lineno++;
   2350 	if (*p++ != '$')
   2351 	    bad_formals();
   2352 	while (isspace(UCH(*p)))
   2353 	    if (*p++ == '\n')
   2354 		rescan_lineno++;
   2355 	if (*p == '<')
   2356 	{
   2357 	    havetags = 1;
   2358 	    if (!(p = parse_id(p + 1, &tmp)))
   2359 		bad_formals();
   2360 	    while (isspace(UCH(*p)))
   2361 		if (*p++ == '\n')
   2362 		    rescan_lineno++;
   2363 	    if (*p++ != '>')
   2364 		bad_formals();
   2365 	    if (redec)
   2366 	    {
   2367 		if (a->argtags[i] != tmp)
   2368 		    arg_type_disagree_warning(rescan_lineno, i + 1, a->name);
   2369 	    }
   2370 	    else
   2371 		a->argtags[i] = tmp;
   2372 	}
   2373 	else if (!redec)
   2374 	    a->argtags[i] = NULL;
   2375 	if (!(p = parse_id(p, &a->argnames[i])))
   2376 	    bad_formals();
   2377 	while (isspace(UCH(*p)))
   2378 	    if (*p++ == '\n')
   2379 		rescan_lineno++;
   2380 	if (*p++)
   2381 	    bad_formals();
   2382     }
   2383     free(args);
   2384 }
   2385 
   2386 static char *
   2387 compile_arg(char **theptr, char *yyvaltag)
   2388 {
   2389     char *p = *theptr;
   2390     struct mstring *c = msnew();
   2391     int i, n;
   2392     Value_t *offsets = NULL, maxoffset;
   2393     bucket **rhs;
   2394 
   2395     maxoffset = 0;
   2396     n = 0;
   2397     for (i = nitems - 1; pitem[i]; --i)
   2398     {
   2399 	n++;
   2400 	if (pitem[i]->class != ARGUMENT)
   2401 	    maxoffset++;
   2402     }
   2403     if (maxoffset > 0)
   2404     {
   2405 	int j;
   2406 
   2407 	offsets = TCMALLOC(Value_t, maxoffset + 1);
   2408 	NO_SPACE(offsets);
   2409 
   2410 	for (j = 0, i++; i < nitems; i++)
   2411 	    if (pitem[i]->class != ARGUMENT)
   2412 		offsets[++j] = (Value_t)(i - nitems + 1);
   2413     }
   2414     rhs = pitem + nitems - 1;
   2415 
   2416     if (yyvaltag)
   2417 	msprintf(c, "yyval.%s = ", yyvaltag);
   2418     else
   2419 	msprintf(c, "yyval = ");
   2420     while (*p)
   2421     {
   2422 	if (*p == '$')
   2423 	{
   2424 	    char *tag = NULL;
   2425 	    if (*++p == '<')
   2426 		if (!(p = parse_id(++p, &tag)) || *p++ != '>')
   2427 		    illegal_tag(rescan_lineno, NULL, NULL);
   2428 	    if (isdigit(UCH(*p)) || *p == '-')
   2429 	    {
   2430 		int val;
   2431 		if (!(p = parse_int(p, &val)))
   2432 		    dollar_error(rescan_lineno, NULL, NULL);
   2433 		if (val <= 0)
   2434 		    i = val - n;
   2435 		else if (val > maxoffset)
   2436 		{
   2437 		    dollar_warning(rescan_lineno, val);
   2438 		    i = val - maxoffset;
   2439 		}
   2440 		else if (maxoffset > 0)
   2441 		{
   2442 		    i = offsets[val];
   2443 		    if (!tag && !(tag = rhs[i]->tag) && havetags)
   2444 			untyped_rhs(val, rhs[i]->name);
   2445 		}
   2446 		msprintf(c, "yystack.l_mark[%d]", i);
   2447 		if (tag)
   2448 		    msprintf(c, ".%s", tag);
   2449 		else if (havetags)
   2450 		    unknown_rhs(val);
   2451 	    }
   2452 	    else if (isalpha(UCH(*p)) || *p == '_')
   2453 	    {
   2454 		char *arg;
   2455 		if (!(p = parse_id(p, &arg)))
   2456 		    dollar_error(rescan_lineno, NULL, NULL);
   2457 		for (i = plhs[nrules]->args - 1; i >= 0; i--)
   2458 		    if (arg == plhs[nrules]->argnames[i])
   2459 			break;
   2460 		if (i < 0)
   2461 		    unknown_arg_warning(rescan_lineno, "$", arg, NULL, NULL);
   2462 		else if (!tag)
   2463 		    tag = plhs[nrules]->argtags[i];
   2464 		msprintf(c, "yystack.l_mark[%d]",
   2465 			 i - plhs[nrules]->args + 1 - n);
   2466 		if (tag)
   2467 		    msprintf(c, ".%s", tag);
   2468 		else if (havetags)
   2469 		    untyped_arg_warning(rescan_lineno, "$", arg);
   2470 	    }
   2471 	    else
   2472 		dollar_error(rescan_lineno, NULL, NULL);
   2473 	}
   2474 	else if (*p == '@')
   2475 	{
   2476 	    at_error(rescan_lineno, NULL, NULL);
   2477 	}
   2478 	else
   2479 	{
   2480 	    if (*p == '\n')
   2481 		rescan_lineno++;
   2482 	    mputc(c, *p++);
   2483 	}
   2484     }
   2485     *theptr = p;
   2486     if (maxoffset > 0)
   2487 	FREE(offsets);
   2488     return msdone(c);
   2489 }
   2490 
   2491 static int
   2492 can_elide_arg(char **theptr, const char *yyvaltag)
   2493 {
   2494     char *p = *theptr;
   2495     int rv = 0;
   2496     int i, n = 0;
   2497     Value_t *offsets = NULL, maxoffset = 0;
   2498     bucket **rhs;
   2499     char *tag = NULL;
   2500 
   2501     if (*p++ != '$')
   2502 	return 0;
   2503     if (*p == '<')
   2504     {
   2505 	if (!(p = parse_id(++p, &tag)) || *p++ != '>')
   2506 	    return 0;
   2507     }
   2508     for (i = nitems - 1; pitem[i]; --i)
   2509     {
   2510 	n++;
   2511 	if (pitem[i]->class != ARGUMENT)
   2512 	    maxoffset++;
   2513     }
   2514     if (maxoffset > 0)
   2515     {
   2516 	int j;
   2517 
   2518 	offsets = TCMALLOC(Value_t, maxoffset + 1);
   2519 	NO_SPACE(offsets);
   2520 
   2521 	for (j = 0, i++; i < nitems; i++)
   2522 	    if (pitem[i]->class != ARGUMENT)
   2523 		offsets[++j] = (Value_t)(i - nitems + 1);
   2524     }
   2525     rhs = pitem + nitems - 1;
   2526 
   2527     if (isdigit(UCH(*p)) || *p == '-')
   2528     {
   2529 	int val;
   2530 	if (!(p = parse_int(p, &val)))
   2531 	    rv = 0;
   2532 	else
   2533 	{
   2534 	    if (val <= 0)
   2535 		rv = 1 - val + n;
   2536 	    else if (val > maxoffset)
   2537 		rv = 0;
   2538 	    else
   2539 	    {
   2540 		i = offsets[val];
   2541 		rv = 1 - i;
   2542 		if (!tag)
   2543 		    tag = rhs[i]->tag;
   2544 	    }
   2545 	}
   2546     }
   2547     else if (isalpha(UCH(*p)) || *p == '_')
   2548     {
   2549 	char *arg;
   2550 	if (!(p = parse_id(p, &arg)))
   2551 	{
   2552 	    FREE(offsets);
   2553 	    return 0;
   2554 	}
   2555 	for (i = plhs[nrules]->args - 1; i >= 0; i--)
   2556 	    if (arg == plhs[nrules]->argnames[i])
   2557 		break;
   2558 	if (i >= 0)
   2559 	{
   2560 	    if (!tag)
   2561 		tag = plhs[nrules]->argtags[i];
   2562 	    rv = plhs[nrules]->args + n - i;
   2563 	}
   2564     }
   2565     if (tag && yyvaltag)
   2566     {
   2567 	if (strcmp(tag, yyvaltag))
   2568 	    rv = 0;
   2569     }
   2570     else if (tag || yyvaltag)
   2571 	rv = 0;
   2572     if (maxoffset > 0)
   2573 	FREE(offsets);
   2574     if (p == NULL || *p || rv <= 0)
   2575 	return 0;
   2576     *theptr = p + 1;
   2577     return rv;
   2578 }
   2579 
   2580 #define ARG_CACHE_SIZE	1024
   2581 static struct arg_cache
   2582 {
   2583     struct arg_cache *next;
   2584     char *code;
   2585     int rule;
   2586 }
   2587  *arg_cache[ARG_CACHE_SIZE];
   2588 
   2589 static int
   2590 lookup_arg_cache(const char *code)
   2591 {
   2592     struct arg_cache *entry;
   2593 
   2594     entry = arg_cache[strnshash(code) % ARG_CACHE_SIZE];
   2595     while (entry)
   2596     {
   2597 	if (!strnscmp(entry->code, code))
   2598 	    return entry->rule;
   2599 	entry = entry->next;
   2600     }
   2601     return -1;
   2602 }
   2603 
   2604 static void
   2605 insert_arg_cache(char *code, int rule)
   2606 {
   2607     struct arg_cache *entry = NEW(struct arg_cache);
   2608     int i;
   2609 
   2610     NO_SPACE(entry);
   2611     i = strnshash(code) % ARG_CACHE_SIZE;
   2612     entry->code = code;
   2613     entry->rule = rule;
   2614     entry->next = arg_cache[i];
   2615     arg_cache[i] = entry;
   2616 }
   2617 
   2618 static void
   2619 clean_arg_cache(void)
   2620 {
   2621     struct arg_cache *e, *t;
   2622     int i;
   2623 
   2624     for (i = 0; i < ARG_CACHE_SIZE; i++)
   2625     {
   2626 	for (e = arg_cache[i]; (t = e); e = e->next, FREE(t))
   2627 	    free(e->code);
   2628 	arg_cache[i] = NULL;
   2629     }
   2630 }
   2631 #endif /* defined(YYBTYACC) */
   2632 
   2633 static void
   2634 advance_to_start(void)
   2635 {
   2636     int c;
   2637     bucket *bp;
   2638     int s_lineno;
   2639 #if defined(YYBTYACC)
   2640     char *args = NULL;
   2641     int argslen = 0;
   2642 #endif
   2643 
   2644     for (;;)
   2645     {
   2646 	const char *s_cptr;
   2647 
   2648 	c = nextc();
   2649 	if (c != '%')
   2650 	    break;
   2651 	s_cptr = cptr;
   2652 	switch (keyword())
   2653 	{
   2654 	case XCODE:
   2655 	    copy_code();
   2656 	    break;
   2657 
   2658 	case MARK:
   2659 	    no_grammar();
   2660 
   2661 	case TEXT:
   2662 	    copy_text();
   2663 	    break;
   2664 
   2665 	case START:
   2666 	    declare_start();
   2667 	    break;
   2668 
   2669 	default:
   2670 	    syntax_error(lineno, line, s_cptr);
   2671 	}
   2672     }
   2673 
   2674     c = nextc();
   2675     if (!isalpha(UCH(c)) && c != '_' && c != '.' && c != '_')
   2676 	syntax_error(lineno, line, cptr);
   2677     bp = get_name();
   2678     if (goal == NULL)
   2679     {
   2680 	if (bp->class == TERM)
   2681 	    terminal_start(bp->name);
   2682 	goal = bp;
   2683     }
   2684 
   2685     s_lineno = lineno;
   2686     c = nextc();
   2687     if (c == EOF)
   2688 	unexpected_EOF();
   2689     rescan_lineno = lineno;	/* line# for possible inherited args rescan */
   2690 #if defined(YYBTYACC)
   2691     if (c == L_PAREN)
   2692     {
   2693 	++cptr;
   2694 	args = copy_args(&argslen);
   2695 	NO_SPACE(args);
   2696 	c = nextc();
   2697     }
   2698 #endif
   2699     if (c != ':')
   2700 	syntax_error(lineno, line, cptr);
   2701     start_rule(bp, s_lineno);
   2702 #if defined(YYBTYACC)
   2703     parse_arginfo(bp, args, argslen);
   2704 #endif
   2705     ++cptr;
   2706 }
   2707 
   2708 static void
   2709 start_rule(bucket *bp, int s_lineno)
   2710 {
   2711     if (bp->class == TERM)
   2712 	terminal_lhs(s_lineno);
   2713     bp->class = NONTERM;
   2714     if (!bp->index)
   2715 	bp->index = nrules;
   2716     if (nrules >= maxrules)
   2717 	expand_rules();
   2718     plhs[nrules] = bp;
   2719     rprec[nrules] = UNDEFINED;
   2720     rassoc[nrules] = TOKEN;
   2721 }
   2722 
   2723 static void
   2724 end_rule(void)
   2725 {
   2726     if (!last_was_action && plhs[nrules]->tag)
   2727     {
   2728 	if (pitem[nitems - 1])
   2729 	{
   2730 	    int i;
   2731 
   2732 	    for (i = nitems - 1; (i > 0) && pitem[i]; --i)
   2733 	    {
   2734 		;
   2735 	    }
   2736 	    if (pitem[i + 1] == NULL || pitem[i + 1]->tag != plhs[nrules]->tag)
   2737 		default_action_warning(plhs[nrules]->name);
   2738 	}
   2739 	else
   2740 	    default_action_warning(plhs[nrules]->name);
   2741     }
   2742 
   2743     last_was_action = 0;
   2744     if (nitems >= maxitems)
   2745 	expand_items();
   2746     pitem[nitems] = NULL;
   2747     ++nitems;
   2748     ++nrules;
   2749 }
   2750 
   2751 static void
   2752 insert_empty_rule(void)
   2753 {
   2754     bucket *bp, **bpp;
   2755 
   2756     assert(cache);
   2757     assert(cache_size >= CACHE_SIZE);
   2758     sprintf(cache, "$$%d", ++gensym);
   2759     bp = make_bucket(cache);
   2760     last_symbol->next = bp;
   2761     last_symbol = bp;
   2762     bp->tag = plhs[nrules]->tag;
   2763     bp->class = ACTION;
   2764 #if defined(YYBTYACC)
   2765     bp->args = 0;
   2766 #endif
   2767 
   2768     nitems = (Value_t)(nitems + 2);
   2769     if (nitems > maxitems)
   2770 	expand_items();
   2771     bpp = pitem + nitems - 1;
   2772     *bpp-- = bp;
   2773     while ((bpp[0] = bpp[-1]) != NULL)
   2774 	--bpp;
   2775 
   2776     if (++nrules >= maxrules)
   2777 	expand_rules();
   2778     plhs[nrules] = plhs[nrules - 1];
   2779     plhs[nrules - 1] = bp;
   2780     rprec[nrules] = rprec[nrules - 1];
   2781     rprec[nrules - 1] = 0;
   2782     rassoc[nrules] = rassoc[nrules - 1];
   2783     rassoc[nrules - 1] = TOKEN;
   2784 }
   2785 
   2786 #if defined(YYBTYACC)
   2787 static char *
   2788 insert_arg_rule(char *arg, char *tag)
   2789 {
   2790     int line_number = rescan_lineno;
   2791     char *code = compile_arg(&arg, tag);
   2792     int rule = lookup_arg_cache(code);
   2793     FILE *f = action_file;
   2794 
   2795     if (rule < 0)
   2796     {
   2797 	rule = nrules;
   2798 	insert_arg_cache(code, rule);
   2799 	trialaction = 1;	/* arg rules always run in trial mode */
   2800 	begin_case(f, rule - 2);
   2801 	fprintf_lineno(f, line_number, input_file_name);
   2802 	fprintf(f, "%s;", code);
   2803 	end_case(f);
   2804 	insert_empty_rule();
   2805 	plhs[rule]->tag = cache_tag(tag, strlen(tag));
   2806 	plhs[rule]->class = ARGUMENT;
   2807     }
   2808     else
   2809     {
   2810 	if (++nitems > maxitems)
   2811 	    expand_items();
   2812 	pitem[nitems - 1] = plhs[rule];
   2813 	free(code);
   2814     }
   2815     return arg + 1;
   2816 }
   2817 #endif
   2818 
   2819 static void
   2820 add_symbol(void)
   2821 {
   2822     int c;
   2823     bucket *bp;
   2824     int s_lineno = lineno;
   2825 #if defined(YYBTYACC)
   2826     char *args = NULL;
   2827     int argslen = 0;
   2828 #endif
   2829 
   2830     c = *cptr;
   2831     if (c == '\'' || c == '"')
   2832 	bp = get_literal();
   2833     else
   2834 	bp = get_name();
   2835 
   2836     c = nextc();
   2837     rescan_lineno = lineno;	/* line# for possible inherited args rescan */
   2838 #if defined(YYBTYACC)
   2839     if (c == L_PAREN)
   2840     {
   2841 	++cptr;
   2842 	args = copy_args(&argslen);
   2843 	NO_SPACE(args);
   2844 	c = nextc();
   2845     }
   2846 #endif
   2847     if (c == ':')
   2848     {
   2849 	end_rule();
   2850 	start_rule(bp, s_lineno);
   2851 #if defined(YYBTYACC)
   2852 	parse_arginfo(bp, args, argslen);
   2853 #endif
   2854 	++cptr;
   2855 	return;
   2856     }
   2857 
   2858     if (last_was_action)
   2859 	insert_empty_rule();
   2860     last_was_action = 0;
   2861 
   2862 #if defined(YYBTYACC)
   2863     if (bp->args < 0)
   2864 	bp->args = argslen;
   2865     if (argslen == 0 && bp->args > 0 && pitem[nitems - 1] == NULL)
   2866     {
   2867 	int i;
   2868 	if (plhs[nrules]->args != bp->args)
   2869 	    wrong_number_args_warning("default ", bp->name);
   2870 	for (i = bp->args - 1; i >= 0; i--)
   2871 	    if (plhs[nrules]->argtags[i] != bp->argtags[i])
   2872 		wrong_type_for_arg_warning(i + 1, bp->name);
   2873     }
   2874     else if (bp->args != argslen)
   2875 	wrong_number_args_warning("", bp->name);
   2876     if (args != NULL)
   2877     {
   2878 	char *ap = args;
   2879 	int i = 0;
   2880 	int elide_cnt = can_elide_arg(&ap, bp->argtags[0]);
   2881 
   2882 	if (elide_cnt > argslen)
   2883 	    elide_cnt = 0;
   2884 	if (elide_cnt)
   2885 	{
   2886 	    for (i = 1; i < elide_cnt; i++)
   2887 		if (can_elide_arg(&ap, bp->argtags[i]) != elide_cnt - i)
   2888 		{
   2889 		    elide_cnt = 0;
   2890 		    break;
   2891 		}
   2892 	}
   2893 	if (elide_cnt)
   2894 	{
   2895 	    assert(i == elide_cnt);
   2896 	}
   2897 	else
   2898 	{
   2899 	    ap = args;
   2900 	    i = 0;
   2901 	}
   2902 	for (; i < argslen; i++)
   2903 	    ap = insert_arg_rule(ap, bp->argtags[i]);
   2904 	free(args);
   2905     }
   2906 #endif /* defined(YYBTYACC) */
   2907 
   2908     if (++nitems > maxitems)
   2909 	expand_items();
   2910     pitem[nitems - 1] = bp;
   2911 }
   2912 
   2913 static void
   2914 copy_action(void)
   2915 {
   2916     int c;
   2917     int i, j, n;
   2918     int depth;
   2919 #if defined(YYBTYACC)
   2920     int haveyyval = 0;
   2921 #endif
   2922     const char *tag;
   2923     FILE *f = action_file;
   2924     struct ainfo a;
   2925     Value_t *offsets = NULL, maxoffset;
   2926     bucket **rhs;
   2927 
   2928     begin_ainfo(a, 0);
   2929 
   2930     if (last_was_action)
   2931 	insert_empty_rule();
   2932     last_was_action = 1;
   2933 #if defined(YYBTYACC)
   2934     trialaction = (*cptr == L_BRAC);
   2935 #endif
   2936 
   2937     begin_case(f, nrules - 2);
   2938 #if defined(YYBTYACC)
   2939     if (backtrack)
   2940     {
   2941 	if (!trialaction)
   2942 	    fprintf(f, "  if (!yytrial)\n");
   2943     }
   2944 #endif
   2945     fprintf_lineno(f, lineno, input_file_name);
   2946     if (*cptr == '=')
   2947 	++cptr;
   2948 
   2949     /* avoid putting curly-braces in first column, to ease editing */
   2950     if (*after_blanks(cptr) == L_CURL)
   2951     {
   2952 	putc('\t', f);
   2953 	cptr = after_blanks(cptr);
   2954     }
   2955 
   2956     maxoffset = 0;
   2957     n = 0;
   2958     for (i = nitems - 1; pitem[i]; --i)
   2959     {
   2960 	++n;
   2961 	if (pitem[i]->class != ARGUMENT)
   2962 	    maxoffset++;
   2963     }
   2964     if (maxoffset > 0)
   2965     {
   2966 	offsets = TMALLOC(Value_t, maxoffset + 1);
   2967 	NO_SPACE(offsets);
   2968 
   2969 	for (j = 0, i++; i < nitems; i++)
   2970 	{
   2971 	    if (pitem[i]->class != ARGUMENT)
   2972 	    {
   2973 		offsets[++j] = (Value_t)(i - nitems + 1);
   2974 	    }
   2975 	}
   2976     }
   2977     rhs = pitem + nitems - 1;
   2978 
   2979     depth = 0;
   2980   loop:
   2981     c = *cptr;
   2982     if (c == '$')
   2983     {
   2984 	if (cptr[1] == '<')
   2985 	{
   2986 	    int d_lineno = lineno;
   2987 	    char *d_line = dup_line();
   2988 	    const char *d_cptr = d_line + (cptr - line);
   2989 
   2990 	    ++cptr;
   2991 	    tag = get_tag();
   2992 	    c = *cptr;
   2993 	    if (c == '$')
   2994 	    {
   2995 		fprintf(f, "yyval.%s", tag);
   2996 		++cptr;
   2997 		FREE(d_line);
   2998 		goto loop;
   2999 	    }
   3000 	    else if (isdigit(UCH(c)))
   3001 	    {
   3002 		i = get_number();
   3003 		if (i == 0)
   3004 		    fprintf(f, "yystack.l_mark[%d].%s", -n, tag);
   3005 		else if (i > maxoffset)
   3006 		{
   3007 		    dollar_warning(d_lineno, i);
   3008 		    fprintf(f, "yystack.l_mark[%ld].%s",
   3009 			    (long)(i - maxoffset), tag);
   3010 		}
   3011 		else if (offsets)
   3012 		    fprintf(f, "yystack.l_mark[%ld].%s",
   3013 			    (long)offsets[i], tag);
   3014 		FREE(d_line);
   3015 		goto loop;
   3016 	    }
   3017 	    else if (c == '-' && isdigit(UCH(cptr[1])))
   3018 	    {
   3019 		++cptr;
   3020 		i = -get_number() - n;
   3021 		fprintf(f, "yystack.l_mark[%d].%s", i, tag);
   3022 		FREE(d_line);
   3023 		goto loop;
   3024 	    }
   3025 #if defined(YYBTYACC)
   3026 	    else if (isalpha(UCH(c)) || c == '_')
   3027 	    {
   3028 		const char *arg = scan_id();
   3029 		for (i = plhs[nrules]->args - 1; i >= 0; i--)
   3030 		    if (arg == plhs[nrules]->argnames[i])
   3031 			break;
   3032 		if (i < 0)
   3033 		    unknown_arg_warning(d_lineno, "$", arg, d_line, d_cptr);
   3034 		fprintf(f, "yystack.l_mark[%d].%s",
   3035 			i - plhs[nrules]->args + 1 - n, tag);
   3036 		FREE(d_line);
   3037 		goto loop;
   3038 	    }
   3039 #endif
   3040 	    else
   3041 		dollar_error(d_lineno, d_line, d_cptr);
   3042 	}
   3043 	else if (cptr[1] == '$')
   3044 	{
   3045 	    if (havetags)
   3046 	    {
   3047 		tag = plhs[nrules]->tag;
   3048 		if (tag == NULL)
   3049 		    untyped_lhs();
   3050 		fprintf(f, "yyval.%s", tag);
   3051 	    }
   3052 	    else
   3053 		fprintf(f, "yyval");
   3054 	    cptr += 2;
   3055 #if defined(YYBTYACC)
   3056 	    haveyyval = 1;
   3057 #endif
   3058 	    goto loop;
   3059 	}
   3060 	else if (isdigit(UCH(cptr[1])))
   3061 	{
   3062 	    ++cptr;
   3063 	    i = get_number();
   3064 	    if (havetags && offsets)
   3065 	    {
   3066 		if (i <= 0 || i > maxoffset)
   3067 		    unknown_rhs(i);
   3068 		tag = rhs[offsets[i]]->tag;
   3069 		if (tag == NULL)
   3070 		    untyped_rhs(i, rhs[offsets[i]]->name);
   3071 		fprintf(f, "yystack.l_mark[%ld].%s", (long)offsets[i], tag);
   3072 	    }
   3073 	    else
   3074 	    {
   3075 		if (i == 0)
   3076 		    fprintf(f, "yystack.l_mark[%d]", -n);
   3077 		else if (i > maxoffset)
   3078 		{
   3079 		    dollar_warning(lineno, i);
   3080 		    fprintf(f, "yystack.l_mark[%ld]", (long)(i - maxoffset));
   3081 		}
   3082 		else if (offsets)
   3083 		    fprintf(f, "yystack.l_mark[%ld]", (long)offsets[i]);
   3084 	    }
   3085 	    goto loop;
   3086 	}
   3087 	else if (cptr[1] == '-')
   3088 	{
   3089 	    cptr += 2;
   3090 	    i = get_number();
   3091 	    if (havetags)
   3092 		unknown_rhs(-i);
   3093 	    fprintf(f, "yystack.l_mark[%d]", -i - n);
   3094 	    goto loop;
   3095 	}
   3096 #if defined(YYBTYACC)
   3097 	else if (isalpha(UCH(cptr[1])) || cptr[1] == '_')
   3098 	{
   3099 	    const char *arg;
   3100 	    ++cptr;
   3101 	    arg = scan_id();
   3102 	    for (i = plhs[nrules]->args - 1; i >= 0; i--)
   3103 		if (arg == plhs[nrules]->argnames[i])
   3104 		    break;
   3105 	    if (i < 0)
   3106 		unknown_arg_warning(lineno, "$", arg, line, cptr);
   3107 	    tag = (i < 0 ? NULL : plhs[nrules]->argtags[i]);
   3108 	    fprintf(f, "yystack.l_mark[%d]", i - plhs[nrules]->args + 1 - n);
   3109 	    if (tag)
   3110 		fprintf(f, ".%s", tag);
   3111 	    else if (havetags)
   3112 		untyped_arg_warning(lineno, "$", arg);
   3113 	    goto loop;
   3114 	}
   3115 #endif
   3116     }
   3117 #if defined(YYBTYACC)
   3118     if (c == '@')
   3119     {
   3120 	if (!locations)
   3121 	{
   3122 	    dislocations_warning();
   3123 	    locations = 1;
   3124 	}
   3125 	if (cptr[1] == '$')
   3126 	{
   3127 	    fprintf(f, "yyloc");
   3128 	    cptr += 2;
   3129 	    goto loop;
   3130 	}
   3131 	else if (isdigit(UCH(cptr[1])))
   3132 	{
   3133 	    ++cptr;
   3134 	    i = get_number();
   3135 	    if (i == 0)
   3136 		fprintf(f, "yystack.p_mark[%d]", -n);
   3137 	    else if (i > maxoffset)
   3138 	    {
   3139 		at_warning(lineno, i);
   3140 		fprintf(f, "yystack.p_mark[%d]", i - maxoffset);
   3141 	    }
   3142 	    else if (offsets)
   3143 		fprintf(f, "yystack.p_mark[%d]", offsets[i]);
   3144 	    goto loop;
   3145 	}
   3146 	else if (cptr[1] == '-')
   3147 	{
   3148 	    cptr += 2;
   3149 	    i = get_number();
   3150 	    fprintf(f, "yystack.p_mark[%d]", -i - n);
   3151 	    goto loop;
   3152 	}
   3153     }
   3154 #endif
   3155     if (IS_NAME1(c))
   3156     {
   3157 	do
   3158 	{
   3159 	    putc(c, f);
   3160 	    c = *++cptr;
   3161 	}
   3162 	while (IS_NAME2(c));
   3163 	goto loop;
   3164     }
   3165     ++cptr;
   3166 #if defined(YYBTYACC)
   3167     if (backtrack)
   3168     {
   3169 	if (trialaction && c == L_BRAC && depth == 0)
   3170 	{
   3171 	    ++depth;
   3172 	    putc(L_CURL, f);
   3173 	    goto loop;
   3174 	}
   3175 	if (trialaction && c == R_BRAC && depth == 1)
   3176 	{
   3177 	    --depth;
   3178 	    putc(R_CURL, f);
   3179 	    c = nextc();
   3180 	    if (c == L_BRAC && !haveyyval)
   3181 	    {
   3182 		goto loop;
   3183 	    }
   3184 	    if (c == L_CURL && !haveyyval)
   3185 	    {
   3186 		fprintf(f, "  if (!yytrial)\n");
   3187 		fprintf_lineno(f, lineno, input_file_name);
   3188 		trialaction = 0;
   3189 		goto loop;
   3190 	    }
   3191 	    end_case(f);
   3192 	    end_ainfo(a);
   3193 	    if (maxoffset > 0)
   3194 		FREE(offsets);
   3195 	    return;
   3196 	}
   3197     }
   3198 #endif
   3199     putc(c, f);
   3200     switch (c)
   3201     {
   3202     case '\n':
   3203 	get_line();
   3204 	if (line)
   3205 	    goto loop;
   3206 	unterminated_action(&a);
   3207 
   3208     case ';':
   3209 	if (depth > 0)
   3210 	    goto loop;
   3211 	end_case(f);
   3212 	end_ainfo(a);
   3213 	if (maxoffset > 0)
   3214 	    FREE(offsets);
   3215 	return;
   3216 
   3217 #if defined(YYBTYACC)
   3218     case L_BRAC:
   3219 	if (backtrack)
   3220 	    ++depth;
   3221 	goto loop;
   3222 
   3223     case R_BRAC:
   3224 	if (backtrack)
   3225 	    --depth;
   3226 	goto loop;
   3227 #endif
   3228 
   3229     case L_CURL:
   3230 	++depth;
   3231 	goto loop;
   3232 
   3233     case R_CURL:
   3234 	if (--depth > 0)
   3235 	    goto loop;
   3236 #if defined(YYBTYACC)
   3237 	if (backtrack)
   3238 	{
   3239 	    c = nextc();
   3240 	    if (c == L_BRAC && !haveyyval)
   3241 	    {
   3242 		trialaction = 1;
   3243 		goto loop;
   3244 	    }
   3245 	    if (c == L_CURL && !haveyyval)
   3246 	    {
   3247 		fprintf(f, "  if (!yytrial)\n");
   3248 		fprintf_lineno(f, lineno, input_file_name);
   3249 		goto loop;
   3250 	    }
   3251 	}
   3252 #endif
   3253 	end_case(f);
   3254 	end_ainfo(a);
   3255 	if (maxoffset > 0)
   3256 	    FREE(offsets);
   3257 	return;
   3258 
   3259     case '\'':
   3260     case '"':
   3261 	{
   3262 	    char *s = copy_string(c);
   3263 	    fputs(s, f);
   3264 	    free(s);
   3265 	}
   3266 	goto loop;
   3267 
   3268     case '/':
   3269 	{
   3270 	    char *s = copy_comment();
   3271 	    puts_trim(s, f);
   3272 	    free(s);
   3273 	}
   3274 	goto loop;
   3275 
   3276     default:
   3277 	goto loop;
   3278     }
   3279 }
   3280 
   3281 #if defined(YYBTYACC)
   3282 static char *
   3283 get_code(struct ainfo *a, const char *loc)
   3284 {
   3285     int c;
   3286     int depth;
   3287     char *tag;
   3288     struct mstring *code_mstr = msnew();
   3289 
   3290     if (!lflag)
   3291 	msprintf(code_mstr, line_format, lineno, input_file_name);
   3292 
   3293     cptr = after_blanks(cptr);
   3294     if (*cptr == L_CURL)
   3295 	/* avoid putting curly-braces in first column, to ease editing */
   3296 	mputc(code_mstr, '\t');
   3297     else
   3298 	syntax_error(lineno, line, cptr);
   3299 
   3300     begin_ainfo((*a), 0);
   3301 
   3302     depth = 0;
   3303   loop:
   3304     c = *cptr;
   3305     if (c == '$')
   3306     {
   3307 	if (cptr[1] == '<')
   3308 	{
   3309 	    int d_lineno = lineno;
   3310 	    char *d_line = dup_line();
   3311 	    const char *d_cptr = d_line + (cptr - line);
   3312 
   3313 	    ++cptr;
   3314 	    tag = get_tag();
   3315 	    c = *cptr;
   3316 	    if (c == '$')
   3317 	    {
   3318 		msprintf(code_mstr, "(*val).%s", tag);
   3319 		++cptr;
   3320 		FREE(d_line);
   3321 		goto loop;
   3322 	    }
   3323 	    else
   3324 		dollar_error(d_lineno, d_line, d_cptr);
   3325 	}
   3326 	else if (cptr[1] == '$')
   3327 	{
   3328 	    /* process '$$' later; replacement is context dependent */
   3329 	    msprintf(code_mstr, "$$");
   3330 	    cptr += 2;
   3331 	    goto loop;
   3332 	}
   3333     }
   3334     if (c == '@' && cptr[1] == '$')
   3335     {
   3336 	if (!locations)
   3337 	{
   3338 	    dislocations_warning();
   3339 	    locations = 1;
   3340 	}
   3341 	msprintf(code_mstr, "%s", loc);
   3342 	cptr += 2;
   3343 	goto loop;
   3344     }
   3345     if (IS_NAME1(c))
   3346     {
   3347 	do
   3348 	{
   3349 	    mputc(code_mstr, c);
   3350 	    c = *++cptr;
   3351 	}
   3352 	while (IS_NAME2(c));
   3353 	goto loop;
   3354     }
   3355     ++cptr;
   3356     mputc(code_mstr, c);
   3357     switch (c)
   3358     {
   3359     case '\n':
   3360 	get_line();
   3361 	if (line)
   3362 	    goto loop;
   3363 	unterminated_action(a);
   3364 
   3365     case L_CURL:
   3366 	++depth;
   3367 	goto loop;
   3368 
   3369     case R_CURL:
   3370 	if (--depth > 0)
   3371 	    goto loop;
   3372 	goto out;
   3373 
   3374     case '\'':
   3375     case '"':
   3376 	{
   3377 	    char *s = copy_string(c);
   3378 	    msprintf(code_mstr, "%s", s);
   3379 	    free(s);
   3380 	}
   3381 	goto loop;
   3382 
   3383     case '/':
   3384 	{
   3385 	    char *s = copy_comment();
   3386 	    msprintf(code_mstr, "%s", s);
   3387 	    free(s);
   3388 	}
   3389 	goto loop;
   3390 
   3391     default:
   3392 	goto loop;
   3393     }
   3394   out:
   3395     return msdone(code_mstr);
   3396 }
   3397 
   3398 static void
   3399 copy_initial_action(void)
   3400 {
   3401     struct ainfo a;
   3402 
   3403     initial_action = get_code(&a, "yyloc");
   3404     end_ainfo(a);
   3405 }
   3406 
   3407 static void
   3408 copy_destructor(void)
   3409 {
   3410     char *code_text;
   3411     struct ainfo a;
   3412     bucket *bp;
   3413 
   3414     code_text = get_code(&a, "(*loc)");
   3415 
   3416     for (;;)
   3417     {
   3418 	int c = nextc();
   3419 	if (c == EOF)
   3420 	    unexpected_EOF();
   3421 	if (c == '<')
   3422 	{
   3423 	    if (cptr[1] == '>')
   3424 	    {			/* "no semantic type" default destructor */
   3425 		cptr += 2;
   3426 		if ((bp = default_destructor[UNTYPED_DEFAULT]) == NULL)
   3427 		{
   3428 		    static char untyped_default[] = "<>";
   3429 		    bp = make_bucket("untyped default");
   3430 		    bp->tag = untyped_default;
   3431 		    default_destructor[UNTYPED_DEFAULT] = bp;
   3432 		}
   3433 		if (bp->destructor != NULL)
   3434 		    destructor_redeclared_warning(&a);
   3435 		else
   3436 		    /* replace "$$" with "(*val)" in destructor code */
   3437 		    bp->destructor = process_destructor_XX(code_text, NULL);
   3438 	    }
   3439 	    else if (cptr[1] == '*' && cptr[2] == '>')
   3440 	    {			/* "no per-symbol or per-type" default destructor */
   3441 		cptr += 3;
   3442 		if ((bp = default_destructor[TYPED_DEFAULT]) == NULL)
   3443 		{
   3444 		    static char typed_default[] = "<*>";
   3445 		    bp = make_bucket("typed default");
   3446 		    bp->tag = typed_default;
   3447 		    default_destructor[TYPED_DEFAULT] = bp;
   3448 		}
   3449 		if (bp->destructor != NULL)
   3450 		    destructor_redeclared_warning(&a);
   3451 		else
   3452 		{
   3453 		    /* postpone re-processing destructor $$s until end of grammar spec */
   3454 		    bp->destructor = TMALLOC(char, strlen(code_text) + 1);
   3455 		    NO_SPACE(bp->destructor);
   3456 		    strcpy(bp->destructor, code_text);
   3457 		}
   3458 	    }
   3459 	    else
   3460 	    {			/* "semantic type" default destructor */
   3461 		char *tag = get_tag();
   3462 		bp = lookup_type_destructor(tag);
   3463 		if (bp->destructor != NULL)
   3464 		    destructor_redeclared_warning(&a);
   3465 		else
   3466 		    /* replace "$$" with "(*val).tag" in destructor code */
   3467 		    bp->destructor = process_destructor_XX(code_text, tag);
   3468 	    }
   3469 	}
   3470 	else if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
   3471 	{			/* "symbol" destructor */
   3472 	    bp = get_name();
   3473 	    if (bp->destructor != NULL)
   3474 		destructor_redeclared_warning(&a);
   3475 	    else
   3476 	    {
   3477 		/* postpone re-processing destructor $$s until end of grammar spec */
   3478 		bp->destructor = TMALLOC(char, strlen(code_text) + 1);
   3479 		NO_SPACE(bp->destructor);
   3480 		strcpy(bp->destructor, code_text);
   3481 	    }
   3482 	}
   3483 	else
   3484 	    break;
   3485     }
   3486     end_ainfo(a);
   3487     free(code_text);
   3488 }
   3489 
   3490 static char *
   3491 process_destructor_XX(char *code, char *tag)
   3492 {
   3493     int c;
   3494     int quote;
   3495     int depth;
   3496     struct mstring *new_code = msnew();
   3497     char *codeptr = code;
   3498 
   3499     depth = 0;
   3500   loop:			/* step thru code */
   3501     c = *codeptr;
   3502     if (c == '$' && codeptr[1] == '$')
   3503     {
   3504 	codeptr += 2;
   3505 	if (tag == NULL)
   3506 	    msprintf(new_code, "(*val)");
   3507 	else
   3508 	    msprintf(new_code, "(*val).%s", tag);
   3509 	goto loop;
   3510     }
   3511     if (IS_NAME1(c))
   3512     {
   3513 	do
   3514 	{
   3515 	    mputc(new_code, c);
   3516 	    c = *++codeptr;
   3517 	}
   3518 	while (IS_NAME2(c));
   3519 	goto loop;
   3520     }
   3521     ++codeptr;
   3522     mputc(new_code, c);
   3523     switch (c)
   3524     {
   3525     case L_CURL:
   3526 	++depth;
   3527 	goto loop;
   3528 
   3529     case R_CURL:
   3530 	if (--depth > 0)
   3531 	    goto loop;
   3532 	return msdone(new_code);
   3533 
   3534     case '\'':
   3535     case '"':
   3536 	quote = c;
   3537 	for (;;)
   3538 	{
   3539 	    c = *codeptr++;
   3540 	    mputc(new_code, c);
   3541 	    if (c == quote)
   3542 		goto loop;
   3543 	    if (c == '\\')
   3544 	    {
   3545 		c = *codeptr++;
   3546 		mputc(new_code, c);
   3547 	    }
   3548 	}
   3549 
   3550     case '/':
   3551 	c = *codeptr;
   3552 	if (c == '*')
   3553 	{
   3554 	    mputc(new_code, c);
   3555 	    ++codeptr;
   3556 	    for (;;)
   3557 	    {
   3558 		c = *codeptr++;
   3559 		mputc(new_code, c);
   3560 		if (c == '*' && *codeptr == '/')
   3561 		{
   3562 		    mputc(new_code, '/');
   3563 		    ++codeptr;
   3564 		    goto loop;
   3565 		}
   3566 	    }
   3567 	}
   3568 	goto loop;
   3569 
   3570     default:
   3571 	goto loop;
   3572     }
   3573 }
   3574 #endif /* defined(YYBTYACC) */
   3575 
   3576 static int
   3577 mark_symbol(void)
   3578 {
   3579     int c;
   3580     const bucket *bp = NULL;
   3581 
   3582     c = cptr[1];
   3583     if (c == '%' || c == '\\')
   3584     {
   3585 	cptr += 2;
   3586 	return (1);
   3587     }
   3588 
   3589     if (c == '=')
   3590 	cptr += 2;
   3591     else if ((c == 'p' || c == 'P') &&
   3592 	     ((c = cptr[2]) == 'r' || c == 'R') &&
   3593 	     ((c = cptr[3]) == 'e' || c == 'E') &&
   3594 	     ((c = cptr[4]) == 'c' || c == 'C') &&
   3595 	     ((c = cptr[5], !IS_IDENT(c))))
   3596 	cptr += 5;
   3597     else if ((c == 'e' || c == 'E') &&
   3598 	     ((c = cptr[2]) == 'm' || c == 'M') &&
   3599 	     ((c = cptr[3]) == 'p' || c == 'P') &&
   3600 	     ((c = cptr[4]) == 't' || c == 'T') &&
   3601 	     ((c = cptr[5]) == 'y' || c == 'Y') &&
   3602 	     ((c = cptr[6], !IS_IDENT(c))))
   3603     {
   3604 	cptr += 6;
   3605 	return (1);
   3606     }
   3607     else
   3608 	syntax_error(lineno, line, cptr);
   3609 
   3610     c = nextc();
   3611     if (isalpha(UCH(c)) || c == '_' || c == '.' || c == '$')
   3612 	bp = get_name();
   3613     else if (c == '\'' || c == '"')
   3614 	bp = get_literal();
   3615     else
   3616     {
   3617 	syntax_error(lineno, line, cptr);
   3618 	/*NOTREACHED */
   3619     }
   3620 
   3621     if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
   3622 	prec_redeclared();
   3623 
   3624     rprec[nrules] = bp->prec;
   3625     rassoc[nrules] = bp->assoc;
   3626     return (0);
   3627 }
   3628 
   3629 static void
   3630 read_grammar(void)
   3631 {
   3632     initialize_grammar();
   3633     advance_to_start();
   3634 
   3635     for (;;)
   3636     {
   3637 	int c = nextc();
   3638 
   3639 	if (c == EOF)
   3640 	    break;
   3641 	if (isalpha(UCH(c))
   3642 	    || c == '_'
   3643 	    || c == '.'
   3644 	    || c == '$'
   3645 	    || c == '\''
   3646 	    || c == '"')
   3647 	{
   3648 	    add_symbol();
   3649 	}
   3650 	else if (c == L_CURL || c == '='
   3651 #if defined(YYBTYACC)
   3652 		 || (backtrack && c == L_BRAC)
   3653 #endif
   3654 	    )
   3655 	{
   3656 	    copy_action();
   3657 	}
   3658 	else if (c == '|')
   3659 	{
   3660 	    end_rule();
   3661 	    start_rule(plhs[nrules - 1], 0);
   3662 	    ++cptr;
   3663 	}
   3664 	else if (c == '%')
   3665 	{
   3666 	    if (mark_symbol())
   3667 		break;
   3668 	}
   3669 	else
   3670 	    syntax_error(lineno, line, cptr);
   3671     }
   3672     end_rule();
   3673 #if defined(YYBTYACC)
   3674     if (goal->args > 0)
   3675 	start_requires_args(goal->name);
   3676 #endif
   3677 }
   3678 
   3679 static void
   3680 free_tags(void)
   3681 {
   3682     int i;
   3683 
   3684     if (tag_table == NULL)
   3685 	return;
   3686 
   3687     for (i = 0; i < ntags; ++i)
   3688     {
   3689 	assert(tag_table[i]);
   3690 	FREE(tag_table[i]);
   3691     }
   3692     FREE(tag_table);
   3693 }
   3694 
   3695 static void
   3696 pack_names(void)
   3697 {
   3698     bucket *bp;
   3699     char *p;
   3700     char *t;
   3701 
   3702     name_pool_size = 13;	/* 13 == sizeof("$end") + sizeof("$accept") */
   3703     for (bp = first_symbol; bp; bp = bp->next)
   3704 	name_pool_size += strlen(bp->name) + 1;
   3705 
   3706     name_pool = TMALLOC(char, name_pool_size);
   3707     NO_SPACE(name_pool);
   3708 
   3709     strlcpy(name_pool, "$accept", name_pool_size);
   3710     strlcpy(name_pool + 8, "$end", name_pool_size - 8);
   3711     t = name_pool + 13;
   3712     for (bp = first_symbol; bp; bp = bp->next)
   3713     {
   3714 	const char *s = bp->name;
   3715 
   3716 	p = t;
   3717 	while ((*t++ = *s++) != 0)
   3718 	{
   3719 	    ;
   3720 	}
   3721 	FREE(bp->name);
   3722 	bp->name = p;
   3723     }
   3724 }
   3725 
   3726 static void
   3727 check_symbols(void)
   3728 {
   3729     bucket *bp;
   3730 
   3731     if (goal->class == UNKNOWN)
   3732 	undefined_goal(goal->name);
   3733 
   3734     for (bp = first_symbol; bp; bp = bp->next)
   3735     {
   3736 	if (bp->class == UNKNOWN)
   3737 	{
   3738 	    undefined_symbol_warning(bp->name);
   3739 	    bp->class = TERM;
   3740 	}
   3741     }
   3742 }
   3743 
   3744 static void
   3745 protect_string(char *src, char **des)
   3746 {
   3747     *des = src;
   3748     if (src)
   3749     {
   3750 	const char *s;
   3751 	char *d;
   3752 
   3753 	unsigned len = 1;
   3754 
   3755 	s = src;
   3756 	while (*s)
   3757 	{
   3758 	    if ('\\' == *s || '"' == *s)
   3759 		len++;
   3760 	    s++;
   3761 	    len++;
   3762 	}
   3763 
   3764 	*des = d = TMALLOC(char, len);
   3765 	NO_SPACE(d);
   3766 
   3767 	s = src;
   3768 	while (*s)
   3769 	{
   3770 	    if ('\\' == *s || '"' == *s)
   3771 		*d++ = '\\';
   3772 	    *d++ = *s++;
   3773 	}
   3774 	*d = '\0';
   3775     }
   3776 }
   3777 
   3778 static void
   3779 pack_symbols(void)
   3780 {
   3781     bucket *bp;
   3782     bucket **v;
   3783     Value_t i, j, k, n;
   3784 #if defined(YYBTYACC)
   3785     Value_t max_tok_pval;
   3786 #endif
   3787 
   3788     nsyms = 2;
   3789     ntokens = 1;
   3790     for (bp = first_symbol; bp; bp = bp->next)
   3791     {
   3792 	++nsyms;
   3793 	if (bp->class == TERM)
   3794 	    ++ntokens;
   3795     }
   3796     start_symbol = (Value_t)ntokens;
   3797     nvars = (Value_t)(nsyms - ntokens);
   3798 
   3799     symbol_name = TMALLOC(char *, nsyms);
   3800     NO_SPACE(symbol_name);
   3801 
   3802     symbol_value = TMALLOC(Value_t, nsyms);
   3803     NO_SPACE(symbol_value);
   3804 
   3805     symbol_prec = TMALLOC(Value_t, nsyms);
   3806     NO_SPACE(symbol_prec);
   3807 
   3808     symbol_assoc = TMALLOC(char, nsyms);
   3809     NO_SPACE(symbol_assoc);
   3810 
   3811 #if defined(YYBTYACC)
   3812     symbol_pval = TMALLOC(Value_t, nsyms);
   3813     NO_SPACE(symbol_pval);
   3814 
   3815     if (destructor)
   3816     {
   3817 	symbol_destructor = CALLOC(sizeof(char *), nsyms);
   3818 	NO_SPACE(symbol_destructor);
   3819 
   3820 	symbol_type_tag = CALLOC(sizeof(char *), nsyms);
   3821 	NO_SPACE(symbol_type_tag);
   3822     }
   3823 #endif
   3824 
   3825     v = TMALLOC(bucket *, nsyms);
   3826     NO_SPACE(v);
   3827 
   3828     v[0] = NULL;
   3829     v[start_symbol] = NULL;
   3830 
   3831     i = 1;
   3832     j = (Value_t)(start_symbol + 1);
   3833     for (bp = first_symbol; bp; bp = bp->next)
   3834     {
   3835 	if (bp->class == TERM)
   3836 	    v[i++] = bp;
   3837 	else
   3838 	    v[j++] = bp;
   3839     }
   3840     assert(i == ntokens && j == nsyms);
   3841 
   3842     for (i = 1; i < ntokens; ++i)
   3843 	v[i]->index = i;
   3844 
   3845     goal->index = (Index_t)(start_symbol + 1);
   3846     k = (Value_t)(start_symbol + 2);
   3847     while (++i < nsyms)
   3848 	if (v[i] != goal)
   3849 	{
   3850 	    v[i]->index = k;
   3851 	    ++k;
   3852 	}
   3853 
   3854     goal->value = 0;
   3855     k = 1;
   3856     for (i = (Value_t)(start_symbol + 1); i < nsyms; ++i)
   3857     {
   3858 	if (v[i] != goal)
   3859 	{
   3860 	    v[i]->value = k;
   3861 	    ++k;
   3862 	}
   3863     }
   3864 
   3865     k = 0;
   3866     for (i = 1; i < ntokens; ++i)
   3867     {
   3868 	n = v[i]->value;
   3869 	if (n > 256)
   3870 	{
   3871 	    for (j = k++; j > 0 && symbol_value[j - 1] > n; --j)
   3872 		symbol_value[j] = symbol_value[j - 1];
   3873 	    symbol_value[j] = n;
   3874 	}
   3875     }
   3876 
   3877     assert(v[1] != NULL);
   3878 
   3879     if (v[1]->value == UNDEFINED)
   3880 	v[1]->value = 256;
   3881 
   3882     j = 0;
   3883     n = 257;
   3884     for (i = 2; i < ntokens; ++i)
   3885     {
   3886 	if (v[i]->value == UNDEFINED)
   3887 	{
   3888 	    while (j < k && n == symbol_value[j])
   3889 	    {
   3890 		while (++j < k && n == symbol_value[j])
   3891 		{
   3892 		    ;
   3893 		}
   3894 		++n;
   3895 	    }
   3896 	    v[i]->value = n;
   3897 	    ++n;
   3898 	}
   3899     }
   3900 
   3901     symbol_name[0] = name_pool + 8;
   3902     symbol_value[0] = 0;
   3903     symbol_prec[0] = 0;
   3904     symbol_assoc[0] = TOKEN;
   3905 #if defined(YYBTYACC)
   3906     symbol_pval[0] = 0;
   3907     max_tok_pval = 0;
   3908 #endif
   3909     for (i = 1; i < ntokens; ++i)
   3910     {
   3911 	symbol_name[i] = v[i]->name;
   3912 	symbol_value[i] = v[i]->value;
   3913 	symbol_prec[i] = v[i]->prec;
   3914 	symbol_assoc[i] = v[i]->assoc;
   3915 #if defined(YYBTYACC)
   3916 	symbol_pval[i] = v[i]->value;
   3917 	if (symbol_pval[i] > max_tok_pval)
   3918 	    max_tok_pval = symbol_pval[i];
   3919 	if (destructor)
   3920 	{
   3921 	    symbol_destructor[i] = v[i]->destructor;
   3922 	    symbol_type_tag[i] = v[i]->tag;
   3923 	}
   3924 #endif
   3925     }
   3926     symbol_name[start_symbol] = name_pool;
   3927     symbol_value[start_symbol] = -1;
   3928     symbol_prec[start_symbol] = 0;
   3929     symbol_assoc[start_symbol] = TOKEN;
   3930 #if defined(YYBTYACC)
   3931     symbol_pval[start_symbol] = (Value_t)(max_tok_pval + 1);
   3932 #endif
   3933     for (++i; i < nsyms; ++i)
   3934     {
   3935 	k = v[i]->index;
   3936 	symbol_name[k] = v[i]->name;
   3937 	symbol_value[k] = v[i]->value;
   3938 	symbol_prec[k] = v[i]->prec;
   3939 	symbol_assoc[k] = v[i]->assoc;
   3940 #if defined(YYBTYACC)
   3941 	symbol_pval[k] = (Value_t)((max_tok_pval + 1) + v[i]->value + 1);
   3942 	if (destructor)
   3943 	{
   3944 	    symbol_destructor[k] = v[i]->destructor;
   3945 	    symbol_type_tag[k] = v[i]->tag;
   3946 	}
   3947 #endif
   3948     }
   3949 
   3950     if (gflag)
   3951     {
   3952 	symbol_pname = TMALLOC(char *, nsyms);
   3953 	NO_SPACE(symbol_pname);
   3954 
   3955 	for (i = 0; i < nsyms; ++i)
   3956 	    protect_string(symbol_name[i], &(symbol_pname[i]));
   3957     }
   3958 
   3959     FREE(v);
   3960 }
   3961 
   3962 static void
   3963 pack_grammar(void)
   3964 {
   3965     int i;
   3966     Value_t j;
   3967 
   3968     ritem = TMALLOC(Value_t, nitems);
   3969     NO_SPACE(ritem);
   3970 
   3971     rlhs = TMALLOC(Value_t, nrules);
   3972     NO_SPACE(rlhs);
   3973 
   3974     rrhs = TMALLOC(Value_t, nrules + 1);
   3975     NO_SPACE(rrhs);
   3976 
   3977     rprec = TREALLOC(Value_t, rprec, nrules);
   3978     NO_SPACE(rprec);
   3979 
   3980     rassoc = TREALLOC(Assoc_t, rassoc, nrules);
   3981     NO_SPACE(rassoc);
   3982 
   3983     ritem[0] = -1;
   3984     ritem[1] = goal->index;
   3985     ritem[2] = 0;
   3986     ritem[3] = -2;
   3987     rlhs[0] = 0;
   3988     rlhs[1] = 0;
   3989     rlhs[2] = start_symbol;
   3990     rrhs[0] = 0;
   3991     rrhs[1] = 0;
   3992     rrhs[2] = 1;
   3993 
   3994     j = 4;
   3995     for (i = 3; i < nrules; ++i)
   3996     {
   3997 	Assoc_t assoc;
   3998 	Value_t prec2;
   3999 
   4000 #if defined(YYBTYACC)
   4001 	if (plhs[i]->args > 0)
   4002 	{
   4003 	    if (plhs[i]->argnames)
   4004 	    {
   4005 		FREE(plhs[i]->argnames);
   4006 		plhs[i]->argnames = NULL;
   4007 	    }
   4008 	    if (plhs[i]->argtags)
   4009 	    {
   4010 		FREE(plhs[i]->argtags);
   4011 		plhs[i]->argtags = NULL;
   4012 	    }
   4013 	}
   4014 #endif /* defined(YYBTYACC) */
   4015 	rlhs[i] = plhs[i]->index;
   4016 	rrhs[i] = j;
   4017 	assoc = TOKEN;
   4018 	prec2 = 0;
   4019 	while (pitem[j])
   4020 	{
   4021 	    ritem[j] = pitem[j]->index;
   4022 	    if (pitem[j]->class == TERM)
   4023 	    {
   4024 		prec2 = pitem[j]->prec;
   4025 		assoc = pitem[j]->assoc;
   4026 	    }
   4027 	    ++j;
   4028 	}
   4029 	ritem[j] = (Value_t)-i;
   4030 	++j;
   4031 	if (rprec[i] == UNDEFINED)
   4032 	{
   4033 	    rprec[i] = prec2;
   4034 	    rassoc[i] = assoc;
   4035 	}
   4036     }
   4037     rrhs[i] = j;
   4038 
   4039     FREE(plhs);
   4040     FREE(pitem);
   4041 #if defined(YYBTYACC)
   4042     clean_arg_cache();
   4043 #endif
   4044 }
   4045 
   4046 static void
   4047 print_grammar(void)
   4048 {
   4049     int i, k;
   4050     size_t j, spacing = 0;
   4051     FILE *f = verbose_file;
   4052 
   4053     if (!vflag)
   4054 	return;
   4055 
   4056     k = 1;
   4057     for (i = 2; i < nrules; ++i)
   4058     {
   4059 	if (rlhs[i] != rlhs[i - 1])
   4060 	{
   4061 	    if (i != 2)
   4062 		fprintf(f, "\n");
   4063 	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
   4064 	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
   4065 	}
   4066 	else
   4067 	{
   4068 	    fprintf(f, "%4d  ", i - 2);
   4069 	    j = spacing;
   4070 	    while (j-- != 0)
   4071 		putc(' ', f);
   4072 	    putc('|', f);
   4073 	}
   4074 
   4075 	while (ritem[k] >= 0)
   4076 	{
   4077 	    fprintf(f, " %s", symbol_name[ritem[k]]);
   4078 	    ++k;
   4079 	}
   4080 	++k;
   4081 	putc('\n', f);
   4082     }
   4083 }
   4084 
   4085 #if defined(YYBTYACC)
   4086 static void
   4087 finalize_destructors(void)
   4088 {
   4089     int i;
   4090     bucket *bp;
   4091 
   4092     for (i = 2; i < nsyms; ++i)
   4093     {
   4094 	char *tag = symbol_type_tag[i];
   4095 
   4096 	if (symbol_destructor[i] == NULL)
   4097 	{
   4098 	    if (tag == NULL)
   4099 	    {			/* use <> destructor, if there is one */
   4100 		if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
   4101 		{
   4102 		    symbol_destructor[i] = TMALLOC(char,
   4103 						   strlen(bp->destructor) + 1);
   4104 		    NO_SPACE(symbol_destructor[i]);
   4105 		    strcpy(symbol_destructor[i], bp->destructor);
   4106 		}
   4107 	    }
   4108 	    else
   4109 	    {			/* use type destructor for this tag, if there is one */
   4110 		bp = lookup_type_destructor(tag);
   4111 		if (bp->destructor != NULL)
   4112 		{
   4113 		    symbol_destructor[i] = TMALLOC(char,
   4114 						   strlen(bp->destructor) + 1);
   4115 		    NO_SPACE(symbol_destructor[i]);
   4116 		    strcpy(symbol_destructor[i], bp->destructor);
   4117 		}
   4118 		else
   4119 		{		/* use <*> destructor, if there is one */
   4120 		    if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
   4121 			/* replace "$$" with "(*val).tag" in destructor code */
   4122 			symbol_destructor[i]
   4123 			    = process_destructor_XX(bp->destructor, tag);
   4124 		}
   4125 	    }
   4126 	}
   4127 	else
   4128 	{			/* replace "$$" with "(*val)[.tag]" in destructor code */
   4129 	    char *destructor_source = symbol_destructor[i];
   4130 	    symbol_destructor[i]
   4131 		= process_destructor_XX(destructor_source, tag);
   4132 	    FREE(destructor_source);
   4133 	}
   4134     }
   4135     /* 'symbol_type_tag[]' elements are freed by 'free_tags()' */
   4136     DO_FREE(symbol_type_tag);	/* no longer needed */
   4137     if ((bp = default_destructor[UNTYPED_DEFAULT]) != NULL)
   4138     {
   4139 	FREE(bp->name);
   4140 	/* 'bp->tag' is a static value, don't free */
   4141 	FREE(bp->destructor);
   4142 	FREE(bp);
   4143     }
   4144     if ((bp = default_destructor[TYPED_DEFAULT]) != NULL)
   4145     {
   4146 	FREE(bp->name);
   4147 	/* 'bp->tag' is a static value, don't free */
   4148 	FREE(bp->destructor);
   4149 	FREE(bp);
   4150     }
   4151     if ((bp = default_destructor[TYPE_SPECIFIED]) != NULL)
   4152     {
   4153 	bucket *p;
   4154 	for (; bp; bp = p)
   4155 	{
   4156 	    p = bp->link;
   4157 	    FREE(bp->name);
   4158 	    /* 'bp->tag' freed by 'free_tags()' */
   4159 	    FREE(bp->destructor);
   4160 	    FREE(bp);
   4161 	}
   4162     }
   4163 }
   4164 #endif /* defined(YYBTYACC) */
   4165 
   4166 void
   4167 reader(void)
   4168 {
   4169     write_section(code_file, banner);
   4170     create_symbol_table();
   4171     read_declarations();
   4172     read_grammar();
   4173     free_symbol_table();
   4174     pack_names();
   4175     check_symbols();
   4176     pack_symbols();
   4177     pack_grammar();
   4178     free_symbols();
   4179     print_grammar();
   4180 #if defined(YYBTYACC)
   4181     if (destructor)
   4182 	finalize_destructors();
   4183 #endif
   4184     free_tags();
   4185 }
   4186 
   4187 #ifdef NO_LEAKS
   4188 static param *
   4189 free_declarations(param *list)
   4190 {
   4191     while (list != NULL)
   4192     {
   4193 	param *next = list->next;
   4194 	free(list->type);
   4195 	free(list->name);
   4196 	free(list->type2);
   4197 	free(list);
   4198 	list = next;
   4199     }
   4200     return list;
   4201 }
   4202 
   4203 void
   4204 reader_leaks(void)
   4205 {
   4206     lex_param = free_declarations(lex_param);
   4207     parse_param = free_declarations(parse_param);
   4208 
   4209     DO_FREE(line);
   4210     DO_FREE(rrhs);
   4211     DO_FREE(rlhs);
   4212     DO_FREE(rprec);
   4213     DO_FREE(ritem);
   4214     DO_FREE(rassoc);
   4215     DO_FREE(cache);
   4216     DO_FREE(name_pool);
   4217     DO_FREE(symbol_name);
   4218     DO_FREE(symbol_prec);
   4219     DO_FREE(symbol_assoc);
   4220     DO_FREE(symbol_value);
   4221 #if defined(YYBTYACC)
   4222     DO_FREE(symbol_pval);
   4223     DO_FREE(symbol_destructor);
   4224     DO_FREE(symbol_type_tag);
   4225 #endif
   4226 }
   4227 #endif
   4228