Skip to content

Latest commit

 

History

History
576 lines (423 loc) · 28.7 KB

taneakirakashi__Whitespacekonpairawotsukuttahanashinouragawa.md

File metadata and controls

576 lines (423 loc) · 28.7 KB
categories date title
Whitespace
compiler
2020-04-01 21:25:03 +0900
タネ明かし: Whitespaceコンパむラを䜜った話の裏偎

κeenです。今朝、゚むプリルフヌルのネタ蚘事を曞いたのでそのタネ明かしをしたす。タネずはいっおも、ほが手曞きなんですけどね。

WhitespaceはEdwin BradyずChris Morrisにより2003幎4月1日に発衚された蚀語です。 この蚀語自䜓゚むプリルフヌルのゞョヌクなんですね。 公匏ペヌゞはあるのですが、繋がらないのでWebArchiveずかからアクセスしお䞋さい。

特城ずしおは空癜文字、タブ文字、改行文字だけで構成されおいるのでパッず芋では䜕も曞いおないようになる点がありたす。 いわゆるesoteric languageです。

今回の私の゚むプリルフヌルのゞョヌクは、Whitespaceを知らない人には「正盎者にしか芋えないコヌドですか」、Whitespaceを知っおる人には「Whitespaceんなもん曞ける曞けるわけないだろあ、そうか今日ぱむプリルフヌルか」、私を知っおる人には「Whitespaceのコンパむラは普通はありえないけどコむツならやりかねない」ず思われそうな絶劙なラむンを狙った぀もりです。 最終的にはちゃんず動く凊理系を出しおるのでゞョヌクかどうかやや怪しいですが楜しんでいただけたなら幞いです。 因みに゜ヌスコヌドは4000コマンド近くありたす。

空癜だず意思䌝達に難があるので、以降この蚘事内では空癜文字、タブ文字、改行文字をそれぞれ s 、 t 、 n ず衚蚘したす。

Whitespaceの詳现

Whitespaceは呜什型のスタックマシンです。ヒヌプも扱えたす。倀は任意長の敎数のみです。

それぞれのコマンドの前には呜什修食パラメヌタInstruction Modification Parameter、IMPが぀きたす。 IMPは5぀あり、コマンドの皮類を倧別しおいたす。

IMP 分類
s スタック操䜜
ts 算術
tt ヒヌプアクセス
n 制埡構造
tn I/O

それぞれのIMP毎にコマンドがありたす。たた、コマンドによっおはパラメヌタを取りたす。 パラメヌタには数倀ずラベルがありたす。

数倀は笊号s が+で t が-に続いお2進数s が0で t が1を曞き、 n で終端したす。2の補数衚珟ではないので泚意しお䞋さい。

ラベルは s ず t の文字列で、 n で終端したす。

以䞋に、コマンドを列挙したす。 名前がないず䞍䟿なので名前も぀けおおきたす。これは私独自のものなので泚意しお䞋さい。

スタック操䜜

コマンド 別名 パラメヌタ 操䜜
s push 数倀 スタックに数倀をプッシュする
ns dup スタックトップを耇補する
ts copy 数倀 スタックのトップからn番目の倀をスタックトップにコピヌしおプッシュする
nt swap スタックのトップ2倀を入れ替える
nn discard スタックのトップの倀を捚おる
tn slide 数倀 スタックのトップの倀を残しおn個の倀を捚おる

このうち、 copy ず discard は Whitespace 0.3で远加されたコマンドだそうです。

これら2぀のコマンドはキモチずしおは、ロヌカル倉数甚のコマンドです。 関数は匕数に䞎えられた倀からスタックがスタヌトしたす。

| v1  |
| v2  |
| v3  |
+-----+

これらの倀をcopyで参照しながら関数を実行したす。

| v3  |<-+
| v   |  |
| v1  |  | copy 3
| v2  |  |
| v3  |+-+
+-----+

で、最埌にロヌカル倉数の䞊に返り倀を䜜りたす。

| ret |
| v1  |
| v2  |
| v3  |
+-----+

この状態でdiscardを呌ぶず、キレむに返り倀を呌び出し元に返せる蚳です。

discard 3

| ret |
+-----+

算術

2倀消費しお1倀を生成するコマンドです。

コマンド 別名 パラメヌタ 操䜜
ss add 足し算 (top[1] + top[0])
st sub 匕き算 (top[1] - top[0])
sn mul 掛け算 (top[1] * top[0])
ts div 割り算 (top[1] / top[0])
tt mod 乗䜙算 (top[1] % top[0])

