Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Regex / System / Text / RegularExpressions / RegexInterpreter.cs / 1 / RegexInterpreter.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- // This RegexInterpreter class is internal to the RegularExpression package. // It executes a block of regular expression codes while consuming // input. namespace System.Text.RegularExpressions { using System.Collections; using System.Diagnostics; using System.Globalization; internal sealed class RegexInterpreter : RegexRunner { internal int runoperator; internal int [] runcodes; internal int runcodepos; internal String [] runstrings; internal RegexCode runcode; internal RegexPrefix runfcPrefix; internal RegexBoyerMoore runbmPrefix; internal int runanchors; internal bool runrtl; internal bool runci; internal CultureInfo runculture; internal RegexInterpreter(RegexCode code, CultureInfo culture) { runcode = code; runcodes = code._codes; runstrings = code._strings; runfcPrefix = code._fcPrefix; runbmPrefix = code._bmPrefix; runanchors = code._anchors; runculture = culture; } protected override void InitTrackCount() { runtrackcount = runcode._trackcount; } private void Advance() { Advance(0); } private void Advance(int i) { runcodepos += (i + 1); SetOperator(runcodes[runcodepos]); } private void Goto(int newpos) { // when branching backward, ensure storage if (newpos < runcodepos) EnsureStorage(); SetOperator(runcodes[newpos]); runcodepos = newpos; } private void Textto(int newpos) { runtextpos = newpos; } private void Trackto(int newpos) { runtrackpos = runtrack.Length - newpos; } private int Textstart() { return runtextstart; } private int Textpos() { return runtextpos; } // push onto the backtracking stack private int Trackpos() { return runtrack.Length - runtrackpos; } private void TrackPush() { runtrack[--runtrackpos] = runcodepos; } private void TrackPush(int I1) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = runcodepos; } private void TrackPush(int I1, int I2) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = I2; runtrack[--runtrackpos] = runcodepos; } private void TrackPush(int I1, int I2, int I3) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = I2; runtrack[--runtrackpos] = I3; runtrack[--runtrackpos] = runcodepos; } private void TrackPush2(int I1) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = -runcodepos; } private void TrackPush2(int I1, int I2) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = I2; runtrack[--runtrackpos] = -runcodepos; } private void Backtrack() { int newpos = runtrack[runtrackpos++]; #if DBG if (runmatch.Debug) { if (newpos < 0) Debug.WriteLine(" Backtracking (back2) to code position " + (-newpos)); else Debug.WriteLine(" Backtracking to code position " + newpos); } #endif if (newpos < 0) { newpos = -newpos; SetOperator(runcodes[newpos] | RegexCode.Back2); } else { SetOperator(runcodes[newpos] | RegexCode.Back); } // When branching backward, ensure storage if (newpos < runcodepos) EnsureStorage(); runcodepos = newpos; } private void SetOperator(int op) { runci = (0 != (op & RegexCode.Ci)); runrtl = (0 != (op & RegexCode.Rtl)); runoperator = op & ~(RegexCode.Rtl | RegexCode.Ci); } private void TrackPop() { runtrackpos++; } // pop framesize items from the backtracking stack private void TrackPop(int framesize) { runtrackpos += framesize; } // Technically we are actually peeking at items already popped. So if you want to // get and pop the top item from the stack, you do // TrackPop(); // TrackPeek(); private int TrackPeek() { return runtrack[runtrackpos - 1]; } // get the ith element down on the backtracking stack private int TrackPeek(int i) { return runtrack[runtrackpos - i - 1]; } // Push onto the grouping stack private void StackPush(int I1) { runstack[--runstackpos] = I1; } private void StackPush(int I1, int I2) { runstack[--runstackpos] = I1; runstack[--runstackpos] = I2; } private void StackPop() { runstackpos++; } // pop framesize items from the grouping stack private void StackPop(int framesize) { runstackpos += framesize; } // Technically we are actually peeking at items already popped. So if you want to // get and pop the top item from the stack, you do // StackPop(); // StackPeek(); private int StackPeek() { return runstack[runstackpos - 1]; } // get the ith element down on the grouping stack private int StackPeek(int i) { return runstack[runstackpos - i - 1]; } private int Operator() { return runoperator; } private int Operand(int i) { return runcodes[runcodepos + i + 1]; } private int Leftchars() { return runtextpos - runtextbeg; } private int Rightchars() { return runtextend - runtextpos; } private int Bump() { return runrtl ? -1 : 1; } private int Forwardchars() { return runrtl ? runtextpos - runtextbeg : runtextend - runtextpos; } private char Forwardcharnext() { char ch = (runrtl ? runtext[--runtextpos] : runtext[runtextpos++]); return(runci ? Char.ToLower(ch, runculture) : ch); } private bool Stringmatch(String str) { int c; int pos; if (!runrtl) { if (runtextend - runtextpos < (c = str.Length)) return false; pos = runtextpos + c; } else { if (runtextpos - runtextbeg < (c = str.Length)) return false; pos = runtextpos; } if (!runci) { while (c != 0) if (str[--c] != runtext[--pos]) return false; } else { while (c != 0) if (str[--c] != Char.ToLower(runtext[--pos], runculture)) return false; } if (!runrtl) { pos += str.Length; } runtextpos = pos; return true; } private bool Refmatch(int index, int len) { int c; int pos; int cmpos; if (!runrtl) { if (runtextend - runtextpos < len) return false; pos = runtextpos + len; } else { if (runtextpos - runtextbeg < len) return false; pos = runtextpos; } cmpos = index + len; c = len; if (!runci) { while (c-- != 0) if (runtext[--cmpos] != runtext[--pos]) return false; } else { while (c-- != 0) if (Char.ToLower(runtext[--cmpos], runculture) != Char.ToLower(runtext[--pos], runculture)) return false; } if (!runrtl) { pos += len; } runtextpos = pos; return true; } private void Backwardnext() { runtextpos += runrtl ? 1 : -1; } private char CharAt(int j) { return runtext[j]; } protected override bool FindFirstChar() { int i; String set; if (0 != (runanchors & (RegexFCD.Beginning | RegexFCD.Start | RegexFCD.EndZ | RegexFCD.End))) { if (!runcode._rightToLeft) { if ((0 != (runanchors & RegexFCD.Beginning) && runtextpos > runtextbeg) || (0 != (runanchors & RegexFCD.Start) && runtextpos > runtextstart)) { runtextpos = runtextend; return false; } if (0 != (runanchors & RegexFCD.EndZ) && runtextpos < runtextend - 1) { runtextpos = runtextend - 1; } else if (0 != (runanchors & RegexFCD.End) && runtextpos < runtextend) { runtextpos = runtextend; } } else { if ((0 != (runanchors & RegexFCD.End) && runtextpos < runtextend) || (0 != (runanchors & RegexFCD.EndZ) && (runtextpos < runtextend - 1 || (runtextpos == runtextend - 1 && CharAt(runtextpos) != '\n'))) || (0 != (runanchors & RegexFCD.Start) && runtextpos < runtextstart)) { runtextpos = runtextbeg; return false; } if (0 != (runanchors & RegexFCD.Beginning) && runtextpos > runtextbeg) { runtextpos = runtextbeg; } } if (runbmPrefix != null) { return runbmPrefix.IsMatch(runtext, runtextpos, runtextbeg, runtextend); } } else if (runbmPrefix != null) { runtextpos = runbmPrefix.Scan(runtext, runtextpos, runtextbeg, runtextend); if (runtextpos == -1) { runtextpos = (runcode._rightToLeft ? runtextbeg : runtextend); return false; } return true; } if (runfcPrefix == null) return true; runrtl = runcode._rightToLeft; runci = runfcPrefix.CaseInsensitive; set = runfcPrefix.Prefix; if (RegexCharClass.IsSingleton(set)) { char ch = RegexCharClass.SingletonChar(set); for (i = Forwardchars(); i > 0; i--) { if (ch == Forwardcharnext()) { Backwardnext(); return true; } } } else { for (i = Forwardchars(); i > 0; i--) { if (RegexCharClass.CharInClass(Forwardcharnext(), set)) { Backwardnext(); return true; } } } return false; } protected override void Go() { Goto(0); for (;;) { #if DBG if (runmatch.Debug) { DumpState(); } #endif switch (Operator()) { case RegexCode.Stop: return; case RegexCode.Nothing: break; case RegexCode.Goto: Goto(Operand(0)); continue; case RegexCode.Testref: if (!IsMatched(Operand(0))) break; Advance(1); continue; case RegexCode.Lazybranch: TrackPush(Textpos()); Advance(1); continue; case RegexCode.Lazybranch | RegexCode.Back: TrackPop(); Textto(TrackPeek()); Goto(Operand(0)); continue; case RegexCode.Setmark: StackPush(Textpos()); TrackPush(); Advance(); continue; case RegexCode.Nullmark: StackPush(-1); TrackPush(); Advance(); continue; case RegexCode.Setmark | RegexCode.Back: case RegexCode.Nullmark | RegexCode.Back: StackPop(); break; case RegexCode.Getmark: StackPop(); TrackPush(StackPeek()); Textto(StackPeek()); Advance(); continue; case RegexCode.Getmark | RegexCode.Back: TrackPop(); StackPush(TrackPeek()); break; case RegexCode.Capturemark: if (Operand(1) != -1 && !IsMatched(Operand(1))) break; StackPop(); if (Operand(1) != -1) TransferCapture(Operand(0), Operand(1), StackPeek(), Textpos()); else Capture(Operand(0), StackPeek(), Textpos()); TrackPush(StackPeek()); Advance(2); continue; case RegexCode.Capturemark | RegexCode.Back: TrackPop(); StackPush(TrackPeek()); Uncapture(); if (Operand(0) != -1 && Operand(1) != -1) Uncapture(); break; case RegexCode.Branchmark: { int matched; StackPop(); matched = Textpos() - StackPeek(); if (matched != 0) { // Nonempty match -> loop now TrackPush(StackPeek(), Textpos()); // Save old mark, textpos StackPush(Textpos()); // Make new mark Goto(Operand(0)); // Loop } else { // Empty match -> straight now TrackPush2(StackPeek()); // Save old mark Advance(1); // Straight } continue; } case RegexCode.Branchmark | RegexCode.Back: TrackPop(2); StackPop(); Textto(TrackPeek(1)); // Recall position TrackPush2(TrackPeek()); // Save old mark Advance(1); // Straight continue; case RegexCode.Branchmark | RegexCode.Back2: TrackPop(); StackPush(TrackPeek()); // Recall old mark break; // Backtrack case RegexCode.Lazybranchmark: { // We hit this the first time through a lazy loop and after each // successful match of the inner expression. It simply continues // on and doesn't loop. StackPop(); int oldMarkPos = StackPeek(); if (Textpos() != oldMarkPos) { // Nonempty match -> try to loop again by going to 'back' state if (oldMarkPos != -1) TrackPush(oldMarkPos, Textpos()); // Save old mark, textpos else TrackPush(Textpos(), Textpos()); } else { // The inner expression found an empty match, so we'll go directly to 'back2' if we // backtrack. In this case, we need to push something on the stack, since back2 pops. // However, in the case of ()+? or similar, this empty match may be legitimate, so push the text // position associated with that empty match. StackPush(oldMarkPos); TrackPush2(StackPeek()); // Save old mark } Advance(1); continue; } case RegexCode.Lazybranchmark | RegexCode.Back: { // After the first time, Lazybranchmark | RegexCode.Back occurs // with each iteration of the loop, and therefore with every attempted // match of the inner expression. We'll try to match the inner expression, // then go back to Lazybranchmark if successful. If the inner expression // failes, we go to Lazybranchmark | RegexCode.Back2 int pos; TrackPop(2); pos = TrackPeek(1); TrackPush2(TrackPeek()); // Save old mark StackPush(pos); // Make new mark Textto(pos); // Recall position Goto(Operand(0)); // Loop continue; } case RegexCode.Lazybranchmark | RegexCode.Back2: // The lazy loop has failed. We'll do a true backtrack and // start over before the lazy loop. StackPop(); TrackPop(); StackPush(TrackPeek()); // Recall old mark break; case RegexCode.Setcount: StackPush(Textpos(), Operand(0)); TrackPush(); Advance(1); continue; case RegexCode.Nullcount: StackPush(-1, Operand(0)); TrackPush(); Advance(1); continue; case RegexCode.Setcount | RegexCode.Back: StackPop(2); break; case RegexCode.Nullcount | RegexCode.Back: StackPop(2); break; case RegexCode.Branchcount: // StackPush: // 0: Mark // 1: Count { StackPop(2); int mark = StackPeek(); int count = StackPeek(1); int matched = Textpos() - mark; if (count >= Operand(1) || (matched == 0 && count >= 0)) { // Max loops or empty match -> straight now TrackPush2(mark, count); // Save old mark, count Advance(2); // Straight } else { // Nonempty match -> count+loop now TrackPush(mark); // remember mark StackPush(Textpos(), count + 1); // Make new mark, incr count Goto(Operand(0)); // Loop } continue; } case RegexCode.Branchcount | RegexCode.Back: // TrackPush: // 0: Previous mark // StackPush: // 0: Mark (= current pos, discarded) // 1: Count TrackPop(); StackPop(2); if (StackPeek(1) > 0) { // Positive -> can go straight Textto(StackPeek()); // Zap to mark TrackPush2(TrackPeek(), StackPeek(1) - 1); // Save old mark, old count Advance(2); // Straight continue; } StackPush(TrackPeek(), StackPeek(1) - 1); // recall old mark, old count break; case RegexCode.Branchcount | RegexCode.Back2: // TrackPush: // 0: Previous mark // 1: Previous count TrackPop(2); StackPush(TrackPeek(), TrackPeek(1)); // Recall old mark, old count break; // Backtrack case RegexCode.Lazybranchcount: // StackPush: // 0: Mark // 1: Count { StackPop(2); int mark = StackPeek(); int count = StackPeek(1); if (count < 0) { // Negative count -> loop now TrackPush2(mark); // Save old mark StackPush(Textpos(), count + 1); // Make new mark, incr count Goto(Operand(0)); // Loop } else { // Nonneg count -> straight now TrackPush(mark, count, Textpos()); // Save mark, count, position Advance(2); // Straight } continue; } case RegexCode.Lazybranchcount | RegexCode.Back: // TrackPush: // 0: Mark // 1: Count // 2: Textpos { TrackPop(3); int mark = TrackPeek(); int textpos = TrackPeek(2); if (TrackPeek(1) <= Operand(1) && textpos != mark) { // Under limit and not empty match -> loop Textto(textpos); // Recall position StackPush(textpos, TrackPeek(1) + 1); // Make new mark, incr count TrackPush2(mark); // Save old mark Goto(Operand(0)); // Loop continue; } else { // Max loops or empty match -> backtrack StackPush(TrackPeek(), TrackPeek(1)); // Recall old mark, count break; // backtrack } } case RegexCode.Lazybranchcount | RegexCode.Back2: // TrackPush: // 0: Previous mark // StackPush: // 0: Mark (== current pos, discarded) // 1: Count TrackPop(); StackPop(2); StackPush(TrackPeek(), StackPeek(1) - 1); // Recall old mark, count break; // Backtrack case RegexCode.Setjump: StackPush(Trackpos(), Crawlpos()); TrackPush(); Advance(); continue; case RegexCode.Setjump | RegexCode.Back: StackPop(2); break; case RegexCode.Backjump: // StackPush: // 0: Saved trackpos // 1: Crawlpos StackPop(2); Trackto(StackPeek()); while (Crawlpos() != StackPeek(1)) Uncapture(); break; case RegexCode.Forejump: // StackPush: // 0: Saved trackpos // 1: Crawlpos StackPop(2); Trackto(StackPeek()); TrackPush(StackPeek(1)); Advance(); continue; case RegexCode.Forejump | RegexCode.Back: // TrackPush: // 0: Crawlpos TrackPop(); while (Crawlpos() != TrackPeek()) Uncapture(); break; case RegexCode.Bol: if (Leftchars() > 0 && CharAt(Textpos() - 1) != '\n') break; Advance(); continue; case RegexCode.Eol: if (Rightchars() > 0 && CharAt(Textpos()) != '\n') break; Advance(); continue; case RegexCode.Boundary: if (!IsBoundary(Textpos(), runtextbeg, runtextend)) break; Advance(); continue; case RegexCode.Nonboundary: if (IsBoundary(Textpos(), runtextbeg, runtextend)) break; Advance(); continue; case RegexCode.ECMABoundary: if (!IsECMABoundary(Textpos(), runtextbeg, runtextend)) break; Advance(); continue; case RegexCode.NonECMABoundary: if (IsECMABoundary(Textpos(), runtextbeg, runtextend)) break; Advance(); continue; case RegexCode.Beginning: if (Leftchars() > 0) break; Advance(); continue; case RegexCode.Start: if (Textpos() != Textstart()) break; Advance(); continue; case RegexCode.EndZ: if (Rightchars() > 1 || Rightchars() == 1 && CharAt(Textpos()) != '\n') break; Advance(); continue; case RegexCode.End: if (Rightchars() > 0) break; Advance(); continue; case RegexCode.One: if (Forwardchars() < 1 || Forwardcharnext() != (char)Operand(0)) break; Advance(1); continue; case RegexCode.Notone: if (Forwardchars() < 1 || Forwardcharnext() == (char)Operand(0)) break; Advance(1); continue; case RegexCode.Set: if (Forwardchars() < 1 || !RegexCharClass.CharInClass(Forwardcharnext(), runstrings[Operand(0)])) break; Advance(1); continue; case RegexCode.Multi: { if (!Stringmatch(runstrings[Operand(0)])) break; Advance(1); continue; } case RegexCode.Ref: { int capnum = Operand(0); if (IsMatched(capnum)) { if (!Refmatch(MatchIndex(capnum), MatchLength(capnum))) break; } else { if ((runregex.roptions & RegexOptions.ECMAScript) == 0) break; } Advance(1); continue; } case RegexCode.Onerep: { int c = Operand(1); if (Forwardchars() < c) break; char ch = (char)Operand(0); while (c-- > 0) if (Forwardcharnext() != ch) goto BreakBackward; Advance(2); continue; } case RegexCode.Notonerep: { int c = Operand(1); if (Forwardchars() < c) break; char ch = (char)Operand(0); while (c-- > 0) if (Forwardcharnext() == ch) goto BreakBackward; Advance(2); continue; } case RegexCode.Setrep: { int c = Operand(1); if (Forwardchars() < c) break; String set = runstrings[Operand(0)]; while (c-- > 0) if (!RegexCharClass.CharInClass(Forwardcharnext(), set)) goto BreakBackward; Advance(2); continue; } case RegexCode.Oneloop: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); char ch = (char)Operand(0); int i; for (i = c; i > 0; i--) { if (Forwardcharnext() != ch) { Backwardnext(); break; } } if (c > i) TrackPush(c - i - 1, Textpos() - Bump()); Advance(2); continue; } case RegexCode.Notoneloop: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); char ch = (char)Operand(0); int i; for (i = c; i > 0; i--) { if (Forwardcharnext() == ch) { Backwardnext(); break; } } if (c > i) TrackPush(c - i - 1, Textpos() - Bump()); Advance(2); continue; } case RegexCode.Setloop: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); String set = runstrings[Operand(0)]; int i; for (i = c; i > 0; i--) { if (!RegexCharClass.CharInClass(Forwardcharnext(), set)) { Backwardnext(); break; } } if (c > i) TrackPush(c - i - 1, Textpos() - Bump()); Advance(2); continue; } case RegexCode.Oneloop | RegexCode.Back: case RegexCode.Notoneloop | RegexCode.Back: { TrackPop(2); int i = TrackPeek(); int pos = TrackPeek(1); Textto(pos); if (i > 0) TrackPush(i - 1, pos - Bump()); Advance(2); continue; } case RegexCode.Setloop | RegexCode.Back: { TrackPop(2); int i = TrackPeek(); int pos = TrackPeek(1); Textto(pos); if (i > 0) TrackPush(i - 1, pos - Bump()); Advance(2); continue; } case RegexCode.Onelazy: case RegexCode.Notonelazy: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); if (c > 0) TrackPush(c - 1, Textpos()); Advance(2); continue; } case RegexCode.Setlazy: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); if (c > 0) TrackPush(c - 1, Textpos()); Advance(2); continue; } case RegexCode.Onelazy | RegexCode.Back: { TrackPop(2); int pos = TrackPeek(1); Textto(pos); if (Forwardcharnext() != (char)Operand(0)) break; int i = TrackPeek(); if (i > 0) TrackPush(i - 1, pos + Bump()); Advance(2); continue; } case RegexCode.Notonelazy | RegexCode.Back: { TrackPop(2); int pos = TrackPeek(1); Textto(pos); if (Forwardcharnext() == (char)Operand(0)) break; int i = TrackPeek(); if (i > 0) TrackPush(i - 1, pos + Bump()); Advance(2); continue; } case RegexCode.Setlazy | RegexCode.Back: { TrackPop(2); int pos = TrackPeek(1); Textto(pos); if (!RegexCharClass.CharInClass(Forwardcharnext(), runstrings[Operand(0)])) break; int i = TrackPeek(); if (i > 0) TrackPush(i - 1, pos + Bump()); Advance(2); continue; } default: throw new NotImplementedException(SR.GetString(SR.UnimplementedState)); } BreakBackward: ; // "break Backward" comes here: Backtrack(); } } #if DBG internal override void DumpState() { base.DumpState(); Debug.WriteLine(" " + runcode.OpcodeDescription(runcodepos) + ((runoperator & RegexCode.Back) != 0 ? " Back" : "") + ((runoperator & RegexCode.Back2) != 0 ? " Back2" : "")); Debug.WriteLine(""); } #endif } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- // This RegexInterpreter class is internal to the RegularExpression package. // It executes a block of regular expression codes while consuming // input. namespace System.Text.RegularExpressions { using System.Collections; using System.Diagnostics; using System.Globalization; internal sealed class RegexInterpreter : RegexRunner { internal int runoperator; internal int [] runcodes; internal int runcodepos; internal String [] runstrings; internal RegexCode runcode; internal RegexPrefix runfcPrefix; internal RegexBoyerMoore runbmPrefix; internal int runanchors; internal bool runrtl; internal bool runci; internal CultureInfo runculture; internal RegexInterpreter(RegexCode code, CultureInfo culture) { runcode = code; runcodes = code._codes; runstrings = code._strings; runfcPrefix = code._fcPrefix; runbmPrefix = code._bmPrefix; runanchors = code._anchors; runculture = culture; } protected override void InitTrackCount() { runtrackcount = runcode._trackcount; } private void Advance() { Advance(0); } private void Advance(int i) { runcodepos += (i + 1); SetOperator(runcodes[runcodepos]); } private void Goto(int newpos) { // when branching backward, ensure storage if (newpos < runcodepos) EnsureStorage(); SetOperator(runcodes[newpos]); runcodepos = newpos; } private void Textto(int newpos) { runtextpos = newpos; } private void Trackto(int newpos) { runtrackpos = runtrack.Length - newpos; } private int Textstart() { return runtextstart; } private int Textpos() { return runtextpos; } // push onto the backtracking stack private int Trackpos() { return runtrack.Length - runtrackpos; } private void TrackPush() { runtrack[--runtrackpos] = runcodepos; } private void TrackPush(int I1) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = runcodepos; } private void TrackPush(int I1, int I2) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = I2; runtrack[--runtrackpos] = runcodepos; } private void TrackPush(int I1, int I2, int I3) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = I2; runtrack[--runtrackpos] = I3; runtrack[--runtrackpos] = runcodepos; } private void TrackPush2(int I1) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = -runcodepos; } private void TrackPush2(int I1, int I2) { runtrack[--runtrackpos] = I1; runtrack[--runtrackpos] = I2; runtrack[--runtrackpos] = -runcodepos; } private void Backtrack() { int newpos = runtrack[runtrackpos++]; #if DBG if (runmatch.Debug) { if (newpos < 0) Debug.WriteLine(" Backtracking (back2) to code position " + (-newpos)); else Debug.WriteLine(" Backtracking to code position " + newpos); } #endif if (newpos < 0) { newpos = -newpos; SetOperator(runcodes[newpos] | RegexCode.Back2); } else { SetOperator(runcodes[newpos] | RegexCode.Back); } // When branching backward, ensure storage if (newpos < runcodepos) EnsureStorage(); runcodepos = newpos; } private void SetOperator(int op) { runci = (0 != (op & RegexCode.Ci)); runrtl = (0 != (op & RegexCode.Rtl)); runoperator = op & ~(RegexCode.Rtl | RegexCode.Ci); } private void TrackPop() { runtrackpos++; } // pop framesize items from the backtracking stack private void TrackPop(int framesize) { runtrackpos += framesize; } // Technically we are actually peeking at items already popped. So if you want to // get and pop the top item from the stack, you do // TrackPop(); // TrackPeek(); private int TrackPeek() { return runtrack[runtrackpos - 1]; } // get the ith element down on the backtracking stack private int TrackPeek(int i) { return runtrack[runtrackpos - i - 1]; } // Push onto the grouping stack private void StackPush(int I1) { runstack[--runstackpos] = I1; } private void StackPush(int I1, int I2) { runstack[--runstackpos] = I1; runstack[--runstackpos] = I2; } private void StackPop() { runstackpos++; } // pop framesize items from the grouping stack private void StackPop(int framesize) { runstackpos += framesize; } // Technically we are actually peeking at items already popped. So if you want to // get and pop the top item from the stack, you do // StackPop(); // StackPeek(); private int StackPeek() { return runstack[runstackpos - 1]; } // get the ith element down on the grouping stack private int StackPeek(int i) { return runstack[runstackpos - i - 1]; } private int Operator() { return runoperator; } private int Operand(int i) { return runcodes[runcodepos + i + 1]; } private int Leftchars() { return runtextpos - runtextbeg; } private int Rightchars() { return runtextend - runtextpos; } private int Bump() { return runrtl ? -1 : 1; } private int Forwardchars() { return runrtl ? runtextpos - runtextbeg : runtextend - runtextpos; } private char Forwardcharnext() { char ch = (runrtl ? runtext[--runtextpos] : runtext[runtextpos++]); return(runci ? Char.ToLower(ch, runculture) : ch); } private bool Stringmatch(String str) { int c; int pos; if (!runrtl) { if (runtextend - runtextpos < (c = str.Length)) return false; pos = runtextpos + c; } else { if (runtextpos - runtextbeg < (c = str.Length)) return false; pos = runtextpos; } if (!runci) { while (c != 0) if (str[--c] != runtext[--pos]) return false; } else { while (c != 0) if (str[--c] != Char.ToLower(runtext[--pos], runculture)) return false; } if (!runrtl) { pos += str.Length; } runtextpos = pos; return true; } private bool Refmatch(int index, int len) { int c; int pos; int cmpos; if (!runrtl) { if (runtextend - runtextpos < len) return false; pos = runtextpos + len; } else { if (runtextpos - runtextbeg < len) return false; pos = runtextpos; } cmpos = index + len; c = len; if (!runci) { while (c-- != 0) if (runtext[--cmpos] != runtext[--pos]) return false; } else { while (c-- != 0) if (Char.ToLower(runtext[--cmpos], runculture) != Char.ToLower(runtext[--pos], runculture)) return false; } if (!runrtl) { pos += len; } runtextpos = pos; return true; } private void Backwardnext() { runtextpos += runrtl ? 1 : -1; } private char CharAt(int j) { return runtext[j]; } protected override bool FindFirstChar() { int i; String set; if (0 != (runanchors & (RegexFCD.Beginning | RegexFCD.Start | RegexFCD.EndZ | RegexFCD.End))) { if (!runcode._rightToLeft) { if ((0 != (runanchors & RegexFCD.Beginning) && runtextpos > runtextbeg) || (0 != (runanchors & RegexFCD.Start) && runtextpos > runtextstart)) { runtextpos = runtextend; return false; } if (0 != (runanchors & RegexFCD.EndZ) && runtextpos < runtextend - 1) { runtextpos = runtextend - 1; } else if (0 != (runanchors & RegexFCD.End) && runtextpos < runtextend) { runtextpos = runtextend; } } else { if ((0 != (runanchors & RegexFCD.End) && runtextpos < runtextend) || (0 != (runanchors & RegexFCD.EndZ) && (runtextpos < runtextend - 1 || (runtextpos == runtextend - 1 && CharAt(runtextpos) != '\n'))) || (0 != (runanchors & RegexFCD.Start) && runtextpos < runtextstart)) { runtextpos = runtextbeg; return false; } if (0 != (runanchors & RegexFCD.Beginning) && runtextpos > runtextbeg) { runtextpos = runtextbeg; } } if (runbmPrefix != null) { return runbmPrefix.IsMatch(runtext, runtextpos, runtextbeg, runtextend); } } else if (runbmPrefix != null) { runtextpos = runbmPrefix.Scan(runtext, runtextpos, runtextbeg, runtextend); if (runtextpos == -1) { runtextpos = (runcode._rightToLeft ? runtextbeg : runtextend); return false; } return true; } if (runfcPrefix == null) return true; runrtl = runcode._rightToLeft; runci = runfcPrefix.CaseInsensitive; set = runfcPrefix.Prefix; if (RegexCharClass.IsSingleton(set)) { char ch = RegexCharClass.SingletonChar(set); for (i = Forwardchars(); i > 0; i--) { if (ch == Forwardcharnext()) { Backwardnext(); return true; } } } else { for (i = Forwardchars(); i > 0; i--) { if (RegexCharClass.CharInClass(Forwardcharnext(), set)) { Backwardnext(); return true; } } } return false; } protected override void Go() { Goto(0); for (;;) { #if DBG if (runmatch.Debug) { DumpState(); } #endif switch (Operator()) { case RegexCode.Stop: return; case RegexCode.Nothing: break; case RegexCode.Goto: Goto(Operand(0)); continue; case RegexCode.Testref: if (!IsMatched(Operand(0))) break; Advance(1); continue; case RegexCode.Lazybranch: TrackPush(Textpos()); Advance(1); continue; case RegexCode.Lazybranch | RegexCode.Back: TrackPop(); Textto(TrackPeek()); Goto(Operand(0)); continue; case RegexCode.Setmark: StackPush(Textpos()); TrackPush(); Advance(); continue; case RegexCode.Nullmark: StackPush(-1); TrackPush(); Advance(); continue; case RegexCode.Setmark | RegexCode.Back: case RegexCode.Nullmark | RegexCode.Back: StackPop(); break; case RegexCode.Getmark: StackPop(); TrackPush(StackPeek()); Textto(StackPeek()); Advance(); continue; case RegexCode.Getmark | RegexCode.Back: TrackPop(); StackPush(TrackPeek()); break; case RegexCode.Capturemark: if (Operand(1) != -1 && !IsMatched(Operand(1))) break; StackPop(); if (Operand(1) != -1) TransferCapture(Operand(0), Operand(1), StackPeek(), Textpos()); else Capture(Operand(0), StackPeek(), Textpos()); TrackPush(StackPeek()); Advance(2); continue; case RegexCode.Capturemark | RegexCode.Back: TrackPop(); StackPush(TrackPeek()); Uncapture(); if (Operand(0) != -1 && Operand(1) != -1) Uncapture(); break; case RegexCode.Branchmark: { int matched; StackPop(); matched = Textpos() - StackPeek(); if (matched != 0) { // Nonempty match -> loop now TrackPush(StackPeek(), Textpos()); // Save old mark, textpos StackPush(Textpos()); // Make new mark Goto(Operand(0)); // Loop } else { // Empty match -> straight now TrackPush2(StackPeek()); // Save old mark Advance(1); // Straight } continue; } case RegexCode.Branchmark | RegexCode.Back: TrackPop(2); StackPop(); Textto(TrackPeek(1)); // Recall position TrackPush2(TrackPeek()); // Save old mark Advance(1); // Straight continue; case RegexCode.Branchmark | RegexCode.Back2: TrackPop(); StackPush(TrackPeek()); // Recall old mark break; // Backtrack case RegexCode.Lazybranchmark: { // We hit this the first time through a lazy loop and after each // successful match of the inner expression. It simply continues // on and doesn't loop. StackPop(); int oldMarkPos = StackPeek(); if (Textpos() != oldMarkPos) { // Nonempty match -> try to loop again by going to 'back' state if (oldMarkPos != -1) TrackPush(oldMarkPos, Textpos()); // Save old mark, textpos else TrackPush(Textpos(), Textpos()); } else { // The inner expression found an empty match, so we'll go directly to 'back2' if we // backtrack. In this case, we need to push something on the stack, since back2 pops. // However, in the case of ()+? or similar, this empty match may be legitimate, so push the text // position associated with that empty match. StackPush(oldMarkPos); TrackPush2(StackPeek()); // Save old mark } Advance(1); continue; } case RegexCode.Lazybranchmark | RegexCode.Back: { // After the first time, Lazybranchmark | RegexCode.Back occurs // with each iteration of the loop, and therefore with every attempted // match of the inner expression. We'll try to match the inner expression, // then go back to Lazybranchmark if successful. If the inner expression // failes, we go to Lazybranchmark | RegexCode.Back2 int pos; TrackPop(2); pos = TrackPeek(1); TrackPush2(TrackPeek()); // Save old mark StackPush(pos); // Make new mark Textto(pos); // Recall position Goto(Operand(0)); // Loop continue; } case RegexCode.Lazybranchmark | RegexCode.Back2: // The lazy loop has failed. We'll do a true backtrack and // start over before the lazy loop. StackPop(); TrackPop(); StackPush(TrackPeek()); // Recall old mark break; case RegexCode.Setcount: StackPush(Textpos(), Operand(0)); TrackPush(); Advance(1); continue; case RegexCode.Nullcount: StackPush(-1, Operand(0)); TrackPush(); Advance(1); continue; case RegexCode.Setcount | RegexCode.Back: StackPop(2); break; case RegexCode.Nullcount | RegexCode.Back: StackPop(2); break; case RegexCode.Branchcount: // StackPush: // 0: Mark // 1: Count { StackPop(2); int mark = StackPeek(); int count = StackPeek(1); int matched = Textpos() - mark; if (count >= Operand(1) || (matched == 0 && count >= 0)) { // Max loops or empty match -> straight now TrackPush2(mark, count); // Save old mark, count Advance(2); // Straight } else { // Nonempty match -> count+loop now TrackPush(mark); // remember mark StackPush(Textpos(), count + 1); // Make new mark, incr count Goto(Operand(0)); // Loop } continue; } case RegexCode.Branchcount | RegexCode.Back: // TrackPush: // 0: Previous mark // StackPush: // 0: Mark (= current pos, discarded) // 1: Count TrackPop(); StackPop(2); if (StackPeek(1) > 0) { // Positive -> can go straight Textto(StackPeek()); // Zap to mark TrackPush2(TrackPeek(), StackPeek(1) - 1); // Save old mark, old count Advance(2); // Straight continue; } StackPush(TrackPeek(), StackPeek(1) - 1); // recall old mark, old count break; case RegexCode.Branchcount | RegexCode.Back2: // TrackPush: // 0: Previous mark // 1: Previous count TrackPop(2); StackPush(TrackPeek(), TrackPeek(1)); // Recall old mark, old count break; // Backtrack case RegexCode.Lazybranchcount: // StackPush: // 0: Mark // 1: Count { StackPop(2); int mark = StackPeek(); int count = StackPeek(1); if (count < 0) { // Negative count -> loop now TrackPush2(mark); // Save old mark StackPush(Textpos(), count + 1); // Make new mark, incr count Goto(Operand(0)); // Loop } else { // Nonneg count -> straight now TrackPush(mark, count, Textpos()); // Save mark, count, position Advance(2); // Straight } continue; } case RegexCode.Lazybranchcount | RegexCode.Back: // TrackPush: // 0: Mark // 1: Count // 2: Textpos { TrackPop(3); int mark = TrackPeek(); int textpos = TrackPeek(2); if (TrackPeek(1) <= Operand(1) && textpos != mark) { // Under limit and not empty match -> loop Textto(textpos); // Recall position StackPush(textpos, TrackPeek(1) + 1); // Make new mark, incr count TrackPush2(mark); // Save old mark Goto(Operand(0)); // Loop continue; } else { // Max loops or empty match -> backtrack StackPush(TrackPeek(), TrackPeek(1)); // Recall old mark, count break; // backtrack } } case RegexCode.Lazybranchcount | RegexCode.Back2: // TrackPush: // 0: Previous mark // StackPush: // 0: Mark (== current pos, discarded) // 1: Count TrackPop(); StackPop(2); StackPush(TrackPeek(), StackPeek(1) - 1); // Recall old mark, count break; // Backtrack case RegexCode.Setjump: StackPush(Trackpos(), Crawlpos()); TrackPush(); Advance(); continue; case RegexCode.Setjump | RegexCode.Back: StackPop(2); break; case RegexCode.Backjump: // StackPush: // 0: Saved trackpos // 1: Crawlpos StackPop(2); Trackto(StackPeek()); while (Crawlpos() != StackPeek(1)) Uncapture(); break; case RegexCode.Forejump: // StackPush: // 0: Saved trackpos // 1: Crawlpos StackPop(2); Trackto(StackPeek()); TrackPush(StackPeek(1)); Advance(); continue; case RegexCode.Forejump | RegexCode.Back: // TrackPush: // 0: Crawlpos TrackPop(); while (Crawlpos() != TrackPeek()) Uncapture(); break; case RegexCode.Bol: if (Leftchars() > 0 && CharAt(Textpos() - 1) != '\n') break; Advance(); continue; case RegexCode.Eol: if (Rightchars() > 0 && CharAt(Textpos()) != '\n') break; Advance(); continue; case RegexCode.Boundary: if (!IsBoundary(Textpos(), runtextbeg, runtextend)) break; Advance(); continue; case RegexCode.Nonboundary: if (IsBoundary(Textpos(), runtextbeg, runtextend)) break; Advance(); continue; case RegexCode.ECMABoundary: if (!IsECMABoundary(Textpos(), runtextbeg, runtextend)) break; Advance(); continue; case RegexCode.NonECMABoundary: if (IsECMABoundary(Textpos(), runtextbeg, runtextend)) break; Advance(); continue; case RegexCode.Beginning: if (Leftchars() > 0) break; Advance(); continue; case RegexCode.Start: if (Textpos() != Textstart()) break; Advance(); continue; case RegexCode.EndZ: if (Rightchars() > 1 || Rightchars() == 1 && CharAt(Textpos()) != '\n') break; Advance(); continue; case RegexCode.End: if (Rightchars() > 0) break; Advance(); continue; case RegexCode.One: if (Forwardchars() < 1 || Forwardcharnext() != (char)Operand(0)) break; Advance(1); continue; case RegexCode.Notone: if (Forwardchars() < 1 || Forwardcharnext() == (char)Operand(0)) break; Advance(1); continue; case RegexCode.Set: if (Forwardchars() < 1 || !RegexCharClass.CharInClass(Forwardcharnext(), runstrings[Operand(0)])) break; Advance(1); continue; case RegexCode.Multi: { if (!Stringmatch(runstrings[Operand(0)])) break; Advance(1); continue; } case RegexCode.Ref: { int capnum = Operand(0); if (IsMatched(capnum)) { if (!Refmatch(MatchIndex(capnum), MatchLength(capnum))) break; } else { if ((runregex.roptions & RegexOptions.ECMAScript) == 0) break; } Advance(1); continue; } case RegexCode.Onerep: { int c = Operand(1); if (Forwardchars() < c) break; char ch = (char)Operand(0); while (c-- > 0) if (Forwardcharnext() != ch) goto BreakBackward; Advance(2); continue; } case RegexCode.Notonerep: { int c = Operand(1); if (Forwardchars() < c) break; char ch = (char)Operand(0); while (c-- > 0) if (Forwardcharnext() == ch) goto BreakBackward; Advance(2); continue; } case RegexCode.Setrep: { int c = Operand(1); if (Forwardchars() < c) break; String set = runstrings[Operand(0)]; while (c-- > 0) if (!RegexCharClass.CharInClass(Forwardcharnext(), set)) goto BreakBackward; Advance(2); continue; } case RegexCode.Oneloop: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); char ch = (char)Operand(0); int i; for (i = c; i > 0; i--) { if (Forwardcharnext() != ch) { Backwardnext(); break; } } if (c > i) TrackPush(c - i - 1, Textpos() - Bump()); Advance(2); continue; } case RegexCode.Notoneloop: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); char ch = (char)Operand(0); int i; for (i = c; i > 0; i--) { if (Forwardcharnext() == ch) { Backwardnext(); break; } } if (c > i) TrackPush(c - i - 1, Textpos() - Bump()); Advance(2); continue; } case RegexCode.Setloop: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); String set = runstrings[Operand(0)]; int i; for (i = c; i > 0; i--) { if (!RegexCharClass.CharInClass(Forwardcharnext(), set)) { Backwardnext(); break; } } if (c > i) TrackPush(c - i - 1, Textpos() - Bump()); Advance(2); continue; } case RegexCode.Oneloop | RegexCode.Back: case RegexCode.Notoneloop | RegexCode.Back: { TrackPop(2); int i = TrackPeek(); int pos = TrackPeek(1); Textto(pos); if (i > 0) TrackPush(i - 1, pos - Bump()); Advance(2); continue; } case RegexCode.Setloop | RegexCode.Back: { TrackPop(2); int i = TrackPeek(); int pos = TrackPeek(1); Textto(pos); if (i > 0) TrackPush(i - 1, pos - Bump()); Advance(2); continue; } case RegexCode.Onelazy: case RegexCode.Notonelazy: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); if (c > 0) TrackPush(c - 1, Textpos()); Advance(2); continue; } case RegexCode.Setlazy: { int c = Operand(1); if (c > Forwardchars()) c = Forwardchars(); if (c > 0) TrackPush(c - 1, Textpos()); Advance(2); continue; } case RegexCode.Onelazy | RegexCode.Back: { TrackPop(2); int pos = TrackPeek(1); Textto(pos); if (Forwardcharnext() != (char)Operand(0)) break; int i = TrackPeek(); if (i > 0) TrackPush(i - 1, pos + Bump()); Advance(2); continue; } case RegexCode.Notonelazy | RegexCode.Back: { TrackPop(2); int pos = TrackPeek(1); Textto(pos); if (Forwardcharnext() == (char)Operand(0)) break; int i = TrackPeek(); if (i > 0) TrackPush(i - 1, pos + Bump()); Advance(2); continue; } case RegexCode.Setlazy | RegexCode.Back: { TrackPop(2); int pos = TrackPeek(1); Textto(pos); if (!RegexCharClass.CharInClass(Forwardcharnext(), runstrings[Operand(0)])) break; int i = TrackPeek(); if (i > 0) TrackPush(i - 1, pos + Bump()); Advance(2); continue; } default: throw new NotImplementedException(SR.GetString(SR.UnimplementedState)); } BreakBackward: ; // "break Backward" comes here: Backtrack(); } } #if DBG internal override void DumpState() { base.DumpState(); Debug.WriteLine(" " + runcode.OpcodeDescription(runcodepos) + ((runoperator & RegexCode.Back) != 0 ? " Back" : "") + ((runoperator & RegexCode.Back2) != 0 ? " Back2" : "")); Debug.WriteLine(""); } #endif } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WindowsToolbarAsMenu.cs
- OperatingSystemVersionCheck.cs
- HorizontalAlignConverter.cs
- DefaultSerializationProviderAttribute.cs
- DeferredSelectedIndexReference.cs
- FunctionImportMapping.cs
- MdImport.cs
- Win32.cs
- TextViewBase.cs
- ListDictionary.cs
- SqlNode.cs
- ItemDragEvent.cs
- SchemaTypeEmitter.cs
- MenuItemBinding.cs
- securitycriticaldataformultiplegetandset.cs
- RegexCompiler.cs
- SspiSafeHandles.cs
- cache.cs
- BindingContext.cs
- TransportSecurityHelpers.cs
- OdbcException.cs
- TemplateAction.cs
- MobileControlBuilder.cs
- DeadCharTextComposition.cs
- DataGridViewCellFormattingEventArgs.cs
- ConfigurationSectionGroup.cs
- ReservationCollection.cs
- EventListenerClientSide.cs
- StateManager.cs
- SrgsSubset.cs
- SoapUnknownHeader.cs
- Debugger.cs
- TextRangeEditTables.cs
- MultitargetingHelpers.cs
- Rotation3DAnimationUsingKeyFrames.cs
- rsa.cs
- GregorianCalendarHelper.cs
- ObservableCollection.cs
- DataGridViewComboBoxCell.cs
- TransactionFlowAttribute.cs
- AnnotationResourceCollection.cs
- RelatedEnd.cs
- ConfigurationLoaderException.cs
- ViewBase.cs
- XmlSchemaAnnotation.cs
- PopOutPanel.cs
- ImageSourceConverter.cs
- ContentPropertyAttribute.cs
- RegisteredScript.cs
- Types.cs
- PeerObject.cs
- BindingSource.cs
- WebBrowser.cs
- SafeEventHandle.cs
- WebControl.cs
- PolicyManager.cs
- ICspAsymmetricAlgorithm.cs
- LoggedException.cs
- CodeChecksumPragma.cs
- Constant.cs
- WebPartConnectVerb.cs
- XomlDesignerLoader.cs
- ToolBarOverflowPanel.cs
- FileNameEditor.cs
- WebPartMenu.cs
- ColumnWidthChangingEvent.cs
- ChtmlPageAdapter.cs
- DesignerLoader.cs
- CollaborationHelperFunctions.cs
- DivideByZeroException.cs
- ImageDrawing.cs
- CodeComment.cs
- IssuanceLicense.cs
- NTAccount.cs
- TemplatePropertyEntry.cs
- SimpleTypeResolver.cs
- WmlFormAdapter.cs
- BuildProvidersCompiler.cs
- SpellerHighlightLayer.cs
- ViewManager.cs
- DesignerTransactionCloseEvent.cs
- WebHeaderCollection.cs
- Group.cs
- ToolStripItem.cs
- ExpressionBinding.cs
- ComplexPropertyEntry.cs
- FixedSOMImage.cs
- TableCellAutomationPeer.cs
- ObjectAnimationUsingKeyFrames.cs
- ListControlBuilder.cs
- CqlWriter.cs
- GeneralTransform3DGroup.cs
- AppDomainGrammarProxy.cs
- SendMessageRecord.cs
- DbConnectionOptions.cs
- DesignerAttribute.cs
- ProcessHostServerConfig.cs
- ApplicationDirectoryMembershipCondition.cs
- InternalDispatchObject.cs
- QuaternionRotation3D.cs