/// <summary> Recursive exploration for <see cref="Shifts"/>. </summary> private IEnumerable <KeyValuePair <int, ParserState.RulePosition> > AllShifts(ParserState.RulePosition rulepos, HashSet <int> alreadySeenRules) { if (alreadySeenRules != null) { if (rulepos.Position == 0 && alreadySeenRules.Contains(rulepos.Rule)) { // This rule was already seen during the recursive exploration yield break; } } var rule = Rules.GetRule(rulepos.Rule); var pos = rulepos.Position; // Reached the end of the rule, only reduce is allowed now if (rule.Steps.Count == pos) { yield break; } var step = rule.Steps[pos]; // These values move us one step forward var next = new ParserState.RulePosition(rulepos.Rule, pos + 1); foreach (var v in step.Source) { yield return(new KeyValuePair <int, ParserState.RulePosition>(v, next)); } if (step.IsTerminal) { yield break; } // Non-terminals allow stepping into any of their sub-rules, so consider // these as well using depth-first exploration using a hashset to avoid // infinite loops. if (alreadySeenRules == null) { alreadySeenRules = new HashSet <int>(); } if (pos == 0) { alreadySeenRules.Add(rulepos.Rule); } foreach (var v in step.Source) { foreach (var kv in AllShifts(new ParserState.RulePosition(v, 0), alreadySeenRules)) { yield return(kv); } } }
/// <summary> All tokens that can cause this rule to reduce. </summary> private IEnumerable <int> Reduces(ParserState.RulePosition rulepos) { var rule = Rules.GetRule(rulepos.Rule); var pos = rulepos.Position; // Reduce only allowed at end of rule if (rule.Steps.Count > pos) { return(new int[0]); } return(rule.ReducingTokens); }
/// <summary> Shifts for a specific position in a rule. </summary> /// <remarks> /// The value is the result of the shift, may be in the same rule or in /// another rule. The key is the shift source, can be either a token /// (in which case the action is a true SLR shift) or a rule (a SLR goto). /// </remarks> private IEnumerable <KeyValuePair <int, ParserState.RulePosition> > Shifts(ParserState.RulePosition rulepos) => AllShifts(rulepos, null);