ANTLR
Правила Lexer в v4
Поиск…
Простые правила
Правила 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() }?;
Семантические предикаты должны быть определены в конце правила, когда это возможно по соображениям производительности.