DLR で俺言語を作ってみる講座:第2回目
id:SiroKuro:20070922:1190471726 の続きです。
Sample_Skeleton の構成について
今回の本題に入る前に、Sample_Skeleton.lzh のクラス構成について書いておきます。
Sample.Program | エントリクラス。public static void Main |
Sample.SampleLanguageContext | 言語共通のコンテキストを格納するクラス |
Sample.SampleUtils | ごった煮 |
Sample.Actions.SampleActionBinder | アクションを抽象構文木に関連付けるクラス。今はまだデフォルト |
Sample.Hosting.SampleConsoleHost | コンソールのホスト |
Sample.Hosting.SampleEngine | Sample 言語のエンジン本体 |
Sample.Hosting.SampleLanguageProvider | LanguageProvider。SampleEngine を生成したり |
Sample.Shell.SampleCommandLine | コンソールのコマンドライン関係 |
Sample.Shell.SampleConsoleOptions | Console 関連の設定 |
Sample.Shell.SampleEngineOptions | Engine 関連の設定 |
Sample.Shell.OptionsParser | コマンドライン引数をパースするクラス |
これらの生成関係を見てみるとこんな感じに。
└ Sample.Program
└ Sample.Hosting.ConsoleHost
└ Sample.Hosting.SampleLanguageProvider
├ Sample.Shell.OptionsParser
| ├ Sample.Shell.SampleConsoleOptions
| └ Sample.Shell.SampleEngineOptions
├ Sample.SampleLanguageContext
└ Sample.Hosting.SampleEngine
└ Sample.Actions.ActionBuilder
ConsoleHost が LanguageProvider を生成、引数をパースして LanguageContext を生成、そして Engine を作るといった感じです。一応これらのコードでコマンドラインインタプリタが動作します。
パース処理の詳細
さて、実際に抽象構文木を作成している Sample.SampleLanguageContext#ParseSourceCode の詳細を見てみます。
public override CodeBlock ParseSourceCode(CompilerContext context) { CodeBlock code = Ast.CodeBlock("__top__"); code.Body = Ast.Statement( Ast.Call(null, typeof(SampleUtils).GetMethod("WriteLine"), Ast.Constant(context.SourceUnit.GetReader().ReadToEnd()))); return code; }
ソースが入力されるとこのメソッドが呼び出されます。入力されたソースは context.SourceUnit.GetReader() から TextReader として取得できます。
Ast.Constant(object obj) メソッドは、obj を定数として保持する AST を作成するメソッドです。今回は入力されたソースを引数に渡すことで、その文字列を値として持つ ConstantExpression が生成され返されます。
Ast.Call(Expression inst, MethodInfo method, params Expression[] args) メソッドは、method で表されるメソッドを呼び出す AST を作成するメソッドです。今回は public static void SampleUtils.WriteLine(object obj) を呼び出すために、インスタンスは null、args は Ast.Constant で生成された値を引数に CallExpression を生成しています。
この AST によって実行されるコードは、C# で書くならば次のような感じです。
SampleUtils.WriteLine("{入力されたソース}");
実行するとこんな感じに。
さんぷるげんごー! sample> abcdefg abcdefg sample>
ちゃんとエコーされているのが分かるかと思います。