Hatena::ブログ(Diary)

七誌の開発日記(旧) このページをアンテナに追加 RSSフィード

新ブログ Twitter OneDrive Wiki

2011-05-02

[][][][]名古屋Geek Bar LT

名古屋Geek Bar 5月2日(月)でLTをして来ました。V6関係のツールがメインですが、自己紹介に絡めて独自言語のセルフホスティングも取り上げています。

SlideShareレイアウトが崩れないようにPDFをアップしています。PowerPointのデータはこちらです。

USTREAM中継の録画も配信中です。

取り上げた話題については以下を参照してください。

2011-01-11

[][][]1.0リリース

独自言語Andromedaのコンパイラver.1.0をリリースしました。

開発当初から自分自身のコンパイル(セルフホスティング)を最初の目標にして、達成した段階で1.0としてリリースすると決めていました。実用性や完成度よりもセルフホスティングを優先したため、バグに気付いてもコーディングで回避できるものは修正を後回しにしています。今後のリリースでバグを潰していく予定です。

特徴

使い方

  1. アーカイブダウンロードすると、コンパイラとソースが入っています。
  2. COMPILER.exeをクリックして実行します。
  3. 自分自身をコンパイルしてadmc.exeを出力します。admc.exeはタイムスタンプ以外はCOMPILER.exeと同一のバイナリです。
  4. サンプルはサブディレクトリの中にtestsという名前で入っています。_build.batをクリックするとサンプルがコンパイルされます。

エクスプローラからの操作を念頭にしているため、コマンドラインアプリケーションでも最後に[Enter]を待って停止する仕様です。

開発動機

なぜコンパイラを作ったか、です。

開発を振り返る

開発開始からセルフホスティングまで4年を費やしました(半分くらいは開発停止期間)。転機となった出来事を列挙します。一度諦めた後、ちょっとしたことの積み重ねから、一気にセルフホスティングに突き進みました。

適当に作ったC#のパーサでもサポートする構文を制限すれば比較的簡単に変換できたのを見て、AndromedaのコンパイラC#からAndromedaに変換すれば良いと気付きました。年末から正月にかけて、トランスレータを作りながらひたすらAndromedaに変換し続けました。

サポートしていない構文は変換前にC#側で直して、動作が変わらないことを確認後、Andromedaに変換しました。変換だけに冬休みの大半を費やしました。

変換完了後いきなりセルフホスティングを試みましたが、すぐに落ちてあえなく撃沈。テストコードの動作結果を比較しながら地道にバグを見つけては回避(修正ではない)していきました。そしてセルフホスティングができるようにはなりましたが、とんでもなく遅い代物でした。C#の1/100以下。

シンボルのルックアップに使っているHashtableが、名前と違ってハッシュせずにリニアサーチしていたのが原因でした。ハッシュ関数を実装したところ、動作速度はC#の1/3〜1/5くらいまで向上しました。Andromedaのコンパイラ最適化を一切行っていないため、このくらいの速度は想定範囲内でした。そのためセルフホスティング到達と判断しました。

Andromeda用に書いたGUIライブラリやサンプルなどを盛り込んで1.0リリースとしました。

最後に

セカンドシステム症候群をトランスレータで乗り越えるという展開は、当初想定していなかったものでした。振り返ればその方向への流れはあったのですが、直前まで意識することはありませんでした。そのパターンは今後も続きそうな気がします。

2010-12-13

[][]FFI

DLLからシンボルがエクスポートされていれば、HaskellからFFIで呼び出せることが分かりました。独自言語(Andromeda)で開発した簡易リンカでDLLを出力してHaskellから呼び出してみました。

※独自言語はEXEしか出力できないため、独自言語から直接DLLコンパイルするのではなく、リンカを作ってDLLを出力しています。

実際にリンカをビルドしてDLLを出力できるようにまとめたセットを用意しました。コンパイラがバンドルされているので、.NET Framework 3.5環境ではすぐに試せるようになっています。

リンカのコード

helloというシンボルをエクスポートしたDLLを出力するコードは以下の通りです。

var exe = new PEModule;
exe.File.Characteristics |= IMAGE_FILE_DLL;
exe.WinNT.SubSystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;

var text = new Block;
var MessageBoxW = new OpCode;

// DllMain()
text.AddOpCode(I386.Ret);

// hello()
exe.Export("hello", text.CurrentAddress);
text.AddOpCode(I386.PushD(1));
text.AddOpCode(I386.PushAd(exe.GetString("だいあろぐ")));
text.AddOpCode(I386.PushAd(exe.GetString("こんにちは、世界!")));
text.AddOpCode(I386.PushD(0));
text.AddOpCode(I386.Call(MessageBoxW));
text.AddOpCode(I386.Ret);
text.AddOpCode(MessageBoxW);
text.AddOpCode(I386.JmpAd(exe.Import("USER32.DLL", "MessageBoxW")));

var dll = "hello.dll";
exe.WriteFile(dll, text, true);

println();
printfln(dll + " を出力しました。");
pause();

