Сворачивание некоторых поддеревьев AST в Antlr с использованием правил перезаписи

У меня есть следующая грамматика (я показываю только важные разделы)

packageDeclaration
    :   PACKAGE qualifiedIdentifier SEMI -> ^(PACKAGE qualifiedIdentifier+) 
    ;

qualifiedIdentifier
    :   (   IDENT               ->  IDENT
        )
        (   DOT ident=IDENT     ->  ^(DOT $qualifiedIdentifier $ident)
        )*
    ;

и скажем, у меня есть декларация пакета "package a.b.c" (кстати, синтаксический анализатор Java)

Теперь я получаю что-то вроде (package (. (. a b) c))

я хочу встроить пакет, чтобы получить (пакет a.b.c)

Я бы предпочел не менять переписывание для квалифицированного идентификатора, а только для packageDeclaration.

Как я могу это сделать.

Теперь я понимаю, что вы имеете в виду под псевдонимом и +. Но мне все еще неясна разница между квалифицированным идентификатором и $qualifiedIdentifier в правиле перезаписи.

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

packageDeclaration
    :   PACKAGE ident=qualifiedIdentifier SEMI -> ^(PACKAGE $ident+) 
    ;

В результате я получаю вложенные токены, например:

 (package
    (a) [end:a]

    (.) [end:.]

    (b) [end:b]

    (.) [end:.]

    (c) [end:c]
  ) [end:package]

Each token is represented as "(<token's text property>) [end: <token's text property>]"

Я надеюсь, что в приведенном выше выводе все ясно, но у меня есть один родительский токен (пакет) с 5 дочерними элементами. Теперь они в правильном порядке и все такое. Я хотел бы, чтобы тот же родитель имел только одного ребенка, как в:

 (package
    (a.b.c) [end:a.b.c]
  ) [end:package]

person Coder    schedule 11.02.2011    source источник
comment
Хорошо сформулированный, подробный вопрос с достаточным количеством опубликованной грамматики, чтобы на него можно было ответить. Отличная работа!   -  person Bart Kiers    schedule 11.02.2011
comment
лол, спасибо, теперь стало легче, когда я больше понимаю antlr   -  person Coder    schedule 11.02.2011


Ответы (1)


Если вы хотите удалить DOT из дерева и оставить только токены a, b и c из import a.b.c; (конечно, с PACKAGE в качестве корня), попробуйте:

qualifiedIdentifier
  :  IDENT (DOT IDENT)* -> IDENT+
  ;

или с DOT просто удалите правило перезаписи:

qualifiedIdentifier
  :  IDENT (DOT IDENT)*
  ;

Кстати, в вашем packageDeclaration есть ошибка:

packageDeclaration
  :  PACKAGE qualifiedIdentifier SEMI -> ^(PACKAGE qualifiedIdentifier+)
  ;

Вместо qualifiedIdentifier+ должно быть qualifiedIdentifier.

Кодер написал:

Я бы предпочел не менять переписывание для квалифицированного идентификатора, а только для packageDeclaration.

Это невозможно.

Если вы не используете qualifiedIdentifier внутри packageDeclaration, в этом случае вы можете сделать что-то вроде:

packageDeclaration
  :  PACKAGE IDENT (DOT IDENT)* SEMI -> ^(PACKAGE IDENT+)
  ;

РЕДАКТИРОВАТЬ

Что касается ваших комментариев:

Кодер написал:

Я немного запутался в значении + в правиле перезаписи. В документации здесь antlr.org/wiki/display/ANTLR3/Tree+construction говорится, что вы можете разбивать деревья на последовательности «a : (^(ID INT))+ -> INT+ ID+ ; // разбивать деревья на последовательности».

Из правила:

a 
  :  (^(ID INT))+ -> INT+ ID+
  ; 

(^(ID INT))+ означает, что есть один или несколько ID и один или более INT, и только тогда вы можете использовать + в правиле перезаписи (все справа от ->).

С другой стороны, у вас есть:

packageDeclaration 
  :  PACKAGE qualifiedIdentifier SEMI
  ; 

