0

私は現在、初めて Flex と Bison で遊んでいます。Bison man pageで文脈上の優先順位について読みました。ディレクティブを使用せずに最小限の例を作成しようとしました%precが、それが実際に何をするのかよくわかっていません。これが私の最小限の例です。

フレックスファイル

%option noyywrap
%{
#include <iostream>
#include "parser.h"

int lineNum = 1;
%}

%%

[ \t]+          ;
\n              { lineNum++; }
\/\/(.*)        ;
"+"             { return PLUS; }
"-"             { return MINUS; }
"*"             { return MULTIPLY; }

[0-9]+          {
                    yylval.int_val = atoi(yytext);
                    return INT;
                }

.               { std::cout << "Unknown token " << yytext << " at line " << lineNum << std::endl; yyterminate(); }

%%

バイソンファイル

%{
#include <iostream>
#include <string>

extern int lineNum;
extern int yylex();
void yyerror(const char* e) { std::cerr << "ERROR ON LINE " << lineNum << ": " << e << std::endl; }

extern int eval;
%}

%union
{
    int int_val;
}

%define parse.error verbose

%token <int_val> INT PLUS MINUS MULTIPLY

%type <int_val> expr

%left PLUS MINUS
%left MULTIPLY

%start expr

%%

expr    :   expr PLUS expr { $$ = $1 + $3; eval = $$; }
        |   expr MINUS expr { $$ = $1 - $3; eval = $$; }
        |   expr MULTIPLY expr { $$ = $1 * $3; eval = $$; }
        |   MINUS expr { $$ = -$2; eval = $$; }
        |   INT
        ;

%%

メイン cpp ファイル

#include <iostream>

int eval = 0;
extern int yyparse();

int main()
{
    yyparse();
    std::cout << eval << std::endl;
    return 0;
}

詳細なテストは行っていませんが、単項マイナスを使用したすべての組み合わせで、正しい結果が得られました。私は幸運ですか、それとも%precディレクティブは特別な場合にのみ必要ですか? また、スタック上のシフトと削減を自分で評価できるように、ディレクティブが必要な場合の例をいただければ幸いです。

ありがとう

4

1 に答える 1

2

単項マイナス演算子は -1 による乗算と同等であり、乗算は結合的であるため、コードは間違った解析を生成しますが、正しい結果を生成します。そのため、代わりに-2*3as として解析していても、結果の値は同じです。-(2*3)(-2)*3

のような式の場合、左結合である-2-3と宣言しているため、正しい解析が得られます。-(-2)-3-(2-3)(1-2)-31-(2-3)

では、単項マイナスの優先順位を宣言する必要がないのはいつですか? もしも

  • プレフィックスとインフィックスの両方である唯一の演算子は-

  • (binary) −, −( ab )=(− a )⊕ bより優先順位の高いすべての演算子 ⊕ ;

  • 正しい解析ツリーを取得することは気にしません。

これは に対して*は機能しますが、通常 (整数)/およびに対しては失敗します%

于 2015-06-26T06:32:25.600 に答える