プログラミングユーティリティ

簡単な例

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