/* 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/WildcardTransition.h"
#include "atn/NotSetTransition.h"
#include "misc/IntervalSet.h"
#include "atn/ATNConfig.h"
#include "support/CPPUtils.h"
#include "atn/LL1Analyzer.h"
using namespace antlr4;
using namespace antlr4::atn;
using namespace antlrcpp;
namespace {
struct ATNConfigHasher final {
size_t operator()(const ATNConfig& atn_config) const {
return atn_config.hashCode();
}
};
struct ATNConfigComparer final {
bool operator()(const ATNConfig& lhs, const ATNConfig& rhs) const {
return lhs == rhs;
}
};
class LL1AnalyzerImpl final {
public:
LL1AnalyzerImpl(const ATN& atn, misc::IntervalSet& look, bool seeThruPreds, bool addEOF) : _atn(atn), _look(look), _seeThruPreds(seeThruPreds), _addEOF(addEOF) {}
///
/// Compute set of tokens that can follow {@code s} in the ATN in the
/// specified {@code ctx}.
///
/// If {@code ctx} is {@code null} and {@code stopState} or the end of the
/// rule containing {@code s} is reached, 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, is added to the result set.
///
/// the ATN state.
/// the ATN state to stop at. This can be a
/// to detect epsilon paths through a closure.
/// The outer context, or {@code null} if the outer context should
/// not be used.
/// The result lookahead set.
/// A set used for preventing epsilon closures in the ATN
/// from causing a stack overflow. Outside code should pass
/// {@code new HashSet} for this argument.
/// 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.
/// {@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 to the
/// result if one is encountered.
/// Add to the result if the end of the
/// outermost context is reached. This parameter has no effect if {@code ctx}
/// is {@code null}.
void LOOK(ATNState *s, ATNState *stopState, Ref const& ctx) {
if (!_lookBusy.insert(ATNConfig(s, 0, ctx)).second) {
return;
}
// 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() == ATNStateType::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;
// 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));
}
if (removed) {
_calledRuleStack.set(s->ruleIndex);
}
return;
}
}
size_t n = s->transitions.size();
for (size_t i = 0; i < n; i++) {
const Transition *t = s->transitions[i].get();
const auto tType = t->getTransitionType();
if (tType == TransitionType::RULE) {
if (_calledRuleStack[(static_cast(t))->target->ruleIndex]) {
continue;
}
Ref newContext = SingletonPredictionContext::create(ctx, (static_cast(t))->followState->stateNumber);
_calledRuleStack.set((static_cast(t))->target->ruleIndex);
LOOK(t->target, stopState, newContext);
_calledRuleStack[(static_cast(t))->target->ruleIndex] = false;
} else if (tType == TransitionType::PREDICATE || tType == TransitionType::PRECEDENCE) {
if (_seeThruPreds) {
LOOK(t->target, stopState, ctx);
} else {
_look.add(LL1Analyzer::HIT_PRED);
}
} else if (t->isEpsilon()) {
LOOK(t->target, stopState, ctx);
} else if (tType == TransitionType::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 (tType == TransitionType::NOT_SET) {
set = set.complement(misc::IntervalSet::of(Token::MIN_USER_TOKEN_TYPE, static_cast(_atn.maxTokenType)));
}
_look.addAll(set);
}
}
}
}
private:
const ATN& _atn;
misc::IntervalSet& _look;
antlrcpp::BitSet _calledRuleStack;
std::unordered_set _lookBusy;
bool _seeThruPreds;
bool _addEOF;
};
}
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++) {
LL1AnalyzerImpl impl(_atn, look[alt], false, false);
impl.LOOK(s->transitions[alt]->target, nullptr, PredictionContext::EMPTY);
// 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(LL1Analyzer::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 {
Ref lookContext = ctx != nullptr ? PredictionContext::fromRuleContext(_atn, ctx) : nullptr;
misc::IntervalSet r;
LL1AnalyzerImpl impl(_atn, r, true, true);
impl.LOOK(s, stopState, lookContext);
return r;
}