以下のコード例では、小型電卓に対して yacc を完全に適用する例を示します。この電卓は、a 〜 z の名前が付いた 26 個のレジスタを持っており、演算子 +、-、*、/、%、&、| と代入演算子で構成された算術式を使用できます。
最上位レベルの式が代入の場合は、その代入だけが行われます。それ以外の場合は、式が出力されます。C 言語の場合と同じように、0 で始まる整数は 8 進数とみなされます。それ以外は、10 進数とみなされます。
yacc 仕様の例として、この電卓プログラムでは、優先度とあいまいさの使い方を示し、簡単な回復処理も含まれています。大幅に簡略化されているのは字句アナライザの部分で、大部分のアプリケーションよりもかなり単純なものになっています。また出力は行ごとにすぐ生成されます。
構文規則によって 8 進 と 10 進の整数を読み取る方法に注目してください。このジョブは、字句アナライザで実行することもできます。
%{ # include <stdio.h> # include <ctype.h> int regs[26]; int base; %} %start list %token DIGIT LETTER %left '|' %left '&' %left '+' '-' %left '*' '/' %' %left UMINUS /* 単項演算子 - の優先度を指定 */ %% /* 規則セクションの開始 */ list : /* 空 */ | list stat '¥n' | list error '¥n' { yyerrok; } ; stat : expr { (void) printf( "%d¥n", $1 ); } | LETTER '=' expr { regs[$1] = $3; } ; expr : '(' expr ')' { $$ = $2; } | expr '+' expr { $$ = $1 + $3; } | expr '-' expr { $$ = $1 - $3; { | expr '*' expr { $$ = $1 * $3; } | expr '/' expr { $$ = $1 / $3; } | exp '%' expr { $$ = $1 % $3; } | expr '&' expr { $$ = $1 & $3; } | expr '|' expr { $$ = $1 | $3; } | '-' expr %prec UMINUS { $$ = -$2; } | LETTER { $$ = reg[$1]; } | number ; number : DIGIT { $$ = $1; base = ($1= =0) ? 8 ; 10; } | number DIGIT { $$ = base * $1 + $2; } ; %% /* サブルーチンセクションの開始 */ int yylex( ) /* 字句解析ルーチン */ { /* 小文字の場合は LETTER を返す */ /* yylval = 0 〜 25、DIGIT を返す */ /* 数字の場合、yylval = 0 〜 9 */ /* その他の文字はすぐに返される */ int c; /* 空白は読み飛ばす */ while ((c = getchar()) = = ' ') ; /* c は空白以外の文字 */ if (islower(c)) { yylval = c - 'a'; return (LETTER); } if (isdigit(c)) { yylval = c - '0'; return (DIGIT); } return (c); } |