将ANTLR解析规则映射到自定义JavaAST类以生成代码
我似乎在努力解决AST->StringTemplate方面的问题,可能是因为我是从手工编写解析器->LLVM开始的 我要寻找的是一种将解析规则自动匹配到AST类的方法,该AST类可以表示解析规则,并包含生成目标语言输出的方法。(在本例中,可能使用StringTemplate。) 在伪代码中,给出以下示例语法:将ANTLR解析规则映射到自定义JavaAST类以生成代码,java,parsing,antlr,llvm,abstract-syntax-tree,Java,Parsing,Antlr,Llvm,Abstract Syntax Tree,我似乎在努力解决AST->StringTemplate方面的问题,可能是因为我是从手工编写解析器->LLVM开始的 我要寻找的是一种将解析规则自动匹配到AST类的方法,该AST类可以表示解析规则,并包含生成目标语言输出的方法。(在本例中,可能使用StringTemplate。) 在伪代码中,给出以下示例语法: numberExpression : DIGIT+ ; 我想将其映射到此AST类: 类号pressionast扩展了BaseAST{ 私人双重价值; 公号pression
numberExpression
: DIGIT+
;
我想将其映射到此AST类:
类号pressionast扩展了BaseAST{
私人双重价值;
公号pressionast(节点){
this.value=node.value;
}
公共字符串generateCode(){
//但是,我们希望生成输出。
//也许使用模板,也许字符串文字,也许治愈癌症…随便什么。
}
}
为了配合它们,可能会有如下胶水:(或者你可能会对Class.forName
之类的东西发疯)
我一直在浏览网页,在语法中找到了解析重写规则,使用->
,但我似乎不知道如何将所有这些逻辑排除在语法之外。特别是从模板设置和生成目标输出的代码。我可以在树上走几次
我想也许我可以使用选项output=AST
,然后提供我自己的从CommonTree扩展的AST类?我承认,我对ANTLR的理解非常原始,所以请原谅我的无知。我跟随的每一个教程都展示了如何按照语法来做这些事情,这对我来说是完全疯狂的,而且很难维护
有人能给我指出一种完成类似事情的方法吗
目标:将AST/codegen/template逻辑排除在语法之外 编辑--------------------------------------------- 我已经求助于跟踪ANTLR的实际源代码(因为它们自己使用),我看到类似的东西,如
BlockAST
,RuleAST
,等等,都是从CommonTree
继承的。我还没有弄清楚重要的部分…他们是如何使用它们的
环顾四周,我注意到您基本上可以键入提示标记:
identifier
: IDENTIFIER<AnyJavaClassIWantAST>
;
标识符
:标识符
;
您不能对解析规则执行完全相同的操作…但是如果您创建一些令牌来表示整个解析规则,您可以使用如下的重写规则:
declaration
: type identifier -> SOME_PARSE_RULE<AnyJavaClassIWantAST>
;
声明
:type identifier->SOME\u PARSE\u规则
;
所有这些都接近我想要的,但理想情况下,我不应该乱扔语法…有没有办法把这些放在其他地方
你能加上这个作为回答吗
下面是一个精心设计的示例,它使用了ANTLR4的一些特性,这些特性在将语法与输出语言(主要是输出语言和生成的侦听器)分离方面有很大的帮助。这个示例语法可以表示一些琐碎的代码,但它不需要语言引用,甚至不需要调用skip()
来查找lexer中的空白。测试类使用生成的侦听器将输入转换为一些Java输出
我避免在第一次尝试中使用任何我不能得到的东西,所以无论如何不要认为这是一个详尽的例子。
辛普朗
与lexer和解析器一起,ANTLR4生成一个监听器接口和默认的空实现类。下面是为上述语法生成的接口
SimpleListener.java
下面是一个测试类,它重写空侦听器中的一些方法并调用解析器
SimplangTest.java
以下是测试类中硬编码的测试输入:
var x = 4;
foo(x, 10);
bar(y + 10 - 1, 'x' + 'y' + 'z');
以下是生成的输出:
define("x", 4);
call("foo", new Object[]{read("x"), 10, });
call("bar", new Object[]{read("y") + 10 - 1, "x" + "y" + "z", });
这是一个愚蠢的例子,但它展示了一些在构建自定义AST时可能对您有用的功能。“目标:将AST/codegen/template逻辑排除在语法之外…[I]我真的不应该浪费语法…”听起来您想要ANTLR的所有好处,而不是ANTLR的任何好处我认为你唯一真正的选择是编写你自己的语法分析器,按照你的方式来做,或者咬紧牙关,按照设计使用ANTLR:使用生成的代码,在语法中指定AST类型,等等。我明白你的意思,尽管我的“目标”可能有点过于直白。ANTLR当然不仅仅是解析的语法语法,所以我当然想利用它的其他特性,但是从实际语法规则本身进行某种程度的抽象会更好。我认为我的
标识符:标识符我发现的代码>功能非常适合我。如果您愿意切换到ANTLR 4,您可以使用its更接近您的目标,它会变成由生成的代码触发的侦听器事件。在这一点上,我对它们的了解还不够,无法给出一个完整的答案,但它确实看起来像是一个不错的语言中立抽象层。@tenterhook非常酷。你能加上这个作为回答吗?我很乐意接受?谢谢大家!@巴特基,你太好了D
public interface SimplangListener extends ParseTreeListener {
void enterArglist(SimplangParser.ArglistContext ctx);
void exitArglist(SimplangParser.ArglistContext ctx);
void enterCall(SimplangParser.CallContext ctx);
void exitCall(SimplangParser.CallContext ctx);
void enterCompilationUnit(SimplangParser.CompilationUnitContext ctx);
void exitCompilationUnit(SimplangParser.CompilationUnitContext ctx);
void enterVariableName(SimplangParser.VariableNameContext ctx);
void exitVariableName(SimplangParser.VariableNameContext ctx);
void enterBlock(SimplangParser.BlockContext ctx);
void exitBlock(SimplangParser.BlockContext ctx);
void enterExpr(SimplangParser.ExprContext ctx);
void exitExpr(SimplangParser.ExprContext ctx);
void enterPrimary_expr(SimplangParser.Primary_exprContext ctx);
void exitPrimary_expr(SimplangParser.Primary_exprContext ctx);
void enterAdd_expr(SimplangParser.Add_exprContext ctx);
void exitAdd_expr(SimplangParser.Add_exprContext ctx);
void enterArg(SimplangParser.ArgContext ctx);
void exitArg(SimplangParser.ArgContext ctx);
void enterAdd_op(SimplangParser.Add_opContext ctx);
void exitAdd_op(SimplangParser.Add_opContext ctx);
void enterStatements(SimplangParser.StatementsContext ctx);
void exitStatements(SimplangParser.StatementsContext ctx);
void enterBlockStatement(SimplangParser.BlockStatementContext ctx);
void exitBlockStatement(SimplangParser.BlockStatementContext ctx);
void enterCallStatement(SimplangParser.CallStatementContext ctx);
void exitCallStatement(SimplangParser.CallStatementContext ctx);
void enterMethodName(SimplangParser.MethodNameContext ctx);
void exitMethodName(SimplangParser.MethodNameContext ctx);
void enterDeclStatement(SimplangParser.DeclStatementContext ctx);
void exitDeclStatement(SimplangParser.DeclStatementContext ctx);
void enterDecl(SimplangParser.DeclContext ctx);
void exitDecl(SimplangParser.DeclContext ctx);
}
public class SimplangTest {
public static void main(String[] args) {
ANTLRInputStream input = new ANTLRInputStream(
"var x = 4;\nfoo(x, 10);\nbar(y + 10 - 1, 'x' + 'y' + 'z');");
SimplangLexer lexer = new SimplangLexer(input);
SimplangParser parser = new SimplangParser(new CommonTokenStream(lexer));
parser.addParseListener(new SimplangBaseListener() {
public void exitArg(SimplangParser.ArgContext ctx) {
System.out.print(", ");
}
public void exitCall(SimplangParser.CallContext call) {
System.out.print("})");
}
public void exitMethodName(SimplangParser.MethodNameContext ctx) {
System.out.printf("call(\"%s\", new Object[]{", ctx.ID()
.getText());
}
public void exitCallStatement(SimplangParser.CallStatementContext ctx) {
System.out.println(";");
}
public void enterDecl(SimplangParser.DeclContext ctx) {
System.out.print("define(");
}
public void exitVariableName(SimplangParser.VariableNameContext ctx) {
System.out.printf("\"%s\", ", ctx.ID().getText());
}
public void exitDeclStatement(SimplangParser.DeclStatementContext ctx) {
System.out.println(");");
}
public void exitAdd_op(SimplangParser.Add_opContext ctx) {
if (ctx.MINUS() != null) {
System.out.print(" - ");
} else {
System.out.print(" + ");
}
}
public void exitPrimary_expr(SimplangParser.Primary_exprContext ctx) {
if (ctx.string != null) {
String value = ctx.string.getText();
System.out.printf("\"%s\"",
value.subSequence(1, value.length() - 1));
} else if (ctx.altNum == 2){ //cheating and using the alt# for "INT"
System.out.printf("read(\"%s\")", ctx.id.getText());
} else {
System.out.print(ctx.INT().getText());
}
}
});
parser.compilationUnit();
}
}
var x = 4;
foo(x, 10);
bar(y + 10 - 1, 'x' + 'y' + 'z');
define("x", 4);
call("foo", new Object[]{read("x"), 10, });
call("bar", new Object[]{read("y") + 10 - 1, "x" + "y" + "z", });