下面是我的代码:
@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中定义的月份标准。在这种情况下,12根据日期方法(1-31)通过,之后29将进行月检查(1-12)并且失败。它应该回溯到根并遵循第二条路径,而不是在29异常时给出No Viable Input。
让我们将语义谓词直接移动到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
命名的替代。只有当第一个数字是正确的日,第二个数字是正确的月(用_input.LT(3)
令牌表示),我们才匹配dayAndMonth
。否则,我们将匹配monthAndDay
命名替代