Parsing Lexer lookahead如何处理ANTLR3和ANTLR4中的贪婪和非贪婪匹配?

Parsing Lexer lookahead如何处理ANTLR3和ANTLR4中的贪婪和非贪婪匹配?,parsing,antlr,antlr3,antlr4,lexer,Parsing,Antlr,Antlr3,Antlr4,Lexer,如果有人能让我从“前瞻”关系背后的困惑中清醒过来,我会非常高兴。请注意,这篇文章有点长,因为它遵循了我的思考过程 我正在尝试编写antlr3语法,允许我匹配输入,例如: “identifierkeyword” 我在Antlr 3.4中提出了这样的语法: KEYWORD: 'keyword' ; IDENTIFIER : (options {greedy=false;}: (LOWCHAR|HIGHCHAR))+ ; /** lowercase letters */ fragment

如果有人能让我从“前瞻”关系背后的困惑中清醒过来,我会非常高兴。请注意,这篇文章有点长,因为它遵循了我的思考过程

我正在尝试编写antlr3语法,允许我匹配输入,例如:

“identifierkeyword”

我在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;
然而,它抱怨它永远不能以这种方式匹配标识符,我真的不明白。(以下备选方案永远无法匹配:1)

基本上,我试图为lexer指定尝试以非贪婪方式匹配(LOWCHAR | HIGHCHAR)的lexer,以便它停止在关键字lookahead。到目前为止,我读到的关于ANTLR词法规则的内容是,应该有某种词法规则的优先级。如果我在lexer语法中首先指定关键字lexer rule,那么后面的任何lexer规则都不能匹配所使用的字符

identifier : IDENTIFIER+;
IDENTIFIER : HIGHCHAR | LOWCHAR;
经过一些搜索,我了解到这里的问题是,它无法以正确的方式标记输入,因为例如,对于输入:“identifierkeyword”,首先是“identifier”部分,因此它决定在没有匹配的关键字标记时开始匹配标识符规则

然后,我尝试在ANTLR 4中编写相同的语法,以测试新的预演功能是否符合我的要求,如下所示:

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”(第一个字符)作为标识符标记,然后解析器需要一个关键字标记,而不是通过这种方式获得的

难道lexer的非贪婪匹配不应该匹配,直到前瞻中有任何其他可能性可用吗?它不应该展望标识符可以包含关键字并以这种方式匹配它的可能性吗

我真的很困惑,我看了一段视频,其中Terence Parr介绍了ANTLR4的新功能,他在视频中谈到了运行前线程,这些线程在实际匹配规则的同时,一直观察所有“正确”的解决方案。我认为它也适用于Lexer规则,其中标记输入“identifierkeyword”的可能正确解决方案是匹配标识符:“IDENTIFIER”和匹配关键字:“KEYWORD”

我想我脑子里有很多关于非贪婪/贪婪匹配的错误。谁能给我解释一下它是怎么工作的吗

在所有这些之后,我在这里发现了一个类似的问题:并制作了一个与之对应的语法:

parse
:   
  identifier 'keyword'
;

identifier
:   
  (HIGHCHAR | LOWCHAR)+
;

/** lowercase letters */
LOWCHAR
:   'a'..'z';
/** uppercase letters */
HIGHCHAR
:   'A'..'Z';
这就是我现在想要的,但是我不明白为什么不能将标识符规则更改为Lexer规则,将LOWCHAR和HIGHCHAR更改为片段。
词法分析器不知道“关键字”中的字母可以作为标识符匹配吗?反之亦然?或者可能是规则的定义只是为了在其内部具有前瞻性,而不是所有可能的匹配语法?

在ANTLR 3和ANTLR 4中解决这一问题的最简单方法是只允许
标识符
匹配单个输入字符,然后创建一个解析器规则来处理这些字符的序列

identifier : IDENTIFIER+;
IDENTIFIER : HIGHCHAR | LOWCHAR;
这将导致lexer将输入的
标识符
作为10个单独的字符跳过,然后将
关键字
作为单个
关键字
标记读取

在ANTLR 4中使用非贪婪运算符
+?
观察到的行为与此类似。此运算符表示“在仍然创建
标识符的情况下,尽可能少地匹配
(HIGHCHAR | LOWCHAR)
块”。显然,创建标记的最少数字是1,因此这实际上是一种非常低效的写入
标识符
以匹配单个字符的方法。
parse
规则无法处理此问题的原因是它只允许单个
标识符
标记出现在
关键字
标记之前。通过创建一个解析器规则
identifier
,就像我上面展示的那样,解析器将能够将
identifier
标记序列(每个标记都是单个字符)作为单个标识符来处理


编辑:您收到消息“以下备选方案永远无法匹配…”的原因在ANTLR 3中,静态分析已确定规则
标识符中的正闭包永远不会匹配超过1个字符,因为该规则始终只匹配1个字符。

在ANTLR 3和ANTLR 4中解决这一问题的最简单方法是只允许
标识符
匹配单个字符输入字符,然后创建一个解析器规则来处理这些字符的序列

identifier : IDENTIFIER+;
IDENTIFIER : HIGHCHAR | LOWCHAR;
这将导致lexer将输入的
标识符
作为10个单独的字符跳过,然后将
关键字
作为单个
关键字
标记读取

在ANTLR 4中使用非贪婪运算符
+?
观察到的行为与此类似。此运算符表示“在仍然创建
标识符的情况下,尽可能少地匹配
(HIGHCHAR | LOWCHAR)
块”。显然,创建标记的最少数字是1,因此这实际上是一种非常低效的写入
标识符
以匹配单个字符的方法。
parse
规则无法处理此问题的原因是它只允许单个
标识符
标记出现在
关键字
标记之前。通过创建一个解析器规则
identifier
,就像我上面展示的那样,解析器将能够将
identifier
标记序列(每个标记都是单个字符)作为单个标识符来处理

编辑:您在ANTLR 3中收到消息“以下备选方案永远无法匹配…”的原因是静态分析已确定规则
标识符中的正闭包永远不会匹配超过1个字符,因为规则将