#include	"global.h"
#include	"list.h"
#include	"irep.h"
#include	"fsa.h"

LexRuleList LexRule::ruleSet;

LexRule::LexRule(char* n)
{
	_name = allocate(strlen(n)+1); strcpy(_name, n);
	_hasDefinition = FALSE;
	_isIgnored = FALSE;
	_isToken = FALSE;
	_filter = 0;
	LexRule *thisRule = this;
	ruleSet.append(thisRule);
}

// The member function find() uses the iterator facility to traverse the
// list for a rule name that matches the target.

LexRule *LexRuleList::find(char *target)
{
	listIter<LexRule *> forEach(this);
	LexRule **item;

	while (item = forEach())
		if (strcmp((*item)->name(), target) == 0)
			return(*item);
	return 0;
}

// Each rule specification of a token is converted in turn to an
// appropriate FSA via invoking the member function process() with the
// initial state.  It in turn invokes the process() member function of
// each LexNode instance.  Ultimately, it returns the final state.  A
// rule with an empty body does not need to generate additional states.

fsaState *LexRule::process(fsaState *init)
{
	fsaState *dest;

#ifdef	DEBUGPRINT
	printf("%s = ", name());
#endif
	dest = (body() ? body()->process(init) : 0);
#ifdef	DEBUGPRINT
	printf(".\n");
#endif
	return dest;
}

// Since the process() member function for LexNode is a stub it should
// not be invoked but redefined in derived classes.

fsaState *LexNode::process(fsaState *)
{
	error(INTERNAL, "Node::process");
}

// The FSA is extended for a terminal symbol by making a new FSA state
// and including an appropriate transition from source to destination
// states.

fsaState *LexCharNode::process(fsaState *init)
{
	fsaState *dest;

#ifdef	DEBUGPRINT
	if (ch1() == ch2())
		printf("#%d ", ch1());
	else
		printf("#%d .. #%d ", ch1(), ch2());
#endif

	dest = new fsaState();
	for (int i = ch1(); i <= ch2(); i++)
	    init->transitions.append(new Transition(i, dest));

// The conversion process continues along the rule sequence so that
// it returns the final FSA state for that sequence.

	return(next ? next->process(dest) : dest);
}

// The FSA is extended for a nonterminal symbol by recursively
// invoking process() for the nonterminal rule.  As before, the
// conversion procedure subsequently resumes for follower nodes.

fsaState *LexNonTermNode::process(fsaState *init)
{
	LexNode *rule;

#ifdef	DEBUGPRINT
	printf("%s ", nonterm()->name());
#endif

	rule = nonterm()->body();
	fsaState *dest = (rule ? rule->process(init) : init);
	return(next ? next->process(dest) : dest);
}

// The FSA is extended for an alternative node by recursively invoking
// process() for the alternative rules.  Null transitions are
// subsequently required to merge the two alternatives to a common
// state.  As before, the conversion procedure subsequently resumes for
// follower nodes.

fsaState *LexSelectNode::process(fsaState *init)
{
	fsaState *dest1, *dest2, *dest;

#ifdef	DEBUGPRINT
	printf("( ");
#endif
	dest1 = (fsaState *) (alt1() ? alt1()->process(init) : init);
#ifdef	DEBUGPRINT
	printf("| ");
#endif
	dest2 = (fsaState *) (alt2() ? alt2()->process(init) : init);
#ifdef	DEBUGPRINT
	printf(") ");
#endif
	dest = new fsaState();
	dest1->transitions.append(new Transition(Transition::NOCHAR, dest));
	dest2->transitions.append(new Transition(Transition::NOCHAR, dest));
        return(next ? next->process(dest) : dest);
}

// The FSA is extended for a repetitive node by recursively invoking
// process() for the repetitive rules.  Appropriate null transitions are
// subsequently required to connect sub-FSAs to reflect the semantics of
// repetition.  As before, the conversion procedure subsequently resumes
// for follower nodes.

fsaState *LexRepeatNode::process(fsaState *init)
{
	fsaState *start, *dest, *loop, *final;

#ifdef	DEBUGPRINT
	printf("{ ");
#endif
	start = new fsaState();
        init->transitions.append(new Transition(Transition::NOCHAR, start));
        dest = (repetition() ? repetition()->process(start) : start);
	if (separator()) {
#ifdef	DEBUGPRINT
		printf(", ");
#endif
		loop = separator()->process(dest);
	} else
		loop = dest;
	loop->transitions.append(new Transition(Transition::NOCHAR, start));
	final = new fsaState();
	dest->transitions.append(new Transition(Transition::NOCHAR, final));
	if (atLeastOne()) {
#ifdef	DEBUGPRINT
	    printf("}+ ")
#endif
	    ;
	} else {
            init->transitions.append(new Transition(Transition::NOCHAR, final));
#ifdef	DEBUGPRINT
	    printf("} ");
#endif
	}
	return(next ? next->process(final) : final);
}


syntax highlighted by Code2HTML, v. 0.9.1