使用ANTLR4

时间:2017-09-11 20:55:14

标签: parsing antlr antlr4 lexer

我使用ANTLR4生成解析器。我是解析器语法的新手。我已经阅读了非常有帮助的ANTLR Mega Tutorial,但我仍然坚持如何正确地订购(和/或编写)我的词法分析器和解析器规则。

我希望解析器能够处理这样的事情:

Hello<<名称>>,你好吗?

在运行时我将替换"<<名称>>"用户名。

所以大多数情况下我正在解析文字(以及标点符号,符号等),偶尔会出现"<<某事>>"标签,我称之为" func"在我的词法规则中。

这是我的语法:

doc: item* EOF ;
item: (func | WORD) PUNCT? ;
func: '<<' ID '>>' ;

WS : [ \t\n\r] -> skip ;
fragment LETTER : [a-zA-Z] ;
fragment DIGIT : [0-9] ;
fragment CHAR : (LETTER | DIGIT | SYMB ) ;
WORD : CHAR+ ;
ID: LETTER ( LETTER | DIGIT)* ;
PUNCT : [.,?!] ;
fragment SYMB : ~[a-zA-Z0-9.,?! |{}<>] ;

旁注:我添加了#34; PUNCT?&#34;在&#34;项目结束时#34;规则,因为有可能,例如在我上面给出的例句中,有一个逗号出现在&#34; func&#34;之后。但是因为你也可以在一个&#34; WORD&#34;之后有一个逗号。然后我决定把标点符号放在&#34; item&#34;而不是在&#34; func&#34;和&#34; WORD&#34;。

如果我在上面的句子上运行这个解析器,我会得到一个如下所示的解析树: Parse tree 1

以红色突出显示的任何内容都是解析错误。

所以它没有认识到&#34; ID&#34;在双角括号内作为&#34; ID&#34;。大概这是因为&#34; WORD&#34;在我的词法分析器规则列表中排在第一位。但是,我没有说&#34;&lt;&lt; WORD&gt;&gt;&#34;,只有一个规则说&#34;&lt;&lt; ID&gt;&gt;&#34;,所以我不清楚为什么会这样。

如果我交换&#34; ID&#34;的顺序和&#34; WORD&#34;在我的语法中,现在它们按顺序排列:

ID: LETTER ( LETTER | DIGIT)* ;
WORD : CHAR+ ;

运行解析器,我得到一个这样的解析树: Parse tree 2

所以现在&#34; func&#34;和&#34; ID&#34;规则正在得到妥善处理,但没有一个人被认可。

我如何克服这个难题?

我想一个选项可能是改变&#34; func&#34;规则为&#34;&lt;&lt; WORD&gt;&gt;&#34;并且只是将所有内容视为单词,废除&#34; ID&#34;。但我想区分文本字和变量标识符(例如,变量标识符中不允许使用特殊字符)。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

由于他的评论中已经提到的“500 - 内部服务器错误”,ANTLR将按照语法中定义的顺序匹配词法规则(最顶层的规则将首先匹配),如果某个输入已经匹配,则ANTLR胜出'尝试以不同的方式匹配它。

在您的情况下,Current.DispatcherUnhandledExceptionWORD规则都可以匹配ID之类的输入,但首先声明abc WORD将始终匹配为abc而不是WORD。实际上ID永远不会匹配,因为ID无法匹配ID的有效输入。

但是,如果您的唯一目标是替换WORD<<之间的任何内容,那么最好使用正则表达式。但是,如果你仍想使用ANTLR,你应该减少你的语法,只关心基本要素。这是为了区分>><<之间的任何输入和输入。因此你的语法应该是这样的:

>>

或者您可以完全跳过start: (INTERESTING | UNINTERESTING) ; INTERESTING: '<<' .*? '>>' ; UNINTERESTING: (~[<])+ | '<' ;

答案 1 :(得分:1)

来自The Definitive ANTLR 4 Reference

  

ANTLR通过解决词汇歧义   将输入字符串与语法中第一个指定的规则相匹配。

使用语法(在Question.g4中)和包含

的t.text文件
Hello << name >>, how are you at nine o'clock?

执行

$ grun Question doc -tokens -diagnostics t.text

给出

[@0,0:4='Hello',<WORD>,1:0]
[@1,6:7='<<',<'<<'>,1:6]
[@2,9:12='name',<WORD>,1:9]
[@3,14:15='>>',<'>>'>,1:14]
[@4,16:16=',',<PUNCT>,1:16]
[@5,18:20='how',<WORD>,1:18]
[@6,22:24='are',<WORD>,1:22]
[@7,26:28='you',<WORD>,1:26]
[@8,30:31='at',<WORD>,1:30]
[@9,33:36='nine',<WORD>,1:33]
[@10,38:44='o'clock',<WORD>,1:38]
[@11,45:45='?',<PUNCT>,1:45]
[@12,47:46='<EOF>',<EOF>,2:0]
line 1:9 mismatched input 'name' expecting ID
line 1:14 extraneous input '>>' expecting {<EOF>, '<<', WORD, PUNCT}

现在在WORD规则中将word更改为item,然后添加word规则:

item: (func | word) PUNCT? ;
word: WORD | ID ;

并在WORD之前输入ID:

ID: LETTER ( LETTER | DIGIT)* ;
WORD : CHAR+ ;

令牌现在是

[@0,0:4='Hello',<ID>,1:0]
[@1,6:7='<<',<'<<'>,1:6]
[@2,9:12='name',<ID>,1:9]
[@3,14:15='>>',<'>>'>,1:14]
[@4,16:16=',',<PUNCT>,1:16]
[@5,18:20='how',<ID>,1:18]
[@6,22:24='are',<ID>,1:22]
[@7,26:28='you',<ID>,1:26]
[@8,30:31='at',<ID>,1:30]
[@9,33:36='nine',<ID>,1:33]
[@10,38:44='o'clock',<WORD>,1:38]
[@11,45:45='?',<PUNCT>,1:45]
[@12,47:46='<EOF>',<EOF>,2:0]

并且没有更多错误。如-gui图形所示,您现在已将分支标识为wordfunc