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