private void MatchPop() { if (MatchStack.Count == 0) { LastMatch.StackPosition = -1; LastMatch.StackId = null; return; } LastMatch.StackPosition = MatchStack.Count; LastMatch.StackId = MatchStack.Pop(); }
void PopStack(SyntaxContext currentContext, SyntaxMatch curMatch) { if (ContextStack.Count() == 1) { MatchStack = MatchStack.Clear(); ScopeStack = new ScopeStack(highlighting.definition.Scope); return; } ContextStack = ContextStack.Pop(); if (!MatchStack.IsEmpty) { PopScopeStack(MatchStack.Peek()?.Scope); MatchStack = MatchStack.Pop(); } PopScopeStack(currentContext.MetaScope); if (curMatch.Scope.Count > 0 && !ScopeStack.IsEmpty) { for (int i = 0; i < curMatch.Scope.Count; i++) { ScopeStack = ScopeStack.Pop(); } } }
public static MatchResult Match(string rootProdName, TokenQueue q, out Ast.SqliteSyntaxProduction ast) { // we use an explicit stack rather than function call recursion because our BNF grammar is deeply nested, // particularly the productions for 'expr'. var stack = new MatchStack { Queue = q }; stack.Push(SqliteGrammar.Prods[rootProdName]); MatchResult?rootResult = null; Ast.SqliteSyntaxProduction rootAst = null; Action <MatchResult, Ast.SqliteSyntaxProduction> finishFrame = (frameResult, frameAstProd) => { stack.Pop(); var parentFrame = stack.Peek(); if (parentFrame == null) { rootResult = frameResult; rootAst = frameAstProd; } else { parentFrame.SubResult = frameResult; if (frameResult.IsMatch) { parentFrame.AstProd.Items.Add(frameAstProd); } } }; #if MATCHER_LOG var matcherLogWriter = File.CreateText(@"C:\temp\matcher.log"); int matcherLogPreviousDepth = 0; #endif // trampoline loop while (!rootResult.HasValue && stack.Any()) { #if MATCHER_LOG stack.DebugDump(matcherLogWriter, q.GetLocation(), q.Substring(q.GetLocation(), 1), matcherLogPreviousDepth > stack.Count); matcherLogPreviousDepth = stack.Count; #endif var frame = stack.Peek(); var result = frame.Prod.Terms[frame.TermIndex].MatchStep(stack, frame, q); if (result.HasValue) { // we are done matching this term if (result.Value.IsMatch) { // move to the next term in the production. frame.Clear(all: false); frame.TermIndex++; if (frame.TermIndex >= frame.Prod.Terms.Length) { // we have matched this full production var prodEndLoc = q.GetLocation(); frame.AstProd.StartToken = frame.ProdStartLoc; frame.AstProd.NumTokens = prodEndLoc - frame.ProdStartLoc; frame.AstProd.Text = q.Substring(frame.ProdStartLoc, prodEndLoc - frame.ProdStartLoc); finishFrame(MatchResult.Matched, frame.AstProd); } } else { // we needed a match and didn't find one. we have to abandon this production. finishFrame(result.Value, null); } } } #if MATCHER_LOG matcherLogWriter.Close(); #endif if (!rootResult.HasValue && !stack.Any()) // detect bugs { throw new Exception("Expected a MatchResult but one was not set."); } ast = rootAst; return(rootResult.Value); }