diff options
Diffstat (limited to 'antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/Profiler.java')
-rw-r--r-- | antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/Profiler.java | 734 |
1 files changed, 734 insertions, 0 deletions
diff --git a/antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/Profiler.java b/antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/Profiler.java new file mode 100644 index 0000000..aea9a17 --- /dev/null +++ b/antlr-3.4/runtime/Java/src/main/java/org/antlr/runtime/debug/Profiler.java @@ -0,0 +1,734 @@ +/* + [The "BSD license"] + Copyright (c) 2005-2009 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.antlr.runtime.debug; + +import org.antlr.runtime.*; +import org.antlr.runtime.misc.DoubleKeyMap; + +import java.util.*; + +/** Using the debug event interface, track what is happening in the parser + * and record statistics about the runtime. + */ +public class Profiler extends BlankDebugEventListener { + public static final String DATA_SEP = "\t"; + public static final String newline = System.getProperty("line.separator"); + + static boolean dump = false; + + public static class ProfileStats { + public String Version; + public String name; + public int numRuleInvocations; + public int numUniqueRulesInvoked; + public int numDecisionEvents; + public int numDecisionsCovered; + public int numDecisionsThatPotentiallyBacktrack; + public int numDecisionsThatDoBacktrack; + public int maxRuleInvocationDepth; + public float avgkPerDecisionEvent; + public float avgkPerBacktrackingDecisionEvent; + public float averageDecisionPercentBacktracks; + public int numBacktrackOccurrences; // doesn't count gated DFA edges + + public int numFixedDecisions; + public int minDecisionMaxFixedLookaheads; + public int maxDecisionMaxFixedLookaheads; + public int avgDecisionMaxFixedLookaheads; + public int stddevDecisionMaxFixedLookaheads; + public int numCyclicDecisions; + public int minDecisionMaxCyclicLookaheads; + public int maxDecisionMaxCyclicLookaheads; + public int avgDecisionMaxCyclicLookaheads; + public int stddevDecisionMaxCyclicLookaheads; +// int Stats.min(toArray(decisionMaxSynPredLookaheads); +// int Stats.max(toArray(decisionMaxSynPredLookaheads); +// int Stats.avg(toArray(decisionMaxSynPredLookaheads); +// int Stats.stddev(toArray(decisionMaxSynPredLookaheads); + public int numSemanticPredicates; + public int numTokens; + public int numHiddenTokens; + public int numCharsMatched; + public int numHiddenCharsMatched; + public int numReportedErrors; + public int numMemoizationCacheHits; + public int numMemoizationCacheMisses; + public int numGuessingRuleInvocations; + public int numMemoizationCacheEntries; + } + + public static class DecisionDescriptor { + public int decision; + public String fileName; + public String ruleName; + public int line; + public int pos; + public boolean couldBacktrack; + + public int n; + public float avgk; // avg across all decision events + public int maxk; + public int numBacktrackOccurrences; + public int numSemPredEvals; + } + + // all about a specific exec of a single decision + public static class DecisionEvent { + public DecisionDescriptor decision; + public int startIndex; + public int k; + public boolean backtracks; // doesn't count gated DFA edges + public boolean evalSemPred; + public long startTime; + public long stopTime; + public int numMemoizationCacheHits; + public int numMemoizationCacheMisses; + } + + /** Because I may change the stats, I need to track that for later + * computations to be consistent. + */ + public static final String Version = "3"; + public static final String RUNTIME_STATS_FILENAME = "runtime.stats"; + + /** Ack, should not store parser; can't do remote stuff. Well, we pass + * input stream around too so I guess it's ok. + */ + public DebugParser parser = null; + + // working variables + + protected int ruleLevel = 0; + //protected int decisionLevel = 0; + protected Token lastRealTokenTouchedInDecision; + protected Set<String> uniqueRules = new HashSet<String>(); + protected Stack<String> currentGrammarFileName = new Stack(); + protected Stack<String> currentRuleName = new Stack(); + protected Stack<Integer> currentLine = new Stack(); + protected Stack<Integer> currentPos = new Stack(); + + // Vector<DecisionStats> + //protected Vector decisions = new Vector(200); // need setSize + protected DoubleKeyMap<String,Integer, DecisionDescriptor> decisions = + new DoubleKeyMap<String,Integer, DecisionDescriptor>(); + + // Record a DecisionData for each decision we hit while parsing + protected List<DecisionEvent> decisionEvents = new ArrayList<DecisionEvent>(); + protected Stack<DecisionEvent> decisionStack = new Stack<DecisionEvent>(); + + protected int backtrackDepth; + + ProfileStats stats = new ProfileStats(); + + public Profiler() { + } + + public Profiler(DebugParser parser) { + this.parser = parser; + } + + public void enterRule(String grammarFileName, String ruleName) { +// System.out.println("enterRule "+grammarFileName+":"+ruleName); + ruleLevel++; + stats.numRuleInvocations++; + uniqueRules.add(grammarFileName+":"+ruleName); + stats.maxRuleInvocationDepth = Math.max(stats.maxRuleInvocationDepth, ruleLevel); + currentGrammarFileName.push( grammarFileName ); + currentRuleName.push( ruleName ); + } + + public void exitRule(String grammarFileName, String ruleName) { + ruleLevel--; + currentGrammarFileName.pop(); + currentRuleName.pop(); + } + + /** Track memoization; this is not part of standard debug interface + * but is triggered by profiling. Code gen inserts an override + * for this method in the recognizer, which triggers this method. + * Called from alreadyParsedRule(). + */ + public void examineRuleMemoization(IntStream input, + int ruleIndex, + int stopIndex, // index or MEMO_RULE_UNKNOWN... + String ruleName) + { + if (dump) System.out.println("examine memo "+ruleName+" at "+input.index()+": "+stopIndex); + if ( stopIndex==BaseRecognizer.MEMO_RULE_UNKNOWN ) { + //System.out.println("rule "+ruleIndex+" missed @ "+input.index()); + stats.numMemoizationCacheMisses++; + stats.numGuessingRuleInvocations++; // we'll have to enter + currentDecision().numMemoizationCacheMisses++; + } + else { + // regardless of rule success/failure, if in cache, we have a cache hit + //System.out.println("rule "+ruleIndex+" hit @ "+input.index()); + stats.numMemoizationCacheHits++; + currentDecision().numMemoizationCacheHits++; + } + } + + /** Warning: doesn't track success/failure, just unique recording event */ + public void memoize(IntStream input, + int ruleIndex, + int ruleStartIndex, + String ruleName) + { + // count how many entries go into table + if (dump) System.out.println("memoize "+ruleName); + stats.numMemoizationCacheEntries++; + } + + @Override + public void location(int line, int pos) { + currentLine.push(line); + currentPos.push(pos); + } + + public void enterDecision(int decisionNumber, boolean couldBacktrack) { + lastRealTokenTouchedInDecision = null; + stats.numDecisionEvents++; + int startingLookaheadIndex = parser.getTokenStream().index(); + TokenStream input = parser.getTokenStream(); + if ( dump ) System.out.println("enterDecision canBacktrack="+couldBacktrack+" "+ decisionNumber + + " backtrack depth " + backtrackDepth + + " @ " + input.get(input.index()) + + " rule " +locationDescription()); + String g = (String) currentGrammarFileName.peek(); + DecisionDescriptor descriptor = decisions.get(g, decisionNumber); + if ( descriptor == null ) { + descriptor = new DecisionDescriptor(); + decisions.put(g, decisionNumber, descriptor); + descriptor.decision = decisionNumber; + descriptor.fileName = (String)currentGrammarFileName.peek(); + descriptor.ruleName = (String)currentRuleName.peek(); + descriptor.line = (Integer)currentLine.peek(); + descriptor.pos = (Integer)currentPos.peek(); + descriptor.couldBacktrack = couldBacktrack; + } + descriptor.n++; + + DecisionEvent d = new DecisionEvent(); + decisionStack.push(d); + d.decision = descriptor; + d.startTime = System.currentTimeMillis(); + d.startIndex = startingLookaheadIndex; + } + + public void exitDecision(int decisionNumber) { + DecisionEvent d = decisionStack.pop(); + d.stopTime = System.currentTimeMillis(); + + int lastTokenIndex = lastRealTokenTouchedInDecision.getTokenIndex(); + int numHidden = getNumberOfHiddenTokens(d.startIndex, lastTokenIndex); + int depth = lastTokenIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1 + d.k = depth; + d.decision.maxk = Math.max(d.decision.maxk, depth); + + if (dump) System.out.println("exitDecision "+decisionNumber+" in "+d.decision.ruleName+ + " lookahead "+d.k +" max token "+lastRealTokenTouchedInDecision); + decisionEvents.add(d); // done with decision; track all + } + + public void consumeToken(Token token) { + if (dump) System.out.println("consume token "+token); + if ( !inDecision() ) { + stats.numTokens++; + return; + } + if ( lastRealTokenTouchedInDecision==null || + lastRealTokenTouchedInDecision.getTokenIndex() < token.getTokenIndex() ) + { + lastRealTokenTouchedInDecision = token; + } + DecisionEvent d = currentDecision(); + // compute lookahead depth + int thisRefIndex = token.getTokenIndex(); + int numHidden = getNumberOfHiddenTokens(d.startIndex, thisRefIndex); + int depth = thisRefIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1 + //d.maxk = Math.max(d.maxk, depth); + if (dump) System.out.println("consume "+thisRefIndex+" "+depth+" tokens ahead in "+ + d.decision.ruleName+"-"+d.decision.decision+" start index "+d.startIndex); + } + + /** The parser is in a decision if the decision depth > 0. This + * works for backtracking also, which can have nested decisions. + */ + public boolean inDecision() { + return decisionStack.size()>0; + } + + public void consumeHiddenToken(Token token) { + //System.out.println("consume hidden token "+token); + if ( !inDecision() ) stats.numHiddenTokens++; + } + + /** Track refs to lookahead if in a fixed/nonfixed decision. + */ + public void LT(int i, Token t) { + if ( inDecision() && i>0 ) { + DecisionEvent d = currentDecision(); + if (dump) System.out.println("LT("+i+")="+t+" index "+t.getTokenIndex()+" relative to "+d.decision.ruleName+"-"+ + d.decision.decision+" start index "+d.startIndex); + if ( lastRealTokenTouchedInDecision==null || + lastRealTokenTouchedInDecision.getTokenIndex() < t.getTokenIndex() ) + { + lastRealTokenTouchedInDecision = t; + if (dump) System.out.println("set last token "+lastRealTokenTouchedInDecision); + } + // get starting index off stack +// int stackTop = lookaheadStack.size()-1; +// Integer startingIndex = (Integer)lookaheadStack.get(stackTop); +// // compute lookahead depth +// int thisRefIndex = parser.getTokenStream().index(); +// int numHidden = +// getNumberOfHiddenTokens(startingIndex.intValue(), thisRefIndex); +// int depth = i + thisRefIndex - startingIndex.intValue() - numHidden; +// /* +// System.out.println("LT("+i+") @ index "+thisRefIndex+" is depth "+depth+ +// " max is "+maxLookaheadInCurrentDecision); +// */ +// if ( depth>maxLookaheadInCurrentDecision ) { +// maxLookaheadInCurrentDecision = depth; +// } +// d.maxk = currentDecision()/ + } + } + + /** Track backtracking decisions. You'll see a fixed or cyclic decision + * and then a backtrack. + * + * enter rule + * ... + * enter decision + * LA and possibly consumes (for cyclic DFAs) + * begin backtrack level + * mark m + * rewind m + * end backtrack level, success + * exit decision + * ... + * exit rule + */ + public void beginBacktrack(int level) { + if (dump) System.out.println("enter backtrack "+level); + backtrackDepth++; + DecisionEvent e = currentDecision(); + if ( e.decision.couldBacktrack ) { + stats.numBacktrackOccurrences++; + e.decision.numBacktrackOccurrences++; + e.backtracks = true; + } + } + + /** Successful or not, track how much lookahead synpreds use */ + public void endBacktrack(int level, boolean successful) { + if (dump) System.out.println("exit backtrack "+level+": "+successful); + backtrackDepth--; + } + + @Override + public void mark(int i) { + if (dump) System.out.println("mark "+i); + } + + @Override + public void rewind(int i) { + if (dump) System.out.println("rewind "+i); + } + + @Override + public void rewind() { + if (dump) System.out.println("rewind"); + } + + + + protected DecisionEvent currentDecision() { + return decisionStack.peek(); + } + + public void recognitionException(RecognitionException e) { + stats.numReportedErrors++; + } + + public void semanticPredicate(boolean result, String predicate) { + stats.numSemanticPredicates++; + if ( inDecision() ) { + DecisionEvent d = currentDecision(); + d.evalSemPred = true; + d.decision.numSemPredEvals++; + if (dump) System.out.println("eval "+predicate+" in "+d.decision.ruleName+"-"+ + d.decision.decision); + } + } + + public void terminate() { + for (DecisionEvent e : decisionEvents) { + //System.out.println("decision "+e.decision.decision+": k="+e.k); + e.decision.avgk += e.k; + stats.avgkPerDecisionEvent += e.k; + if ( e.backtracks ) { // doesn't count gated syn preds on DFA edges + stats.avgkPerBacktrackingDecisionEvent += e.k; + } + } + stats.averageDecisionPercentBacktracks = 0.0f; + for (DecisionDescriptor d : decisions.values()) { + stats.numDecisionsCovered++; + d.avgk /= (double)d.n; + if ( d.couldBacktrack ) { + stats.numDecisionsThatPotentiallyBacktrack++; + float percentBacktracks = d.numBacktrackOccurrences / (float)d.n; + //System.out.println("dec "+d.decision+" backtracks "+percentBacktracks*100+"%"); + stats.averageDecisionPercentBacktracks += percentBacktracks; + } + // ignore rules that backtrack along gated DFA edges + if ( d.numBacktrackOccurrences > 0 ) { + stats.numDecisionsThatDoBacktrack++; + } + } + stats.averageDecisionPercentBacktracks /= stats.numDecisionsThatPotentiallyBacktrack; + stats.averageDecisionPercentBacktracks *= 100; // it's a percentage + stats.avgkPerDecisionEvent /= stats.numDecisionEvents; + stats.avgkPerBacktrackingDecisionEvent /= (double)stats.numBacktrackOccurrences; + + System.err.println(toString()); + System.err.println(getDecisionStatsDump()); + +// String stats = toNotifyString(); +// try { +// Stats.writeReport(RUNTIME_STATS_FILENAME,stats); +// } +// catch (IOException ioe) { +// System.err.println(ioe); +// ioe.printStackTrace(System.err); +// } + } + + public void setParser(DebugParser parser) { + this.parser = parser; + } + + // R E P O R T I N G + + public String toNotifyString() { + StringBuffer buf = new StringBuffer(); + buf.append(Version); + buf.append('\t'); + buf.append(parser.getClass().getName()); +// buf.append('\t'); +// buf.append(numRuleInvocations); +// buf.append('\t'); +// buf.append(maxRuleInvocationDepth); +// buf.append('\t'); +// buf.append(numFixedDecisions); +// buf.append('\t'); +// buf.append(Stats.min(decisionMaxFixedLookaheads)); +// buf.append('\t'); +// buf.append(Stats.max(decisionMaxFixedLookaheads)); +// buf.append('\t'); +// buf.append(Stats.avg(decisionMaxFixedLookaheads)); +// buf.append('\t'); +// buf.append(Stats.stddev(decisionMaxFixedLookaheads)); +// buf.append('\t'); +// buf.append(numCyclicDecisions); +// buf.append('\t'); +// buf.append(Stats.min(decisionMaxCyclicLookaheads)); +// buf.append('\t'); +// buf.append(Stats.max(decisionMaxCyclicLookaheads)); +// buf.append('\t'); +// buf.append(Stats.avg(decisionMaxCyclicLookaheads)); +// buf.append('\t'); +// buf.append(Stats.stddev(decisionMaxCyclicLookaheads)); +// buf.append('\t'); +// buf.append(numBacktrackDecisions); +// buf.append('\t'); +// buf.append(Stats.min(toArray(decisionMaxSynPredLookaheads))); +// buf.append('\t'); +// buf.append(Stats.max(toArray(decisionMaxSynPredLookaheads))); +// buf.append('\t'); +// buf.append(Stats.avg(toArray(decisionMaxSynPredLookaheads))); +// buf.append('\t'); +// buf.append(Stats.stddev(toArray(decisionMaxSynPredLookaheads))); +// buf.append('\t'); +// buf.append(numSemanticPredicates); +// buf.append('\t'); +// buf.append(parser.getTokenStream().size()); +// buf.append('\t'); +// buf.append(numHiddenTokens); +// buf.append('\t'); +// buf.append(numCharsMatched); +// buf.append('\t'); +// buf.append(numHiddenCharsMatched); +// buf.append('\t'); +// buf.append(numberReportedErrors); +// buf.append('\t'); +// buf.append(numMemoizationCacheHits); +// buf.append('\t'); +// buf.append(numMemoizationCacheMisses); +// buf.append('\t'); +// buf.append(numGuessingRuleInvocations); +// buf.append('\t'); +// buf.append(numMemoizationCacheEntries); + return buf.toString(); + } + + public String toString() { + return toString(getReport()); + } + + public ProfileStats getReport() { +// TokenStream input = parser.getTokenStream(); +// for (int i=0; i<input.size()&& lastRealTokenTouchedInDecision !=null&&i<= lastRealTokenTouchedInDecision.getTokenIndex(); i++) { +// Token t = input.get(i); +// if ( t.getChannel()!=Token.DEFAULT_CHANNEL ) { +// stats.numHiddenTokens++; +// stats.numHiddenCharsMatched += t.getText().length(); +// } +// } + stats.Version = Version; + stats.name = parser.getClass().getName(); + stats.numUniqueRulesInvoked = uniqueRules.size(); + //stats.numCharsMatched = lastTokenConsumed.getStopIndex() + 1; + return stats; + } + + public DoubleKeyMap getDecisionStats() { + return decisions; + } + + public List getDecisionEvents() { + return decisionEvents; + } + + public static String toString(ProfileStats stats) { + StringBuffer buf = new StringBuffer(); + buf.append("ANTLR Runtime Report; Profile Version "); + buf.append(stats.Version); + buf.append(newline); + buf.append("parser name "); + buf.append(stats.name); + buf.append(newline); + buf.append("Number of rule invocations "); + buf.append(stats.numRuleInvocations); + buf.append(newline); + buf.append("Number of unique rules visited "); + buf.append(stats.numUniqueRulesInvoked); + buf.append(newline); + buf.append("Number of decision events "); + buf.append(stats.numDecisionEvents); + buf.append(newline); + buf.append("Overall average k per decision event "); + buf.append(stats.avgkPerDecisionEvent); + buf.append(newline); + buf.append("Number of backtracking occurrences (can be multiple per decision) "); + buf.append(stats.numBacktrackOccurrences); + buf.append(newline); + buf.append("Overall average k per decision event that backtracks "); + buf.append(stats.avgkPerBacktrackingDecisionEvent); + buf.append(newline); + buf.append("Number of rule invocations while backtracking "); + buf.append(stats.numGuessingRuleInvocations); + buf.append(newline); + buf.append("num decisions that potentially backtrack "); + buf.append(stats.numDecisionsThatPotentiallyBacktrack); + buf.append(newline); + buf.append("num decisions that do backtrack "); + buf.append(stats.numDecisionsThatDoBacktrack); + buf.append(newline); + buf.append("num decisions that potentially backtrack but don't "); + buf.append(stats.numDecisionsThatPotentiallyBacktrack - stats.numDecisionsThatDoBacktrack); + buf.append(newline); + buf.append("average % of time a potentially backtracking decision backtracks "); + buf.append(stats.averageDecisionPercentBacktracks); + buf.append(newline); + buf.append("num unique decisions covered "); + buf.append(stats.numDecisionsCovered); + buf.append(newline); + buf.append("max rule invocation nesting depth "); + buf.append(stats.maxRuleInvocationDepth); + buf.append(newline); + +// buf.append("number of fixed lookahead decisions "); +// buf.append(); +// buf.append('\n'); +// buf.append("min lookahead used in a fixed lookahead decision "); +// buf.append(); +// buf.append('\n'); +// buf.append("max lookahead used in a fixed lookahead decision "); +// buf.append(); +// buf.append('\n'); +// buf.append("average lookahead depth used in fixed lookahead decisions "); +// buf.append(); +// buf.append('\n'); +// buf.append("standard deviation of depth used in fixed lookahead decisions "); +// buf.append(); +// buf.append('\n'); +// buf.append("number of arbitrary lookahead decisions "); +// buf.append(); +// buf.append('\n'); +// buf.append("min lookahead used in an arbitrary lookahead decision "); +// buf.append(); +// buf.append('\n'); +// buf.append("max lookahead used in an arbitrary lookahead decision "); +// buf.append(); +// buf.append('\n'); +// buf.append("average lookahead depth used in arbitrary lookahead decisions "); +// buf.append(); +// buf.append('\n'); +// buf.append("standard deviation of depth used in arbitrary lookahead decisions "); +// buf.append(); +// buf.append('\n'); +// buf.append("number of evaluated syntactic predicates "); +// buf.append(); +// buf.append('\n'); +// buf.append("min lookahead used in a syntactic predicate "); +// buf.append(); +// buf.append('\n'); +// buf.append("max lookahead used in a syntactic predicate "); +// buf.append(); +// buf.append('\n'); +// buf.append("average lookahead depth used in syntactic predicates "); +// buf.append(); +// buf.append('\n'); +// buf.append("standard deviation of depth used in syntactic predicates "); +// buf.append(); +// buf.append('\n'); + buf.append("rule memoization cache size "); + buf.append(stats.numMemoizationCacheEntries); + buf.append(newline); + buf.append("number of rule memoization cache hits "); + buf.append(stats.numMemoizationCacheHits); + buf.append(newline); + buf.append("number of rule memoization cache misses "); + buf.append(stats.numMemoizationCacheMisses); + buf.append(newline); +// buf.append("number of evaluated semantic predicates "); +// buf.append(); +// buf.append(newline); + buf.append("number of tokens "); + buf.append(stats.numTokens); + buf.append(newline); + buf.append("number of hidden tokens "); + buf.append(stats.numHiddenTokens); + buf.append(newline); + buf.append("number of char "); + buf.append(stats.numCharsMatched); + buf.append(newline); + buf.append("number of hidden char "); + buf.append(stats.numHiddenCharsMatched); + buf.append(newline); + buf.append("number of syntax errors "); + buf.append(stats.numReportedErrors); + buf.append(newline); + return buf.toString(); + } + + public String getDecisionStatsDump() { + StringBuffer buf = new StringBuffer(); + buf.append("location"); + buf.append(DATA_SEP); + buf.append("n"); + buf.append(DATA_SEP); + buf.append("avgk"); + buf.append(DATA_SEP); + buf.append("maxk"); + buf.append(DATA_SEP); + buf.append("synpred"); + buf.append(DATA_SEP); + buf.append("sempred"); + buf.append(DATA_SEP); + buf.append("canbacktrack"); + buf.append("\n"); + for (String fileName : decisions.keySet()) { + for (int d : decisions.keySet(fileName)) { + DecisionDescriptor s = decisions.get(fileName, d); + buf.append(s.decision); + buf.append("@"); + buf.append(locationDescription(s.fileName,s.ruleName,s.line,s.pos)); // decision number + buf.append(DATA_SEP); + buf.append(s.n); + buf.append(DATA_SEP); + buf.append(String.format("%.2f",s.avgk)); + buf.append(DATA_SEP); + buf.append(s.maxk); + buf.append(DATA_SEP); + buf.append(s.numBacktrackOccurrences); + buf.append(DATA_SEP); + buf.append(s.numSemPredEvals); + buf.append(DATA_SEP); + buf.append(s.couldBacktrack ?"1":"0"); + buf.append(newline); + } + } + return buf.toString(); + } + + protected int[] trim(int[] X, int n) { + if ( n<X.length ) { + int[] trimmed = new int[n]; + System.arraycopy(X,0,trimmed,0,n); + X = trimmed; + } + return X; + } + + protected int[] toArray(List a) { + int[] x = new int[a.size()]; + for (int i = 0; i < a.size(); i++) { + Integer I = (Integer) a.get(i); + x[i] = I.intValue(); + } + return x; + } + + /** Get num hidden tokens between i..j inclusive */ + public int getNumberOfHiddenTokens(int i, int j) { + int n = 0; + TokenStream input = parser.getTokenStream(); + for (int ti = i; ti<input.size() && ti <= j; ti++) { + Token t = input.get(ti); + if ( t.getChannel()!=Token.DEFAULT_CHANNEL ) { + n++; + } + } + return n; + } + + protected String locationDescription() { + return locationDescription( + currentGrammarFileName.peek(), + currentRuleName.peek(), + currentLine.peek(), + currentPos.peek()); + } + + protected String locationDescription(String file, String rule, int line, int pos) { + return file+":"+line+":"+pos+"(" + rule + ")"; + } +} |