Свертывание некоторых поддеревьев AST в Antlr с использованием правил перезаписи - PullRequest
2 голосов
/ 11 февраля 2011

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

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

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

и, скажем, у меня есть декларация пакета "package abc" (кстати, анализатор Java)

То, что я получаю сейчас, - это что-то в форме (package (. (. Ab) c))

, что я хочу, это вставить пакет так, чтобы я получил (package abc)

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

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

Я понимаю, что вы подразумеваете под псевдонимом и + сейчас.Но мне все еще неясно, в чем разница между qualIItier и $ qualIdentifier в правиле перезаписи.

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

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]

1 Ответ

1 голос
/ 11 февраля 2011

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

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+)
  ;

EDIT

По поводу ваших комментариев:

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

Я немного запутался в значении + в правиле перезаписи. В документации здесь 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 identifier: qualIdentifier -> $ identifier" и использовании quanlifiedIdentifier против $ quanlifiedIdentifier

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

name
  :  ID '.' ID
  ;

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

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

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

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

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

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

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

(СНИП)

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

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

...