| /* 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. |
| */ |
| |
| #include "atn/RuleStopState.h" |
| #include "atn/Transition.h" |
| #include "atn/RuleTransition.h" |
| #include "atn/SingletonPredictionContext.h" |
| #include "atn/AbstractPredicateTransition.h" |
| #include "atn/WildcardTransition.h" |
| #include "atn/NotSetTransition.h" |
| #include "misc/IntervalSet.h" |
| #include "atn/ATNConfig.h" |
| #include "atn/EmptyPredictionContext.h" |
| |
| #include "support/CPPUtils.h" |
| |
| #include "atn/LL1Analyzer.h" |
| |
| using namespace antlr4; |
| using namespace antlr4::atn; |
| using namespace antlrcpp; |
| |
| LL1Analyzer::LL1Analyzer(const ATN &atn) : _atn(atn) { |
| } |
| |
| LL1Analyzer::~LL1Analyzer() { |
| } |
| |
| std::vector<misc::IntervalSet> LL1Analyzer::getDecisionLookahead(ATNState *s) const { |
| std::vector<misc::IntervalSet> look; |
| |
| if (s == nullptr) { |
| return look; |
| } |
| |
| look.resize(s->transitions.size()); // Fills all interval sets with defaults. |
| for (size_t alt = 0; alt < s->transitions.size(); alt++) { |
| bool seeThruPreds = false; // fail to get lookahead upon pred |
| |
| ATNConfig::Set lookBusy; |
| antlrcpp::BitSet callRuleStack; |
| _LOOK(s->transitions[alt]->target, nullptr, PredictionContext::EMPTY, |
| look[alt], lookBusy, callRuleStack, seeThruPreds, false); |
| |
| // Wipe out lookahead for this alternative if we found nothing |
| // or we had a predicate when we !seeThruPreds |
| if (look[alt].size() == 0 || look[alt].contains(HIT_PRED)) { |
| look[alt].clear(); |
| } |
| } |
| return look; |
| } |
| |
| misc::IntervalSet LL1Analyzer::LOOK(ATNState *s, RuleContext *ctx) const { |
| return LOOK(s, nullptr, ctx); |
| } |
| |
| misc::IntervalSet LL1Analyzer::LOOK(ATNState *s, ATNState *stopState, RuleContext *ctx) const { |
| misc::IntervalSet r; |
| bool seeThruPreds = true; // ignore preds; get all lookahead |
| Ref<PredictionContext> lookContext = ctx != nullptr ? PredictionContext::fromRuleContext(_atn, ctx) : nullptr; |
| |
| ATNConfig::Set lookBusy; |
| antlrcpp::BitSet callRuleStack; |
| _LOOK(s, stopState, lookContext, r, lookBusy, callRuleStack, seeThruPreds, true); |
| |
| return r; |
| } |
| |
| void LL1Analyzer::_LOOK(ATNState *s, ATNState *stopState, Ref<PredictionContext> const& ctx, misc::IntervalSet &look, |
| ATNConfig::Set &lookBusy, antlrcpp::BitSet &calledRuleStack, bool seeThruPreds, bool addEOF) const { |
| |
| Ref<ATNConfig> c = std::make_shared<ATNConfig>(s, 0, ctx); |
| |
| if (lookBusy.count(c) > 0) // Keep in mind comparison is based on members of the class, not the actual instance. |
| return; |
| |
| lookBusy.insert(c); |
| |
| // ml: s can never be null, hence no need to check if stopState is != null. |
| if (s == stopState) { |
| if (ctx == nullptr) { |
| look.add(static_cast<int>(Token::EPSILON)); |
| return; |
| } else if (ctx->isEmpty() && addEOF) { |
| look.add(static_cast<int>(Token::EOF)); |
| return; |
| } |
| } |
| |
| if (s->getStateType() == ATNState::RULE_STOP) { |
| if (ctx == nullptr) { |
| look.add(static_cast<int>(Token::EPSILON)); |
| return; |
| } else if (ctx->isEmpty() && addEOF) { |
| look.add(static_cast<int>(Token::EOF)); |
| return; |
| } |
| |
| if (ctx != PredictionContext::EMPTY) { |
| bool removed = calledRuleStack.test(s->ruleIndex); |
| calledRuleStack[s->ruleIndex] = false; |
| auto onExit = finally([removed, &calledRuleStack, s] { |
| if (removed) { |
| calledRuleStack.set(s->ruleIndex); |
| } |
| }); |
| // run thru all possible stack tops in ctx |
| for (size_t i = 0; i < ctx->size(); i++) { |
| ATNState *returnState = _atn.states[ctx->getReturnState(i)]; |
| _LOOK(returnState, stopState, ctx->getParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF); |
| } |
| return; |
| } |
| } |
| |
| size_t n = s->transitions.size(); |
| for (size_t i = 0; i < n; i++) { |
| Transition *t = s->transitions[i]; |
| |
| if (t->getSerializationType() == Transition::RULE) { |
| if (calledRuleStack[(static_cast<RuleTransition*>(t))->target->ruleIndex]) { |
| continue; |
| } |
| |
| Ref<PredictionContext> newContext = SingletonPredictionContext::create(ctx, (static_cast<RuleTransition*>(t))->followState->stateNumber); |
| auto onExit = finally([t, &calledRuleStack] { |
| calledRuleStack[(static_cast<RuleTransition*>(t))->target->ruleIndex] = false; |
| }); |
| |
| calledRuleStack.set((static_cast<RuleTransition*>(t))->target->ruleIndex); |
| _LOOK(t->target, stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF); |
| |
| } else if (is<AbstractPredicateTransition *>(t)) { |
| if (seeThruPreds) { |
| _LOOK(t->target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF); |
| } else { |
| look.add(HIT_PRED); |
| } |
| } else if (t->isEpsilon()) { |
| _LOOK(t->target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF); |
| } else if (t->getSerializationType() == Transition::WILDCARD) { |
| look.addAll(misc::IntervalSet::of(Token::MIN_USER_TOKEN_TYPE, static_cast<ssize_t>(_atn.maxTokenType))); |
| } else { |
| misc::IntervalSet set = t->label(); |
| if (!set.isEmpty()) { |
| if (is<NotSetTransition*>(t)) { |
| set = set.complement(misc::IntervalSet::of(Token::MIN_USER_TOKEN_TYPE, static_cast<ssize_t>(_atn.maxTokenType))); |
| } |
| look.addAll(set); |
| } |
| } |
| } |
| } |