Bison / Flexを導入してみる
開発環境
OSはWindows、IDEはVisual Studio (2022) で行います。
マイプログラミング言語が作れるようになるらしいです。使ってみたかっただけです。
Windows向けにポーティングされたWinFlexBisonを使う方法とWSL上でBison/Flexを動かす方法の2つを調べました。
WinFlexBison
ライセンスはFlexがBSD, Bison GPLv3となっています。ただし、Bisonを使ったからと言って生成物にはGPLは波及しない(仕組み上、生成物にコピーが含まれるが特例扱いだった気がします)なので、その辺は大丈夫(なはず)です。
ページを見るとDownloadsリンクがあるので、そちらから安定板(win_flex_bison-version.zip)をダウンロードします。
プロジェクト作成
一連の流れについてはこちらのページが詳しいです。
設定だけでなく次のページ以降に実際の開発についても記述があるのでおすすめです。
概要としては
- メイン(開発する言語)のソリューションおよびプロジェクトを作成
- FlexおよびBisonのファイルを配置するためのプロジェクトを作成
- カスタムビルドルールを設定
といった感じです。
WSL2 + Bison / Flex
WinFlexBisonはWindows上で動かすには最適でバイナリをプロジェクトに登録しておけばバージョンの問題とかも気にしなくて良くなるという利点があります。ただ、現在だとWSLでオリジナルのBison/Flexを動かせるのでそちらを使うという手もあります。
> wsl --install
・UbuntuにBison/Flexをインストール
いずれもパスワードの入力が必要。
> wsl sudo apt-get update
> wsl sudo apt-get install -y bison flex
Windowsで動かすにあたっていくつか注意点があります。
1.unistd.h
Flexのコードに #define YY_NO_UNISTD_H を追加してください。
オリジナルのFlexが生成するコードにはunistd.hを使用するものが含まれますが、Windows(Visual Studio)にはunistd.hがないためコンパイルエラーとなってしまいます。そこでunistd.hを使わない宣言を追加する必要があります。
2. POSIX関数名
Microsoftは色々考えてPOSIX関数名は非推奨にしたそうです。関数自体は用意していてアンダースコアがPrefixとして付いています。そういうこともあってisattyとfilenoはそのままだと動きません。そこで以下のいずれかの方法で対応する必要があります。
A. 別名を定義
マクロで別名を定義することでMicrosoftが用意した関数を呼び出します。
#if defined(_WIN32)
#define YY_NO_UNISTD_H
#include <io.h>
#define isatty _isatty
#define fileno _fileno
#endif
B. 警告を抑制
B-1. プリプロセッサ定義
オプションのプリプロセッサ定義に_CRT_NONSTDC_NO_WARNINGSを追加します。これにより非推奨の関数名を使うことが許容されます。
B-2. ファイル内の非推奨警告を抑制
#pragmaを使ってファイル内の非推奨警告を抑制する方法もあります。
#if defined(_WIN32)
#define YY_NO_UNISTD_H
#include <io.h>
#pragma warning(disable : 4996)
#endif
個人的にはプロジェクト設定での対応は好みではないのですが、Windows以外でも動かすかもしれず、そこでもPOSIX関数を使うかもしれないのであればB-1で良いと思います(実際には_CRT_SECURE_NO_WARNINGSとか他の抑制も必要になって鬱陶しいのでC4996自体を抑制したくなったりします)。
逆に非推奨は非推奨として認めるべしって感じであれば都度適切に対応するAが良いでしょう。
B-2はB-2で修正内容と影響範囲のバランスが取れてますよね。
BisonやFlexによるコード生成についてはビルド前イベントとして登録しておけば覚えなくても良いので楽ちんです。登録内容は以下のものでどうでしょう。
- wsl flex -oFlexの出力ファイル名 Flexの定義ファイル名
- Flexの実行
- powershell -Command "(Get-Content Flexの出力ファイル名) -replace '\r?\n', \"`r`n\" | Set-Content Flexの出力ファイル名"
- Flexの出力ファイルの改行コードをCRLF(\r\n)に統一
- wsl bison -dv -oBisonの出力ファイル名.cpp Bisonの定義ファイル名
- Bisonの実行
- powershell -Command "(Get-Content Bisonの出力ファイル名.hpp) -replace '\r?\n', \"`r`n\" | Set-Content Bisonの出力ファイル名.hpp"
- Bisonの出力ヘッダの改行コードをCRLF(\r\n)に統一
- 出力をcppにした場合はhpp、cならh
- powershell -Command "(Get-Content Bisonの出力ファイル名.cpp -replace '\r?\n', \"`r`n\" | Set-Content Bisonの出力ファイル名.cpp"
- Bisonの出力ソースの改行コードをCRLF(\r\n)に統一
言語名がClangなら以下のような感じ
wsl flex -oClang.flex.cpp Clang.l
powershell -Command "(Get-Content Clang.flex.cpp) -replace '\r?\n', \"`r`n\" | Set-Content Clang.flex.cpp"
wsl bison -dv -oClang.tab.cpp Clang.y
powershell -Command "(Get-Content Clang.tab.hpp) -replace '\r?\n', \"`r`n\" | Set-Content Clang.tab.hpp"
powershell -Command "(Get-Content Clang.tab.cpp) -replace '\r?\n', \"`r`n\" | Set-Content Clang.tab.cpp"
「毎回コード生成するのは…」と思うお方はバッチファイルにしてプロジェクトに配置するのもありですね。
細かな話
公式マニュアルを読んでみると歴史的な経緯によるLALRパーサの挙動で謎のConfilictとかあるけどすまんな、みたいな話があったりします。
回避方法(%define lr.type ielr, LRテーブルのタイプをIELRにする)も載っていたりするので、本格的に開発を進める前にやはり眺めておいた方が良いでしょう。
それとよく見かける使用方法はC言語としてコードを生成しますが、C++としてコードを生成することも可能です。
やはり、先ほどのマニュアルにも記載はありますが、以下のページにも奮闘の記録があるので参考にするとよろしいでしょう。
コメント
コメントを投稿