как использовать последовательность для токенизации, но не возвращаемую как номинал результата

#antlr4

#antlr4

Вопрос:

Я хотел бы использовать правило или последовательность в качестве разделителя для токенизации файла, но не возвращать разделитель

Я пытался использовать -> channel(hidden) , но это портит синтаксический анализ

У меня есть грамматика, такая, что

 grammar test;

file
 : l1 l2? l3
;

l1
 : 'L1:' STRING_LITERAL 'n'
;
l2
 : 'L2:'(NUMBER)  'n'
;
l3
 :'L3:' WORD|NUMBER 'n'
;


NUMBER          : [0-9]  ;
STRING_LITERAL  : '"' (~["\rn] | EscapeSequence)* '"';
WORD            : ('a'..'z' | 'A'..'Z') ;
fragment EscapeSequence
    : '\' [btnfr"'\]
    | '\' ([0-3]? [0-7])? [0-7]
    ;
  

и входной файл, подобный

 L1: "SO LONG"
L2: 42
L3: FISH
  

Я бы хотел не возвращать L1: L2: и L3: , но возвращать «ТАК ДОЛГО» 42 и FISH

Я получаю токены, которые я ищу, но я также получаю n L1: L2: и L3:

Смотрите это для дерева результатов

Также я заметил, что если у меня установлено правило l1 как l1: (~ [«\ r n]) * ; Я могу сопоставлять до конца строки без проблем, но я получаю каждое слово как отдельный токен. Для меня это имеет смысл, но есть ли способ использовать его как единый токен?

Комментарии:

1. Также я заметил, что если у меня установлено правило l1 как l1 : (~ [«\ r n]) * ; Я могу сопоставлять до конца строки без проблем, но я получаю каждое слово как отдельный токен. Для меня это имеет смысл, но есть ли способ использовать его как единый токен?

2. Привет, Демиан, не публикуй дополнительную информацию в качестве комментария, а добавляй их в вопрос =)

3. Спасибо за предложение! Выполнено

Ответ №1:

Если вы хотите иметь возможность использовать эти L1: токены внутри синтаксического анализатора, то удалить их невозможно. В любом случае я не вижу реального варианта использования для этого. Но я не понимаю, почему вы не можете просто пропустить (или скрыть) эти токены во время лексера. Кажется, это работает просто отлично:

 parse
 : NL* line ( NL  line )* NL* EOF
 ;

line
 : l1
 | l2
 | l3
 ;

l1 : STRING_LITERAL;
l2 : NUMBER ;
l3 : ( WORD | NUMBER );

NUMBER         : [0-9] ;
STRING_LITERAL : '"' ( ~["\rn] | EscapeSequence )* '"';
WORD           : [a-zA-Z] ;

IGNORED
 : 'L' [0-9] ':' -> skip
 ;

SPACES
 : [ t]  -> skip
 ;

NL
 : 'r'? 'n'
 ;

fragment EscapeSequence
 : '\' [btnfr"'\]
 | '\' ([0-3]? [0-7])? [0-7]
 ;
  

в результате:

введите описание изображения здесь

[…] итак, я должен быть в состоянии сделать что-то вроде if (parser.l1() == «ТАК ДОЛГО»»), затем сделайте что-нибудь

ANTLR работает не так. Анализатор создает дерево синтаксического анализа (со всеми определенными вами токенами). Затем это дерево синтаксического анализа можно использовать для извлечения значений. Извлечение значений может быть выполнено путем ручного обхода дерева синтаксического анализа или с помощью класса прослушивателя (или посетителя) ANTLR:https://github.com/antlr/antlr4/blob/master/doc/listeners.md

Вот мое предложение для вас: не используйте skip разрыв строки и L1: токены из лексера и используйте слушателя или посетителя для извлечения данных из вашего дерева синтаксического анализа.

Комментарии:

1. Спасибо, Барт. Вариант использования заключается в том, что у синтаксического анализатора уже есть parser.l1() метод, и я бы хотел, чтобы он просто возвращал значение. По сути, я думаю об этом как о словаре ключ-значение (возможно, это неправильный способ увидеть это?), Поэтому я должен быть в состоянии сделать что-то вроде if (parser.l1() == «SO LONG»»), а затем сделать что-то

2. Также аналогично с n, я бы хотел, чтобы он вообще не возвращался

3. Вам нужен n в синтаксическом анализаторе: он обозначает конец строки. Без этого вы не сможете определить разницу между L2: 123nL2: 456n и L2: 123 456n

4. ах, теперь я понимаю. Большое спасибо за это @BartKiers!