Что означает фрагмент в ANTLR?
Я видел оба правила:
fragment DIGIT : '0'..'9';
и
DIGIT : '0'..'9';
В чем разница?
Фрагмент чем-то похож на встроенную функцию: он делает грамматику более читаемой и простой в обслуживании.
Фрагмент никогда не будет считаться токеном, он служит только для упрощения грамматики.
Рассматривать:
NUMBER: DIGITS | OCTAL_DIGITS | HEX_DIGITS;
fragment DIGITS: '1'..'9' '0'..'9'*;
fragment OCTAL_DIGITS: '0' '0'..'7'+;
fragment HEX_DIGITS: '0x' ('0'..'9' | 'a'..'f' | 'A'..'F')+;
В этом примере сопоставление ЧИСЛА всегда будет возвращать НОМЕР в лексер, независимо от того, соответствует ли он «1234», «0xab12» или «0777».
fragment
означает в ANTLR. Но приведенный вами пример плохой: вы не хотите, чтобы лексер создавалNUMBER
токен, который может быть шестнадцатеричным, десятичным или восьмеричным числом. Это означает, что вам нужно проверитьNUMBER
токен в производственной среде (правило парсера). Вы могли бы лучше пусть лексер производитINT
,OCT
иHEX
маркер и создать правило производства:number : INT | OCT | HEX;
. В таком примере aDIGIT
может быть фрагментом, который будет использоваться токенамиINT
иHEX
.Согласно справочнику Definitive Antlr4:
на самом деле они улучшат читаемость вашей грамматики.
посмотрите на этот пример:
STRING - это лексический анализатор, использующий правило фрагмента, например ESC. Юникод используется в правиле Esc, а шестнадцатеричный - в правиле фрагмента Юникода. Правила ESC, UNICODE и HEX не могут использоваться явно.
источник
Окончательный справочник по ANTLR 4 (стр. 106) :
Абстрактные концепции:
Вариант 1: (если мне нужна rule1 Правилу2, Правилу3 лица или о группе)
Случай 2: (если мне все равно ПРАВИЛО1, ПРАВИЛО2, ПРАВИЛО3, я просто сосредоточусь на ПРАВИЛЕ0)
Case3: (эквивалентно Case2, что делает его более читаемым, чем Case2)
Различия между Case1 и Case2 / 3?
Посмотрим на конкретный пример.
Цель: определить
[ABC]+
,[DEF]+
,[GHI]+
жетоныinput.txt
Main.py
Случай1 и результаты:
Alphabet.g4 (Case1)
Результат:
Случай2 / 3 и результаты:
Alphabet.g4 (Case2)
Alphabet.g4 (Case3)
Результат:
Вы видели части "захватывающие группы" и "не захватывающие группы" ?
Посмотрим на конкретный пример2.
Цель: определить восьмеричные / десятичные / шестнадцатеричные числа
input.txt
Число.g4
Main.py
Результат:
Если добавить модификатор «фрагмент» к
DECIMAL_NUMBER
,OCTAL_NUMBER
,HEXADECIMAL_NUMBER
вы не сможете захватить число объектов (поскольку они не являются лексемы больше). И результат будет:источник
В этом сообщении в блоге есть очень ясный пример, который
fragment
имеет существенное значение:Грамматика распознает «42», но не «7». Вы можете исправить это, сделав цифру фрагментом (или переместив ЦИФРУ после INT).
источник
fragment
, а в порядке правил лексера.DIGIT
как фрагментINT
решает проблему только потому, что фрагменты не определяют токены, тем самым создаваяINT
первое лексическое правило. Я согласен с вами, что это значимый пример, но (имо) только для тех, кто уже знает, чтоfragment
означает ключевое слово. Я считаю, что это несколько вводит в заблуждение тех, кто впервые пытается понять, как правильно использовать фрагменты.