ANTLR:没有可行的替代错误

ANTLR:没有可行的替代错误,antlr,parser-generator,Antlr,Parser Generator,我的任务是编写简单的解析器生成器,因此我编写了类似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

我的任务是编写简单的解析器生成器,因此我编写了类似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 ;)

那么我在哪里会犯错误呢?我尝试到处搜索(谷歌等)错误“没有可行的替代方案”,但这并没有真正帮助我。

ANTLR词法分析器在使用解析器之前完全分配明确的令牌类型。当多个标记类型可以匹配一个标记时,语法中出现的第一个标记类型就是所使用的标记类型。对于语法,标记不能同时具有类型
ID
和类型
LRULEID
。由于输入的
foo
与这两个lexer规则都匹配,因此使用语法中第一个出现的标记:
ID
COLON
ID
分号

由于
ID
标记从未在解析器中实际引用,因此我建议进行以下更改之一。这两个选项中的任何一个都可以解决您所描述的问题,因此最终语法的外观完全取决于您的偏好

前言

您需要将空格引用从
space+
更改为
space*
,否则规则将要求在
之间至少有一个空格字符

选项1

完全删除
ID
lexer规则

选项2

  • ID
    更改为解析器规则,这样它就不会试图将令牌类型
    ID
    分配给所有标识符

    id : LRULEID | PRULEID;
    
  • 通过引用
    id
    更新
    pRule1
    规则

    pRule1 : ((id | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE+)+ ;
    
  • 不相关的旁注

    如果删除
    lRule
    pRule1
    规则中最外层的
    +
    闭包,而是将它们添加到规则引用本身,则语法可能更容易阅读,如下所示。请注意,我更改了前言中所述的
    空格
    参考

    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* ;
    
    也可从以下网址:

    表示解析器无法根据剩余的输入决定采用两条或多条路径中的哪一条。它跟踪违规输入的起始标记,还知道错误[发生]时解析器在不同路径中的位置

    在我的例子中,为了调试,我在解析之前调用了lexer.nextToken()。反过来,如果没有lexer.reset(),则在输入EOF错误时没有可行的替代方案

    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* ;