1 /* 2 * Copyright (c) 2012-2020 The ANTLR Project. All rights reserved. 3 * Use of this file is governed by the BSD 3-clause license that 4 * can be found in the LICENSE.txt file in the project root. 5 */ 6 7 module antlr.v4.runtime.atn.ProfilingATNSimulator; 8 9 import std.conv; 10 import std.datetime; 11 import std.algorithm; 12 import antlr.v4.runtime.atn.ATNConfigSet; 13 import antlr.v4.runtime.atn.ParserATNSimulator; 14 import antlr.v4.runtime.atn.DecisionInfo; 15 import antlr.v4.runtime.atn.ErrorInfo; 16 import antlr.v4.runtime.atn.PredicateEvalInfo; 17 import antlr.v4.runtime.atn.LookaheadEventInfo; 18 import antlr.v4.runtime.dfa.DFAState; 19 import antlr.v4.runtime.dfa.DFA; 20 import antlr.v4.runtime.Parser; 21 import antlr.v4.runtime.atn.SemanticContext; 22 import antlr.v4.runtime.TokenStream; 23 import antlr.v4.runtime.ParserRuleContext; 24 25 /** 26 * TODO add class description 27 */ 28 class ProfilingATNSimulator : ParserATNSimulator 29 { 30 31 protected DecisionInfo[] decisions; 32 33 protected int currentDecision; 34 35 protected int numDecisions; 36 37 protected size_t _sllStopIndex; 38 39 protected size_t _llStopIndex; 40 41 protected DFAState currentState; 42 43 /** 44 * we can determine whether or not a decision / input pair is context-sensitive. 45 * If LL gives a different result than SLL's predicted alternative, we have a 46 * context sensitivity for sure. The converse is not necessarily true, however. 47 * It's possible that after conflict resolution chooses minimum alternatives, 48 * SLL could get the same answer as LL. Regardless of whether or not the result indicates 49 * an ambiguity, it is not treated as a context sensitivity because LL prediction 50 * was not required in order to produce a correct prediction for this decision and input sequence. 51 * It may in fact still be a context sensitivity but we don't know by looking at the 52 * minimum alternatives for the current input. 53 */ 54 public int conflictingAltResolvedBySLL; 55 56 public this(Parser parser) 57 { 58 super(parser, 59 parser.getInterpreter().atn, 60 parser.getInterpreter().decisionToDFA, 61 parser.getInterpreter().sharedContextCache); 62 numDecisions = to!int(atn.decisionToState.length); 63 decisions = new DecisionInfo[numDecisions]; 64 for (int i=0; i<numDecisions; i++) { 65 decisions[i] = new DecisionInfo(i); 66 } 67 } 68 69 /** 70 * @uml 71 * @override 72 */ 73 public override int adaptivePredict(TokenStream input, int decision, ParserRuleContext outerContext) 74 { 75 try { 76 this._sllStopIndex = -1; 77 this._llStopIndex = -1; 78 this.currentDecision = decision; 79 auto start = MonoTime.currTime; // expensive but useful info 80 int alt = super.adaptivePredict(input, decision, outerContext); 81 auto stop = MonoTime.currTime; 82 decisions[decision].timeInPrediction += ticksToNSecs(stop.ticks - start.ticks); 83 decisions[decision].invocations++; 84 85 auto SLL_k = _sllStopIndex - _startIndex + 1; 86 decisions[decision].SLL_TotalLook += SLL_k; 87 decisions[decision].SLL_MinLook = decisions[decision].SLL_MinLook==0 ? SLL_k : min(decisions[decision].SLL_MinLook, SLL_k); 88 if ( SLL_k > decisions[decision].SLL_MaxLook ) { 89 decisions[decision].SLL_MaxLook = SLL_k; 90 decisions[decision].SLL_MaxLookEvent = 91 new LookaheadEventInfo(decision, null, alt, input, _startIndex, _sllStopIndex, false); 92 } 93 94 if (_llStopIndex >= 0) { 95 int LL_k = to!int(_llStopIndex - _startIndex) + 1; 96 decisions[decision].LL_TotalLook += LL_k; 97 decisions[decision].LL_MinLook = decisions[decision].LL_MinLook==0 ? LL_k : min(decisions[decision].LL_MinLook, LL_k); 98 if ( LL_k > decisions[decision].LL_MaxLook ) { 99 decisions[decision].LL_MaxLook = LL_k; 100 decisions[decision].LL_MaxLookEvent = 101 new LookaheadEventInfo(decision, null, alt, input, _startIndex, _llStopIndex, true); 102 } 103 } 104 105 return alt; 106 } 107 finally { 108 this.currentDecision = -1; 109 } 110 111 } 112 113 /** 114 * @uml 115 * @override 116 */ 117 public override DFAState getExistingTargetState(DFAState previousD, int t) 118 { 119 // this method is called after each time the input position advances 120 // during SLL prediction 121 _sllStopIndex = _input.index; 122 123 DFAState existingTargetState = super.getExistingTargetState(previousD, t); 124 if (existingTargetState !is null) { 125 decisions[currentDecision].SLL_DFATransitions++; // count only if we transition over a DFA state 126 if ( existingTargetState==ERROR ) { 127 decisions[currentDecision].errors 128 ~= new ErrorInfo(currentDecision, previousD.configs, _input, _startIndex, _sllStopIndex, false); 129 } 130 } 131 132 currentState = existingTargetState; 133 return existingTargetState; 134 135 } 136 137 /** 138 * @uml 139 * @override 140 */ 141 protected override DFAState computeTargetState(DFA dfa, DFAState previousD, int t) 142 { 143 DFAState state = super.computeTargetState(dfa, previousD, t); 144 currentState = state; 145 return state; 146 } 147 148 /** 149 * @uml 150 * @override 151 */ 152 protected override ATNConfigSet computeReachSet(ATNConfigSet closure, int t, bool fullCtx) 153 { 154 if (fullCtx) { 155 // this method is called after each time the input position advances 156 // during full context prediction 157 _llStopIndex = _input.index(); 158 } 159 160 ATNConfigSet reachConfigs = super.computeReachSet(closure, t, fullCtx); 161 if (fullCtx) { 162 decisions[currentDecision].LL_ATNTransitions++; // count computation even if error 163 if (reachConfigs !is null) { 164 } 165 else { // no reach on current lookahead symbol. ERROR. 166 // TODO: does not handle delayed errors per getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule() 167 decisions[currentDecision].errors 168 ~= new ErrorInfo(currentDecision, closure, _input, _startIndex, _llStopIndex, true); 169 } 170 } 171 else { 172 decisions[currentDecision].SLL_ATNTransitions++; 173 if (reachConfigs !is null) { 174 } 175 else { // no reach on current lookahead symbol. ERROR. 176 decisions[currentDecision].errors 177 ~= new ErrorInfo(currentDecision, closure, _input, _startIndex, _sllStopIndex, false); 178 } 179 } 180 return reachConfigs; 181 182 } 183 184 /** 185 * @uml 186 * @override 187 */ 188 protected override bool evalSemanticContext(SemanticContext pred, ParserRuleContext parserCallStack, 189 int alt, bool fullCtx) 190 { 191 bool result = super.evalSemanticContext(pred, parserCallStack, alt, fullCtx); 192 if (pred.classinfo != SemanticContext.PrecedencePredicate.classinfo) { 193 bool fullContext = _llStopIndex >= 0; 194 auto stopIndex = fullContext ? _llStopIndex : _sllStopIndex; 195 decisions[currentDecision].predicateEvals 196 ~= new PredicateEvalInfo(currentDecision, _input, _startIndex, stopIndex, pred, result, alt, fullCtx); 197 } 198 return result; 199 } 200 201 public DecisionInfo[] getDecisionInfo() 202 { 203 return decisions; 204 } 205 206 }