以下のコード例では、小型電卓に対して 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);
}
|