/* 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 LL1Analyzer::getDecisionLookahead(ATNState *s) const { std::vector 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 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 const& ctx, misc::IntervalSet &look, ATNConfig::Set &lookBusy, antlrcpp::BitSet &calledRuleStack, bool seeThruPreds, bool addEOF) const { Ref c = std::make_shared(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(Token::EPSILON); return; } else if (ctx->isEmpty() && addEOF) { look.add(Token::EOF); return; } } if (s->getStateType() == ATNState::RULE_STOP) { if (ctx == nullptr) { look.add(Token::EPSILON); return; } else if (ctx->isEmpty() && addEOF) { look.add(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(t))->target->ruleIndex]) { continue; } Ref newContext = SingletonPredictionContext::create(ctx, (static_cast(t))->followState->stateNumber); auto onExit = finally([t, &calledRuleStack] { calledRuleStack[(static_cast(t))->target->ruleIndex] = false; }); calledRuleStack.set((static_cast(t))->target->ruleIndex); _LOOK(t->target, stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF); } else if (is(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(_atn.maxTokenType))); } else { misc::IntervalSet set = t->label(); if (!set.isEmpty()) { if (is(t)) { set = set.complement(misc::IntervalSet::of(Token::MIN_USER_TOKEN_TYPE, static_cast(_atn.maxTokenType))); } look.addAll(set); } } } }