Antlr4在第二个谓词失败时不遵循备用路径

时间:2016-09-28 17:52:37

标签: java antlr antlr4

这是我的代码:

@parser::members {

public boolean twoDigitDay(String text) {
    try {
        int day = Integer.parseInt(text);
        if (day >= 1 && day <= 31)
        {
            return true;
        }
    }
    catch (Exception e)
    {

    }
    return false;
}
public boolean twoDigitMonth(String text) {
    try {
        int day = Integer.parseInt(text);
        if (day >= 1 && day <= 12)
        {
            return true;
        }
    }
    catch (Exception e)
    {
    }
    return false;
}

}

date        :   day seperator month
        |   month seperator day
        ;

day             :   dayTwoDigits ;
month           :   monthTwoDigit;
monthTwoDigit   :   {twoDigitMonth(getCurrentToken().getText())}? TWO_DIGITS;
dayTwoDigits    :   {twoDigitDay(getCurrentToken().getText())}? TWO_DIGITS;
seperator   :   ('/');
ONE_DIGIT   :   [0-9];
TWO_DIGIT   :   ONE_DIGIT ONE_DIGIT

这里的问题是: 输入 - 12/29(它应该进入月份分隔日路径,因为首先是失败)。解析器在29处抛出无可行输入...因为29不满足@member中定义的月份标准。在这种情况下,在29进行月检查(1-12)之后,根据日期方法(1-31)传递12并且它失败。它应该回溯到根并遵循第二条路径,而不是在29异常时给出无可行输入。

1 个答案:

答案 0 :(得分:0)

让我们将语义谓词直接移到date语法规则。

TWO_DIGIT : [0-9][0-9];

date
    : {twoDigitDay(getCurrentToken().getText()) && twoDigitMonth(_input.LT(3).getText())}? 
        TWO_DIGIT '/' TWO_DIGIT # dayAndMonth
    | {twoDigitMonth(getCurrentToken().getText()) && twoDigitDay(_input.LT(3).getText())}?
        TWO_DIGIT '/' TWO_DIGIT # monthAndDay
    ;

当我们开始匹配规则date时,我们首先检查dayAndMonth命名的替代方案。我们仅在第一个数字是正确的日期且第二个数字是正确的月份(用dayAndMonth令牌代表)时匹配_input.LT(3)。否则,我们将匹配monthAndDay命名替代。