public static Result ReadStmt(TokenQueue q, out Ast.SqliteSyntaxProduction ast, string rootProdName = "sql-stmt") { var startingLocation = q.GetLocation(); var matchResult = Matcher.Match(rootProdName, q, out ast); var numTokens = q.GetLocation() - startingLocation; if (matchResult.IsMatch) { return(new Result(numTokens)); } else { return(new Result(matchResult.ErrorMessage ?? "Not a statement.", numTokens)); } }
public static Result ReadExpr(TokenQueue q, out Ast.SqliteSyntaxProduction ast) { var startingLocation = q.GetLocation(); var matchResult = Matcher.Match("expr", q, out ast); var numTokens = q.GetLocation() - startingLocation; if (matchResult.IsMatch) { return(new Result(numTokens)); } else { return(new Result(matchResult.ErrorMessage ?? "Not an expression.", numTokens)); } }
public void Clear(bool all = true) { if (all) { ProdStartLoc = 0; Prod = null; TermIndex = 0; AstProd = null; } OptionalState = OptionalTermState.Start; OptionalStartLoc = 0; OrState = OrTermState.Start; OrProdIndex = 0; OrStartLoc = 0; ProdMatched = false; ListState = ListTermState.Start; ListCount = 0; ListSeparatorStartLoc = 0; SubResult.ErrorMessage = "Uninitialized result"; SubResult.IsMatch = false; }
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); }