2011-03-02 10 views
0

私はANTLRを使用してパスカルインタプリタを作成しようとしていますが、現在はASTツリーを歩いている間にループを処理する際にいくつかの問題があります。ANTLRでのループの反復

parametricLoop 
    : FOR IDENTIFIER ASSIGN start = integerExpression TO end = integerExpression DO 
    statement 
    -> ^(PARAMETRIC_LOOP IDENTIFIER $start $end statement) 
    ; 

(とdowntoを有する変異体は無視される):forループ例えば は、以下のように解析されます。 どのようにすれば、ループの実行を必要に応じて何度も繰り返すことができますか?私はそのためにinput.Mark()とinput.Rewind()を使うべきであることを知っています。しかし、どこに置くべきでしょうか?私の現在の間違っバリアントは、(ターゲット言語は、C#で)そうなります

parametricLoop 
    : 
     ^(
      PARAMETRIC_LOOP 
      IDENTIFIER 
      start = integerExpression 
      { 
       Variable parameter = Members.variable($IDENTIFIER.text); 
       parameter.value = $start.result; 
      } 
      end = integerExpression 
      { 
       int end_value = $end.result; 
       if ((int)parameter.value > end_value) goto EndLoop; 
       parametric_loop_start = input.Mark(); 
      } 
      statement 
      { 
       parameter.value = (int)parameter.value + 1; 
       if ((int)parameter.value <= end_value) 
        input.Rewind(parametric_loop_start); 
      ) 
      { 
       EndLoop: ; 
      } 
     ; 

(ホープすべてが理解できます)。繰り返しの条件は、ステートメントの最初の実行の前にチェックする必要があります。 MarkとRewindを@initと@afterを含む別のコードブロックに配置してプレイしようとしましたが、後ろにgotoをループヘッドに入れましたが、たびにループが繰り返されるか、Unexpected token metのような例外がスローされました= '(代入)。私は、どのように適切に動作させるのか、どのような実際的な例も見つけることができません。誰もこの問題の解決策を提案できますか?

+0

これらのMark()およびRewind(...)メソッドは、ツリーの文法から呼び出されます。それらは例外を投げていると私は推測する?あなたは「あなたはinput.Mark()とinput.Rewind()」を使用することを知っていますが、あなたにそれを教えてくれましたか?単純なツリーベースのインタプリタについては、以下を参照してください。http://www.antlr.org/wiki/display/ANTLR3/Simple+tree-based+interpeter –

+0

これは、文法を組み合わせて実行しようとしている人です。木文法でこれをやっています(成功することなく、これをやろうとしていることに注意してください)。ツリー文法はCommonTreeオブジェクトの構造化されたコレクションで、AFAIKの 'mark()'や 'rewind(...)'メソッドにはアクセスできません。さらに、あなたの(ツリー)文法の中の複雑な構造を解釈することは、(IMHO)行く方法ではなく、私は本当にここであなたのための「速い修正」を見ません。これを「適切な」方法で行うことは、ページがいっぱいの手頃なサイズの記事を構成するでしょう。 –

答えて

0

私はANTLRを使っていませんが、あなたが解析している間にプログラムを実行しようとしているようですが、それは実際にはパーサーが設計されたものではありません(単純な算術式は、しかし、あなたが発見したように、ループには問題があります)。構文解析をのみを使用してASTを構築することを強くお勧めします。したがって、parametricLoopのパーサーコードは、変数、条件、および本文を表す子ノードを持つループを表すツリーノードを作成するだけです。その後、別の通常のC#クラス(パーサーによって生成されたASTを提供する)では、何らかの方法でツリーをトラバースしてコードを実行すると、順番にノード間を行き来する自由が完全に得られますループの実行をシミュレートします。

0

は似たような問題が、いくつかの点解決:

  1. を私のために働くことはありませんあなたが代わりにCommonTreeNodeStream、CommonTreeNodeStreamのBufferedTreeNodeStreamを使用する必要があるようです(見つけるために長い時間を苦労)

  2. 利用しよう

ここで私はリストコマンドのコードですが、これは簡単にこのstyに変更することができますル:

list returns [Object r] 
    : ^(LIST ID 
      {int e_index = input.Index;} 
      exp=. 
      {int s_index = input.Index;} 
      statements=. 
     ) 
     { 
      int next = input.Index; 
      input.Seek(e_index); 
      object list = expression(); 
      foreach(object o in (IEnumerable<object>)list) 
      { 
       model[$ID.Text] = o; 
       input.Seek(s_index); 
       $r += optional_block().ToString(); 
      } 
      input.Seek(next); 
     } 
1

私はANTLR 3.4で動作し、私はクラスCommonTreeNodeStreamで動作する解決策を見つけました。

基本的には、私のツリーパーサーの新しいインスタンスを分割して、すべてのサブツリーを分析しました。私のサンプルコードではwhileループを定義しています:

tree grammar Interpreter; 
... 
@members 
{ 
    ... 
    private Interpreter (CommonTree node, Map<String, Integer> symbolTable) 
    { 
    this (new CommonTreeNodeStream (node)); 
    ... 
    } 
    ... 
} 
... 
stmt : ... 
     | ^(WHILE c=. s1=.) // ^(WHILE cond stmt) 
      { 
       for (;;) 
       { 
       Interpreter condition = new Interpreter (c, this.symbolTable); 
       boolean  result = condition.cond(); 
       if (! result) 
        break; 

       Interpreter statement = new Interpreter (s1, this.symbolTable); 
       statement.stmt(); 
       } 
      } 
... 
cond returns [boolean result] 
          : ^(LT e1=expr e2=expr) {$result = ($e1.value < $e2.value);} 
          | ...