【发布时间】:2014-01-31 06:25:22
【问题描述】:
如果有人能让我从前瞻关系与涉及贪婪/非贪婪匹配的标记化背后的困惑中解脱出来,我会非常高兴。请注意,这是一篇稍长的帖子,因为它遵循了我的思考过程。
我正在尝试编写允许我匹配输入的 antlr3 语法,例如:
“标识符关键字”
我在 Antlr 3.4 中想出了一个这样的语法:
KEYWORD: 'keyword' ;
IDENTIFIER
:
(options {greedy=false;}: (LOWCHAR|HIGHCHAR))+
;
/** lowercase letters */
fragment LOWCHAR
: 'a'..'z';
/** uppercase letters */
fragment HIGHCHAR
: 'A'..'Z';
parse: IDENTIFIER KEYWORD EOF;
但是它抱怨它永远无法以这种方式匹配 IDENTIFIER,我真的不明白。 (以下选项永远无法匹配:1)
基本上,我试图为尝试匹配 (LOWCHAR|HIGHCHAR) 非贪婪方式的词法分析器指定,因此它在 KEYWORD 前瞻处停止。到目前为止,我所读到的关于 ANTLR 词法分析器的内容应该是词法分析器规则的某种优先级。如果我在词法分析器语法中首先指定 KEYWORD 词法分析器规则,那么后面的任何词法分析器规则都不能匹配所使用的字符。
经过一番搜索,我了解到这里的问题是它无法以正确的方式对输入进行标记,因为例如对于输入:“identifierkeyword”,“标识符”部分首先出现,因此它决定在那里开始匹配 IDENTIFIER 规则还没有 KEYWORD 标记匹配。
然后我尝试在 ANTLR 4 中编写相同的语法,以测试新的 run-ahead 功能是否可以匹配我想要的,它看起来像这样:
KEYWORD: 'keyword' ;
/** lowercase letters */
fragment LOWCHAR
: 'a'..'z';
/** uppercase letters */
fragment HIGHCHAR
: 'A'..'Z';
IDENTIFIER
:
(LOWCHAR|HIGHCHAR)+?
;
parse: IDENTIFIER KEYWORD EOF;
对于输入:“identifierkeyword”,它会产生以下错误: 第 1:1 行不匹配的输入“d”需要“关键字”
它将字符“i”(第一个字符)作为 IDENTIFIER 标记匹配,然后解析器期望得到一个他不会以这种方式获得的 KEYWORD 标记。
词法分析器的非贪婪匹配是否应该匹配,直到未来有任何其他可能性可用?难道它不应该提前考虑 IDENTIFIER 可以包含 KEYWORD 并以这种方式匹配它的可能性吗?
我对此感到非常困惑,我观看了 Terence Parr 介绍 ANTLR4 的新功能的视频,其中他谈到了在实际匹配规则的同时一直监视所有“正确”解决方案的预运行线程。我认为它也适用于 Lexer 规则,其中对输入“identifierkeyword”进行标记的可能正确解决方案是匹配 IDENTIFIER:“identifier”和匹配 KEYWORD:“keyword”
我认为我对非贪婪/贪婪匹配有很多错误。有人可以解释一下它是如何工作的吗?
毕竟我在这里找到了一个类似的问题:ANTLR trying to match token within longer token 并制作了一个与之对应的语法:
parse
:
identifier 'keyword'
;
identifier
:
(HIGHCHAR | LOWCHAR)+
;
/** lowercase letters */
LOWCHAR
: 'a'..'z';
/** uppercase letters */
HIGHCHAR
: 'A'..'Z';
这就是我现在想要的,但是我不明白为什么我不能将标识符规则更改为 Lexer 规则,将 LOWCHAR 和 HIGHCHAR 更改为片段。 词法分析器不知道“关键字”中的字母可以作为标识符匹配吗?或相反亦然?或者可能是规则仅被定义为在自身内部具有前瞻功能,而不是所有可能的匹配语法?
【问题讨论】:
标签: parsing antlr antlr3 antlr4 lexer