| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- #
- # 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.
- #/
- from antlr4.IntervalSet import IntervalSet
- from antlr4.Token import Token
- from antlr4.PredictionContext import PredictionContext, SingletonPredictionContext, PredictionContextFromRuleContext
- from antlr4.RuleContext import RuleContext
- from antlr4.atn.ATN import ATN
- from antlr4.atn.ATNConfig import ATNConfig
- from antlr4.atn.ATNState import ATNState, RuleStopState
- from antlr4.atn.Transition import WildcardTransition, NotSetTransition, AbstractPredicateTransition, RuleTransition
- class LL1Analyzer (object):
- __slots__ = 'atn'
- #* Special value added to the lookahead sets to indicate that we hit
- # a predicate during analysis if {@code seeThruPreds==false}.
- #/
- HIT_PRED = Token.INVALID_TYPE
- def __init__(self, atn:ATN):
- self.atn = atn
- #*
- # Calculates the SLL(1) expected lookahead set for each outgoing transition
- # of an {@link ATNState}. The returned array has one element for each
- # outgoing transition in {@code s}. If the closure from transition
- # <em>i</em> leads to a semantic predicate before matching a symbol, the
- # element at index <em>i</em> of the result will be {@code null}.
- #
- # @param s the ATN state
- # @return the expected symbols for each outgoing transition of {@code s}.
- #/
- def getDecisionLookahead(self, s:ATNState):
- if s is None:
- return None
- count = len(s.transitions)
- look = [] * count
- for alt in range(0, count):
- look[alt] = set()
- lookBusy = set()
- seeThruPreds = False # fail to get lookahead upon pred
- self._LOOK(s.transition(alt).target, None, PredictionContext.EMPTY,
- look[alt], lookBusy, set(), seeThruPreds, False)
- # Wipe out lookahead for this alternative if we found nothing
- # or we had a predicate when we !seeThruPreds
- if len(look[alt])==0 or self.HIT_PRED in look[alt]:
- look[alt] = None
- return look
- #*
- # Compute set of tokens that can follow {@code s} in the ATN in the
- # specified {@code ctx}.
- #
- # <p>If {@code ctx} is {@code null} and the end of the rule containing
- # {@code s} is reached, {@link Token#EPSILON} is added to the result set.
- # If {@code ctx} is not {@code null} and the end of the outermost rule is
- # reached, {@link Token#EOF} is added to the result set.</p>
- #
- # @param s the ATN state
- # @param stopState the ATN state to stop at. This can be a
- # {@link BlockEndState} to detect epsilon paths through a closure.
- # @param ctx the complete parser context, or {@code null} if the context
- # should be ignored
- #
- # @return The set of tokens that can follow {@code s} in the ATN in the
- # specified {@code ctx}.
- #/
- def LOOK(self, s:ATNState, stopState:ATNState=None, ctx:RuleContext=None):
- r = IntervalSet()
- seeThruPreds = True # ignore preds; get all lookahead
- lookContext = PredictionContextFromRuleContext(s.atn, ctx) if ctx is not None else None
- self._LOOK(s, stopState, lookContext, r, set(), set(), seeThruPreds, True)
- return r
- #*
- # Compute set of tokens that can follow {@code s} in the ATN in the
- # specified {@code ctx}.
- #
- # <p>If {@code ctx} is {@code null} and {@code stopState} or the end of the
- # rule containing {@code s} is reached, {@link Token#EPSILON} is added to
- # the result set. If {@code ctx} is not {@code null} and {@code addEOF} is
- # {@code true} and {@code stopState} or the end of the outermost rule is
- # reached, {@link Token#EOF} is added to the result set.</p>
- #
- # @param s the ATN state.
- # @param stopState the ATN state to stop at. This can be a
- # {@link BlockEndState} to detect epsilon paths through a closure.
- # @param ctx The outer context, or {@code null} if the outer context should
- # not be used.
- # @param look The result lookahead set.
- # @param lookBusy A set used for preventing epsilon closures in the ATN
- # from causing a stack overflow. Outside code should pass
- # {@code new HashSet<ATNConfig>} for this argument.
- # @param calledRuleStack A set used for preventing left recursion in the
- # ATN from causing a stack overflow. Outside code should pass
- # {@code new BitSet()} for this argument.
- # @param seeThruPreds {@code true} to true semantic predicates as
- # implicitly {@code true} and "see through them", otherwise {@code false}
- # to treat semantic predicates as opaque and add {@link #HIT_PRED} to the
- # result if one is encountered.
- # @param addEOF Add {@link Token#EOF} to the result if the end of the
- # outermost context is reached. This parameter has no effect if {@code ctx}
- # is {@code null}.
- #/
- def _LOOK(self, s:ATNState, stopState:ATNState , ctx:PredictionContext, look:IntervalSet, lookBusy:set,
- calledRuleStack:set, seeThruPreds:bool, addEOF:bool):
- c = ATNConfig(s, 0, ctx)
- if c in lookBusy:
- return
- lookBusy.add(c)
- if s == stopState:
- if ctx is None:
- look.addOne(Token.EPSILON)
- return
- elif ctx.isEmpty() and addEOF:
- look.addOne(Token.EOF)
- return
- if isinstance(s, RuleStopState ):
- if ctx is None:
- look.addOne(Token.EPSILON)
- return
- elif ctx.isEmpty() and addEOF:
- look.addOne(Token.EOF)
- return
- if ctx != PredictionContext.EMPTY:
- removed = s.ruleIndex in calledRuleStack
- try:
- calledRuleStack.discard(s.ruleIndex)
- # run thru all possible stack tops in ctx
- for i in range(0, len(ctx)):
- returnState = self.atn.states[ctx.getReturnState(i)]
- self._LOOK(returnState, stopState, ctx.getParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
- finally:
- if removed:
- calledRuleStack.add(s.ruleIndex)
- return
- for t in s.transitions:
- if type(t) == RuleTransition:
- if t.target.ruleIndex in calledRuleStack:
- continue
- newContext = SingletonPredictionContext.create(ctx, t.followState.stateNumber)
- try:
- calledRuleStack.add(t.target.ruleIndex)
- self._LOOK(t.target, stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
- finally:
- calledRuleStack.remove(t.target.ruleIndex)
- elif isinstance(t, AbstractPredicateTransition ):
- if seeThruPreds:
- self._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
- else:
- look.addOne(self.HIT_PRED)
- elif t.isEpsilon:
- self._LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF)
- elif type(t) == WildcardTransition:
- look.addRange( range(Token.MIN_USER_TOKEN_TYPE, self.atn.maxTokenType + 1) )
- else:
- set_ = t.label
- if set_ is not None:
- if isinstance(t, NotSetTransition):
- set_ = set_.complement(Token.MIN_USER_TOKEN_TYPE, self.atn.maxTokenType)
- look.addSet(set_)
|