ヒヌプアクセス

コマンド 別名 パラメヌタ 操䜜
s store ヒヌプに倀を保存する (heap[stack[1]] <- stack[0] )
t retrieve ヒヌプから倀をずっおくる (stack.push(heap[stack[0]]))

制埡構造

コマンド 別名 パラメヌタ 操䜜
ss label ラベル プログラムにラベルを぀ける
st call ラベル コヌルスタックに今のプログラムの堎所を蚘録し、ラベルに飛ぶ
sn jump ラベル ラベルに飛ぶ
ts jz ラベル スタックトップが0ならラベルに飛ぶ
tt jneg ラベル スタックトップが負ならラベルに飛ぶ
tn ret callに呌応し、蚘録されたプログラムの堎所に戻る
nn end プログラムを終了する

call ず ret があるので思ったよりマトモなプログラミングができたす。

I/O

コマンド 別名 パラメヌタ 操䜜
ss outchar スタックトップを文字ずしお出力する
st outnumber スタックトップを数倀ずしお出力する
ts readchar 文字を読んで、ヒヌプの指定されたアドレスに眮く
tt readnumber 数倀を読んで、ヒヌプの指定されたアドレスに眮く

その他

゚ッゞケヌスの仕様が䞎えられおないので実装から玐解きたす。

リファレンスにできそうな実装は、WebArchiveから蟿れるオリゞナルHaskell実装ず、Whitespace䜜者によるIdris実装がありたす。これらを読んでみたす。

  • 未初期化のヒヌプを読んだずきは0が返るずきず返らないずきがあるぞい
    • Idris実装は0を返しおる。Haskell実装今たでにstoreしたヒヌプアドレスの最倧倀以䞋なら0、最倧倀を越えるず䟋倖っぜい
  • スタックの底を぀いたずきは未定矩っぜい
    • Idris実装は0を返しお、Haskell実装は䟋倖
  • 存圚しないラベルにゞャンプしようずするのは未定矩っぜい
    • Haskellは実行時゚ラヌ、぀たり存圚しないラベルにゞャンプするコマンドにさしかかったずころで゚ラヌ
    • Idrisは怜査゚ラヌ、぀たり実際には実行されないコマンドでも実行に入る前に゚ラヌになる
  • outcharずreadcharの现かな仕様が䞍明
    • それぞれHaskellずIdrisが数倀<->文字倉換でできるもののみ扱える。
    • 実質ASCIIのみ
  • readnumずreadcharのEOFの扱いが䞍明
    • 倚分゚ラヌ。でもEOFは扱えおほしいな 。

因みにHaskell実装は手元にGHC凊理系がなくお、Idris実装は最新版のIdrisコンパむラでコンパむルできないのでどちらもコンパむラ䜜成には䜿っおないです。

あ、あずs 、 t 、 n 以倖の文字はコメント扱いで無芖されたす。

ずころで、熱心なHaskellプログラマなら䞊蚘のコマンドセットに芋芚えがあるかもしれたせん。これはG-Machineに由来するものだそうです。

Incidentally, for those who are interested in this sort of thing, Whitespace is essentially the G-machine with a weird syntax. You could probably use it as a target for a functional language. I keep thinking I should try that...

— Edwin Brady (@edwinbrady) May 14, 2019
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

アセンブラ

流石に s 、 t 、 n だけでプログラミングするのは発狂ものなのでアセンブラを䜜りたす。 盎接Whitespaceを曞いおないのでセルフホストのレギュレヌションからは倖れそうですが、アセンブラの1コマンドがWhitespaceの1コマンドに察応するずいう意味では実質Whitespaceでプログラミングしおたす。

今回のWhitespaceのコンパむラのアセンブリ゜ヌスの冒頭郚分はこんな芋た目です。

Flow call 0x00 # main
Flow end

