- symbol_list *p1;
- bucket *bp;
-
- symbol_list *crule; /* points to first symbol_list of current rule. */
- /* its symbol is the lhs of the rule. */
- symbol_list *crule1; /* points to the symbol_list preceding crule. */
-
- p1 = NULL;
-
- t = lex ();
-
- while (t != TWO_PERCENTS && t != ENDFILE)
- {
- if (t == IDENTIFIER || t == BAR)
- {
- int actionflag = 0;
- int rulelength = 0; /* number of symbols in rhs of this rule so far */
- int xactions = 0; /* JF for error checking */
- bucket *first_rhs = 0;
-
- if (t == IDENTIFIER)
- {
- lhs = symval;
-
- if (!start_flag)
- {
- startval = lhs;
- start_flag = 1;
- }
-
- t = lex ();
- if (t != COLON)
- {
- complain (_("ill-formed rule: initial symbol not followed by colon"));
- unlex (t);
- }
- }
-
- if (nrules == 0 && t == BAR)
- {
- complain (_("grammar starts with vertical bar"));
- lhs = symval; /* BOGUS: use a random symval */
- }
- /* start a new rule and record its lhs. */
-
- nrules++;
- nitems++;
-
- record_rule_line ();
-
- p = XCALLOC (symbol_list, 1);
- p->sym = lhs;
-
- crule1 = p1;
- if (p1)
- p1->next = p;
- else
- grammar = p;
-
- p1 = p;
- crule = p;
-
- /* mark the rule's lhs as a nonterminal if not already so. */
-
- if (lhs->class == SUNKNOWN)
- {
- lhs->class = SNTERM;
- lhs->value = nvars;
- nvars++;
- }
- else if (lhs->class == STOKEN)
- complain (_("rule given for %s, which is a token"), lhs->tag);
-
- /* read the rhs of the rule. */
-
- for (;;)
- {
- t = lex ();
- if (t == PREC)
- {
- t = lex ();
- crule->ruleprec = symval;
- t = lex ();
- }
-
- if (!(t == IDENTIFIER || t == LEFT_CURLY))
- break;
-
- /* If next token is an identifier, see if a colon follows it.
- If one does, exit this rule now. */
- if (t == IDENTIFIER)
- {
- bucket *ssave;
- int t1;
-
- ssave = symval;
- t1 = lex ();
- unlex (t1);
- symval = ssave;
- if (t1 == COLON)
- break;
-
- if (!first_rhs) /* JF */
- first_rhs = symval;
- /* Not followed by colon =>
- process as part of this rule's rhs. */
- }
-
- /* If we just passed an action, that action was in the middle
- of a rule, so make a dummy rule to reduce it to a
- non-terminal. */
- if (actionflag)
- {
- bucket *sdummy;
-
- /* Since the action was written out with this rule's */
- /* number, we must give the new rule this number */
- /* by inserting the new rule before it. */
-
- /* Make a dummy nonterminal, a gensym. */
- sdummy = gensym ();
-
- /* Make a new rule, whose body is empty,
- before the current one, so that the action
- just read can belong to it. */
- nrules++;
- nitems++;
- record_rule_line ();
- p = XCALLOC (symbol_list, 1);
- if (crule1)
- crule1->next = p;
- else
- grammar = p;
- p->sym = sdummy;
- crule1 = XCALLOC (symbol_list, 1);
- p->next = crule1;
- crule1->next = crule;
-
- /* insert the dummy generated by that rule into this rule. */
- nitems++;
- p = XCALLOC (symbol_list, 1);
- p->sym = sdummy;
- p1->next = p;
- p1 = p;
-
- actionflag = 0;
- }
-
- if (t == IDENTIFIER)
- {
- nitems++;
- p = XCALLOC (symbol_list, 1);
- p->sym = symval;
- p1->next = p;
- p1 = p;
- }
- else /* handle an action. */
- {
- copy_action (crule, rulelength);
- actionflag = 1;
- xactions++; /* JF */
- }
- rulelength++;
- } /* end of read rhs of rule */
-
- /* Put an empty link in the list to mark the end of this rule */
- p = XCALLOC (symbol_list, 1);
- p1->next = p;
- p1 = p;
-
- if (t == PREC)
- {
- complain (_("two @prec's in a row"));
- t = lex ();
- crule->ruleprec = symval;
- t = lex ();
- }
- if (t == GUARD)
- {
- if (!semantic_parser)
- complain ("%s",
- _
- ("%guard present but %semantic_parser not specified"));
-
- copy_guard (crule, rulelength);
- t = lex ();
- }
- else if (t == LEFT_CURLY)
- {
- /* This case never occurs -wjh */
- if (actionflag)
- complain (_("two actions at end of one rule"));
- copy_action (crule, rulelength);
- actionflag = 1;
- xactions++; /* -wjh */
- t = lex ();
- }
- /* If $$ is being set in default way, report if any type
- mismatch. */
- else if (!xactions
- && first_rhs && lhs->type_name != first_rhs->type_name)
- {
- if (lhs->type_name == 0
- || first_rhs->type_name == 0
- || strcmp (lhs->type_name, first_rhs->type_name))
- complain (_("type clash (`%s' `%s') on default action"),
- lhs->type_name ? lhs->type_name : "",
- first_rhs->type_name ? first_rhs->type_name : "");
- }
- /* Warn if there is no default for $$ but we need one. */
- else if (!xactions && !first_rhs && lhs->type_name != 0)
- complain (_("empty rule for typed nonterminal, and no action"));
- if (t == SEMICOLON)
- t = lex ();
- }
-#if 0
- /* these things can appear as alternatives to rules. */
-/* NO, they cannot.
- a) none of the documentation allows them
- b) most of them scan forward until finding a next %
- thus they may swallow lots of intervening rules
-*/
- else if (t == TOKEN)
- {
- parse_token_decl (STOKEN, SNTERM);
- t = lex ();
- }
- else if (t == NTERM)
- {
- parse_token_decl (SNTERM, STOKEN);
- t = lex ();
- }
- else if (t == TYPE)
- {
- t = get_type ();
- }
- else if (t == UNION)
- {
- parse_union_decl ();
- t = lex ();
- }
- else if (t == EXPECT)
- {
- parse_expect_decl ();
- t = lex ();
- }
- else if (t == START)
- {
- parse_start_decl ();
- t = lex ();
- }
-#endif
-
- else
- {
- complain (_("invalid input: %s"), token_buffer);
- t = lex ();
- }
- }
-
- /* grammar has been read. Do some checking */
-
- if (nsyms > MAXSHORT)
- fatal (_("too many symbols (tokens plus nonterminals); maximum %d"),
- MAXSHORT);
- if (nrules == 0)
- fatal (_("no rules in the input grammar"));
-
- if (typed == 0 /* JF put out same default YYSTYPE as YACC does */
- && !value_components_used)
- {
- /* We used to use `unsigned long' as YYSTYPE on MSDOS,
- but it seems better to be consistent.
- Most programs should declare their own type anyway. */
- fprintf (fattrs, "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n");
- if (fdefines)
- fprintf (fdefines, "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n");
- }
-
- /* Report any undefined symbols and consider them nonterminals. */
-
- for (bp = firstsymbol; bp; bp = bp->next)
- if (bp->class == SUNKNOWN)
- {
- complain (_
- ("symbol %s is used, but is not defined as a token and has no rules"),
-bp->tag);
- bp->class = SNTERM;
- bp->value = nvars++;
- }
-
- ntokens = nsyms - nvars;