/** identify the ATN states where we need to set the outer alt number. * For regular rules, that's the block at the target to rule start state. * For left-recursive rules, we track the primary block, which looks just * like a regular rule's outer block, and the star loop block (always * there even if 1 alt). */ public virtual BitSet FindOuterMostDecisionStates() { BitSet track = new BitSet(atn.states.Count); int numberOfDecisions = atn.NumberOfDecisions; for (int i = 0; i < numberOfDecisions; i++) { DecisionState decisionState = atn.GetDecisionState(i); RuleStartState startState = atn.ruleToStartState[decisionState.ruleIndex]; // Look for StarLoopEntryState that is in any left recursive rule if (decisionState is StarLoopEntryState) { StarLoopEntryState loopEntry = (StarLoopEntryState)decisionState; if (loopEntry.precedenceRuleDecision) { // Recursive alts always result in a (...)* in the transformed // left recursive rule and that always has a BasicBlockStartState // even if just 1 recursive alt exists. ATNState blockStart = loopEntry.Transition(0).target; // track the StarBlockStartState associated with the recursive alternatives track.Set(blockStart.stateNumber); } } else if (startState.Transition(0).target == decisionState) { // always track outermost block for any rule if it exists track.Set(decisionState.stateNumber); } } return track; }
/** identify the ATN states where we need to set the outer alt number. * For regular rules, that's the block at the target to rule start state. * For left-recursive rules, we track the primary block, which looks just * like a regular rule's outer block, and the star loop block (always * there even if 1 alt). */ public virtual BitSet FindOuterMostDecisionStates() { BitSet track = new BitSet(atn.states.Count); int numberOfDecisions = atn.NumberOfDecisions; for (int i = 0; i < numberOfDecisions; i++) { DecisionState decisionState = atn.GetDecisionState(i); RuleStartState startState = atn.ruleToStartState[decisionState.ruleIndex]; // Look for StarLoopEntryState that is in any left recursive rule if (decisionState is StarLoopEntryState) { StarLoopEntryState loopEntry = (StarLoopEntryState)decisionState; if (loopEntry.precedenceRuleDecision) { // Recursive alts always result in a (...)* in the transformed // left recursive rule and that always has a BasicBlockStartState // even if just 1 recursive alt exists. ATNState blockStart = loopEntry.Transition(0).target; // track the StarBlockStartState associated with the recursive alternatives track.Set(blockStart.stateNumber); } } else if (startState.Transition(0).target == decisionState) { // always track outermost block for any rule if it exists track.Set(decisionState.stateNumber); } } return(track); }
public GrammarParserInterpreter(Grammar g, ATN atn, ITokenStream input) : base(g.fileName, g.GetVocabulary(), g.GetRuleNames(), atn, // must run ATN through serializer to set some state flags input) { this.g = g; decisionStatesThatSetOuterAltNumInContext = FindOuterMostDecisionStates(); stateToAltsMap = new int[g.atn.states.Count][]; }
public GrammarParserInterpreter(Grammar g, ATN atn, ITokenStream input) : base(g.fileName, g.GetVocabulary(), g.GetRuleNames(), atn, // must run ATN through serializer to set some state flags input) { this.g = g; decisionStatesThatSetOuterAltNumInContext = FindOuterMostDecisionStates(); stateToAltsMap = new int[g.atn.states.Count][]; }
/** Given an ambiguous parse information, return the list of ambiguous parse trees. * An ambiguity occurs when a specific token sequence can be recognized * in more than one way by the grammar. These ambiguities are detected only * at decision points. * * The list of trees includes the actual interpretation (that for * the minimum alternative number) and all ambiguous alternatives. * The actual interpretation is always first. * * This method reuses the same physical input token stream used to * detect the ambiguity by the original parser in the first place. * This method resets/seeks within but does not alter originalParser. * * The trees are rooted at the node whose start..stop token indices * include the start and stop indices of this ambiguity event. That is, * the trees returned will always include the complete ambiguous subphrase * identified by the ambiguity event. The subtrees returned will * also always contain the node associated with the overridden decision. * * Be aware that this method does NOT notify error or parse listeners as * it would trigger duplicate or otherwise unwanted events. * * This uses a temporary ParserATNSimulator and a ParserInterpreter * so we don't mess up any statistics, event lists, etc... * The parse tree constructed while identifying/making ambiguityInfo is * not affected by this method as it creates a new parser interp to * get the ambiguous interpretations. * * Nodes in the returned ambig trees are independent of the original parse * tree (constructed while identifying/creating ambiguityInfo). * * @since 4.5.1 * * @param g From which grammar should we drive alternative * numbers and alternative labels. * * @param originalParser The parser used to create ambiguityInfo; it * is not modified by this routine and can be either * a generated or interpreted parser. It's token * stream *is* reset/seek()'d. * @param tokens A stream of tokens to use with the temporary parser. * This will often be just the token stream within the * original parser but here it is for flexibility. * * @param decision Which decision to try different alternatives for. * * @param alts The set of alternatives to try while re-parsing. * * @param startIndex The index of the first token of the ambiguous * input or other input of interest. * * @param stopIndex The index of the last token of the ambiguous input. * The start and stop indexes are used primarily to * identify how much of the resulting parse tree * to return. * * @param startRuleIndex The start rule for the entire grammar, not * the ambiguous decision. We re-parse the entire input * and so we need the original start rule. * * @return The list of all possible interpretations of * the input for the decision in ambiguityInfo. * The actual interpretation chosen by the parser * is always given first because this method * retests the input in alternative order and * ANTLR always resolves ambiguities by choosing * the first alternative that matches the input. * The subtree returned * * @throws RecognitionException Throws upon syntax error while matching * ambig input. */ public static IList <ParserRuleContext> GetAllPossibleParseTrees(Grammar g, Parser originalParser, ITokenStream tokens, int decision, BitSet alts, int startIndex, int stopIndex, int startRuleIndex) { IList <ParserRuleContext> trees = new List <ParserRuleContext>(); // Create a new parser interpreter to parse the ambiguous subphrase ParserInterpreter parser = DeriveTempParserInterpreter(g, originalParser, tokens); if (stopIndex >= (tokens.Size - 1)) { // if we are pointing at EOF token // EOF is not in tree, so must be 1 less than last non-EOF token stopIndex = tokens.Size - 2; } // get ambig trees int alt = alts.NextSetBit(0); while (alt >= 0) { // re-parse entire input for all ambiguous alternatives // (don't have to do first as it's been parsed, but do again for simplicity // using this temp parser.) parser.Reset(); parser.AddDecisionOverride(decision, startIndex, alt); ParserRuleContext t = parser.Parse(startRuleIndex); GrammarInterpreterRuleContext ambigSubTree = (GrammarInterpreterRuleContext)Trees.GetRootOfSubtreeEnclosingRegion(t, startIndex, stopIndex); // Use higher of overridden decision tree or tree enclosing all tokens if (Trees.IsAncestorOf(parser.OverrideDecisionRoot, ambigSubTree)) { ambigSubTree = (GrammarInterpreterRuleContext)parser.OverrideDecisionRoot; } trees.Add(ambigSubTree); alt = alts.NextSetBit(alt + 1); } return(trees); }
/** Given an ambiguous parse information, return the list of ambiguous parse trees. * An ambiguity occurs when a specific token sequence can be recognized * in more than one way by the grammar. These ambiguities are detected only * at decision points. * * The list of trees includes the actual interpretation (that for * the minimum alternative number) and all ambiguous alternatives. * The actual interpretation is always first. * * This method reuses the same physical input token stream used to * detect the ambiguity by the original parser in the first place. * This method resets/seeks within but does not alter originalParser. * * The trees are rooted at the node whose start..stop token indices * include the start and stop indices of this ambiguity event. That is, * the trees returned will always include the complete ambiguous subphrase * identified by the ambiguity event. The subtrees returned will * also always contain the node associated with the overridden decision. * * Be aware that this method does NOT notify error or parse listeners as * it would trigger duplicate or otherwise unwanted events. * * This uses a temporary ParserATNSimulator and a ParserInterpreter * so we don't mess up any statistics, event lists, etc... * The parse tree constructed while identifying/making ambiguityInfo is * not affected by this method as it creates a new parser interp to * get the ambiguous interpretations. * * Nodes in the returned ambig trees are independent of the original parse * tree (constructed while identifying/creating ambiguityInfo). * * @since 4.5.1 * * @param g From which grammar should we drive alternative * numbers and alternative labels. * * @param originalParser The parser used to create ambiguityInfo; it * is not modified by this routine and can be either * a generated or interpreted parser. It's token * stream *is* reset/seek()'d. * @param tokens A stream of tokens to use with the temporary parser. * This will often be just the token stream within the * original parser but here it is for flexibility. * * @param decision Which decision to try different alternatives for. * * @param alts The set of alternatives to try while re-parsing. * * @param startIndex The index of the first token of the ambiguous * input or other input of interest. * * @param stopIndex The index of the last token of the ambiguous input. * The start and stop indexes are used primarily to * identify how much of the resulting parse tree * to return. * * @param startRuleIndex The start rule for the entire grammar, not * the ambiguous decision. We re-parse the entire input * and so we need the original start rule. * * @return The list of all possible interpretations of * the input for the decision in ambiguityInfo. * The actual interpretation chosen by the parser * is always given first because this method * retests the input in alternative order and * ANTLR always resolves ambiguities by choosing * the first alternative that matches the input. * The subtree returned * * @throws RecognitionException Throws upon syntax error while matching * ambig input. */ public static IList<ParserRuleContext> GetAllPossibleParseTrees(Grammar g, Parser originalParser, ITokenStream tokens, int decision, BitSet alts, int startIndex, int stopIndex, int startRuleIndex) { IList<ParserRuleContext> trees = new List<ParserRuleContext>(); // Create a new parser interpreter to parse the ambiguous subphrase ParserInterpreter parser = DeriveTempParserInterpreter(g, originalParser, tokens); if (stopIndex >= (tokens.Size - 1)) { // if we are pointing at EOF token // EOF is not in tree, so must be 1 less than last non-EOF token stopIndex = tokens.Size - 2; } // get ambig trees int alt = alts.NextSetBit(0); while (alt >= 0) { // re-parse entire input for all ambiguous alternatives // (don't have to do first as it's been parsed, but do again for simplicity // using this temp parser.) parser.Reset(); parser.AddDecisionOverride(decision, startIndex, alt); ParserRuleContext t = parser.Parse(startRuleIndex); GrammarInterpreterRuleContext ambigSubTree = (GrammarInterpreterRuleContext)Trees.GetRootOfSubtreeEnclosingRegion(t, startIndex, stopIndex); // Use higher of overridden decision tree or tree enclosing all tokens if (Trees.IsAncestorOf(parser.OverrideDecisionRoot, ambigSubTree)) { ambigSubTree = (GrammarInterpreterRuleContext)parser.OverrideDecisionRoot; } trees.Add(ambigSubTree); alt = alts.NextSetBit(alt + 1); } return trees; }