Spaces:
Build error
Build error
# | |
# Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. | |
# Use of this file is governed by the BSD 3-clause license that | |
# can be found in the LICENSE.txt file in the project root. | |
# | |
# A parser simulator that mimics what ANTLR's generated | |
# parser code does. A ParserATNSimulator is used to make | |
# predictions via adaptivePredict but this class moves a pointer through the | |
# ATN to simulate parsing. ParserATNSimulator just | |
# makes us efficient rather than having to backtrack, for example. | |
# | |
# This properly creates parse trees even for left recursive rules. | |
# | |
# We rely on the left recursive rule invocation and special predicate | |
# transitions to make left recursive rules work. | |
# | |
# See TestParserInterpreter for examples. | |
# | |
from antlr4.dfa.DFA import DFA | |
from antlr4.BufferedTokenStream import TokenStream | |
from antlr4.Lexer import Lexer | |
from antlr4.Parser import Parser | |
from antlr4.ParserRuleContext import InterpreterRuleContext, ParserRuleContext | |
from antlr4.Token import Token | |
from antlr4.atn.ATN import ATN | |
from antlr4.atn.ATNState import StarLoopEntryState, ATNState, LoopEndState | |
from antlr4.atn.ParserATNSimulator import ParserATNSimulator | |
from antlr4.PredictionContext import PredictionContextCache | |
from antlr4.atn.Transition import Transition | |
from antlr4.error.Errors import RecognitionException, UnsupportedOperationException, FailedPredicateException | |
class ParserInterpreter(Parser): | |
__slots__ = ( | |
'grammarFileName', 'atn', 'tokenNames', 'ruleNames', 'decisionToDFA', | |
'sharedContextCache', '_parentContextStack', | |
'pushRecursionContextStates' | |
) | |
def __init__(self, grammarFileName:str, tokenNames:list, ruleNames:list, atn:ATN, input:TokenStream): | |
super().__init__(input) | |
self.grammarFileName = grammarFileName | |
self.atn = atn | |
self.tokenNames = tokenNames | |
self.ruleNames = ruleNames | |
self.decisionToDFA = [ DFA(state) for state in atn.decisionToState ] | |
self.sharedContextCache = PredictionContextCache() | |
self._parentContextStack = list() | |
# identify the ATN states where pushNewRecursionContext must be called | |
self.pushRecursionContextStates = set() | |
for state in atn.states: | |
if not isinstance(state, StarLoopEntryState): | |
continue | |
if state.isPrecedenceDecision: | |
self.pushRecursionContextStates.add(state.stateNumber) | |
# get atn simulator that knows how to do predictions | |
self._interp = ParserATNSimulator(self, atn, self.decisionToDFA, self.sharedContextCache) | |
# Begin parsing at startRuleIndex# | |
def parse(self, startRuleIndex:int): | |
startRuleStartState = self.atn.ruleToStartState[startRuleIndex] | |
rootContext = InterpreterRuleContext(None, ATNState.INVALID_STATE_NUMBER, startRuleIndex) | |
if startRuleStartState.isPrecedenceRule: | |
self.enterRecursionRule(rootContext, startRuleStartState.stateNumber, startRuleIndex, 0) | |
else: | |
self.enterRule(rootContext, startRuleStartState.stateNumber, startRuleIndex) | |
while True: | |
p = self.getATNState() | |
if p.stateType==ATNState.RULE_STOP : | |
# pop; return from rule | |
if len(self._ctx)==0: | |
if startRuleStartState.isPrecedenceRule: | |
result = self._ctx | |
parentContext = self._parentContextStack.pop() | |
self.unrollRecursionContexts(parentContext.a) | |
return result | |
else: | |
self.exitRule() | |
return rootContext | |
self.visitRuleStopState(p) | |
else: | |
try: | |
self.visitState(p) | |
except RecognitionException as e: | |
self.state = self.atn.ruleToStopState[p.ruleIndex].stateNumber | |
self._ctx.exception = e | |
self._errHandler.reportError(self, e) | |
self._errHandler.recover(self, e) | |
def enterRecursionRule(self, localctx:ParserRuleContext, state:int, ruleIndex:int, precedence:int): | |
self._parentContextStack.append((self._ctx, localctx.invokingState)) | |
super().enterRecursionRule(localctx, state, ruleIndex, precedence) | |
def getATNState(self): | |
return self.atn.states[self.state] | |
def visitState(self, p:ATNState): | |
edge = 0 | |
if len(p.transitions) > 1: | |
self._errHandler.sync(self) | |
edge = self._interp.adaptivePredict(self._input, p.decision, self._ctx) | |
else: | |
edge = 1 | |
transition = p.transitions[edge - 1] | |
tt = transition.serializationType | |
if tt==Transition.EPSILON: | |
if self.pushRecursionContextStates[p.stateNumber] and not isinstance(transition.target, LoopEndState): | |
t = self._parentContextStack[-1] | |
ctx = InterpreterRuleContext(t[0], t[1], self._ctx.ruleIndex) | |
self.pushNewRecursionContext(ctx, self.atn.ruleToStartState[p.ruleIndex].stateNumber, self._ctx.ruleIndex) | |
elif tt==Transition.ATOM: | |
self.match(transition.label) | |
elif tt in [ Transition.RANGE, Transition.SET, Transition.NOT_SET]: | |
if not transition.matches(self._input.LA(1), Token.MIN_USER_TOKEN_TYPE, Lexer.MAX_CHAR_VALUE): | |
self._errHandler.recoverInline(self) | |
self.matchWildcard() | |
elif tt==Transition.WILDCARD: | |
self.matchWildcard() | |
elif tt==Transition.RULE: | |
ruleStartState = transition.target | |
ruleIndex = ruleStartState.ruleIndex | |
ctx = InterpreterRuleContext(self._ctx, p.stateNumber, ruleIndex) | |
if ruleStartState.isPrecedenceRule: | |
self.enterRecursionRule(ctx, ruleStartState.stateNumber, ruleIndex, transition.precedence) | |
else: | |
self.enterRule(ctx, transition.target.stateNumber, ruleIndex) | |
elif tt==Transition.PREDICATE: | |
if not self.sempred(self._ctx, transition.ruleIndex, transition.predIndex): | |
raise FailedPredicateException(self) | |
elif tt==Transition.ACTION: | |
self.action(self._ctx, transition.ruleIndex, transition.actionIndex) | |
elif tt==Transition.PRECEDENCE: | |
if not self.precpred(self._ctx, transition.precedence): | |
msg = "precpred(_ctx, " + str(transition.precedence) + ")" | |
raise FailedPredicateException(self, msg) | |
else: | |
raise UnsupportedOperationException("Unrecognized ATN transition type.") | |
self.state = transition.target.stateNumber | |
def visitRuleStopState(self, p:ATNState): | |
ruleStartState = self.atn.ruleToStartState[p.ruleIndex] | |
if ruleStartState.isPrecedenceRule: | |
parentContext = self._parentContextStack.pop() | |
self.unrollRecursionContexts(parentContext.a) | |
self.state = parentContext[1] | |
else: | |
self.exitRule() | |
ruleTransition = self.atn.states[self.state].transitions[0] | |
self.state = ruleTransition.followState.stateNumber | |