X-Git-Url: https://gitweb.ps.run/toc/blobdiff_plain/9f94b672a5dc32da5ad01742bd4e976315a30d9c..c6ad2948bb98d42f8e0883ef82cd14cd2d5eda60:/antlr4-cpp-runtime-4.9.2-source/runtime/src/atn/SemanticContext.cpp diff --git a/antlr4-cpp-runtime-4.9.2-source/runtime/src/atn/SemanticContext.cpp b/antlr4-cpp-runtime-4.9.2-source/runtime/src/atn/SemanticContext.cpp new file mode 100644 index 0000000..0531e37 --- /dev/null +++ b/antlr4-cpp-runtime-4.9.2-source/runtime/src/atn/SemanticContext.cpp @@ -0,0 +1,377 @@ +/* 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 "misc/MurmurHash.h" +#include "support/CPPUtils.h" +#include "support/Arrays.h" + +#include "SemanticContext.h" + +using namespace antlr4; +using namespace antlr4::atn; +using namespace antlrcpp; + +//------------------ Predicate ----------------------------------------------------------------------------------------- + +SemanticContext::Predicate::Predicate() : Predicate(INVALID_INDEX, INVALID_INDEX, false) { +} + +SemanticContext::Predicate::Predicate(size_t ruleIndex, size_t predIndex, bool isCtxDependent) +: ruleIndex(ruleIndex), predIndex(predIndex), isCtxDependent(isCtxDependent) { +} + + +bool SemanticContext::Predicate::eval(Recognizer *parser, RuleContext *parserCallStack) { + RuleContext *localctx = nullptr; + if (isCtxDependent) + localctx = parserCallStack; + return parser->sempred(localctx, ruleIndex, predIndex); +} + +size_t SemanticContext::Predicate::hashCode() const { + size_t hashCode = misc::MurmurHash::initialize(); + hashCode = misc::MurmurHash::update(hashCode, ruleIndex); + hashCode = misc::MurmurHash::update(hashCode, predIndex); + hashCode = misc::MurmurHash::update(hashCode, isCtxDependent ? 1 : 0); + hashCode = misc::MurmurHash::finish(hashCode, 3); + return hashCode; +} + +bool SemanticContext::Predicate::operator == (const SemanticContext &other) const { + if (this == &other) + return true; + + const Predicate *p = dynamic_cast(&other); + if (p == nullptr) + return false; + + return ruleIndex == p->ruleIndex && predIndex == p->predIndex && isCtxDependent == p->isCtxDependent; +} + +std::string SemanticContext::Predicate::toString() const { + return std::string("{") + std::to_string(ruleIndex) + std::string(":") + std::to_string(predIndex) + std::string("}?"); +} + +//------------------ PrecedencePredicate ------------------------------------------------------------------------------- + +SemanticContext::PrecedencePredicate::PrecedencePredicate() : precedence(0) { +} + +SemanticContext::PrecedencePredicate::PrecedencePredicate(int precedence) : precedence(precedence) { +} + +bool SemanticContext::PrecedencePredicate::eval(Recognizer *parser, RuleContext *parserCallStack) { + return parser->precpred(parserCallStack, precedence); +} + +Ref SemanticContext::PrecedencePredicate::evalPrecedence(Recognizer *parser, + RuleContext *parserCallStack) { + if (parser->precpred(parserCallStack, precedence)) { + return SemanticContext::NONE; + } + else { + return nullptr; + } +} + +int SemanticContext::PrecedencePredicate::compareTo(PrecedencePredicate *o) { + return precedence - o->precedence; +} + +size_t SemanticContext::PrecedencePredicate::hashCode() const { + size_t hashCode = 1; + hashCode = 31 * hashCode + static_cast(precedence); + return hashCode; +} + +bool SemanticContext::PrecedencePredicate::operator == (const SemanticContext &other) const { + if (this == &other) + return true; + + const PrecedencePredicate *predicate = dynamic_cast(&other); + if (predicate == nullptr) + return false; + + return precedence == predicate->precedence; +} + +std::string SemanticContext::PrecedencePredicate::toString() const { + return "{" + std::to_string(precedence) + ">=prec}?"; +} + +//------------------ AND ----------------------------------------------------------------------------------------------- + +SemanticContext::AND::AND(Ref const& a, Ref const& b) { + Set operands; + + if (is(a)) { + for (auto operand : std::dynamic_pointer_cast(a)->opnds) { + operands.insert(operand); + } + } else { + operands.insert(a); + } + + if (is(b)) { + for (auto operand : std::dynamic_pointer_cast(b)->opnds) { + operands.insert(operand); + } + } else { + operands.insert(b); + } + + std::vector> precedencePredicates = filterPrecedencePredicates(operands); + + if (!precedencePredicates.empty()) { + // interested in the transition with the lowest precedence + auto predicate = [](Ref const& a, Ref const& b) { + return a->precedence < b->precedence; + }; + + auto reduced = std::min_element(precedencePredicates.begin(), precedencePredicates.end(), predicate); + operands.insert(*reduced); + } + + std::copy(operands.begin(), operands.end(), std::back_inserter(opnds)); +} + +std::vector> SemanticContext::AND::getOperands() const { + return opnds; +} + +bool SemanticContext::AND::operator == (const SemanticContext &other) const { + if (this == &other) + return true; + + const AND *context = dynamic_cast(&other); + if (context == nullptr) + return false; + + return Arrays::equals(opnds, context->opnds); +} + +size_t SemanticContext::AND::hashCode() const { + return misc::MurmurHash::hashCode(opnds, typeid(AND).hash_code()); +} + +bool SemanticContext::AND::eval(Recognizer *parser, RuleContext *parserCallStack) { + for (auto opnd : opnds) { + if (!opnd->eval(parser, parserCallStack)) { + return false; + } + } + return true; +} + +Ref SemanticContext::AND::evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) { + bool differs = false; + std::vector> operands; + for (auto context : opnds) { + Ref evaluated = context->evalPrecedence(parser, parserCallStack); + differs |= (evaluated != context); + if (evaluated == nullptr) { + // The AND context is false if any element is false. + return nullptr; + } else if (evaluated != NONE) { + // Reduce the result by skipping true elements. + operands.push_back(evaluated); + } + } + + if (!differs) { + return shared_from_this(); + } + + if (operands.empty()) { + // All elements were true, so the AND context is true. + return NONE; + } + + Ref result = operands[0]; + for (size_t i = 1; i < operands.size(); ++i) { + result = SemanticContext::And(result, operands[i]); + } + + return result; +} + +std::string SemanticContext::AND::toString() const { + std::string tmp; + for (auto var : opnds) { + tmp += var->toString() + " && "; + } + return tmp; +} + +//------------------ OR ------------------------------------------------------------------------------------------------ + +SemanticContext::OR::OR(Ref const& a, Ref const& b) { + Set operands; + + if (is(a)) { + for (auto operand : std::dynamic_pointer_cast(a)->opnds) { + operands.insert(operand); + } + } else { + operands.insert(a); + } + + if (is(b)) { + for (auto operand : std::dynamic_pointer_cast(b)->opnds) { + operands.insert(operand); + } + } else { + operands.insert(b); + } + + std::vector> precedencePredicates = filterPrecedencePredicates(operands); + if (!precedencePredicates.empty()) { + // interested in the transition with the highest precedence + auto predicate = [](Ref const& a, Ref const& b) { + return a->precedence < b->precedence; + }; + auto reduced = std::max_element(precedencePredicates.begin(), precedencePredicates.end(), predicate); + operands.insert(*reduced); + } + + std::copy(operands.begin(), operands.end(), std::back_inserter(opnds)); +} + +std::vector> SemanticContext::OR::getOperands() const { + return opnds; +} + +bool SemanticContext::OR::operator == (const SemanticContext &other) const { + if (this == &other) + return true; + + const OR *context = dynamic_cast(&other); + if (context == nullptr) + return false; + + return Arrays::equals(opnds, context->opnds); +} + +size_t SemanticContext::OR::hashCode() const { + return misc::MurmurHash::hashCode(opnds, typeid(OR).hash_code()); +} + +bool SemanticContext::OR::eval(Recognizer *parser, RuleContext *parserCallStack) { + for (auto opnd : opnds) { + if (opnd->eval(parser, parserCallStack)) { + return true; + } + } + return false; +} + +Ref SemanticContext::OR::evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) { + bool differs = false; + std::vector> operands; + for (auto context : opnds) { + Ref evaluated = context->evalPrecedence(parser, parserCallStack); + differs |= (evaluated != context); + if (evaluated == NONE) { + // The OR context is true if any element is true. + return NONE; + } else if (evaluated != nullptr) { + // Reduce the result by skipping false elements. + operands.push_back(evaluated); + } + } + + if (!differs) { + return shared_from_this(); + } + + if (operands.empty()) { + // All elements were false, so the OR context is false. + return nullptr; + } + + Ref result = operands[0]; + for (size_t i = 1; i < operands.size(); ++i) { + result = SemanticContext::Or(result, operands[i]); + } + + return result; +} + +std::string SemanticContext::OR::toString() const { + std::string tmp; + for(auto var : opnds) { + tmp += var->toString() + " || "; + } + return tmp; +} + +//------------------ SemanticContext ----------------------------------------------------------------------------------- + +const Ref SemanticContext::NONE = std::make_shared(INVALID_INDEX, INVALID_INDEX, false); + +SemanticContext::~SemanticContext() { +} + +bool SemanticContext::operator != (const SemanticContext &other) const { + return !(*this == other); +} + +Ref SemanticContext::evalPrecedence(Recognizer * /*parser*/, RuleContext * /*parserCallStack*/) { + return shared_from_this(); +} + +Ref SemanticContext::And(Ref const& a, Ref const& b) { + if (!a || a == NONE) { + return b; + } + + if (!b || b == NONE) { + return a; + } + + Ref result = std::make_shared(a, b); + if (result->opnds.size() == 1) { + return result->opnds[0]; + } + + return result; +} + +Ref SemanticContext::Or(Ref const& a, Ref const& b) { + if (!a) { + return b; + } + if (!b) { + return a; + } + + if (a == NONE || b == NONE) { + return NONE; + } + + Ref result = std::make_shared(a, b); + if (result->opnds.size() == 1) { + return result->opnds[0]; + } + + return result; +} + +std::vector> SemanticContext::filterPrecedencePredicates(const Set &collection) { + std::vector> result; + for (auto context : collection) { + if (antlrcpp::is(context)) { + result.push_back(std::dynamic_pointer_cast(context)); + } + } + + return result; +} + + +//------------------ Operator ----------------------------------------------------------------------------------------- + +SemanticContext::Operator::~Operator() { +}