这是我的代码:
@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异常时给出无可行输入。
答案 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
命名替代。