一个简单的例子:
(grammar):
stat: ID '=' expr NEWLINE -> ^('=' ID expr)
expr: atom '+' atom -> ^(+ atom atom)
atom: INT | ID
...
(input text): a = 3 + 5
Run Code Online (Sandbox Code Playgroud)
相应的'3 + 5'的CommonTree包含一个'+'标记和两个子标记(3,5).
此时,恢复解析为此树('3 + 5')的原始输入文本的最佳方法是什么?
我已经获得了CommonTree对象中单个标记的文本,位置和行号,因此从理论上讲,可以确保只丢弃空格标记并使用此信息将它们拼凑在一起,但它看起来容易出错.
有一个更好的方法吗?
有一个更好的方法吗?
更好,我不知道。当然还有另一种方法。你决定什么更好。
另一种选择是创建自定义 AST 节点类(以及相应的节点适配器),并在解析期间将匹配的文本添加到此 AST 节点。这里的技巧是不使用skip(),它会丢弃词法分析器中的令牌,而是将其放在通道上HIDDEN。这实际上是相同的,但是,这些(隐藏)标记匹配的文本在解析器中仍然可用。
一个快速演示:将所有这 3 个文件放在名为 的目录中demo:
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;}
;
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
您可以通过打开 shell 并 cd 到包含该demo目录的目录并执行以下命令来运行此演示:
java -cp demo/antlr-3.3.jar org.antlr.Tool demo/Tg javac -cp 演示/antlr-3.3.jar 演示/*.java java -cp .:demo/antlr-3.3.jar demo.Main
这将产生以下输出:
树:(+ 12 42) 匹配:12 + 42;
| 归档时间: |
|
| 查看次数: |
1124 次 |
| 最近记录: |