там только один qualifiedIdentifier, поэтому вы можете использовать только этот единственный qualifiedIdentifier в своем правиле перезаписи (без +!)

Кодер написал:

Меня также смущает разница между указанием псевдонима в правиле перезаписи, как в «PACKAGE ident:qualifiedIdentifier -> $ident», и использованием quanlifiedIdentifier против $quanlifiedIdentifier.

Псевдоним можно использовать, если не очевидно, какое не очевидно, какое правило следует размещать в каком месте дерева или если вы хотите больше контролировать размещение дочерних элементов. Например, учитывая правило:

name
  :  ID '.' ID
  ;

и вы хотите, чтобы первый ID стал правильным потомком. Делает:

name
  :  ID '.' ID > ^(NAME ID ID)
  ;

поместит первый идентификатор в качестве левого дочернего элемента. Чтобы сделать его правильным дочерним, выполните:

name
  :  a=ID '.' b=ID > ^(NAME $b $a)
  ;

РЕДАКТИРОВАТЬ II

Кодер написал:

В результате я получаю вложенные токены, например:

(SNIP)

Каждый токен представлен как...

Хорошо, я понимаю, что ты имеешь в виду. Вы должны понимать, что парсер "питает" лексер. Лексер нарезает ввод символов и создает токены из этих символов (IDENT является таким токеном, как и DOT). Затем эти токены передаются парсеру. Парсер не может просто создавать или объединять токены. Итак, ответ таков: то, что вы хотите, сделать нелегко, это, безусловно, невозможно сделать в «синтаксисе ANTLR» внутри вашей грамматики.

person Bart Kiers    schedule 11.02.2011
comment
круто, я попробую это спасибо. Я немного запутался в значении + в правиле перезаписи. Документация здесь antlr.org/wiki/display/ANTLR3/Tree+construction говорит, что вы можете разбивать деревья на последовательности a : (^(ID INT))+ -> INT+ ID+ ; // разбиваем деревья на последовательности. Меня также смущает разница между указанием псевдонима в правиле перезаписи, как в PACKAGE ident:qualifiedIdentifier -> $ident vs, с использованием quanlifiedIdentifier vs $quanlifiedIdentifier - person Coder; 11.02.2011
comment
Я попробовал то, что вы предложили, чтобы удалить правило перезаписи, как в 'qualifiedIdentifier : IDENT (DOT IDENT)* ; ', но теперь я получаю один токен за каждый пакет и DOT. то, что я хотел бы, это два токена, как в (пакет abc). Это возможно? - person Coder; 11.02.2011
comment
Хорошо, я могу разобрать это на Java, когда мне это нужно, я просто хотел убедиться, что нет простого способа сделать это в ANTLR, прежде чем я сверну свою собственную обертку библиотеки дерева, лол. Также, возможно, я пропустил ваш ответ, чтобы я понял, что вы подразумеваете под псевдонимом и + сейчас. Но мне все еще неясна разница между квалифицированным идентификатором и $qualifiedIdentifier в правиле перезаписи. Вы где-то ответили на это, и я пропустил это? - person Coder; 11.02.2011
comment
@Coder, $qualifiedIdentifier, используемый в самом правиле (qualifiedIdentifier), вызывает рекурсивное заполнение дерева дочерними узлами: это немного сложно объяснить ... - person Bart Kiers; 11.02.2011
comment
Я предполагаю, что вы имеете в виду $qualifiedidentifier в перезаписи и квалифицированный идентификатор в правиле. Я провел больше тестов с этим, и я не думаю, что вы можете указать квалифицированный идентификатор в перезаписи. В этом случае есть смысл. Мое замешательство было только в перезаписи. Еще раз спасибо всем за помощь. Я рад, что это работает для меня. Это очень мощно, и я рад, что мне не пришлось сворачивать свой собственный (я подумал об этом, лол) - person Coder; 12.02.2011
comment
@Code, да, правильно: вам нужно $ перед qualifiedidentifier в этом правиле перезаписи. Пожалуйста. - person Bart Kiers; 12.02.2011