我有以下语法:
grammar Hello;
prog: stat+ EOF;
stat: DELIMITER_OPEN expr DELIMITER_CLOSE;
expr: NOTES COMMA value=VAR_VALUE #delim_body;
VAR_VALUE: ANBang*;
NOTES: WS* 'notes' WS*;
COMMA: ',';
DELIMITER_OPEN: '<<!';
DELIMITER_CLOSE: '!>>';
fragment ANBang: AlphaNum | Bang;
fragment AlphaNum: [a-zA-Z0-9];
fragment Bang: '!';
WS : [ \t\r\n]+ -> skip ;
解析以下作品:
<<! notes, Test !>>
并且变量值为&#34; Test&#34;但是,当我消除DELIMITER_OPEN和NOTES之间的空格时,解析器失败:
<<!notes, Test !>>
第1行:3个不匹配的输入&#39;注释&#39;期待NOTES
答案 0 :(得分:2)
这是另一个错误订购词法规则的案例。
当词法分析器扫描下一个标记时,它首先尝试查找与最长标记匹配的规则。如果多个规则匹配,则会通过按定义顺序选择 first 来消除歧义。
<<! notes, Test !>>
将被标记为:
DELIMITER_OPEN
NOTES
COMMA
VAR_VALUE
WS
DELIMITER_CLOSE
这是因为NOTES
规则可以匹配以下内容:
<<! notes, Test !>>
\____/
哪个包含空白。如果你删除它:
<<!notes, Test !>>
然后NOTES
和VAR_VALUE
规则都可以匹配文字notes
,并且VAR_VALUE
在语法中定义为 first ,所以它优先。标记化是:
DELIMITER_OPEN
VAR_VALUE
COMMA
VAR_VALUE
WS
DELIMITER_CLOSE
并且它与您的expr
规则不符。
更改此规则以解决问题:
NOTES: 'notes';
VAR_VALUE: ANBang+;
将WS*
添加到其他规则并没有多大意义,因为跳过了WS
。并且将令牌声明为具有可能的零宽度*
也没有意义,因此请改用+
。最后,重新排序规则,以便最具体的规则匹配拳头。
这样,notes
成为语法中的关键字。如果您不希望它成为关键字,请完全删除NOTES
规则,并将VAR_VALUE
规则与谓词一起使用。或者,您可以使用词法分析器模式。