Невозможно написать правило Antlr3 для ситуации - PullRequest
0 голосов
/ 10 мая 2018

У меня есть особый случай, когда я не могу написать для этого правило парсера Antlr3.

У меня есть 5 правил синтаксического анализа, скажем, a, b, c, d и e.

Условия:

  1. Они могут быть в любом порядке.
  2. Каждое правило не является обязательным.
  3. Каждое правило может быть только один раз в синтаксисе.
  4. В синтаксисе будет либо «a», либо «b». Оба не могут быть в синтаксисе.

Возможные случаи:

  • а д д е
  • c d e b
  • д е с
  • д с ......... и т.д.

Antlr предоставляет какой-либо простой способ реализовать это? Это возможно путем реализации правила для каждой комбинации правил.

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

ANTLR4 не позволяет реализовать все указанные вами условия. В частности, условие, что правила могут появляться в любом порядке, но только один раз, является чем-то, что едва поддерживается любым синтаксическим анализатором.

Однако вы можете использовать двухэтапный подход. Во-первых, позвольте всем правилам появляться в любом порядке. Готово обычно так:

main: sub*;
sub: a | b | c;

После синтаксического анализа вы можете сделать еще один шаг (обычно у вас будет семантический шаг в любом случае, который также подходит и здесь) и проверить вхождения в сгенерированном дереве разбора. Затем вы можете выдать подробное сообщение об ошибке, сообщающее пользователю, что не разрешено (что сложно, если не невозможно, если вы попытаетесь сделать это в правилах синтаксического анализатора). Подход, изложенный @sprinter, тоже подойдет, но он не даст вам значимого сообщения об ошибке, а просто скажет, что у правила element нет жизнеспособного alt (что может иметь много причин, а не только повторяющиеся правила).

И с этим вторым шагом вы можете легко применить любое дополнительное условие (особые приказы, правила, которые не должны сочетаться друг с другом и т. Д., Без необходимости изменять вашу грамматику), что вы не можете сделать на этапе разбора (поскольку вы не можете просматривать правила ).

0 голосов
/ 10 мая 2018

Возможный способ сделать это - использовать контекстно-зависимые предикаты. Способ реализации зависит от языка, но может выглядеть примерно так:

statement : element*;

element : {!seen(a) && !seen(b)}? a {add(a);}
    | {!seen(a) && !seen(b)}? b {add(b);}
    | {!seen(c) c {add(c);}
    ....

По сути, это останавливает анализатор, рассматривающий опцию после того, как он был замечен один раз.

Вот очень простой пример использования Java:

@parser::header {
    import java.util.EnumSet;
    import java.util.List;
}
@parser::members {
    public enum Val {A, B, C, D, E};
    public EnumSet<Val> result = EnumSet.noneOf(Val.class); 
}

statement : (a|b|c|d|e)+ EOF;

a : {!result.contains(Val.A) && !result.contains(Val.B)}? 'a' {result.add(Val.A);};
b : {!result.contains(Val.A) && !result.contains(Val.B)}? 'b' {result.add(Val.B);};
c : {!result.contains(Val.C)}? 'c' {result.add(Val.C);};
d : {!result.contains(Val.D)}? 'd' {result.add(Val.D);};
e : {!result.contains(Val.E)}? 'e' {result.add(Val.E);};
...