| /* 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(); |
| } |
| |