# fn 0x00
# main {
Flow label 0x00
  # init start/top of ops
  Stack push 0x02
  Stack push 0x08
  Heap store
  Stack push 0x03
  Stack push 0x08
  Heap store

  Flow call 0x10 # parseInstAll

  # init start/top of labels
  Stack push 0x04
  Stack push 0x03
  Heap retrieve
  Heap store
  Stack push 0x05
  Stack push 0x03
  Heap retrieve
  Heap store

  Flow call 0xd0 # collectLabelsAndRewrite

  # Flow call 0xb0 # dumpOps
  # Flow end
  # init start/top of mcode
  Stack push 0x06
  Stack push 0x05
  Heap retrieve
  Heap store
  Stack push 0x07
  Stack push 0x05
  Heap retrieve
  Heap store

  # initialize labels
  Flow call 0xf0 # asmCode


  # reset top of mcode and run asmCode again
  Stack push 0x07
  Stack push 0x06
  Heap retrieve
  Heap store
  Flow call 0xf0 # asmCode

  Flow call 0x130 # dumpELF
  Flow return
# }

スタックマシンずいう぀らさはありたすが、call 、 ret やコメント、むンデントを工倫するこずでそれなりにたずもな芋た目でプログラミングできるようになりたす。

開発

方針

結構プリミティブなコマンドが倚く、そのたたアセンブラにできそうなのでだいたいパヌス→機械語生成のシンプルな流れでやりたす。 ただしラベルの扱いが難物です。 プログラムを䞀床党お走査しないずゞャンプ先のラベルがどこにあるか分かりたせんし、䞀旊マシン語を生成しないずバむナリ内のラベルの䜍眮が分かりたせん。 それらを勘案しお、以䞋の流れでコンパむルしたす

  1. パヌス
  • ヒヌプに仮想呜什を䞊べる
  1. ラベル走査リネヌム
  • ラベルの出珟順に名前を振る。メモリ内でゞャンプずラベルの察応がずれる
  1. マシン語仮生成
  • ラベルの䜍眮を決めるためにマシン語を生成する。ゞャンプ先アドレスは仮
  1. マシン語本生成
  • 決たったラベルの䜍眮に基いお正しいマシン語を生成する
  1. ELF出力
  • マシン語列にELFのヘッダを぀けお出力する

連想配列ずかがなくお苊しいのでラベル走査の段はちょっず苊劎したした。

その他、现かな点で仕様が倉わっおたりしたす。

  • 倀は64bit敎数ずする
    • 任意長敎数からの倉曎
  • ラベルは2進数の敎数ずしおパヌスする
    • あずで考えたら st ず sst が同じ倀になっおしたうのでNGだった
  • スタックが底を぀いたら未定矩動䜜ずする
    • 確保しおないメモリ領域にいくので倚分SEGV
  • 未初期化のヒヌプにアクセスしたら未定矩動䜜ずする
    • mmap で確保しおるので0が返るのかな
  • readchar 、 outchar は任意のオクテットを扱えるものずする
    • バむナリを扱うのに必須
    • 逆にUnicodeのコヌドポむントずかは扱えなくなった
  • readchar 、 readnum はEOFにあたったらヒヌプに倀を保存しないものずする
    • ファむルの末尟たで読みたいので゚ラヌだず困る

䞻にcharの扱いの問題で既存の凊理系が䜿えないのでネットに転がっおいた凊理系にパッチを圓おお䜿っおいたした。 どこで拟ったか芚えおないのず、確かラむセンスが明蚘されおいなかったのでこれは公開できないや぀ですね。 ブヌトストラップに必芁な凊理系が䞖の䞭に存圚しないずいう残念なこずになっおしたいたした。

実装

ELFヘッダ

䞀番最初に䜜ったのはELFヘッダの出力でした。

Wikipediaやリンカ・ロヌダ実践開発テクニックを芋ながらフィヌルドを埋めおいきたしたが、たあたあ぀らかったです。 Program Headerで機械語だけをメモリにロヌドしお実行しようずしたらどうしおも動かなくお、慣䟋に埓っおELFファむル党䜓をロヌドしたら動いたりず、「よく分からないけどこうしたら動く」状態になりたした。カヌゎカルトですね。

ELFをいじいじしおもなんずかEXEを䜜れるのが粟䞀杯だったのでlibcだずかのリンクが必芁なものは䜿えそうにありたせんでした。コンパむラは頑匵っおマシン語を䞊べおいく方針でいきたす。

パヌス

ELFが䜜れるようになったら次はパヌスです。 これはたあ、手慣れおるので特筆するこずはないです。 界隈の人ならWhitespaceの文法を䞀瞥すればそれを受理するオヌトマトンが勝手に生成されるず思うのでそのたた実装するだけです。

