Antlr语义谓词未能找到可行的替代方案

Antlr语义谓词未能找到可行的替代方案,antlr,antlr4,antlr4cs,Antlr,Antlr4,Antlr4cs,对于.NETFramework4.8,我无法使用更简单的语义谓词来处理ANTLR4.6.6 下面的语法无法找到可行的输入选项 "received:last week" 更新: 这是我问题的简化。只有在“last week”前面加上“received”的情况下,才可能有语法将“received:last week”解析为“received”“last week”,但如果我将“subject:last week”解析为“subject”“last”“week”。当我运行此代码

对于.NETFramework4.8,我无法使用更简单的语义谓词来处理ANTLR4.6.6 下面的语法无法找到可行的输入选项

"received:last week"

更新: 这是我问题的简化。只有在“last week”前面加上“received”的情况下,才可能有语法将“received:last week”解析为“received”“last week”,但如果我将“subject:last week”解析为“subject”“last”“week”。

当我运行此代码时:

publicstaticvoidmain(字符串[]args){
String source=“已收到:上周”;
testLexer lexer=新的testLexer(CharStreams.fromString(source));
testParser=newtestparser(newcommontokenstream(lexer));
System.out.println(parser.parse().toString树(parser));
}
错误
行1:0在输入“已接收”时没有可行的备选方案
被打印到STDERR。当我将
{false}?
更改为
{true}?
时,输入被正确解析(如预期的那样)

如果由于
{false}?
谓词,您希望输入被解析为
received':'text
,那么您误解了ANTLR的lexer是如何工作的。lexer独立于解析器生成标记。解析器试图匹配
文本
标记并不重要,您的输入总是以相同的方式标记

lexer的工作原理如下:

received
 : RECEIVED ':' last_week
 ;

subject
 : SUBJECT ':' text
 ;

last_week
 : LAST WEEK
 ;

text
 : TEXT
 | LAST
 | WEEK
 ;

RECEIVED : 'received';
SUBJECT  : 'subject';
LAST     : 'last';
WEEK     : 'week';
TEXT     : ~[ :]+;
  • 尽可能多地使用字符
  • 如果有两个或多个lexer规则匹配相同的字符,则让第一个定义的规则“win”
  • 根据这些规则,很明显,
    “received:last week”
    标记为
    received
    :“
    last week
    标记

    编辑 只有在“last week”前面加上“received”的情况下,但如果我将“subject:last week”解析为“subject”“last”“week”,那么语法是否可以将“received:last week”解析为“received”“last week”

    通过使用,您可以使lexer具有一定的上下文敏感性。然后必须创建单独的lexer语法和parser语法,如下所示:

    received
     : RECEIVED ':' last_week
     ;
    
    subject
     : SUBJECT ':' text
     ;
    
    last_week
     : LAST WEEK
     ;
    
    text
     : TEXT
     | LAST
     | WEEK
     ;
    
    RECEIVED : 'received';
    SUBJECT  : 'subject';
    LAST     : 'last';
    WEEK     : 'week';
    TEXT     : ~[ :]+;
    
    TestLexer.g4 您可以在解析器语法中使用上述lexer:

    TestParser.g4 现在,
    “已收到:上周”
    将标记为:

    'received'                `received`
    COLON                     `:`
    LASTWEEK                  `last week`
    EOF                       `<EOF>`
    
    'subject'                 `subject`
    COLON                     `:`
    TEXT                      `last`
    TEXT                      `week`
    EOF                       `<EOF>`
    
    编辑二 您还可以将上周创建的
    移动到解析器中,如下所示:

    received
     : RECEIVED ':' last_week
     ;
    
    subject
     : SUBJECT ':' text
     ;
    
    last_week
     : LAST WEEK
     ;
    
    text
     : TEXT
     | LAST
     | WEEK
     ;
    
    RECEIVED : 'received';
    SUBJECT  : 'subject';
    LAST     : 'last';
    WEEK     : 'week';
    TEXT     : ~[ :]+;
    

    谢谢这是我问题的简化。只有在“last week”前面加上“received”的情况下,才可能有语法将“received:last week”解析为“received”“last week”,但如果我的“subject:last week”被解析为“subject”“last”“week”,则可能有语法将其解析为“received”“last week”。你所说的lexer总是匹配最长的字符串,这意味着这是不可能实现的。我尝试在lexer lever上使用语义谓词,事实上我能够匹配上面简单示例中的那些,但是我没有足够的上下文来检查前面的标记“received”。这是一个很好的答案!非常感谢你!不客气@ekalchev。我还为稍微不同的解决方案添加了第二次编辑。
    received
     : RECEIVED ':' last_week
     ;
    
    subject
     : SUBJECT ':' text
     ;
    
    last_week
     : LAST WEEK
     ;
    
    text
     : TEXT
     | LAST
     | WEEK
     ;
    
    RECEIVED : 'received';
    SUBJECT  : 'subject';
    LAST     : 'last';
    WEEK     : 'week';
    TEXT     : ~[ :]+;