呼び出すHaskell側は前回と同じです。

test2.hs
{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign

foreign import ccall "hello" hello :: IO ()

main = do hello

独自言語に関しては、リンカだけでなくコンパイラまで作ってセルフホスティングに持ち込みたかったのですが、方向性に悩んで中断したままです。

2009-07-27

[][][][]Andromeda for Silverlight

自作言語AndromedaをSilverlightに移植しました。Win32バイナリを出力するネイティブコンパイラです。動作確認とソースのダウンロードは以下です。

ツリーのSamplesからビルドしたいサンプルを選んで[Build]ボタンを押すとビルドが始まります。成功すれば[Save]ボタンでローカルにEXEファイルを保存することができます。ソースを編集するとビルドに反映されます。エラーからソースの該当箇所に飛ぶことができます。

実用的な意味はあまりなく、完全に実験目的です。言語の設計方針等は id:n7shi:20090310 のスライドを参照してください。

2009-03-10

[][]まとめ

LLPMLからAndromedaまでの開発を振り返って、アーキテクチャをスライドにまとめました。

SlideShareははてなダイアリー対応なので、embedコードをブログの本文にコピペするだけで貼り付けることができました。

2009-03-08

[]開発中止

C#のunsafeについて検討した結果、C言語の代用としてネイティブコンパイルすることが可能であるとの結論に達しました。そのため独自言語Andromedaの実装を中止することにしました。

開発途中の最終版です。BNF処理系やアセンブラは未完成のままで、コード生成で大量の警告が出ます。

今後はC#ネイティブコンパイラ開発を検討しています。LLPMLはC#で記述したため、Andromedaとして自分自身を書き直す手間がありました。それに対してC#C#コンパイラを書けば、コンパイラの完成後に自分自身を書き直さなくてもコンパイルできます。

ですがすぐに開発には着手しないで、しばらくはC#のコード記述の効率化を研究しようと思います。

もともと独自言語の開発はコード記述の効率化を目的に開始したものでした。コードの記述を効率化するに当たって、パースやコンパイルまで完全に制御する必要があったためです。これはコンパイラが完成するまでは効率が悪くても我慢するという発想です。そのため独自言語の貧弱な開発環境を我慢していました。これは能率が非常に悪かったため、発想を逆にして、最初に効率化を求めることにしました。C#コンパイラを作るのであれば、C#の周辺ツールを作っても無駄にはなりません。

2009-01-12

n7shi2009-01-12

[][]GUIコントロールの追加

AndromedaにGUIコントロール(Win32ラッパー)を追加しました。LLPMLの問題もいくつか修正しました。

ボタンを押すと終了する簡単なアプリケーションは次のようになります。

#pragma subsystem(WINDOWS_GUI)

var f = new Form;
f.SetClientSize(120, 50);

var b = new Button;
b.SetBounds(30, 15, 60, 20);
b.Text = "Quit";
b.Click.Add(\ => f.Close());
f.AddControl(b);

Application.Run(f);

クラスも関数も定義せずにフラットに書いています。

最初のpragmaはコマンドプロンプトを抑制するためのものです。printfデバッグをするときはコメントアウトします。

イベント定義(b.Click.Add)ではラムダ式を使っています。パーサの都合でC#Haskellをごちゃ混ぜにした文法になっています。

【C#】        x => x + 1
【Haskell】  \x -> x + 1
【Andromeda】\x => x + 1

\はバックスラッシュをλに見立てたもののようです。

クラスで書き換え

C#風にウィンドウをクラスにする書き方も可能です。

#pragma subsystem(WINDOWS_GUI)

Application.Run(new Form1);

class Form1 : Form
{
    function ctor
    {
        SetClientSize(120, 50);
        
        var b = new Button;
        b.SetBounds(30, 15, 60, 20);
        b.Text = "Quit";
        b.Click.Add(\ => Close());
        AddControl(b);
    }
}

コントロールが増えるとこの形の方が便利です。

2008-10-19

[]コンパイラの作り直し

LLPMLが一定の完成度に達したので、Andromeda言語でコンパイラを作り直し始めました。

x86以外のCPUにも対応するため、試験的にARMバイナリの出力を行っています。

設計について見直しをするため、LLPMLを移植するのではなく、一から作り直しています。1.0として自分自身のコンパイルを目指します。そうなれば現在のLLPMLは不要になるため、.NETやC#から完全に独立することができます。

1.0まではx86とARMの二本立ての予定です。ARM対応が順調に進めば、1.0ではWindows Mobile上でのセルフ開発が可能になるかもしれません。1.0以降でx64にも対応する予定です。

コード生成を積極的に利用していきます。現時点で定型的な定義の記述を容易にするため、ExcelのXML形式(xlsxではなく単独のXML形式)から構造体のソースコードを生成しています。これは過渡的な形態で、1.0以降では中間のソースコードを生成せずに直接XMLコンパイルする予定です。ソースもExcelに限定しないで、図形言語なども扱えるようにしていきたいと思います。