/** Return a list of parse trees, one for each alternative in a decision * given the same input. * * Very similar to {@link #getAllPossibleParseTrees} except * that it re-parses the input for every alternative in a decision, * not just the ambiguous ones (there is no alts parameter here). * This method also tries to reduce the size of the parse trees * by stripping away children of the tree that are completely out of range * of startIndex..stopIndex. Also, because errors are expected, we * use a specialized error handler that more or less bails out * but that also consumes the first erroneous token at least. This * ensures that an error node will be in the parse tree for display. * * NOTES: * // we must parse the entire input now with decision overrides * // we cannot parse a subset because it could be that a decision * // above our decision of interest needs to read way past * // lookaheadInfo.stopIndex. It seems like there is no escaping * // the use of a full and complete token stream if we are * // resetting to token index 0 and re-parsing from the start symbol. * // It's not easy to restart parsing somewhere in the middle like a * // continuation because our call stack does not match the * // tree stack because of left recursive rule rewriting. grrrr! * * @since 4.5.1 */ public static IList <ParserRuleContext> GetLookaheadParseTrees(Grammar g, ParserInterpreter originalParser, ITokenStream tokens, int startRuleIndex, int decision, int startIndex, int stopIndex) { IList <ParserRuleContext> trees = new List <ParserRuleContext>(); // Create a new parser interpreter to parse the ambiguous subphrase ParserInterpreter parser = DeriveTempParserInterpreter(g, originalParser, tokens); DecisionState decisionState = originalParser.Atn.decisionToState[decision]; for (int alt = 1; alt <= decisionState.Transitions.Length; alt++) { // 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.) BailButConsumeErrorStrategy errorHandler = new BailButConsumeErrorStrategy(); parser.ErrorHandler = errorHandler; parser.Reset(); parser.AddDecisionOverride(decision, startIndex, alt); ParserRuleContext tt = parser.Parse(startRuleIndex); int stopTreeAt = stopIndex; if (errorHandler.firstErrorTokenIndex >= 0) { stopTreeAt = errorHandler.firstErrorTokenIndex; // cut off rest at first error } Interval overallRange = tt.SourceInterval; if (stopTreeAt > overallRange.b) { // If we try to look beyond range of tree, stopTreeAt must be EOF // for which there is no EOF ref in grammar. That means tree // will not have node for stopTreeAt; limit to overallRange.b stopTreeAt = overallRange.b; } ParserRuleContext subtree = Trees.GetRootOfSubtreeEnclosingRegion(tt, startIndex, stopTreeAt); // Use higher of overridden decision tree or tree enclosing all tokens if (Trees.IsAncestorOf(parser.OverrideDecisionRoot, subtree)) { subtree = parser.OverrideDecisionRoot; } Trees.StripChildrenOutOfRange(subtree, parser.OverrideDecisionRoot, startIndex, stopTreeAt); trees.Add(subtree); } 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); }