#include "global.h"
#include "list.h"
#include "nodes.h"
#include "conf.h"
// The closure() member function adds the configuration implied by the
// current node and rule head to closureSet. It returns 1 if it is a
// new configuration, and 0 if it has been encountered previously.
int ParNode::closure(ParRule *head, LConfList *closureSet)
{
Conf *thisConf;
LConf *thisLConf = 0;
thisConf = Conf::confs.find(this);
if (thisConf == 0)
thisConf = new Conf(head, this);
thisLConf = LConf::cogs.find(thisConf);
if (thisLConf == 0)
thisLConf = new LConf(thisConf);
if (closureSet->find(thisLConf->conf) == 0) {
closureSet->append(thisLConf);
return 1;
}
return 0;
}
// For non-terminals, the current configuration is noted, and if it has
// not been encountered previously, the configurations anticipated by
// its constituents are also included.
void ParNonTermNode::findClosure(ParRule *head, LConfList *closureSet)
{
if (closure(head, closureSet) && nonterm()->isNonTerm())
nonterm()->rhs()->findClosure(nonterm(), closureSet);
}
// The current configuration is merely noted for the end of rule
// sequences. No further additions are required since no other
// configurations are implied.
void ParEndNode::findClosure(ParRule *head, LConfList *closureSet)
{
closure(head, closureSet);
}
// The closure for an Inherited attribute marker is similar to that of
// non-terminals since they are implemented as such.
void ParActionNode::findClosure(ParRule *head, LConfList *closureSet)
{
if (closure(head, closureSet))
nontermRule()->rhs()->findClosure(nontermRule(), closureSet);
}
// The closure for a selection node is computed by propagating the
// request down the individual rule bodies.
void ParSelectNode::findClosure(ParRule *head, LConfList *closure)
{
alt1()->findClosure(head, closure);
alt2()->findClosure(head, closure);
}
// The member function findMoves() enumerates symbols that are
// anticipated from a the current state, and constructs destination
// configuration sets if they don't already exist. It is recursively
// invoked from new configuration sets.
void ConfSet::findMoves()
{
list<ParRule *> triggerSet;
listIter<LConf *> forEachLConf(closure);
LConf **item;
// Symbols involved in shift transition are first accumulated by
// traversing through all configurations.
while (item = forEachLConf()) {
ParNode *n = (*item)->conf->dot;
if (n->next() && !triggerSet.find(n->nontermRule()))
triggerSet.append(n->nontermRule());
}
listIter<ParRule *> forEachRule(&triggerSet);
ParRule **rule;
ConfSet *newConfSet;
LConfList *destClosure = new LConfList();
while (rule = forEachRule()) {
listIter<LConf *> forEachLConf(closure);
LConf **cg;
// For each symbol involved in a transition, the closure for the new
// configuration is found together with the corresponding configuration
// set.
while (cg = forEachLConf()) {
ParNode *n = (*cg)->conf->dot;
if (n->next() && n->nontermRule() == *rule)
n->next()->findClosure((*cg)->conf->rule, destClosure);
}
// If the computed closure may be found in a configuration set, it must
// have existed and need not be created or re-visited.
newConfSet = confSets.find(destClosure);
if (newConfSet)
delete destClosure;
else {
// Alternatively, a new configuration set with the new closure set is
// created, and findMoves() is invoked recursively.
newConfSet = new ConfSet(destClosure);
newConfSet->findMoves();
}
moves.append(new Move(*rule, newConfSet));
destClosure = new LConfList();
}
delete destClosure;
}
// The following find member functions searches for a item in a list.
ConfSet *MoveList::findDest(ParRule *target)
{
node<Move *> *p = (node<Move *> *) head;
while (p) {
if (target == p->item->trigger)
return(p->item->dest);
p = (node<Move *> *) p->next;
}
return 0;
}
Conf *ConfList::find(ParNode *d)
{
node<Conf *> *p = (node<Conf *> *) head;
while (p) {
if (d == p->item->dot)
return(p->item);
p = (node<Conf *> *) p->next;
}
return 0;
}
LConf *LConfList::find(Conf *c)
{
node<LConf *> *p = (node<LConf *> *) head;
while (p) {
if (c == p->item->conf)
return(p->item);
p = (node<LConf *> *) p->next;
}
return 0;
}
void LConfList::replicate()
{
node<LConf *> *p = (node<LConf *> *) head;
while (p) {
p->item = new LConf(p->item->conf);
p = (node<LConf *> *) p->next;
}
}
ConfSet *ConfSetList::find(LConfList *c)
{
node<ConfSet *> *p = (node<ConfSet *> *) head;
while (p) {
if (c->contains(*(p->item->closure)) &&
p->item->closure->contains(*c))
return(p->item);
p = (node<ConfSet *> *) p->next;
}
return 0;
}
// The following show() member functions are for reporting purposes.
void Conf::show(FILE *fp)
{
fprintf(fp, "%s ::=", rule->name());
ParNode *prod = rule->rhs()->leadsTo(dot);
prod->show(dot, fp);
}
void LConf::show(FILE *fp)
{
conf->show(fp);
fprintf(fp, ",");
listIter<ParRule *> forEachRule(&lookAhead);
ParRule **r;
while (r = forEachRule())
fprintf(fp, " %s", (*r)->name());
fprintf(fp, "\n");
}
void ConfSet::show(FILE *fp)
{
printf("ConfSet %d:\n", id());
listIter<LConf *> forEach(closure);
LConf **item;
// print out lconfs
while (item = forEach())
(*item)->show(fp);
// print out moves
listIter<Move *> forEachMove(&moves);
Move **m;
while (m = forEachMove())
fprintf(fp, "\t%s -> %d\n", (*m)->trigger->name(),
(*m)->dest->id());
fprintf(fp, "\n");
}
// The append() member function for LConfList is redefined so that
// insertions for LConf items are ordered by their reduceOrder. This
// allows for correct reduce-reduce conflict resolution.
void LConfList::append(const LConf *i)
{
node<const LConf *> *n = new node<const LConf *>(i);
if (!len) {
len = 1;
head = tail = n;
return;
}
node<LConf *> *prev = 0, *h = (node<LConf *> *) head;
len++;
while (h)
if (i->conf->dot->reduceOrder() <
h->item->conf->dot->reduceOrder()) {
n->next = h;
if (prev)
prev->next = n; // middle of list
else
head = n; // first in list
return;
} else {
prev = h;
h = (node<LConf *> *) h->next;
}
prev->next = n; // last
tail = n;
}
ConfList Conf::confs;
LConfList LConf::cogs;
ConfSetList ConfSet::confSets;
int ConfSet::NextId = 1;
syntax highlighted by Code2HTML, v. 0.9.1