internal Binary( RegOp op, RegExTree l, RegExTree r ) : base( op ) { lKid = l; rKid = r; }
/// <summary> /// Create a transition path in the NFSA from the given /// start state to the given end state, corresponding to the /// RegEx tree value. The method may (almost always does) /// create new NFSA states and recurses to make paths for /// the subtrees of the given tree. /// </summary> /// <param name="tree">The tree to encode</param> /// <param name="start">The start state for the pattern</param> /// <param name="end">The end state for the pattern</param> internal void MakePath(RegExTree tree, NState startState, NState endState) { NState tmp1 = null; NState tmp2 = null; int rLen, lLen; switch (tree.op) { case RegOp.eof: break; // Binary nodes =================================== case RegOp.context: case RegOp.concat: case RegOp.alt: // Binary nodes =================================== Binary binNode = tree as Binary; switch (tree.op) { case RegOp.context: rLen = binNode.rKid.contextLength(); lLen = binNode.lKid.contextLength(); if (rLen <= 0 && lLen <= 0) throw new StringInterpretException("variable right context '/' not implemented"); else { endState.rhCntx = rLen; endState.lhCntx = lLen; tmp1 = MkState(); MakePath(binNode.lKid, startState, tmp1); MakePath(binNode.rKid, tmp1, endState); } break; case RegOp.concat: tmp1 = MkState(); MakePath(binNode.lKid, startState, tmp1); MakePath(binNode.rKid, tmp1, endState); break; case RegOp.alt: tmp1 = MkState(); MakePath(binNode.lKid, startState, tmp1); tmp1.AddEpsTrns(endState); tmp1 = MkState(); MakePath(binNode.rKid, startState, tmp1); tmp1.AddEpsTrns(endState); break; } break; // Unary nodes =================================== case RegOp.closure: case RegOp.finiteRep: // Unary nodes =================================== Unary unaryNode = tree as Unary; switch (tree.op) { case RegOp.closure: tmp2 = MkState(); if (unaryNode.minRep == 0) { tmp1 = MkState(); startState.AddEpsTrns(tmp1); } else { NState dummy = startState; for (int i = 0; i < unaryNode.minRep; i++) { tmp1 = MkState(); MakePath(unaryNode.kid, dummy, tmp1); dummy = tmp1; } } MakePath(unaryNode.kid, tmp1, tmp2); tmp2.AddEpsTrns(tmp1); tmp1.AddEpsTrns(endState); break; case RegOp.finiteRep: { NState dummy = tmp1 = startState; for (int i = 0; i < unaryNode.minRep; i++) { tmp1 = MkState(); MakePath(unaryNode.kid, dummy, tmp1); dummy = tmp1; } tmp1.AddEpsTrns(endState); for (int i = unaryNode.minRep; i < unaryNode.maxRep; i++) { tmp1 = MkState(); MakePath(unaryNode.kid, dummy, tmp1); dummy = tmp1; dummy.AddEpsTrns(endState); } } break; } break; // Leaf nodes =================================== case RegOp.litStr: case RegOp.primitive: case RegOp.charClass: // Leaf nodes =================================== Leaf leafNode = tree as Leaf; switch (tree.op) { case RegOp.litStr: { // Make a linear sequence of states with successive // transitions on successive string characters. // string text = leafNode.str; NState dummy = startState; // Need to deal with special case of empty string if (text.Length == 0) dummy.AddEpsTrns(endState); else { // This code is complicated by the fact that unicode // escape substitution may have inserted surrogate // pairs of characters in the string. We need // one transition for every unicode character, // not one for every char value in this string. // int index = 0; int code = CharacterUtilities.CodePoint(text, ref index); // First character int next = CharacterUtilities.CodePoint(text, ref index); // Next, possibly -1 while (next >= 0) { tmp1 = MkState(); dummy.AddChrTrns(code, tmp1); dummy = tmp1; code = next; next = CharacterUtilities.CodePoint(text, ref index); } // Postcondition ==> "code" is the last char. dummy.AddChrTrns(code, endState); } } break; case RegOp.primitive: startState.AddChrTrns(leafNode.chVal, endState); break; case RegOp.charClass: startState.AddClsTrans(leafNode, endState); break; } break; default: throw new GplexInternalException("unknown tree op"); } }
internal int maxRep; // max repetitions for finiteRep. internal Unary( RegOp op, RegExTree l ) : base( op ) { kid = l; }
internal abstract void Op( RegExTree tree );
internal void ParseRE( AAST aast ) { regX = new AAST.ReParser( verb, vrbSpan, aast ).Parse(); }
void Check( AAST aast, RegExTree tree ) { Binary bnryTree; Unary unryTree; if (tree == null) return; switch (tree.op) { case RegOp.charClass: case RegOp.primitive: case RegOp.litStr: case RegOp.eof: break; case RegOp.context: case RegOp.concat: case RegOp.alt: bnryTree = (Binary)tree; Check( aast, bnryTree.lKid ); Check( aast, bnryTree.rKid ); if (tree.op == RegOp.context && bnryTree.lKid.contextLength() == 0 && bnryTree.rKid.contextLength() == 0) aast.hdlr.ListError( pSpan, 75 ); break; case RegOp.closure: case RegOp.finiteRep: unryTree = (Unary)tree; Check( aast, unryTree.kid ); break; case RegOp.leftAnchor: case RegOp.rightAnchor: aast.hdlr.ListError( pSpan, 69 ); break; } }
// internal void Dump() { Console.WriteLine(pattern); } internal void ParseRE( AAST aast ) { reAST = new AAST.ReParser( pattern, pSpan, aast ).Parse(); SemanticCheck( aast ); }