ANTLR-获取AST层次结构设置时遇到问题
我正试图了解ANTLR中的树构造操作员(^和!) 我有一个flex字节数组的语法(UINT16描述数组中的字节数,后跟这么多字节)。我已经注释掉了所有语义谓词及其关联代码,这些代码确实验证了数组中的字节数是否与前两个字节所指示的字节数相同……这部分不是我遇到的问题 我的问题是解析某些输入后生成的树。所发生的只是每个角色都是一个同级节点。我希望生成的AST类似于您可以在AntlWorks 1.4的解释器窗口中看到的树。当我尝试更改使用^character创建树的方式时,我得到一个例外:ANTLR-获取AST层次结构设置时遇到问题,antlr,abstract-syntax-tree,antlrworks,Antlr,Abstract Syntax Tree,Antlrworks,我正试图了解ANTLR中的树构造操作员(^和!) 我有一个flex字节数组的语法(UINT16描述数组中的字节数,后跟这么多字节)。我已经注释掉了所有语义谓词及其关联代码,这些代码确实验证了数组中的字节数是否与前两个字节所指示的字节数相同……这部分不是我遇到的问题 我的问题是解析某些输入后生成的树。所发生的只是每个角色都是一个同级节点。我希望生成的AST类似于您可以在AntlWorks 1.4的解释器窗口中看到的树。当我尝试更改使用^character创建树的方式时,我得到一个例外: Unhan
Unhandled Exception: System.SystemException: more than one node as root (TODO: make exception hierarchy)
以下是语法(目前针对C#):
以下是我所认为的AST:
这是C#中的程序,我用它来获得AST的视觉(实际上是文本的,但后来我通过图形来获得图片)表示:
namespace FlexByteArray_Hex
{
using System;
using Antlr.Runtime;
using Antlr.Runtime.Tree;
using Antlr.Utility.Tree;
public class Program
{
public static void Main(string[] args)
{
ICharStream input = new ANTLRStringStream("0001ff");
FlexByteArray_HexGrammarLexer lex = new FlexByteArray_HexGrammarLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lex);
FlexByteArray_HexGrammarParser parser = new FlexByteArray_HexGrammarParser(tokens);
Console.WriteLine("Parser created.");
CommonTree tree = parser.expr().Tree as CommonTree;
Console.WriteLine("------Input parsed-------");
if (tree == null)
{
Console.WriteLine("Tree is null.");
}
else
{
DOTTreeGenerator treegen = new DOTTreeGenerator();
Console.WriteLine(treegen.ToDOT(tree));
}
}
}
}
下面是该程序在GraphViz中的输出:
Java中的相同程序(以防您想试用它而不使用C#):
Ansss写道:
当我尝试更改使用^character创建树的方式时,我得到一个例外:
Unhandled Exception: System.SystemException: more than one node as root (TODO: make exception hierarchy)
当试图使解析器规则a
成为p
中树的根时,如下所示:
p : a^ b;
a : A A;
b : B B;
ANTLR不知道A
中的哪个是规则A
的根。当然,不可能有两个根
内联树操作符在某些情况下很方便,但在这种情况下,它们无法完成任务。您不能在可能没有内容的生产规则(如剩余\u数据
规则)内分配根。在这种情况下,您需要在语法的tokens{…}
部分中创建“虚构的标记”,并使用重写规则(->^(…)
)创建AST
演示
以下语法:
grammar FlexByteArray_HexGrammar;
options {
output=AST;
}
tokens {
ROOT;
ARRAY;
LENGTH;
DATA;
}
expr
: array* EOF -> ^(ROOT array*)
;
array
@init { int index = 0; }
: array_length array_data[$array_length.value] -> ^(ARRAY array_length array_data)
;
array_length returns [int value]
: a=hex_byte b=hex_byte {$value = $a.value*16*16 + $b.value;} -> ^(LENGTH hex_byte hex_byte)
;
array_data [int length]
: ({length > 0}?=> hex_byte {length--;})* {length == 0}? -> ^(DATA hex_byte*)
;
hex_byte returns [int value]
: a=HEX_DIGIT b=HEX_DIGIT {$value = Integer.parseInt($a.text+$b.text, 16);}
;
HEX_DIGIT
: '0'..'9' | 'a'..'f' | 'A'..'F'
;
将分析以下输入:
0001ff0002abcd
进入以下步骤:
如您所见,使用以下主类:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
FlexByteArray_HexGrammarLexer lexer = new FlexByteArray_HexGrammarLexer(new ANTLRStringStream("0001ff0002abcd"));
FlexByteArray_HexGrammarParser parser = new FlexByteArray_HexGrammarParser(new CommonTokenStream(lexer));
CommonTree tree = (CommonTree)parser.expr().getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}
更多信息
- 如果您想更多地了解我在
解析器规则中使用的谓词,请参阅前面的问答:array\u data
- 要获取有关树重写操作符
的更多信息,请参阅前面的问答:->^(…)
数组_数据
规则,请执行以下操作:
array_data [int length]
: ({length > 0}?=> hex_byte {length--;})* {length == 0}? -> ^(DATA hex_byte*)
;
正如您在注释中已经提到的,您可以通过在规则后添加[TYPE IDENTIFIER]
将一个或多个参数传递给规则
第一个(选通)语义谓词{length>0}?=>
,检查length
是否大于零。如果是这种情况,解析器将尝试匹配一个hex_字节
,之后长度
变量将减少一。当length
为零时,或者当解析器没有更多的hex_字节
要解析时,这一切都会停止,这在EOF下一行时发生。因为它可以解析的hex_字节数小于必需的s,所以在规则的最末端有一个(验证)语义谓词,{length==0}?
,它可以确保正确解析的hex_字节数(不多也不少!)
希望能进一步澄清。谢谢您的详细回答!我把谓词注释掉了,但没有删除它们,因为我有点希望ANTLR专家会告诉我它们是否有问题……你肯定改进了它们(我不知道你可以将参数传递到规则中,我有很多东西要学)!Tree rewrite操作符,我肯定也会对此进行研究(刚刚从PragProg.com购买了权威的ANTLR参考)。一个问题,“=>”运算符是什么?您在数组_数据规则的前提条件之后使用了它。@anssss,{…}?=>
称为选通语义谓词。签出“更多信息”下的第一个链接以查看其工作原理。当然,不客气,您发布了一个非常好的详细问题,包括示例Java和C代码。我希望所有的问题都像你的一样@Ansssss,另请参见我答案中的编辑。
array_data [int length]
: ({length > 0}?=> hex_byte {length--;})* {length == 0}? -> ^(DATA hex_byte*)
;