public static Map<Integer, Interval> getStateToGrammarRegionMap(GrammarRootAST ast, IntervalSet grammarTokenTypes) {
		Map<Integer, Interval> stateToGrammarRegionMap = new HashMap<Integer, Interval>();
		if ( ast==null ) return stateToGrammarRegionMap;

		List<GrammarAST> nodes = ast.getNodesWithType(grammarTokenTypes);
		for (GrammarAST n : nodes) {
			if (n.atnState != null) {
				Interval tokenRegion = Interval.of(n.getTokenStartIndex(), n.getTokenStopIndex());
				org.antlr.runtime.tree.Tree ruleNode = null;
				// RULEs, BLOCKs of transformed recursive rules point to original token interval
				switch ( n.getType() ) {
					case ANTLRParser.RULE :
						ruleNode = n;
						break;
					case ANTLRParser.BLOCK :
					case ANTLRParser.CLOSURE :
						ruleNode = n.getAncestor(ANTLRParser.RULE);
						break;
				}
				if ( ruleNode instanceof RuleAST ) {
					String ruleName = ((RuleAST) ruleNode).getRuleName();
					Rule r = ast.g.getRule(ruleName);
					if ( r instanceof LeftRecursiveRule ) {
						RuleAST originalAST = ((LeftRecursiveRule) r).getOriginalAST();
						tokenRegion = Interval.of(originalAST.getTokenStartIndex(), originalAST.getTokenStopIndex());
					}
				}
				stateToGrammarRegionMap.put(n.atnState.stateNumber, tokenRegion);
			}
		}
		return stateToGrammarRegionMap;
	}
Return list of (TOKEN_NAME node, 'literal' node) pairs
tool/src/org/antlr/v4/tool/Grammar.java