あまり参考資料がなかったので苦労しました。 苦労したところ、経験して理解したことについてメモしていきます。 基本的な文法については、他のぺーじを見て勉強してください。
ちなみにここでは、linuxにインストールされている、 「bison,flex」を利用しています。(多分、どこでも同じでしょうけど。)
flexファイル「*.l」と、bisonファイル「*.y」がソースファイルになる。 ここでは、「parse.y」と「parsel.l」を例にとって説明する。
コンパイルの手順
下の一文を必ず加える。
場合によっては、
数値や単語などにマッチしたときに、 その値をbisonファイルに返したい時が多くある。 サンプルプログラムを見ると、 yylvalをintやdoubleなどに指定してそれに代入する方法で値を戻している。
例えば、、
ところが、
しかし、型変換、なんて荒業は使わなくても良い方法がある。 unionを利用する。
parse.y
parsel.l
([0-9]+)|([0-9]+\.[0-9]*) { sscanf (yytext, "%lf", &yylval.n); return (NUMBER); } [a-zA-Z]+ {yylval.ch = yytext; return (CHAR);}
当然利用可能。ただ、落とし穴が多少あるので注意する点を書く。 注意する点は3つ。
configure.in
AC_INIT(parsel.l) AM_INIT_AUTOMAKE(calc, 0.1.0) dnl Checks for programs. AC_PROG_CC AC_PROG_YACC AM_PROG_LEX dnl Checks for libraries. dnl Replace `main' with a function in -lfl: AC_CHECK_LIB(fl, main) dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(malloc.h unistd.h) AC_C_CONST dnl Checks for library functions. AC_OUTPUT(Makefile)
Makefile.am
noinst_PROGRAMS = parser parser_SOURCES = parse.y parsel.l YFLAGS = -d
automake, autoconfでは、bisonを実行したあと、 ファイル名を自動的に変更指定しまう。 そのため、インクルードするはずだったファイル名が変わってしまう。 その点に注意する。
具体的には、「parse.y」 →「parse.tab.c 、 parse.tab.h」 → 「parse.c、parse.h」という変更が行われる。 よって、#include "parse.tab.h"ではなく、#include "parse.h" と、ソースファイルに書いておかなければならない。
上でも書いたが、ファイル名を勝手に書き直してくれてしまう。 ということで、「parse.l」と「parse.y」は、automakeをつかうと、 最終的なファイル名が同じになってしまう。
これではエラーが起きても当然なので、これを避けるために、 異なる名前にする。 (あまり美しい解決方法ではない。 その他の方法を知っている人は、ぜひ教えてください。)
パーサ以外はC++でオブジェクト指向でプログラムしている場合、 当然bisonで生成されるコードでも、せめてクラスくらいは理解して欲しい。 そのためには、C++のコードである必要がある。
automake、autoconfを利用する場合、Parse.y++などという名前にしておくと、 自動的にParse.c++という名前に置き換わる。 同様に、Parse.yyはParse.ccに置き換わる。 この機能を利用すれば、C++のコードとしてコンパイルするので、 クラスなどを理解することができるようになる。
ただこれだと、classの中にパーサを埋め込むことができない。 (もしかしたら必要ないのかも知れないけれど)。 bison++というツールを使うと、もしかしたらできるのかもしれないが、 調べていない。 少なくともそのままでは、automake、autoconfでは対応していない。
(後日談) manによるとbison++とflex++でparserクラスがつくれるらしい. あと,Yet-another Object-Oriented Lex (YooLex)ってのもあるらしい.