#java #parsing #antlr4 #identifier
#java #синтаксический анализ #antlr4 #идентификатор
Вопрос:
Я пытаюсь сопоставить комплексные числа, используя разные обозначения, одно из которых использует cis
функцию как таковую: cis
ФАЗА МОДУЛЯ
Проблема в том, что мое правило идентификатора соответствует cis
, а также началу следующего за ним числа, и поскольку оно больше, чем сам CIS
токен, оно всегда возвращает тип токена идентификатора. Как я мог этого избежать?
Вот грамматика :
grammar Sandbox;
input : number? CIS UNSIGNED
| IDENTIFIER
;
number : FLOAT
| UFLOAT
| UINT
| INT
;
fragment DIGIT : [0-9] ;
UFLOAT : UINT (DOT UINT? | 'f') ;
FLOAT : SUB UFLOAT ;
UINT : DIGITS ;
INT : SUB UINT ;
UNSIGNED : UFLOAT
| UINT
;
DIGITS : DIGIT ;
// Specific lexer rules
CIS : 'cis' ;
SUB : '-' ;
DOT : '.' ;
WS : [ t] -> skip ;
NEWLINE : 'r'? 'n' ;
IDENTIFIER : [a-zA-Z_] [a-zA-Z0-9_]* ; // has to be after complex so i or cis doesn't match this first
Редактировать:
Входные данные, которые я пытался проанализировать, являются сложными 1 i
, но используют их соответствующий модуль и фазу следующим образом : 1.4142135623730951cis0.7853981633974483
И моя реальная проблема заключается в том, что правило ИДЕНТИФИКАТОРА совпадает cis0
, а не просто соответствует правилу CIS lexer, даже если оно определено перед ним.
Я смутно знаю, что ANTLR выбирает правило на основе наибольшего совпадения, но в этом случае я хочу избежать этого =o .
Комментарии:
1. Не главная проблема, но
в
[a-zA-Z_] [a-zA-Z0-9_]*
этом нет необходимости.2. Ах, это действительно так, поскольку только первый символ имеет это ограничение, верно? = O Спасибо, я это исправлю
3. В
MODULUS cis PHASE
MODULUS
иPHASE
идентификаторы или числа? Покажите фактический пример ввода, который анализируется неправильно. Кроме того, я считаю, что в вашей грамматике много проблем. Например,IMAGINARY : IM UNSIGNED?
совпадения, напримерi 3
.4. да, точно, в основном они могут быть либо числами с плавающей запятой, либо целыми числами, но единственное отличие состоит в том, что если это мнимая часть, она должна быть без знака, чтобы /- обрабатывался до этого (я думаю). Вот один пример, который я хотел проанализировать:
1.4142135623730951cis0.7853981633974483
это комплекс1 i
, поэтому модуль и аргументы являются этими двумя значениями соответственно5. Я удалил все остальные правила лексера и синтаксического анализатора, за исключением правила
cis
удаления примера
Ответ №1:
Я вижу здесь два решения:
- Сделайте комплексное число правилом одного лексера:
COMPLEX: (FLOAT | UFLOAT | UINT | INT) WS* CIS WS* UNSIGNED;
который будет длиннее идентификатора или ключевого слова pur CIS (и, следовательно, соответствует первому).
- Второе
cis
слово — это ключевое слово, когда оно следует за цифрой (с необязательными пробелами между ними), верно? Итак, вы можете выполнить обратный просмотр (LA(-1)
в вашем предикате, чтобы отклонитьcis
как идентификатор, если это условие истинно.
Я бы предпочел решение 1, потому что соглашение заключается в том, что отдельные объекты (а комплексное число, такое как число с плавающей запятой или строка, является одним логическим объектом) полностью совпадают в правиле лексера, а не в правиле синтаксического анализатора.
Комментарии:
1. Ага, это хороший трюк, я обязательно подумаю об этом, если у меня когда-нибудь возникнут проблемы с приоритетом правил. Я пометил это как ответ, но для второго подхода меня все еще интересует обратная связь, это то же самое, что и для регулярного выражения? Есть ли ссылка, где я тоже могу прочитать об этом = o
2. В ANTLR не используется и не поддерживается регулярное выражение. Но да, оглядываться назад — это как смотреть вперед, только с отрицательным смещением.
LA()
В лексере есть функция, которую вы можете использовать для проверки символов во входном потоке относительно текущей позиции. Аналогичная функцияLT()
(для токена look ahead) существует в анализаторе для получения определенного токена относительно текущей позиции токена.3. Я прочитал справочник ANTLR, и на данный момент я дошел только до страниц 210 ~, поэтому я предполагаю, что это произойдет после ха-ха. Я изучу
LA
, иLT
поскольку это то, что я действительно хотел иметь возможность использовать, хе-хе. Большое спасибо за помощь информация!
Ответ №2:
Я просто помещаю это здесь, потому что я думаю, что это может быть потенциальным решением, хотя я бы предпочел не использовать семантические предикаты, потому что это привязывает мою грамматику к целевому / конкретному языку =/ (я никогда не использовал их раньше, поэтому я не уверен, есть ли какие-либо другие предостережения):
IDENTIFIER: [a-zA-Z_][a-zA-Z0-9_]* { identifierIsNotReserved() }?;
И тогда нам просто нужно реализовать identifierIsNotReserved
метод, чтобы проверить, использовало ли правило идентификатора зарезервированное ключевое слово, и если да, то запретить применение правила. И я цитирую:
Семантический предикат представляет собой блок произвольного кода на целевом языке, окруженный символом {…}?, который принимает логическое значение. Если возвращаемое значение равно false, правило лексера пропускается.
Редактировать: забыл добавить ссылку на то, где я это нашел, вот она: https://riptutorial.com/antlr/example/11237/actions-and-semantic-predicates
Комментарии:
1. Выбор такого решения означал бы, что вы бы отказались от создания любого идентификатора, начинающегося с ключевого слова (вы собираетесь отклонить
cis0
, верно?). Нет ли случаев, когдаcis0
(или аналогичных) является допустимым идентификатором?2. Хотел опубликовать ответ, но я вижу, что Майк уже это сделал (и я бы ответил на что-то похожее на его вариант 1).