Parsing 使用固定字符数的ANTLR规则

Parsing 使用固定字符数的ANTLR规则,parsing,serialization,antlr,Parsing,Serialization,Antlr,我正在尝试为PHP serialize()格式编写一个ANTLR语法,除了字符串之外,其他一切似乎都很正常。问题在于序列化字符串的格式为: s:6:"length"; 就正则表达式而言,类似于s:(\d+):“.{\1}”的规则将描述此格式 但我找不到一种方法来表达词法分析器或语法分析器的语法:整个想法是让读取的字符数依赖于描述要读取的字符数的反向引用,就像Fortran Hollerith常量(即6hllength)中那样,而不是依赖于字符串分隔符 这个例子似乎说明了问题,但我不知道如何解决

我正在尝试为PHP serialize()格式编写一个ANTLR语法,除了字符串之外,其他一切似乎都很正常。问题在于序列化字符串的格式为:

s:6:"length";
就正则表达式而言,类似于
s:(\d+):“.{\1}”的规则将描述此格式

但我找不到一种方法来表达词法分析器或语法分析器的语法:整个想法是让读取的字符数依赖于描述要读取的字符数的反向引用,就像Fortran Hollerith常量(即
6hllength
)中那样,而不是依赖于字符串分隔符

这个例子似乎说明了问题,但我不知道如何解决。请注意,我的目标语言是Python,而大多数文档和示例都是针对Java的:

// numeral literal
ICON {int counter=0;} :
    /* other alternatives */
    // hollerith
    'h' ({counter>0}? NOTNL {counter--;})* {counter==0}?
      {
      $setType(HOLLERITH);
      String str = $getText;
      str = str.replaceFirst("([0-9])+h", "");
      $setText(str);
      }
    /* more alternatives */
    ;

由于像
s:3:“a“b”
这样的输入是有效的,所以您不能在lexer中定义
String
标记,除非第一个和最后一个双引号总是字符串的开始和结束。但我想情况并非如此

因此,您需要这样一个lexer规则:

SString
  :  's:' Int ':"' ( . )* '";'
  ;
换句话说:匹配一个
s:
,然后是一个
整数,后跟
:“
然后是一个或多个可以是任何字符的字符,以
";。但是当未达到值
Int
时,您需要告诉lexer停止消费。您可以通过在语法中混合一些普通代码来做到这一点。您可以通过将普通代码包装在
{
}
中来嵌入普通代码。因此,首先将令牌
Int
持有的值转换为一个名为
chars
的整数变量:

SString
  :  's:' Int {chars = int($Int.text)} ':"' ( . )* '";'
  ;
现在,在
(.)*
循环中嵌入一些代码,以在
字符数减为零时停止消耗:

SString
  :  's:' Int {chars = int($Int.text)} ':"' ( {if chars == 0: break} . {chars = chars-1} )* '";'
  ;
就这样

一点演示语法:

grammar Test;

options {
  language=Python;
}

parse
  :  (SString {print 'parsed: [\%s]' \% $SString.text})+ EOF
  ;

SString
  :  's:' Int {chars = int($Int.text)} ':"' ( {if chars == 0: break} . {chars = chars-1} )* '";'
  ;

Int
  :  '0'..'9'+
  ;
(请注意,您需要在语法中转义
%

和一个测试脚本:

import antlr3
from TestLexer import TestLexer
from TestParser import TestParser

input = 's:6:"length";s:1:""";s:0:"";s:3:"end";'
char_stream = antlr3.ANTLRStringStream(input)
lexer = TestLexer(char_stream)
tokens = antlr3.CommonTokenStream(lexer)
parser = TestParser(tokens)
parser.parse()
将生成以下输出:

parsed: [s:6:"length";]
parsed: [s:1:""";]
parsed: [s:0:"";]
parsed: [s:3:"end";]