一个简单的例子:
(grammar):
stat: ID '=' expr NEWLINE -> ^('=' ID expr)
expr: atom '+' atom -> ^(+ atom atom)
atom: INT | ID
...
(input text): a = 3 + 5
“3 + 5”对应的 CommonTree 包含一个“+”标记和两个 child (3, 5)。
此时,恢复解析为这棵树 ('3 + 5') 的原始输入文本的最佳方法是什么?
我在 CommonTree
对象中得到了文本、位置和各个标记的行号,因此理论上可以确保仅丢弃空白标记并使用此信息将它们拼凑在一起, 但它看起来容易出错。
有更好的方法吗?
最佳答案
Is there a better way to do this?
更好,我不知道。当然, 还有另一种方法。您决定什么更好。
另一种选择是创建自定义 AST 节点类(和相应的节点适配器)并在解析期间将匹配的文本添加到该 AST 节点。这里的技巧是不使用 skip()
,它会从词法分析器中丢弃标记,而是将其放在 HIDDEN
channel 中。这实际上是相同的,但是,这些(隐藏的)标记匹配的文本在解析器中仍然可用。
快速演示:将所有这 3 个文件放在名为 demo
的目录中:
演示/T.g
grammar T;
options {
output=AST;
ASTLabelType=XTree;
}
@parser::header {
package demo;
import demo.*;
}
@lexer::header {
package demo;
import demo.*;
}
parse
: expr EOF -> expr
;
expr
@after{$expr.tree.matched = $expr.text;}
: Int '+' Int ';' -> ^('+' Int Int)
;
Int
: '0'..'9'+
;
Space
: ' ' {$channel=HIDDEN;}
;
演示/XTree.java
package demo;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
public class XTree extends CommonTree {
protected String matched;
public XTree(Token t) {
super(t);
matched = null;
}
}
演示/Main.java
package demo;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "12 + 42 ;";
TLexer lexer = new TLexer(new ANTLRStringStream(source));
TParser parser = new TParser(new CommonTokenStream(lexer));
parser.setTreeAdaptor(new CommonTreeAdaptor(){
@Override
public Object create(Token t) {
return new XTree(t);
}
});
XTree root = (XTree)parser.parse().getTree();
System.out.println("tree : " + root.toStringTree());
System.out.println("matched : " + root.matched);
}
}
您可以通过打开 shell 并 cd-ing 到包含 demo
目录的目录并执行以下命令来运行此演示:
java -cp demo/antlr-3.3.jar org.antlr.Tool demo/T.g javac -cp demo/antlr-3.3.jar demo/*.java java -cp .:demo/antlr-3.3.jar demo.Main
这将产生以下输出:
tree : (+ 12 42) matched : 12 + 42 ;
关于java - 在 antlr 中,有没有办法在 AST 模式下获取 CommonTree 的解析文本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12941718/