以下甚至可能吗?我想“反转”给予antlr的输入并使每个标记成为前一个标记的子标记。
因此,对于输入(假设每个标记由'。'字符分隔):
Stack.Overflow.Horse
我希望我的语法产生以下AST:
Horse
|---Overflow
|---Stack
到目前为止,我已经成功地扭转了节点,但我无法让他们成为彼此的孩子:
function
: ID PERIOD function
-> function ID
| ID
;
ID : 'a'..'z'*
;
答案 0 :(得分:3)
我认为没有一种简单的方法可以做到这一点。你可以这样制定你的规则:
function
: ID PERIOD function
-> ^(function ID)
| ID
;
但这只会使最后一个节点成为根,所有其他节点成为子节点。例如,以下来源:
a.b.c.d.e
将导致以下树:
e
/ / \ \
d c b a
我无法看到一个简单的修复方法,因为当您第一次解析a.b.c.d.e
时,a
将ID
和b.c.d.e
递归调用function
:
a.b.c.d.e
| +-----+
| |
| `-----> function
|
`----------> ID
导致b.c.d.e
将a
作为其子级。当b
成为ID
时,它也会作为a
旁边的子项添加。在您的情况下,a
应该作为孩子删除,然后添加到b
的孩子列表中。但是AFAIK,这在ANLTR中是不可能的(至少,在语法中不是一个干净的方式)。
修改强>
好吧,作为一个解决方案,我有一些优雅的想法,但这并没有像我希望的那样工作。因此,作为一个不太优雅的解决方案,您可以将last
节点与重写规则中的根匹配:
function
: (id '.')* last=id -> ^($last)
;
然后使用children
运算符收集List
中所有可能的先前节点(+=
):
function
: (children+=id '.')* last=id -> ^($last)
;
并在解析器中使用自定义成员方法将这些children
“注入”到树的根目录中(在List
中从右到左!):
function
: (children+=id '.')* last=id {reverse($children, (CommonTree)$last.tree);} -> ^($last)
;
一个小小的演示:
grammar ReverseTree;
options {
output=AST;
}
tokens {
ROOT;
}
@members {
private void reverse(List nodes, CommonTree root) {
if(nodes == null) return;
for(int i = nodes.size()-1; i >= 0; i--) {
CommonTree temp = (CommonTree)nodes.get(i);
root.addChild(temp);
root = temp;
}
}
}
parse
: function+ EOF -> ^(ROOT function+)
;
function
: (children+=id '.')* last=id {reverse($children, (CommonTree)$last.tree);} -> ^($last)
;
id
: ID
;
ID
: ('a'..'z' | 'A'..'Z')+
;
Space
: ' ' {skip();}
;
还有一个小测试班:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("a.b.c.d.e Stack.Overflow.Horse singleNode");
ReverseTreeLexer lexer = new ReverseTreeLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ReverseTreeParser parser = new ReverseTreeParser(tokens);
ReverseTreeParser.parse_return returnValue = parser.parse();
CommonTree tree = (CommonTree)returnValue.getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}
将产生一个看起来像这样的AST:
输入字符串:
"a.b.c.d.e Stack.Overflow.Horse singleNode"