mayuにC/C++のpreprocessorを搭載してみた

mayu.exeとmayu_pp.exe, mayu_pp.cfgのdownloadと概要はhttp://www.ric.hi-ho.ne.jp/giraffe/mayus/

目的と例

Windowsの定数の定義

#include <winuser.h>

window ConsoleWindow /ConsoleWindowClass/ : Global
  key C-Up = &PostMessage(ToItself, WM_VSCROLL, SB_LINEUP, 0)
  key C-Down = &PostMessage(ToItself, WM_VSCROLL, SB_LINEDOWN, 0)
  key C-PageUp = &PostMessage(ToItself, WM_VSCROLL, SB_PAGEUP, 0)
  key C-PageDown = &PostMessage(ToItself, WM_VSCROLL, SB_PAGEDOWN, 0)
  key C-Home = &PostMessage(ToItself, WM_VSCROLL, SB_TOP, 0)
  key C-End = &PostMessage(ToItself, WM_VSCROLL, SB_BOTTOM, 0)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
window ConsoleWindow /ConsoleWindowClass/ : Global
  key C-Up = &PostMessage(ToItself, 0x0115, 0, 0)
  key C-Down = &PostMessage(ToItself, 0x0115, 1, 0)
  key C-PageUp = &PostMessage(ToItself, 0x0115, 2, 0)
  key C-PageDown = &PostMessage(ToItself, 0x0115, 3, 0)
  key C-Home = &PostMessage(ToItself, 0x0115, 6, 0)
  key C-End = &PostMessage(ToItself, 0x0115, 7, 0)

関数のようなものの定義

#define IeIncre(x, y) &PlugIn("IE_INCRE", x, y, true)
#define IeIncreISearch(x) IeIncre("ISearch", x)
#define IeIncreISearchReverse(x) IeIncre("ISearchReverse", x)

window HH /:HH Parent:/ : Global
  key C-S = IeIncreISearch("hh")
  key C-R = IeIncreISearchReverse("hh")

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
window HH /:HH Parent:/ : Global
  key C-S = &PlugIn("IE_INCRE", "ISearch", "hh", true)
  key C-R = &PlugIn("IE_INCRE", "ISearchReverse", "hh", true)

Boost.Preprocessorを使った自動生成

#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/stringize.hpp>
#define KEY_lvn_columnclick(z_, n_, x_) key BOOST_PP_CAT(a-_, n_) = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", BOOST_PP_STRINGIZE(n_)) \u000a
window ListView /:(SysListView32|SysListViewEx32)$/ : Global
	BOOST_PP_REPEAT(10, KEY_lvn_columnclick, ~)
#undef KEY_lvn_columnclick

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

window ListView /:(SysListView32|SysListViewEx32)$/ : Global
	key a-_0 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "0") 
 key a-_1 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "1") 
 key a-_2 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "2") 
 key a-_3 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "3") 
 key a-_4 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "4") 
 key a-_5 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "5") 
 key a-_6 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "6") 
 key a-_7 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "7") 
 key a-_8 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "8") 
 key a-_9 = &Sync &PlugIn("CommonCtrl", "lvn_columnclick", "9") 

仕様

mayu.exeはただファイルを開く前に"mayu_pp file"を実行して、その標準出力をファイル内容として扱うだけです。
mayu_ppの起動そのものに失敗した場合はmayu_ppが無いものとして普通の動作になり、出力がありつつExitCodeがエラーな場合にはその出力をエラーメッセージとしてファイルが見つからなかったときのログ表示をします。
以下はmayu_ppのソースアーカイブのreadme.txtです。

Unicode非対応です。Boost.Waveが基本的にUnicodeに対応してないみたいです。
どこまでが純粋にWaveの部分で、どこからが単なる付属lexerなのかは分かりませんが。
結局はC/C++のpreprocessorであり、C/C++のlexerなしでは使えるものではない、と考えるのが妥当なようです。

基本的な仕様:
mayu_pp *.mayuで*.mayuのpreprocess結果をstdoutに出力
コマンドライン引数の拡張子と違う拡張子のファイルを#includeした場合は出力しない(これによりC/C++のヘッダを使える)
出力には#line等は含まない
//cppcomment等もそのまま残す
単体の\u000a等のUniversalCharacterを指定の文字に変換する(これによりマクロ出力に改行を含められる)
mayu_pp.cfgにwave.cfgの-D(define)と-S(sysincludedir)だけに対応した設定

以下、Boost.Waveに関してしたこと。

re2clex/cpp.re:
  /regex/と\m@regex@のStringLiteral化
  &StringのIdentifier化
advanced_preprocessing_hooks@mayu_pp.cpp:
  found_unknown_directiveでそのまま#unknownを#unknownにする
  opened/returning_include_fileで拡張子を見て、コマンドライン引数で与えられたファイル名の拡張子と違う場合は出力をしない
load_file_to_string@mayu_pp.cpp:
  BOM付きUnicodeファイルを開けるように

雑感

mayuにpreprocessorというのは、2003年にWave: a Standard conformant C++ preprocessor library - CodeProjectを読んだときにやろうと思ったんですが、当時は結局waveのライブラリとしての使い方が分からなかったような記憶があります。
Waveを使えば簡単に何にでもPreprocessorが搭載できると思ってたんですが、そんなわけありませんでした。