У меня вопрос об обработке пробелов в грамматике antlr3. Вот урезанная версия грамматики:Как обрабатывать пробелы между токенами в грамматике antlr3
grammar SLiMScript;
inputFile :
NEWLINE*
sectionOutput?
;
sectionOutput : '#OUTPUT' NEWLINE+ outputLine+ ;
outputLine : (output_all) NEWLINE+ ;
output_all : NUMBER 'A' STRING? ;
NEWLINE : ('\r'? '\n') ;
NUMBER : ('0' | (DIGIT_1 DIGIT_0*)) ('.' DIGIT_0*)? EXPONENT? ;
fragment EXPONENT : ('e'|'E') ('+'|'-')? DIGIT_0+ ;
fragment DIGIT_0 : '0'..'9' ;
fragment DIGIT_1 : '1'..'9' ;
STRING : '"' (~('"'|'\n'|'\r'|'\\'))* '"' ;
WS : (' ' | '\t') { skip(); } ;
А вот простой входной файл:
#OUTPUT
1000 A "foo bar baz"
В общем, я хочу, чтобы пробельные раздели; таким образом, правило пробелов в конце грамматики. Тем не менее, я хочу, чтобы между токенами требовалось пустое пространство. Например, если вы посмотрите на выходной файл, я не хочу, чтобы 1000A"foo"
был законным; Мне нужны промежутки между токенами. Необходимо четко указать, что всюду в грамматике было бы довольно болезненно. И я не могу иметь торт и съесть его; если я держу пробельные зачистки, правила, то я не могу изменить мое правило заявления на:
output_all : NUMBER WS 'A' (WS STRING)? ;
потому, что пробельные маркеры уже получили раздел в этой точке; для правила не осталось пробелов. Может быть, у меня нет выбора, кроме как избавиться от неявного пробела и вместо этого поставить ссылку WS
между каждыми парами токенов во всей грамматике, чтобы получить поведение, которое я хочу. Но, конечно, есть лучший способ ...?
Как делают такие языки, как C? Вы можете написать static int foo
, но вы не можете написать staticintfoo
; почему нет? Как грамматики для таких языков создают пробелы между токенами? Я предполагаю, что это потому, что staticintfoo
получает токенизацию как идентификатор, по-видимому, потому что это первое правило; эта строка также будет соответствовать токенам static
, int
и (идентификатор) foo
, но до этого они могут быть поглощены как один большой идентификатор, и это вызывает ошибку, поскольку этот идентификатор не определен. Есть ли способ сделать что-то подобное в моей ситуации? Чтобы неявно требовать пробелы между токенами, создавая версию без пробелов, вызывают альтернативную интерпретацию, которая приводит к ошибке? Я действительно не вижу изящного способа сделать это.
Я читал книги Парра. Языковые шаблоны реализации и окончательный ANTLR Reference, и я более или менее понимаю их, я думаю, но я чувствую, что мне не хватает хорошего обзора того, как на самом деле разрабатывать практическую грамматику для различных конкретных прикладных ситуаций. Какая-то книга, например, «Искусство LL (*)». Есть ли такая книга?
Способ, которым работает ваш C, заключается в том, что лексеры, как правило, едят максимально возможную строку, соответствующую токену. Поэтому 'staticintfoo' - это идентификатор, а не три токена,« статические »,« int »,« foo ». Тогда сообщение об ошибке будет указано, что 'staticintfoo' является необъявленным идентификатором, а не синтаксической ошибкой. –