1

論理演算子に問題があります

私の .y ファイルには次のものがあります。

expr: expr oper1 expr { $$=insert_expression($2, $1, $3); }
     | expr oper2 expr { $$=insert_expression($2, $1, $3); }
     ;

私の .l ファイルでは、oper1 と oper2 が次のようになっていると判断しました。

"<" | ">" | "=" | "<>" | "<=" | ">=" { return oper1; }
"AND" | "OR" { return oper2; }

次に、値を入れる構造があります。

typedef struct _Expression
{
    char *oper;
    struct _Expression *ex1;
    struct _Expression *ex2;
} is_expression;

値を入れます:

is_expression* insert_expression(char* oper, is_expression *expr1, is_expression *expr2)
{
    is_expression* e = (is_expression*)malloc(sizeof(is_expression));

    e->ex1 = expr1;
    e->ex2 = expr2;
    e->oper = oper;

    return e;
}

そして最後にそれらを表示します:

void show_expression(is_expression *e)
{
    show_expression(e->ex1);
    printf("%s", e->oper);
    show_expression(e->ex2);
}

しかし、expr oper expr を使用するたびにセグメンテーション違反が発生します。

Program received signal SIGSEGV, Segmentation Fault

私が間違っていることについてのアイデアはありますか?

ありがとう

4

3 に答える 3

1

どれどれ:

void show_expression(is_expression *e)
{
    show_expression(e->ex1);
    printf("%s", e->oper);
    show_expression(e->ex2);
}

再帰には終了する方法が必要です!

大きな手がかりはprintf、演算子を出力するものが 1 つしかないことです。しかし、ツリーには演算子以外のもの、つまりオペランドがあります。

式ツリーでは、これらのオペランドはリーフ ノードです。それらはどのように表されますか?ex1おそらくandのヌルポインタを持っていますex2よね?(ゴミではないことを願っています: すべてのパーサー ルールは$$何らかの値に影響しますよね?)

また、yacc ファイルには、それ以外にも多くの情報が含まれている必要があります。あなたが示したルールはexpr、終端記号のシーケンスに還元できないため、それ自体では存在できません。

于 2012-04-11T18:36:36.260 に答える
0

の値を正しくするには、可能なすべての型を指定$nするディレクティブが必要です。次に、 /ディレクティブ%unionでそれらの型を使用する必要があります。%token%type

%union {
    is_expression  *exp;
    char           *str;
}

%token<str> oper1 oper2
%type<exp> expr

次に、.lファイルに値が正しく設定されていることも確認する必要があります。

"<" | ">" | "=" | "<>" | "<=" | ">=" { yylval.str = strdup(yytext); return oper1; }
"AND" | "OR" { yylval.str = strdup(yytext); return oper2; }

それ以外の場合は、最初のオペランドとしてランダムガベージをに渡しinsert_expression、で何かをしようとするとクラッシュしますoper(ランダムガベージを指しているため)

于 2012-04-12T00:22:53.867 に答える
0

すべてのトークンのデフォルト タイプは ですint。持っていない場合

%union {
    char *oper1
    char *oper2
}

問題が発生します。そのままでは、ポインターと整数が混在しています。これにより、プログラムが任意のメモリにアクセスしようとし、segfault が発生します。

編集:

よし、それを gdb または私の好みのcgdbで起動します。

cgdb yourCompiledParser
> r (add necessary command line switches)
when it segfaults
> backtrace

これにより、失敗しているおおよその場所が得られ、ブレークポイントが必要な場所が示されます。gdb/cgdb のデバッグのヒントについては、この記事をご覧ください。

于 2012-04-11T18:35:44.200 に答える