-/* Input parser for bison
- Copyright (C) 1984, 1986, 1989, 1992, 1998, 2000, 2001, 2002
+/* Input parser for Bison
+
+ Copyright (C) 1984, 1986, 1989, 1992, 1998, 2000, 2001, 2002, 2003
Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-
#include "system.h"
-#include "quotearg.h"
-#include "quote.h"
-#include "getargs.h"
+
+#include <quotearg.h>
+
+#include "complain.h"
+#include "conflicts.h"
#include "files.h"
-#include "symtab.h"
-#include "options.h"
+#include "getargs.h"
#include "gram.h"
-#include "complain.h"
+#include "muscle_tab.h"
#include "output.h"
#include "reader.h"
-#include "conflicts.h"
-#include "muscle_tab.h"
+#include "symlist.h"
+#include "symtab.h"
-int lineno;
static symbol_list *grammar = NULL;
-static int start_flag = 0;
-
-/* Nonzero if %union has been seen. */
-int typed = 0;
+static bool start_flag = false;
+merger_list *merge_functions;
-symbol_list *
-symbol_list_new (symbol_t *sym, location_t location)
-{
- symbol_list *res = XMALLOC (symbol_list, 1);
- res->next = NULL;
- res->sym = sym;
- res->location = location;
- res->action = NULL;
- res->ruleprec = NULL;
- return res;
-}
-
-symbol_list *
-symbol_list_prepend (symbol_list *list, symbol_t *symbol, location_t location)
-{
- symbol_list *res = symbol_list_new (symbol, location);
- res->next = list;
- return res;
-}
+/* Has %union been seen? */
+bool typed = false;
+/* Should rules have a default precedence? */
+bool default_prec = true;
\f
-/*--------------------------------------------------------------.
-| Get the data type (alternative in the union) of the value for |
-| symbol N in rule RULE. |
-`--------------------------------------------------------------*/
-
-char *
-get_type_name (int n, symbol_list *rule)
-{
- int i;
- symbol_list *rp;
-
- if (n < 0)
- {
- complain (_("invalid $ value"));
- return NULL;
- }
-
- rp = rule;
- i = 0;
-
- while (i < n)
- {
- rp = rp->next;
- if (rp == NULL || rp->sym == NULL)
- {
- complain (_("invalid $ value"));
- return NULL;
- }
- ++i;
- }
-
- return rp->sym->type_name;
-}
-
-
/*-----------------------.
| Set the start symbol. |
`-----------------------*/
void
-grammar_start_symbol_set (symbol_t *s, location_t l)
+grammar_start_symbol_set (symbol *sym, location loc)
{
if (start_flag)
- complain (_("multiple %s declarations"), "%start");
+ complain_at (loc, _("multiple %s declarations"), "%start");
else
{
- start_flag = 1;
- startsymbol = s;
- startsymbol_location = l;
+ start_flag = true;
+ startsymbol = sym;
+ startsymbol_location = loc;
}
}
`----------------------------------------------------------------*/
void
-prologue_augment (const char *prologue, location_t location)
+prologue_augment (const char *prologue, location loc)
{
struct obstack *oout =
!typed ? &pre_prologue_obstack : &post_prologue_obstack;
- if (!no_lines_flag)
- {
- obstack_fgrow2 (oout, muscle_find ("linef"),
- location.first_line,
- quotearg_style (c_quoting_style,
- muscle_find ("filename")));
- }
+ obstack_fgrow1 (oout, "]b4_syncline([[%d]], [[", loc.start.line);
+ MUSCLE_OBSTACK_SGROW (oout,
+ quotearg_style (c_quoting_style, loc.start.file));
+ obstack_sgrow (oout, "]])[\n");
obstack_sgrow (oout, prologue);
}
+\f
+
+/*-------------------------------------------------------------------.
+| Return the merger index for a merging function named NAME, whose |
+| arguments have type TYPE. Records the function, if new, in |
+| MERGER_LIST. |
+`-------------------------------------------------------------------*/
+static int
+get_merge_function (uniqstr name, uniqstr type, location loc)
+{
+ merger_list *syms;
+ merger_list head;
+ int n;
+ if (! glr_parser)
+ return 0;
-/*----------------------.
-| Handle the epilogue. |
-`----------------------*/
+ if (type == NULL)
+ type = uniqstr_new ("");
-void
-epilogue_set (const char *epilogue, location_t location)
-{
- if (!no_lines_flag)
+ head.next = merge_functions;
+ for (syms = &head, n = 1; syms->next != NULL; syms = syms->next, n += 1)
+ if (UNIQSTR_EQ (name, syms->next->name))
+ break;
+ if (syms->next == NULL)
{
- obstack_fgrow2 (&muscle_obstack, muscle_find ("linef"),
- location.first_line,
- quotearg_style (c_quoting_style,
- muscle_find ("filename")));
+ syms->next = xmalloc (sizeof syms->next[0]);
+ syms->next->name = uniqstr_new (name);
+ syms->next->type = uniqstr_new (type);
+ syms->next->next = NULL;
+ merge_functions = head.next;
}
- obstack_sgrow (&muscle_obstack, epilogue);
- obstack_1grow (&muscle_obstack, 0);
- muscle_insert ("epilogue", obstack_finish (&muscle_obstack));
+ else if (!UNIQSTR_EQ (type, syms->next->type))
+ warn_at (loc, _("result type clash on merge function %s: <%s> != <%s>"),
+ name, type, syms->next->type);
+ return n;
}
+/*--------------------------------------.
+| Free all merge-function definitions. |
+`--------------------------------------*/
-\f
-
-/*-------------------------------------------------------------------.
-| Generate a dummy symbol, a nonterminal, whose name cannot conflict |
-| with the user's names. |
-`-------------------------------------------------------------------*/
-
-static symbol_t *
-gensym (location_t location)
+void
+free_merger_functions (void)
{
- /* Incremented for each generated symbol */
- static int gensym_count = 0;
- static char buf[256];
-
- symbol_t *sym;
-
- sprintf (buf, "@%d", ++gensym_count);
- sym = getsym (buf, location);
- sym->class = nterm_sym;
- sym->number = nvars++;
- return sym;
+ merger_list *L0;
+ if (! glr_parser)
+ return;
+ L0 = merge_functions;
+ while (L0 != NULL)
+ {
+ merger_list *L1 = L0->next;
+ free (L0);
+ L0 = L1;
+ }
}
+
\f
/*-------------------------------------------------------------------.
| Parse the input grammar into a one symbol_list structure. Each |
/* The (currently) last symbol of GRAMMAR. */
symbol_list *grammar_end = NULL;
-/* Append S to the GRAMMAR. */
+/* Append SYM to the grammar. */
void
-grammar_symbol_append (symbol_t *symbol, location_t location)
+grammar_symbol_append (symbol *sym, location loc)
{
- symbol_list *p = symbol_list_new (symbol, location);
+ symbol_list *p = symbol_list_new (sym, loc);
if (grammar_end)
grammar_end->next = p;
`----------------------------------------------*/
void
-grammar_rule_begin (symbol_t *lhs, location_t location)
+grammar_rule_begin (symbol *lhs, location loc)
{
if (!start_flag)
{
startsymbol = lhs;
- startsymbol_location = location;
- start_flag = 1;
+ startsymbol_location = loc;
+ start_flag = true;
}
/* Start a new rule and record its lhs. */
++nritems;
previous_rule_end = grammar_end;
- grammar_symbol_append (lhs, location);
+ grammar_symbol_append (lhs, loc);
current_rule = grammar_end;
/* Mark the rule's lhs as a nonterminal if not already so. */
++nvars;
}
else if (lhs->class == token_sym)
- complain (_("rule given for %s, which is a token"), lhs->tag);
+ complain_at (loc, _("rule given for %s, which is a token"), lhs->tag);
}
/* Check that the last rule (CURRENT_RULE) is properly defined. For
static void
grammar_current_rule_check (void)
{
- symbol_t *lhs = current_rule->sym;
- symbol_t *first_rhs = current_rule->next->sym;
+ symbol *lhs = current_rule->sym;
+ char const *lhs_type = lhs->type_name;
+ symbol *first_rhs = current_rule->next->sym;
/* If there is an action, then there is nothing we can do: the user
- is allowed to shoot in her foot. */
+ is allowed to shoot herself in the foot. */
if (current_rule->action)
return;
- /* If $$ is being set in default way, report if any type mismatch.
- */
+ /* Don't worry about the default action if $$ is untyped, since $$'s
+ value can't be used. */
+ if (! lhs_type)
+ return;
+
+ /* If $$ is being set in default way, report if any type mismatch. */
if (first_rhs)
{
- const char *lhs_type = lhs->type_name ? lhs->type_name : "";
const char *rhs_type = first_rhs->type_name ? first_rhs->type_name : "";
- if (strcmp (lhs_type, rhs_type))
- complain (_("type clash (`%s' `%s') on default action"),
- lhs_type, rhs_type);
+ if (!UNIQSTR_EQ (lhs_type, rhs_type))
+ warn_at (current_rule->location,
+ _("type clash on default action: <%s> != <%s>"),
+ lhs_type, rhs_type);
}
/* Warn if there is no default for $$ but we need one. */
else
- {
- if (lhs->type_name)
- complain (_("empty rule for typed nonterminal, and no action"));
- }
+ warn_at (current_rule->location,
+ _("empty rule for typed nonterminal, and no action"));
}
`-------------------------------------*/
void
-grammar_rule_end (location_t location)
+grammar_rule_end (location loc)
{
/* Put an empty link in the list to mark the end of this rule */
grammar_symbol_append (NULL, grammar_end->location);
- current_rule->location = location;
+ current_rule->location = loc;
grammar_current_rule_check ();
}
/* Make a DUMMY nonterminal, whose location is that of the midrule
action. Create the MIDRULE. */
- location_t dummy_location = current_rule->action_location;
- symbol_t *dummy = gensym (dummy_location);
+ location dummy_location = current_rule->action_location;
+ symbol *dummy = dummy_symbol_get (dummy_location);
symbol_list *midrule = symbol_list_new (dummy, dummy_location);
/* Make a new rule, whose body is empty, before the current one, so
/* Set the precedence symbol of the current rule to PRECSYM. */
void
-grammar_current_rule_prec_set (symbol_t *precsym)
+grammar_current_rule_prec_set (symbol *precsym, location loc)
{
if (current_rule->ruleprec)
- complain (_("two @prec's in a row"));
+ complain_at (loc, _("only one %s allowed per rule"), "%prec");
current_rule->ruleprec = precsym;
}
-/* Attach a SYMBOL to the current rule. If needed, move the previous
+/* Attach dynamic precedence DPREC to the current rule. */
+
+void
+grammar_current_rule_dprec_set (int dprec, location loc)
+{
+ if (! glr_parser)
+ warn_at (loc, _("%s affects only GLR parsers"), "%dprec");
+ if (dprec <= 0)
+ complain_at (loc, _("%s must be followed by positive number"), "%dprec");
+ else if (current_rule->dprec != 0)
+ complain_at (loc, _("only one %s allowed per rule"), "%dprec");
+ current_rule->dprec = dprec;
+}
+
+/* Attach a merge function NAME with argument type TYPE to current
+ rule. */
+
+void
+grammar_current_rule_merge_set (uniqstr name, location loc)
+{
+ if (! glr_parser)
+ warn_at (loc, _("%s affects only GLR parsers"), "%merge");
+ if (current_rule->merger != 0)
+ complain_at (loc, _("only one %s allowed per rule"), "%merge");
+ current_rule->merger =
+ get_merge_function (name, current_rule->sym->type_name, loc);
+}
+
+/* Attach SYM to the current rule. If needed, move the previous
action as a mid-rule action. */
void
-grammar_current_rule_symbol_append (symbol_t *symbol, location_t location)
+grammar_current_rule_symbol_append (symbol *sym, location loc)
{
if (current_rule->action)
grammar_midrule_action ();
++nritems;
- grammar_symbol_append (symbol, location);
+ grammar_symbol_append (sym, loc);
}
-
/* Attach an ACTION to the current rule. If needed, move the previous
action as a mid-rule action. */
void
-grammar_current_rule_action_append (const char *action, location_t location)
+grammar_current_rule_action_append (const char *action, location loc)
{
if (current_rule->action)
grammar_midrule_action ();
current_rule->action = action;
- current_rule->action_location = location;
+ current_rule->action_location = loc;
}
\f
static void
packgram (void)
{
- unsigned int itemno;
- int ruleno;
- symbol_list *p;
-
- ritem = XCALLOC (item_number_t, nritems);
- rules = XCALLOC (rule_t, nrules) - 1;
+ unsigned int itemno = 0;
+ rule_number ruleno = 0;
+ symbol_list *p = grammar;
- itemno = 0;
- ruleno = 1;
+ ritem = xnmalloc (nritems, sizeof *ritem);
+ rules = xnmalloc (nrules, sizeof *rules);
- p = grammar;
while (p)
{
- symbol_t *ruleprec = p->ruleprec;
+ symbol *ruleprec = p->ruleprec;
rules[ruleno].user_number = ruleno;
rules[ruleno].number = ruleno;
rules[ruleno].lhs = p->sym;
rules[ruleno].rhs = ritem + itemno;
+ rules[ruleno].prec = NULL;
+ rules[ruleno].dprec = p->dprec;
+ rules[ruleno].merger = p->merger;
+ rules[ruleno].precsym = NULL;
rules[ruleno].location = p->location;
- rules[ruleno].useful = TRUE;
+ rules[ruleno].useful = true;
rules[ruleno].action = p->action;
rules[ruleno].action_location = p->action_location;
p = p->next;
while (p && p->sym)
{
- /* item_number_t = symbol_number_t.
+ /* item_number = symbol_number.
But the former needs to contain more: negative rule numbers. */
ritem[itemno++] = symbol_number_as_item_number (p->sym->number);
/* A rule gets by default the precedence and associativity
of the last token in it. */
- if (p->sym->class == token_sym)
+ if (p->sym->class == token_sym && default_prec)
rules[ruleno].prec = p->sym;
if (p)
p = p->next;
rules[ruleno].precsym = ruleprec;
rules[ruleno].prec = ruleprec;
}
- ritem[itemno++] = -ruleno;
+ ritem[itemno++] = rule_number_as_item_number (ruleno);
++ruleno;
if (p)
p = p->next;
}
- assert (itemno == nritems);
+ if (itemno != nritems)
+ abort ();
- if (trace_flag)
+ if (trace_flag & trace_sets)
ritem_print (stderr);
}
\f
void
reader (void)
{
- gram_control_t gram_control;
- lineno = 1;
-
/* Initialize the symbol table. */
symbols_new ();
- /* Construct the axiom symbol. */
- axiom = getsym ("$axiom", empty_location);
- axiom->class = nterm_sym;
- axiom->number = nvars++;
+ /* Construct the accept symbol. */
+ accept = symbol_get ("$accept", empty_location);
+ accept->class = nterm_sym;
+ accept->number = nvars++;
/* Construct the error token */
- errtoken = getsym ("error", empty_location);
+ errtoken = symbol_get ("error", empty_location);
errtoken->class = token_sym;
errtoken->number = ntokens++;
/* Construct a token that represents all undefined literal tokens.
It is always token number 2. */
- undeftoken = getsym ("$undefined.", empty_location);
+ undeftoken = symbol_get ("$undefined", empty_location);
undeftoken->class = token_sym;
undeftoken->number = ntokens++;
obstack_init (&pre_prologue_obstack);
obstack_init (&post_prologue_obstack);
- finput = xfopen (infile, "r");
+ finput = xfopen (grammar_file, "r");
gram_in = finput;
- gram_debug = !!getenv ("parse");
- gram__flex_debug = !!getenv ("scan");
+ gram__flex_debug = trace_flag & trace_scan;
+ gram_debug = trace_flag & trace_parse;
scanner_initialize ();
- gram_parse (&gram_control);
+ gram_parse ();
+
+ /* If something went wrong during the parsing, don't try to
+ continue. */
+ if (complaint_issued)
+ return;
/* Grammar has been read. Do some checking */
if (nrules == 0)
/* Report any undefined symbols and consider them nonterminals. */
symbols_check_defined ();
- /* If the user did not define her EOFTOKEN, do it now. */
- if (!eoftoken)
+ /* If the user did not define her ENDTOKEN, do it now. */
+ if (!endtoken)
{
- eoftoken = getsym ("$", empty_location);
- eoftoken->class = token_sym;
- eoftoken->number = 0;
+ endtoken = symbol_get ("$end", empty_location);
+ endtoken->class = token_sym;
+ endtoken->number = 0;
/* Value specified by POSIX. */
- eoftoken->user_token_number = 0;
+ endtoken->user_token_number = 0;
}
/* Insert the initial rule, which line is that of the first rule
(not that of the start symbol):
- axiom: %start EOF. */
+ accept: %start EOF. */
{
- symbol_list *p = symbol_list_new (axiom, empty_location);
+ symbol_list *p = symbol_list_new (accept, empty_location);
p->location = grammar->location;
p->next = symbol_list_new (startsymbol, empty_location);
- p->next->next = symbol_list_new (eoftoken, empty_location);
+ p->next->next = symbol_list_new (endtoken, empty_location);
p->next->next->next = symbol_list_new (NULL, empty_location);
p->next->next->next->next = grammar;
nrules += 1;
grammar = p;
}
- if (nsyms > SHRT_MAX)
- fatal (_("too many symbols (tokens plus nonterminals); maximum %d"),
- SHRT_MAX);
-
- assert (nsyms == ntokens + nvars);
+ if (! (nsyms <= SYMBOL_NUMBER_MAXIMUM && nsyms == ntokens + nvars))
+ abort ();
xfclose (finput);