public IPredictionTreeDestination SetDecisionFor(GrammarVocabulary rootTransitionKey, PredictionTreeLeaf targetStateNode) { Debug.Assert(rootTransitionKey != null, "Error, the root transition key to make a decision was invalid!"); IPredictionTreeDestination result; if (targetStateNode != null) { if (!this.decisionTree.TryGetValue(rootTransitionKey, targetStateNode, out result)) { this.decisionTree.Add(rootTransitionKey, targetStateNode, result = new PredictionTreeDestination() { DecidingFactor = rootTransitionKey, Target = targetStateNode }); } } else { if (!this.followFailures.TryGetValue(rootTransitionKey, out result)) { this.followFailures.Add(rootTransitionKey, result = new PredictionTreeFollowCaller(this) { DecidingFactor = rootTransitionKey }); } } return(result); }
FollowTransition( Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, GrammarVocabulary transitionKey, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleLookup, bool usePrevious, bool injectIncomingPaths, bool includeRootEdges = false, bool isEpsilonTransition = false, bool silentlyFail = false, bool isReduction = false) { var resultData = from u in FollowTransitionInternal(fullSeries, transitionKey, ruleLookup, usePrevious, isEpsilonTransition, silentlyFail, isReduction) group u.Item2 by u.Item1; FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, PredictionTreeBranch> result = new FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, PredictionTreeBranch>(); foreach (var element in resultData) { if (element.Key.IsEmpty) { result.SetAutoSegment(false); } result.Add(element.Key, element.ToList()); if (element.Key.IsEmpty) { result.SetAutoSegment(true); } } return(result); }
public TransitionRequest(GrammarVocabulary transition, PredictionTreeBranch path, bool usePrevious, bool isReduction) { this.path = path; this.transitionRequirement = transition; this.usePrevious = usePrevious; this.isReduction = isReduction; }
/// <summary> /// Constructs the initial look-ahead for the transitions. /// </summary> /// <remarks></remarks> public void ConstructInitialLookahead(GrammarSymbolSet grammarSymbols, Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleVocabulary) { /* * * Left-recursive rules will use the relevant rule * paths within their projections within a loop to avoid * stack overflow. * */ bool includeRules = this.RootLeaf.Veins.LeftRecursionType != ProductionRuleLeftRecursionType.None; var result = new ControlledDictionary <GrammarVocabulary, PredictionTree>(); this.LookAhead = result; if (includeRules) { /* * * On left-recursive rules, the requirements change. * * * The rules must be considered at the start to * ensure that the left recursive branches * can be switched 'off' to allow for reductions * to function properly. * */ foreach (var key in this.Veins.Keys) { var targets = this.Veins[key]; if (targets.Any(k => k.GetRecursionType() != ProductionRuleLeftRecursionType.None && this.RootLeaf == this)) { var intersection = key.Intersect(this.Veins.DFAOriginState.OutTransitions.FullCheck); var reducedRules = key.GetRuleVariant().GetSymbols().Select(k => (IGrammarRuleSymbol)k).Select(k => new { Node = fullSeries.GetRuleNodeFromFullSeries(k.Source), Symbol = k }).Where(k => k.Node.HasBeenReduced || k.Node == k.Node.RootLeaf && k.Node.Veins.LeftRecursionType != ProductionRuleLeftRecursionType.None).Select(k => k.Symbol); var ruleVar = new GrammarVocabulary(key.symbols, reducedRules.ToArray()); intersection |= (key.GetTokenVariant() | ruleVar); if (!intersection.IsEmpty) { result._Add(intersection, targets); } } else { DoReductionAware(fullSeries, result, key); } } } else { foreach (var key in this.Veins.Keys.ToArray()) { DoReductionAware(fullSeries, result, key); } } /* * * Lexical ambiguity handling follows after the full transition table is known. * */ SyntacticAnalysisCore.CreateLexicalAmbiguityTransitions(grammarSymbols, result, null, this, fullSeries, ruleVocabulary); }
/// <summary> /// Returns whether the <see cref="CurrentNode"/>'s States Transition Table /// collides with the <paramref name="collider"/> provided. /// </summary> /// <param name="collider">The <see cref="GrammarVocabulary"/> /// to check for collisions with.</param> /// <returns>true, if the <paramref name="collider"/> collides with the /// transition table.</returns> public bool CollidesWith(GrammarVocabulary collider) { if (this.CurrentNode == null || collider == null || collider.IsEmpty) { return(false); } return(!this.CurrentNode.Veins.DFAOriginState.OutTransitions.FullCheck.Intersect(collider).IsEmpty); }
private static TransitionRequest GetTransitionRequest(GrammarVocabulary transition, PredictionTreeBranch path, bool usePrevious, bool isReduction) { List <TransitionRequest> result; var fKey = Tuple.Create(usePrevious, isReduction); lock (transitionRequests) if (transitionRequests.TryGetValue(fKey, transition, path, out result)) { lock (result) return(result.FirstOrDefault(p => p.DeviationDetail.SequenceEqual(path.deviations))); } return(null); }
private static IEnumerable <PredictionTreeBranch> PushIntersection( PredictionTreeBranch sourceMasterPath, FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, Tuple <int, PredictionTreeBranch> > transitionTableResult, Stack <Tuple <int, PredictionTreeBranch> > toProcess, HashSet <PredictionTreeBranch> seen, Tuple <int, PredictionTreeBranch> currentPathTuple, PredictionTreeBranch currentPath, PredictionTreeBranch path, GrammarVocabulary intersection, GrammarVocabulary transitionKey = null) { /* * * * * * * * * * * * * * * * * * * * * * * * * *\ * Construct the transition table with the matching * * paths. * * * * * * * * * * * * * * * * * * * * * * * * * * */ var intersectingCurrent = from key in currentPath.CurrentNode.Veins.Keys let intersect = key.Intersect(intersection) where !intersect.IsEmpty let subPathSet = currentPath.CurrentNode.Veins[key] from subPath in subPathSet.UnalteredOriginals let rPath = new PredictionTreeBranch(sourceMasterPath.Take(currentPath.Depth).Concat(subPath).ToList(), currentPath.Depth + subPath.Depth, true, false, currentPath.GetDeviationsUpTo(currentPath.Depth), minDepth: currentPath.Depth) where rPath.Valid select rPath; var set = new List <Tuple <int, PredictionTreeBranch> >(from ip in intersectingCurrent select Tuple.Create(currentPathTuple.Item1, ip)) { Tuple.Create(currentPathTuple.Item1 + 1, new PredictionTreeBranch(path.baseList, path.Depth, false, false, minDepth: path.Depth)) }; var distinctNodeArray = (from element in set select element.Item2).Distinct().ToArray(); foreach (var element in distinctNodeArray) { yield return(element); } transitionTableResult.Add(transitionKey ?? intersection, set); /* * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * If the current point is an edge, walk further * * up the parse tree to see what else lies in store. * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * Further ambiguities might result in additional look- * * ahead being necessary. * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (seen.Add(path) && path.CurrentNode.Veins.DFAOriginState.IsEdge) { toProcess.Push(Tuple.Create(currentPathTuple.Item1 + 1, path)); } }
public ProductionRuleProjectionReduction SetReductionOn(GrammarVocabulary reducedRule, int deviationLevel, Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries) { Debug.Assert(reducedRule != null, "Error, the root transition key to make a reduction was invalid!"); var vocabSymbol = reducedRule.GetSymbols()[0]; var ruleVocabSymbol = vocabSymbol as IGrammarRuleSymbol; if (ruleVocabSymbol != null) { var rootNode = fullSeries.GetRuleNodeFromFullSeries(ruleVocabSymbol.Source); if (!rootNode.HasBeenReduced) { rootNode.HasBeenReduced = true; } } return(new ProductionRuleProjectionReduction() { ReducedRule = reducedRule, LookAheadDepth = deviationLevel, Rule = this.RootLeaf.Rule }); }
private void DoReductionAware(Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, ControlledDictionary <GrammarVocabulary, PredictionTree> result, GrammarVocabulary key) { var tokenVar = key.GetTokenVariant(); var reducedRules = key .GetRuleVariant() .GetSymbols() .Select(k => (IGrammarRuleSymbol)k) .Select(k => new { Node = fullSeries.GetRuleNodeFromFullSeries(k.Source), Symbol = k }) .Where(k => k.Node.HasBeenReduced).Select(k => k.Symbol);// || k.Node == k.Node.RootLeaf && k.Node.Value.LeftRecursionType != ProductionRuleLeftRecursionType.None && this == this.RootLeaf var ruleVar = new GrammarVocabulary(key.symbols, reducedRules.ToArray()); if (!tokenVar.IsEmpty) { result._Add(tokenVar, this.Veins[key]); } if (!ruleVar.IsEmpty) { result._Add(ruleVar, this.Veins[key]); } }
private static TransitionRequest PushTransitionRequest(GrammarVocabulary transition, PredictionTreeBranch path, bool usePrevious, bool isReduction) { var fKey = Tuple.Create(usePrevious, isReduction); lock (transitionRequests) { List <TransitionRequest> resultSet; if (!transitionRequests.TryGetValue(fKey, transition, path, out resultSet)) { transitionRequests.Add(fKey, transition, path, resultSet = new List <TransitionRequest>()); } lock (resultSet) { TransitionRequest result = resultSet.FirstOrDefault(p => p.DeviationDetail.SequenceEqual(path.deviations)); if (result == null) { resultSet.Add(result = new TransitionRequest(transition, path, usePrevious, isReduction)); } return(result); } } }
private void ObtainTerminalAmbiguitiesOnPath( PredictionTreeBranch sourceMasterPath, Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, ControlledDictionary <IOilexerGrammarProductionRuleEntry, SyntacticalDFARootState> ruleDFAs, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleLookup, FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, Tuple <int, PredictionTreeBranch> > transitionTableResult, GrammarSymbolSet grammarSymbols) { var ambiguousSymbols = grammarSymbols.AmbiguousSymbols.ToList(); Stack <Tuple <int, PredictionTreeBranch> > toProcess = new Stack <Tuple <int, PredictionTreeBranch> >(); var fullCheck = this.Veins.Keys.Aggregate(GrammarVocabulary.UnionAggregateDelegate); /* * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Kick things off with the master path, this is derived * * from the incoming states from the parent rule. * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ toProcess.Push(Tuple.Create(0, sourceMasterPath)); //foreach (var transition in this.Value.Keys) // foreach (var target in this.Value[transition]) // toProcess.Push(new PredictionTreeBranch(sourceMasterPath.Take(sourceMasterPath.Depth).Concat(target).ToList(), sourceMasterPath.Depth, true, false, sourceMasterPath.GetDeviationsUpTo(sourceMasterPath.Depth))); HashSet <PredictionTreeBranch> seen = new HashSet <PredictionTreeBranch>(); while (toProcess.Count > 0) { var currentPathTuple = toProcess.Pop(); var currentPath = currentPathTuple.Item2; if (currentPath.Depth == 0) { continue; } if (currentPath.CurrentNode.Veins.Keys.Aggregate(GrammarVocabulary.UnionAggregateDelegate).Intersect(fullCheck).IsEmpty) { continue; } /* * * Walk up the tree one level into the state that * follows the current rule in whatever the current * calling rule might be. * */ var incomingTransitions = currentPath.FollowTransition(fullSeries, ruleLookup[currentPath.CurrentNode.Veins.Rule], ruleLookup, true, false, true, true); /* * * Aggregate the transitions from our previously * calculated LL(1) look-ahead information. * */ /* * * On the state following this rule, gather up the * targets which do overlap one or more of our * transitions. * */ var fullAmbiguityContext = incomingTransitions.FullCheck | fullCheck; var intersectionPoints = (from t in incomingTransitions.Keys let intersection = t.Intersect(fullCheck) where !intersection.IsEmpty from path in incomingTransitions[t] select new { Intersection = intersection, Path = path }).ToArray(); var overlap = GrammarVocabulary.NullInst; if ((fullAmbiguityContext != null && !fullAmbiguityContext.IsEmpty) && grammarSymbols.IsGrammarPotentiallyAmbiguous(fullAmbiguityContext)) { foreach (var ambiguity in ambiguousSymbols) { var localIntersect = fullCheck & ambiguity.AmbiguityKey; var incomingIntersect = incomingTransitions.FullCheck & ambiguity.AmbiguityKey; if (localIntersect.IsEmpty || incomingIntersect.IsEmpty) { /* If the intersection isn't present on one or the other sides; then, for the purposes of * this follow check, the union would not be relevant, it would likely be identified within the * prediction upon the state itself. */ continue; } var aggregateIntersect = fullAmbiguityContext & ambiguity.AmbiguityKey; var overlapIntersect = overlap & ambiguity.AmbiguityKey; if (aggregateIntersect.Equals(ambiguity.AmbiguityKey) && !overlapIntersect.Equals(ambiguity.AmbiguityKey)) { /* */ var ambiguityIntersection = (from t in incomingTransitions.Keys let intersection = t.Intersect(incomingIntersect) where !intersection.IsEmpty from path in incomingTransitions[t] select new { Intersection = intersection, Path = path }).ToArray(); var ambiguityVocabulary = new GrammarVocabulary(grammarSymbols, ambiguity); foreach (var intersectingPoint in ambiguityIntersection) { var path = intersectingPoint.Path; var intersection = localIntersect; if (path.Equals(currentPath)) { continue; } /* Notify the nodes of the ambiguities so their state-machines can be patched up. * This is done explicitly to avoid the ambiguity cropping up and allowing it everywhere, * which is incorrect. If it shows up where it's not supposed to, we have a logic error * somwehere. */ foreach (var node in (from ambigPath in PushIntersection(sourceMasterPath, transitionTableResult, toProcess, seen, currentPathTuple, currentPath, path, intersection, ambiguityVocabulary) select ambigPath.CurrentNode).Distinct().ToArray()) { node.DenoteLexicalAmbiguity(ambiguity); } } ambiguity.Occurrences++; overlap |= aggregateIntersect; } } } foreach (var intersectingPoint in intersectionPoints) { var path = intersectingPoint.Path; var intersection = intersectingPoint.Intersection; if (path.Equals(currentPath)) { continue; } PushIntersection(sourceMasterPath, transitionTableResult, toProcess, seen, currentPathTuple, currentPath, path, intersection).ToArray(); } } }
private PredictionTree GetFollowDPathSet(FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, Tuple <int, PredictionTreeBranch> > transitionTableResult, GrammarVocabulary transition, Dictionary <PredictionTreeBranch, int[]> epDepthLookup) { //var minMinDepth = (from deviationPath in transitionTableResult[transition] // select deviationPath.Item2.MinDepth).Min(); //minDepth = minMinDepth; //epDepthLookup = epDepthLookup.ToDictionary(dps => new PredictionTreeBranch(dps.Key.Skip(minMinDepth).ToList(), dps.Key.Depth - minMinDepth, minDepth: dps.Key.MinDepth - minMinDepth), dps => dps.Value); var result = PredictionTree.GetPathSet(transition, epDepthLookup.Keys.ToList(), this, ProductionRuleProjectionType.FollowAmbiguity, PredictionDerivedFrom.LookAhead_FollowPrediction); result.SetFollowEpsilonData(provider => epDepthLookup[provider]); return(result); }
FollowTransitionInternal( Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, GrammarVocabulary transitionKey, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleLookup, bool usePrevious, bool isEpsilonTransition = false, bool silentlyFail = false, bool isReduction = false) { if (transitionKey.IsEmpty) { return(new Tuple <GrammarVocabulary, PredictionTreeBranch> [0]); } List <Tuple <GrammarVocabulary, PredictionTreeBranch> > result = new List <Tuple <GrammarVocabulary, PredictionTreeBranch> >(); /* * * The transition was broken up earlier to yield * subsets that overlapped on a portion of the * transition. * */ var ambiguityVocabulary = transitionKey.DisambiguateVocabulary(); short[] deviationsToPass = this.deviations; if (isReduction) { deviationsToPass = this.IncrementDeviations(this.Depth, false); } var targetPath = usePrevious ? this.Depth == this.MinDepth && this.Depth > 0 ? new PredictionTreeBranch(this.baseList, this.Depth - 1, false, false, deviationsToPass, this.epsilonDerivations, this.MinDepth - 1) : this.DecreaseDepth(false) : this; if (isReduction) { targetPath = new PredictionTreeBranch(targetPath.baseList, targetPath.Depth, false, false, deviationsToPass, this.epsilonDerivations, targetPath.MinDepth); } var fullTransitionKey = targetPath.CurrentNode.Veins.DFAOriginState.OutTransitions.Keys.FirstOrDefault(v => !v.Intersect(transitionKey.DisambiguateVocabulary()).IsEmpty); var cachedRequest = GetTransitionRequest(transitionKey, targetPath, usePrevious, isReduction); if (cachedRequest != null) { return(cachedRequest.Detail); } if (fullTransitionKey == null && !silentlyFail) { Debug.Assert(fullTransitionKey != null); } else if (fullTransitionKey == null && silentlyFail) { return(result); } var targetOfTransition = targetPath.CurrentNode.Veins.DFAOriginState.OutTransitions[fullTransitionKey]; var targetNodeOfTransition = fullSeries[targetOfTransition]; PredictionTreeLeaf[] previousNodes = null; if (targetPath.Depth > 0) { previousNodes = targetPath.Take(targetPath.Depth).ToArray(); } else { previousNodes = new PredictionTreeLeaf[0]; } if (targetNodeOfTransition.Veins.Keys.Count > 0) { foreach (var key in targetNodeOfTransition.Veins.Keys) { var tokenVar = key.GetTokenVariant(); var originalSet = key.GetRuleVariant().GetSymbols().Select(k => (IGrammarRuleSymbol)k).Select(k => new { Node = fullSeries.GetRuleNodeFromFullSeries(k.Source), Symbol = k }).Where(k => k.Node.HasBeenReduced).ToArray(); var reducedRules = originalSet.Where(k => NodeIsRelevantToThis(k.Node, targetNodeOfTransition)).Select(k => k.Symbol).ToArray(); var ruleVar = new GrammarVocabulary(key.symbols, reducedRules); foreach (var path in targetNodeOfTransition.Veins[key].UnalteredOriginals) { var currentSubPath = path; /* * * The transition is derived from the parent node's transitions because the current node is omittable. * */ while (!currentSubPath.CurrentNode.Veins.Keys.Any(k => !k.Intersect(key).IsEmpty) && currentSubPath.Depth > 0) { currentSubPath = currentSubPath.DecreaseDepth(false); } if (!tokenVar.IsEmpty) { result.Add(Tuple.Create(tokenVar, GetTransitionPath(targetPath, previousNodes, currentSubPath, ruleLookup, usePrevious, isEpsilonTransition))); } if (!ruleVar.IsEmpty) { result.Add(Tuple.Create(ruleVar, GetTransitionPath(targetPath, previousNodes, currentSubPath, ruleLookup, usePrevious, isEpsilonTransition))); } } } if (targetOfTransition.IsEdge) { HandleLeftRecursiveInjection(fullSeries, ruleLookup, usePrevious, isEpsilonTransition, silentlyFail, result, targetPath, targetNodeOfTransition, previousNodes); var result2 = result.ToArray().ToList(); if (previousNodes.Length > 0) { result.AddRange(GetTransitionPath(targetPath, previousNodes, targetNodeOfTransition, ruleLookup, usePrevious, isEpsilonTransition, false).FollowTransitionInternal(fullSeries, ruleLookup[targetNodeOfTransition.Veins.Rule], ruleLookup, true, isEpsilonTransition: isEpsilonTransition)); } else { result.Add(Tuple.Create(GrammarVocabulary.NullInst, new PredictionTreeBranch(new[] { targetNodeOfTransition }, passAlong: false))); } } } else if (targetOfTransition.IsEdge && previousNodes.Length > 0) { HandleLeftRecursiveInjection(fullSeries, ruleLookup, usePrevious, isEpsilonTransition, silentlyFail, result, targetPath, targetNodeOfTransition, previousNodes); result.AddRange(targetPath.FollowTransitionInternal(fullSeries, ruleLookup[targetNodeOfTransition.Veins.Rule], ruleLookup, true, isEpsilonTransition: isEpsilonTransition)); } else if (targetOfTransition.IsEdge && previousNodes.Length == 0 /* && includeRootEdges*/) { result.Add(Tuple.Create(GrammarVocabulary.NullInst, new PredictionTreeBranch(new[] { targetNodeOfTransition }, passAlong: false))); } var transitionDetail = PushTransitionRequest(transitionKey, targetPath, usePrevious, isReduction); if (transitionDetail.Detail == null) { transitionDetail.Detail = result; } return(result); }