4

私はC/C ++を使用してBison&Flexで簡単な計算機をプログラミングしています(ロジックはBisonで行われ、C / C ++部分はSTLなどのデータ構造を担当します)。

私は次の問題を抱えています:

私の計算機では、ドル記号$はi++と++i(接頭辞と接尾辞の両方)を意味します。例:

int y = 3;
-> $y = 4
-> y$ = 4

ユーザーが:をヒットしたとき、が評価されたint_expression1 && int_expression2場合(つまり、false)、私は評価するためにバイソンになりたくありません!int_expression10int_expression2

例えば ​​:

int a = 0 ; 
int x = 2 ;

そして、ユーザーがヒットします:int z = a&&x$..。

したがって、変数aはに評価されます0。したがって、評価したくありませんがx、それでも1ずつ増加します...これがbison /c++のコードです。

%union
{
    int int_value;
    double double_value;
    char* string_value;
}

%type <int_value> int_expr
%type <double_value> double_expr
%type <double_value> cmp_expr

int_expr:

    | int_expr '&&' int_expr    { /* And operation between two integers */
                      if ($1 == 0) 
                        $$ = 0;
                      else  // calc
                        $$ = $1 && $3;          
                    }

最初の式がすでにfalse(つまり)と評価されている場合、2番目の式を評価しないようにbisonに指示するにはどうすればよい0ですか?

4

2 に答える 2

2

広範な解説を答えに変換する:

最初の式がすでにfalseと評価されている場合、2番目の式を評価しないようにBisonに指示するにはどうすればよいですか?

Bisonではなく、評価を行うのはあなたのコードです。それが属するところに「非難」を置きなさい。

&&RHSが評価される前に、ルールを処理していることを検出する必要があります。最初の評価が0の場合、評価を一時停止するコードを&&2番目のコードの前後に挿入する必要がある可能性があります。また、他のすべての評価コードを変更して、「評価しない」フラグを確認して従う必要があります。 。int_exprint_expr

または、Bisonに解析を実行させ、解析時に評価するのではなく、解析の完了時に実行するプログラムを作成します。これは、はるかに大きな変更のセットです。

2番目のint_exprの前にコードを配置してもよろしいですか?私はそれを行うためのもっともらしい方法を見つけることができないようです。int_exprこれは素晴らしいトリックですが、評価全体を台無しにすることなく、2番目を評価しないようにBisonに実際に指示する方法を見つけることができません。

評価することになっていないときに評価されないようにコードを作成する必要があります。Bisonの構文は次のとおりです。

| int_expr '&&' {...code 1...} int_expr {...code 2...}

「コード1」はチェックを行い$1、評価を停止するように調整します(グローバル変数などを設定します)。「コード2」は条件付きで評価されます$4(「コード1」は現在$ 3であるため4)。すべての評価コードは、「コード1」の指示に従わなければなりません—「コード1」が「評価しない」と言っている場合は評価してはなりません。または、私が提案し、aselle が提案したことを行うことができます; 個別に解析および評価します。

UNIXプログラミング環境についての2番目のaselleの提案。hocそこには、読む価値のある計算機(高階計算機と呼ばれます)の開発に関する章全体があります。ただし、この本は1984年に出版されたものであり、C標準よりもかなり前から存在していることに注意してください。Cコードにはプロトタイプはなく、(最新の標準では)いくつかの自由が必要です。私は現代のChoc6で(それらの最後のバージョンがhoc説明しています;バージョン1〜3も)持っています—必要に応じて私に連絡してください(私のプロファイルを参照してください)。

それが問題です。使用できないため、ルールの途中で評価を停止することはできませんreturn(使用できますが、使用できません。プログラムが終了します)。| intExpr '&&' { if ($1 == 0) {/* turn off a flag */ } } intExpr { /* code */}終了$3すると、$4は自動的に評価されます。

ルールの途中で評価を停止することはできますが、可能性を考慮して式評価コードブロックをコーディングする必要があります。そして、私が「評価をやめる」と言ったとき、私は「計算をやめる」という意味であり、「そのトラックでパーサーをやめる」という意味ではありませんでした。解析を続行する必要があります。値を計算するコードは、評価が不要な場合ではなく、評価が必要な場合にのみ評価する必要があります。これは(ugh!)グローバルフラグであるか、他のメカニズムを使用している可能性があります。

パーサーをコードジェネレーターに変換し、解析後にコードを実行するのがおそらく最善です。この種の複雑さは、それが良い戦略である理由です。

@JonathanLeffler:あなたは確かに王様です!これは答えになるはずです!!!

今それは答えです。

于 2012-12-01T18:15:08.663 に答える
1

電卓で評価する前に、他の表現を生成したいと思うことはほぼ間違いありません。解析木やastは古典的な手法ですが、単純なスタックマシンも人気があります。これを行う方法の素晴らしい例はたくさんありますが、私のお気に入りは http://www.amazon.com/Unix-Programming-Environment-Prentice-Hall-Software/dp/013937681X で、単純な直接評価ツールの使用方法を示していますあなたが yacc (旧バイソン) で作成したようなものを、BASIC とほぼ同じくらい強力なプログラミング言語にまで発展させます。非常に少ないページですべて。かなり古い本ですが、一読の価値ありです。

また、スカラーと 3 つのベクトル用の単純な式言語計算機であるSeExpr http://www.disneyanimation.com/technology/seexpr.htmlも参照してください。https://github.com/wdas/SeExpr/blob/master/src/SeExpr/SeExprNode.cppの 313 行目を見る と、eval() 関数の && 実装が表示されます。

void
SeExprAndNode::eval(SeVec3d& result) const
{
    // operands and result must be scalar
    SeVec3d a, b;
    child(0)->eval(a);
    if (!a[0]) {
    result[0] = 0;
    } else { 
    child(1)->eval(b);
    result[0] = (b[0] != 0.0); 
    }
}

このファイルには、解析ツリー内の操作を表すすべてのオブジェクトが含まれています。これらのオブジェクトは、コードが解析されるときに生成されます (これらは yacc のアクションです)。お役に立てれば。

于 2012-12-01T16:07:37.210 に答える