2

这是我试图制作的 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 并在遇到 '=' 时给出不匹配异常。

你会怎么写这个语法?

4

2 回答 2

4

您使用了太多的词法分析器规则。该规则KeyValue只会匹配符号ID '=' ID周围没有空格=:它应该是解析器规则(以小写字母开头)。只有当它是解析器规则时,它才能在 周围有空格=,然后将被丢弃。

确保您了解词法分析器和解析器规则之间的区别!请参阅: 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 }}

如下:

在此处输入图像描述

于 2012-07-05T17:37:06.913 回答
0

这对你有用吗:

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

这消除了对=标志的前瞻需求。(编辑为反转括号内的出现顺序,不确定 ANTLR 如何处理此问题。)

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

也许相关:ANTLR How to use lexer rules have the same start?

于 2012-07-04T21:49:48.253 回答