コンパイラ作成日誌0x0 『bisonを使ってみる』

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

コンパイラ作成日誌0x0 『bisonを使ってみる』

投稿記事 by MoNoQLoREATOR » 11年前

これから1年以内にコンパイラを作ります。
俺言語をC++言語に変換し、既存のC++コンパイラを使って実行ファイルを作成するという方式を考えています。
これなら1年以内に実現できそうです。

というわけで、その第一歩としてまずはbisonという構文解析プログラム作成ツールを使ってみました。
これは、BNFに似た言語を使って構文を定義すると、その構文に従って構文解析を行うCのコードを生成してくれるツールです。

今回は逆ポーランド記法の式を演算するものを作成してみました。
「BNFに似た言語」のコードがこちら

CODE:

%{

#include 
#include 
#include 

#define YYSTYPE double

int yylex(void);
void yyerror(const char* s);

%}

%token NUM

%%

input   : /* empty */
        | input line
;

line    : '\n'
        | expr '\n'
                { printf("\t%.10g\n", $1); }
;

expr    : NUM
        | expr expr '+'
                { $$ = $1 + $2;            }
        | expr expr '-'
                { $$ = $1 - $2;            }
        | expr expr '*'
                { $$ = $1 * $2;            }
        | expr expr '/'
                { $$ = $1 / $2;            }
        | expr expr '^'
                { $$ = pow($1, $2);        }
        | expr 'n'
                { $$ = -$1;                }
;

%%

/* トークン解析関数 */
int yylex(void)
{
  int c;

  /* 空白、タブは飛ばす */
  while((c = getchar()) == ' ' || c == '\t')
    ;
  /* 数値を切り出す */
  if(c == '.' || isdigit(c))
  {
    ungetc(c, stdin);
    scanf("%lf", &yylval);
    return NUM;
  }
  /* EOF を返す */
  if(c == EOF)
    return 0;
  /* 文字を返す */
  return c;
}

/* エラー表示関数 */
void yyerror(const char* s)
{
  fprintf(stderr, "error: %s\n", s);
}

int main(void)
{
  /* 構文解析関数 yyparse */
  return yyparse();
}
実はこのコード、このサイトのコードをそのまま使っていたりします。
まあ、今回はとりあえずbisonを'使ってみる'ということで。
このコードはコンソール画面で入力を受け付けて処理するものだったので、次回はファイルから受け付けてファイルに出力するものを作ってみます。

それでは、楽しいプログラミングライフを!
最後に編集したユーザー MoNoQLoREATOR on 2013年12月17日(火) 02:07 [ 編集 1 回目 ]

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前

Re: コンパイラ作成日誌0x0 

投稿記事 by h2so5 » 11年前

Valaっていう言語が似たようなことをやっているので参考になるかもしれません。

アバター
へろりくしょん
記事: 92
登録日時: 14年前

RE: コンパイラ作成日誌0x0 

投稿記事 by へろりくしょん » 11年前

Bison 便利ですよね。
ただ、まともな処理系を作ろうと思ったら、エラー処理が恐ろしく面倒です。

ここで言うエラーとは、構文エラーの事です。
エラーが見つかるたびに処理を止める。 というのも1つのポリシーだとは思いますが、
出来るならば、可能な限り多くのエラーを見つける事が親切だと思います。
しかし同時に、エラーの報告は必要最低限であるべきです。

例えばC言語において
for(i = 0; i < 10; i++
{
  int hoge;
}
と、for() 文を閉じ忘れた場合、) が抜けてるよ。 とだけ教えてあげるのが親切です。
ここで、予期しない { が現れたよ。 ここで宣言は出来ないよ。 hoge って何? とか、カッコの閉じ忘れに付随してずらーと並べるのはよろしくありませんね。

エラートークンを下手な所にいれてしまうと、コンフリクトが降り注ぐか、エラーメッセージのノンストップレボリューションです。

精度の高いエラー処理は思いの外難しいです。 のーみそとろけます。 私は死にました。
VC++ のエラーメッセージが神懸かって見えますよ。


後、Bison の yyerror() 関数は、そのままだと使い物にならないので、スケルトンを編集して使うといいです。
せめて引数に、行番号・トークン番号を渡すようにした方がいいでしょう。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: コンパイラ作成日誌0x0 

投稿記事 by MoNoQLoREATOR » 11年前

返信ありがとうございます。

>>h2so5さん
valaを少し調べてみましたが、とてもC#に似ていますね。
参考にしてみます。

>>へろりさん
そうですよね。エラー処理が一番の難関ですよね。
正直今のところ全く見通しが立っていません。
参考にしたサイトで本格的エラー処理を行っていたと思いますので参考にして熟考したいところです。
ただ、まだbisonを使うと決めたわけではないのですよ。
違うパーサを利用する可能性はまだまだあります。
とは言っても本質的な部分は変わらないのでしょうけれど。