Antlr 无法匹配 [a-z]+

Antlr failing to match [a-z]+

尝试拆分输入的第一个单词,这样 apple a type of fruit 将拆分为 applea type of fruit

grammar Hello;

entry
  :  headword definition
  ;

headword
  :  HEADWORD
  ;

definition
  :  ANYTHING
  ;

HEADWORD : [a-z]+ ;
SPACE   : [ \t]+ -> skip ;
ANYTHING : .+; 

使用 Getting Started 演练:

C:\Code\antlr\hello>java org.antlr.v4.Tool Hello.g4
warning(131): Hello.g4:17:12: greedy block ()+ contains wildcard; the non-greedy syntax ()+? may be preferred

C:\Code\antlr\hello>javac Hello*.java

C:\Code\antlr\hello>grun Hello entry -tree

C:\Code\antlr\hello>java org.antlr.v4.gui.TestRig Hello entry -tree
asdf asdf
^Z
line 1:0 missing HEADWORD at 'asdf asdf\r\n'
(entry (headword <missing HEADWORD>) (definition asdf asdf\r\n))

为什么无法匹配 HEADWORD?

即使尝试直接匹配 HEADWORD 也不起作用:

C:\Code\antlr\hello>grun Hello HEADWORD -tree
asdf^Z

Terminate batch job (Y/N)? y

它似乎永远循环,所以我不得不用 Ctrl-C 杀死它。

ANTLR 词法分析器规则使用尽可能多的字符。所以你的规则 ANYTHING : .+; 消耗了整个输入,导致它成为唯一要创建的标记。这就是 HEADWORD 未创建的原因。

是的,ANTLR 的词法分析器规则是从上到下匹配的,但是只有当 2 个(或更多)词法分析器规则匹配相同数量的字符时,从上到下才有意义。然后首先定义的规则“获胜”,但前提是(多个)规则匹配相同数量的字符。在您的情况下,ANYTHING 将(几乎)总是匹配最多的字符,因此将是要创建的唯一标记。

如果您的输入只是 "apple",则会创建一个 HEADWORD 标记,因为 HEADWORDANYTHING 都匹配输入,但是 HEADWORD 首先定义,因此优先。

并且将 .+ 更改为 .+? 只会导致 ANYTHING 永远不会与您的输入 apple a type of fruit 匹配。只会创建 5 HEADWORD 个代币。

根据经验,让词法分析器规则以 .*.+(或 .*?.+?)结尾绝不是一个好主意。