Я пытаюсь написать простой синтаксический анализатор ANTLR для обработки корректировки даты, поэтому, например, я мог бы написать: +1w+1d
для обозначения «переход через неделю и день» или MIN(+30d, +1m)
для обозначения «30 дней после введите дату или 1 месяц, в зависимости от того, что наступит раньше ". Эти правила должны быть составными, поэтому MIN(+30d, +1m)+1d
означает «день после (30 дней с даты ввода или 1 месяц с даты ввода, в зависимости от того, что наступит раньше)», а +1dMIN(+30d, +1m)
означает «30 дней с (день после дата ввода) или 1 месяц спустя (день после даты ввода), в зависимости от того, что наступит раньше ".
[Я ценю приведенные здесь примеры довольно банально - реальная грамматика должна понимать о выходных, праздничных днях, границах месяца и т. д. c, так что это может быть что-то вроде «через месяц после (конец месяца входной даты или пятница после даты ввода - в зависимости от того, что наступит раньше)» et c etc]
Код I хочу написать это:
DateAdjutmeParser parser = buildFromString("MAX(+30d,+1m)");
ParseTree tree = parser.rootNode();
return new MyVisitor().visit(tree, LocalDate.of(2020,4,23)); //Not allowed extra parameters here.
Проблема в том, как именно я могу передать "Дата контекста"? Я не могу сохранить его в классе MyVisitor
как член, поскольку вызов visit()
является рекурсивным, и это перезаписывает контекст. Я мог бы создать параллельный набор объектов, которые имели бы правильные методы, но это, кажется, много шаблонного.
Есть ли решение ANTLR?
Подробнее:
Это посетитель, которого я хотел бы написать:
public class MyVisitor extends DateAdjustBaseVisitor<LocalDate> {
@Override
public LocalDate visitOffsetRule(DateAdjustParser.OffsetRuleContext ctx) {
LocalDate contextDate = ???; //
return contextDate.plus(Integer.valueOf(ctx.num.toString()), ChronoUnit.valueOf(ctx.unit.toString()));
}
@Override
public LocalDate visitMinMaxRule(DateAdjustParser.MinMaxRuleContext ctx) {
LocalDate contextDate = ???; //
LocalDate left = this.visitChildren(ctx.left, contextDate);
LocalDate right = this.visitChildren(ctx.right, contextDate);
if(ctx.type.getText().equals("MIN")) {
return left.compareTo(right) > 0 ? left : right;
} else {
return left.compareTo(right) < 0 ? left : right;
}
}
}
вот моя грамматика:
grammar DateAdjust;
rootNode: offset+;
offset
: num=NUMBER unit=UNIT #OffsetRule
| type=( MIN | MAX ) '(' left=offset ',' right=offset ')' #MinMaxRule
;
UNIT: [dwmy]; //Days Weeks Months Years
NUMBER: [+-]?[0..9]+;
MAX: 'MAX';
MIN: 'MIN';