为什么ANTLR4不匹配"of"作为单词,","匹配为标点符号?



我有一个带有语法定义的Hello.g4语法文件:

definition : wordsWithPunctuation ;
words : (WORD)+ ;
wordsWithPunctuation : word ( word | punctuation word | word punctuation | '(' wordsWithPunctuation ')' | '"' wordsWithPunctuation '"' )*  ;
NUMBER : [0-9]+ ;
word : WORD ;
WORD : [A-Za-z-]+ ;
punctuation : PUNCTUATION ;
PUNCTUATION : (','|'!'|'?'|'''|':'|'.') ;
WS : [ trn]+ -> skip ; // skip spaces, tabs, newlines

现在,如果我试图从以下输入构建一个解析树:

a b c d of at of abc bcd of
a b c d at abc, bcd
a b c d of at of abc, bcd of

返回错误:

Hello::definition:1:31: extraneous input 'of' expecting {<EOF>, '(', '"', WORD, PUNCTUATION}

虽然:

a b c d  at:  abc bcd!

正确工作。

语法、输入或解释器有什么问题?

如果我修改wordsWithPunctuation规则,通过添加(... | 'of' | ',' word | ...),那么它完全匹配输入,但对我来说它看起来很可疑-单词of如何与单词aabc不同?或者为什么,与其他punctuation字符不同(即,为什么它匹配:!,但不匹配, ?)?

<标题> Update1:

我使用的是Eclipse的ANTLR4插件,因此项目构建时输出如下:

ANTLR Tool v4.2.2 (/var/folders/.../antlr-4.2.2-complete.jar)
Hello.g4 -o /Users/.../eclipse_workspace/antlr_test_project/target/generated-sources/antlr4 -listener -no-visitor -encoding UTF-8
<标题>更新2:

上面给出的语法只是部分来自:

grammar Hello;
text : (entry)+ ;
entry : blub 'abrr' '-' ('1')? '.' ('(' NUMBER ')')? sims '-' '(' definitionAndExamples ')' 'Hello' 'all' 'the' 'people' 'of' 'the' 'world';
blub : WORD ;
sims : sim (',' sim)* ;
sim : words ;
definitionAndExamples : definitions (';' examples)? ;
definitions : definition (';' definition )* ;
definition : wordsWithPunctuation ;
examples : example (';' example )* ;
example : '"' wordsWithPunctuation '"' ;
words : (WORD)+ ;
wordsWithPunctuation : word ( word | punctuation word | word punctuation | '(' wordsWithPunctuation ')' | '"' wordsWithPunctuation '"' )*  ;
NUMBER : [0-9]+ ;
word : WORD ;
WORD : [A-Za-z-]+ ;
punctuation : PUNCTUATION ;
PUNCTUATION : (','|'!'|'?'|'''|':'|'.') ;
WS : [ trn]+ -> skip ; // skip spaces, tabs, newlines

现在对我来说,entry规则中的单词以某种方式打破了entry规则中的其他规则。但是为什么呢?这是语法中的一种反模式吗?

通过在解析器规则中包含'of', ANTLR正在创建一个隐式匿名令牌来表示该输入。单词of将始终具有特殊的令牌类型,因此它永远不会具有WORD类型。它可能出现在解析树中的唯一位置是'of'出现在解析器规则中的位置。

您可以通过将语法分离到HelloLexer中的单独lexer grammar HelloLexer来防止ANTLR创建这些匿名令牌类型。HelloParser.g4中的parser grammar HelloParser。我强烈建议您始终使用这种形式,原因如下:

  1. Lexer模式只有当你这样做时才有效。
  2. 隐式定义的令牌是语法中最常见的错误来源之一,分离语法可以防止它发生。

分隔语法后,可以更新word解析器规则,以允许将特殊令牌of视为单词。

word
  : WORD
  | 'of'
  | ... other keywords which are also "words"
  ;

相关内容

  • 没有找到相关文章

最新更新