M GrammerでDSL
OsloとM言語で、DSLを作る例を紹介します(MSDN Hands-On-Lab18を参考)。
映画と監督のデータを登録する「MovieSTART 映画名 [BY 監督名]」のようなDSLを作りたいとします(sample.movie)。
MovieSTART Hello2009 BY Mike MovieSTART "Star Sky" MovieSTART DogAndCat BY "H Miya"
DSLを定義するためのエディタ「Intellipad」を以下のパラメータで起動します(ipad-vs-samples.xamlは今のところ、動的コンパイル機能のパラメータ)。
".\Intellipad\ipad.exe" /c:ipad-vs-samples.xaml
左のペインがDSL、真ん中がDSL定義、右がアウトプットツリーです。これで、DSLを定義しながら、DSLを入力して、ツリーが正しいかを確認できます。
DSLを定義するプログラムはこんな感じになります。Osloでは、独自のDSLを定義するためにM Grammar(mg.exe)という言語が用意されています。ファイルの拡張子はMGです(sample.mg)。
module MoviePlayer { language MovieLanguage { interleave Skippable = Whitespace; // --------------- // ↓シンタックス // --------------- //ルート(映画の繰り返し) //moviesとは「Movieの1個以上の繰り返し」と定義 //それを、Movies{...}で出力 syntax Main = movies:Movie+ => Movies{ valuesof(movies) }; //映画 //Movieは「MovieStart MovieName Director」 //それを { Name {...}, Director{...}}で出力 syntax Movie = MovieStart name:MovieName director:Director => { Name {name}, Director{director}} ; //映画の構文(ダブルクォーテーション囲みもOK) syntax MovieName = name:Name => name | name:NameVerbatim => name; //監督の構文(ダブルクォーテーション囲みもOK) syntax Director = By name:Name => name | By name:NameVerbatim => name | empty => "Unknown"; //ダブルクォーテーションで囲まれた名前 nest syntax NameVerbatim = '"' name:NameWithWhitespace '"' => name; // --------------- // ↓トークン // --------------- //アルファベットと数字 token AlphaNumerical = 'a'..'z' | 'A'..'Z' | '0'..'9'; //映画監督を示す定数 final token By = "BY"; //映画開始を示す定数 final token MovieStart = "MovieSTART"; //名前(アルファ数値の固まり:映画名 または 監督名) token Name = AlphaNumerical+; //名前と区切り(ダブルクォーテーション用) token NameWithWhitespace = (AlphaNumerical | Whitespace)+; //区切り(改行 または タブ または スペース) token Whitespace = '\r' | '\n' | '\t' | ' '; } }
lex(字句解析)、yacc(構文解析)と似てますが、MGrammarは、ツリーを組み立てることに特化してるようです(printfとかできないので、デバッグは難しいかも)。
最初の入力に対してアウトプットされるツリーは次の通りです。
Movies{ { Name{ "Hello2009" }, Director{ "Mike" } }, { Name{ "Star Sky" }, Director{ "Unknown" } }, { Name{ "DogAndCat" }, Director{ "H Miya" } } }