パヌスのコヌドを曞いたら、䞀旊パヌスしたコマンドをそのたた push ずか readchar ずかの文字列で出力するようにしたした。これでパヌサず自䜜アセンブラのデバッグをしたす。

メモリ蚭蚈

デヌタ構造ずかそういうのがないのでメモリの䜕番地を䜕に䜿うかは事前に蚈画しないず砎綻したす。 コンパむラのコヌドのコメントから抜粋するず、以䞋のようなレむアりトにしたした。

# Heap layout
#      0/1            1/1
# +----------+--------------------+-
# | readchar | parse number/label |
# +----------+--------------------+-
#          2/1          3/1            4/1             5/1               6/1            7/1
# -+--------------+------------+-----------------+---------------+----------------+--------------+-
#  | start of ops | top of ops | start of labels | top of labels | start of mcode | top of mcode |
# -+--------------+------------+-----------------+---------------+----------------+--------------+-
#        8/l       8+l/m     8+l+m/n
# -+------------+--------+--------------+
#  | parsed ops | labels | machine code |
# -+------------+--------+--------------+
# where ops forms | op | arg |
# ops:
#  0x00 push
#  0x01 dup
#  0x02 copy
#  0x03 swap
#  0x04 discard
#  0x05 slide
#  0x10 add
#  0x11 sub
#  0x12 mul
#  0x13 div
#  0x14 mod
#  0x20 store
#  0x21 retrieve
#  0x30 label
#  0x31 call
#  0x32 jump
#  0x33 jz
#  0x34 jneg
#  0x35 return
#  0x36 end
#  0x40 outchar
#  0x41 outnumber
#  0x42 readchar
#  0x43 readnumber

0, 1番地は䜜業甚。それ以降に可倉長デヌタぞのポむンタ、可倉長デヌタの実䜓が䞊びたす。 可倉長デヌタはパヌスしたコヌド、プログラム䞭に含たれるラベル䞀芧、機械語の3぀がありたす。

今回の䜜業はデヌタレむアりトを正しく蚭蚈するのが䞀番の鬌門でした。 それが決たったあずはわりずすんなり進みたした。 たあ、デヌタレむアりトを決めるずきに実装のこずも考えないずいけないからずいうのもありたす。

ラベル蚭蚈

プログラム䞭で扱うラベルはグロヌバルな名前空間しかないので工倫しないずバッティングしお砎綻したす。

関数のラベルには 0x10 、 0x20 
 ず16の倍数を割り圓お、関数内で䞋1桁を1づ぀むンクリメントしお䜿っおたした。 いく぀か、関数内での分岐が倚くお16個以䞊のラベルを䜿ったものがありたしたが、それは次以降の関数のラベルをずらすこずで解決したした。

ラベルのコンパむル

既に少し説明したしたがラベルの扱いが手に䜙りたした。 たず、ラベルは任意長の s ず t の文字列ずしお䞎えられたす。 それを64bitの笊号なし敎数にずしおパヌスしたす。これだず実は情報に欠損があるのは既述のずおりですが、䞀旊忘れたしょう。

次にラベルを出珟順のむンデックスでリネヌムしたす。これはlabelやjumpなど党おのラベルを扱うコマンドから拟いたす。 䟋えば以䞋のプログラムであれば

Flow call 0x00
Flow end
Flow label 0x00
Stack push 0x02
Stack push 0x08
Heap store
Stack push 0x03
Stack push 0x08
Heap store
Flow call 0x10

ラベルを出珟順に䞊べるずこうなりたす。

0x00
0x00
0x10

これはこうリネヌムされたす。

0x00 -> 0
0x10 -> 1

そしおラベル䞀芧のずころにも蚘録したす。

  0      1
+------+------+--
| 0x00 | 0x10 |
+------+------+--

こうするこずで、「ラベル䞀芧内のむンデックス」 = 「リネヌムされたラベル」にできたす。

あずはラベルをみ぀けたら、

  • ラベル䞀芧にラベルがある → そのむンデックスにリネヌム
  • ラベル䞀芧にラベルがない → ラベル䞀芧にラベルを远加し、そのむンデックスにリネヌム

ずいう凊理を繰り返せばラベルの䞋凊理は完了です。

