added -depend cmd-line option; fixes #71
This commit is contained in:
parent
68dd847c04
commit
2db3691f6d
|
@ -9,6 +9,8 @@ September 30, 2012
|
|||
|
||||
* Added a getter to IntStream for the token factory
|
||||
|
||||
* Added -depend cmd-line option.
|
||||
|
||||
September 29, 2012
|
||||
|
||||
* no nongreedy or wildcard in parser.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
grammar T;
|
||||
options {tokenVocab=A;}
|
||||
s : ID ;
|
||||
ID : 'a'..'z'+ ;
|
||||
WS : (' '|'\n') {skip();} ;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/** templates used to generate make-compatible dependencies */
|
||||
group depend;
|
||||
|
||||
/** Generate "f : x, y, z" dependencies for input
|
||||
* dependencies and generated files. in and out
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.antlr.v4.automata.ATNFactory;
|
|||
import org.antlr.v4.automata.LexerATNFactory;
|
||||
import org.antlr.v4.automata.ParserATNFactory;
|
||||
import org.antlr.v4.codegen.CodeGenPipeline;
|
||||
import org.antlr.v4.codegen.CodeGenerator;
|
||||
import org.antlr.v4.misc.Graph;
|
||||
import org.antlr.v4.parse.ANTLRLexer;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
|
@ -50,6 +51,7 @@ import org.antlr.v4.runtime.misc.Nullable;
|
|||
import org.antlr.v4.semantics.SemanticPipeline;
|
||||
import org.antlr.v4.tool.ANTLRMessage;
|
||||
import org.antlr.v4.tool.ANTLRToolListener;
|
||||
import org.antlr.v4.tool.BuildDependencyGenerator;
|
||||
import org.antlr.v4.tool.DOTGenerator;
|
||||
import org.antlr.v4.tool.DefaultToolListener;
|
||||
import org.antlr.v4.tool.ErrorManager;
|
||||
|
@ -126,6 +128,7 @@ public class Tool {
|
|||
public boolean verbose_dfa = false;
|
||||
public boolean gen_listener = true;
|
||||
public boolean gen_visitor = false;
|
||||
public boolean gen_dependencies = false;
|
||||
public String genPackage = null;
|
||||
public Map<String, String> grammarOptions = null;
|
||||
|
||||
|
@ -146,10 +149,10 @@ public class Tool {
|
|||
new Option("gen_visitor", "-visitor", "generate parse tree visitor"),
|
||||
new Option("gen_visitor", "-no-visitor", "don't generate parse tree visitor (default)"),
|
||||
new Option("genPackage", "-package", OptionArgType.STRING, "specify a package/namespace for the generated code"),
|
||||
new Option("gen_dependencies", "-depend", "generate file dependencies"),
|
||||
new Option("", "-D<option>=value", "set/override a grammar-level option"),
|
||||
|
||||
|
||||
new Option("saveLexer", "-Xsave-lexer", "save temp lexer file created for combined grammars"),
|
||||
new Option("saveLexer", "-Xsave-lexer", "save temp lexer file created for combined grammars"),
|
||||
new Option("launch_ST_inspector", "-XdbgST", "launch StringTemplate visualizer on generated code"),
|
||||
new Option("force_atn", "-Xforce-atn", "use the ATN simulator for all predictions"),
|
||||
new Option("log", "-Xlog", "dump lots of logging info to antlr-timestamp.log"),
|
||||
|
@ -324,7 +327,21 @@ public class Tool {
|
|||
for (GrammarRootAST t : sortedGrammars) {
|
||||
final Grammar g = createGrammar(t);
|
||||
g.fileName = t.fileName;
|
||||
process(g, true);
|
||||
if ( gen_dependencies ) {
|
||||
BuildDependencyGenerator dep =
|
||||
new BuildDependencyGenerator(this, g);
|
||||
/*
|
||||
List outputFiles = dep.getGeneratedFileList();
|
||||
List dependents = dep.getDependenciesFileList();
|
||||
System.out.println("output: "+outputFiles);
|
||||
System.out.println("dependents: "+dependents);
|
||||
*/
|
||||
System.out.println(dep.getDependencies().render());
|
||||
|
||||
}
|
||||
else {
|
||||
process(g, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,7 +606,7 @@ public class Tool {
|
|||
// be the base output directory (or current directory if there is not a -o)
|
||||
//
|
||||
File outputDir;
|
||||
if ( fileName.endsWith(".tokens") ) {// CodeGenerator.VOCAB_FILE_EXTENSION)) {
|
||||
if ( fileName.endsWith(CodeGenerator.VOCAB_FILE_EXTENSION) ) {
|
||||
outputDir = new File(outputDirectory);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2012 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.v4.tool;
|
||||
|
||||
import org.antlr.v4.Tool;
|
||||
import org.antlr.v4.codegen.CodeGenerator;
|
||||
import org.antlr.v4.misc.Utils;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.stringtemplate.v4.ST;
|
||||
import org.stringtemplate.v4.STGroup;
|
||||
import org.stringtemplate.v4.STGroupFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Given a grammar file, show the dependencies on .tokens etc...
|
||||
* Using ST, emit a simple "make compatible" list of dependencies.
|
||||
* For example, combined grammar T.g (no token import) generates:
|
||||
*
|
||||
* TParser.java : T.g
|
||||
* T.tokens : T.g
|
||||
* TLexer.java : T.g
|
||||
*
|
||||
* If "-lib libdir" is used on command-line with -depend and option
|
||||
* tokenVocab=A in grammar, then include the path like this:
|
||||
*
|
||||
* T.g: libdir/A.tokens
|
||||
*
|
||||
* Pay attention to -o as well:
|
||||
*
|
||||
* outputdir/TParser.java : T.g
|
||||
*
|
||||
* So this output shows what the grammar depends on *and* what it generates.
|
||||
*
|
||||
* Operate on one grammar file at a time. If given a list of .g on the
|
||||
* command-line with -depend, just emit the dependencies. The grammars
|
||||
* may depend on each other, but the order doesn't matter. Build tools,
|
||||
* reading in this output, will know how to organize it.
|
||||
*
|
||||
* This code was obvious until I removed redundant "./" on front of files
|
||||
* and had to escape spaces in filenames :(
|
||||
*
|
||||
* I literally copied from v3 so might be slightly inconsistent with the
|
||||
* v4 code base.
|
||||
*/
|
||||
public class BuildDependencyGenerator {
|
||||
protected Tool tool;
|
||||
protected Grammar g;
|
||||
protected CodeGenerator generator;
|
||||
protected STGroup templates;
|
||||
|
||||
public BuildDependencyGenerator(Tool tool, Grammar g) {
|
||||
this.tool = tool;
|
||||
this.g = g;
|
||||
String language = g.getOptionString("language");
|
||||
generator = new CodeGenerator(tool, g, language);
|
||||
}
|
||||
|
||||
/** From T.g return a list of File objects that
|
||||
* name files ANTLR will emit from T.g.
|
||||
*/
|
||||
public List<File> getGeneratedFileList() {
|
||||
List<File> files = new ArrayList<File>();
|
||||
|
||||
// add generated recognizer; e.g., TParser.java
|
||||
files.add(getOutputFile(generator.getRecognizerFileName()));
|
||||
// add output vocab file; e.g., T.tokens. This is always generated to
|
||||
// the base output directory, which will be just . if there is no -o option
|
||||
//
|
||||
files.add(getOutputFile(generator.getVocabFileName()));
|
||||
// are we generating a .h file?
|
||||
ST headerExtST = null;
|
||||
ST extST = generator.templates.getInstanceOf("codeFileExtension");
|
||||
if (generator.templates.isDefined("headerFile")) {
|
||||
headerExtST = generator.templates.getInstanceOf("headerFileExtension");
|
||||
String suffix = Grammar.getGrammarTypeToFileNameSuffix(g.getType());
|
||||
String fileName = g.name + suffix + headerExtST.render();
|
||||
files.add(getOutputFile(fileName));
|
||||
}
|
||||
if ( g.isCombined() ) {
|
||||
// add autogenerated lexer; e.g., TLexer.java TLexer.h TLexer.tokens
|
||||
|
||||
String suffix = Grammar.getGrammarTypeToFileNameSuffix(ANTLRParser.LEXER);
|
||||
String lexer = g.name + suffix + extST.render();
|
||||
files.add(getOutputFile(lexer));
|
||||
|
||||
// TLexer.h
|
||||
if (headerExtST != null) {
|
||||
String header = g.name + suffix + headerExtST.render();
|
||||
files.add(getOutputFile(header));
|
||||
}
|
||||
// for combined, don't generate TLexer.tokens
|
||||
}
|
||||
|
||||
// handle generated files for imported grammars
|
||||
List<Grammar> imports = g.getAllImportedGrammars();
|
||||
if ( imports!=null ) {
|
||||
for (Grammar g : imports) {
|
||||
// File outputDir = tool.getOutputDirectory(g.fileName);
|
||||
// String fname = groomQualifiedFileName(outputDir.toString(), g.getRecognizerName() + extST.render());
|
||||
// files.add(new File(outputDir, fname));
|
||||
files.add(getOutputFile(g.fileName));
|
||||
}
|
||||
}
|
||||
|
||||
if (files.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
public File getOutputFile(String fileName) {
|
||||
File outputDir = tool.getOutputDirectory(g.fileName);
|
||||
if ( outputDir.toString().equals(".") ) {
|
||||
// pay attention to -o then
|
||||
outputDir = tool.getOutputDirectory(fileName);
|
||||
}
|
||||
if ( outputDir.toString().equals(".") ) {
|
||||
return new File(fileName);
|
||||
}
|
||||
if (outputDir.getName().equals(".")) {
|
||||
String fname = outputDir.toString();
|
||||
int dot = fname.lastIndexOf('.');
|
||||
outputDir = new File(outputDir.toString().substring(0,dot));
|
||||
}
|
||||
|
||||
if (outputDir.getName().indexOf(' ') >= 0) { // has spaces?
|
||||
String escSpaces = Utils.replace(outputDir.toString(),
|
||||
" ",
|
||||
"\\ ");
|
||||
outputDir = new File(escSpaces);
|
||||
}
|
||||
return new File(outputDir, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of File objects that name files ANTLR will read
|
||||
* to process T.g; This can be .tokens files if the grammar uses the tokenVocab option
|
||||
* as well as any imported grammar files.
|
||||
*/
|
||||
public List<File> getDependenciesFileList() {
|
||||
// Find all the things other than imported grammars
|
||||
List<File> files = getNonImportDependenciesFileList();
|
||||
|
||||
// Handle imported grammars
|
||||
List<Grammar> imports = g.getAllImportedGrammars();
|
||||
if ( imports!=null ) {
|
||||
for (Grammar g : imports) {
|
||||
String libdir = tool.libDirectory;
|
||||
String fileName = groomQualifiedFileName(libdir, g.fileName);
|
||||
files.add(new File(fileName));
|
||||
}
|
||||
}
|
||||
|
||||
if (files.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of File objects that name files ANTLR will read
|
||||
* to process T.g; This can only be .tokens files and only
|
||||
* if they use the tokenVocab option.
|
||||
*
|
||||
* @return List of dependencies other than imported grammars
|
||||
*/
|
||||
public List<File> getNonImportDependenciesFileList() {
|
||||
List<File> files = new ArrayList<File>();
|
||||
|
||||
// handle token vocabulary loads
|
||||
String tokenVocab = g.getOptionString("tokenVocab");
|
||||
if (tokenVocab != null) {
|
||||
String fileName =
|
||||
tokenVocab + CodeGenerator.VOCAB_FILE_EXTENSION;
|
||||
File vocabFile;
|
||||
if ( tool.libDirectory.equals(".") ) {
|
||||
vocabFile = new File(fileName);
|
||||
}
|
||||
else {
|
||||
vocabFile = new File(tool.libDirectory, fileName);
|
||||
}
|
||||
files.add(vocabFile);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
public ST getDependencies() {
|
||||
loadDependencyTemplates();
|
||||
ST dependenciesST = templates.getInstanceOf("dependencies");
|
||||
dependenciesST.add("in", getDependenciesFileList());
|
||||
dependenciesST.add("out", getGeneratedFileList());
|
||||
dependenciesST.add("grammarFileName", g.fileName);
|
||||
return dependenciesST;
|
||||
}
|
||||
|
||||
public void loadDependencyTemplates() {
|
||||
if (templates != null) return;
|
||||
String fileName = "org/antlr/v4/tool/templates/depend.stg";
|
||||
templates = new STGroupFile(fileName);
|
||||
}
|
||||
|
||||
public CodeGenerator getGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
public String groomQualifiedFileName(String outputDir, String fileName) {
|
||||
if (outputDir.equals(".")) {
|
||||
return fileName;
|
||||
}
|
||||
else if (outputDir.indexOf(' ') >= 0) { // has spaces?
|
||||
String escSpaces = Utils.replace(outputDir,
|
||||
" ",
|
||||
"\\ ");
|
||||
return escSpaces + File.separator + fileName;
|
||||
}
|
||||
else {
|
||||
return outputDir + File.separator + fileName;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue