- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我似乎在 AST->StringTemplate 方面苦苦挣扎,可能是因为我来自手工编写解析器 -> LLVM。
我正在寻找的是一种自动将解析规则与可以表示它的 AST 类匹配并包含生成目标语言输出的方法的方法。 (在这种情况下可能使用 StringTemplate。)
在伪代码中,给出这个示例语法:
numberExpression
: DIGIT+
;
我想把它映射到这个 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.
}
}
为了将它们结合起来,也许会有如下所示的胶水:(或者你可能会疯狂使用 Class.forName
东西)
switch (child.ruleName) {
case 'numberExpression':
return new NumberExpressionAST(child);
break;
}
我一直在网上搜索,我发现语法中有 ->
解析重写规则,但我似乎无法弄清楚如何将所有这些逻辑排除在语法之外。特别是从模板设置和生成目标输出的代码。我可以多次在树上行走。
我想也许我可以使用选项 output=AST
然后提供我自己的从 CommonTree 扩展的 AST 类?我承认,我对 ANTLR 的掌握非常原始,请原谅我的无知。我遵循的每个教程都展示了按照对我的语法进行所有这些操作是完全疯狂且难以维护的。
有人能告诉我完成类似事情的方法吗?
目标:将 AST/代码生成/模板逻辑排除在语法之外。
编辑----------------------------------------
我求助于追踪 ANTLR 的实际源代码(因为它们使用自己),我看到类似的东西,如 BlockAST
、RuleAST
等,它们都继承自普通树
。我还没有完全弄清楚重要的部分……他们是如何使用它们的……
环顾四周,我注意到您基本上可以输入提示标记:
identifier
: IDENTIFIER<AnyJavaClassIWantAST>
;
您不能对解析规则做完全相同的事情...但是如果您创建一些标记来表示整个解析规则,您可以像这样使用重写规则:
declaration
: type identifier -> SOME_PARSE_RULE<AnyJavaClassIWantAST>
;
所有这些都更接近我想要的,但理想情况下我不应该乱扔语法......有什么办法可以把它们放在其他地方吗?
最佳答案
Could you add this as an answer...
这是一个人为的例子,它使用了一些 ANTLR4 的特性,这些特性在将语法与输出语言(主要是 alternative labels)分离方面大有帮助。和生成的监听器。这个示例语法可以表示一些微不足道的代码,但它没有语言引用——甚至没有调用 skip()
来获取词法分析器中的空格。测试类使用生成的监听器将输入转换为一些 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;
连同词法分析器和解析器,ANTLR4 生成一个监听器接口(interface)和默认的空实现类。这是为上面的语法生成的接口(interface)。
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", });
这是一个愚蠢的示例,但它展示了一些在构建自定义 AST 时可能对您有用的功能。
关于java - 将 ANTLR 解析规则映射到用于代码生成的自定义 Java AST 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13577328/
请看一下我的代码。 int main () { Program* allcommand = new Program; allcommand->addCommand("add", new
因此,当我遇到调试断言时,我正在编写代码。现在我很想知道为什么这段代码不起作用: for(Model::MeshMap::iterator it = obj1->GetMeshes().begin()
这是我上一个问题的延续 Group, Sum byType then get diff using Java streams . 按照建议,我应该作为单独的线程发布,而不是更新原始线程。 因此,通过我
我正在实现一些非常适合 map 的代码。但是,我要迭代的列表中有大量对象,所以我的问题是哪种方法是解决此问题的最佳方法: var stuff = $.map(listOfMyObjects, some
我正在尝试创建一个包含不同类的成员函数指针的映射。成员函数都具有相同的签名。为了做到这一点,我所有的类都继承了一个 Object 类,它只有默认构造函数、虚拟析构函数和一个虚拟 ToString()
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: how do you make a heterogeneous boost::map? 有可能在 C++ 中
我有一个 Mysql 查询,请检查以下内容: SELECT `tbl_classSubjects`.`classID` , `tbl_classSubjects`.`sectionID` , `tbl
抱歉,这可能是一个基本问题。 JNA直接映射和接口(interface)映射有什么区别? 我的解释是否正确: 直接映射 : 直接使用库对象(如 Java 中的静态 main) 接口(interface
在 Twitter's Scala school collections section ,它们显示了一个带有偏函数作为值的 Map: // timesTwo() was defined earlie
很难说出这里问的是什么。这个问题是模棱两可的、模糊的、不完整的、过于宽泛的或修辞的,无法以目前的形式得到合理的回答。如需帮助澄清这个问题以便重新打开它,visit the help center .
据我了解,从 scala stdlib 声明一个映射并没有将其专门用于原始类型。我要的不是付出装箱/拆箱的代价,而是同时拥有scala map 的接口(interface)。一个明显的选择是使用 tr
如何为这样的 JSON 响应创建对象映射,它只是一个整数数组: [ 565195, 565309, 565261, 565515, 565292, 565281, 566346, 5
是否可以为 DTO 对象创建映射然后查询它们 而不是域?如果不解释为什么? 如果我需要几个 dtos 怎么办? DTos 是只读的 ID 由 NH 自动生成 将来这些 dtos 将设置映射到链接的 d
我有一个返回的函数(常规代码) [words: "one two", row: 23, col: 45] 在 Scala 中,我将上面更改为 Scala Map,但随后我被迫将其声明为 Map[Str
我有一组与 Vanilla 磅蛋糕烘焙相关的数据(200 行),具有 27 个特征,如下所示。标签caketaste是衡量烤蛋糕的好坏程度,由 bad(0) 定义, neutral(1) , good
我有试图映射到新代码的遗留代码。 OLD_PERSON pid sid name age NEW_PERSON pid sid fid age RESOLVE_PERSON pid fid statu
我有一个表,其中一个字段可以指向其他 3 个表之一中的外键,具体取决于鉴别器值是什么(Project、TimeKeep 或 CostCenter。通常这是用子类实现的,我想知道我有什么 注意子类名称与
我有一个类型 [ST s (Int, [Int])] 的绑定(bind)我正在尝试申请runST使用映射到每个元素,如下所示: name :: [ST s (Int, [Int])] --Of Cou
在我正在进行的项目中,我有以下实体:分析师、客户 和承包商。每个都继承自基类 User。 public abstract class User { public virtual int Id
我想知道是否可以在 Vim 中创建一个映射(对于普通模式),允许用户在映射执行之前输入。 我想为我最常用的 grep 命令创建一个快捷方式的映射。我希望命令允许输入我正在搜索的内容,然后在输入时执行。
我是一名优秀的程序员,十分优秀!