我想标记一些二进制数据,其中某些部分的长度取决于前一个标记的值。你可以这样想:
<length><binary data>
假设长度是两个字节的无符号整数,表示以字节为单位的二进制数据的长度。
如何使用 ANTLR 4 实现这种相关性?
最佳答案
您可能需要扩展 ANTLR 的输入流。截至目前,唯一的输入流, ANTLRInputStream
和 ANTLRFileStream
, 由 char[]
支持这可能不适合您匹配任何类型的二进制数据的要求。
要按照您的描述使词法分析器上下文敏感,您可以:
UNSIGNED
数字标记,一旦匹配,用这个值初始化一个实例变量( bytesToConsume
); bytesToConsume
已设置,只要此 bytesToConsume
消耗字节/字符大于0! bytesToConsume
已经初始化,不想匹配UNSIGNED
token ! !这些检查由 semantic predicates 执行
{boolean-expression}?
.一个演示:
grammar T;
@lexer::members {
private int bytesToConsume = -1;
boolean binary() {
if(bytesToConsume < 0) {
return false;
}
bytesToConsume--;
return true;
}
}
parse
: block* EOF
;
block
: UNSIGNED BINARY
;
UNSIGNED
: {!binary()}?
[0-9a-fA-F] [0-9a-fA-F] {bytesToConsume = Integer.parseInt(getText(), 16);}
;
BINARY
: ({binary()}? . )+
;
一个驱动程序类:
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
public class Main {
public static void main(String[] args) throws Exception {
TLexer lexer = new TLexer(new ANTLRInputStream("03aaa0Fbbbbbbbbbbbbbbb01c"));
TParser parser = new TParser(new CommonTokenStream(lexer));
ParseTree tree = parser.parse();
System.out.println(tree.toStringTree(parser));
}
}
通过执行以下操作来测试它:
*尼克斯
java -jar antlr-4.0-complete.jar T.g4 javac -cp .:antlr-4.0-complete.jar *.java java -cp .:antlr-4.0-complete.jar Main
Windows
java -jar antlr-4.0-complete.jar T.g4 javac -cp .;antlr-4.0-complete.jar *.java java -cp .;antlr-4.0-complete.jar Main
And you'll see the following being printed to the console (I added indentation though):
(parse
(block 03 aaa)
(block 0F bbbbbbbbbbbbbbb)
(block 01 c)
<EOF>)
编辑
也许可以通过使用 ANTLR4 的 lexical modes 来做一些更清洁的事情。 .但是,我对 v4 还是很陌生,我不知道这是否可行,因为一旦消耗了一定数量的字节/字符,您就想回到默认词法范围,而不是在 BINARY 模式中明确结束.
关于antlr - 如何将一个 token 的长度取决于另一个 token 的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15348045/