2012-07-04 1 views
2

Вот что я пытаюсь сделать AST этого:ANTLR для необязательного ключевого значения

{{ name }} 
{{ name | option }} 
{{ name | option1 | option2 }} 
{{ name | key=value }} 
{{ name | option1 | key=value }} 
{{ name | option1 | {{ another }} | option3 }} 

Так на практике всегда есть имя (a..zA..Z0..9) и опции иногда находятся в формате ключевого значения, а иногда и в простом и без формата значений.

Я пытаюсь написать грамматику лексера/парсера для нее ANTLR, но она дергается о разных вещах. Вот мой лучший снимок:

start : box+; 
box : '{{' Name ('|' Options)* '}}'; 
Options : (SimpleOption | KeyValue | box); 
Name : ID; 
SimpleOption: ID; 
KeyValue:  ID '=' ID; 
fragment 
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ; 
WS : (' ' | '\t' | '\r' | '\n' {$channel=HIDDEN;} ; 

Это, очевидно, неправильно, потому что имя и SimpleOption неоднозначны. Даже инлайн правило бесполезно:

box : '{{' Name ('|' (ID | KeyValue | box))* '}}'; 

Потому что он никогда не выбирает KeyValue и дает несовпадение исключение на встрече с «=».

Как вы напишете эту грамматику?

+0

'name' не должно быть неоднозначным потому что идентификатор всегда будет сведен к этому, если это первый токен после '{{', и никогда иначе. Полученный ответ выглядит как двусмысленность для меня. – Lucero

ответ

4

Вы используете слишком много правил LeXeR. Правило KeyValue будет соответствовать только ID '=' ID без пробелов вокруг знака =: оно должно быть правилом анализатора (начинаться с буквы нижнего регистра). Только когда это правило парсера, оно может иметь пробелы вокруг =, которые затем будут отброшены.

Убедитесь, что вы понимаете разницу между правилами лексера и парсера! См: Practical difference between parser rules and lexer rules in ANTLR?

Это следует сделать это:

grammar T; 

start  : box+ EOF; 
box  : '{{' ID ('|' opts)* '}}'; 
opts  : key_value | ID | box; // note that 'options' is a reserved word in ANTLR! 
key_value : ID '=' ID; 
ID  : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '0'..'9' | '_')*; 
WS  : (' ' | '\t' | '\r' | '\n') {skip();}; 

, который будет анализировать ввод

{{ name | option1 = value1 | {{ another | k=v }} | option3 }} 

следующим образом:

enter image description here

0

ли эта работа для вас:

Options : (SimpleOptionOrKeyValue | box); 
SimpleOptionOrKeyValue: ID ('=' ID |); 

Это устраняет необходимость опережающего просмотра для = знака. (Отредактировано для изменения порядка появления внутри parens, не уверен, как ANTLR обрабатывает это.)

Различие между простой опцией и значением ключа может быть выполнено на семантическом уровне.

Возможно, связанные с: ANTLR How to use lexer rules having same starting?

+0

«Невозможно оглянуться назад больше, чем один токен» - это ответ Antlr на это решение :(- но спасибо за ссылки –

+0

Работает ли он тогда, если вы создадите новое правило для '' = 'ID'? Например: 'ValueForKeyValue : ('=' ID); ' – krlmlr

+0

Без обид, но этот ответ неверен и должен быть удален (не знаю, почему он получил преимущество).' SimpleOptionOrKeyValue' все еще является правилом лексера, в то время как это должно быть правило синтаксического анализа, и ANTLR не было бы вопроса, ожидающего увидеть, есть ли '=' или нет: парсер ANTLR - это 'LL (*)'. –