merger_list *merge_functions;
/* Was %union seen? */
-bool typed = false;
+bool union_seen = false;
+
+/* Was a tag seen? */
+bool tag_seen = false;
/* Should rules have a default precedence? */
bool default_prec = true;
\f
-/*-------------------------------------------------------------------.
-| Return the merger index for a merging function named NAME, whose |
-| arguments have type TYPE. Records the function, if new, in |
-| MERGER_LIST. |
-`-------------------------------------------------------------------*/
+/*------------------------------------------------------------------------.
+| Return the merger index for a merging function named NAME. Records the |
+| function, if new, in MERGER_LIST. |
+`------------------------------------------------------------------------*/
static int
-get_merge_function (uniqstr name, uniqstr type, location loc)
+get_merge_function (uniqstr name)
{
merger_list *syms;
merger_list head;
if (! glr_parser)
return 0;
- if (type == NULL)
- type = uniqstr_new ("");
-
head.next = merge_functions;
for (syms = &head, n = 1; syms->next; syms = syms->next, n += 1)
if (UNIQSTR_EQ (name, syms->next->name))
{
syms->next = xmalloc (sizeof syms->next[0]);
syms->next->name = uniqstr_new (name);
- syms->next->type = uniqstr_new (type);
+ /* After all symbol type declarations have been parsed, packgram invokes
+ record_merge_function_type to set the type. */
+ syms->next->type = NULL;
syms->next->next = NULL;
merge_functions = head.next;
}
- 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;
}
+/*-------------------------------------------------------------------------.
+| For the existing merging function with index MERGER, record the result |
+| type as TYPE as required by the lhs of the rule whose %merge declaration |
+| is at DECLARATION_LOC. |
+`-------------------------------------------------------------------------*/
+
+static void
+record_merge_function_type (int merger, uniqstr type, location declaration_loc)
+{
+ int merger_find;
+ merger_list *merge_function;
+
+ if (merger <= 0)
+ return;
+
+ if (type == NULL)
+ type = uniqstr_new ("");
+
+ merger_find = 1;
+ for (merge_function = merge_functions;
+ merge_function != NULL && merger_find != merger;
+ merge_function = merge_function->next)
+ merger_find += 1;
+ assert (merge_function != NULL && merger_find == merger);
+ if (merge_function->type != NULL && !UNIQSTR_EQ (merge_function->type, type))
+ {
+ complain_at (declaration_loc,
+ _("result type clash on merge function `%s': <%s> != <%s>"),
+ merge_function->name, type, merge_function->type);
+ complain_at (merge_function->type_declaration_location,
+ _("previous declaration"));
+ }
+ merge_function->type = uniqstr_new (type);
+ merge_function->type_declaration_location = declaration_loc;
+}
+
/*--------------------------------------.
| Free all merge-function definitions. |
`--------------------------------------*/
/* The rule currently being defined, and the previous rule.
CURRENT_RULE points to the first LHS of the current rule, while
PREVIOUS_RULE_END points to the *end* of the previous rule (NULL). */
-symbol_list *current_rule = NULL;
+static symbol_list *current_rule = NULL;
static symbol_list *previous_rule_end = NULL;
static bool
symbol_should_be_used (symbol_list const *s)
{
- return (s->sym->destructor
+ return (symbol_destructor_get (s->sym)
|| (s->midrule && s->midrule->used));
}
/* Put an empty link in the list to mark the end of this rule */
grammar_symbol_append (NULL, grammar_end->location);
current_rule->location = loc;
- grammar_rule_check (current_rule);
}
midrule->action = current_rule->action;
midrule->action_location = dummy_location;
current_rule->action = NULL;
- /* If $$ was used in the action, the LHS of the enclosing rule was
- incorrectly flagged as used. */
- midrule->used = current_rule->used;
- current_rule->used = false;
+ /* The action has not been translated yet, so $$ use hasn't been
+ detected yet. */
+ midrule->used = false;
if (previous_rule_end)
previous_rule_end->next = midrule;
/* End the dummy's rule. */
midrule->next = symbol_list_new (NULL, dummy_location);
- grammar_rule_check (midrule);
midrule->next->next = current_rule;
previous_rule_end = midrule->next;
the current rule. Bind it to its dedicated rule. */
grammar_current_rule_symbol_append (dummy, dummy_location);
grammar_end->midrule = midrule;
+ midrule->midrule_parent_rule = current_rule;
+ midrule->midrule_parent_rhs_index = symbol_list_length (current_rule->next);
}
/* Set the precedence symbol of the current rule to PRECSYM. */
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);
+ current_rule->merger = get_merge_function (name);
+ current_rule->merger_declaration_location = loc;
}
/* Attach SYM to the current rule. If needed, move the previous
void
grammar_current_rule_action_append (const char *action, location loc)
{
- current_rule->action = translate_rule_action (current_rule, action, loc);
+ if (current_rule->action)
+ grammar_midrule_action ();
+ /* After all symbol declarations have been parsed, packgram invokes
+ translate_rule_action. */
+ current_rule->action = action;
current_rule->action_location = loc;
}
{
int rule_length = 0;
symbol *ruleprec = p->ruleprec;
+ record_merge_function_type (p->merger, p->sym->type_name,
+ p->merger_declaration_location);
rules[ruleno].user_number = ruleno;
rules[ruleno].number = ruleno;
rules[ruleno].lhs = p->sym;
rules[ruleno].precsym = NULL;
rules[ruleno].location = p->location;
rules[ruleno].useful = true;
- rules[ruleno].action = p->action;
+ rules[ruleno].action = p->action ? translate_rule_action (p) : NULL;
rules[ruleno].action_location = p->action_location;
+ /* If this rule contains midrules, rest assured that
+ grammar_midrule_action inserted the midrules into grammar before this
+ rule. Thus, the midrule actions have already been scanned in order to
+ set `used' flags for this rule's rhs, so grammar_rule_check will work
+ properly. */
+ /* Don't check the generated rule 0. It has no action, so some rhs
+ symbols may appear unused, but the parsing algorithm ensures that
+ %destructor's are invoked appropriately. */
+ if (p != grammar)
+ grammar_rule_check (p);
+
for (p = p->next; p && p->sym; p = p->next)
{
++rule_length;