我试图理解ANTLR中的树构造运算符(^和!)。
我有一个用于灵活字节数组(一个UINT16,描述数组中的字节数,后跟这么多个字节)的语法。我已经将所有的语义断言及其关联的代码注释掉了,以验证数组中是否有与第前两个字节指示的一样多字节...这部分不是我遇到问题的部分。
我的问题在于解析一些输入后生成的树。所有发生的就是每个字符都是兄弟节点。我预期生成的AST树应该与ANTLRWorks 1.4中的Interpreter窗口中可以看到的树类似。一旦我尝试使用^字符更改如何制作树,我就会得到以下形式的异常:
Unhandled Exception: System.SystemException: more than one node as root (TODO: make exception hierarchy)
这里是该语法的概述(目前针对C#):
grammar FlexByteArray_HexGrammar;
options
{
//language = 'Java';
language = 'CSharp2';
output=AST;
}
expr
: array_length remaining_data
//the amount of remaining data must be equal to the array_length (times 2 since 2 hex characters per byte)
// need to check if the array length is zero first to avoid checking $remaining_data.text (null reference) in that situation.
//{ ($array_length.value == 0 && $remaining_data.text == null) || ($remaining_data.text != null && $array_length.value*2 == $remaining_data.text.Length) }?
;
array_length //returns [UInt16 value]
: uint16_little //{ $value = $uint16_little.value; }
;
hex_byte1 //needed just so I can distinguish between two bytes in a uint16 when doing a semantic predicate (or whatever you call it where I write in the target language in curly brackets)
: hex_byte
;
uint16_big //returns [UInt16 value]
: hex_byte1 hex_byte //{ $value = Convert.ToUInt16($hex_byte.text + $hex_byte1.text); }
;
uint16_little //returns [UInt16 value]
: hex_byte1 hex_byte //{ $value = Convert.ToUInt16($hex_byte1.text + $hex_byte.text); }
;
remaining_data
: hex_byte*
;
hex_byte
: HEX_DIGIT HEX_DIGIT
;
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F')
;
以下是我对AST的大致理解:
以下是我用C#编写的程序,可以通过GraphViz生成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#)。
import org.antlr.*;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
public class Program
{
public static void main(String[] args) throws Exception
{
FlexByteArray_HexGrammarLexer lex = new FlexByteArray_HexGrammarLexer(new ANTLRStringStream("0001ff"));
CommonTokenStream tokens = new CommonTokenStream(lex);
FlexByteArray_HexGrammarParser parser = new FlexByteArray_HexGrammarParser(tokens);
System.out.println("Parser created.");
CommonTree tree = (CommonTree)parser.expr().tree;
System.out.println("------Input parsed-------");
if (tree == null)
{
System.out.println("Tree is null.");
}
else
{
DOTTreeGenerator treegen = new DOTTreeGenerator();
System.out.println(treegen.toDOT(tree));
}
}
}
{ ... }?=>
被称为 _门控语义谓词_。请查看 更多信息 下的第一个链接以了解其工作原理。当然欢迎你,你发布了一个非常好的、详细的问题,包括 Java 和 C# 代码示例。我希望所有的问题都像你的一样! - Bart Kiers