如何将一个标记的长度依赖于另一个标记的值?

时间:2013-03-11 20:32:17

标签: antlr binary-data antlr4

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

<length><binary data>

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

如何与ANTLR 4实现此关联?

1 个答案:

答案 0 :(得分:1)

您可能需要扩展ANTLR的输入流。截至目前,唯一的输入流ANTLRInputStreamANTLRFileStreamchar[]备份,可能不符合您匹配任何类型二进制数据的要求。

为了使你所描述的词法分析器上下文敏感,你可以:

  • 匹配UNSIGNED数字标记,一旦匹配,使用此值初始化实例变量(bytesToConsume);
  • 一旦设置了bytesToConsume,只要此bytesToConsume大于0 就消耗字节/字符!
  • 当然,只要bytesToConsume初始化,您就不希望匹配UNSIGNED令牌

这些检查由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));
  }
}

通过执行以下操作进行测试:

* nix中

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

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

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

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

修改

使用ANTLR4的lexical modes也许可能更清洁。但是,我对v4很新,我不知道这是否可行,因为一旦消耗了一定量的字节/字符而不是BINARY模式中的清除结束,你想要回弹到默认的词法范围。