forked from jasder/antlr
crap; was messing with lexers but anyway just added depth back to closure
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 6915]
This commit is contained in:
parent
0e4fbf903d
commit
6414fa00c6
|
@ -319,9 +319,9 @@ public class <lexerName> extends Lexer {
|
|||
|
||||
<namedActions.members>
|
||||
|
||||
<dfas>
|
||||
<actions>
|
||||
<sempreds>
|
||||
<dfas>
|
||||
<pdas>
|
||||
}
|
||||
>>
|
||||
|
|
|
@ -2,8 +2,17 @@ package org.antlr.v4.analysis;
|
|||
|
||||
import org.antlr.v4.automata.DFA;
|
||||
import org.antlr.v4.automata.DecisionState;
|
||||
import org.antlr.v4.tool.Grammar;
|
||||
import org.antlr.v4.tool.LexerGrammar;
|
||||
import org.antlr.v4.automata.NFA;
|
||||
import org.antlr.v4.misc.BitSet;
|
||||
import org.antlr.v4.misc.IntervalSet;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.antlr.v4.semantics.UseDefAnalyzer;
|
||||
import org.antlr.v4.tool.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class AnalysisPipeline {
|
||||
public Grammar g;
|
||||
|
@ -26,6 +35,9 @@ public class AnalysisPipeline {
|
|||
void processLexer() {
|
||||
LexerGrammar lg = (LexerGrammar)g;
|
||||
for (String modeName : lg.modes.keySet()) {
|
||||
|
||||
Set<Rule> rulesInNFA = getRulesInNFA(lg, modeName);
|
||||
|
||||
LexerNFAToDFAConverter conv = new LexerNFAToDFAConverter(lg);
|
||||
DFA dfa = conv.createDFA(modeName);
|
||||
lg.modeToDFA.put(modeName, dfa);
|
||||
|
@ -85,4 +97,52 @@ public class AnalysisPipeline {
|
|||
|
||||
return dfa;
|
||||
}
|
||||
|
||||
public Set<Rule> getRulesInNFA(LexerGrammar lg, String modeName) {
|
||||
Set<Rule> rulesInNFA = getRulesTooComplexForDFA(lg, modeName);
|
||||
System.out.println("rules in NFA: "+rulesInNFA);
|
||||
|
||||
IntervalSet charsPredictingNFARules = new IntervalSet();
|
||||
for (Rule r : rulesInNFA) {
|
||||
if ( !r.isFragment() ) {
|
||||
LinearApproximator approx = new LinearApproximator(lg, NFA.INVALID_DECISION_NUMBER);
|
||||
IntervalSet fset = approx.FIRST(lg.nfa.ruleToStartState.get(r));
|
||||
System.out.println("first of "+r.name+"="+fset);
|
||||
charsPredictingNFARules.addAll(fset);
|
||||
}
|
||||
}
|
||||
System.out.println("charsPredictingNFARules="+charsPredictingNFARules);
|
||||
// now find any other rules that start with that set
|
||||
for (Rule r : lg.modes.get(modeName)) {
|
||||
if ( !r.isFragment() && !rulesInNFA.contains(r) ) {
|
||||
LinearApproximator approx = new LinearApproximator(lg, NFA.INVALID_DECISION_NUMBER);
|
||||
IntervalSet fset = approx.FIRST(lg.nfa.ruleToStartState.get(r));
|
||||
if ( !fset.and(charsPredictingNFARules).isNil() ) {
|
||||
System.out.println("rule "+r.name+" collides");
|
||||
rulesInNFA.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rulesInNFA;
|
||||
}
|
||||
|
||||
// TODO: oops. find all nongreedy loops too!
|
||||
public Set<Rule> getRulesTooComplexForDFA(LexerGrammar lg, String modeName) {
|
||||
Set<Rule> complexRules = new HashSet<Rule>();
|
||||
Map<Rule, Set<Rule>> dep = UseDefAnalyzer.getRuleDependencies(lg, modeName);
|
||||
System.out.println("dep="+dep);
|
||||
for (Rule r : lg.modes.get(modeName)) {
|
||||
if ( dep.containsKey(r) ) { complexRules.add(r); continue; }
|
||||
BitSet labelTypes = BitSet.of(ANTLRParser.ASSIGN);
|
||||
labelTypes.add(ANTLRParser.PLUS_ASSIGN);
|
||||
List<GrammarAST> labels = r.ast.getNodesWithType(labelTypes);
|
||||
if ( labels.size()>0 ) { complexRules.add(r); continue; }
|
||||
List<GrammarAST> actions = r.ast.getNodesWithType(ANTLRParser.ACTION);
|
||||
ActionAST actionOnFarRight = r.ast.getLexerAction();
|
||||
for (GrammarAST action : actions) {
|
||||
if ( action != actionOnFarRight ) complexRules.add(r);
|
||||
}
|
||||
}
|
||||
return complexRules;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,9 @@ public class NFAConfig {
|
|||
if (resolvedWithPredicate) {
|
||||
buf.append("|resolveWithPredicate");
|
||||
}
|
||||
if ( context.approximated ) {
|
||||
buf.append("|approx");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,34 @@ import org.antlr.v4.automata.NFAState;
|
|||
* on the path from this node thru the parent pointers to the root.
|
||||
*/
|
||||
public class NFAContext {
|
||||
/** This is similar to Bermudez's m constant in his LAR(m) where
|
||||
* he bounds the stack so your state sets don't explode. The main difference
|
||||
* is that I bound only recursion on the stack, not the simple stack size.
|
||||
* This looser constraint will let the conversion roam further to find
|
||||
* lookahead to resolve a decision.
|
||||
*
|
||||
* We restrict the size of an NFA configuration to be finite because a
|
||||
* stack component may mention the same NFA invocation state at
|
||||
* most m times. Hence, the number of DFA states will not grow forever.
|
||||
*
|
||||
* m=0 implies you can make as many calls as you want--you just
|
||||
* can't ever visit a state that is on your rule invocation stack.
|
||||
* I.e., you cannot ever recurse.
|
||||
* m=1 implies you are able to recurse once (i.e., call a rule twice
|
||||
* from the same place).
|
||||
* ...
|
||||
*
|
||||
* This tracks recursion to a rule specific to an invocation site!
|
||||
* It does not detect multiple calls to a rule from different rule
|
||||
* invocation states. We are guaranteed to terminate because the
|
||||
* stack can only grow as big as the number of NFA states * m.
|
||||
*
|
||||
* I noticed that the Java grammar didn't work with m=1 in ANTLR v3,
|
||||
* but it did work with m=4. Let's set to 4. Recursion is sometimes
|
||||
* needed to resolve some fixed lookahead decisions.
|
||||
*/
|
||||
public static int MAX_RECURSION_DEPTH_PER_NFA_CONFIG_STACK = 0;
|
||||
|
||||
public NFAContext parent;
|
||||
|
||||
/** The NFA state following state that invoked another rule's start state
|
||||
|
@ -56,7 +84,7 @@ public class NFAContext {
|
|||
/** Indicates this config led to recursive closure request. Everything
|
||||
* derived from here is approximation.
|
||||
*/
|
||||
public boolean recursed;
|
||||
public boolean approximated;
|
||||
|
||||
/** Computing the hashCode is very expensive and closureBusy()
|
||||
* uses it to track when it's seen a state|ctx before to avoid
|
||||
|
@ -152,19 +180,12 @@ public class NFAContext {
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Given an NFA state number, how many times has the NFA-to-DFA
|
||||
* conversion pushed that state on the stack? In other words,
|
||||
* the NFA state must be a rule invocation state and this method
|
||||
* tells you how many times you've been to this state. If none,
|
||||
* then you have not called the target rule from this state before
|
||||
* (though another NFA state could have called that target rule).
|
||||
* If n=1, then you've been to this state before during this
|
||||
* DFA construction and are going to invoke that rule again.
|
||||
*
|
||||
* Note that many NFA states can invoke rule r, but we ignore recursion
|
||||
* unless you hit the same rule invocation state again.
|
||||
/** Given an NFA state number, how many times does it appear on stack?
|
||||
* The NFA-to-DFA conversion pushes "return" states as it does
|
||||
* rule invocations. The NFA state number must be a rule return state
|
||||
* (following state from invocation state).
|
||||
*/
|
||||
public int recursionDepthEmanatingFromState(int state) {
|
||||
public int occurrences(int state) {
|
||||
NFAContext sp = this;
|
||||
int n = 0; // track recursive invocations of target from this state
|
||||
//System.out.println("this.context is "+sp);
|
||||
|
|
|
@ -338,7 +338,7 @@ public class PredictionDFAFactory {
|
|||
// if we have context info and we're at rule stop state, do
|
||||
// local follow for invokingRule and global follow for other links
|
||||
void ruleStopStateClosure(DFAState d, NFAConfig c, boolean collectPredicates) {
|
||||
if ( !c.context.recursed ) {
|
||||
if ( !c.context.approximated ) {
|
||||
//System.out.println("dynamic FOLLOW of "+c.state+" context="+c.context);
|
||||
if ( c.context.isEmpty() ) {
|
||||
commonClosure(d, c, collectPredicates); // do global FOLLOW
|
||||
|
@ -389,25 +389,59 @@ public class PredictionDFAFactory {
|
|||
for (int i=0; i<n; i++) {
|
||||
Transition t = c.state.transition(i);
|
||||
if ( t instanceof RuleTransition) {
|
||||
NFAState retState = ((RuleTransition)t).followState;
|
||||
RuleTransition rt = (RuleTransition) t;
|
||||
// have we called rt.target before? If so, rt.followState will be in c.context
|
||||
int depth = c.context.occurrences(rt.followState.stateNumber);
|
||||
System.out.println("ctx "+c.context+" c.state "+c.state+" ret state is "+rt.followState.stateNumber);
|
||||
// Even if not on context stack already, must consider self-recursion.
|
||||
// If a state in rule r's NFA invokes r's start state (only state
|
||||
// rule trans can invoke) then it's yet more recursion.
|
||||
// So we count previous invocations of r first and then
|
||||
// increment if we're jumping to start state from within r.
|
||||
if ( c.state.rule == t.target.rule ) depth++;
|
||||
System.out.println("recur depth "+depth);
|
||||
// Detect an attempt to recurse too high
|
||||
// if this context has hit the max recursions,
|
||||
// don't allow it to enter rule again
|
||||
NFAContext newContext = c.context;
|
||||
if ( c.state.rule != t.target.rule &&
|
||||
!c.context.contains(((RuleTransition)t).followState) ) { // !recursive?
|
||||
if ( depth > NFAContext.MAX_RECURSION_DEPTH_PER_NFA_CONFIG_STACK ) {
|
||||
//System.out.println("# recursive invoke of "+t.target+" ret to "+retState+" ctx="+c.context);
|
||||
// don't record recursion, but record we approximated so we know
|
||||
// what to do at end of rule and for error msgs.
|
||||
c.context.approximated = true;
|
||||
}
|
||||
else {
|
||||
// otherwise, it's cool to (re)enter target of this rule ref
|
||||
// first create a new context and push onto call tree,
|
||||
// recording the fact that we are invoking a rule and
|
||||
// from which state.
|
||||
//System.out.println("nonrecursive invoke of "+t.target+" ret to "+retState+" ctx="+c.context);
|
||||
NFAState retState = ((RuleTransition)t).followState;
|
||||
newContext = new NFAContext(c.context, retState);
|
||||
}
|
||||
else {
|
||||
//System.out.println("# recursive invoke of "+t.target+" ret to "+retState+" ctx="+c.context);
|
||||
// don't record recursion, but record we did so we know
|
||||
// what to do at end of rule.
|
||||
c.context.recursed = true;
|
||||
}
|
||||
// traverse epsilon edge to new rule
|
||||
closure(d, new NFAConfig(c, t.target, newContext),
|
||||
collectPredicates);
|
||||
|
||||
// NFAState retState = ((RuleTransition)t).followState;
|
||||
// NFAContext newContext = c.context;
|
||||
// if ( c.state.rule != t.target.rule &&
|
||||
// !c.context.contains(((RuleTransition)t).followState) ) { // !recursive?
|
||||
// // first create a new context and push onto call tree,
|
||||
// // recording the fact that we are invoking a rule and
|
||||
// // from which state.
|
||||
// //System.out.println("nonrecursive invoke of "+t.target+" ret to "+retState+" ctx="+c.context);
|
||||
// newContext = new NFAContext(c.context, retState);
|
||||
// }
|
||||
// else {
|
||||
// //System.out.println("# recursive invoke of "+t.target+" ret to "+retState+" ctx="+c.context);
|
||||
// // don't record recursion, but record we did so we know
|
||||
// // what to do at end of rule.
|
||||
// c.context.recursed = true;
|
||||
// }
|
||||
// // traverse epsilon edge to new rule
|
||||
// closure(d, new NFAConfig(c, t.target, newContext),
|
||||
// collectPredicates);
|
||||
}
|
||||
else if ( t instanceof ActionTransition ) {
|
||||
collectPredicates = false; // can't see past actions
|
||||
|
@ -500,14 +534,14 @@ public class PredictionDFAFactory {
|
|||
MachineProbe probe = new MachineProbe(dfa);
|
||||
|
||||
for (DFAState d : resolver.ambiguousStates) {
|
||||
Set<Integer> alts = resolver.getAmbiguousAlts(d);
|
||||
List<Integer> sorted = new ArrayList<Integer>(alts);
|
||||
Set<Integer> ambigAlts = Resolver.getAmbiguousAlts(d);
|
||||
List<Integer> sorted = new ArrayList<Integer>(ambigAlts);
|
||||
Collections.sort(sorted);
|
||||
//System.err.println("ambig alts="+sorted);
|
||||
List<DFAState> dfaStates = probe.getAnyDFAPathToTarget(d);
|
||||
//System.out.print("path =");
|
||||
for (DFAState d2 : dfaStates) {
|
||||
System.out.print(" "+d2.stateNumber);
|
||||
// System.out.print(" "+d2.stateNumber);
|
||||
}
|
||||
//System.out.println("");
|
||||
|
||||
|
@ -541,6 +575,10 @@ public class PredictionDFAFactory {
|
|||
if ( !d.resolvedWithPredicates &&
|
||||
(incompletelyCoveredAlts==null || incompletelyCoveredAlts.size()==0) )
|
||||
{
|
||||
Set<Integer> approxContextAlts = Resolver.getAltsWithApproximateContext(d);
|
||||
Set<Integer> certainAmbiguousAlt = ambigAlts;
|
||||
if ( approxContextAlts!=null ) certainAmbiguousAlt.removeAll(approxContextAlts);
|
||||
//if ( ambigAlts.containsAll()
|
||||
g.tool.errMgr.ambiguity(g.fileName, d, sorted, input, altPaths,
|
||||
hasPredicateBlockedByAction);
|
||||
}
|
||||
|
|
|
@ -144,6 +144,19 @@ public class Resolver {
|
|||
return ambiguousAlts;
|
||||
}
|
||||
|
||||
public static Set<Integer> getAltsWithApproximateContext(DFAState d) {
|
||||
Set<Integer> approxContextAlts = new HashSet<Integer>();
|
||||
|
||||
for (NFAConfig c : d.nfaConfigs) {
|
||||
if ( c.context.approximated ) {
|
||||
approxContextAlts.add(Utils.integer(c.alt));
|
||||
}
|
||||
}
|
||||
|
||||
if ( approxContextAlts.size()==0 ) return null;
|
||||
return approxContextAlts;
|
||||
}
|
||||
|
||||
public void resolveAmbiguities(DFAState d) {
|
||||
if ( PredictionDFAFactory.debug ) {
|
||||
System.out.println("resolveNonDeterminisms "+d.toString());
|
||||
|
|
|
@ -8,8 +8,6 @@ import org.antlr.v4.tool.TerminalAST;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
// TODO: i don't think we create lexer NFAs anymore
|
||||
|
||||
public class LexerNFAFactory extends ParserNFAFactory {
|
||||
public LexerNFAFactory(LexerGrammar g) { super(g); }
|
||||
|
||||
|
@ -41,6 +39,7 @@ public class LexerNFAFactory extends ParserNFAFactory {
|
|||
return nfa;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Handle range(GrammarAST a, GrammarAST b) {
|
||||
BasicState left = newState(a);
|
||||
BasicState right = newState(b);
|
||||
|
@ -57,6 +56,7 @@ public class LexerNFAFactory extends ParserNFAFactory {
|
|||
* the DFA. Machine== o-'f'->o-'o'->o-'g'->o and has n+1 states
|
||||
* for n characters.
|
||||
*/
|
||||
@Override
|
||||
public Handle stringLiteral(TerminalAST stringLiteralAST) {
|
||||
String chars = stringLiteralAST.getText();
|
||||
chars = CharSupport.getStringFromGrammarStringLiteral(chars);
|
||||
|
|
|
@ -33,6 +33,10 @@ public interface NFAFactory {
|
|||
|
||||
NFAState newState();
|
||||
|
||||
Handle label(Handle t);
|
||||
|
||||
Handle listLabel(Handle t);
|
||||
|
||||
Handle tokenRef(TerminalAST node);
|
||||
|
||||
/** From set build single edge graph o->o-set->o. To conform to
|
||||
|
|
|
@ -403,6 +403,14 @@ public class ParserNFAFactory implements NFAFactory {
|
|||
return n;
|
||||
}
|
||||
|
||||
public Handle label(Handle t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
public Handle listLabel(Handle t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
public NFAState newState(Class nodeType, GrammarAST node) {
|
||||
try {
|
||||
Constructor ctor = nodeType.getConstructor(NFA.class);
|
||||
|
|
|
@ -25,6 +25,7 @@ public class LexerFactory {
|
|||
lexerST.add("modes", lg.modes.keySet());
|
||||
fileST.add("fileName", gen.getRecognizerFileName());
|
||||
fileST.add("lexer", lexerST);
|
||||
|
||||
for (String modeName : lg.modes.keySet()) { // for each mode
|
||||
injectDFAs(lg, lexerST, modeName);
|
||||
//injectPDAs(lg, lexerST, modeName);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 ANTLRLexer.g 2010-06-14 12:35:30
|
||||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 ANTLRLexer.g 2010-06-16 13:46:52
|
||||
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
|
@ -264,7 +264,7 @@ public class ANTLRLexer extends Lexer {
|
|||
if ( (( input.LA(2) != '/')) ) {
|
||||
alt3=1;
|
||||
}
|
||||
else if ( (((( true )&&( !(input.LA(1) == '*' && input.LA(2) == '/') ))||( true ))) ) {
|
||||
else if ( ((( true )||(( true )&&( !(input.LA(1) == '*' && input.LA(2) == '/') )))) ) {
|
||||
alt3=2;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 ANTLRParser.g 2010-06-14 12:35:32
|
||||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 ANTLRParser.g 2010-06-16 13:46:54
|
||||
|
||||
/*
|
||||
[The "BSD licence"]
|
||||
|
@ -339,7 +339,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: id, prequelConstruct, grammarType, mode, rules, DOC_COMMENT
|
||||
// elements: DOC_COMMENT, id, rules, mode, grammarType, prequelConstruct
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -1184,7 +1184,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: IMPORT, delegateGrammar
|
||||
// elements: delegateGrammar, IMPORT
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -1465,7 +1465,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: TOKENS, tokenSpec
|
||||
// elements: tokenSpec, TOKENS
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -1620,7 +1620,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: id, STRING_LITERAL, ASSIGN
|
||||
// elements: ASSIGN, id, STRING_LITERAL
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -1914,7 +1914,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: ACTION, actionScopeName, AT, id
|
||||
// elements: id, AT, ACTION, actionScopeName
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -2214,7 +2214,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: MODE, id, rule
|
||||
// elements: rule, id, MODE
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -2606,7 +2606,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: ruleModifiers, ruleReturns, id, ruleBlock, ARG_ACTION, exceptionGroup, DOC_COMMENT, rulePrequels
|
||||
// elements: exceptionGroup, id, ARG_ACTION, ruleReturns, DOC_COMMENT, ruleBlock, ruleModifiers, rulePrequels
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -2918,7 +2918,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: ACTION, FINALLY
|
||||
// elements: FINALLY, ACTION
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -3352,7 +3352,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: THROWS, qid
|
||||
// elements: qid, THROWS
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -3482,7 +3482,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: ACTION, SCOPE
|
||||
// elements: SCOPE, ACTION
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -3561,7 +3561,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: SCOPE, id
|
||||
// elements: id, SCOPE
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -3660,7 +3660,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: ACTION, id, AT
|
||||
// elements: ACTION, AT, id
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -4178,7 +4178,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: rewrite, elements
|
||||
// elements: elements, rewrite
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -4550,7 +4550,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: labeledElement, ebnfSuffix
|
||||
// elements: ebnfSuffix, labeledElement
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -5257,7 +5257,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: element, TREE_BEGIN
|
||||
// elements: TREE_BEGIN, element
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -5372,7 +5372,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: block, blockSuffixe
|
||||
// elements: blockSuffixe, block
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -5830,7 +5830,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: id, ruleref, DOT
|
||||
// elements: ruleref, DOT, id
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -6177,7 +6177,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: NOT, terminal
|
||||
// elements: terminal, NOT
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -6396,7 +6396,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: altList, optionsSpec, ra
|
||||
// elements: optionsSpec, ra, altList
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -6571,7 +6571,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: RULE_REF, ARG_ACTION, op
|
||||
// elements: ARG_ACTION, RULE_REF, op
|
||||
// token labels: op
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -7909,7 +7909,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: ebnfSuffix, rewriteTreeAtom
|
||||
// elements: rewriteTreeAtom, ebnfSuffix
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -7992,7 +7992,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: rewriteTree, ebnfSuffix
|
||||
// elements: ebnfSuffix, rewriteTree
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -8231,7 +8231,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: TOKEN_REF, ARG_ACTION, elementOptions
|
||||
// elements: elementOptions, ARG_ACTION, TOKEN_REF
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -8472,7 +8472,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: ebnfSuffix, rewriteTreeAlt
|
||||
// elements: rewriteTreeAlt, ebnfSuffix
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -8609,7 +8609,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: rewriteTreeAtom, rewriteTreeElement, TREE_BEGIN
|
||||
// elements: TREE_BEGIN, rewriteTreeElement, rewriteTreeAtom
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -8764,7 +8764,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: rewriteTemplateArgs, str, TEMPLATE
|
||||
// elements: str, TEMPLATE, rewriteTemplateArgs
|
||||
// token labels: str
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -8913,7 +8913,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: rewriteTemplateArgs, id
|
||||
// elements: id, rewriteTemplateArgs
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
@ -9271,7 +9271,7 @@ public class ANTLRParser extends Parser {
|
|||
|
||||
|
||||
// AST REWRITE
|
||||
// elements: ACTION, id
|
||||
// elements: id, ACTION
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 ASTVerifier.g 2010-06-14 12:35:33
|
||||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 ASTVerifier.g 2010-06-16 13:46:55
|
||||
|
||||
/*
|
||||
[The "BSD license"]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 ActionSplitter.g 2010-06-14 12:35:32
|
||||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 ActionSplitter.g 2010-06-16 13:46:55
|
||||
|
||||
package org.antlr.v4.parse;
|
||||
|
||||
|
|
|
@ -98,10 +98,10 @@ element returns [NFAFactory.Handle p]
|
|||
;
|
||||
|
||||
labeledElement returns [NFAFactory.Handle p]
|
||||
: ^(ASSIGN ID atom) {$p = $atom.p;}
|
||||
| ^(ASSIGN ID block) {$p = $block.p;}
|
||||
| ^(PLUS_ASSIGN ID atom) {$p = $atom.p;}
|
||||
| ^(PLUS_ASSIGN ID block) {$p = $block.p;}
|
||||
: ^(ASSIGN ID atom) {$p = factory.label($atom.p);}
|
||||
| ^(ASSIGN ID block) {$p = factory.label($block.p);}
|
||||
| ^(PLUS_ASSIGN ID atom) {$p = factory.listLabel($atom.p);}
|
||||
| ^(PLUS_ASSIGN ID block) {$p = factory.listLabel($block.p);}
|
||||
;
|
||||
|
||||
treeSpec returns [NFAFactory.Handle p]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 NFABuilder.g 2010-06-14 12:35:33
|
||||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 NFABuilder.g 2010-06-16 13:46:55
|
||||
|
||||
/*
|
||||
[The "BSD license"]
|
||||
|
@ -579,7 +579,7 @@ public class NFABuilder extends TreeParser {
|
|||
|
||||
|
||||
match(input, Token.UP, null);
|
||||
p = (atom10!=null?atom10.p:null);
|
||||
p = factory.label((atom10!=null?atom10.p:null));
|
||||
|
||||
}
|
||||
break;
|
||||
|
@ -597,7 +597,7 @@ public class NFABuilder extends TreeParser {
|
|||
|
||||
|
||||
match(input, Token.UP, null);
|
||||
p = block11;
|
||||
p = factory.label(block11);
|
||||
|
||||
}
|
||||
break;
|
||||
|
@ -615,7 +615,7 @@ public class NFABuilder extends TreeParser {
|
|||
|
||||
|
||||
match(input, Token.UP, null);
|
||||
p = (atom12!=null?atom12.p:null);
|
||||
p = factory.listLabel((atom12!=null?atom12.p:null));
|
||||
|
||||
}
|
||||
break;
|
||||
|
@ -633,7 +633,7 @@ public class NFABuilder extends TreeParser {
|
|||
|
||||
|
||||
match(input, Token.UP, null);
|
||||
p = block13;
|
||||
p = factory.listLabel(block13);
|
||||
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 BasicSemanticTriggers.g 2010-06-14 12:35:34
|
||||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 BasicSemanticTriggers.g 2010-06-16 13:46:56
|
||||
|
||||
/*
|
||||
[The "BSD license"]
|
||||
|
|
|
@ -156,7 +156,7 @@ rule
|
|||
)
|
||||
{
|
||||
int numAlts = $RULE.getFirstChildWithType(BLOCK).getChildCount();
|
||||
Rule r = new Rule(g, $name.text, (GrammarASTWithOptions)$RULE, numAlts);
|
||||
Rule r = new Rule(g, $name.text, (RuleAST)$RULE, numAlts);
|
||||
if ( g.isLexer() ) r.mode = currentMode;
|
||||
if ( modifiers.size()>0 ) r.modifiers = modifiers;
|
||||
rules.add(r);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 CollectSymbols.g 2010-06-14 12:35:34
|
||||
// $ANTLR 3.2.1-SNAPSHOT May 24, 2010 15:02:05 CollectSymbols.g 2010-06-16 13:46:56
|
||||
|
||||
/*
|
||||
[The "BSD license"]
|
||||
|
@ -864,7 +864,7 @@ public class CollectSymbols extends org.antlr.v4.runtime.tree.TreeFilter {
|
|||
if ( state.backtracking==1 ) {
|
||||
|
||||
int numAlts = RULE8.getFirstChildWithType(BLOCK).getChildCount();
|
||||
Rule r = new Rule(g, (name!=null?name.getText():null), (GrammarASTWithOptions)RULE8, numAlts);
|
||||
Rule r = new Rule(g, (name!=null?name.getText():null), (RuleAST)RULE8, numAlts);
|
||||
if ( g.isLexer() ) r.mode = currentMode;
|
||||
if ( modifiers.size()>0 ) r.modifiers = modifiers;
|
||||
rules.add(r);
|
||||
|
|
|
@ -106,9 +106,8 @@ public class SemanticPipeline {
|
|||
if ( g.isLexer() ) assignLexerTokenTypes(g, collector);
|
||||
else assignTokenTypes(g, collector, symcheck);
|
||||
|
||||
UseDefAnalyzer usedef = new UseDefAnalyzer();
|
||||
usedef.checkRewriteElementsPresentOnLeftSide(g, collector.rules);
|
||||
usedef.trackTokenRuleRefsInActions(g);
|
||||
UseDefAnalyzer.checkRewriteElementsPresentOnLeftSide(g);
|
||||
UseDefAnalyzer.trackTokenRuleRefsInActions(g);
|
||||
}
|
||||
|
||||
void identifyStartRules(CollectSymbols collector) {
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package org.antlr.v4.semantics;
|
||||
|
||||
import org.antlr.v4.automata.Label;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.antlr.v4.tool.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/** Look for errors and deadcode stuff */
|
||||
public class UseDefAnalyzer {
|
||||
public void checkRewriteElementsPresentOnLeftSide(Grammar g, List<Rule> rules) {
|
||||
for (Rule r : rules) {
|
||||
public static void checkRewriteElementsPresentOnLeftSide(Grammar g) {
|
||||
for (Rule r : g.rules.values()) {
|
||||
for (int a=1; a<=r.numberOfAlts; a++) {
|
||||
Alternative alt = r.alt[a];
|
||||
for (GrammarAST e : alt.rewriteElements) {
|
||||
|
@ -26,7 +27,7 @@ public class UseDefAnalyzer {
|
|||
}
|
||||
|
||||
// side-effect: updates Alternative with refs in actions
|
||||
public void trackTokenRuleRefsInActions(Grammar g) {
|
||||
public static void trackTokenRuleRefsInActions(Grammar g) {
|
||||
for (Rule r : g.rules.values()) {
|
||||
for (int i=1; i<=r.numberOfAlts; i++) {
|
||||
Alternative alt = r.alt[i];
|
||||
|
@ -38,4 +39,31 @@ public class UseDefAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
/** Find all rules reachable from r directly or indirectly for all r in g */
|
||||
public static Map<Rule, Set<Rule>> getRuleDependencies(Grammar g) {
|
||||
return getRuleDependencies(g, g.rules.values());
|
||||
}
|
||||
|
||||
public static Map<Rule, Set<Rule>> getRuleDependencies(LexerGrammar g, String modeName) {
|
||||
return getRuleDependencies(g, g.modes.get(modeName));
|
||||
}
|
||||
|
||||
public static Map<Rule, Set<Rule>> getRuleDependencies(Grammar g, Collection<Rule> rules) {
|
||||
Map<Rule, Set<Rule>> dependencies = new HashMap<Rule, Set<Rule>>();
|
||||
|
||||
for (Rule r : rules) {
|
||||
List<GrammarAST> tokenRefs = r.ast.getNodesWithType(ANTLRParser.TOKEN_REF);
|
||||
for (GrammarAST tref : tokenRefs) {
|
||||
Set<Rule> calls = dependencies.get(r);
|
||||
if ( calls==null ) {
|
||||
calls = new HashSet<Rule>();
|
||||
dependencies.put(r, calls);
|
||||
}
|
||||
calls.add(g.getRule(tref.getText()));
|
||||
}
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package org.antlr.v4.tool;
|
||||
|
||||
import org.antlr.runtime.BitSet;
|
||||
import org.antlr.runtime.CommonToken;
|
||||
import org.antlr.runtime.Token;
|
||||
import org.antlr.runtime.tree.Tree;
|
||||
import org.antlr.v4.automata.NFAState;
|
||||
import org.antlr.v4.misc.BitSet;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.antlr.v4.runtime.tree.CommonTree;
|
||||
|
||||
|
@ -44,8 +44,8 @@ public class GrammarAST extends CommonTree {
|
|||
GrammarAST t = null;
|
||||
while ( work.size()>0 ) {
|
||||
t = work.remove(0);
|
||||
if ( types.member(t.getType()) ) nodes.add(this);
|
||||
work.addAll(children);
|
||||
if ( types.member(t.getType()) ) nodes.add(t);
|
||||
if ( t.children!=null ) work.addAll(t.children);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public class Rule implements AttributeResolver {
|
|||
public String name;
|
||||
public List<GrammarAST> modifiers;
|
||||
|
||||
public GrammarASTWithOptions ast;
|
||||
public RuleAST ast;
|
||||
public AttributeDict args;
|
||||
public AttributeDict retvals;
|
||||
public AttributeDict scope; // scope { int i; }
|
||||
|
@ -86,7 +86,7 @@ public class Rule implements AttributeResolver {
|
|||
/** All rules have unique index 1..n */
|
||||
public int index;
|
||||
|
||||
public Rule(Grammar g, String name, GrammarASTWithOptions ast, int numberOfAlts) {
|
||||
public Rule(Grammar g, String name, RuleAST ast, int numberOfAlts) {
|
||||
this.g = g;
|
||||
this.name = name;
|
||||
this.ast = ast;
|
||||
|
|
Loading…
Reference in New Issue