В ANTLR, как я должен реализовать посетитель с состоянием / контекстом? - PullRequest
1 голос
/ 23 апреля 2020

Я пытаюсь написать простой синтаксический анализатор 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';

1 Ответ

1 голос
/ 24 апреля 2020

Не решение Antlr-speci c, а типичное решение DSL заключается в использовании таблицы состояний с областью видимости (она же таблица символов) для накопления результатов AST / CST-обхода.

См. Это ответ за реализацию . Другой существует в Antlr репозитории .

...