ANTLR表示可选键值

时间:2012-07-04 21:39:01

标签: antlr grammar lexer

以下是我试图制作它的AST:

{{ 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;}  ;

这显然是错误的,因为Name和SimpleOption是不明确的。即使内联规则也没用:

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

因为它永远不会选择KeyValue并在遇到'='时给出Mismatch异常。

你会怎么写这个语法?

2 个答案:

答案 0 :(得分:4)

你正在使用过多的词法规则。规则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

答案 1 :(得分:0)

这适合你吗?

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

这消除了=符号前瞻的需要。 (编辑改变了parens内部的外观顺序,不确定ANTLR如何处理它。)

然后可以在语义层面上执行简单选项和键值之间的区别。

也许相关:ANTLR How to use lexer rules having same starting?