org.antlr.v4.codegen.CodeGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of antlr4 Show documentation
Show all versions of antlr4 Show documentation
The ANTLR 4 grammar compiler.
/*
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
package org.antlr.v4.codegen;
import org.antlr.v4.Tool;
import org.antlr.v4.codegen.model.OutputModelObject;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.stringtemplate.v4.AutoIndentWriter;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STWriter;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.util.LinkedHashMap;
import java.util.Map;
/** General controller for code gen. Can instantiate sub generator(s).
*/
public class CodeGenerator {
public static final String TEMPLATE_ROOT = "org/antlr/v4/tool/templates/codegen";
public static final String VOCAB_FILE_EXTENSION = ".tokens";
public static final String DEFAULT_LANGUAGE = "Java";
public static final String vocabFilePattern =
"=\n}>" +
"=\n}>";
public final Grammar g;
public final Tool tool;
public final String language;
private Target target;
public int lineWidth = 72;
private CodeGenerator(String language) {
this.g = null;
this.tool = null;
this.language = language;
}
public CodeGenerator(Grammar g) {
this(g.tool, g, g.getOptionString("language"));
}
public CodeGenerator(Tool tool, Grammar g, String language) {
this.g = g;
this.tool = tool;
this.language = language != null ? language : DEFAULT_LANGUAGE;
}
public static boolean targetExists(String language) {
String targetName = "org.antlr.v4.codegen.target."+language+"Target";
try {
Class extends Target> c = Class.forName(targetName).asSubclass(Target.class);
Constructor extends Target> ctor = c.getConstructor(CodeGenerator.class);
CodeGenerator gen = new CodeGenerator(language);
Target target = ctor.newInstance(gen);
return target.templatesExist();
}
catch (Exception e) { // ignore errors; we're detecting presence only
}
return false;
}
public Target getTarget() {
if ( target == null && targetExists(language) ) {
loadLanguageTarget(language);
}
return target;
}
public STGroup getTemplates() {
Target t = getTarget();
return t==null ? null : t.getTemplates();
}
protected void loadLanguageTarget(String language) {
String targetName = "org.antlr.v4.codegen.target."+language+"Target";
try {
Class extends Target> c = Class.forName(targetName).asSubclass(Target.class);
Constructor extends Target> ctor = c.getConstructor(CodeGenerator.class);
target = ctor.newInstance(this);
}
catch (Exception e) {
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
e,
targetName);
}
}
// CREATE TEMPLATES BY WALKING MODEL
private OutputModelController createController() {
OutputModelFactory factory = new ParserFactory(this);
OutputModelController controller = new OutputModelController(factory);
factory.setController(controller);
return controller;
}
private ST walk(OutputModelObject outputModel, boolean header) {
OutputModelWalker walker = new OutputModelWalker(tool, getTemplates());
return walker.walk(outputModel, header);
}
public ST generateLexer() { return generateLexer(false); }
public ST generateLexer(boolean header) { return walk(createController().buildLexerOutputModel(header), header); }
public ST generateParser() { return generateParser(false); }
public ST generateParser(boolean header) { return walk(createController().buildParserOutputModel(header), header); }
public ST generateListener() { return generateListener(false); }
public ST generateListener(boolean header) { return walk(createController().buildListenerOutputModel(header), header); }
public ST generateBaseListener() { return generateBaseListener(false); }
public ST generateBaseListener(boolean header) { return walk(createController().buildBaseListenerOutputModel(header), header); }
public ST generateVisitor() { return generateVisitor(false); }
public ST generateVisitor(boolean header) { return walk(createController().buildVisitorOutputModel(header), header); }
public ST generateBaseVisitor() { return generateBaseVisitor(false); }
public ST generateBaseVisitor(boolean header) { return walk(createController().buildBaseVisitorOutputModel(header), header); }
/** Generate a token vocab file with all the token names/types. For example:
* ID=7
* FOR=8
* 'for'=8
*
* This is independent of the target language; used by antlr internally
*/
ST getTokenVocabOutput() {
ST vocabFileST = new ST(vocabFilePattern);
Map tokens = new LinkedHashMap();
// make constants for the token names
for (String t : g.tokenNameToTypeMap.keySet()) {
int tokenType = g.tokenNameToTypeMap.get(t);
if ( tokenType>=Token.MIN_USER_TOKEN_TYPE) {
tokens.put(t, tokenType);
}
}
vocabFileST.add("tokens", tokens);
// now dump the strings
Map literals = new LinkedHashMap();
for (String literal : g.stringLiteralToTypeMap.keySet()) {
int tokenType = g.stringLiteralToTypeMap.get(literal);
if ( tokenType>=Token.MIN_USER_TOKEN_TYPE) {
literals.put(literal, tokenType);
}
}
vocabFileST.add("literals", literals);
return vocabFileST;
}
public void writeRecognizer(ST outputFileST, boolean header) {
getTarget().genFile(g, outputFileST, getRecognizerFileName(header));
}
public void writeListener(ST outputFileST, boolean header) {
getTarget().genFile(g, outputFileST, getListenerFileName(header));
}
public void writeBaseListener(ST outputFileST, boolean header) {
getTarget().genFile(g, outputFileST, getBaseListenerFileName(header));
}
public void writeVisitor(ST outputFileST, boolean header) {
getTarget().genFile(g, outputFileST, getVisitorFileName(header));
}
public void writeBaseVisitor(ST outputFileST, boolean header) {
getTarget().genFile(g, outputFileST, getBaseVisitorFileName(header));
}
public void writeVocabFile() {
// write out the vocab interchange file; used by antlr,
// does not change per target
ST tokenVocabSerialization = getTokenVocabOutput();
String fileName = getVocabFileName();
if ( fileName!=null ) {
getTarget().genFile(g, tokenVocabSerialization, fileName);
}
}
public void write(ST code, String fileName) {
try {
// long start = System.currentTimeMillis();
Writer w = tool.getOutputFileWriter(g, fileName);
STWriter wr = new AutoIndentWriter(w);
wr.setLineWidth(lineWidth);
code.write(wr);
w.close();
// long stop = System.currentTimeMillis();
}
catch (IOException ioe) {
tool.errMgr.toolError(ErrorType.CANNOT_WRITE_FILE,
ioe,
fileName);
}
}
public String getRecognizerFileName() { return getRecognizerFileName(false); }
public String getListenerFileName() { return getListenerFileName(false); }
public String getVisitorFileName() { return getVisitorFileName(false); }
public String getBaseListenerFileName() { return getBaseListenerFileName(false); }
public String getBaseVisitorFileName() { return getBaseVisitorFileName(false); }
public String getRecognizerFileName(boolean header) { return getTarget().getRecognizerFileName(header); }
public String getListenerFileName(boolean header) { return getTarget().getListenerFileName(header); }
public String getVisitorFileName(boolean header) { return getTarget().getVisitorFileName(header); }
public String getBaseListenerFileName(boolean header) { return getTarget().getBaseListenerFileName(header); }
public String getBaseVisitorFileName(boolean header) { return getTarget().getBaseVisitorFileName(header); }
/** What is the name of the vocab file generated for this grammar?
* Returns null if no .tokens file should be generated.
*/
public String getVocabFileName() {
return g.name+VOCAB_FILE_EXTENSION;
}
public String getHeaderFileName() {
ST extST = getTemplates().getInstanceOf("headerFileExtension");
if ( extST==null ) return null;
String recognizerName = g.getRecognizerName();
return recognizerName+extST.render();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy