mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 20:33:03 +00:00
Add new files for IELR and canonical LR implementation.
* src/AnnotationList.c: New. * src/AnnotationList.h: New. * src/InadequacyList.c: New. * src/InadequacyList.h: New. * src/Sbitset.c: New. * src/Sbitset.h: New. * src/ielr.c: New. * src/ielr.h: New.
This commit is contained in:
12
ChangeLog
12
ChangeLog
@@ -1,3 +1,15 @@
|
||||
2009-04-21 Joel E. Denny <jdenny@ces.clemson.edu>
|
||||
|
||||
Add new files for IELR and canonical LR implementation.
|
||||
* src/AnnotationList.c: New.
|
||||
* src/AnnotationList.h: New.
|
||||
* src/InadequacyList.c: New.
|
||||
* src/InadequacyList.h: New.
|
||||
* src/Sbitset.c: New.
|
||||
* src/Sbitset.h: New.
|
||||
* src/ielr.c: New.
|
||||
* src/ielr.h: New.
|
||||
|
||||
2009-04-20 Joel E. Denny <jdenny@ces.clemson.edu>
|
||||
|
||||
Implement %define lr.default_rules.
|
||||
|
||||
811
src/AnnotationList.c
Normal file
811
src/AnnotationList.c
Normal file
@@ -0,0 +1,811 @@
|
||||
/* IELR's inadequacy annotation list.
|
||||
|
||||
Copyright (C) 2009 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 memory address of the associated inadequacy
|
||||
* node. Because memory is usually allocated in ascending order (FIXME:
|
||||
* Is this true enough? Should we keep some sort of global index to
|
||||
* guarantee it?), 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 < (*node)->inadequacyNode)
|
||||
cmp = 1;
|
||||
else if ((*node)->inadequacyNode < self->inadequacyNode)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
}
|
||||
177
src/AnnotationList.h
Normal file
177
src/AnnotationList.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/* IELR's inadequacy annotation list.
|
||||
|
||||
Copyright (C) 2009 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/>. */
|
||||
|
||||
#ifndef ANNOTATION_LIST_H_
|
||||
# define ANNOTATION_LIST_H_
|
||||
|
||||
#include <bitsetv.h>
|
||||
#include "Sbitset.h"
|
||||
#include "InadequacyList.h"
|
||||
#include "state.h"
|
||||
|
||||
typedef unsigned int AnnotationIndex;
|
||||
|
||||
/**
|
||||
* A node in a list of annotations on a particular LR(0) state. Each
|
||||
* annotation records how isocores of that LR(0) state might contribute to an
|
||||
* individual inadequacy, which might manifest in a different state. Don't
|
||||
* break encapsulation by modifying the fields directly. Use the provided
|
||||
* interface functions.
|
||||
*/
|
||||
typedef struct AnnotationList
|
||||
{
|
||||
/** The next node in the list or \c NULL if none. */
|
||||
struct AnnotationList *next;
|
||||
/** The \c InadequacyList node describing how this inadequacy manifests. */
|
||||
InadequacyList *inadequacyNode;
|
||||
/**
|
||||
* List of how the "always", "never", and potential contributions of the
|
||||
* inadequacy might be made by isocores of the annotated LR(0) state:
|
||||
* - The number of rows is the number of contributions. That is,
|
||||
* <tt>AnnotationList::inadequacyNode->contributionCount</tt>.
|
||||
* - The token associated with contribution \c i is
|
||||
* <tt>InadequacyList__getContributionToken (AnnotationList::inadequacyNode, i)</tt>.
|
||||
* - Iff <tt>AnnotationList::contributions[i] = NULL</tt>, contribution
|
||||
* \c i is an "always" contribution. That is, for every isocore of the
|
||||
* annotated LR(0) state, its core or the core of one its eventual
|
||||
* successors will definitely make this contribution to the inadequacy.
|
||||
* It may contribute by either:
|
||||
* - Creating a shift of contribution <tt>i</tt>'s token in the state
|
||||
* that can manifest the inadequacy.
|
||||
* - Propagating that token to the lookahead set of contribution
|
||||
* <tt>i</tt>'s reduction in the state that can manifest the
|
||||
* inadequacy.
|
||||
* - Otherwise:
|
||||
* - The number of columns in <tt>AnnotationList::contributions[i]</tt>
|
||||
* is the number of kernel items in any isocore of the annotated LR(0)
|
||||
* state.
|
||||
* - Iff <tt>AnnotationList::contributions[i]</tt> is empty, contribution
|
||||
* \c i is a "never" contribution. That is, no isocore of the
|
||||
* annotated LR(0) state can make this contribution to the inadequacy.
|
||||
* - Otherwise, for each bit \c j that is set in
|
||||
* <tt>AnnotationList::contributions[i]</tt>, if the token associated
|
||||
* with contribution \c i is present in the lookahead set of kernel
|
||||
* item \c j of an isocore of the annotated LR(0) state, that isocore
|
||||
* will make contribution \c i to the inadequacy by propagating the
|
||||
* contribution's token to the lookahead set of the contribution's
|
||||
* reduction in the state that can manifest the inadequacy.
|
||||
*/
|
||||
Sbitset contributions[1];
|
||||
} AnnotationList;
|
||||
|
||||
/**
|
||||
* \pre
|
||||
* - <tt>s != NULL</tt>.
|
||||
* - \c follow_kernel_items, \c always_follows, and \c predecessors were
|
||||
* computed by \c ielr_compute_auxiliary_tables.
|
||||
* - The size of each of \c annotation_lists and \c annotation_counts is
|
||||
* \c ::nstates.
|
||||
* \post
|
||||
* - <tt>inadequacy_lists[s->number]</tt> now describes all inadequacies that
|
||||
* manifest in \c s.
|
||||
* - For every state <tt>states[i]</tt>, <tt>annotation_lists[i]</tt> now
|
||||
* contains all annotations associated with all inadequacies that manifest
|
||||
* in \c s.
|
||||
* - <tt>annotation_counts[i]</tt> was incremented by the number of new
|
||||
* annotations added to <tt>states[i]</tt>.
|
||||
* - <tt>*max_contributionsp</tt> is the higher of:
|
||||
* - The maximum number of contributions computed per annotation.
|
||||
* - <tt>*max_contributionsp \@pre</tt>.
|
||||
* - All memory for all new annotations was allocated on
|
||||
* \c annotations_obstackp.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* \pre
|
||||
* - <tt>self != NULL</tt>.
|
||||
* - \c nitems is the number of kernel items in the LR(0) state that every
|
||||
* node in the list \c self annotates.
|
||||
* \post
|
||||
* - A textual representation of all nodes in the list \c self was printed to
|
||||
* stderr. \c spaces spaces were printed before each line of the text.
|
||||
*/
|
||||
void AnnotationList__debug (AnnotationList const *self, size_t nitems,
|
||||
int spaces);
|
||||
|
||||
/**
|
||||
* \pre
|
||||
* - <tt>self != NULL</tt>.
|
||||
* - \c nitems is the number of kernel items in the LR(0) state that \c self
|
||||
* annotates.
|
||||
* - The number of rows in \c lookahead_filter is at least \c nitems, and the
|
||||
* number of columns is \c ::ntokens.
|
||||
* \post
|
||||
* - <tt>lookahead_filter[i][j]</tt> is set iff some annotation in the list
|
||||
* \c self lists token \c j in kernel item \c i as a contributor.
|
||||
*/
|
||||
void AnnotationList__computeLookaheadFilter (AnnotationList const *self,
|
||||
size_t nitems,
|
||||
bitsetv lookahead_filter);
|
||||
|
||||
/**
|
||||
* \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.
|
||||
* \post
|
||||
* - If <tt>require_split_stable = false</tt>, \c result = either:
|
||||
* - \c ContributionIndex__none iff the state described by \c lookaheads
|
||||
* makes none of the contributions in \c self.
|
||||
* - The index of the dominating contribution in \c self that is made by
|
||||
* that state.
|
||||
* - \c ContributionIndex__error_action to indicate that the inadequacy
|
||||
* manifests as a conflict and that a syntax error action (because of a
|
||||
* %nonassoc) dominates instead.
|
||||
* - Otherwise, \c result is the same as if <tt>require_split_stable =
|
||||
* false</tt> except that it is also \c ContributionIndex__none if there
|
||||
* are contributions made by the state but the dominating contribution is
|
||||
* not split-stable. By split-stable, we mean that the dominating
|
||||
* contribution cannot change due to loss of one or more potential
|
||||
* contributions due to loss of lookaheads due to splitting of the state.
|
||||
* - After determining which contributions are actually made by the state,
|
||||
* the algorithm for determining which contribution dominates in the
|
||||
* conflict is intended to choose exactly the same action as conflicts.c
|
||||
* would choose... no matter how crazy conflicts.c's choice is.
|
||||
*/
|
||||
ContributionIndex
|
||||
AnnotationList__computeDominantContribution (AnnotationList const *self,
|
||||
size_t nitems, bitset *lookaheads,
|
||||
bool require_split_stable);
|
||||
|
||||
#endif /* !ANNOTATION_LIST_H_ */
|
||||
76
src/InadequacyList.c
Normal file
76
src/InadequacyList.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/* IELR's inadequacy list.
|
||||
|
||||
Copyright (C) 2009 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 "InadequacyList.h"
|
||||
|
||||
ContributionIndex const ContributionIndex__none = -1;
|
||||
ContributionIndex const ContributionIndex__error_action = -2;
|
||||
|
||||
InadequacyList *
|
||||
InadequacyList__new_conflict (state *manifesting_state, symbol *token,
|
||||
bitset actions)
|
||||
{
|
||||
InadequacyList *result = xmalloc (sizeof *result);
|
||||
result->next = NULL;
|
||||
result->manifestingState = manifesting_state;
|
||||
result->contributionCount = bitset_count (actions);
|
||||
result->inadequacy.conflict.token = token;
|
||||
result->inadequacy.conflict.actions = actions;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
InadequacyList__delete (InadequacyList *self)
|
||||
{
|
||||
while (self)
|
||||
{
|
||||
InadequacyList *node = self;
|
||||
self = self->next;
|
||||
bitset_free (node->inadequacy.conflict.actions);
|
||||
free (node);
|
||||
}
|
||||
}
|
||||
|
||||
ContributionIndex
|
||||
InadequacyList__getShiftContributionIndex (InadequacyList const *self)
|
||||
{
|
||||
if (!bitset_test (self->inadequacy.conflict.actions,
|
||||
self->manifestingState->reductions->num))
|
||||
return ContributionIndex__none;
|
||||
return self->contributionCount - 1;
|
||||
}
|
||||
|
||||
symbol *
|
||||
InadequacyList__getContributionToken (InadequacyList const *self,
|
||||
ContributionIndex i)
|
||||
{
|
||||
aver (0 <= i && i < self->contributionCount);
|
||||
return self->inadequacy.conflict.token;
|
||||
}
|
||||
|
||||
void
|
||||
InadequacyList__prependTo (InadequacyList *self, InadequacyList **list)
|
||||
{
|
||||
InadequacyList *head_old = *list;
|
||||
*list = self;
|
||||
self->next = head_old;
|
||||
}
|
||||
135
src/InadequacyList.h
Normal file
135
src/InadequacyList.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/* IELR's inadequacy list.
|
||||
|
||||
Copyright (C) 2009 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/>. */
|
||||
|
||||
#ifndef INADEQUACY_LIST_H_
|
||||
# define INADEQUACY_LIST_H_
|
||||
|
||||
#include <bitset.h>
|
||||
#include "gram.h"
|
||||
#include "state.h"
|
||||
#include "symtab.h"
|
||||
|
||||
/**
|
||||
* For a conflict, each rule in the grammar can have at most one contributing
|
||||
* reduction except that rule 0 cannot have any because the reduction on rule 0
|
||||
* cannot have lookaheads. For a conflict, exactly one shift can contribute.
|
||||
* Thus the number of rules in the grammar is an upper bound on the number of
|
||||
* possible contributions to any conflict. The maximum number of possible
|
||||
* items in a state is also an upper bound, but the \c nitems member of \c
|
||||
* state is currently a \c size_t and thus, if changed, risks becoming out of
|
||||
* sync with this type. Whatever the type, it must support negatives for sake
|
||||
* of the special values below.
|
||||
*/
|
||||
typedef rule_number ContributionIndex;
|
||||
|
||||
/* Special \c ContributionIndex used to indicate null result when looking for a
|
||||
contribution. */
|
||||
extern ContributionIndex const ContributionIndex__none;
|
||||
|
||||
/* Special \c ContributionIndex used by
|
||||
\c AnnotationList__computeDominantContribution to signal when the action
|
||||
chosen in a conflict is a syntax error because of a %nonassoc. */
|
||||
extern ContributionIndex const ContributionIndex__error_action;
|
||||
|
||||
/**
|
||||
* The description of a conflict. Don't break encapsulation by modifying the
|
||||
* fields directly. Use the provided interface functions for
|
||||
* \c InadequacyList.
|
||||
*/
|
||||
typedef struct {
|
||||
/** The \c token passed to \c InadequacyList__new_conflict. */
|
||||
symbol *token;
|
||||
/** The \c actions passed to \c InadequacyList__new_conflict. */
|
||||
bitset actions;
|
||||
} Conflict;
|
||||
|
||||
/**
|
||||
* A node in a list that describes all the inadequacies that manifest in a
|
||||
* particular state. Don't break encapsulation by modifying the fields
|
||||
* directly. Use the provided interface functions.
|
||||
*/
|
||||
typedef struct InadequacyList {
|
||||
struct InadequacyList *next;
|
||||
state *manifestingState;
|
||||
ContributionIndex contributionCount;
|
||||
union {
|
||||
Conflict conflict;
|
||||
} inadequacy;
|
||||
} InadequacyList;
|
||||
|
||||
/**
|
||||
* \pre
|
||||
* - <tt>manifesting_state != NULL</tt>.
|
||||
* - \c token is a token.
|
||||
* - The size of \c actions is
|
||||
* <tt>manifesting_state->reductions->num + 1</tt>.
|
||||
* \post
|
||||
* - \c result is a new \c InadequacyList with one node indicating that, in
|
||||
* \c manifesting_state, the following actions are in conflict on \c token:
|
||||
* - Shift iff
|
||||
* <tt>bitset_test (actions, manifesting_state->reductions->num)</tt>.
|
||||
* - For any \c i such that
|
||||
* <tt>0 <= i < manifesting_state->reductions->num</tt>, the reduction
|
||||
* for the rule <tt>manifesting_state->reductions->rules[i]</tt> iff
|
||||
* <tt>actions[i]</tt> is set.
|
||||
* - \c result assumes responsibility for the memory of \c actions.
|
||||
*/
|
||||
InadequacyList *InadequacyList__new_conflict (state *manifesting_state,
|
||||
symbol *token, bitset actions);
|
||||
|
||||
/**
|
||||
* \post
|
||||
* - All memory associated with all nodes in the list \c self was freed.
|
||||
*/
|
||||
void InadequacyList__delete (InadequacyList *self);
|
||||
|
||||
/**
|
||||
* \pre
|
||||
* - <tt>self != NULL</tt>.
|
||||
* \post
|
||||
* - \c result = either:
|
||||
* - \c ContributionIndex__none iff there is no shift contribution in
|
||||
* \c self (perhaps because \c self isn't a conflict).
|
||||
* - The index of the shift contribution, otherwise.
|
||||
*/
|
||||
ContributionIndex
|
||||
InadequacyList__getShiftContributionIndex (InadequacyList const *self);
|
||||
|
||||
/**
|
||||
* \pre
|
||||
* - <tt>self != NULL</tt>.
|
||||
* - <tt>0 <= i < self->contributionCount</tt>.
|
||||
* \post
|
||||
* - \c result = the token associated with contribution \c i in the
|
||||
* inadequacy described by the node \c self.
|
||||
*/
|
||||
symbol *InadequacyList__getContributionToken (InadequacyList const *self,
|
||||
ContributionIndex i);
|
||||
|
||||
/**
|
||||
* \pre
|
||||
* - \c self is a single node.
|
||||
* - <tt>list != NULL</tt>.
|
||||
* \post
|
||||
* - \c list now contains \c self as its first node.
|
||||
* - \c list assumes responsibility for the memory of \c self.
|
||||
*/
|
||||
void InadequacyList__prependTo (InadequacyList *self, InadequacyList **list);
|
||||
|
||||
#endif /* !INADEQUACY_LIST_H_ */
|
||||
78
src/Sbitset.c
Normal file
78
src/Sbitset.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/* A simple, memory-efficient bitset implementation.
|
||||
|
||||
Copyright (C) 2009 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 "Sbitset.h"
|
||||
|
||||
Sbitset
|
||||
Sbitset__new (Sbitset__Index nbits)
|
||||
{
|
||||
/* Some functions, like Sbitset__last_byte_mask, will fail if nbits = 0. */
|
||||
aver (nbits);
|
||||
return xcalloc (1, Sbitset__nbytes (nbits));
|
||||
}
|
||||
|
||||
Sbitset
|
||||
Sbitset__new_on_obstack (Sbitset__Index nbits, struct obstack *obstackp)
|
||||
{
|
||||
char *result;
|
||||
char *ptr;
|
||||
char *end;
|
||||
aver (nbits);
|
||||
result = obstack_alloc (obstackp, Sbitset__nbytes (nbits));
|
||||
for (ptr = result, end = result + Sbitset__nbytes (nbits); ptr < end; ++ptr)
|
||||
*ptr = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
Sbitset__delete (Sbitset self)
|
||||
{
|
||||
free (self);
|
||||
}
|
||||
|
||||
bool
|
||||
Sbitset__isEmpty (Sbitset self, Sbitset__Index nbits)
|
||||
{
|
||||
char *last = self + Sbitset__nbytes (nbits) - 1;
|
||||
for (; self < last; ++self)
|
||||
if (*self != 0)
|
||||
return false;
|
||||
return ((*last) & Sbitset__last_byte_mask (nbits)) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
Sbitset__fprint(Sbitset self, Sbitset__Index nbits, FILE *file)
|
||||
{
|
||||
Sbitset__Index i;
|
||||
Sbitset itr;
|
||||
bool first = true;
|
||||
fprintf (file, "nbits = %d, set = {", nbits);
|
||||
SBITSET__FOR_EACH (self, nbits, itr, i)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
fprintf (file, ",");
|
||||
fprintf (file, " %d", i);
|
||||
}
|
||||
fprintf (file, " }");
|
||||
}
|
||||
87
src/Sbitset.h
Normal file
87
src/Sbitset.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* A simple, memory-efficient bitset implementation.
|
||||
|
||||
Copyright (C) 2009 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/>. */
|
||||
|
||||
#ifndef SBITSET_H_
|
||||
# define SBITSET_H_
|
||||
|
||||
typedef char *Sbitset;
|
||||
typedef size_t Sbitset__Index;
|
||||
|
||||
#define Sbitset__nbytes(NBITS) (((NBITS)+7)/8)
|
||||
#define Sbitset__byteAddress(SELF, INDEX) (((SELF) + (INDEX)/8))
|
||||
#define Sbitset__bit_mask(INDEX) (0x1 << (7 - (INDEX)%8))
|
||||
#define Sbitset__last_byte_mask(NBITS) (0xff << (7 - ((NBITS)-1)%8))
|
||||
|
||||
/* nbits must not be 0. */
|
||||
Sbitset Sbitset__new (Sbitset__Index nbits);
|
||||
Sbitset Sbitset__new_on_obstack (Sbitset__Index nbits,
|
||||
struct obstack *obstackp);
|
||||
void Sbitset__delete (Sbitset self);
|
||||
|
||||
#define Sbitset__test(SELF, INDEX) \
|
||||
((*Sbitset__byteAddress ((SELF), (INDEX)) & Sbitset__bit_mask (INDEX)) != 0)
|
||||
|
||||
bool Sbitset__isEmpty (Sbitset self, Sbitset__Index nbits);
|
||||
|
||||
void Sbitset__fprint(Sbitset self, Sbitset__Index nbits, FILE *file);
|
||||
|
||||
#define Sbitset__set(SELF, INDEX) \
|
||||
do { \
|
||||
*Sbitset__byteAddress ((SELF), (INDEX)) = \
|
||||
*Sbitset__byteAddress ((SELF), (INDEX)) | Sbitset__bit_mask (INDEX); \
|
||||
} while(0)
|
||||
|
||||
#define Sbitset__reset(SELF, INDEX) \
|
||||
do { \
|
||||
*Sbitset__byteAddress ((SELF), (INDEX)) = \
|
||||
*Sbitset__byteAddress ((SELF), (INDEX)) & ~Sbitset__bit_mask (INDEX); \
|
||||
} while(0)
|
||||
|
||||
/* NBITS is the size of the bitset. More than NBITS bits might be reset. */
|
||||
#define Sbitset__zero(SELF, NBITS) \
|
||||
do { \
|
||||
memset (SELF, 0, Sbitset__nbytes (NBITS)); \
|
||||
} while(0)
|
||||
|
||||
/* NBITS is the size of the bitset. More than NBITS bits might be set. */
|
||||
#define Sbitset__ones(SELF, NBITS) \
|
||||
do { \
|
||||
memset (SELF, 0xff, Sbitset__nbytes (NBITS)); \
|
||||
} while(0)
|
||||
|
||||
/* NBITS is the size of every bitset. More than NBITS bits might be set. */
|
||||
#define Sbitset__or(SELF, OTHER1, OTHER2, NBITS) \
|
||||
do { \
|
||||
char *ptr_self = (SELF); \
|
||||
char *ptr_other1 = (OTHER1); \
|
||||
char *ptr_other2 = (OTHER2); \
|
||||
char *end_self = ptr_self + Sbitset__nbytes (NBITS); \
|
||||
for (; ptr_self < end_self; ++ptr_self, ++ptr_other1, ++ptr_other2) \
|
||||
*ptr_self = *ptr_other1 | *ptr_other2; \
|
||||
} while(0)
|
||||
|
||||
#define SBITSET__FOR_EACH(SELF, NBITS, ITER, INDEX) \
|
||||
for ((ITER) = (SELF); (ITER) < (SELF) + Sbitset__nbytes (NBITS); ++(ITER)) \
|
||||
if (*(ITER) != 0) \
|
||||
for ((INDEX) = ((ITER)-(SELF))*8; \
|
||||
(INDEX) < (NBITS) && (SELF)+(INDEX)/8 < (ITER)+1; \
|
||||
++(INDEX)) \
|
||||
if (((*ITER) & Sbitset__bit_mask (INDEX)) != 0)
|
||||
|
||||
#endif /* !SBITSET_H_ */
|
||||
1200
src/ielr.c
Normal file
1200
src/ielr.c
Normal file
File diff suppressed because it is too large
Load Diff
46
src/ielr.h
Normal file
46
src/ielr.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* IELR main implementation.
|
||||
|
||||
Copyright (C) 2009 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/>. */
|
||||
|
||||
#ifndef IELR_H_
|
||||
# define IELR_H_
|
||||
|
||||
#include <bitset.h>
|
||||
|
||||
#include "state.h"
|
||||
|
||||
/**
|
||||
* \pre
|
||||
* - \c ::states is of size \c ::nstates and defines an LALR(1) parser for
|
||||
* the users's grammar.
|
||||
* - \c ::ntokens is the number of tokens in the grammar.
|
||||
* \post
|
||||
* - \c ::states is of size \c ::nstates (which might be greater than
|
||||
* <tt>::nstates \@pre</tt>) and defines the type of parser specified by
|
||||
* the value of the \c \%define variable \c lr.type. Its value can be:
|
||||
* - \c "LALR".
|
||||
* - \c "IELR".
|
||||
* - \c "canonical LR".
|
||||
*/
|
||||
void ielr (void);
|
||||
|
||||
bool ielr_item_has_lookahead (state *s, symbol_number lhs, size_t item,
|
||||
symbol_number lookahead, state ***predecessors,
|
||||
bitset **item_lookahead_sets);
|
||||
|
||||
#endif /* !IELR_H_ */
|
||||
Reference in New Issue
Block a user