Как избежать создания промежуточных и бесполезных узлов AST с помощью ANTLR3? - PullRequest
2 голосов
/ 17 мая 2011

Я написал грамматику ANTLR3, разделенную на более мелкие правила для повышения читабельности. Например:

messageSequenceChart:
  'msc' mscHead bmsc 'endmsc' end
;

# Where mscHead is a shortcut to :
mscHead:
  mscName mscParameterDecl? timeOffset? end
  mscInstInterface? mscGateInterface
;

Я знаю, что встроенная функция построения AST ANTLR позволяет пользователю объявлять промежуточные узлы AST, которых не будет в конечном AST. Но что, если вы построите AST вручную?

messageSequenceChart returns [msc::MessageSequenceChart* n = 0]:
  'msc' mscHead bmsc'endmsc' end
  {
    $n = new msc::MessageSequenceChart(/* mscHead subrules accessors like $mscHead.mscName.n ? */
                                       $bmsc.n);
  }
;

mscHead:
  mscName mscParameterDecl? timeOffset? end
;

Документация не говорит о такой вещи. Похоже, мне придется создавать узлы для каждого промежуточного правила, чтобы иметь доступ к их результату подправил.

Кто-нибудь знает лучшее решение?

Спасибо.

1 Ответ

2 голосов
/ 17 мая 2011

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

Следующая демонстрация показывает, как это сделать. Хотя это не в C, я уверен, что вы сможете настроить его так, чтобы он соответствовал вашим потребностям:

grammar Test;

parse
  :  sub EOF {System.out.printf("second=\%s\n", $sub.second);}
  ;

sub returns [String first, String second, String third]
  :  a=INT b=INT c=INT
     {
       $first = $a.text;
       $second = $b.text;
       $third = $c.text;
     }
  ;

INT
  :  '0'..'9'+
  ;

SPACE
  :  ' ' {$channel=HIDDEN;}
  ;

И если вы анализируете вход "12 34 56" сгенерированным парсером, second=34 выводится на консоль, как вы можете видеть после запуска:

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    TestLexer lex = new TestLexer(new ANTLRStringStream("12 34 56"));
    TokenStream tokens = new TokenRewriteStream(lex);
    TestParser parser = new TestParser(tokens);
    parser.parse();
  }
}

Итак, ярлык из правила parse, например $sub.INT или $sub.$a, для доступа к одному из трех токенов INT, в не , к сожалению, возможно.

...