0

bison を使用して単純な言語のコンパイラを構築しています。文法の一部を次に示します。

stmt: IF '(' exp ')' stmt{
        if(exp) $$=$5;
      }
      |PRINT ';' {
        cout<<"hi";
       }
;

exp: true|false
;

この if ステートメントの解析で問題が発生しました: 次のコードがあるとします:

if(false) print;

stmt->PRINT は stmt-> IF (exp) stmt の前に解析されるため、「hi」は出力されます。私に何ができる?(私はバイソンとコンパイルが初めてなので、質問のエラーを自由に修正してください)。

4

2 に答える 2

1

それは当然です。print ステートメントを解析しているので、「cout」が実行されます。あなたがしようとしているのは、印刷命令を格納するバイトコードのようなものを作成することです。次に、この出力命令を if 式と組み合わせて、if ステートメント命令を作成できます。

頭のてっぺんから、Bison の正確なステートメントを思い出すことはできません (ドキュメントを調べる必要があります) が、通常、値スタックの型、通常は構造体の結合を定義する必要があります。 this (ただし、値スタックのタイプにする bison コマンドがあります)。

union {
 int type;
 struct {
  int type; // must always be first, this is a union
  union stmt *stmt; // conditional stmt to execute
  union expr *expr; // expression to evaluate
 } if_stmt;
 struct {
  int type;
 } print_stmt;
} stmt;

これにより、次のようなルールを文法に入れることができます

stmt: IF '(' expr ')' stmt   { $$.type = IF_STMT; $$.if_stmt.expr = copy ($3); $$.if_stmt.stmt = copy ($5); }

など(そこにoff-by-oneエラーがある可能性があり、$sが0または1で始まるかどうか思い出せません)。copyメモリ割り当てを管理するには、関数を自分で実装する必要があります。bison は値のスタックのみを提供します。最後に、ツリー (一般に構文ツリーと呼ばれていると思います) が作成されます。このツリーを実行して、IF_STMT タイプのノードについて if_stmt.expr を評価し、true が返された場合は if_stmt.stmt を評価します。等々。

次に、言語の解析が終了したら、バイト コードを「実行」できます。if ステートメントにヒットすると、式を評価し、true (そうではない) の場合、上記で概説したようにステートメントを実行します。 print-instruction を実行すると (式が false であるため、実行されません)、'hi' が出力され、探している結果が得られます (つまり、何も出力されません)。

それはあなたがそれについて行く必要がある方法です。バイソンで解析中に条件付き実行を (簡単に) 行うことはできません。

于 2010-01-10T14:53:35.750 に答える
0

ifだけで機能させたい場合は、EXP evalでスタックを作成し、EXPの真の値をスタックにプッシュし、IFブロックで関数呼び出しを実行できるかどうかを確認し、割り当てなどを行うことができます。スタック上の値と IF リダクションで、スタックから値をポップするだけです。

元:

    Stack (bool) x;


    CanExec()
    {
        if x== NULL //no IF yet
            return true;
        for i in x
            if i == false
                return false; //if we have at last 1 if banch with FALSE, we cannot execute it
        return true;
    }

    if_stmt:    IF if_exp block                {Pop()}
                |IF if_exp block else block    {Pop()}

    if_exp:     '(' exp ')'                    {Push((bool)exp)}

    else:       ELSE                           {tmp = Pop(); Push(!tmp)}

今、あなたがしなければならないことは、CanExec() の場合にすべての副作用操作をチェックすることだけです

于 2013-12-04T18:00:13.710 に答える