Поиск…


Простые правила

Правила Lexer определяют типы токенов. Их имя должно начинаться с буквы верхнего регистра, чтобы отличать их от правил парсера.

INTEGER: [0-9]+;
IDENTIFIER: [a-zA-Z_] [a-zA-Z_0-9]*;

OPEN_PAREN: '(';
CLOSE_PAREN: ')';

Основной синтаксис:

Синтаксис Имея в виду
A Правило совпадения lexer или фрагмент с именем A
AB Матч A за которым следует B
(A|B) Сопоставьте либо A либо B
'text' Соответствовать литералу "text"
A? Матч A ноль или один раз
A* Матч A ноль или более раз
A+ Матч A или несколько раз
[A-Z0-9] Сопоставьте один символ в определенных диапазонах (в этом примере между AZ или 0-9)
'a'..'z' Альтернативный синтаксис для диапазона символов
~[AZ] Отрицание диапазона - соответствует любому одиночному символу не в диапазоне
. Совпадение любого персонажа

Фрагменты

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

INTEGER: DIGIT+
       | '0' [Xx] HEX_DIGIT+
       ;

fragment DIGIT: [0-9];
fragment HEX_DIGIT: [0-9A-Fa-f];

Неявные правила лексера

Когда жетоны, подобные '{' , используются в правиле парсера , для них создается неявное правило лексера, если не существует явного правила.

Другими словами, если у вас есть правило lexer:

OPEN_BRACE: '{';

Тогда оба этих правила синтаксического анализа эквивалентны:

parserRule: '{';
parserRule: OPEN_BRACE;

Но если OPEN_BRACE lexer OPEN_BRACE не определено, будет создано неявное анонимное правило. В этом случае неявное правило будет определено так, как если бы оно было определено перед другими правилами: оно будет иметь более высокий приоритет, чем другие правила.

Приоритетные правила

Несколько правил lexer могут соответствовать одному и тому же входному тексту. В этом случае тип токена будет выбран следующим образом:

  • Сначала выберите правило lexer, которое соответствует самому длинному входу
  • Если текст соответствует неявно определенному токену (например, '{' ), используйте неявное правило
  • Если несколько правил lexer совпадают с одной и той же длиной ввода, выберите первую , основанную на порядке определения

Следующая комбинированная грамматика:

grammar LexerPriorityRulesExample;

// Parser rules

randomParserRule: 'foo'; // Implicitly declared token type
    
// Lexer rules
    
BAR: 'bar';
IDENTIFIER: [A-Za-z]+;
BAZ: 'baz';

WS: [ \t\r\n]+ -> skip;

Учитывая следующий ввод:

aaa foo bar baz barz

Выполним следующую лексерную последовательность из лексера:

IDENTIFIER 'foo' BAR IDENTIFIER IDENTIFIER
  • aaa имеет тип IDENTIFIER

    Только правило IDENTIFIER может соответствовать этому знаку, нет никакой двусмысленности.

  • foo имеет тип 'foo'

    Правило анализатора randomParserRule вводит неявный тип токена 'foo' , который является приоритетным по правилу IDENTIFIER .

  • bar имеет тип BAR

    Этот текст соответствует правилу BAR , которое определено до правила IDENTIFIER , и поэтому имеет приоритет.

  • baz имеет тип IDENTIFIER

    Этот текст соответствует правилу BAZ , но также соответствует правилу IDENTIFIER . Последний выбирается так, как он определен до BAR .

    Учитывая грамматику, BAZ никогда не сможет сравниться, так как правило IDENTIFIER уже охватывает все, что может соответствовать BAZ .

  • barz имеет тип IDENTIFIER

    Правило BAR может соответствовать первым 3 символам этой строки ( bar ), но правило IDENTIFIER будет соответствовать 4 символам. Поскольку IDENTIFIER соответствует более длинной подстроке, он выбирается над BAR .

Как правило, определенные правила должны быть определены перед более общими правилами. Если правило может соответствовать только входному сигналу, который уже покрыт ранее определенным правилом, он никогда не будет использоваться.

Неявно определенные правила, такие как 'foo' действуют так, как если бы они были определены перед всеми другими правилами lexer.

Команды Lexer

Правило lexer может иметь связанные команды :

WHITESPACE: [ \r\n] -> skip;

Команды определяются после a -> в конце правила.

  • skip : skip согласованный текст, не будет выдан токен
  • channel(n) : выдает токен на другом канале
  • type(n) : Изменяет тип испущенного маркера
  • mode(n) , pushMode(n) , popMode , more : управляет лексерскими режимами

Действия и семантические предикаты

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

IDENTIFIER: [A-Z]+ { log("matched rule"); };

Семантический предикат - это блок произвольного кода на целевом языке, окруженный { ... }? , который вычисляет логическое значение. Если возвращаемое значение равно false, правило lexer пропускается.

IDENTIFIER: [A-Z]+ { identifierIsValid() }?;

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



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow