System.Text.RegularExpressions.Interpreter.Eval C# (CSharp) Method

Eval() private method

private Eval ( Mode mode, int &ref_ptr, int pc ) : bool
mode Mode
ref_ptr int
pc int
return bool
		private bool Eval (Mode mode, ref int ref_ptr, int pc) {
			int ptr = ref_ptr;
		Begin:
			for (;;) {
				ushort word = program[pc];
				OpCode op = (OpCode)(word & 0x00ff);
				OpFlags flags = (OpFlags)(word & 0xff00);

				switch (op) {
				case OpCode.Anchor: {
					int skip = program[pc + 1];
					
					int anch_offset = program[pc + 2];
					bool anch_reverse = (flags & OpFlags.RightToLeft) != 0;	
					int anch_ptr = anch_reverse ?  ptr - anch_offset  : ptr + anch_offset;
					int anch_end = text_end - match_min + anch_offset;	// maximum anchor position  
					
					
					int anch_begin =  0;


					// the general case for an anchoring expression is at the bottom, however we
					// do some checks for the common cases before to save processing time. the current
					// optimizer only outputs three types of anchoring expressions: fixed position,
					// fixed substring, and no anchor.

					OpCode anch_op = (OpCode)(program[pc + 3] & 0x00ff);					
					if (anch_op == OpCode.Position && skip == 6) {				// position anchor
						// Anchor
						// 	Position
						//	True

						switch ((Position)program[pc + 4]) {
						case Position.StartOfString:
							if (anch_reverse || anch_offset == 0) {
								if (anch_reverse)
									ptr = anch_offset;
								if (TryMatch (ref ptr, pc + skip))
									goto Pass;
							}
							break;
						
						case Position.StartOfLine:
							 if (anch_ptr == 0) {
								ptr = 0;
								if (TryMatch (ref ptr, pc + skip))
									goto Pass;
								
								++ anch_ptr;
							}

							while ((anch_reverse && anch_ptr >= 0) || (!anch_reverse && anch_ptr <= anch_end)) {  
								if (anch_ptr == 0 || text[anch_ptr - 1] == '\n') {
									if (anch_reverse)
										ptr = anch_ptr == anch_end ? anch_ptr : anch_ptr + anch_offset;
									else
										ptr = anch_ptr == 0 ? anch_ptr : anch_ptr - anch_offset;
									if (TryMatch (ref ptr, pc + skip))
										goto Pass;
								}
							
								if (anch_reverse)
									-- anch_ptr;
								else
									++ anch_ptr;
							}
							break;
						
						case Position.StartOfScan:
							if (anch_ptr == scan_ptr) {							
								ptr = anch_reverse ? scan_ptr + anch_offset : scan_ptr - anch_offset;
								if (TryMatch (ref ptr, pc + skip))
									goto Pass;
							}
							break;

						default:
							// FIXME
							break;
						}
					}
					else if (qs != null ||
						(anch_op == OpCode.String && skip == 6 + program[pc + 4])) {	// substring anchor
						// Anchor
						//	String
						//	True
				 
						bool reverse = ((OpFlags)program[pc + 3] & OpFlags.RightToLeft) != 0;

						if (qs == null) {
							bool ignore = ((OpFlags)program[pc + 3] & OpFlags.IgnoreCase) != 0;
							string substring = GetString (pc + 3);
							qs = new QuickSearch (substring, ignore, reverse);
						}
						while ((anch_reverse && anch_ptr >= anch_begin) 
						       || (!anch_reverse && anch_ptr <= anch_end)) {

							if (reverse) 	
							{
								anch_ptr = qs.Search (text, anch_ptr, anch_begin);
								if (anch_ptr != -1)
									anch_ptr += qs.Length ;
								
							}
							else
								anch_ptr = qs.Search (text, anch_ptr, anch_end);
							if (anch_ptr < 0)
								break;

							ptr = reverse ? anch_ptr + anch_offset : anch_ptr - anch_offset;
							if (TryMatch (ref ptr, pc + skip))
								goto Pass;

							if (reverse)
								anch_ptr -= 2;
							else 
								++ anch_ptr;
						}
					}
					else if (anch_op == OpCode.True) {					// no anchor
						// Anchor
						//	True

					
						while ((anch_reverse && anch_ptr >= anch_begin) 
						       || (!anch_reverse && anch_ptr <= anch_end)) {

							ptr = anch_ptr;
							if (TryMatch (ref ptr, pc + skip))
								goto Pass;
							if (anch_reverse)
								-- anch_ptr;
							else 
								++ anch_ptr;
						}
					}
					else {									// general case
						// Anchor
						//	<expr>
						//	True

						while ((anch_reverse && anch_ptr >= anch_begin) 
						       || (!anch_reverse && anch_ptr <= anch_end)) {

							ptr = anch_ptr;
							if (Eval (Mode.Match, ref ptr, pc + 3)) {
								// anchor expression passed: try real expression at the correct offset

								ptr = anch_reverse ? anch_ptr + anch_offset : anch_ptr - anch_offset;
								if (TryMatch (ref ptr, pc + skip))
									goto Pass;
							}

						    if (anch_reverse)
								-- anch_ptr;
							else 
								++ anch_ptr;
						}
					}

					goto Fail;
				}
				
				case OpCode.False: {
					goto Fail;
				}

				case OpCode.True: {
					goto Pass;
				}

				case OpCode.Position: {
					if (!IsPosition ((Position)program[pc + 1], ptr))
						goto Fail;
					pc += 2;
					break;
				}

				case OpCode.String: {
					bool reverse = (flags & OpFlags.RightToLeft) != 0;
					bool ignore = (flags & OpFlags.IgnoreCase) != 0;
					int len = program[pc + 1];

					if (reverse) {
						ptr -= len;
						if (ptr < 0)
							goto Fail;
					}
					else 
					if (ptr + len > text_end)
						goto Fail;

					pc += 2;
					for (int i = 0; i < len; ++ i) {
						char c = text[ptr + i];
						if (ignore)
							c = Char.ToLower (c);

						if (c != (char)program[pc ++])
							goto Fail;
					}

					if (!reverse)
						ptr += len;
					break;
				}

				case OpCode.Reference: {
					bool reverse = (flags & OpFlags.RightToLeft) != 0;
					bool ignore = (flags & OpFlags.IgnoreCase) != 0;
					int m = GetLastDefined (program [pc + 1]);
					if (m < 0)
						goto Fail;

					int str = marks [m].Index;
					int len = marks [m].Length;

					if (reverse) {
						ptr -= len;
						if (ptr < 0)
							goto Fail;
					}
					else if (ptr + len > text_end)
						goto Fail;

					pc += 2;
					if (ignore) {
						for (int i = 0; i < len; ++ i) {
							if (Char.ToLower (text[ptr + i]) != Char.ToLower (text[str + i]))
								goto Fail;
						}
					} else {
						for (int i = 0; i < len; ++ i) {
							if (text[ptr + i] != text[str + i])
								goto Fail;
						}
					}

					if (!reverse)
						ptr += len;
					break;
				}

				case OpCode.Character: case OpCode.Category: case OpCode.NotCategory:
				case OpCode.Range: case OpCode.Set: {
					if (!EvalChar (mode, ref ptr, ref pc, false))
						goto Fail;
					break;
				}

				case OpCode.In: {
					int target = pc + program[pc + 1];
					pc += 2;
					if (!EvalChar (mode, ref ptr, ref pc, true))
						goto Fail;

					pc = target;
					break;
				}

				case OpCode.Open: {
					Open (program[pc + 1], ptr);
					pc += 2;
					break;
				}

				case OpCode.Close: {
					Close (program[pc + 1], ptr);
					pc += 2;
					break;
				}

			        case OpCode.BalanceStart: {

					int start = ptr; //point before the balancing group
					
					if (!Eval (Mode.Match, ref ptr, pc + 5))
						goto Fail;
					
					
					
					if(!Balance (program[pc + 1], program[pc + 2], (program[pc + 3] == 1 ? true : false) , start)) {
						goto Fail;
					}

					
					pc += program[pc + 4];
					break;
				}

				case OpCode.Balance: {
					goto Pass;
				}

				case OpCode.IfDefined: {
					int m = GetLastDefined (program [pc + 2]);
					if (m < 0)
						pc += program[pc + 1];
					else
						pc += 3;
					break;
				}

				case OpCode.Sub: {
					if (!Eval (Mode.Match, ref ptr, pc + 2))
						goto Fail;

					pc += program[pc + 1];
					break;
				}

				case OpCode.Test: {
					int cp = Checkpoint ();
					int test_ptr = ptr;
					if (Eval (Mode.Match, ref test_ptr, pc + 3))
						pc += program[pc + 1];
					else {
						Backtrack (cp);
						pc += program[pc + 2];
					}
					break;
				}

				case OpCode.Branch: {
					OpCode branch_op;
					do {
						int cp = Checkpoint ();
						if (Eval (Mode.Match, ref ptr, pc + 2))
							goto Pass;
						
						Backtrack (cp);
						
						pc += program[pc + 1];
						branch_op = (OpCode)(program[pc] & 0xff);
					} while (branch_op != OpCode.False);

					goto Fail;
				}

				case OpCode.Jump: {
					pc += program[pc + 1];
					break;
				}

				case OpCode.Repeat: {
					this.repeat = new RepeatContext (
						this.repeat,			// previous context
						ReadProgramCount (pc + 2),		// minimum
						ReadProgramCount (pc + 4),		// maximum
						(flags & OpFlags.Lazy) != 0,	// lazy
						pc + 6				// subexpression
					);

					if (Eval (Mode.Match, ref ptr, pc + program[pc + 1]))
						goto Pass;
					else {
						this.repeat = this.repeat.Previous;
						goto Fail;
					}
				}

				case OpCode.Until: {
					RepeatContext current = this.repeat;

					//
					// Can we avoid recursion?
					//
					// Backtracking can be forced in nested quantifiers from the tail of this quantifier.
					// Thus, we cannot, in general, use a simple loop on repeat.Expression to handle
					// quantifiers.
					//
					// If 'deep' was unmolested, that implies that there was no nested quantifiers.
					// Thus, we can safely avoid recursion.
					//
					if (deep == current)
						goto Pass;

					int start = current.Start;
					int start_count = current.Count;

					while (!current.IsMinimum) {
						++ current.Count;
						current.Start = ptr;
						deep = current;
						if (!Eval (Mode.Match, ref ptr, current.Expression)) {
							current.Start = start;
							current.Count = start_count;
							goto Fail;
						}
						if (deep != current)	// recursive mode
							goto Pass;
					}

					if (ptr == current.Start) {
						// degenerate match ... match tail or fail
						this.repeat = current.Previous;
						deep = null;
						if (Eval (Mode.Match, ref ptr, pc + 1))
							goto Pass;
					
						this.repeat = current;
						goto Fail;
					}

					if (current.IsLazy) {
						for (;;) {
							// match tail first ...
							this.repeat = current.Previous;
							deep = null;
							int cp = Checkpoint ();
							if (Eval (Mode.Match, ref ptr, pc + 1))
								goto Pass;

							Backtrack (cp);

							// ... then match more
							this.repeat = current;
							if (current.IsMaximum)
								goto Fail;
							++ current.Count;
							current.Start = ptr;
							deep = current;
							if (!Eval (Mode.Match, ref ptr, current.Expression)) {
								current.Start = start;
								current.Count = start_count;
								goto Fail;
							}
							if (deep != current)	// recursive mode
								goto Pass;
							// Degenerate match: ptr has not moved since the last (failed) tail match.
							// So, next and subsequent tail matches will fail.
							if (ptr == current.Start)
								goto Fail;
						}
					} else {
						int stack_size = stack.Count;

						// match greedily as much as possible
						while (!current.IsMaximum) {
							int cp = Checkpoint ();
							int old_ptr = ptr;
							int old_start = current.Start;

							++ current.Count;
							current.Start = ptr;
							deep = current;
							if (!Eval (Mode.Match, ref ptr, current.Expression)) {
								-- current.Count;
								current.Start = old_start;
								Backtrack (cp);
								break;
							}
							if (deep != current) {
								// recursive mode: no more backtracking, truncate the stack
								stack.Count = stack_size;
								goto Pass;
							}
							stack.Push (cp);
							stack.Push (old_ptr);

							// Degenerate match: no point going on
							if (ptr == current.Start)
								break;
						}

						// then, match the tail, backtracking as necessary.
						this.repeat = current.Previous;
						for (;;) {
							deep = null;
							if (Eval (Mode.Match, ref ptr, pc + 1)) {
								stack.Count = stack_size;
								goto Pass;
							}
							if (stack.Count == stack_size) {
								this.repeat = current;
								goto Fail;
							}

							--current.Count;
							ptr = stack.Pop ();
							Backtrack (stack.Pop ());
						}
					}
				}

				case OpCode.FastRepeat: {
					this.fast = new RepeatContext (
						fast,
						ReadProgramCount (pc + 2),		// minimum
						ReadProgramCount (pc + 4),		// maximum
						(flags & OpFlags.Lazy) != 0,	// lazy
						pc + 6				// subexpression
					);

					fast.Start = ptr;

					int cp = Checkpoint ();

					pc += program[pc + 1];		// tail expression
					ushort tail_word = program[pc];

					int c1 = -1;		// first character of tail operator
					int c2 = -1;		// ... and the same character, in upper case if ignoring case
					int coff = 0;		// 0 or -1 depending on direction

					OpCode tail_op = (OpCode)(tail_word & 0xff);
					if (tail_op == OpCode.Character || tail_op == OpCode.String) {
						OpFlags tail_flags = (OpFlags)(tail_word & 0xff00);

						if ((tail_flags & OpFlags.Negate) != 0)
							goto skip;

						if (tail_op == OpCode.String)
						{
							int offset = 0;
						
							if ((tail_flags & OpFlags.RightToLeft) != 0)
							{
								offset = program[pc + 1] - 1 ;
							}
							  
							c1 = program[pc + 2 + offset];				// first char of string
						}
						else
							c1 = program[pc + 1];				// character
						
						if ((tail_flags & OpFlags.IgnoreCase) != 0)
							c2 = Char.ToUpper ((char)c1);			// ignore case
						else
							c2 = c1;

						if ((tail_flags & OpFlags.RightToLeft) != 0)
							coff = -1;					// reverse
						else
							coff = 0;
					}

				skip:
					if (fast.IsLazy) {
						if (!fast.IsMinimum && !Eval (Mode.Count, ref ptr, fast.Expression)) {
							//Console.WriteLine ("lazy fast: failed mininum.");
							fast = fast.Previous;
							goto Fail;
						}
						
						while (true) {
							int p = ptr + coff;
							if (c1 < 0 || (p >= 0 && p < text_end && (c1 == text[p] || c2 == text[p]))) {
								deep = null;
								if (Eval (Mode.Match, ref ptr, pc))
									break;
							}

							if (fast.IsMaximum) {
								//Console.WriteLine ("lazy fast: failed with maximum.");
								fast = fast.Previous;
								goto Fail;
							}

							Backtrack (cp);
							if (!Eval (Mode.Count, ref ptr, fast.Expression)) {
								//Console.WriteLine ("lazy fast: no more.");
								fast = fast.Previous;
								goto Fail;
							}
						}
						fast = fast.Previous;
						goto Pass;
					}
					else {
						if (!Eval (Mode.Count, ref ptr, fast.Expression)) {
							fast = fast.Previous;
							goto Fail;
						}
					
						int width;
						if (fast.Count > 0)
							width = (ptr - fast.Start) / fast.Count;
						else
							width = 0;

						while (true) {
							int p = ptr + coff;
							if (c1 < 0 || (p >= 0 && p < text_end && (c1 == text[p] || c2 == text[p]))) {
								deep = null;
								if (Eval (Mode.Match, ref ptr, pc))
									break;
							}

							-- fast.Count;
							if (!fast.IsMinimum) {
								fast = fast.Previous;
								goto Fail;
							}

							ptr -= width;
							Backtrack (cp);
						}
						fast = fast.Previous;
						goto Pass;
					}
				}

				case OpCode.Info: {
					Debug.Assert (false, "Regex", "Info block found in pattern");
					goto Fail;
				}
				}
			}
		Pass:
			ref_ptr = ptr;

			switch (mode) {
			case Mode.Match:
				return true;

			case Mode.Count: {
				++ fast.Count;
				if (fast.IsMaximum || (fast.IsLazy && fast.IsMinimum))
					return true;

				pc = fast.Expression;
				goto Begin;
			}
			}

		Fail:
			switch (mode) {
			case Mode.Match:
				return false;

			case Mode.Count: {
				if (!fast.IsLazy && fast.IsMinimum)
					return true;

				ref_ptr = fast.Start;
				return false;
			}
			}

			return false;
		}

Usage Example

Beispiel #1
0
        public bool Evaluate(string block, ScriptContext context)
        {
            var replacer = context.Get<IVariableReplacer>();
            var scriptLog = context.Get<IScriptLog>();

            var replaced = replacer.Replace(block, context);
            // replace single equals with double equals
            replaced = Regex.Replace(replaced, "([^=:<>])=(?!=)", "$1==");

            if(context.DebugLevel > 0) {
                scriptLog.Log(context.Name, "if {0}".ToFormat(replaced), context.LineNumber);
            }

            try
            {
                var interpreter = new Interpreter();
                var result = (bool)interpreter.Eval(replaced);
                if(context.DebugLevel > 0) {
                    scriptLog.Log(context.Name, "if result {0}".ToFormat(result.ToString().ToLower()), context.LineNumber);
                }
                return result;
            }
            catch(Exception exc)
            {
                scriptLog.Log(context.Name, "if result {0}".ToFormat(exc), context.LineNumber);

                return false;
            }
        }
All Usage Examples Of System.Text.RegularExpressions.Interpreter::Eval