diff --git a/tool/playground/AA.g b/tool/playground/AA.g index a482b1205..da3fb75fe 100644 --- a/tool/playground/AA.g +++ b/tool/playground/AA.g @@ -14,7 +14,7 @@ member stat: expr ';' {System.out.println("found expr: "+$stat.text);} | ID '=' expr ';' - {System.out.println("found assign: "+$stat.text);} + {System.out.println("found assign: "+$stat.text+$ID.text);} ; expr: INT diff --git a/tool/playground/T.g b/tool/playground/T.g index 899167684..2ad228a87 100644 --- a/tool/playground/T.g +++ b/tool/playground/T.g @@ -1,5 +1,2 @@ -grammar T; - -tokens { A,B } - -s : A ; +lexer grammar T; +A : 'a'; diff --git a/tool/src/org/antlr/v4/Tool.java b/tool/src/org/antlr/v4/Tool.java index f40d47b0f..59a0e7a1a 100644 --- a/tool/src/org/antlr/v4/Tool.java +++ b/tool/src/org/antlr/v4/Tool.java @@ -29,6 +29,7 @@ package org.antlr.v4; +import org.antlr.misc.Graph; import org.antlr.runtime.ANTLRFileStream; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CharStream; @@ -221,7 +222,7 @@ public class Tool { continue; } if ( arg.charAt(0)!='-' ) { // file name - grammarFiles.add(arg); + if ( !grammarFiles.contains(arg) ) grammarFiles.add(arg); continue; } boolean found = false; @@ -316,14 +317,11 @@ public class Tool { } public void processGrammarsOnCommandLine() { - for (String fileName : grammarFiles) { - GrammarAST t = loadGrammar(fileName); - if ( t==null || t instanceof GrammarASTErrorNode) return; // came back as error node - if ( ((GrammarRootAST)t).hasErrors ) return; - GrammarRootAST ast = (GrammarRootAST)t; + List sortedGrammars = sortGrammarByTokenVocab(grammarFiles); - final Grammar g = createGrammar(ast); - g.fileName = fileName; + for (GrammarRootAST t : sortedGrammars) { + final Grammar g = createGrammar(t); + g.fileName = t.fileName; process(g, true); } } @@ -337,7 +335,6 @@ public class Tool { public void process(Grammar g, boolean gencode) { g.loadImportedGrammars(); - GrammarTransformPipeline transform = new GrammarTransformPipeline(g, this); transform.process(); @@ -367,13 +364,12 @@ public class Tool { if ( g.ast!=null && internalOption_PrintGrammarTree ) System.out.println(g.ast.toStringTree()); //g.ast.inspect(); - if ( errMgr.getNumErrors()>0 ) return; - + int prevErrors = errMgr.getNumErrors(); // MAKE SURE GRAMMAR IS SEMANTICALLY CORRECT (FILL IN GRAMMAR OBJECT) SemanticPipeline sem = new SemanticPipeline(g); sem.process(); - if ( errMgr.getNumErrors()>0 ) return; + if ( errMgr.getNumErrors()>prevErrors ) return; // BUILD ATN FROM AST ATNFactory factory; @@ -389,7 +385,7 @@ public class Tool { //if ( generate_DFA_dot ) generateDFAs(g); - if ( g.tool.getNumErrors()>0 ) return; + if ( g.tool.getNumErrors()>prevErrors ) return; // GENERATE CODE if ( gencode ) { @@ -398,6 +394,63 @@ public class Tool { } } + public List sortGrammarByTokenVocab(List fileNames) { +// System.out.println(fileNames); + Graph g = new Graph(); + List roots = new ArrayList(); + for (String fileName : fileNames) { + GrammarAST t = loadGrammar(fileName); + if ( t==null || t instanceof GrammarASTErrorNode) continue; // came back as error node + if ( ((GrammarRootAST)t).hasErrors ) continue; + GrammarRootAST root = (GrammarRootAST)t; + roots.add(root); + root.fileName = fileName; + String grammarName = root.getChild(0).getText(); + + GrammarAST tokenVocabNode = findOptionValueAST(root, "tokenVocab"); + // Make grammars depend on any tokenVocab options + if ( tokenVocabNode!=null ) { + String vocabName = tokenVocabNode.getText(); + g.addEdge(grammarName, vocabName); + } + // add cycle to graph so we always process a grammar if no error + // even if no dependency + g.addEdge(grammarName, grammarName); + } + + List sortedGrammarNames = g.sort(); +// System.out.println("sortedGrammarNames="+sortedGrammarNames); + + List sortedRoots = new ArrayList(); + for (String grammarName : sortedGrammarNames) { + for (GrammarRootAST root : roots) { + if ( root.getGrammarName().equals(grammarName) ) { + sortedRoots.add(root); + break; + } + } + } + + return sortedRoots; + } + + /** Manually get option node from tree; return null if no defined. */ + public static GrammarAST findOptionValueAST(GrammarRootAST root, String option) { + GrammarAST options = (GrammarAST)root.getFirstChildWithType(ANTLRParser.OPTIONS); + if ( options!=null ) { + for (Object o : options.getChildren()) { + GrammarAST c = (GrammarAST)o; + if ( c.getType() == ANTLRParser.ASSIGN && + c.getChild(0).getText().equals(option) ) + { + return (GrammarAST)c.getChild(1); + } + } + } + return null; + } + + /** Given the raw AST of a grammar, create a grammar object associated with the AST. Once we have the grammar object, ensure that all nodes in tree referred to this grammar. Later, we will diff --git a/tool/src/org/antlr/v4/tool/ast/GrammarRootAST.java b/tool/src/org/antlr/v4/tool/ast/GrammarRootAST.java index 193188f86..90d37ff1e 100644 --- a/tool/src/org/antlr/v4/tool/ast/GrammarRootAST.java +++ b/tool/src/org/antlr/v4/tool/ast/GrammarRootAST.java @@ -46,6 +46,7 @@ public class GrammarRootAST extends GrammarASTWithOptions { /** Track stream used to create this tree */ public TokenStream tokens; public Map cmdLineOptions; // -DsuperClass=T on command line + public String fileName; public GrammarRootAST(GrammarAST node) { super(node); @@ -60,6 +61,11 @@ public class GrammarRootAST extends GrammarASTWithOptions { super(type,t,text); } + public String getGrammarName() { + Tree t = getChild(0); + if ( t!=null ) return t.getText(); + return null; + } @Override public String getOptionString(String key) {