我已经阅读了非常有用的ANTLR Mega Tutorial但我仍然坚持如何正确地订购(和/或写)我的词法分析器和解析器规则 .
我希望解析器能够处理这样的事情:
你好“姓名”,你好吗?
在运行时,我将用用户名替换“<< name >>” .
所以我主要解析文本单词(和标点符号等),除了偶尔出现的“<< something >>”标签,我在lexer规则中称之为“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.,?! |{}<>] ;
旁注:我添加了“PUNCT?”在“项目”规则的末尾,因为有可能(例如在我上面给出的例句中)在“func”之后出现逗号 . 但是因为你也可以在“WORD”之后有一个逗号然后我决定将标点符号放在“item”而不是“func”和“WORD”中 .
如果我在上面的句子上运行这个解析器,我会得到一个如下所示的解析树:
以红色突出显示的任何内容都是解析错误 .
因此,它不会将双尖括号内的“ID”识别为“ID” . 据推测,这是因为“WORD”在我的词法规则列表中排在第一位 . 但是,我没有说“<< WORD >>”的规则,只有一条说“<< ID >>”的规则,所以我不清楚为什么会这样 .
如果我在语法中交换“ID”和“WORD”的顺序,那么它们现在按以下顺序排列:
ID: LETTER ( LETTER | DIGIT)* ;
WORD : CHAR+ ;
并运行解析器,我得到一个这样的解析树:
所以现在正在正确处理“func”和“ID”规则,但没有一个“WORD”被识别 .
我如何克服这个难题?
我想一个选项可能是将“func”规则更改为“<< WORD >>”,并将所有内容视为单词,取消“ID” . 但我想区分文本字和变量标识符(例如,变量标识符中不允许使用特殊字符) .
谢谢你的帮助!
2 回答
来自The Definitive ANTLR 4 Reference:
用你的语法(在Question.g4中)和一个包含的t.text文件
执行
给
现在在
item
规则中将WORD
更改为word
,并添加word
规则:并在WORD之前输入ID:
令牌现在
并且没有更多的错误 . 如-gui图形所示,您现在已将分支标识为
word
或func
.由于他的评论中已经提到的“500 - 内部服务器错误”,ANTLR将按照语法中定义的顺序匹配词法规则(最顶层的规则将首先匹配),如果某个输入已匹配,则ANTLR将不会尝试不同的是匹配它 .
在您的情况下,
WORD
和ID
规则都可以匹配abc
之类的输入,但是首先声明WORD
abc
将始终匹配为WORD
,而不是ID
. 实际上ID
将永远不会匹配,因为没有有效的输入作为ID
,WORD
无法匹配 .但是,如果您的唯一目标是替换
<<
和>>
之间的任何内容,那么最好使用正则表达式 . 但是,如果你仍想使用ANTLR,你应该减少你的语法,只关心基本要素 . 这是为了区分<<
和>>
之间的任何输入和输入 . 因此你的语法应该是这样的:或者你可以完全跳过
UNINTERESTING
.