Next: , Previous: RPN Calc, Up: Examples


2.2 中間記法電卓:calc

後置記法演算子に代わって中間記法演算子を扱うように rpcalcを変更します。 中間記法には、演算子の優先順位の概念と、 適切な深さに入れ子できるかっこが必要です。 中間記法電卓を作るためのBisonソースファイル calc.yを示します。

     /* 中間記法電卓 -- calc */
     
     %{
     #define YYSTYPE double
     #include <math.h>
     %}
     
     /* BISON宣言 */
     %token NUM
     %left '-' '+'
     %left '*' '/'
     %left NEG     /* negation--単項マイナス */
     %right '^'    /* べき乗関数        */
     
     /* 文法規則が続く */
     %%
     input:    /* 空文字列 */
             | input line
     ;
     
     line:     '\n'
             | exp '\n'  { printf ("\t%.10g\n", $1); }
     ;
     
     exp:      NUM                { $$ = $1;         }
             | exp '+' exp        { $$ = $1 + $3;    }
             | exp '-' exp        { $$ = $1 - $3;    }
             | exp '*' exp        { $$ = $1 * $3;    }
             | exp '/' exp        { $$ = $1 / $3;    }
             | '-' exp  %prec NEG { $$ = -$2;        }
             | exp '^' exp        { $$ = pow ($1, $3); }
             | '(' exp ')'        { $$ = $2;         }
     ;
     %%

yylexyyerrormain関数は、 前の例のものと同じです。

このプログラムには、2つの重要な特徴があります。

第2の部分(Bison宣言部)では、 %leftがトークンの型とそれが左結合演算子であると宣言します。 宣言%left%right(右結合演算子)は、 結合性を持たないトークン型名を宣言するために使われる%tokenの代わりに なります (1文字のリテラルであるトークンは、通常、宣言する必要がありません。 ここでは、結合性を宣言します)。

演算子の優先順位は、宣言が書かれる行の順序で決まります。 後から宣言された演算子ほど、高い優先順位を持ちます。 したがって、べき乗の優先順位がもっとも高く、 単項の負(NEG)、「‘*’」と「‘/’」と続きます。 See Operator Precedence

もう1つの重要な特徴は、単項の負の演算子のために文法部分にある %precです。 %precは、単純にBisonに対して、規則‘| '-' exp’は NEGと同じ優先順位を持つように指示し、 この例ではどちらも2番目に高い優先順位を持ちます。

以下はcalc.yの実行例です。

     % calc
     4 + 4.5 - (34/(8*3+-3))
     6.880952381
     -56 + 2
     -54
     3 ^ 2
     9