Как указать несколько правил лексера в одном правиле? - PullRequest
0 голосов
/ 10 февраля 2020

У меня есть следующее правило синтаксического анализатора:

declaration     : (KW_VARIABLE DT_IDENTIFIER) |
                  (KW_VARIABLE DT_IDENTIFIER OP_ASSIGNMENT DT_DATA_TYPES) OP_SEMICOLON;

и следующие правила лексера:

KW_VARIABLE     : 'var';

OP_ASSIGNMENT   : '=';
OP_SEMICOLON    : ';';

DT_IDENTIFIER   : [a-z]+;
DT_INTEGER      : [0-9]+;
DT_DATA_TYPES   : (DT_IDENTIFIER | DT_INTEGER);

С этими правилами я хочу написать следующий код:

var a = 10;
var b = 40;
var c = 50;
var d = c;

Мой код слушателя для выхода из объявления выглядит следующим образом:

public override void ExitDeclaration([NotNull] PyroParser.DeclarationContext context)
{
    bool isAssigned = context.OP_ASSIGNMENT() != null;

    if (!isAssigned)
    {
        return;
    }

    Console.WriteLine(context.DT_DATA_TYPES().GetText());
    base.ExitDeclaration(context);
}

В первой строке появляется сообщение об ошибке:

строка 1: 8 несоответствующий ввод '10', ожидающий DT_DATA_TYPES

Я просто хочу иметь возможность ссылаться на все типы данных в одном правиле, как я могу это сделать?

1 Ответ

2 голосов
/ 10 февраля 2020

Это неверно:

DT_IDENTIFIER   : [a-z]+;
DT_INTEGER      : [0-9]+;
DT_DATA_TYPES   : (DT_IDENTIFIER | DT_INTEGER);

После совпадения DT_IDENTIFIER или DT_INTEGER оно никогда не станет DT_DATA_TYPES. Лексер сопоставляет правила сверху вниз, и как только совпадение найдено, он не откажется от него. И простое изменение порядка правил:

DT_DATA_TYPES   : (DT_IDENTIFIER | DT_INTEGER);
DT_IDENTIFIER   : [a-z]+;
DT_INTEGER      : [0-9]+;

тоже не сработает: таким образом лексер никогда не выдаст токены DT_IDENTIFIER и DT_INTEGER.

Вы можете сделать что-то вроде это вместо:

dt_data_types   : (DT_IDENTIFIER | DT_INTEGER);

DT_IDENTIFIER   : [a-z]+;
DT_INTEGER      : [0-9]+;
...