jay*_*lps 8 java parsing antlr llvm abstract-syntax-tree
我似乎正在努力解决AST-> StringTemplate方面的问题,可能是因为我来自手工编写解析器 - > LLVM.
我正在寻找的是一种自动将解析规则与可以表示它的AST类匹配的方法,并且包含生成目标语言输出的方法.(在这种情况下可能使用StringTemplate.)
在伪代码中,给出了这个示例语法:
numberExpression
: DIGIT+
;
Run Code Online (Sandbox Code Playgroud)
我想让它映射到这个AST类:
class NumberExpressionAST extends BaseAST {
private double value;
public NumberExpressionAST(node) {
this.value = node.value;
}
public String generateCode() {
// However we want to generate the output.
// Maybe use a template, maybe string literals, maybe cure cancer...whatever.
}
}
Run Code Online (Sandbox Code Playgroud)
为了交配它们,也许会有一些胶水如下:(或者你可能会疯狂的Class.forName东西)
switch (child.ruleName) {
case 'numberExpression':
return new NumberExpressionAST(child);
break;
}
Run Code Online (Sandbox Code Playgroud)
我一直在网上搜索,我在语法中找到了解析重写规则,->但我似乎无法弄清楚如何将所有这些逻辑排除在语法之外.特别是从模板设置和生成目标输出的代码.我可以多次走树了.
我想也许我可以使用该选项output=AST,然后可能提供我自己的从CommonTree扩展的AST类?我承认,我对ANTLR的把握非常原始,所以请原谅我的无知.我所遵循的每个教程都显示了所有这些内容与语法内联,这对我来说是完全疯狂和难以维护的.
有人能指出我一种完成类似事情的方法吗?
目标:保持AST/codegen /模板逻辑不受语法限制.
编辑---------------------------------------------
我使出通过ANTLR的实际源代码跟踪(因为他们使用自己),我看到这样类似的事情BlockAST,RuleAST等全部继承CommonTree.我还没有弄清楚重要的部分......他们是如何使用它们的......
从环顾四周,我注意到你基本上可以输入提示标记:
identifier
: IDENTIFIER<AnyJavaClassIWantAST>
;
Run Code Online (Sandbox Code Playgroud)
对于解析规则,您不能完全相同...但是如果您创建一些令牌来表示整个解析规则,则可以使用重写规则,如下所示:
declaration
: type identifier -> SOME_PARSE_RULE<AnyJavaClassIWantAST>
;
Run Code Online (Sandbox Code Playgroud)
所有这一切都更接近我想要的,但理想情况下我不应该乱丢语法......有没有办法将这些放在其他地方?
你能补充一下作为答案......
这是一个人为的例子,它使用了一些ANTLR4的功能,这些功能在很大程度上将语法与输出语言分开,主要是替代标签和生成的监听器.这个示例语法可以代表一些简单的代码,但它没有语言引用 - 甚至没有调用skip()lexer中的空格.测试类使用生成的侦听器将输入转换为某些Java输出.
我避免使用任何我在前几次尝试中无法工作的东西,所以不要以任何方式认为这是一个详尽的例子.
grammar Simplang;
compilationUnit : statements EOF;
statements : statement+;
statement : block #BlockStatement
| call #CallStatement
| decl #DeclStatement
;
block : LCUR statements RCUR;
call : methodName LPAR args=arglist? RPAR SEMI;
methodName : ID;
arglist : arg (COMMA arg)*;
arg : expr;
decl : VAR variableName EQ expr SEMI;
variableName : ID;
expr : add_expr;
add_expr : lhs=primary_expr (add_op rhs=primary_expr)*;
add_op : PLUS | MINUS;
primary_expr : string=STRING
| id=ID
| integer=INT
;
VAR: 'var';
ID: ('a'..'z'|'A'..'Z')+;
INT: ('0'..'9')+;
STRING: '\'' ~('\r'|'\n'|'\'')* '\'';
SEMI: ';';
LPAR: '(';
RPAR: ')';
LCUR: '{';
RCUR: '}';
PLUS: '+';
MINUS: '-';
COMMA: ',';
EQ: '=';
WS: (' '|'\t'|'\f'|'\r'|'\n') -> skip;
Run Code Online (Sandbox Code Playgroud)
与词法分析器和解析器一起,ANTLR4生成一个侦听器接口和默认的空实现类.这是为上面的语法生成的界面.
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);
}
Run Code Online (Sandbox Code Playgroud)
这是一个测试类,它覆盖空侦听器中的一些方法并调用解析器.
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();
}
}
Run Code Online (Sandbox Code Playgroud)
这是测试类中硬编码的测试输入:
var x = 4;
foo(x, 10);
bar(y + 10 - 1, 'x' + 'y' + 'z');
Run Code Online (Sandbox Code Playgroud)
这是产生的输出:
define("x", 4);
call("foo", new Object[]{read("x"), 10, });
call("bar", new Object[]{read("y") + 10 - 1, "x" + "y" + "z", });
Run Code Online (Sandbox Code Playgroud)
这是一个愚蠢的例子,但它显示了一些在构建自定义AST时可能对您有用的功能.
| 归档时间: |
|
| 查看次数: |
3237 次 |
| 最近记录: |