mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-16 07:43: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>
|
2009-04-20 Joel E. Denny <jdenny@ces.clemson.edu>
|
||||||
|
|
||||||
Implement %define lr.default_rules.
|
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