PageRenderTime 107ms CodeModel.GetById 17ms app.highlight 79ms RepoModel.GetById 1ms app.codeStats 1ms

/usr.bin/yacc/reader.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1924 lines | 1701 code | 186 blank | 37 comment | 474 complexity | 6b4a20320a9583d372b80dab8ea55ec2 MD5 | raw file
   1/*
   2 * Copyright (c) 1989 The Regents of the University of California.
   3 * All rights reserved.
   4 *
   5 * This code is derived from software contributed to Berkeley by
   6 * Robert Paul Corbett.
   7 *
   8 * Redistribution and use in source and binary forms, with or without
   9 * modification, are permitted provided that the following conditions
  10 * are met:
  11 * 1. Redistributions of source code must retain the above copyright
  12 *    notice, this list of conditions and the following disclaimer.
  13 * 2. Redistributions in binary form must reproduce the above copyright
  14 *    notice, this list of conditions and the following disclaimer in the
  15 *    documentation and/or other materials provided with the distribution.
  16 * 4. Neither the name of the University nor the names of its contributors
  17 *    may be used to endorse or promote products derived from this software
  18 *    without specific prior written permission.
  19 *
  20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30 * SUCH DAMAGE.
  31 */
  32
  33#if 0
  34#ifndef lint
  35static char sccsid[] = "@(#)reader.c	5.7 (Berkeley) 1/20/91";
  36#endif
  37#endif
  38
  39#include <sys/cdefs.h>
  40__FBSDID("$FreeBSD$");
  41
  42#include <limits.h>
  43#include <stdlib.h>
  44#include <string.h>
  45#include "defs.h"
  46
  47/*  The line size must be a positive integer.  One hundred was chosen	*/
  48/*  because few lines in Yacc input grammars exceed 100 characters.	*/
  49/*  Note that if a line exceeds LINESIZE characters, the line buffer	*/
  50/*  will be expanded to accommodate it.					*/
  51
  52#define LINESIZE 100
  53
  54char *cache;
  55int cinc, cache_size;
  56
  57int ntags, tagmax;
  58char **tag_table;
  59
  60char saw_eof, unionized;
  61char *cptr, *line;
  62int linesize;
  63
  64bucket *goal;
  65int prec;
  66int gensym;
  67char last_was_action;
  68
  69int maxitems;
  70bucket **pitem;
  71
  72int maxrules;
  73bucket **plhs;
  74
  75int name_pool_size;
  76char *name_pool;
  77
  78static const char line_format[] = "#line %d \"%s\"\n";
  79
  80static void add_symbol(void);
  81static void advance_to_start(void);
  82static void cachec(int);
  83static void check_symbols(void);
  84static void copy_action(void);
  85static void copy_ident(void);
  86static void copy_text(void);
  87static void copy_union(void);
  88static void declare_expect(int);
  89static void declare_start(void);
  90static void declare_tokens(int);
  91static void declare_types(void);
  92static char *dup_line(void);
  93static void end_rule(void);
  94static void expand_items(void);
  95static void expand_rules(void);
  96static void free_tags(void);
  97static void get_line(void);
  98static bucket *get_literal(void);
  99static bucket *get_name(void);
 100static int get_number(void);
 101static char *get_tag(void);
 102static int hexval(int);
 103static void initialize_grammar(void);
 104static void insert_empty_rule(void);
 105static int is_reserved(char *);
 106static int keyword(void);
 107static int mark_symbol(void);
 108static int nextc(void);
 109static void pack_grammar(void);
 110static void pack_names(void);
 111static void pack_symbols(void);
 112static void print_grammar(void);
 113static void read_declarations(void);
 114static void read_grammar(void);
 115static void skip_comment(void);
 116static void start_rule(bucket *, int);
 117
 118static void
 119cachec(int c)
 120{
 121    assert(cinc >= 0);
 122    if (cinc >= cache_size)
 123    {
 124	cache_size += 256;
 125	cache = realloc(cache, cache_size);
 126	if (cache == 0) no_space();
 127    }
 128    cache[cinc] = c;
 129    ++cinc;
 130}
 131
 132
 133static void
 134get_line(void)
 135{
 136    FILE *f = input_file;
 137    int c;
 138    int i;
 139
 140    if (saw_eof || (c = getc(f)) == EOF)
 141    {
 142	if (line) { free(line); line = 0; }
 143	cptr = 0;
 144	saw_eof = 1;
 145	return;
 146    }
 147
 148    if (line == 0 || linesize != (LINESIZE + 1))
 149    {
 150	if (line) free(line);
 151	linesize = LINESIZE + 1;
 152	line = malloc(linesize);
 153	if (line == 0) no_space();
 154    }
 155
 156    i = 0;
 157    ++lineno;
 158    for (;;)
 159    {
 160	line[i]  =  c;
 161	if (c == '\n') { cptr = line; return; }
 162	if (++i >= linesize)
 163	{
 164	    linesize += LINESIZE;
 165	    line = realloc(line, linesize);
 166	    if (line ==  0) no_space();
 167	}
 168	c = getc(f);
 169	if (c ==  EOF)
 170	{
 171	    line[i] = '\n';
 172	    saw_eof = 1;
 173	    cptr = line;
 174	    return;
 175	}
 176    }
 177}
 178
 179
 180static char *
 181dup_line(void)
 182{
 183    char *p, *s, *t;
 184
 185    if (line == 0) return (0);
 186    s = line;
 187    while (*s != '\n') ++s;
 188    p = malloc(s - line + 1);
 189    if (p == 0) no_space();
 190
 191    s = line;
 192    t = p;
 193    while ((*t++ = *s++) != '\n') continue;
 194    return (p);
 195}
 196
 197
 198static void
 199skip_comment(void)
 200{
 201    char *s;
 202
 203    int st_lineno = lineno;
 204    char *st_line = dup_line();
 205    char *st_cptr = st_line + (cptr - line);
 206
 207    s = cptr + 2;
 208    for (;;)
 209    {
 210	if (*s == '*' && s[1] == '/')
 211	{
 212	    cptr = s + 2;
 213	    free(st_line);
 214	    return;
 215	}
 216	if (*s == '\n')
 217	{
 218	    get_line();
 219	    if (line == 0)
 220		unterminated_comment(st_lineno, st_line, st_cptr);
 221	    s = cptr;
 222	}
 223	else
 224	    ++s;
 225    }
 226}
 227
 228
 229static int
 230nextc(void)
 231{
 232    char *s;
 233
 234    if (line == 0)
 235    {
 236	get_line();
 237	if (line == 0)
 238	    return (EOF);
 239    }
 240
 241    s = cptr;
 242    for (;;)
 243    {
 244	switch (*s)
 245	{
 246	case '\n':
 247	    get_line();
 248	    if (line == 0) return (EOF);
 249	    s = cptr;
 250	    break;
 251
 252	case ' ':
 253	case '\t':
 254	case '\f':
 255	case '\r':
 256	case '\v':
 257	case ',':
 258	case ';':
 259	    ++s;
 260	    break;
 261
 262	case '\\':
 263	    cptr = s;
 264	    return ('%');
 265
 266	case '/':
 267	    if (s[1] == '*')
 268	    {
 269		cptr = s;
 270		skip_comment();
 271		s = cptr;
 272		break;
 273	    }
 274	    else if (s[1] == '/')
 275	    {
 276		get_line();
 277		if (line == 0) return (EOF);
 278		s = cptr;
 279		break;
 280	    }
 281	    /* FALLTHROUGH */
 282
 283	default:
 284	    cptr = s;
 285	    return (*s);
 286	}
 287    }
 288}
 289
 290
 291static int
 292keyword(void)
 293{
 294    int c;
 295    char *t_cptr = cptr;
 296
 297    c = *++cptr;
 298    if (isalpha(c))
 299    {
 300	cinc = 0;
 301	for (;;)
 302	{
 303	    if (isalpha(c))
 304	    {
 305		if (isupper(c)) c = tolower(c);
 306		cachec(c);
 307	    }
 308	    else if (isdigit(c) || c == '_' || c == '.' || c == '$')
 309		cachec(c);
 310	    else
 311		break;
 312	    c = *++cptr;
 313	}
 314	cachec(NUL);
 315
 316	if (strcmp(cache, "token") == 0 || strcmp(cache, "term") == 0)
 317	    return (TOKEN);
 318	if (strcmp(cache, "type") == 0)
 319	    return (TYPE);
 320	if (strcmp(cache, "left") == 0)
 321	    return (LEFT);
 322	if (strcmp(cache, "right") == 0)
 323	    return (RIGHT);
 324	if (strcmp(cache, "nonassoc") == 0 || strcmp(cache, "binary") == 0)
 325	    return (NONASSOC);
 326	if (strcmp(cache, "start") == 0)
 327	    return (START);
 328	if (strcmp(cache, "union") == 0)
 329	    return (UNION);
 330	if (strcmp(cache, "ident") == 0)
 331	    return (IDENT);
 332	if (strcmp(cache, "expect") == 0)
 333	    return (EXPECT);
 334    }
 335    else
 336    {
 337	++cptr;
 338	if (c == '{')
 339	    return (TEXT);
 340	if (c == '%' || c == '\\')
 341	    return (MARK);
 342	if (c == '<')
 343	    return (LEFT);
 344	if (c == '>')
 345	    return (RIGHT);
 346	if (c == '0')
 347	    return (TOKEN);
 348	if (c == '2')
 349	    return (NONASSOC);
 350    }
 351    syntax_error(lineno, line, t_cptr);
 352    /*NOTREACHED*/
 353    return (0);
 354}
 355
 356
 357static void
 358copy_ident(void)
 359{
 360    int c;
 361    FILE *f = output_file;
 362
 363    c = nextc();
 364    if (c == EOF) unexpected_EOF();
 365    if (c != '"') syntax_error(lineno, line, cptr);
 366    ++outline;
 367    fprintf(f, "#ident \"");
 368    for (;;)
 369    {
 370	c = *++cptr;
 371	if (c == '\n')
 372	{
 373	    fprintf(f, "\"\n");
 374	    return;
 375	}
 376	putc(c, f);
 377	if (c == '"')
 378	{
 379	    putc('\n', f);
 380	    ++cptr;
 381	    return;
 382	}
 383    }
 384}
 385
 386
 387static void
 388copy_text(void)
 389{
 390    int c;
 391    int quote;
 392    FILE *f = text_file;
 393    int need_newline = 0;
 394    int t_lineno = lineno;
 395    char *t_line = dup_line();
 396    char *t_cptr = t_line + (cptr - line - 2);
 397
 398    if (*cptr == '\n')
 399    {
 400	get_line();
 401	if (line == 0)
 402	    unterminated_text(t_lineno, t_line, t_cptr);
 403    }
 404    if (!lflag) fprintf(f, line_format, lineno, input_file_name);
 405
 406loop:
 407    c = *cptr++;
 408    switch (c)
 409    {
 410    case '\n':
 411    next_line:
 412	putc('\n', f);
 413	need_newline = 0;
 414	get_line();
 415	if (line) goto loop;
 416	unterminated_text(t_lineno, t_line, t_cptr);
 417
 418    case '\'':
 419    case '"':
 420	{
 421	    int s_lineno = lineno;
 422	    char *s_line = dup_line();
 423	    char *s_cptr = s_line + (cptr - line - 1);
 424
 425	    quote = c;
 426	    putc(c, f);
 427	    for (;;)
 428	    {
 429		c = *cptr++;
 430		putc(c, f);
 431		if (c == quote)
 432		{
 433		    need_newline = 1;
 434		    free(s_line);
 435		    goto loop;
 436		}
 437		if (c == '\n')
 438		    unterminated_string(s_lineno, s_line, s_cptr);
 439		if (c == '\\')
 440		{
 441		    c = *cptr++;
 442		    putc(c, f);
 443		    if (c == '\n')
 444		    {
 445			get_line();
 446			if (line == 0)
 447			    unterminated_string(s_lineno, s_line, s_cptr);
 448		    }
 449		}
 450	    }
 451	}
 452
 453    case '/':
 454	putc(c, f);
 455	need_newline = 1;
 456	c = *cptr;
 457	if (c == '/')
 458	{
 459	    putc('*', f);
 460	    while ((c = *++cptr) != '\n')
 461	    {
 462		if (c == '*' && cptr[1] == '/')
 463		    fprintf(f, "* ");
 464		else
 465		    putc(c, f);
 466	    }
 467	    fprintf(f, "*/");
 468	    goto next_line;
 469	}
 470	if (c == '*')
 471	{
 472	    int c_lineno = lineno;
 473	    char *c_line = dup_line();
 474	    char *c_cptr = c_line + (cptr - line - 1);
 475
 476	    putc('*', f);
 477	    ++cptr;
 478	    for (;;)
 479	    {
 480		c = *cptr++;
 481		putc(c, f);
 482		if (c == '*' && *cptr == '/')
 483		{
 484		    putc('/', f);
 485		    ++cptr;
 486		    free(c_line);
 487		    goto loop;
 488		}
 489		if (c == '\n')
 490		{
 491		    get_line();
 492		    if (line == 0)
 493			unterminated_comment(c_lineno, c_line, c_cptr);
 494		}
 495	    }
 496	}
 497	need_newline = 1;
 498	goto loop;
 499
 500    case '%':
 501    case '\\':
 502	if (*cptr == '}')
 503	{
 504	    if (need_newline) putc('\n', f);
 505	    ++cptr;
 506	    free(t_line);
 507	    return;
 508	}
 509	/* FALLTHROUGH */
 510
 511    default:
 512	putc(c, f);
 513	need_newline = 1;
 514	goto loop;
 515    }
 516}
 517
 518
 519static void
 520copy_union(void)
 521{
 522    int c;
 523    int quote;
 524    int depth;
 525    int u_lineno = lineno;
 526    char *u_line = dup_line();
 527    char *u_cptr = u_line + (cptr - line - 6);
 528
 529    if (unionized) over_unionized(cptr - 6);
 530    unionized = 1;
 531
 532    if (!lflag)
 533	fprintf(text_file, line_format, lineno, input_file_name);
 534
 535    fprintf(text_file, "typedef union");
 536    if (dflag) fprintf(union_file, "typedef union");
 537
 538    depth = 0;
 539loop:
 540    c = *cptr++;
 541    putc(c, text_file);
 542    if (dflag) putc(c, union_file);
 543    switch (c)
 544    {
 545    case '\n':
 546    next_line:
 547	get_line();
 548	if (line == 0) unterminated_union(u_lineno, u_line, u_cptr);
 549	goto loop;
 550
 551    case '{':
 552	++depth;
 553	goto loop;
 554
 555    case '}':
 556	if (--depth == 0)
 557	{
 558	    fprintf(text_file, " YYSTYPE;\n");
 559	    free(u_line);
 560	    return;
 561	}
 562	goto loop;
 563
 564    case '\'':
 565    case '"':
 566	{
 567	    int s_lineno = lineno;
 568	    char *s_line = dup_line();
 569	    char *s_cptr = s_line + (cptr - line - 1);
 570
 571	    quote = c;
 572	    for (;;)
 573	    {
 574		c = *cptr++;
 575		putc(c, text_file);
 576		if (dflag) putc(c, union_file);
 577		if (c == quote)
 578		{
 579		    free(s_line);
 580		    goto loop;
 581		}
 582		if (c == '\n')
 583		    unterminated_string(s_lineno, s_line, s_cptr);
 584		if (c == '\\')
 585		{
 586		    c = *cptr++;
 587		    putc(c, text_file);
 588		    if (dflag) putc(c, union_file);
 589		    if (c == '\n')
 590		    {
 591			get_line();
 592			if (line == 0)
 593			    unterminated_string(s_lineno, s_line, s_cptr);
 594		    }
 595		}
 596	    }
 597	}
 598
 599    case '/':
 600	c = *cptr;
 601	if (c == '/')
 602	{
 603	    putc('*', text_file);
 604	    if (dflag) putc('*', union_file);
 605	    while ((c = *++cptr) != '\n')
 606	    {
 607		if (c == '*' && cptr[1] == '/')
 608		{
 609		    fprintf(text_file, "* ");
 610		    if (dflag) fprintf(union_file, "* ");
 611		}
 612		else
 613		{
 614		    putc(c, text_file);
 615		    if (dflag) putc(c, union_file);
 616		}
 617	    }
 618	    fprintf(text_file, "*/\n");
 619	    if (dflag) fprintf(union_file, "*/\n");
 620	    goto next_line;
 621	}
 622	if (c == '*')
 623	{
 624	    int c_lineno = lineno;
 625	    char *c_line = dup_line();
 626	    char *c_cptr = c_line + (cptr - line - 1);
 627
 628	    putc('*', text_file);
 629	    if (dflag) putc('*', union_file);
 630	    ++cptr;
 631	    for (;;)
 632	    {
 633		c = *cptr++;
 634		putc(c, text_file);
 635		if (dflag) putc(c, union_file);
 636		if (c == '*' && *cptr == '/')
 637		{
 638		    putc('/', text_file);
 639		    if (dflag) putc('/', union_file);
 640		    ++cptr;
 641		    free(c_line);
 642		    goto loop;
 643		}
 644		if (c == '\n')
 645		{
 646		    get_line();
 647		    if (line == 0)
 648			unterminated_comment(c_lineno, c_line, c_cptr);
 649		}
 650	    }
 651	}
 652	goto loop;
 653
 654    default:
 655	goto loop;
 656    }
 657}
 658
 659
 660static int
 661hexval(int c)
 662{
 663    if (c >= '0' && c <= '9')
 664	return (c - '0');
 665    if (c >= 'A' && c <= 'F')
 666	return (c - 'A' + 10);
 667    if (c >= 'a' && c <= 'f')
 668	return (c - 'a' + 10);
 669    return (-1);
 670}
 671
 672
 673static bucket *
 674get_literal(void)
 675{
 676    int c, quote;
 677    int i;
 678    int n;
 679    char *s;
 680    bucket *bp;
 681    int s_lineno = lineno;
 682    char *s_line = dup_line();
 683    char *s_cptr = s_line + (cptr - line);
 684
 685    quote = *cptr++;
 686    cinc = 0;
 687    for (;;)
 688    {
 689	c = *cptr++;
 690	if (c == quote) break;
 691	if (c == '\n') unterminated_string(s_lineno, s_line, s_cptr);
 692	if (c == '\\')
 693	{
 694	    char *c_cptr = cptr - 1;
 695
 696	    c = *cptr++;
 697	    switch (c)
 698	    {
 699	    case '\n':
 700		get_line();
 701		if (line == 0) unterminated_string(s_lineno, s_line, s_cptr);
 702		continue;
 703
 704	    case '0': case '1': case '2': case '3':
 705	    case '4': case '5': case '6': case '7':
 706		n = c - '0';
 707		c = *cptr;
 708		if (IS_OCTAL(c))
 709		{
 710		    n = (n << 3) + (c - '0');
 711		    c = *++cptr;
 712		    if (IS_OCTAL(c))
 713		    {
 714			n = (n << 3) + (c - '0');
 715			++cptr;
 716		    }
 717		}
 718		if (n > (int)UCHAR_MAX) illegal_character(c_cptr);
 719		c = n;
 720	    	break;
 721
 722	    case 'x':
 723		c = *cptr++;
 724		n = hexval(c);
 725		if (n < 0 || n >= 16)
 726		    illegal_character(c_cptr);
 727		for (;;)
 728		{
 729		    c = *cptr;
 730		    i = hexval(c);
 731		    if (i < 0 || i >= 16) break;
 732		    ++cptr;
 733		    n = (n << 4) + i;
 734		    if (n > (int)UCHAR_MAX) illegal_character(c_cptr);
 735		}
 736		c = n;
 737		break;
 738
 739	    case 'a': c = 7; break;
 740	    case 'b': c = '\b'; break;
 741	    case 'f': c = '\f'; break;
 742	    case 'n': c = '\n'; break;
 743	    case 'r': c = '\r'; break;
 744	    case 't': c = '\t'; break;
 745	    case 'v': c = '\v'; break;
 746	    }
 747	}
 748	cachec(c);
 749    }
 750    free(s_line);
 751
 752    n = cinc;
 753    s = malloc(n);
 754    if (s == 0) no_space();
 755
 756    for (i = 0; i < n; ++i)
 757	s[i] = cache[i];
 758
 759    cinc = 0;
 760    if (n == 1)
 761	cachec('\'');
 762    else
 763	cachec('"');
 764
 765    for (i = 0; i < n; ++i)
 766    {
 767	c = ((unsigned char *)s)[i];
 768	if (c == '\\' || c == cache[0])
 769	{
 770	    cachec('\\');
 771	    cachec(c);
 772	}
 773	else if (isprint(c))
 774	    cachec(c);
 775	else
 776	{
 777	    cachec('\\');
 778	    switch (c)
 779	    {
 780	    case 7: cachec('a'); break;
 781	    case '\b': cachec('b'); break;
 782	    case '\f': cachec('f'); break;
 783	    case '\n': cachec('n'); break;
 784	    case '\r': cachec('r'); break;
 785	    case '\t': cachec('t'); break;
 786	    case '\v': cachec('v'); break;
 787	    default:
 788		cachec(((c >> 6) & 7) + '0');
 789		cachec(((c >> 3) & 7) + '0');
 790		cachec((c & 7) + '0');
 791		break;
 792	    }
 793	}
 794    }
 795
 796    if (n == 1)
 797	cachec('\'');
 798    else
 799	cachec('"');
 800
 801    cachec(NUL);
 802    bp = lookup(cache);
 803    bp->class = TERM;
 804    if (n == 1 && bp->value == UNDEFINED)
 805	bp->value = *(unsigned char *)s;
 806    free(s);
 807
 808    return (bp);
 809}
 810
 811
 812static int
 813is_reserved(char *name)
 814{
 815    char *s;
 816
 817    if (strcmp(name, ".") == 0 ||
 818	    strcmp(name, "$accept") == 0 ||
 819	    strcmp(name, "$end") == 0)
 820	return (1);
 821
 822    if (name[0] == '$' && name[1] == '$' && isdigit(name[2]))
 823    {
 824	s = name + 3;
 825	while (isdigit(*s)) ++s;
 826	if (*s == NUL) return (1);
 827    }
 828
 829    return (0);
 830}
 831
 832
 833static bucket *
 834get_name(void)
 835{
 836    int c;
 837
 838    cinc = 0;
 839    for (c = *cptr; IS_IDENT(c); c = *++cptr)
 840	cachec(c);
 841    cachec(NUL);
 842
 843    if (is_reserved(cache)) used_reserved(cache);
 844
 845    return (lookup(cache));
 846}
 847
 848
 849static int
 850get_number(void)
 851{
 852    int c;
 853    int n;
 854
 855    n = 0;
 856    for (c = *cptr; isdigit(c); c = *++cptr)
 857	n = 10*n + (c - '0');
 858
 859    return (n);
 860}
 861
 862
 863static char *
 864get_tag(void)
 865{
 866    int c;
 867    int i;
 868    char *s;
 869    int t_lineno = lineno;
 870    char *t_line = dup_line();
 871    char *t_cptr = t_line + (cptr - line);
 872
 873    ++cptr;
 874    c = nextc();
 875    if (c == EOF) unexpected_EOF();
 876    if (!isalpha(c) && c != '_' && c != '$')
 877	illegal_tag(t_lineno, t_line, t_cptr);
 878
 879    cinc = 0;
 880    do { cachec(c); c = *++cptr; } while (IS_IDENT(c));
 881    cachec(NUL);
 882
 883    c = nextc();
 884    if (c == EOF) unexpected_EOF();
 885    if (c != '>')
 886	illegal_tag(t_lineno, t_line, t_cptr);
 887    ++cptr;
 888
 889    for (i = 0; i < ntags; ++i)
 890    {
 891	if (strcmp(cache, tag_table[i]) == 0)
 892	    return (tag_table[i]);
 893    }
 894
 895    if (ntags >= tagmax)
 896    {
 897	tagmax += 16;
 898	tag_table = (char **)
 899			(tag_table ? realloc(tag_table, tagmax*sizeof(char *))
 900				   : malloc(tagmax*sizeof(char *)));
 901	if (tag_table == 0) no_space();
 902    }
 903
 904    s = malloc(cinc);
 905    if  (s == 0) no_space();
 906    strcpy(s, cache);
 907    tag_table[ntags] = s;
 908    ++ntags;
 909    free(t_line);
 910    return (s);
 911}
 912
 913
 914static void
 915declare_tokens(int assoc)
 916{
 917    int c;
 918    bucket *bp;
 919    int value;
 920    char *tag = 0;
 921
 922    if (assoc != TOKEN) ++prec;
 923
 924    c = nextc();
 925    if (c == EOF) unexpected_EOF();
 926    if (c == '<')
 927    {
 928	tag = get_tag();
 929	c = nextc();
 930	if (c == EOF) unexpected_EOF();
 931    }
 932
 933    for (;;)
 934    {
 935	if (isalpha(c) || c == '_' || c == '.' || c == '$')
 936	    bp = get_name();
 937	else if (c == '\'' || c == '"')
 938	    bp = get_literal();
 939	else
 940	    return;
 941
 942	if (bp == goal) tokenized_start(bp->name);
 943	bp->class = TERM;
 944
 945	if (tag)
 946	{
 947	    if (bp->tag && tag != bp->tag)
 948		retyped_warning(bp->name);
 949	    bp->tag = tag;
 950	}
 951
 952	if (assoc != TOKEN)
 953	{
 954	    if (bp->prec && prec != bp->prec)
 955		reprec_warning(bp->name);
 956	    bp->assoc = assoc;
 957	    bp->prec = prec;
 958	}
 959
 960	c = nextc();
 961	if (c == EOF) unexpected_EOF();
 962	value = UNDEFINED;
 963	if (isdigit(c))
 964	{
 965	    value = get_number();
 966	    if (bp->value != UNDEFINED && value != bp->value)
 967		revalued_warning(bp->name);
 968	    bp->value = value;
 969	    c = nextc();
 970	    if (c == EOF) unexpected_EOF();
 971	}
 972    }
 973}
 974
 975
 976/*
 977 * %expect requires special handling
 978 * as it really isn't part of the yacc
 979 * grammar only a flag for yacc proper.
 980 */
 981static void
 982declare_expect(int assoc)
 983{
 984    int c;
 985
 986    if (assoc != EXPECT) ++prec;
 987
 988    /*
 989     * Stay away from nextc - doesn't
 990     * detect EOL and will read to EOF.
 991     */
 992    c = *++cptr;
 993    if (c == EOF) unexpected_EOF();
 994
 995    for(;;)
 996    {
 997	if (isdigit(c))
 998	{
 999	    SRexpect = get_number();
1000	    break;
1001	}
1002	/*
1003	 * Looking for number before EOL.
1004	 * Spaces, tabs, and numbers are ok,
1005	 * words, punc., etc. are syntax errors.
1006	 */
1007	else if (c == '\n' || isalpha(c) || !isspace(c))
1008	{
1009	    syntax_error(lineno, line, cptr);
1010	}
1011	else
1012	{
1013	    c = *++cptr;
1014	    if (c == EOF) unexpected_EOF();
1015	}
1016    }
1017}
1018
1019
1020static void
1021declare_types(void)
1022{
1023    int c;
1024    bucket *bp;
1025    char *tag;
1026
1027    c = nextc();
1028    if (c == EOF) unexpected_EOF();
1029    if (c != '<') syntax_error(lineno, line, cptr);
1030    tag = get_tag();
1031
1032    for (;;)
1033    {
1034	c = nextc();
1035	if (isalpha(c) || c == '_' || c == '.' || c == '$')
1036	    bp = get_name();
1037	else if (c == '\'' || c == '"')
1038	    bp = get_literal();
1039	else
1040	    return;
1041
1042	if (bp->tag && tag != bp->tag)
1043	    retyped_warning(bp->name);
1044	bp->tag = tag;
1045    }
1046}
1047
1048
1049static void
1050declare_start(void)
1051{
1052    int c;
1053    bucket *bp;
1054
1055    c = nextc();
1056    if (c == EOF) unexpected_EOF();
1057    if (!isalpha(c) && c != '_' && c != '.' && c != '$')
1058	syntax_error(lineno, line, cptr);
1059    bp = get_name();
1060    if (bp->class == TERM)
1061	terminal_start(bp->name);
1062    if (goal && goal != bp)
1063	restarted_warning();
1064    goal = bp;
1065}
1066
1067
1068static void
1069read_declarations(void)
1070{
1071    int c, k;
1072
1073    cache_size = 256;
1074    cache = malloc(cache_size);
1075    if (cache == 0) no_space();
1076
1077    for (;;)
1078    {
1079	c = nextc();
1080	if (c == EOF) unexpected_EOF();
1081	if (c != '%') syntax_error(lineno, line, cptr);
1082	switch (k = keyword())
1083	{
1084	case MARK:
1085	    return;
1086
1087	case IDENT:
1088	    copy_ident();
1089	    break;
1090
1091	case TEXT:
1092	    copy_text();
1093	    break;
1094
1095	case UNION:
1096	    copy_union();
1097	    break;
1098
1099	case TOKEN:
1100	case LEFT:
1101	case RIGHT:
1102	case NONASSOC:
1103	    declare_tokens(k);
1104	    break;
1105
1106	case EXPECT:
1107	    declare_expect(k);
1108	    break;
1109
1110	case TYPE:
1111	    declare_types();
1112	    break;
1113
1114	case START:
1115	    declare_start();
1116	    break;
1117	}
1118    }
1119}
1120
1121
1122static void
1123initialize_grammar(void)
1124{
1125    nitems = 4;
1126    maxitems = 300;
1127    pitem = malloc(maxitems*sizeof(bucket *));
1128    if (pitem == 0) no_space();
1129    pitem[0] = 0;
1130    pitem[1] = 0;
1131    pitem[2] = 0;
1132    pitem[3] = 0;
1133
1134    nrules = 3;
1135    maxrules = 100;
1136    plhs = malloc(maxrules*sizeof(bucket *));
1137    if (plhs == 0) no_space();
1138    plhs[0] = 0;
1139    plhs[1] = 0;
1140    plhs[2] = 0;
1141    rprec = malloc(maxrules*sizeof(short));
1142    if (rprec == 0) no_space();
1143    rprec[0] = 0;
1144    rprec[1] = 0;
1145    rprec[2] = 0;
1146    rassoc = malloc(maxrules*sizeof(char));
1147    if (rassoc == 0) no_space();
1148    rassoc[0] = TOKEN;
1149    rassoc[1] = TOKEN;
1150    rassoc[2] = TOKEN;
1151}
1152
1153
1154static void
1155expand_items(void)
1156{
1157    maxitems += 300;
1158    pitem = realloc(pitem, maxitems*sizeof(bucket *));
1159    if (pitem == 0) no_space();
1160}
1161
1162
1163static void
1164expand_rules(void)
1165{
1166    maxrules += 100;
1167    plhs = realloc(plhs, maxrules*sizeof(bucket *));
1168    if (plhs == 0) no_space();
1169    rprec = realloc(rprec, maxrules*sizeof(short));
1170    if (rprec == 0) no_space();
1171    rassoc = realloc(rassoc, maxrules*sizeof(char));
1172    if (rassoc == 0) no_space();
1173}
1174
1175
1176static void
1177advance_to_start(void)
1178{
1179    int c;
1180    bucket *bp;
1181    char *s_cptr;
1182    int s_lineno;
1183
1184    for (;;)
1185    {
1186	c = nextc();
1187	if (c != '%') break;
1188	s_cptr = cptr;
1189	switch (keyword())
1190	{
1191	case MARK:
1192	    no_grammar();
1193
1194	case TEXT:
1195	    copy_text();
1196	    break;
1197
1198	case START:
1199	    declare_start();
1200	    break;
1201
1202	default:
1203	    syntax_error(lineno, line, s_cptr);
1204	}
1205    }
1206
1207    c = nextc();
1208    if (!isalpha(c) && c != '_' && c != '.' && c != '_')
1209	syntax_error(lineno, line, cptr);
1210    bp = get_name();
1211    if (goal == 0)
1212    {
1213	if (bp->class == TERM)
1214	    terminal_start(bp->name);
1215	goal = bp;
1216    }
1217
1218    s_lineno = lineno;
1219    c = nextc();
1220    if (c == EOF) unexpected_EOF();
1221    if (c != ':') syntax_error(lineno, line, cptr);
1222    start_rule(bp, s_lineno);
1223    ++cptr;
1224}
1225
1226
1227static void
1228start_rule(bucket *bp, int s_lineno)
1229{
1230    if (bp->class == TERM)
1231	terminal_lhs(s_lineno);
1232    bp->class = NONTERM;
1233    if (nrules >= maxrules)
1234	expand_rules();
1235    plhs[nrules] = bp;
1236    rprec[nrules] = UNDEFINED;
1237    rassoc[nrules] = TOKEN;
1238}
1239
1240
1241static void
1242end_rule(void)
1243{
1244    int i;
1245
1246    if (!last_was_action && plhs[nrules]->tag)
1247    {
1248	for (i = nitems - 1; pitem[i]; --i) continue;
1249	if (pitem[i+1] == 0 || pitem[i+1]->tag != plhs[nrules]->tag)
1250	    default_action_warning();
1251    }
1252
1253    last_was_action = 0;
1254    if (nitems >= maxitems) expand_items();
1255    pitem[nitems] = 0;
1256    ++nitems;
1257    ++nrules;
1258}
1259
1260
1261static void
1262insert_empty_rule(void)
1263{
1264    bucket *bp, **bpp;
1265
1266    assert(cache);
1267    sprintf(cache, "$$%d", ++gensym);
1268    bp = make_bucket(cache);
1269    last_symbol->next = bp;
1270    last_symbol = bp;
1271    bp->tag = plhs[nrules]->tag;
1272    bp->class = NONTERM;
1273
1274    if ((nitems += 2) > maxitems)
1275	expand_items();
1276    bpp = pitem + nitems - 1;
1277    *bpp-- = bp;
1278    while ((bpp[0] = bpp[-1])) --bpp;
1279
1280    if (++nrules >= maxrules)
1281	expand_rules();
1282    plhs[nrules] = plhs[nrules-1];
1283    plhs[nrules-1] = bp;
1284    rprec[nrules] = rprec[nrules-1];
1285    rprec[nrules-1] = 0;
1286    rassoc[nrules] = rassoc[nrules-1];
1287    rassoc[nrules-1] = TOKEN;
1288}
1289
1290
1291static void
1292add_symbol(void)
1293{
1294    int c;
1295    bucket *bp;
1296    int s_lineno = lineno;
1297
1298    c = *cptr;
1299    if (c == '\'' || c == '"')
1300	bp = get_literal();
1301    else
1302	bp = get_name();
1303
1304    c = nextc();
1305    if (c == ':')
1306    {
1307	end_rule();
1308	start_rule(bp, s_lineno);
1309	++cptr;
1310	return;
1311    }
1312
1313    if (last_was_action)
1314	insert_empty_rule();
1315    last_was_action = 0;
1316
1317    if (++nitems > maxitems)
1318	expand_items();
1319    pitem[nitems-1] = bp;
1320}
1321
1322
1323static void
1324copy_action(void)
1325{
1326    int c;
1327    int i, n;
1328    int depth;
1329    int quote;
1330    char *tag;
1331    FILE *f = action_file;
1332    int a_lineno = lineno;
1333    char *a_line = dup_line();
1334    char *a_cptr = a_line + (cptr - line);
1335
1336    if (last_was_action)
1337	insert_empty_rule();
1338    last_was_action = 1;
1339
1340    fprintf(f, "case %d:\n", nrules - 2);
1341    if (!lflag)
1342	fprintf(f, line_format, lineno, input_file_name);
1343    if (*cptr == '=') ++cptr;
1344
1345    n = 0;
1346    for (i = nitems - 1; pitem[i]; --i) ++n;
1347
1348    depth = 0;
1349loop:
1350    c = *cptr;
1351    if (c == '$')
1352    {
1353	if (cptr[1] == '<')
1354	{
1355	    int d_lineno = lineno;
1356	    char *d_line = dup_line();
1357	    char *d_cptr = d_line + (cptr - line);
1358
1359	    ++cptr;
1360	    tag = get_tag();
1361	    c = *cptr;
1362	    if (c == '$')
1363	    {
1364		fprintf(f, "yyval.%s", tag);
1365		++cptr;
1366		free(d_line);
1367		goto loop;
1368	    }
1369	    else if (isdigit(c))
1370	    {
1371		i = get_number();
1372		if (i > n) dollar_warning(d_lineno, i);
1373		fprintf(f, "yyvsp[%d].%s", i - n, tag);
1374		free(d_line);
1375		goto loop;
1376	    }
1377	    else if (c == '-' && isdigit(cptr[1]))
1378	    {
1379		++cptr;
1380		i = -get_number() - n;
1381		fprintf(f, "yyvsp[%d].%s", i, tag);
1382		free(d_line);
1383		goto loop;
1384	    }
1385	    else
1386		dollar_error(d_lineno, d_line, d_cptr);
1387	}
1388	else if (cptr[1] == '$')
1389	{
1390	    if (ntags)
1391	    {
1392		tag = plhs[nrules]->tag;
1393		if (tag == 0) untyped_lhs();
1394		fprintf(f, "yyval.%s", tag);
1395	    }
1396	    else
1397		fprintf(f, "yyval");
1398	    cptr += 2;
1399	    goto loop;
1400	}
1401	else if (isdigit(cptr[1]))
1402	{
1403	    ++cptr;
1404	    i = get_number();
1405	    if (ntags)
1406	    {
1407		if (i <= 0 || i > n)
1408		    unknown_rhs(i);
1409		tag = pitem[nitems + i - n - 1]->tag;
1410		if (tag == 0) untyped_rhs(i, pitem[nitems + i - n - 1]->name);
1411		fprintf(f, "yyvsp[%d].%s", i - n, tag);
1412	    }
1413	    else
1414	    {
1415		if (i > n)
1416		    dollar_warning(lineno, i);
1417		fprintf(f, "yyvsp[%d]", i - n);
1418	    }
1419	    goto loop;
1420	}
1421	else if (cptr[1] == '-')
1422	{
1423	    cptr += 2;
1424	    i = get_number();
1425	    if (ntags)
1426		unknown_rhs(-i);
1427	    fprintf(f, "yyvsp[%d]", -i - n);
1428	    goto loop;
1429	}
1430    }
1431    if (isalpha(c) || c == '_' || c == '$')
1432    {
1433	do
1434	{
1435	    putc(c, f);
1436	    c = *++cptr;
1437	} while (isalnum(c) || c == '_' || c == '$');
1438	goto loop;
1439    }
1440    putc(c, f);
1441    ++cptr;
1442    switch (c)
1443    {
1444    case '\n':
1445    next_line:
1446	get_line();
1447	if (line) goto loop;
1448	unterminated_action(a_lineno, a_line, a_cptr);
1449
1450    case ';':
1451	if (depth > 0) goto loop;
1452	fprintf(f, "\nbreak;\n");
1453	return;
1454
1455    case '{':
1456	++depth;
1457	goto loop;
1458
1459    case '}':
1460	if (--depth > 0) goto loop;
1461	fprintf(f, "\nbreak;\n");
1462	return;
1463
1464    case '\'':
1465    case '"':
1466	{
1467	    int s_lineno = lineno;
1468	    char *s_line = dup_line();
1469	    char *s_cptr = s_line + (cptr - line - 1);
1470
1471	    quote = c;
1472	    for (;;)
1473	    {
1474		c = *cptr++;
1475		putc(c, f);
1476		if (c == quote)
1477		{
1478		    free(s_line);
1479		    goto loop;
1480		}
1481		if (c == '\n')
1482		    unterminated_string(s_lineno, s_line, s_cptr);
1483		if (c == '\\')
1484		{
1485		    c = *cptr++;
1486		    putc(c, f);
1487		    if (c == '\n')
1488		    {
1489			get_line();
1490			if (line == 0)
1491			    unterminated_string(s_lineno, s_line, s_cptr);
1492		    }
1493		}
1494	    }
1495	}
1496
1497    case '/':
1498	c = *cptr;
1499	if (c == '/')
1500	{
1501	    putc('*', f);
1502	    while ((c = *++cptr) != '\n')
1503	    {
1504		if (c == '*' && cptr[1] == '/')
1505		    fprintf(f, "* ");
1506		else
1507		    putc(c, f);
1508	    }
1509	    fprintf(f, "*/\n");
1510	    goto next_line;
1511	}
1512	if (c == '*')
1513	{
1514	    int c_lineno = lineno;
1515	    char *c_line = dup_line();
1516	    char *c_cptr = c_line + (cptr - line - 1);
1517
1518	    putc('*', f);
1519	    ++cptr;
1520	    for (;;)
1521	    {
1522		c = *cptr++;
1523		putc(c, f);
1524		if (c == '*' && *cptr == '/')
1525		{
1526		    putc('/', f);
1527		    ++cptr;
1528		    free(c_line);
1529		    goto loop;
1530		}
1531		if (c == '\n')
1532		{
1533		    get_line();
1534		    if (line == 0)
1535			unterminated_comment(c_lineno, c_line, c_cptr);
1536		}
1537	    }
1538	}
1539	goto loop;
1540
1541    default:
1542	goto loop;
1543    }
1544}
1545
1546
1547static int
1548mark_symbol(void)
1549{
1550    int c;
1551    bucket *bp = NULL;
1552
1553    c = cptr[1];
1554    if (c == '%' || c == '\\')
1555    {
1556	cptr += 2;
1557	return (1);
1558    }
1559
1560    if (c == '=')
1561	cptr += 2;
1562    else if ((c == 'p' || c == 'P') &&
1563	     ((c = cptr[2]) == 'r' || c == 'R') &&
1564	     ((c = cptr[3]) == 'e' || c == 'E') &&
1565	     ((c = cptr[4]) == 'c' || c == 'C') &&
1566	     ((c = cptr[5], !IS_IDENT(c))))
1567	cptr += 5;
1568    else
1569	syntax_error(lineno, line, cptr);
1570
1571    c = nextc();
1572    if (isalpha(c) || c == '_' || c == '.' || c == '$')
1573	bp = get_name();
1574    else if (c == '\'' || c == '"')
1575	bp = get_literal();
1576    else
1577    {
1578	syntax_error(lineno, line, cptr);
1579	/*NOTREACHED*/
1580    }
1581
1582    if (rprec[nrules] != UNDEFINED && bp->prec != rprec[nrules])
1583	prec_redeclared();
1584
1585    rprec[nrules] = bp->prec;
1586    rassoc[nrules] = bp->assoc;
1587    return (0);
1588}
1589
1590
1591static void
1592read_grammar(void)
1593{
1594    int c;
1595
1596    initialize_grammar();
1597    advance_to_start();
1598
1599    for (;;)
1600    {
1601	c = nextc();
1602	if (c == EOF) break;
1603	if (isalpha(c) || c == '_' || c == '.' || c == '$' || c == '\'' ||
1604		c == '"')
1605	    add_symbol();
1606	else if (c == '{' || c == '=')
1607	    copy_action();
1608	else if (c == '|')
1609	{
1610	    end_rule();
1611	    start_rule(plhs[nrules-1], 0);
1612	    ++cptr;
1613	}
1614	else if (c == '%')
1615	{
1616	    if (mark_symbol()) break;
1617	}
1618	else
1619	    syntax_error(lineno, line, cptr);
1620    }
1621    end_rule();
1622}
1623
1624
1625static void
1626free_tags(void)
1627{
1628    int i;
1629
1630    if (tag_table == 0) return;
1631
1632    for (i = 0; i < ntags; ++i)
1633    {
1634	assert(tag_table[i]);
1635	free(tag_table[i]);
1636    }
1637    free(tag_table);
1638}
1639
1640
1641static void
1642pack_names(void)
1643{
1644    bucket *bp;
1645    char *p, *s, *t;
1646
1647    name_pool_size = 13;  /* 13 == sizeof("$end") + sizeof("$accept") */
1648    for (bp = first_symbol; bp; bp = bp->next)
1649	name_pool_size += strlen(bp->name) + 1;
1650    name_pool = malloc(name_pool_size);
1651    if (name_pool == 0) no_space();
1652
1653    strcpy(name_pool, "$accept");
1654    strcpy(name_pool+8, "$end");
1655    t = name_pool + 13;
1656    for (bp = first_symbol; bp; bp = bp->next)
1657    {
1658	p = t;
1659	s = bp->name;
1660	while ((*t++ = *s++)) continue;
1661	free(bp->name);
1662	bp->name = p;
1663    }
1664}
1665
1666
1667static void
1668check_symbols(void)
1669{
1670    bucket *bp;
1671
1672    if (goal->class == UNKNOWN)
1673	undefined_goal(goal->name);
1674
1675    for (bp = first_symbol; bp; bp = bp->next)
1676    {
1677	if (bp->class == UNKNOWN)
1678	{
1679	    undefined_symbol_warning(bp->name);
1680	    bp->class = TERM;
1681	}
1682    }
1683}
1684
1685
1686static void
1687pack_symbols(void)
1688{
1689    bucket *bp;
1690    bucket **v;
1691    int i, j, k, n;
1692
1693    nsyms = 2;
1694    ntokens = 1;
1695    for (bp = first_symbol; bp; bp = bp->next)
1696    {
1697	++nsyms;
1698	if (bp->class == TERM) ++ntokens;
1699    }
1700    start_symbol = ntokens;
1701    nvars = nsyms - ntokens;
1702
1703    symbol_name = malloc(nsyms*sizeof(char *));
1704    if (symbol_name == 0) no_space();
1705    symbol_value = malloc(nsyms*sizeof(short));
1706    if (symbol_value == 0) no_space();
1707    symbol_prec = malloc(nsyms*sizeof(short));
1708    if (symbol_prec == 0) no_space();
1709    symbol_assoc = malloc(nsyms);
1710    if (symbol_assoc == 0) no_space();
1711
1712    v = malloc(nsyms*sizeof(bucket *));
1713    if (v == 0) no_space();
1714
1715    v[0] = 0;
1716    v[start_symbol] = 0;
1717
1718    i = 1;
1719    j = start_symbol + 1;
1720    for (bp = first_symbol; bp; bp = bp->next)
1721    {
1722	if (bp->class == TERM)
1723	    v[i++] = bp;
1724	else
1725	    v[j++] = bp;
1726    }
1727    assert(i == ntokens && j == nsyms);
1728
1729    for (i = 1; i < ntokens; ++i)
1730	v[i]->index = i;
1731
1732    goal->index = start_symbol + 1;
1733    k = start_symbol + 2;
1734    while (++i < nsyms)
1735	if (v[i] != goal)
1736	{
1737	    v[i]->index = k;
1738	    ++k;
1739	}
1740
1741    goal->value = 0;
1742    k = 1;
1743    for (i = start_symbol + 1; i < nsyms; ++i)
1744    {
1745	if (v[i] != goal)
1746	{
1747	    v[i]->value = k;
1748	    ++k;
1749	}
1750    }
1751
1752    k = 0;
1753    for (i = 1; i < ntokens; ++i)
1754    {
1755	n = v[i]->value;
1756	if (n > 256)
1757	{
1758	    for (j = k++; j > 0 && symbol_value[j-1] > n; --j)
1759		symbol_value[j] = symbol_value[j-1];
1760	    symbol_value[j] = n;
1761	}
1762    }
1763
1764    if (v[1]->value == UNDEFINED)
1765	v[1]->value = 256;
1766
1767    j = 0;
1768    n = 257;
1769    for (i = 2; i < ntokens; ++i)
1770    {
1771	if (v[i]->value == UNDEFINED)
1772	{
1773	    while (j < k && n == symbol_value[j])
1774	    {
1775		while (++j < k && n == symbol_value[j]) continue;
1776		++n;
1777	    }
1778	    v[i]->value = n;
1779	    ++n;
1780	}
1781    }
1782
1783    symbol_name[0] = name_pool + 8;
1784    symbol_value[0] = 0;
1785    symbol_prec[0] = 0;
1786    symbol_assoc[0] = TOKEN;
1787    for (i = 1; i < ntokens; ++i)
1788    {
1789	symbol_name[i] = v[i]->name;
1790	symbol_value[i] = v[i]->value;
1791	symbol_prec[i] = v[i]->prec;
1792	symbol_assoc[i] = v[i]->assoc;
1793    }
1794    symbol_name[start_symbol] = name_pool;
1795    symbol_value[start_symbol] = -1;
1796    symbol_prec[start_symbol] = 0;
1797    symbol_assoc[start_symbol] = TOKEN;
1798    for (++i; i < nsyms; ++i)
1799    {
1800	k = v[i]->index;
1801	symbol_name[k] = v[i]->name;
1802	symbol_value[k] = v[i]->value;
1803	symbol_prec[k] = v[i]->prec;
1804	symbol_assoc[k] = v[i]->assoc;
1805    }
1806
1807    free(v);
1808}
1809
1810
1811static void
1812pack_grammar(void)
1813{
1814    int i, j;
1815    int assoc, preced;
1816
1817    ritem = malloc(nitems*sizeof(short));
1818    if (ritem == 0) no_space();
1819    rlhs = malloc(nrules*sizeof(short));
1820    if (rlhs == 0) no_space();
1821    rrhs = malloc((nrules+1)*sizeof(short));
1822    if (rrhs == 0) no_space();
1823    rprec = realloc(rprec, nrules*sizeof(short));
1824    if (rprec == 0) no_space();
1825    rassoc = realloc(rassoc, nrules);
1826    if (rassoc == 0) no_space();
1827
1828    ritem[0] = -1;
1829    ritem[1] = goal->index;
1830    ritem[2] = 0;
1831    ritem[3] = -2;
1832    rlhs[0] = 0;
1833    rlhs[1] = 0;
1834    rlhs[2] = start_symbol;
1835    rrhs[0] = 0;
1836    rrhs[1] = 0;
1837    rrhs[2] = 1;
1838
1839    j = 4;
1840    for (i = 3; i < nrules; ++i)
1841    {
1842	rlhs[i] = plhs[i]->index;
1843	rrhs[i] = j;
1844	assoc = TOKEN;
1845	preced = 0;
1846	while (pitem[j])
1847	{
1848	    ritem[j] = pitem[j]->index;
1849	    if (pitem[j]->class == TERM)
1850	    {
1851		preced = pitem[j]->prec;
1852		assoc = pitem[j]->assoc;
1853	    }
1854	    ++j;
1855	}
1856	ritem[j] = -i;
1857	++j;
1858	if (rprec[i] == UNDEFINED)
1859	{
1860	    rprec[i] = preced;
1861	    rassoc[i] = assoc;
1862	}
1863    }
1864    rrhs[i] = j;
1865
1866    free(plhs);
1867    free(pitem);
1868}
1869
1870
1871static void
1872print_grammar(void)
1873{
1874    int i, j, k;
1875    int spacing;
1876    FILE *f = verbose_file;
1877
1878    if (!vflag) return;
1879
1880    k = 1;
1881    spacing = 0;
1882    for (i = 2; i < nrules; ++i)
1883    {
1884	if (rlhs[i] != rlhs[i-1])
1885	{
1886	    if (i != 2) fprintf(f, "\n");
1887	    fprintf(f, "%4d  %s :", i - 2, symbol_name[rlhs[i]]);
1888	    spacing = strlen(symbol_name[rlhs[i]]) + 1;
1889	}
1890	else
1891	{
1892	    fprintf(f, "%4d  ", i - 2);
1893	    j = spacing;
1894	    while (--j >= 0) putc(' ', f);
1895	    putc('|', f);
1896	}
1897
1898	while (ritem[k] >= 0)
1899	{
1900	    fprintf(f, " %s", symbol_name[ritem[k]]);
1901	    ++k;
1902	}
1903	++k;
1904	putc('\n', f);
1905    }
1906}
1907
1908
1909void
1910reader(void)
1911{
1912    write_section(banner);
1913    create_symbol_table();
1914    read_declarations();
1915    read_grammar();
1916    free_symbol_table();
1917    free_tags();
1918    pack_names();
1919    check_symbols();
1920    pack_symbols();
1921    pack_grammar();
1922    free_symbols();
1923    print_grammar();
1924}