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