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:
parrt 2010-07-07 13:38:13 -08:00
parent 0e4fbf903d
commit 6414fa00c6
23 changed files with 265 additions and 90 deletions

View File

@ -319,9 +319,9 @@ public class <lexerName> extends Lexer {
<namedActions.members>
<dfas>
<actions>
<sempreds>
<dfas>
<pdas>
}
>>

View File

@ -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;
}
}

View File

@ -129,6 +129,9 @@ public class NFAConfig {
if (resolvedWithPredicate) {
buf.append("|resolveWithPredicate");
}
if ( context.approximated ) {
buf.append("|approx");
}
return buf.toString();
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -63,7 +63,7 @@ public class Resolver {
*/
public static Set<Integer> getAmbiguousAlts(DFAState d) {
//System.out.println("getNondetAlts for DFA state "+stateNumber);
Set<Integer> ambiguousAlts = new HashSet<Integer>();
Set<Integer> ambiguousAlts = new HashSet<Integer>();
// If only 1 NFA conf then no way it can be nondeterministic;
// save the overhead. There are many o-a->o NFA transitions
@ -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());

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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 {

View File

@ -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:

View File

@ -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"]

View File

@ -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;

View File

@ -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]

View File

@ -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;

View File

@ -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"]

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;