| /* |
| * [The "BSD license"] |
| * Copyright (c) 2010 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.tool; |
| |
| import org.antlr.Tool; |
| import org.antlr.codegen.CodeGenerator; |
| import org.antlr.misc.Utils; |
| import org.stringtemplate.v4.ST; |
| import org.stringtemplate.v4.STGroup; |
| import org.stringtemplate.v4.STGroupFile; |
| |
| import java.io.*; |
| 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 |
| * T__g : T.g |
| * |
| * For tree grammar TP with import of T.tokens: |
| * |
| * TP.g : T.tokens |
| * TP.java : TP.g |
| * |
| * If "-lib libdir" is used on command-line with -depend, then include the |
| * path like |
| * |
| * TP.g : libdir/T.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 is a wee bit slow probably because the code generator has to load |
| * all of its template files in order to figure out the file extension |
| * for the generated recognizer. |
| * |
| * This code was obvious until I removed redundant "./" on front of files |
| * and had to escape spaces in filenames :( |
| */ |
| public class BuildDependencyGenerator { |
| protected String grammarFileName; |
| protected String tokenVocab; |
| protected Tool tool; |
| protected Grammar grammar; |
| protected CodeGenerator generator; |
| protected STGroup templates; |
| |
| public BuildDependencyGenerator(Tool tool, String grammarFileName) |
| throws IOException { |
| this.tool = tool; |
| this.grammarFileName = grammarFileName; |
| grammar = tool.getRootGrammar(grammarFileName); |
| String language = (String) grammar.getOption("language"); |
| generator = new CodeGenerator(tool, grammar, language); |
| generator.loadTemplates(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>(); |
| File outputDir = tool.getOutputDirectory(grammarFileName); |
| if (outputDir.getName().equals(".")) { |
| outputDir = null; |
| } else if (outputDir.getName().indexOf(' ') >= 0) { // has spaces? |
| String escSpaces = Utils.replace(outputDir.toString(), |
| " ", |
| "\\ "); |
| outputDir = new File(escSpaces); |
| } |
| // add generated recognizer; e.g., TParser.java |
| String recognizer = |
| generator.getRecognizerFileName(grammar.name, grammar.type); |
| files.add(new File(outputDir, recognizer)); |
| // 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(new File(tool.getOutputDirectory(), generator.getVocabFileName())); |
| // are we generating a .h file? |
| ST headerExtST = null; |
| ST extST = generator.getTemplates().getInstanceOf("codeFileExtension"); |
| if (generator.getTemplates().isDefined("headerFile")) { |
| headerExtST = generator.getTemplates().getInstanceOf("headerFileExtension"); |
| String suffix = Grammar.grammarTypeToFileNameSuffix[grammar.type]; |
| String fileName = grammar.name + suffix + headerExtST.render(); |
| files.add(new File(outputDir, fileName)); |
| } |
| if (grammar.type == Grammar.COMBINED) { |
| // add autogenerated lexer; e.g., TLexer.java TLexer.h TLexer.tokens |
| // don't add T__.g (just a temp file) |
| |
| String suffix = Grammar.grammarTypeToFileNameSuffix[Grammar.LEXER]; |
| String lexer = grammar.name + suffix + extST.render(); |
| files.add(new File(outputDir, lexer)); |
| |
| // TLexer.h |
| if (headerExtST != null) { |
| String header = grammar.name + suffix + headerExtST.render(); |
| files.add(new File(outputDir, header)); |
| } |
| // for combined, don't generate TLexer.tokens |
| } |
| |
| // handle generated files for imported grammars |
| List<Grammar> imports = |
| grammar.composite.getDelegates(grammar.composite.getRootGrammar()); |
| for (Grammar g : imports) { |
| outputDir = tool.getOutputDirectory(g.getFileName()); |
| String fname = groomQualifiedFileName(outputDir.toString(), g.getRecognizerName() + extST.render()); |
| files.add(new File(fname)); |
| } |
| |
| if (files.size() == 0) { |
| return null; |
| } |
| return files; |
| } |
| |
| /** |
| * 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 = |
| grammar.composite.getDelegates(grammar.composite.getRootGrammar()); |
| for (Grammar g : imports) { |
| String libdir = tool.getLibraryDirectory(); |
| String fileName = groomQualifiedFileName(libdir, g.fileName); |
| files.add(new File(fileName)); |
| } |
| |
| if (files.size() == 0) { |
| 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 |
| tokenVocab = (String) grammar.getOption("tokenVocab"); |
| if (tokenVocab != null) { |
| |
| File vocabFile = tool.getImportedVocabFile(tokenVocab); |
| 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", grammar.fileName); |
| return dependenciesST; |
| } |
| |
| public void loadDependencyTemplates() { |
| if (templates != null) return; |
| String fileName = "org/antlr/tool/templates/depend.stg"; |
| templates = new STGroupFile(fileName); |
| } |
| |
| public String getTokenVocab() { |
| return tokenVocab; |
| } |
| |
| 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.toString(), |
| " ", |
| "\\ "); |
| return escSpaces + File.separator + fileName; |
| } else { |
| return outputDir + File.separator + fileName; |
| } |
| } |
| } |