YACC/LEXという字句解析/構文解析の仕組みをちょっとかじったことがあり、気になっていた。これを使いこなせれば、文字列を扱うことなら何でもできるといったすぐれもので、言ってみればちょっとしたコンパイラを作るための仕組みである。で、この仕組みをWindowsパソコン上で使えないかといろいろやってみた。で、やっとのことでWindows上でUNIX環境をシミュレートするCYGWINなるものをセットアップしCYGWIN上でgccやyacc/lexを使って構文解析ツールを作るための環境構築まで漕ぎ着けた。そしてここでふと、VC++.NETの開発環境下でYACC/LEXを使えないかと思い立ち、いろいろ粘ってみた。その時の記録である。自分が技術的なことで困っていろいろな人のブログからヒントを得て大いに助かっているので、もし同じようなところで困っている人がいたらなんらかの「参考」になればとの思いである。
★VC++.NET2003にてYACC/LEX(bison/flex)を利用する
1. まず前提条件として、WindowsPC上でcygwinのインストールが完了していること。
C:\cygwin\bin, C:\cygwin\lib、下にYACC/LEX(bison/flex)関係のコマンドおよびライブラリが入っていること。つまりcygwinを起動してシェル下にて、bison/flexがちゃんと利用できることを確認。例えば、
flex sample.l -> lex.yy.cが生成
bison -d sample.y -> sample.tab.cとsample.tab.hが生成
gcc main.c sample.tab.c lex.yy.c -lfl -o sample (←あくまで例)
がちゃんとコンパイル&リンク通ってsampleコマンドが所定の機能を果たすこと。
2. VC++.NET2003にて、まずは「Win32コンソールプロジェクト」で新規プロジェクトを生成してみる。例としてプロジェクト名を「aaa」と仮定する。
3. aaa.cppソースを以下に記述。main()からyyparse()を呼んでいるだけのもの。引数がなければ標準入力から、引数があればその引数で指定されたファイルがそれぞれ入力データとしてyyparse()に引き渡される。
-----------------------------------------------------------
#include <stdio.h>
#include "stdafx.h"
extern "C" int yyparse(); // <-- ※
extern "C" FILE *yyin; // <--※
int _tmain(int argc, _TCHAR* argv[])
{
if(argc > 1) {
if(yyin = fopen(argv[1], "r")) {
yyparse();
fclose(yyin);
}
} else {
yyparse();
}
return 0;
}
------------------------------------------------------------
※extern "C"をつけないとリンクでエラーになるようです。試行錯誤でみつけた。
4. 「ソースファイル」を右クリックして「追加」→「新しい項目の追加」でテキストファイルを選んで、aaa.l を追加する。同様にaaa.yも追加する。
5. aaa.lとaaa.yにそれぞれ字句解析と構文解析の規則を記述する。
6. aaa.lを右クリックしてプロパティを開く。
ツールがカスタムビルドツールになっていることを確認して、カスタムビルドステップのコマンドラインのところを、
flex --nounistd aaa.l (注意:ハイフンは2つ)とする。
"--nounistd" をつけないとunistd.hが見つからないといって怒られる。(これも試行錯誤の結果であり、このオプションがどんな意味をもつのか当方はよく分かっていない)
出力ファイルのところは、lex.yy.cとする。
7. aaa.yを右クリックしてプロパティを開く。 ツールがカスタムビルドツールになっていることを確認して、カスタムビルドステップのコマンドラインのところを、
bison -d aaa.yとする。
出力ファイルのところは、aaa.tab.c; aaa.tab.h とする。
8. VC++.NET2003のメニューバーの「ツール」→「オプション」→「Projects」で「実行ファイルディレクトリ」にC:\cygwin\bin を追加する。
9. aaa.lを右クリックして「コンパイル」を実行する。
aaa.yを右クリックして「コンパイル」を実行する。
両者とも正常終了すれば、lex.yy.c, aaa.tab.c, aaa.tab.hの3ファイルが生成されているはず。エラーの場合は、どこかの記述が間違っていると思われる。
10. 「ソースファイル」を右クリック「追加」→「既存項目の追加」でaaa.tab.cとlex.yy.cを追加。
これでaaa.tab.cとlex.yy.cが現れる。
「ヘッダーファイル」を右クリック「追加」→「既存項目の追加」でaaa.tab.hを追加。これで
aaa.tab.hが現れる。
11. lex.yy.cを右クリックしプロパティを開く。 「プリコンパイル済みヘッダー」を選んで、「プリコンパイル済みヘッダーの作成/使用」を「プリコンパイル済みヘッダーを使用しない」に設定する。aaa.tab.cも上記と同様に設定する。
12. aaa.tab.cを右クリックして「コンパイル」を実行する。
lex.yy.cを右クリックして「コンパイル」を実行する。ワーニングがいくつか出るみたいだが、エラーが出ていないのを確認する。
13. ソリューションエクスプローラの一番上の"aaa"をクリックしてから、メニューバーのプロジェクトから 「プロパティ」→「リンカ」→「全般」の「追加のライブラリディレクトリ」でC:\cygwin\libを追加。コマンドラインを選び、追加のオプションのところに、libfl.aを記述。
14. 最後にメニューバーの「ビルド」から「ソリューションのリビルド」を行い、コンパイル&リンクが正常終了するのを確認する。
aaa.lとaaa.yがビルドされるとlex.yy.cとaaa.tab.cが新しく出来るのでいちいち確認メッセージみたいなのが出る。嫌な場合は、aaa.lとaaa.yを右クリックしてプロパティから「ビルドから除外」を「はい」と設定しておけばいいのではないかと思う。もちろん変更をかけたらビルドの除外を「いいえ」にするのはいうまでもない。
15. 以上のやり方で当方のPC環境において、VC++.NET2003でのYACC/LEX利用ができるようになった。
なお、ここに書かれた内容が技術的に正しいかどうかは保証の限りではない。試してみる方はあくまでも自己責任であることを申し添える。