我有一个任务是编写简单的解析器生成器,所以我编写了类似 ANTLR 的语法并尝试解析像“foo:bar;”这样的简单文件,但得到了以下输出:
[@0,0:2='foo',<1>,1:0]
[@1,3:3=':',<16>,1:3]
[@2,4:6='bar',<1>,1:4]
[@3,7:7=';',<18>,1:7]
[@4,8:7='<EOF>',<-1>,1:8]
line 1:0 no viable alternative at input 'foo'
(rule foo : bar ;)
我的语法看起来像
grammar parsGen;
gram : rule SEMICOLON (NEWLINE+ rule SEMICOLON)* ;
rule : lRule | pRule ;
lRule : LRULEID COLON lRule1 ;
lRule1 : (((LRULEID | STRING | SET) | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE+)+ ;
pRule : PRULEID COLON pRule1 ;
pRule1 : (((LRULEID | PRULEID) | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE+)+ ;
modificator : PLUS | ASTERISK | QUESTION ;
ID : LRULEID | PRULEID ;
LRULEID : UPPERLETTER (UPPERLETTER | LOWERLETTER | DIGIT)* ;
PRULEID : LOWERLETTER (UPPERLETTER | LOWERLETTER | DIGIT)* ;
STRING : ('\''.*?'\'') ;
SET : '\''.*?'\'..\''.*?'\'' ;
UPPERLETTER : [A-Z] ;
LOWERLETTER : [a-z] ;
DIGIT : [0-9] ;
NEWLINE : '\r\n'|'\n'|'\r' ;
PLUS : '+' ;
ASTERISK : '*' ;
QUESTION : '?' ;
LBRACE : '(' ;
RBRACE : ')' ;
SPACE : ' ' ;
COLON : ':' ;
PIPE : '|' ;
SEMICOLON : ';' ;
那么我哪里可能会出错呢?我尝试到处搜索(谷歌,SO等)错误“没有可行的替代方案”,但这并没有真正帮助我。
最佳答案
ANTLR 词法分析器在使用解析器之前完全分配明确的标记类型。当多个标记类型可以匹配一个标记时,语法中出现的第一个标记就是使用的标记类型。对于您的语法,标记不能具有类型 ID
和类型 LRULEID
同时。自输入foo
匹配这两个词法分析器规则,使用语法中第一个出现的规则,因此您的标记为:ID
, COLON
, ID
, SEMICOLON
, <EOF>
.
自 ID
解析器中从未实际引用 token,我建议进行以下更改之一。 这些选项中的任何一个都可以解决您所描述的问题,因此选择完全取决于您对最终语法外观的偏好。
前言
您需要更改 SPACE+
的空间引用至SPACE*
,或者规则将要求 bar
之间至少有一个空格字符和;
.
选项 1
删除ID
词法分析器完全规则。
选项 2
更改
ID
解析器规则,因此它不会尝试分配 token 类型ID
您的所有标识符。id : LRULEID | PRULEID;
更新
pRule1
通过引用id
进行规则.pRule1 : ((id | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE+)+ ;
不相关的旁注
如果删除最外面的 +
,您的语法可能会更容易阅读lRule
内的封闭和pRule1
规则,而是将它们添加到规则引用本身中,如下所示。请注意,我更改了 SPACE
引用文献如前言中所述。
lRule : LRULEID COLON lRule1+ ;
lRule1 : ((LRULEID | STRING | SET) | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE* ;
pRule : PRULEID COLON pRule1+ ;
pRule1 : ((LRULEID | PRULEID) | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE* ;
关于ANTLR : no viable alternative error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16856963/