问题
I’m looking at pragmatically translating huge amounts of relatively simple TSQL code to Groovy code. There are a number of reasons sure, but the driving reason is just to see if it can be done and in the process learn about compilers/grammers/ etc.
Antlr4 seems like the ideal tool for this problem (Java is a plus).
Tokenizing / parsing the TSQL (using a grammar file), and reading the tree using the generated Listener/Visitor is pretty straight forward.
I know I could just create the string representation of the Groovy code inside of my inherited visitor, but coupling the matching Groovy token values with my TSQLVisitor doesn’t seem like the cleanest solution.
What would be considered the best practice here? and in general for mapping one language to another in Antlr4 ?
Things I’m considering:
- Using StringTemplate, and defining my groovy code in an STG file (my TSQLVisitor would use these templates and return the full string representation of the Groovy code).
- Switch to Antlr3 which supports adding StringTemplate logic directly into the Grammar file.
回答1:
Best practices depends on your objective. Where the conversion must not introduce or must minimize any added technical baggage or performance or maintenance overhead, then Ira's comments control.
If, however, performance and maintenance are not essential issues, the conversion is close to 1:1 semantically, and you have the ability to add run-time support code in the target environment, then an Antlr4 style conversion becomes possible. Of course, the greater the semantic differences between the source and target languages the more difficult it becomes - the size and complexity of the target run-time support lib becomes counter-productive. And, it only takes one deep-seated difference to drive a requirement for an analysis tool like Ira has developed.
Presuming an adequate Groovy lib has been developed, production of the target code is reduced to near one-liner's called for from the visitor onEntry and onExit routines. Coupling can be reduced somewhat by abstracting the rendering:
public class Render {
private static final String templateDir = "some/path/to/templates";
private STGroupFile blocksGroup;
private STGroupFile stmtGroup;
public Render() {
blocksGroup = new STGroupFile(Strings.concatAsClassPath(templateDir, "Blocks.stg"));
stmtGroup = new STGroupFile(Strings.concatAsClassPath(templateDir, "Statements.stg"));
}
public String gen(GenType type, String name) {
return gen(type, name, null);
}
/**
* type is an enum, identifying the group template
* name is the template name within the group
* varMap contains the named values to be passed to the template
*/
public String gen(GenType type, String name, Map<String, Object> varMap) {
Log.debug(this, name);
STGroupFile stf = null;
switch (type) {
case BLOCK:
stf = blocksGroup;
break;
case STMT:
stf = stmtGroup;
break;
}
ST st = stf.getInstanceOf(name);
if (varMap != null) {
for (String varName : varMap.keySet()) {
try {
st.add(varName, varMap.get(varName));
} catch (NullPointerException e) {
Log.error(this, "Error adding attribute: " + name + ":" + varName + " [" + e.getMessage() + "]");
}
}
}
return st.render();
}
}
来源:https://stackoverflow.com/questions/29201861/antlr4-language-translation-separating-template-logic-from-visitor-class