| /* IELR's inadequacy annotation list. |
| |
| Copyright (C) 2009-2012 Free Software Foundation, Inc. |
| |
| This file is part of Bison, the GNU Compiler Compiler. |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include <config.h> |
| #include "system.h" |
| |
| #include "AnnotationList.h" |
| #include "lalr.h" |
| #include "ielr.h" |
| |
| /** |
| * \pre |
| * - <tt>annotations_obstackp != NULL</tt>. |
| * \post |
| * - \c result is a new \c AnnotationList with one node whose: |
| * - \c inadequacyNode member is \c NULL. |
| * - \c contributions member is allocated with \c contribution_count |
| * uninitialized elements. |
| * - All memory was allocated on \c annotations_obstackp. |
| */ |
| static AnnotationList* |
| AnnotationList__alloc_on_obstack (ContributionIndex contribution_count, |
| struct obstack *annotations_obstackp) |
| { |
| AnnotationList *result; |
| size_t contributions_size = |
| contribution_count * sizeof result->contributions[0]; |
| result = obstack_alloc (annotations_obstackp, |
| offsetof (AnnotationList, contributions) |
| + contributions_size); |
| result->next = NULL; |
| result->inadequacyNode = NULL; |
| return result; |
| } |
| |
| /** |
| * \pre |
| * - <tt>self != NULL</tt>. |
| * - <tt>0 <= ci < self->inadequacyNode->contributionCount</tt>. |
| * \post |
| * - \c result = true iff contribution \c ci in \c self represents an |
| * "always" contribution. |
| */ |
| static bool |
| AnnotationList__isContributionAlways (AnnotationList const *self, |
| ContributionIndex ci) |
| { |
| aver (0 <= ci && ci < self->inadequacyNode->contributionCount); |
| return self->contributions[ci] == NULL; |
| } |
| |
| /** |
| * \pre |
| * - \c self is a single node. |
| * - \c self annotates the same state as every other node in \c list, and |
| * that state has \c nitems kernel items. |
| * \post |
| * - If the list \c list already contains an identical annotation to \c self, |
| * \c self was discarded, \c result is false, and the caller is responsible |
| * for the memory of \c self. |
| * - Otherwise, \c list now contains the node \c self, \c result is true, and |
| * \c list assumes responsibility for the memory of \c self. |
| * - The sort in \c list is: |
| * - Sort in reverse order on the unique ID of the associated |
| * inadequacy node. Because these IDs are assigned in ascending |
| * order, this should mean that the insertion position within an |
| * annotation list is usually near the beginning with other |
| * annotations associated with the same inadequacy. |
| * - Next, sort on the first contribution that is different as follows: |
| * - Sort an always-contribution before a never-contribution before a |
| * potential-contribution. |
| * - Two always-contributions are identical. |
| * - Two never-contributions are identical. |
| * - For two potential-contributions, sort on the contributions' kernel |
| * item bitsets interpreted as binary numbers. |
| * - The sorting has a few effects: |
| * - It accelerates elimination of identical annotations during insertion. |
| * - It determines how the output of \c AnnotationList__debug is sorted. |
| * - Other than that, it's probably not important. |
| */ |
| static bool |
| AnnotationList__insertInto (AnnotationList *self, AnnotationList **list, |
| size_t nitems) |
| { |
| AnnotationList **node; |
| for (node = list; *node; node = &(*node)->next) |
| { |
| int cmp = 0; |
| ContributionIndex ci; |
| if (self->inadequacyNode->id < (*node)->inadequacyNode->id) |
| cmp = 1; |
| else if ((*node)->inadequacyNode->id < self->inadequacyNode->id) |
| cmp = -1; |
| else |
| for (ci = 0; |
| cmp == 0 && ci < self->inadequacyNode->contributionCount; |
| ++ci) |
| { |
| if (AnnotationList__isContributionAlways (self, ci)) |
| { |
| if (!AnnotationList__isContributionAlways (*node, ci)) |
| cmp = -1; |
| } |
| else if (AnnotationList__isContributionAlways (*node, ci)) |
| cmp = 1; |
| else |
| { |
| size_t item; |
| for (item = 0; cmp == 0 && item < nitems; ++item) |
| { |
| if (!Sbitset__test (self->contributions[ci], item)) |
| { |
| if (Sbitset__test ((*node)->contributions[ci], item)) |
| cmp = -1; |
| } |
| else if (!Sbitset__test ((*node)->contributions[ci], item)) |
| cmp = 1; |
| } |
| } |
| } |
| if (cmp < 0) |
| { |
| self->next = *node; |
| *node = self; |
| break; |
| } |
| else if (cmp == 0) |
| { |
| self = NULL; |
| break; |
| } |
| } |
| if (!*node) |
| *node = self; |
| return self != NULL; |
| } |
| |
| static bitset |
| AnnotationList__compute_shift_tokens (transitions *trans) |
| { |
| bitset shift_tokens = bitset_create (ntokens, BITSET_FIXED); |
| int i; |
| FOR_EACH_SHIFT (trans, i) |
| bitset_set (shift_tokens, TRANSITION_SYMBOL (trans, i)); |
| return shift_tokens; |
| } |
| |
| static bitset |
| AnnotationList__compute_conflicted_tokens (bitset shift_tokens, |
| reductions *reds) |
| { |
| bitset conflicted_tokens = bitset_create (ntokens, BITSET_FIXED); |
| bitset conflicted_tokens_rule = bitset_create (ntokens, BITSET_FIXED); |
| bitset tokens = bitset_create (ntokens, BITSET_FIXED); |
| int i; |
| |
| bitset_copy (tokens, shift_tokens); |
| for (i = 0; i < reds->num; ++i) |
| { |
| bitset_and (conflicted_tokens_rule, tokens, reds->lookahead_tokens[i]); |
| bitset_or (conflicted_tokens, |
| conflicted_tokens, conflicted_tokens_rule); |
| bitset_or (tokens, tokens, reds->lookahead_tokens[i]); |
| /* Check that rules are sorted on rule number or the next step in |
| AnnotationList__compute_from_inadequacies will misbehave. */ |
| aver (i == 0 || reds->rules[i-1] < reds->rules[i]); |
| } |
| |
| bitset_free (tokens); |
| bitset_free (conflicted_tokens_rule); |
| |
| return conflicted_tokens; |
| } |
| |
| static bool |
| AnnotationList__compute_lhs_contributions (state *s, rule *the_rule, |
| symbol_number conflicted_token, |
| bitsetv follow_kernel_items, |
| bitsetv always_follows, |
| state ***predecessors, |
| bitset **item_lookahead_sets, |
| Sbitset *items, |
| struct obstack |
| *annotations_obstackp) |
| { |
| goto_number lhs_goto = map_goto (s->number, the_rule->lhs->number); |
| if (bitset_test (always_follows[lhs_goto], conflicted_token)) |
| return true; |
| *items = Sbitset__new_on_obstack (s->nitems, annotations_obstackp); |
| { |
| bitset_iterator biter_item; |
| bitset_bindex item; |
| BITSET_FOR_EACH (biter_item, follow_kernel_items[lhs_goto], item, 0) |
| if (ielr_item_has_lookahead (s, 0, item, conflicted_token, |
| predecessors, item_lookahead_sets)) |
| Sbitset__set (*items, item); |
| } |
| return false; |
| } |
| |
| static void |
| AnnotationList__computePredecessorAnnotations (AnnotationList *self, state *s, |
| bitsetv follow_kernel_items, |
| bitsetv always_follows, |
| state ***predecessors, |
| bitset **item_lookahead_sets, |
| AnnotationList |
| **annotation_lists, |
| AnnotationIndex |
| *annotation_counts, |
| struct obstack |
| *annotations_obstackp) |
| { |
| state **predecessor; |
| for (predecessor = predecessors[s->number]; *predecessor; ++predecessor) |
| { |
| AnnotationList *annotation_node = |
| AnnotationList__alloc_on_obstack ( |
| self->inadequacyNode->contributionCount, annotations_obstackp); |
| annotation_node->inadequacyNode = self->inadequacyNode; |
| bool potential_contribution = false; |
| bitset *lookaheads = NULL; |
| { |
| ContributionIndex ci; |
| for (ci = 0; ci < self->inadequacyNode->contributionCount; ++ci) |
| { |
| symbol_number contribution_token = |
| InadequacyList__getContributionToken (self->inadequacyNode, ci) |
| ->number; |
| if (AnnotationList__isContributionAlways (self, ci)) |
| { |
| annotation_node->contributions[ci] = NULL; |
| continue; |
| } |
| annotation_node->contributions[ci] = |
| Sbitset__new_on_obstack ((*predecessor)->nitems, |
| annotations_obstackp); |
| { |
| size_t predecessor_item = 0; |
| Sbitset sbiter_item; |
| Sbitset__Index self_item; |
| SBITSET__FOR_EACH (self->contributions[ci], s->nitems, |
| sbiter_item, self_item) |
| { |
| /* If this kernel item is the beginning of a RHS, it must be |
| the kernel item in the start state, and so it has an empty |
| lookahead set. Thus, it can't contribute to inadequacies, |
| and so it should never have been identified as a |
| contribution. If, instead, this kernel item is the |
| successor of the start state's kernel item, the lookahead |
| set is still empty, and so it also should never have been |
| identified as a contribution. This situation is fortunate |
| because we want to avoid the - 2 below in both cases. */ |
| aver (s->items[self_item] > 1); |
| /* If this kernel item is next to the beginning of the RHS, |
| then check all of the predecessor's goto follows for the |
| LHS. */ |
| if (item_number_is_rule_number (ritem[s->items[self_item] |
| - 2])) |
| { |
| Sbitset items; |
| unsigned int rulei; |
| for (rulei = s->items[self_item]; |
| !item_number_is_rule_number (ritem[rulei]); |
| ++rulei) |
| ; |
| if (AnnotationList__compute_lhs_contributions ( |
| *predecessor, |
| &rules[item_number_as_rule_number (ritem[rulei])], |
| contribution_token, |
| follow_kernel_items, always_follows, predecessors, |
| item_lookahead_sets, &items, annotations_obstackp)) |
| { |
| obstack_free (annotations_obstackp, |
| annotation_node->contributions[ci]); |
| annotation_node->contributions[ci] = NULL; |
| break; |
| } |
| else |
| { |
| Sbitset__or (annotation_node->contributions[ci], |
| annotation_node->contributions[ci], |
| items, (*predecessor)->nitems); |
| obstack_free (annotations_obstackp, items); |
| } |
| } |
| /* If this kernel item is later in the RHS, then check the |
| predecessor item's lookahead set. */ |
| else |
| { |
| /* We don't have to start the predecessor item search at |
| the beginning every time because items from both |
| states are sorted by their indices in ritem. */ |
| for (; |
| predecessor_item < (*predecessor)->nitems; |
| ++predecessor_item) |
| if ((*predecessor)->items[predecessor_item] |
| == s->items[self_item] - 1) |
| break; |
| aver (predecessor_item != (*predecessor)->nitems); |
| if (ielr_item_has_lookahead (*predecessor, 0, |
| predecessor_item, |
| contribution_token, |
| predecessors, |
| item_lookahead_sets)) |
| Sbitset__set (annotation_node->contributions[ci], |
| predecessor_item); |
| } |
| } |
| } |
| if (annotation_node->contributions[ci]) |
| { |
| Sbitset biter; |
| Sbitset__Index i; |
| SBITSET__FOR_EACH (annotation_node->contributions[ci], |
| (*predecessor)->nitems, biter, i) |
| { |
| potential_contribution = true; |
| if (!lookaheads) |
| { |
| size_t j; |
| lookaheads = xnmalloc ((*predecessor)->nitems, |
| sizeof *lookaheads); |
| for (j = 0; j < (*predecessor)->nitems; ++j) |
| lookaheads[j] = NULL; |
| } |
| if (!lookaheads[i]) |
| lookaheads[i] = bitset_create (ntokens, BITSET_FIXED); |
| bitset_set (lookaheads[i], contribution_token); |
| } |
| } |
| } |
| } |
| |
| /* If the predecessor has any contributions besides just "always" and |
| "never" contributions: |
| - If the dominant contribution is split-stable, the annotation could |
| not affect merging on this predecessor state or its eventual |
| predecessor states. Moreover, all contributions that affect |
| whether the dominant contribution remains dominant must be "always" |
| or "never" contributions in order for the dominant contribution to |
| be split-stable. Thus, the dominant contribution computation result |
| in eventual successor states will not be affected by lookaheads |
| tracked for this predecessor state. (Also, as in the isocore |
| compatibility test, we depend on the fact that isocores with equal |
| dominant contributions will have the same dominant contribution when |
| merged. Otherwise, we might have to worry that the presence of a |
| potential contribution might somehow be the culprit of that behavior |
| and thus need to be tracked regardless of the split stability of the |
| dominant contribution.) Thus, go ahead and discard the annotation |
| to save space now plus time during state splitting. |
| - Otherwise, record the annotation, and compute any resulting |
| annotations needed on predecessor states. */ |
| if (potential_contribution) |
| { |
| if (ContributionIndex__none |
| != AnnotationList__computeDominantContribution ( |
| annotation_node, (*predecessor)->nitems, lookaheads, true)) |
| { |
| obstack_free (annotations_obstackp, annotation_node); |
| annotation_node = NULL; |
| } |
| { |
| size_t i; |
| for (i = 0; i < (*predecessor)->nitems; ++i) |
| if (lookaheads[i]) |
| bitset_free (lookaheads[i]); |
| free (lookaheads); |
| } |
| if (annotation_node) |
| { |
| if (AnnotationList__insertInto (annotation_node, |
| &annotation_lists[(*predecessor) |
| ->number], |
| (*predecessor)->nitems)) |
| { |
| ++annotation_counts[(*predecessor)->number]; |
| AnnotationList__computePredecessorAnnotations ( |
| annotation_node, *predecessor, |
| follow_kernel_items, always_follows, predecessors, |
| item_lookahead_sets, annotation_lists, annotation_counts, |
| annotations_obstackp); |
| } |
| else |
| obstack_free (annotations_obstackp, annotation_node); |
| } |
| } |
| else |
| obstack_free (annotations_obstackp, annotation_node); |
| } |
| } |
| |
| void |
| AnnotationList__compute_from_inadequacies ( |
| state *s, bitsetv follow_kernel_items, bitsetv always_follows, |
| state ***predecessors, bitset **item_lookahead_sets, |
| InadequacyList **inadequacy_lists, AnnotationList **annotation_lists, |
| AnnotationIndex *annotation_counts, |
| ContributionIndex *max_contributionsp, |
| struct obstack *annotations_obstackp, |
| InadequacyListNodeCount *inadequacy_list_node_count) |
| { |
| bitsetv all_lookaheads; |
| bitset shift_tokens; |
| bitset conflicted_tokens; |
| bitset_iterator biter_conflict; |
| bitset_bindex conflicted_token; |
| |
| /* Return an empty list if s->lookahead_tokens = NULL. */ |
| if (s->consistent) |
| return; |
| |
| all_lookaheads = bitsetv_create (s->nitems, ntokens, BITSET_FIXED); |
| bitsetv_ones (all_lookaheads); |
| shift_tokens = AnnotationList__compute_shift_tokens (s->transitions); |
| conflicted_tokens = |
| AnnotationList__compute_conflicted_tokens (shift_tokens, s->reductions); |
| |
| /* Add an inadequacy annotation for each conflicted_token. */ |
| BITSET_FOR_EACH (biter_conflict, conflicted_tokens, conflicted_token, 0) |
| { |
| AnnotationList *annotation_node; |
| /* FIXME: Would a BITSET_FRUGAL or BITEST_SPARSE be more efficient? Now |
| or convert it inside InadequacyList__new_conflict? */ |
| bitset actions = bitset_create (s->reductions->num + 1, BITSET_FIXED); |
| ContributionIndex contribution_count = 0; |
| bool potential_contribution = false; |
| |
| /* Allocate the annotation node. */ |
| { |
| int rule_i; |
| for (rule_i = 0; rule_i < s->reductions->num; ++rule_i) |
| if (bitset_test (s->reductions->lookahead_tokens[rule_i], |
| conflicted_token)) |
| ++contribution_count; |
| if (bitset_test (shift_tokens, conflicted_token)) |
| ++contribution_count; |
| annotation_node = |
| AnnotationList__alloc_on_obstack (contribution_count, |
| annotations_obstackp); |
| } |
| |
| /* Add a contribution for each reduction that has conflicted_token as a |
| lookahead. */ |
| { |
| ContributionIndex ci = 0; |
| int item_i = 0; |
| int rule_i; |
| for (rule_i = 0; rule_i < s->reductions->num; ++rule_i) |
| { |
| rule *the_rule = s->reductions->rules[rule_i]; |
| if (bitset_test (s->reductions->lookahead_tokens[rule_i], |
| conflicted_token)) |
| { |
| bitset_set (actions, rule_i); |
| /* If this reduction is on a kernel item, just add it. */ |
| if (!item_number_is_rule_number (the_rule->rhs[0])) |
| { |
| annotation_node->contributions[ci] = |
| Sbitset__new_on_obstack (s->nitems, |
| annotations_obstackp); |
| /* Catch item_i up to rule_i. This works because both are |
| sorted on rule number. */ |
| while (!item_number_is_rule_number ( |
| ritem[s->items[item_i]]) |
| || item_number_as_rule_number ( |
| ritem[s->items[item_i]]) |
| != the_rule->number) |
| { |
| ++item_i; |
| aver (item_i < s->nitems); |
| } |
| Sbitset__set (annotation_node->contributions[ci], item_i); |
| } |
| /* Otherwise, add the kernel items whose lookahead sets |
| contribute the conflicted token to this reduction's |
| lookahead set. */ |
| else if (AnnotationList__compute_lhs_contributions ( |
| s, the_rule, conflicted_token, follow_kernel_items, |
| always_follows, predecessors, item_lookahead_sets, |
| &annotation_node->contributions[ci], |
| annotations_obstackp)) |
| { |
| annotation_node->contributions[ci++] = NULL; |
| continue; |
| } |
| /* The lookahead token has to come from somewhere. */ |
| aver (!Sbitset__isEmpty (annotation_node->contributions[ci], |
| s->nitems)); |
| ++ci; |
| potential_contribution = true; |
| } |
| } |
| } |
| |
| /* If there are any contributions besides just "always" contributions: |
| - If there's also a shift contribution, record it. |
| - If the dominant contribution is split-stable, then the annotation |
| could not affect merging, so go ahead and discard the annotation and |
| the inadequacy to save space now plus time during state splitting. |
| - Otherwise, record the annotation and the inadequacy, and compute any |
| resulting annotations needed on predecessor states. */ |
| if (potential_contribution) |
| { |
| if (bitset_test (shift_tokens, conflicted_token)) |
| { |
| bitset_set (actions, s->reductions->num); |
| annotation_node->contributions[contribution_count - 1] = NULL; |
| } |
| { |
| InadequacyList *conflict_node = |
| InadequacyList__new_conflict ( |
| s, symbols[conflicted_token], actions, |
| inadequacy_list_node_count); |
| actions = NULL; |
| annotation_node->inadequacyNode = conflict_node; |
| if (ContributionIndex__none |
| != AnnotationList__computeDominantContribution ( |
| annotation_node, s->nitems, all_lookaheads, true)) |
| { |
| obstack_free (annotations_obstackp, annotation_node); |
| InadequacyList__delete (conflict_node); |
| } |
| else |
| { |
| InadequacyList__prependTo (conflict_node, |
| &inadequacy_lists[s->number]); |
| aver (AnnotationList__insertInto ( |
| annotation_node, &annotation_lists[s->number], |
| s->nitems)); |
| /* This aver makes sure the |
| AnnotationList__computeDominantContribution check above |
| does discard annotations in the simplest case of a S/R |
| conflict with no token precedence. */ |
| aver (!bitset_test (shift_tokens, conflicted_token) |
| || symbols[conflicted_token]->prec); |
| ++annotation_counts[s->number]; |
| if (contribution_count > *max_contributionsp) |
| *max_contributionsp = contribution_count; |
| AnnotationList__computePredecessorAnnotations ( |
| annotation_node, s, |
| follow_kernel_items, always_follows, predecessors, |
| item_lookahead_sets, annotation_lists, annotation_counts, |
| annotations_obstackp); |
| } |
| } |
| } |
| else |
| { |
| bitset_free (actions); |
| obstack_free (annotations_obstackp, annotation_node); |
| } |
| } |
| |
| bitsetv_free (all_lookaheads); |
| bitset_free (shift_tokens); |
| bitset_free (conflicted_tokens); |
| } |
| |
| void |
| AnnotationList__debug (AnnotationList const *self, size_t nitems, int spaces) |
| { |
| AnnotationList const *a; |
| AnnotationIndex ai; |
| for (a = self, ai = 0; a; a = a->next, ++ai) |
| { |
| { |
| int j; |
| for (j = 0; j < spaces; ++j) |
| putc (' ', stderr); |
| } |
| fprintf (stderr, "Annotation %d (manifesting state %d):\n", |
| ai, a->inadequacyNode->manifestingState->number); |
| { |
| ContributionIndex ci; |
| bitset_bindex rulei = 0; /* init suppresses compiler warning */ |
| rulei = bitset_first (a->inadequacyNode->inadequacy.conflict.actions); |
| for (ci = 0; ci < a->inadequacyNode->contributionCount; ++ci) |
| { |
| symbol_number token = |
| InadequacyList__getContributionToken (a->inadequacyNode, ci) |
| ->number; |
| { |
| int j; |
| for (j = 0; j < spaces+2; ++j) |
| putc (' ', stderr); |
| } |
| if (ci == InadequacyList__getShiftContributionIndex ( |
| a->inadequacyNode)) |
| fprintf (stderr, "Contributes shift of token %d.\n", token); |
| else |
| { |
| fprintf (stderr, "Contributes token %d", token); |
| aver (rulei != BITSET_BINDEX_MAX); |
| fprintf (stderr, " as lookahead, rule number %d", |
| a->inadequacyNode->manifestingState |
| ->reductions->rules[rulei]->number); |
| rulei = |
| bitset_next (a->inadequacyNode->inadequacy.conflict.actions, |
| rulei+1); |
| if (AnnotationList__isContributionAlways (a, ci)) |
| fprintf (stderr, " always."); |
| else |
| { |
| fprintf (stderr, ", items: "); |
| Sbitset__fprint (a->contributions[ci], nitems, stderr); |
| } |
| fprintf (stderr, "\n"); |
| } |
| } |
| } |
| } |
| } |
| |
| void |
| AnnotationList__computeLookaheadFilter (AnnotationList const *self, |
| size_t nitems, |
| bitsetv lookahead_filter) |
| { |
| bitsetv_zero (lookahead_filter); |
| for (; self; self = self->next) |
| { |
| ContributionIndex ci; |
| for (ci = 0; ci < self->inadequacyNode->contributionCount; ++ci) |
| if (!AnnotationList__isContributionAlways (self, ci)) |
| { |
| Sbitset__Index item; |
| Sbitset biter; |
| symbol_number token = |
| InadequacyList__getContributionToken (self->inadequacyNode, ci) |
| ->number; |
| SBITSET__FOR_EACH (self->contributions[ci], nitems, biter, item) |
| bitset_set (lookahead_filter[item], token); |
| } |
| } |
| } |
| |
| /** |
| * \pre |
| * - <tt>self != NULL</tt>. |
| * - \c nitems is the number of kernel items in the LR(0) state that \c self |
| * annotates. |
| * - \c lookaheads describes the lookahead sets on the kernel items of some |
| * isocore of the LR(0) state that \c self annotates. Either: |
| * - <tt>lookaheads = NULL</tt> only if the lookahead set on every kernel |
| * item is empty. |
| * - For any <tt>0 <= i < nitems</tt>, <tt>lookaheads[i]</tt> is either: |
| * - \c NULL only if the lookahead set on kernel item \c i is empty. |
| * - The (possibly empty) lookahead set on kernel item \c i. |
| * - <tt>0 <= ci < self->inadequacyNode->contributionCount</tt>. |
| * \post |
| * - \c result = true iff contribution \c ci in \c self is made by the state |
| * described by \c lookaheads. |
| */ |
| static bool |
| AnnotationList__stateMakesContribution (AnnotationList const *self, |
| size_t nitems, ContributionIndex ci, |
| bitset *lookaheads) |
| { |
| if (AnnotationList__isContributionAlways (self, ci)) |
| return true; |
| if (!lookaheads) |
| return false; |
| { |
| symbol_number token = |
| InadequacyList__getContributionToken (self->inadequacyNode, ci)->number; |
| Sbitset__Index item; |
| Sbitset biter; |
| SBITSET__FOR_EACH (self->contributions[ci], nitems, biter, item) |
| if (lookaheads[item] && bitset_test (lookaheads[item], token)) |
| return true; |
| } |
| return false; |
| } |
| |
| ContributionIndex |
| AnnotationList__computeDominantContribution (AnnotationList const *self, |
| size_t nitems, bitset *lookaheads, |
| bool require_split_stable) |
| { |
| symbol *token; |
| ContributionIndex const ci_shift = |
| InadequacyList__getShiftContributionIndex (self->inadequacyNode); |
| |
| token = self->inadequacyNode->inadequacy.conflict.token; |
| |
| /* S/R conflict. */ |
| if (ci_shift != ContributionIndex__none) |
| { |
| bool find_stable_domination_over_shift = false; |
| bool find_stable_error_action_domination = false; |
| { |
| ContributionIndex ci; |
| int actioni; |
| ContributionIndex ci_rr_dominator = ContributionIndex__none; |
| int shift_precedence = token->prec; |
| |
| /* If the token has no precedence set, shift is always chosen. */ |
| if (!shift_precedence) |
| return ci_shift; |
| |
| /* Figure out which reductions contribute, which of those would |
| dominate in a R/R comparison, and whether any reduction dominates |
| the shift so that the R/R comparison is actually needed. */ |
| for (ci = 0, actioni = bitset_first (self->inadequacyNode->inadequacy |
| .conflict.actions); |
| ci < self->inadequacyNode->contributionCount; |
| ++ci, actioni = bitset_next (self->inadequacyNode->inadequacy |
| .conflict.actions, actioni+1)) |
| { |
| int reduce_precedence = 0; |
| if (ci == ci_shift) |
| continue; |
| { |
| rule *r = self->inadequacyNode->manifestingState |
| ->reductions->rules[actioni]; |
| if (r->prec) |
| reduce_precedence = r->prec->prec; |
| } |
| /* If there's no need to check whether this reduction actually |
| contributes because the shift eliminates it from the R/R |
| comparison anyway, continue to the next reduction. */ |
| if (reduce_precedence |
| && (reduce_precedence < shift_precedence |
| || (reduce_precedence == shift_precedence |
| && token->assoc == right_assoc))) |
| continue; |
| if (!AnnotationList__stateMakesContribution (self, nitems, ci, |
| lookaheads)) |
| continue; |
| /* This uneliminated reduction contributes, so see if it can cause |
| an error action. */ |
| if (reduce_precedence == shift_precedence |
| && token->assoc == non_assoc) |
| { |
| /* It's not possible to find split-stable domination over |
| shift after a potential %nonassoc. */ |
| if (find_stable_domination_over_shift) |
| return ContributionIndex__none; |
| if (!require_split_stable |
| || AnnotationList__isContributionAlways (self, ci)) |
| return ContributionIndex__error_action; |
| find_stable_error_action_domination = true; |
| } |
| /* Consider this uneliminated contributing reduction in the R/R |
| comparison. */ |
| if (ci_rr_dominator == ContributionIndex__none) |
| ci_rr_dominator = ci; |
| /* If precedence is set for this uneliminated contributing |
| reduction, it dominates the shift, so try to figure out which |
| reduction dominates the R/R comparison. */ |
| if (reduce_precedence) |
| { |
| /* It's not possible to find split-stable error action |
| domination after a potential reduction. */ |
| if (find_stable_error_action_domination) |
| return ContributionIndex__none; |
| if (!require_split_stable) |
| return ci_rr_dominator; |
| if (!AnnotationList__isContributionAlways (self, |
| ci_rr_dominator)) |
| return ContributionIndex__none; |
| if (AnnotationList__isContributionAlways (self, ci)) |
| return ci_rr_dominator; |
| find_stable_domination_over_shift = true; |
| } |
| } |
| } |
| if (find_stable_domination_over_shift |
| || find_stable_error_action_domination) |
| return ContributionIndex__none; |
| /* No reduce or error action domination found, so shift dominates. */ |
| return ci_shift; |
| } |
| |
| /* R/R conflict, so the reduction with the lowest rule number dominates. |
| Fortunately, contributions are sorted by rule number. */ |
| { |
| ContributionIndex ci; |
| for (ci = 0; ci < self->inadequacyNode->contributionCount; ++ci) |
| if (AnnotationList__stateMakesContribution (self, nitems, ci, |
| lookaheads)) |
| { |
| if (require_split_stable |
| && !AnnotationList__isContributionAlways (self, ci)) |
| return ContributionIndex__none; |
| return ci; |
| } |
| } |
| return ContributionIndex__none; |
| } |