Как заставить antlr4 полностью токенизировать терминальные узлы

Я пытаюсь использовать Antlr для создания очень простого синтаксического анализатора, который в основном токенизирует серию идентификаторов с разделителями ..

Я сделал простую грамматику:

r  : STRUCTURE_SELECTOR ;
STRUCTURE_SELECTOR: '.' (ID STRUCTURE_SELECTOR?)? ;
ID : [_a-z0-9$]* ;             
WS : [ \t\r\n]+ -> skip ;

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

В качестве примера:

  • . даст один конечный узел с текстом .
  • .foobar даст два узла, родительский с текстом . и дочерний с текстом foobar
  • .foobar.baz даст четыре узла: родитель с текстом ., дочерний элемент с текстом foobar, дочерний элемент второго уровня с текстом . и дочерний элемент третьего уровня с текстом baz.

person Ed Kohlwey    schedule 16.09.2017    source источник


Ответы (1)


Правила, начинающиеся с заглавной буквы, являются правилами Lexer.

Со следующим входным файлом t.text

.
.foobar
.foobar.baz

ваша грамматика (в файле Question.g4) производит следующие токены

$ grun Question r -tokens -diagnostics t.text
[@0,0:0='.',<STRUCTURE_SELECTOR>,1:0]
[@1,2:8='.foobar',<STRUCTURE_SELECTOR>,2:0]
[@2,10:20='.foobar.baz',<STRUCTURE_SELECTOR>,3:0]
[@3,22:21='<EOF>',<EOF>,4:0]

Лексер (парсер) жадный. Он пытается прочитать как можно больше входных символов (токенов) с помощью правила. Правило лексера STRUCTURE_SELECTOR: '.' (ID STRUCTURE_SELECTOR?)? может считывать точку, идентификатор и снова точку и идентификатор (из-за маркера повторения ?) до NL. Вот почему каждая строка заканчивается одним токеном.

При составлении грамматики ошибка

warning(146): Question.g4:5:0: non-fragment lexer rule ID can match the empty string

возникает из-за того, что маркер повторения идентификатора равен * (что означает 0 или более раз) вместо + (один или более раз).

Теперь попробуйте эту грамматику:

grammar Question;

r  
@init {System.out.println("Question last update 2135");}
    :   ( structure_selector NL )+ EOF
    ;

structure_selector
    :   '.'
    |   '.' ID structure_selector*
    ;

ID  : [_a-z0-9$]+ ;   
NL  : [\r\n]+ ;          
WS  : [ \t]+ -> skip ;

$ grun Question r -tokens -diagnostics t.text
[@0,0:0='.',<'.'>,1:0]
[@1,1:1='\n',<NL>,1:1]
[@2,2:2='.',<'.'>,2:0]
[@3,3:8='foobar',<ID>,2:1]
[@4,9:9='\n',<NL>,2:7]
[@5,10:10='.',<'.'>,3:0]
[@6,11:16='foobar',<ID>,3:1]
[@7,17:17='.',<'.'>,3:7]
[@8,18:20='baz',<ID>,3:8]
[@9,21:21='\n',<NL>,3:11]
[@10,22:21='<EOF>',<EOF>,4:0]
Question last update 2135
line 3:7 reportAttemptingFullContext d=1 (structure_selector), input='.'
line 3:7 reportContextSensitivity d=1 (structure_selector), input='.'

а $ grun Question r -gui t.text отображает ожидаемую иерархическую древовидную структуру.

person BernardK    schedule 16.09.2017