Поскольку ввод, такой как s:3:"a"b";
, действителен, вы не можете определить токен String
в своем лексере, если только первая и последняя двойные кавычки не равны всегда началу и концу вашей строки. Но я думаю, что это не так.
Итак, вам понадобится правило лексера, например:
SString
: 's:' Int ':"' ( . )* '";'
;
Другими словами: соответствует s:
, затем значение integer
, затем :"
, затем один или несколько символов, которые могут быть любыми, заканчивающимися ";
. Но вы должны указать лексеру прекратить потребление, когда значение Int
не достигнуто. Вы можете сделать это, смешав некоторый простой код в вашей грамматике, чтобы сделать это. Вы можете встроить простой код, обернув его внутри {
и }
. Поэтому сначала преобразуйте значение, которое токен Int
содержит в целочисленную переменную с именем chars
:
SString
: 's:' Int {chars = int($Int.text)} ':"' ( . )* '";'
;
Теперь вставьте некоторый код в цикл ( . )*
, чтобы остановить его потребление, как только chars
будет отсчитан до нуля:
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";]