ANTLR4 отрицательный взгляд в лексере

Я пытаюсь определить правила лексера для PostgreSQL SQL.

Проблема в том, что определение оператора и комментарии строки противоречат друг другу.

например @--- это токен оператора @- с последующим -- комментарий а не токен оператора @---

В grako можно было бы определить негативную перспективу для - фрагмент как:

OP_MINUS: '-' ! ( '-' ) .

В ANTLR4 я не смог найти способа откатить уже потребленный фрагмент.

Есть идеи?

Вот оригинальное определение, каким может быть оператор PostgreSQL:

The operator name is a sequence of up to NAMEDATALEN-1
(63 by default) characters from the following list:

 + - * / < > = ~ ! @ # % ^ & | ` ?

There are a few restrictions on your choice of name:
-- and /* cannot appear anywhere in an operator name,
since they will be taken as the start of a comment.

A multicharacter operator name cannot end in + or -,
unless the name also contains at least one of these
characters:

~ ! @ # % ^ & | ` ?

For example, @- is an allowed operator name, but *- is not.
This restriction allows PostgreSQL to parse SQL-compliant
commands without requiring spaces between tokens.

1 ответ

Решение

Вы можете использовать семантический предикат в своих правилах лексера, чтобы выполнять прогнозирование (или отставание) без использования символов. Например, следующее охватывает несколько правил для оператора.

OPERATOR
  : ( [+*<>=~!@#%^&|`?]
    | '-' {_input.LA(1) != '-'}?
    | '/' {_input.LA(1) != '*'}?
    )+
  ;

Однако вышеприведенное правило не касается ограничений на включение + или же - в конце оператора. Чтобы справиться с этим как можно проще, я бы, вероятно, разделил два случая на отдельные правила.

// this rule does not allow + or - at the end of a rule
OPERATOR
  : ( [*<>=~!@#%^&|`?]
    | ( '+'
      | '-' {_input.LA(1) != '-'}?
      )+
      [*<>=~!@#%^&|`?]
    | '/' {_input.LA(1) != '*'}?
    )+
  ;

// this rule allows + or - at the end of a rule and sets the type to OPERATOR
// it requires a character from the special subset to appear
OPERATOR2
  : ( [*<>=+]
    | '-' {_input.LA(1) != '-'}?
    | '/' {_input.LA(1) != '*'}?
    )*
    [~!@#%^&|`?]
    OPERATOR?
    ( '+'
    | '-' {_input.LA(1) != '-'}?
    )+
    -> type(OPERATOR)
  ;
Другие вопросы по тегам