4

我想标记一些二进制数据,其中某些部分的长度取决于先前标记的值。你可以这样想:

<length><binary data>

假设长度是两个字节的无符号整数,表示二进制数据的长度(以字节为单位)。

如何使用 ANTLR 4 实现这种关联?

4

1 回答 1

1

您可能需要扩展 ANTLR 的输入流。到目前为止,唯一的输入流ANTLRInputStreamANTLRFileStream由 a 支持,char[]这可能不适合您匹配任何类型的二进制数据的要求。

如您所述,要使词法分析器上下文敏感,您可以:

  • 匹配一个UNSIGNED数字标记,一旦匹配,就bytesToConsume用这个值初始化一个实例变量();
  • 一旦bytesToConsume设置好,只要bytesToConsume大于 0 就消耗字节/字符
  • 当然,一旦bytesToConsume被初始化,你就不想匹配一个UNSIGNED令牌

这些检查由语义谓词 {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 主要

视窗

java -jar antlr-4.0-complete.jar T.g4
javac -cp .;antlr-4.0-complete.jar *.java
java -cp .;antlr-4.0-complete.jar 主要

您会看到以下内容被打印到控制台(虽然我添加了缩进):

(parse 
  (block 03 aaa) 
  (block 0F bbbbbbbbbbbbbbb) 
  (block 01 c) 
  <EOF>)

编辑

通过使用 ANTLR4 的词法模式,也许可以实现一些更简洁的东西。但是,我对 v4 很陌生,我不知道这是否可能,因为一旦消耗了一定数量的字节/字符而不是二进制模式中的明确结束,您想弹回默认词法范围.

于 2013-03-11T21:55:58.677 回答