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"
}
}
}
