internal virtual object ExecuteRegExp(Context cx, Scriptable scope, RegExpImpl res, string str, int[] indexp, int matchType) { REGlobalData gData = new REGlobalData(); int start = indexp[0]; int end = str.Length; if (start > end) { start = end; } // // Call the recursive matcher to do the real work. // bool matches = MatchRegExp(gData, re, str, start, end, res.multiline); if (!matches) { if (matchType != PREFIX) { return null; } return Undefined.instance; } int index = gData.cp; int ep = indexp[0] = index; int matchlen = ep - (start + gData.skipped); index -= matchlen; object result; Scriptable obj; if (matchType == TEST) { result = true; obj = null; } else { result = cx.NewArray(scope, 0); obj = (Scriptable)result; string matchstr = Sharpen.Runtime.Substring(str, index, index + matchlen); obj.Put(0, obj, matchstr); } if (re.parenCount == 0) { res.parens = null; res.lastParen = SubString.emptySubString; } else { SubString parsub = null; int num; res.parens = new SubString[re.parenCount]; for (num = 0; num < re.parenCount; num++) { int cap_index = gData.ParensIndex(num); string parstr; if (cap_index != -1) { int cap_length = gData.ParensLength(num); parsub = new SubString(str, cap_index, cap_length); res.parens[num] = parsub; if (matchType != TEST) { obj.Put(num + 1, obj, parsub.ToString()); } } else { if (matchType != TEST) { obj.Put(num + 1, obj, Undefined.instance); } } } res.lastParen = parsub; } if (!(matchType == TEST)) { obj.Put("index", obj, Sharpen.Extensions.ValueOf(start + gData.skipped)); obj.Put("input", obj, str); } if (res.lastMatch == null) { res.lastMatch = new SubString(); res.leftContext = new SubString(); res.rightContext = new SubString(); } res.lastMatch.str = str; res.lastMatch.index = index; res.lastMatch.length = matchlen; res.leftContext.str = str; if (cx.GetLanguageVersion() == Context.VERSION_1_2) { res.leftContext.index = start; res.leftContext.length = gData.skipped; } else { res.leftContext.index = 0; res.leftContext.length = start + gData.skipped; } res.rightContext.str = str; res.rightContext.index = ep; res.rightContext.length = end - ep; return result; }
internal REBackTrackData(REGlobalData gData, int op, int pc, int cp, int continuationOp, int continuationPc) { previous = gData.backTrackStackTop; this.op = op; this.pc = pc; this.cp = cp; this.continuationOp = continuationOp; this.continuationPc = continuationPc; parens = gData.parens; stateStackTop = gData.stateStackTop; }
private static bool ExecuteREBytecode(REGlobalData gData, string input, int end) { int pc = 0; byte[] program = gData.regexp.program; int continuationOp = REOP_END; int continuationPc = 0; bool result = false; int op = program[pc++]; if (gData.regexp.anchorCh < 0 && ReopIsSimple(op)) { bool anchor = false; while (gData.cp <= end) { int match = SimpleMatch(gData, input, op, program, pc, end, true); if (match >= 0) { anchor = true; pc = match; op = program[pc++]; break; } gData.skipped++; gData.cp++; } if (!anchor) { return false; } } for (; ; ) { if (ReopIsSimple(op)) { int match = SimpleMatch(gData, input, op, program, pc, end, true); result = match >= 0; if (result) { pc = match; } } else { switch (op) { case REOP_ALTPREREQ: case REOP_ALTPREREQi: case REOP_ALTPREREQ2: { char matchCh1 = (char)GetIndex(program, pc); pc += INDEX_LEN; char matchCh2 = (char)GetIndex(program, pc); pc += INDEX_LEN; if (gData.cp == end) { result = false; break; } char c = input[gData.cp]; if (op == REOP_ALTPREREQ2) { if (c != matchCh1 && !ClassMatcher(gData, gData.regexp.classList[matchCh2], c)) { result = false; break; } } else { if (op == REOP_ALTPREREQi) { c = Upcase(c); } if (c != matchCh1 && c != matchCh2) { result = false; break; } } goto case REOP_ALT; } case REOP_ALT: { int nextpc = pc + GetOffset(program, pc); pc += INDEX_LEN; op = program[pc++]; int startcp = gData.cp; if (ReopIsSimple(op)) { int match = SimpleMatch(gData, input, op, program, pc, end, true); if (match < 0) { op = program[nextpc++]; pc = nextpc; continue; } result = true; pc = match; op = program[pc++]; } byte nextop = program[nextpc++]; PushBackTrackState(gData, nextop, nextpc, startcp, continuationOp, continuationPc); continue; } case REOP_JUMP: { int offset = GetOffset(program, pc); pc += offset; op = program[pc++]; continue; } case REOP_LPAREN: { int parenIndex = GetIndex(program, pc); pc += INDEX_LEN; gData.SetParens(parenIndex, gData.cp, 0); op = program[pc++]; continue; } case REOP_RPAREN: { int parenIndex = GetIndex(program, pc); pc += INDEX_LEN; int cap_index = gData.ParensIndex(parenIndex); gData.SetParens(parenIndex, cap_index, gData.cp - cap_index); op = program[pc++]; continue; } case REOP_ASSERT: { int nextpc = pc + GetIndex(program, pc); pc += INDEX_LEN; op = program[pc++]; if (ReopIsSimple(op) && SimpleMatch(gData, input, op, program, pc, end, false) < 0) { result = false; break; } PushProgState(gData, 0, 0, gData.cp, gData.backTrackStackTop, continuationOp, continuationPc); PushBackTrackState(gData, REOP_ASSERTTEST, nextpc); continue; } case REOP_ASSERT_NOT: { int nextpc = pc + GetIndex(program, pc); pc += INDEX_LEN; op = program[pc++]; if (ReopIsSimple(op)) { int match = SimpleMatch(gData, input, op, program, pc, end, false); if (match >= 0 && program[match] == REOP_ASSERTNOTTEST) { result = false; break; } } PushProgState(gData, 0, 0, gData.cp, gData.backTrackStackTop, continuationOp, continuationPc); PushBackTrackState(gData, REOP_ASSERTNOTTEST, nextpc); continue; } case REOP_ASSERTTEST: case REOP_ASSERTNOTTEST: { REProgState state = PopProgState(gData); gData.cp = state.index; gData.backTrackStackTop = state.backTrack; continuationPc = state.continuationPc; continuationOp = state.continuationOp; if (op == REOP_ASSERTNOTTEST) { result = !result; } break; } case REOP_STAR: case REOP_PLUS: case REOP_OPT: case REOP_QUANT: case REOP_MINIMALSTAR: case REOP_MINIMALPLUS: case REOP_MINIMALOPT: case REOP_MINIMALQUANT: { int min; int max; bool greedy = false; switch (op) { case REOP_STAR: { greedy = true; goto case REOP_MINIMALSTAR; } case REOP_MINIMALSTAR: { // fallthrough min = 0; max = -1; break; } case REOP_PLUS: { greedy = true; goto case REOP_MINIMALPLUS; } case REOP_MINIMALPLUS: { // fallthrough min = 1; max = -1; break; } case REOP_OPT: { greedy = true; goto case REOP_MINIMALOPT; } case REOP_MINIMALOPT: { // fallthrough min = 0; max = 1; break; } case REOP_QUANT: { greedy = true; goto case REOP_MINIMALQUANT; } case REOP_MINIMALQUANT: { // fallthrough min = GetOffset(program, pc); pc += INDEX_LEN; // See comments in emitREBytecode for " - 1" reason max = GetOffset(program, pc) - 1; pc += INDEX_LEN; break; } default: { throw Kit.CodeBug(); } } PushProgState(gData, min, max, gData.cp, null, continuationOp, continuationPc); if (greedy) { PushBackTrackState(gData, REOP_REPEAT, pc); continuationOp = REOP_REPEAT; continuationPc = pc; pc += 3 * INDEX_LEN; op = program[pc++]; } else { if (min != 0) { continuationOp = REOP_MINIMALREPEAT; continuationPc = pc; pc += 3 * INDEX_LEN; op = program[pc++]; } else { PushBackTrackState(gData, REOP_MINIMALREPEAT, pc); PopProgState(gData); pc += 2 * INDEX_LEN; // <parencount> & <parenindex> pc = pc + GetOffset(program, pc); op = program[pc++]; } } continue; } case REOP_ENDCHILD: { // If we have not gotten a result here, it is because of an // empty match. Do the same thing REOP_EMPTY would do. result = true; // Use the current continuation. pc = continuationPc; op = continuationOp; continue; } case REOP_REPEAT: { int nextpc; int nextop; do { REProgState state = PopProgState(gData); if (!result) { // Failed, see if we have enough children. if (state.min == 0) { result = true; } continuationPc = state.continuationPc; continuationOp = state.continuationOp; pc += 2 * INDEX_LEN; pc += GetOffset(program, pc); goto switchStatement_break; } if (state.min == 0 && gData.cp == state.index) { // matched an empty string, that'll get us nowhere result = false; continuationPc = state.continuationPc; continuationOp = state.continuationOp; pc += 2 * INDEX_LEN; pc += GetOffset(program, pc); goto switchStatement_break; } int new_min = state.min; int new_max = state.max; if (new_min != 0) { new_min--; } if (new_max != -1) { new_max--; } if (new_max == 0) { result = true; continuationPc = state.continuationPc; continuationOp = state.continuationOp; pc += 2 * INDEX_LEN; pc += GetOffset(program, pc); goto switchStatement_break; } nextpc = pc + 3 * INDEX_LEN; nextop = program[nextpc]; int startcp = gData.cp; if (ReopIsSimple(nextop)) { nextpc++; int match = SimpleMatch(gData, input, nextop, program, nextpc, end, true); if (match < 0) { result = (new_min == 0); continuationPc = state.continuationPc; continuationOp = state.continuationOp; pc += 2 * INDEX_LEN; pc += GetOffset(program, pc); goto switchStatement_break; } result = true; nextpc = match; } continuationOp = REOP_REPEAT; continuationPc = pc; PushProgState(gData, new_min, new_max, startcp, null, state.continuationOp, state.continuationPc); if (new_min == 0) { PushBackTrackState(gData, REOP_REPEAT, pc, startcp, state.continuationOp, state.continuationPc); int parenCount = GetIndex(program, pc); int parenIndex = GetIndex(program, pc + INDEX_LEN); for (int k = 0; k < parenCount; k++) { gData.SetParens(parenIndex + k, -1, 0); } } } while (program[nextpc] == REOP_ENDCHILD); pc = nextpc; op = program[pc++]; continue; } case REOP_MINIMALREPEAT: { REProgState state = PopProgState(gData); if (!result) { // // Non-greedy failure - try to consume another child. // if (state.max == -1 || state.max > 0) { PushProgState(gData, state.min, state.max, gData.cp, null, state.continuationOp, state.continuationPc); continuationOp = REOP_MINIMALREPEAT; continuationPc = pc; int parenCount = GetIndex(program, pc); pc += INDEX_LEN; int parenIndex = GetIndex(program, pc); pc += 2 * INDEX_LEN; for (int k = 0; k < parenCount; k++) { gData.SetParens(parenIndex + k, -1, 0); } op = program[pc++]; continue; } else { // Don't need to adjust pc since we're going to pop. continuationPc = state.continuationPc; continuationOp = state.continuationOp; break; } } else { if (state.min == 0 && gData.cp == state.index) { // Matched an empty string, that'll get us nowhere. result = false; continuationPc = state.continuationPc; continuationOp = state.continuationOp; break; } int new_min = state.min; int new_max = state.max; if (new_min != 0) { new_min--; } if (new_max != -1) { new_max--; } PushProgState(gData, new_min, new_max, gData.cp, null, state.continuationOp, state.continuationPc); if (new_min != 0) { continuationOp = REOP_MINIMALREPEAT; continuationPc = pc; int parenCount = GetIndex(program, pc); pc += INDEX_LEN; int parenIndex = GetIndex(program, pc); pc += 2 * INDEX_LEN; for (int k = 0; k < parenCount; k++) { gData.SetParens(parenIndex + k, -1, 0); } op = program[pc++]; } else { continuationPc = state.continuationPc; continuationOp = state.continuationOp; PushBackTrackState(gData, REOP_MINIMALREPEAT, pc); PopProgState(gData); pc += 2 * INDEX_LEN; pc = pc + GetOffset(program, pc); op = program[pc++]; } continue; } goto case REOP_END; } case REOP_END: { return true; } default: { throw Kit.CodeBug("invalid bytecode"); } } switchStatement_break: ; } if (!result) { REBackTrackData backTrackData = gData.backTrackStackTop; if (backTrackData != null) { gData.backTrackStackTop = backTrackData.previous; gData.parens = backTrackData.parens; gData.cp = backTrackData.cp; gData.stateStackTop = backTrackData.stateStackTop; continuationOp = backTrackData.continuationOp; continuationPc = backTrackData.continuationPc; pc = backTrackData.pc; op = backTrackData.op; continue; } else { return false; } } op = program[pc++]; } }
private static bool MatchRegExp(REGlobalData gData, RECompiled re, string input, int start, int end, bool multiline) { if (re.parenCount != 0) { gData.parens = new long[re.parenCount]; } else { gData.parens = null; } gData.backTrackStackTop = null; gData.stateStackTop = null; gData.multiline = multiline || (re.flags & JSREG_MULTILINE) != 0; gData.regexp = re; int anchorCh = gData.regexp.anchorCh; // // have to include the position beyond the last character // in order to detect end-of-input/line condition // for (int i = start; i <= end; ++i) { // // If the first node is a literal match, step the index into // the string until that match is made, or fail if it can't be // found at all. // if (anchorCh >= 0) { for (; ; ) { if (i == end) { return false; } char matchCh = input[i]; if (matchCh == anchorCh || ((gData.regexp.flags & JSREG_FOLD) != 0 && Upcase(matchCh) == Upcase((char)anchorCh))) { break; } ++i; } } gData.cp = i; gData.skipped = i - start; for (int j = 0; j < re.parenCount; j++) { gData.parens[j] = -1l; } bool result = ExecuteREBytecode(gData, input, end); gData.backTrackStackTop = null; gData.stateStackTop = null; if (result) { return true; } if (anchorCh == ANCHOR_BOL && !gData.multiline) { gData.skipped = end; return false; } i = start + gData.skipped; } return false; }
private static bool ClassMatcher(REGlobalData gData, RECharSet charSet, char ch) { if (!charSet.converted) { ProcessCharSet(gData, charSet); } int byteIndex = ch >> 3; return (charSet.length == 0 || ch >= charSet.length || (charSet.bits[byteIndex] & (1 << (ch & unchecked((int)(0x7))))) == 0) ^ charSet.sense; }
private static int SimpleMatch(REGlobalData gData, string input, int op, byte[] program, int pc, int end, bool updatecp) { bool result = false; char matchCh; int parenIndex; int offset; int length; int index; int startcp = gData.cp; switch (op) { case REOP_EMPTY: { result = true; break; } case REOP_BOL: { if (gData.cp != 0) { if (!gData.multiline || !IsLineTerm(input[gData.cp - 1])) { break; } } result = true; break; } case REOP_EOL: { if (gData.cp != end) { if (!gData.multiline || !IsLineTerm(input[gData.cp])) { break; } } result = true; break; } case REOP_WBDRY: { result = ((gData.cp == 0 || !IsWord(input[gData.cp - 1])) ^ !((gData.cp < end) && IsWord(input[gData.cp]))); break; } case REOP_WNONBDRY: { result = ((gData.cp == 0 || !IsWord(input[gData.cp - 1])) ^ ((gData.cp < end) && IsWord(input[gData.cp]))); break; } case REOP_DOT: { if (gData.cp != end && !IsLineTerm(input[gData.cp])) { result = true; gData.cp++; } break; } case REOP_DIGIT: { if (gData.cp != end && IsDigit(input[gData.cp])) { result = true; gData.cp++; } break; } case REOP_NONDIGIT: { if (gData.cp != end && !IsDigit(input[gData.cp])) { result = true; gData.cp++; } break; } case REOP_ALNUM: { if (gData.cp != end && IsWord(input[gData.cp])) { result = true; gData.cp++; } break; } case REOP_NONALNUM: { if (gData.cp != end && !IsWord(input[gData.cp])) { result = true; gData.cp++; } break; } case REOP_SPACE: { if (gData.cp != end && IsREWhiteSpace(input[gData.cp])) { result = true; gData.cp++; } break; } case REOP_NONSPACE: { if (gData.cp != end && !IsREWhiteSpace(input[gData.cp])) { result = true; gData.cp++; } break; } case REOP_BACKREF: { parenIndex = GetIndex(program, pc); pc += INDEX_LEN; result = BackrefMatcher(gData, parenIndex, input, end); break; } case REOP_FLAT: { offset = GetIndex(program, pc); pc += INDEX_LEN; length = GetIndex(program, pc); pc += INDEX_LEN; result = FlatNMatcher(gData, offset, length, input, end); break; } case REOP_FLAT1: { matchCh = (char)(program[pc++] & unchecked((int)(0xFF))); if (gData.cp != end && input[gData.cp] == matchCh) { result = true; gData.cp++; } break; } case REOP_FLATi: { offset = GetIndex(program, pc); pc += INDEX_LEN; length = GetIndex(program, pc); pc += INDEX_LEN; result = FlatNIMatcher(gData, offset, length, input, end); break; } case REOP_FLAT1i: { matchCh = (char)(program[pc++] & unchecked((int)(0xFF))); if (gData.cp != end) { char c = input[gData.cp]; if (matchCh == c || Upcase(matchCh) == Upcase(c)) { result = true; gData.cp++; } } break; } case REOP_UCFLAT1: { matchCh = (char)GetIndex(program, pc); pc += INDEX_LEN; if (gData.cp != end && input[gData.cp] == matchCh) { result = true; gData.cp++; } break; } case REOP_UCFLAT1i: { matchCh = (char)GetIndex(program, pc); pc += INDEX_LEN; if (gData.cp != end) { char c = input[gData.cp]; if (matchCh == c || Upcase(matchCh) == Upcase(c)) { result = true; gData.cp++; } } break; } case REOP_CLASS: case REOP_NCLASS: { index = GetIndex(program, pc); pc += INDEX_LEN; if (gData.cp != end) { if (ClassMatcher(gData, gData.regexp.classList[index], input[gData.cp])) { gData.cp++; result = true; break; } } break; } default: { throw Kit.CodeBug(); } } if (result) { if (!updatecp) { gData.cp = startcp; } return pc; } gData.cp = startcp; return -1; }
private static void ProcessCharSet(REGlobalData gData, RECharSet charSet) { lock (charSet) { if (!charSet.converted) { ProcessCharSetImpl(gData, charSet); charSet.converted = true; } } }
private static void ProcessCharSetImpl(REGlobalData gData, RECharSet charSet) { int src = charSet.startIndex; int end = src + charSet.strlength; char rangeStart = 0; char thisCh; int byteLength; char c; int n; int nDigits; int i; bool inRange = false; byteLength = (charSet.length + 7) / 8; charSet.bits = new byte[byteLength]; if (src == end) { return; } if (gData.regexp.source[src] == '^') { System.Diagnostics.Debug.Assert((!charSet.sense)); ++src; } else { System.Diagnostics.Debug.Assert((charSet.sense)); } while (src != end) { nDigits = 2; switch (gData.regexp.source[src]) { case '\\': { ++src; c = gData.regexp.source[src++]; switch (c) { case 'b': { thisCh = (char)unchecked((int)(0x8)); break; } case 'f': { thisCh = (char)unchecked((int)(0xC)); break; } case 'n': { thisCh = (char)unchecked((int)(0xA)); break; } case 'r': { thisCh = (char)unchecked((int)(0xD)); break; } case 't': { thisCh = (char)unchecked((int)(0x9)); break; } case 'v': { thisCh = (char)unchecked((int)(0xB)); break; } case 'c': { if ((src < end) && IsControlLetter(gData.regexp.source[src])) { thisCh = (char)(gData.regexp.source[src++] & unchecked((int)(0x1F))); } else { --src; thisCh = '\\'; } break; } case 'u': { nDigits += 2; goto case 'x'; } case 'x': { // fall thru n = 0; for (i = 0; (i < nDigits) && (src < end); i++) { c = gData.regexp.source[src++]; int digit = ToASCIIHexDigit(c); if (digit < 0) { src -= (i + 1); n = '\\'; break; } n = (n << 4) | digit; } thisCh = (char)(n); break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { n = (c - '0'); c = gData.regexp.source[src]; if ('0' <= c && c <= '7') { src++; n = 8 * n + (c - '0'); c = gData.regexp.source[src]; if ('0' <= c && c <= '7') { src++; i = 8 * n + (c - '0'); if (i <= 0xff) { n = i; } else { src--; } } } thisCh = (char)(n); break; } case 'd': { AddCharacterRangeToCharSet(charSet, '0', '9'); continue; } case 'D': { AddCharacterRangeToCharSet(charSet, (char)0, (char)('0' - 1)); AddCharacterRangeToCharSet(charSet, (char)('9' + 1), (char)(charSet.length - 1)); continue; } case 's': { for (i = (charSet.length - 1); i >= 0; i--) { if (IsREWhiteSpace(i)) { AddCharacterToCharSet(charSet, (char)(i)); } } continue; } case 'S': { for (i = (charSet.length - 1); i >= 0; i--) { if (!IsREWhiteSpace(i)) { AddCharacterToCharSet(charSet, (char)(i)); } } continue; } case 'w': { for (i = (charSet.length - 1); i >= 0; i--) { if (IsWord((char)i)) { AddCharacterToCharSet(charSet, (char)(i)); } } continue; } case 'W': { for (i = (charSet.length - 1); i >= 0; i--) { if (!IsWord((char)i)) { AddCharacterToCharSet(charSet, (char)(i)); } } continue; } default: { thisCh = c; break; } } break; } default: { thisCh = gData.regexp.source[src++]; break; } } if (inRange) { if ((gData.regexp.flags & JSREG_FOLD) != 0) { System.Diagnostics.Debug.Assert((rangeStart <= thisCh)); for (c = rangeStart; c <= thisCh; ) { AddCharacterToCharSet(charSet, c); char uch = Upcase(c); char dch = Downcase(c); if (c != uch) { AddCharacterToCharSet(charSet, uch); } if (c != dch) { AddCharacterToCharSet(charSet, dch); } if (++c == 0) { break; } } } else { // overflow AddCharacterRangeToCharSet(charSet, rangeStart, thisCh); } inRange = false; } else { if ((gData.regexp.flags & JSREG_FOLD) != 0) { AddCharacterToCharSet(charSet, Upcase(thisCh)); AddCharacterToCharSet(charSet, Downcase(thisCh)); } else { AddCharacterToCharSet(charSet, thisCh); } if (src < (end - 1)) { if (gData.regexp.source[src] == '-') { ++src; inRange = true; rangeStart = thisCh; } } } } }
private static bool FlatNIMatcher(REGlobalData gData, int matchChars, int length, string input, int end) { if ((gData.cp + length) > end) { return false; } char[] source = gData.regexp.source; for (int i = 0; i < length; i++) { char c1 = source[matchChars + i]; char c2 = input[gData.cp + i]; if (c1 != c2 && Upcase(c1) != Upcase(c2)) { return false; } } gData.cp += length; return true; }
private static bool BackrefMatcher(REGlobalData gData, int parenIndex, string input, int end) { int len; int i; if (gData.parens == null || parenIndex >= gData.parens.Length) { return false; } int parenContent = gData.ParensIndex(parenIndex); if (parenContent == -1) { return true; } len = gData.ParensLength(parenIndex); if ((gData.cp + len) > end) { return false; } if ((gData.regexp.flags & JSREG_FOLD) != 0) { for (i = 0; i < len; i++) { char c1 = input[parenContent + i]; char c2 = input[gData.cp + i]; if (c1 != c2 && Upcase(c1) != Upcase(c2)) { return false; } } } else { if (!input.RegionMatches(parenContent, input, gData.cp, len)) { return false; } } gData.cp += len; return true; }
private static bool FlatNMatcher(REGlobalData gData, int matchChars, int length, string input, int end) { if ((gData.cp + length) > end) { return false; } for (int i = 0; i < length; i++) { if (gData.regexp.source[matchChars + i] != input[gData.cp + i]) { return false; } } gData.cp += length; return true; }
private static void PushBackTrackState(REGlobalData gData, byte op, int pc, int cp, int continuationOp, int continuationPc) { gData.backTrackStackTop = new REBackTrackData(gData, op, pc, cp, continuationOp, continuationPc); }
private static void PushBackTrackState(REGlobalData gData, byte op, int pc) { REProgState state = gData.stateStackTop; gData.backTrackStackTop = new REBackTrackData(gData, op, pc, gData.cp, state.continuationOp, state.continuationPc); }
private static REProgState PopProgState(REGlobalData gData) { REProgState state = gData.stateStackTop; gData.stateStackTop = state.previous; return state; }
private static void PushProgState(REGlobalData gData, int min, int max, int cp, REBackTrackData backTrackLastToSave, int continuationOp, int continuationPc) { gData.stateStackTop = new REProgState(gData.stateStackTop, min, max, cp, backTrackLastToSave, continuationOp, continuationPc); }