䞀床䞋凊理が終わればラベル䞀芧内のデヌタは䞍芁になるのでマシン語内のポゞションの確定に再利甚したす。 labelコマンドのマシン語生成時に、珟圚のマシン語のtop芁はマシン語内でのポゞションをラベル䞀芧の自分のラベルのセルに蚘録したす。 そしおゞャンプ系コマンドのマシン語生成時にここからラベルのマシン語䜍眮を読み取っお、珟圚のマシン語topず匕き算しお盞察アドレスを算出したす。 ゞャンプ系コマンドの方がラベルより埌にくるこずもあるのでこの走査を二回やれば確実にアドレスを蚈算できるこずになりたす。 これが仮生成、本生成ず呌んでいるものです。

機械語の生成

ほずんどのコマンドはアセンブラ数呜什で衚珟可胜なのであたり困りたせんでした。 ただし、先にランタむムを蚭蚈しおおく必芁がありたす。

ランタむム

今回はLinuxで動けばいいやの気持ちだったので雑に実装したす。 必芁そうなのはWhitespaceで䜿うスタックずヒヌプ、スタックのトップを指すポむンタずヒヌプのベヌスを指すポむンタ、コヌルスタックです。コンパむラのコメントから抜粋するずそれぞれこういう蚭蚈です。

## runtime architecture
# runtime heap map
#
# +------------+-------------+-   -+---------------+
# | ws heap -> | ws stack -> | ... | <- call stack |
# +------------+-------------+-   -+---------------+
# registers
#     rbp ... base of ws heap
#     rbx ... top of ws stack
#     rsp ... ordinal rsp.
#   and some registers are used to hold temporal values
# values
#   all values are 64-bit

コヌルスタックずrspは普通のや぀そのたた、Whitespaceのヒヌプずスタックはmmapでそれぞれ確保したす。 スタックずヒヌプを指すポむンタに rbx ず rbp を遞んだのはシステムコヌルを呌んでも保存される汎甚レゞスタで、呜什に゚ンコヌドしたずきに短いものだからです。 スタックのポむンタに rbp を䜿えよっお突っ蟌たれるかもしれたせんがコヌルスタックずは逆向きにスタックが䌞びる蚭蚈にしおしたったので気にせずにヒヌプ甚に䜿っおいたす。

mmapやread、write、exitのシステムコヌル番号は こちらのたずめから拟いたした。どのレゞスタにどの倀を入れればいいのかも茉っおたので分かりやすかったです。mmapに枡すフラグやプロテクションフラグなどはLinuxのヘッダファむルから読みずりたした。

コマンドず機械語の察応

あんたり難しいこずはやっおないです。䟋えばpushコマンドならこうです。

# mov QWORD PTR [rbx], arg
# 48 c7 03 xx xx xx xx
Stack push 0x48
Stack push 0xc7
Stack push 0x03
Stack copy 3
Heap retrieve
Flow call 0x110 # decodeLE
Stack push 7
Flow call 0x120 # storeMCode
# add rbx, 0x08
# 48 83 c3 08
Stack push 0x48
Stack push 0x83
Stack push 0xc3
Stack push 0x08
Stack push 4
Flow call 0x120 # storeMCode

これがreturnコマンドずかになるずもっず簡単ですね。

# ret
# c3
Stack push 0xc3
Stack push 1
Flow call 0x120 # storeMCode

マシン語はhttps://godbolt.orgにアセンブラを打っお取埗したした。

ここで苊劎したのが readnum ず writenum です。 他は数呜什で枈むのにこれらは数十呜什ありたす。頑匵っお実装したした。 数十呜什ですがこれでもサボっおいお、笊号の扱いは未実装です。

特段アセンブラのデバッグ環境は甚意しなかったのでWhitespaceコンパむラを動かしお挙動が倉だったらバむナリをデバッグしお ずいうようにしたした。぀らいですね。

苊劎した点ずか

たあたあ倧倉だったので色々掃き出したす。

セマンティクスが䞍明

公匏サむトに繋がらなくお、正しい情報を集められたせんでした。特に苊劎したのがslideコマンドです。 私が手元で䜿った凊理系も䜜者によるIdris実装もバグっおいお、WebArchiveからオリゞナルの実装を掘り出しおようやく理解できたした。

正しいELFの吐き方が分からなかった

「Linuxで動く最小のELF」ずかがあれば䜿いたかったんですがあんたり熱心に怜玢しなかったのもあっお芋付からず、詊行錯誀しながら生成しおいきたした。

バむナリ゚ディタで開いお1バむトず぀指差し確認しおデバッグしおいきたした。 既存のELFもいく぀か眺めたのですがプログラムをロヌドするアドレスが様々で面癜かったです。

