#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 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); }