| /* 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/PredicateEvalInfo.h" |
| #include "atn/LookaheadEventInfo.h" |
| #include "Parser.h" |
| #include "atn/ATNConfigSet.h" |
| #include "support/CPPUtils.h" |
| |
| #include "atn/ProfilingATNSimulator.h" |
| |
| using namespace antlr4; |
| using namespace antlr4::atn; |
| using namespace antlr4::dfa; |
| using namespace antlrcpp; |
| |
| using namespace std::chrono; |
| |
| ProfilingATNSimulator::ProfilingATNSimulator(Parser *parser) |
| : ParserATNSimulator(parser, parser->getInterpreter<ParserATNSimulator>()->atn, |
| parser->getInterpreter<ParserATNSimulator>()->decisionToDFA, |
| parser->getInterpreter<ParserATNSimulator>()->getSharedContextCache()) { |
| for (size_t i = 0; i < atn.decisionToState.size(); i++) { |
| _decisions.push_back(DecisionInfo(i)); |
| } |
| } |
| |
| size_t ProfilingATNSimulator::adaptivePredict(TokenStream *input, size_t decision, ParserRuleContext *outerContext) { |
| auto onExit = finally([this](){ |
| _currentDecision = 0; // Originally -1, but that makes no sense (index into a vector and init value is also 0). |
| }); |
| |
| _sllStopIndex = -1; |
| _llStopIndex = -1; |
| _currentDecision = decision; |
| high_resolution_clock::time_point start = high_resolution_clock::now(); |
| size_t alt = ParserATNSimulator::adaptivePredict(input, decision, outerContext); |
| high_resolution_clock::time_point stop = high_resolution_clock::now(); |
| _decisions[decision].timeInPrediction += duration_cast<nanoseconds>(stop - start).count(); |
| _decisions[decision].invocations++; |
| |
| long long SLL_k = _sllStopIndex - _startIndex + 1; |
| _decisions[decision].SLL_TotalLook += SLL_k; |
| _decisions[decision].SLL_MinLook = _decisions[decision].SLL_MinLook == 0 ? SLL_k : std::min(_decisions[decision].SLL_MinLook, SLL_k); |
| if (SLL_k > _decisions[decision].SLL_MaxLook) { |
| _decisions[decision].SLL_MaxLook = SLL_k; |
| _decisions[decision].SLL_MaxLookEvent = std::make_shared<LookaheadEventInfo>(decision, nullptr, alt, input, _startIndex, _sllStopIndex, false); |
| } |
| |
| if (_llStopIndex >= 0) { |
| long long LL_k = _llStopIndex - _startIndex + 1; |
| _decisions[decision].LL_TotalLook += LL_k; |
| _decisions[decision].LL_MinLook = _decisions[decision].LL_MinLook == 0 ? LL_k : std::min(_decisions[decision].LL_MinLook, LL_k); |
| if (LL_k > _decisions[decision].LL_MaxLook) { |
| _decisions[decision].LL_MaxLook = LL_k; |
| _decisions[decision].LL_MaxLookEvent = std::make_shared<LookaheadEventInfo>(decision, nullptr, alt, input, _startIndex, _llStopIndex, true); |
| } |
| } |
| |
| return alt; |
| } |
| |
| DFAState* ProfilingATNSimulator::getExistingTargetState(DFAState *previousD, size_t t) { |
| // this method is called after each time the input position advances |
| // during SLL prediction |
| _sllStopIndex = (int)_input->index(); |
| |
| DFAState *existingTargetState = ParserATNSimulator::getExistingTargetState(previousD, t); |
| if (existingTargetState != nullptr) { |
| _decisions[_currentDecision].SLL_DFATransitions++; // count only if we transition over a DFA state |
| if (existingTargetState == ERROR.get()) { |
| _decisions[_currentDecision].errors.push_back( |
| ErrorInfo(_currentDecision, previousD->configs.get(), _input, _startIndex, _sllStopIndex, false) |
| ); |
| } |
| } |
| |
| _currentState = existingTargetState; |
| return existingTargetState; |
| } |
| |
| DFAState* ProfilingATNSimulator::computeTargetState(DFA &dfa, DFAState *previousD, size_t t) { |
| DFAState *state = ParserATNSimulator::computeTargetState(dfa, previousD, t); |
| _currentState = state; |
| return state; |
| } |
| |
| std::unique_ptr<ATNConfigSet> ProfilingATNSimulator::computeReachSet(ATNConfigSet *closure, size_t t, bool fullCtx) { |
| if (fullCtx) { |
| // this method is called after each time the input position advances |
| // during full context prediction |
| _llStopIndex = (int)_input->index(); |
| } |
| |
| std::unique_ptr<ATNConfigSet> reachConfigs = ParserATNSimulator::computeReachSet(closure, t, fullCtx); |
| if (fullCtx) { |
| _decisions[_currentDecision].LL_ATNTransitions++; // count computation even if error |
| if (reachConfigs != nullptr) { |
| } else { // no reach on current lookahead symbol. ERROR. |
| // TODO: does not handle delayed errors per getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule() |
| _decisions[_currentDecision].errors.push_back(ErrorInfo(_currentDecision, closure, _input, _startIndex, _llStopIndex, true)); |
| } |
| } else { |
| ++_decisions[_currentDecision].SLL_ATNTransitions; |
| if (reachConfigs != nullptr) { |
| } else { // no reach on current lookahead symbol. ERROR. |
| _decisions[_currentDecision].errors.push_back(ErrorInfo(_currentDecision, closure, _input, _startIndex, _sllStopIndex, false)); |
| } |
| } |
| return reachConfigs; |
| } |
| |
| bool ProfilingATNSimulator::evalSemanticContext(Ref<SemanticContext> const& pred, ParserRuleContext *parserCallStack, |
| size_t alt, bool fullCtx) { |
| bool result = ParserATNSimulator::evalSemanticContext(pred, parserCallStack, alt, fullCtx); |
| if (!(std::dynamic_pointer_cast<SemanticContext::PrecedencePredicate>(pred) != nullptr)) { |
| bool fullContext = _llStopIndex >= 0; |
| int stopIndex = fullContext ? _llStopIndex : _sllStopIndex; |
| _decisions[_currentDecision].predicateEvals.push_back( |
| PredicateEvalInfo(_currentDecision, _input, _startIndex, stopIndex, pred, result, alt, fullCtx)); |
| } |
| |
| return result; |
| } |
| |
| void ProfilingATNSimulator::reportAttemptingFullContext(DFA &dfa, const BitSet &conflictingAlts, ATNConfigSet *configs, |
| size_t startIndex, size_t stopIndex) { |
| if (conflictingAlts.count() > 0) { |
| conflictingAltResolvedBySLL = conflictingAlts.nextSetBit(0); |
| } else { |
| conflictingAltResolvedBySLL = configs->getAlts().nextSetBit(0); |
| } |
| _decisions[_currentDecision].LL_Fallback++; |
| ParserATNSimulator::reportAttemptingFullContext(dfa, conflictingAlts, configs, startIndex, stopIndex); |
| } |
| |
| void ProfilingATNSimulator::reportContextSensitivity(DFA &dfa, size_t prediction, ATNConfigSet *configs, |
| size_t startIndex, size_t stopIndex) { |
| if (prediction != conflictingAltResolvedBySLL) { |
| _decisions[_currentDecision].contextSensitivities.push_back( |
| ContextSensitivityInfo(_currentDecision, configs, _input, startIndex, stopIndex) |
| ); |
| } |
| ParserATNSimulator::reportContextSensitivity(dfa, prediction, configs, startIndex, stopIndex); |
| } |
| |
| void ProfilingATNSimulator::reportAmbiguity(DFA &dfa, DFAState *D, size_t startIndex, size_t stopIndex, bool exact, |
| const BitSet &ambigAlts, ATNConfigSet *configs) { |
| size_t prediction; |
| if (ambigAlts.count() > 0) { |
| prediction = ambigAlts.nextSetBit(0); |
| } else { |
| prediction = configs->getAlts().nextSetBit(0); |
| } |
| if (configs->fullCtx && prediction != conflictingAltResolvedBySLL) { |
| // Even though this is an ambiguity we are reporting, we can |
| // still detect some context sensitivities. Both SLL and LL |
| // are showing a conflict, hence an ambiguity, but if they resolve |
| // to different minimum alternatives we have also identified a |
| // context sensitivity. |
| _decisions[_currentDecision].contextSensitivities.push_back( |
| ContextSensitivityInfo(_currentDecision, configs, _input, startIndex, stopIndex) |
| ); |
| } |
| _decisions[_currentDecision].ambiguities.push_back( |
| AmbiguityInfo(_currentDecision, configs, ambigAlts, _input, startIndex, stopIndex, configs->fullCtx) |
| ); |
| ParserATNSimulator::reportAmbiguity(dfa, D, startIndex, stopIndex, exact, ambigAlts, configs); |
| } |
| |
| std::vector<DecisionInfo> ProfilingATNSimulator::getDecisionInfo() const { |
| return _decisions; |
| } |
| |
| DFAState* ProfilingATNSimulator::getCurrentState() const { |
| return _currentState; |
| } |