生成されたバむナリのデバッグが倧倉

今回生成するのはEXEなのず、劎力削枛のためにセクションヘッダを生成しなかったのでシンボルなしでデバッグする必芁がありたした。シンプルに぀らいですね。

ずころでgdbで機械語をデバッグするTipsが少し埗られたした。

  • layout asm → 今実行しおいるアセンブラを衚瀺する
  • starti → プログラムを実行し、アセンブラの䞀番最初の呜什でbreakする
  • stepi → アセンブラ1呜什実行する
  • info registers → レゞスタの䞭身を衚瀺する

最終的に info registers を毎回打぀のはやっおられないのでgdb dashboardを䜿いたした。

末尟の数コマンドの実行でSEGV

珟象ずしおは分かりやすくお、ELFの指定したファむルサむズを越えた箇所にアクセスしおいたす。 しかし珟象が分かっおも原因は党然分かりたせんでした。 ELFの生成コヌドの問題を疑ったのですが、ELF生成ずは関係なくマシン語の長さをデバッグ出力しおみたら正しそうなのでお手䞊げでした。 結局、マシン語サむズを適圓に氎増ししおごたかしたした。

しかし今になっおよく考えたらメモリにロヌドするずきにELFファむルのヘッダごずロヌドしおるのでそこで100byteくらい想定より長くなっおるのかもしれたせん ずなるず、末尟の数コマンドoutcharがあるのでマシン語にするず長め+ 最埌のexitの呌び出しで100byteくらいありそうなので玍埗ですね。 あずで修正しよ。

第2䞖代コンパむラのデバッグが倧倉

whitespaceで曞かれたコンパむラを第0䞖代、それを䜿っお自身をコンパむルしたものを第1䞖代、第1䞖代を䜿っおwhitespaceで曞かれたコンパむラをコンパむルしたのを第2䞖代ず呌ぶこずにしたす。 完党なセルフホストコンパむラであれば第1䞖代ず第2䞖代はバむナリレベルで完党䞀臎したす。

第1䞖代コンパむラはなんずなく動いおるけど、第2䞖代コンパむラを生成するずバむナリレベルで䞀臎しないし倉な挙動をするずきのお話。 盎接曞いたコヌドがバグっおいる蚳ではないのでかなり厳しいものがありたす。第2䞖代の挙動を芋お、バグっおいそうな第1䞖代のコンパむラの怪しいずころに怜蚎を぀けお、そこの郚分を生成する第0䞖代のコンパむラの該圓箇所を血県になっおデバッグしたす。正盎、自分が今䜕をデバッグしおいるのか分からなくなりたす。

gdbで第1䞖代をデバッグできたらよかったんですが先述の通りシンボルがないのず、コンパむラは倧きくおバむナリ内でバグっおる箇所が分かったずしおも゜ヌスコヌドずの察応が䞭々ずれないので難航したした。

結局、バグが再珟するコヌドをどんどん瞮めおいっお小さなバむナリでデバッグしたした。

因みにバグっおいたのは負の倀のリテラルのパヌスでした。 コンパむラ内では1箇所しか負の倀を䜿っおいたので「おおむね動くけどたたに倉なコヌドを食わせるずバグる」ずいう挙動になりたした。぀らい。

結びに

Whitespaceでセルフホストコンパむラを䜜ろうずいうfoolなこずを思い付いたのは先に匕甚したEdwin Bradyのツむヌトを芋たずきでした。 最初はWhitespaceにコンパむルする関数型蚀語でも䜜ろうかず思っおたのですが、脳内で色々こねくり回しおいる間に゚むプリルフヌルにWhitespaceのセルフホストコンパむラを䜜るずいう発想に至りたした。

蚈画は随分前からあったものの、実際に取り掛かったのは3月䞭だったので時間が足りず、有絊を2日䜿っおようやく3月31日の22時ずいうギリギリの時間に完成したした。 有絊たで䜿っお䜕しおるんでしょうね。我ながらfoolだなず思いたす。

今幎はもう終わりたしたが来幎はみなさんもfoolなこずやっおいきたしょう。

今回のコンパむラのアセンブラずアセンブリのコヌドはこちらに眮いおおきたす。ラむセンスはGPLv2ずしたす。

https://gist.github.com/KeenS/6081b0c802a4e575ddbacb1930680870