コンパイラの勉強(第二章を読む)

コンパイラ構成法

コンパイラ構成法

大学でコンパイラについて学んだ。でも、今は相当忘れてしまっているから、ちょっと思い出しつつ、勉強していこうと思う。普段、職業としてプログラムを書いていると、バグが出た出ないとかそういう点ばかりに目がいってしまう。でも、プログラムは書かれた通りにしか動かない。というわけで、すべてのバグは人間が作り出したものだ。動作がちゃんと掴めていないから、思った通りに動かないということになってしまう。動作をちゃんと把握するためにも、コンパイラについて学ぶことは有用かと思われる。というわけで、構文解析から読書する。

コンパイル&実行

コンパイルするには次のようにコマンドを打つ。

$ bison -y prog2-1.y
$ gcc y.tab.c -ly -o prog2-1

実行してみる

$ ./prog2-1
1+1

となるので、受理されていることが分かる。

prog2-1.y

/* プログラム2.1(21ページ) */

/*  Yaccで記述した式の定義  */

%%

input  : expr '\n' ;
expr   : expr '+' term | expr '-' term | term ;
term   : term '*' factor | term '/' factor | factor ;
factor : num | '(' expr ')' ;
     num    : digit | num digit ;
     digit  : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;

%%

yylex()
{
  return getchar();
}

prog2-2.y

/* プログラム2.2(25ページ)*/

/*  構文解析の過程をトレース */

%%

input  : expr '\n'        { printf("correct expression\n"); }
       ;

expr   : expr '+' term    { printf("expr + term -> expr\n"); }
       | expr '-' term    { printf("expr - term -> expr\n"); }
       | term             { printf("term -> expr\n"); }
       ;

term   : term '*' factor  { printf("term * factor ->term\n"); }
       | term '/' factor  { printf("term / factor ->term\n"); }
       | factor           { printf("factor -> term\n"); }
       ;

factor : 'i'              { printf("i -> factor\n"); }
       | '(' expr ')'     { printf("( expr ) -> factor\n"); }
       ;
%%

yylex()
{
  int c;

  switch (c =getchar()) {
  case EOF:  printf("EOF detected\n"); break;
  case '\n': printf("--> '\\n'\n");    break;
  default:   printf("--> '%c'\n", c);  break;
  }
  return c;
}