blob: ba236276414b70016c6ab7c15f4f017eb325d908 [file] [log] [blame]
/* 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/LL1Analyzer.h"
#include "Token.h"
#include "atn/RuleTransition.h"
#include "misc/IntervalSet.h"
#include "RuleContext.h"
#include "atn/DecisionState.h"
#include "Recognizer.h"
#include "atn/ATNType.h"
#include "Exceptions.h"
#include "support/CPPUtils.h"
#include "atn/ATN.h"
using namespace antlr4;
using namespace antlr4::atn;
using namespace antlrcpp;
ATN::ATN() : ATN(ATNType::LEXER, 0) {
}
ATN::ATN(ATN &&other) {
// All source vectors are implicitly cleared by the moves.
states = std::move(other.states);
decisionToState = std::move(other.decisionToState);
ruleToStartState = std::move(other.ruleToStartState);
ruleToStopState = std::move(other.ruleToStopState);
grammarType = std::move(other.grammarType);
maxTokenType = std::move(other.maxTokenType);
ruleToTokenType = std::move(other.ruleToTokenType);
lexerActions = std::move(other.lexerActions);
modeToStartState = std::move(other.modeToStartState);
}
ATN::ATN(ATNType grammarType_, size_t maxTokenType_) : grammarType(grammarType_), maxTokenType(maxTokenType_) {
}
ATN::~ATN() {
for (ATNState *state : states) {
delete state;
}
}
/**
* Required to be defined (even though not used) as we have an explicit move assignment operator.
*/
ATN& ATN::operator = (ATN &other) NOEXCEPT {
states = other.states;
decisionToState = other.decisionToState;
ruleToStartState = other.ruleToStartState;
ruleToStopState = other.ruleToStopState;
grammarType = other.grammarType;
maxTokenType = other.maxTokenType;
ruleToTokenType = other.ruleToTokenType;
lexerActions = other.lexerActions;
modeToStartState = other.modeToStartState;
return *this;
}
/**
* Explicit move assignment operator to make this the preferred assignment. With implicit copy/move assignment
* operators it seems the copy operator is preferred causing trouble when releasing the allocated ATNState instances.
*/
ATN& ATN::operator = (ATN &&other) NOEXCEPT {
// All source vectors are implicitly cleared by the moves.
states = std::move(other.states);
decisionToState = std::move(other.decisionToState);
ruleToStartState = std::move(other.ruleToStartState);
ruleToStopState = std::move(other.ruleToStopState);
grammarType = std::move(other.grammarType);
maxTokenType = std::move(other.maxTokenType);
ruleToTokenType = std::move(other.ruleToTokenType);
lexerActions = std::move(other.lexerActions);
modeToStartState = std::move(other.modeToStartState);
return *this;
}
misc::IntervalSet ATN::nextTokens(ATNState *s, RuleContext *ctx) const {
LL1Analyzer analyzer(*this);
return analyzer.LOOK(s, ctx);
}
misc::IntervalSet const& ATN::nextTokens(ATNState *s) const {
if (!s->_nextTokenUpdated) {
std::unique_lock<std::mutex> lock { _mutex };
if (!s->_nextTokenUpdated) {
s->_nextTokenWithinRule = nextTokens(s, nullptr);
s->_nextTokenUpdated = true;
}
}
return s->_nextTokenWithinRule;
}
void ATN::addState(ATNState *state) {
if (state != nullptr) {
//state->atn = this;
state->stateNumber = static_cast<int>(states.size());
}
states.push_back(state);
}
void ATN::removeState(ATNState *state) {
delete states.at(state->stateNumber);// just free mem, don't shift states in list
states.at(state->stateNumber) = nullptr;
}
int ATN::defineDecisionState(DecisionState *s) {
decisionToState.push_back(s);
s->decision = static_cast<int>(decisionToState.size() - 1);
return s->decision;
}
DecisionState *ATN::getDecisionState(size_t decision) const {
if (!decisionToState.empty()) {
return decisionToState[decision];
}
return nullptr;
}
size_t ATN::getNumberOfDecisions() const {
return decisionToState.size();
}
misc::IntervalSet ATN::getExpectedTokens(size_t stateNumber, RuleContext *context) const {
if (stateNumber == ATNState::INVALID_STATE_NUMBER || stateNumber >= states.size()) {
throw IllegalArgumentException("Invalid state number.");
}
RuleContext *ctx = context;
ATNState *s = states.at(stateNumber);
misc::IntervalSet following = nextTokens(s);
if (!following.contains(Token::EPSILON)) {
return following;
}
misc::IntervalSet expected;
expected.addAll(following);
expected.remove(Token::EPSILON);
while (ctx && ctx->invokingState != ATNState::INVALID_STATE_NUMBER && following.contains(Token::EPSILON)) {
ATNState *invokingState = states.at(ctx->invokingState);
RuleTransition *rt = static_cast<RuleTransition*>(invokingState->transitions[0]);
following = nextTokens(rt->followState);
expected.addAll(following);
expected.remove(Token::EPSILON);
if (ctx->parent == nullptr) {
break;
}
ctx = static_cast<RuleContext *>(ctx->parent);
}
if (following.contains(Token::EPSILON)) {
expected.add(static_cast<int>(Token::EOF));
}
return expected;
}
std::string ATN::toString() const {
std::stringstream ss;
std::string type;
switch (grammarType) {
case ATNType::LEXER:
type = "LEXER ";
break;
case ATNType::PARSER:
type = "PARSER ";
break;
default:
break;
}
ss << "(" << type << "ATN " << std::hex << this << std::dec << ") maxTokenType: " << maxTokenType << std::endl;
ss << "states (" << states.size() << ") {" << std::endl;
size_t index = 0;
for (auto *state : states) {
if (state == nullptr) {
ss << " " << index++ << ": nul" << std::endl;
} else {
std::string text = state->toString();
ss << " " << index++ << ": " << indent(text, " ", false) << std::endl;
}
}
index = 0;
for (auto *state : decisionToState) {
if (state == nullptr) {
ss << " " << index++ << ": nul" << std::endl;
} else {
std::string text = state->toString();
ss << " " << index++ << ": " << indent(text, " ", false) << std::endl;
}
}
ss << "}";
return ss.str();
}