C
Go
golang
compiler
コンパイラ

C コンパイラ [🐈cc] をスクラッチから開発する日記

はじめに

開発の動機

Cコンパイラをスクラッチから開発してみた(日記)

@ruiu さんのこの記事を初めて読んだとき、何度も挫折してきた自作 C コンパイラに再挑戦したいなあと思いました。ですが、その時は「rui さんみたいなすごい人にはできても、自分なんかには無理だ」などと言い訳して、結局チャレンジしませんでした。

ところが、最近とある心の病気を発症してしまい、日常生活が送れなくなってしまいました。学校にも行けず、ゲームや本も楽しいと思えず、毎日つらいのに暇でやることありません。日によっては本当に体が動かずずっと横になっている状態なのですが、気持ちはつらくてもある程度体が動く日もありました。

毎日なにもせずにいると、自尊心がどんどん削られていきます。人に迷惑は書けるのに、なにもできない毎日です。そこで、これではいけないと、体が動かせる時は、自尊心を回復できるようなことをしようと思いました。

しかし、自尊心を回復できること、というのは意外と難しいものです。思考力も落ちているので、難しいことをしようとしても失敗してしまいます。かといって、簡単なことだと失敗したときに自分はダメな人間だと思ってしまいますし、成功しても自分すごいとはなかなか思えません。さらに、便利なツールを作るなど、何かのためにすることだと、失敗したときのガッカリが増えてしまいます。

ここでは過程は省きますが、自分の性格等も考慮した結果、自作 C コンパイラが最適だという結論に至りました。C コンパイラは難しいと思われていますが、細かく分解して見てみると、作るだけであれば技術的難易度はそれほど高くありません(時間はかかりますが)。これまでに何度かチャレンジしているので、ある程度なにをやればいいか解っています。もし完成すれば、なにかすごいことをしたという達成感がありますし、失敗してしまったとしても「難しいことにチャレンジしたのだから、失敗しても仕方ない」と割り切ることができそうです。

そう考えて、私は C コンパイラを作り始めました。そして、@ruiu さんが日記を公開しているのを思い出し、自分も書いてみようかな、と思うようになりました。彼の日記を読んだとき、私は「すごい人だからすごいことができた」のだと思い、結局チャレンジしませんでした。私は少なくとも彼ほどすごい人間ではなく、普通のプログラマに近いと思います。そんな私が C コンパイラを作ることで、「自分でもできるかもしれない」と思ってチャレンジする人も出てくればいいな、と思っています。

また、時間はあるとはいえ、心の病気を治療中であり、明らかに思考力やプログラミング力も落ちていることを実感しているので、完成しない可能性がそれなりにあります。調子が悪いとき、マイナス思考になっているときは、「自分のようななにもないダメな人間に、そんなだいそれたことができるはずがない」と、根拠もないのに投げ出したくなることもあります。そんなとき、たとえ一度投げ出してしまったとしても、日記を公開する形で書いていれば、もう一度やってみようという気持ちになれるかもしれないなと思いました。「普通の人でも C コンパイラを作れるんだと証明したい」という理由付けも、他人のためにという理由があれば、諦めたときに再開するための原動力になるだろうという打算の結果です。よく「心の病気の人に頑張れと言ってはいけない」と言われることもあります。それは正しいのですが、そういう言葉が負担になる時はネットは見ないようにしているので、もし日記が更新されなくなったときには、twitter 等で励ましの言葉等いただけるとおそらく喜びます。

開発方針

@ruiu さんは、機能の少ない C コンパイラのサブセットを作り、それを段々 C コンパイラに近づけていく、という方針で開発されたそうですが、私にはその方針は合いませんでした。サブセットを作っても、最終的に C コンパイラになるまでは「完成したという達成感」を得られないからです。

そこで、私は C コンパイラを、パーサコンビネータなどのいくつかの小さなツールに分割し、その小さなツールを作り、最終的に組み合わせて C コンパイラにする、という方針を取ることにしました。この方針であれば、それぞれのツールが完成した時点で達成感を得ることができます。

また、これまでは自作コンパイラで自作コンパイラをコンパイルする、という夢を見すぎて、なれない C 言語で作ろうとしたためにつまづく、という失敗が多くありました。この反省を踏まえて、今回は使い慣れた Go 言語を使用しています。セルフホスティングの夢を見て完成しないようでは本末転倒です(自作コンパイラで C 実装の Go コンパイラをコンパイルし、そのコンパイラで最新の Go コンパイラをコンパイルし、そのコンパイラで自作コンパイラをコンパイルする、という間接的な方法で、似たようなことができるので、それで納得することにしました)。

現在の状況

ver20180527

気が向いたときに更新しています。

https://github.com/zakuro9715/zcp

zcp                zakuro computer platform
├── lib
│   └── atomio     バックトラッキングで使用するための io
├── utils          Posix Utility
│   ├── basename
│   └── cat
└── zcp            zakuro compiler platform
    ├── jessica    パーサーコンビネータ
    │   ├── ast
    │   ├── decca  .decca ファイル(構文定義ファイル)の解析器
    │   └── expr   構文定義用の式
    ├── zbc     zakuro low level language (アセンブラライクな低水準言語用ライブラリ) 未実装
    ├── zcc        zakuro c compiler 未実装
    └── zvm        zakuro virtual machine 未実装
        └── zir    zvm internal representation (zbc で定義) 未実装

日記

日付は起きた時点を基準にしていて、夜型の生活になっているため、git のコミットログとズレている可能性があります。

なにか手を動かした日は、日記を書くつもりですが、力尽きて書けない日もあるかもしれません。

~ 03/21

パーサージェネレータ jessica を実装中です。PEG を参考に独自に実装しています(足りない機能、余分な機能があります)。PEG基礎文法最速マスター にある算術式パーザを参考にして書かれた四則演算がパースできます。

jessica という名前は、言語というキーワードからジェシカ・ミットフォードを連想してつけられたものです。

03/22

  • この記事を作成しました。
  • cbb9b8b jessica: rune を受け取って bool を返す関数で 1 文字にマッチするか指定する expr.Predicate を追加

03/24

  • ec558de cat のエラーを修正。内側のスコープで := を使ってしまい、外の変数に代入したいのに新しい変数を作成してしまっていた
  • f29ff67 jessica: ast.EmpyNode を追加。nil とほぼ同じ使い方だが、レシーバの nil チェックをしなくても良くなる。パーサの戻り値として使用され、木を処理する段階で除去される
  • 56df237 atomio: 子を Commit したあと、親で Rollback したときに正しく戻らないバグを修正
  • 1b53f1f jessica: 否定/肯定先読みを実装

03/26

  • 2db8dc5 文字クラスを実装(列挙と範囲のみ)。
  • 4c5413f decca の解析器の jessica.expr での実装を開始。今後破棄するかも(Unity を使用しての実装に)
  • Issue でタスク管理するようにしてみた
  • #5 Jessica に入っていた AST 等の共通ライブラリを Deborah に切り出し
    • 68a7bdc Walk を実装。単純に DFS して木を巡回する
    • 67c34d8 EularTour を実装。EularTour で巡回した結果をリストで返す。Printer に使うつもりで作ったが、結局使わなかったので今後削除するかも
    • 62043c4 Printer を実装。jessica の ast.String() と同じような文字列を吐く Visitor

数日調子が悪かったけど、今日は比較的たくさん進んで満足感がある。よかった。

03/29

  • 735ad15 token.Token をインターフェースに変更。必要に応じて独自の struct を使うことで、Token に独自情報を埋め込めるようになる
  • 27b8782 Escaper を追加。これまで色んな場所でアドホックに実装していたエスケープを、ちゃんと実装する場所を作った。今は複雑なエスケープをする箇所はないので、簡易実装
  • a00ad6c jessica はパーサーコンビネータライブラリにして、構文定義の文字列からパーサーを作る機能は、Unity に実装することにした。jessica/decca にその部分は書かれていたので、それを unity に移動
  • 0877e7c ParsingExpr とそれを実装した struct は、名前に Expr がついていた。これは、構文定義の式という意味で、過去には Parser だったが、構文定義文字列自体のパーサーと混同しそうなのでこの名前に変更された。しかし、その部分は Unity に移したので混同する恐れはないし、今の機能を考えると Parser の方が実態に即しているので、改めて Parser に戻すことにした。結構面倒だったので、名前を気にしすぎて頻繁に変更するのは避けたいところ
  • 1e673a4 a9e97cc マッチするが AST には残さない機能を追加。実際は、ast.NewEmpty() が返され、これは少なくとも deborah の中では無視されるようにできている(Children 等からも消されるので、普通に扱えば勝手に消える)。Phantom という名前は必要以上にかっこいいので、良くなかったかも(なんか意味深なので、深い理由があるのではと疑ってしまう。でもかっこいいからとりあえずこのままにする)
  • f7b95f a09811b 736db9 ちょっとだけ手を付けていた unity の実装、変数を internal に移して名前を変更。テストを書き換えていたら、バグらしき挙動を見つけた。"abc" を Literal でパースしようとした時に、2文字目以降の文字すべてのカラムが 2 になっている。バックトラックが絡んでいる気がする(atomio の実装が適当すぎたかもしれない)。

~ 04/02

数日ぶり。コード自体は少しずつ書いていたが、コミットしていなかったり、コミットしたけど Qiita に来るのが面倒で日記を書かなかったり。

匂いと光で、すっかり春になったことを感じる。最近朝に起きられる日が続いていて良い。

  • deborah: 細かい変更をいくつか入れた。トークンを結合できるようにしたり、Position に ByteOffset を入れたり、Position を構造体にしたり、Position の Counter を追加したり。
  • 6cfbbf jessica: Optional (e?) を実装。実際には 0 回以上 1 回以下の繰り返しとして実装されている。
  • 467955a jessica: Placeholder を実装。その後の変更で今の名前は Lazy。パーサーを返す関数を渡しておくと、実際に必要になった時に呼び出され、返したパーサーを使ってパースする(パース自体は Lazy ではない。パースのタイミングは普通と同じ)。
  • a45de3d jessica: SquashToken を実装。これまでの実装では、パーサーの仕様上字句解析が存在しないため、^[a-zA-Z0-9]+$ の正規表現ような文字列にマッチさせようとすると、「文字クラスに該当する1文字」というトークンの繰り返しとして AST が作られてしまう問題があった。SquashToken は、パーサーが返した AST のトークンをまとめて 1 つにした上で葉を返すので、これを使用することで、必要に応じてトークンを決められる。
  • c37a3c3 jessica: Transform を追加。ast を変換する関数を渡しておくことで、パース結果の AST の構造や値を扱いやすい形に変更できる。
  • :tada: :octocat: :100:
  • 65aea2f jessica: コードを見直して大幅に整理した。パーサーの実装は internal/parser に移動。外部公開用の jessica.Parserparser.Parser を分けることで、今まで公開になっていた ParserContext を非公開にできるようになり、外から見た時にシンプルになった(もともと ParserContext はパース中の情報を持っているだけなので、公開である必要はなかった。外部から呼び出す Parse と、内部パーサーとして呼び出されるときの Parse が同じだったため公開になっていた)
  • d26ec84 unity: とりあえずの構文定義。一応、それっぽい文字列が受理されるパーサーになっているが、かなり適当。たたき台。

unity の実装過程で必要になった機能がだいたい実装できたので、あともう少しで unity も動くようになりそう。unity は jessica を使っているので、C 言語のパーサーを書く前の練習にもなっている。AST の変形や走査は悩んだが、パーサーを定義する段階で可能な限り変形することにした(木構造の変形は構文の定義に依存しているので、同じ場所に書けるようになると見やすくて都合が良い)。

unity ができたら満足してしまって放置する、という危険が凄く見えるので、ちゃんと C コンパイラまでたどり着けるようにがんばりたい。特に、C コンパイラに取り掛かるときの最初の一歩は大変そうに見えてしまうだろうから、一気にやろうとせずにちょっとずつを心がける。

04/04

  • c5019a4 unity: これまでの ParsingError は got, want を受け取る形式のみだったが、自由なエラーメッセージを設定する方法を追加。
  • 90eb7db jessica: 必ずエラーになるパーサーを追加。よくある構文ミスを検出する等に使用できる。
  • bdc6166 jessica: Grammer を追加。名前をつけてパーサーを保持する。名前を指定して、その名前のための LazyParser を取得できるので、定義が循環しているときにそれを使う。その他、たくさんのパーサーからある文法のパーサーを作るのに便利な機能を見つけたら実装する予定。
  • b9257c9 カバレッジを取るようにしてみた。

04/05

  • b26fd63 . で import するタイプの DSL をつくった。Go なので DSL を作るつもりはなかったが、Unity の実装過程で書き始めたヘルパ関数が段々と DSL になりつつあり、便利だったので DSL として採用した
  • 20cf356 機能実装した Grammer を使って、既に実装していた部分のみ書き直し。副次的な産物として、中途半端になっていた Kind が定義済みの構文分は作られた。

Yak Shaving が続く。基本的には迂回せず深掘りする予定なので問題ないが、C コンパイラを作っているという感覚が薄れてきている。今の所 C 言語が全く関係していない

この後は、Unity の各構文の木構造を Transform を使って変形する部分を書いて、それが終われば AST からパーサーを生成する部分が比較的楽に書けるはず。その後、サポートする機能を増やしていけば、Unity が C コンパイラ自作に使えるようになるので、C の構文定義を下記はじめることになるだろうか。道のりは長く見えるが、スタート地点も既に遠くに見えている。一歩一歩は小さいけれど、継続によって遠く見える場所からここまで来たのだから、これからも続けて行こう。🐢

~ 04/15

最近は調子が悪く、低空飛行気味です。書けそうなときにはコードを書いていますが、ずっと寝ている日も多く、日記を書く気力はありませんでした。今日も詳しく書く気力はないので簡単なメモ程度 + 生存報告代わりです。

  • pamela: パーサージェネレータで ab -> "a" / "b" 程度の簡単な構文定義が処理できるようになりました。あとの構文の実装は、たぶんやるだけ(だと思いたい)。
  • deborah: AST の printer が見やすくなりました。
  • jessica: いくつか追加・仕様変更
  • README を少し書きました

04/18

また数日調子が悪かったのですが、今日は比較的元気でした。

  • 全体的に、Coverage を見ながらテストを虱潰しに追加。Coverage を見すぎるのは良くないが、Coverage を埋める過程で発見できたバグも多くあったので、過信しなければ Coverage を見ながらテストを書くのも悪くないと思った。もちろん、Coverage が高いから十分にテストができていると思いこむのは危険
  • 非常にどうでも良い話だが、Coverage が上がるほど Codecov のアイコンの色が汚くなってつらい。100% なら綺麗な緑なのだろうが、90% だとくすんだ黄緑色。逆に、もっと低ければ赤色でもう少し綺麗なので、Coverage を上げる過程でどんどん色が汚くなり、モチベーションが削がれるという現象が発生した

04/19

睡眠導入剤とむずむず足症候群対策の薬(もともとはてんかんの治療薬らしい)のおかげか、睡眠の質が劇的に改善し、ぐっすり眠って早い時間に起きられた。日中も調子がよく、コードをたくさん書いた

  • za.kuro.red C コンパイラとは関係ないが、放置していた自己紹介サイト予定地にサイトを建てた。CSS を頑張って書いた。vh は便利だなあ。コンパイラが完成したらここのトップに大きく自慢げに「C コンパイラ創った」って書きたい。がんばろう
  • pamela: Sequence 構文をサポートした。OrderedChoice のサポートが先になっていたのは、構文定義の都合上そっちが内側に来るから。繰り返し等のサポートはまだだけど、一応パーサージェネレータとして使える最低限の機能までたどり着いたら、できるだけ早く C コンパイラに手を付けたい。もうすぐ C コンパイラに手を付けられると最近ずっと書いている気がするが、あまり気にしないことにする。少しずつ歩くと、近くに見えていた場所が意外と遠く見えただけで、歩いた距離が短かったわけではないから、いつかたどり着くのだ。

追加

  • pamela: e+ e* e? ( e ) の各構文をサポートした。やるだけなのに意外とミスするので構文追加はこれからも結構厄介な作業になりそう。でも動くと楽しい。
  • pamela: それなりに機能が充実したので、四則演算の構文定義 が通るようになった。1 + 2 * (3 + 4) / 5 みたいな式がパースできる構文を定義できる。

pamela が段々実用的になってきた。Pamela 自体の構文のパースには、自前のパーサーコンビネータ jessica を使っているので、jessica もある程度動いていると言っていいだろう。自作パーサーコンビネータで自作コンパイラコンパイラを作る、と表現するとちょっとかっこいい :tiger:

04/20

暑い。

  • e472747deborah: AST を変換する Converter を実装。NewConverter はリフレクションをガリガリ使っていて、これにより仕様側は interface{} を使うことなく、下のように任意の型を変換先にできる(ジェネリクス風のことができる)

    compiler := NewConverter(func(v ast.AST, out *[]byte) error {
      b, err = generateByteCode(v)
      if err != nil {
        return err
      }
      *out = b
      return nil
    }
    

-42daf9 pamela: 不要な nil チェックを消した。nil な slice にたいしての len や for は panic になると思い込んでいたが、空 slice として動くらしい
- 9eaf4f0 debora: 木を変換(写像)する Map を追加。対象の AST と 変換済みの子を受け取って AST を返す関数 func (AST, ...AST) AST を渡すと、末端から順番に全体を変換する

04/21

昨日よりさらに暑い。まだ 4 月だとは思えない暑さ

  • 言語実装パターンのバイトコードインタプリタを読みながら、レジスタマシンにしたいなあなどと考えながら VM の設計をしている。
  • オブジェクトファイルのフォーマットがある程度固まって今は実装中。未解決シンボルも扱えるはずなので、ちゃんとファイルごとにコンパイルができるが、リンカを作らないといけないので、一旦未解決シンボルは後回しにする予定
  • コンパイラの名前をこれまでは暫定的に zcc としていたが、#tcfm での話が面白かったので、🐈cc に決定した。読み方は決めてないけど、「ねこのえもじしーしー」って読んでもいいと思います。その他、実行するバイナリはこの命名規則で、🐈vm🐈asm🐈ldなどが作られる予定
  • 🐈obj: 文字列定数を格納するための StringTable を実装。これはオブジェクトファイルを実装するときの部品として使われる予定。
  • 今日の日記は🐈がたくさんいて面白い。ディレクトリ名に入っているので、おそらくこれからも登場し続けるだろう
  • deborah: 少しだけテストを足した。

04/22

  • コミットログによると、StringTable を定数プールに拡張しようとしていたらしいが、多分これは取り消される(この時の変更の根拠となった考え方に、間違いがあったことに気がついた)。

04/23

  • いろんな変なテクニックを使って高速化するためのパッケージ komi をつくった(名前はなにかの本の表紙が囲碁だったことから)。今の所、[]byte と string を unsafe をつかってコピー無しで変換する関数を作ったくらい
  • neovim がバグってつらいので、Emoji を変数に入れて列挙しただけの emoi というパッケージをつくった。go:generate 最高
  • 🐈 コマンドを作った。このコマンドから、他のあらゆる機能にアクセスするようになる予定(Go の場合は窓口となるコマンドを作ることで、完全にシングルバイナリにできる)
  • ランダムにテストが落ちているなあと思ったら、for i, v := range map[int32]... のキーがソートされていることを期待しているコードを書いてしまっていた。しかも、テストでもキーが小さい順に追加されるコードを書いていた。全体を通して完全に小さい順だと思い込んでいた。Golang の map の for がランダマイズされる仕様だったからこそ、発見されたバグである。ありがとう Golang。

気がつけば、日記を書き始めてから 1 月を過ぎている。実際には開発期間はもうちょっと長い。月日がたつのは早く、その分もどかしい気持ちにもなる。焦りすぎるのもよくないと解っているが、焦る自分が残っていることに安堵する気持ちもある。無理をしない程度に、というのは忘れずに、それでも精一杯には頑張りたいな。

04/24

  • 🐈アーキテクチャとは独立に、低レイヤでの汎用のパッケージ群の名前を pascaline に決めた
  • バイナリ列を扱うためのパッケージ bytecode を作った。int64 から関数一つでコンバートしたり、Writer で書き込んだり、いろいろ
  • Emoi パッケージにテストを生成するようにした。
  • pascaline/isa というパッケージを作った。汎用 isa の定義のためのいろいろがあり、アセンブラ等から使われる予定。

ここのところ調子は良かったけれど、今日はちょっと元気少なめでした。これまでが元気すぎたとも言えるけど、でもそれでも万全ではなかったから、まだまだ道半ばだな、と思う。でも、少し前よりはずっと良くなった。起き上がれないこともなくなったし。

04/25

  • Object ファイルを扱う構造体を作った。↓と同じ理由で、プログラム以外は未実装
  • 🐈isa を作った。nop iconst iadd dump idump の命令をとりあえず作っておいた。これだけあれば、VMが動いてることを確認できそうという理由。
  • isa.Define をメソッドチェインするために、ISA を返す仕様にした(これまでは追加したInstruction を返していたけど使ってなかった)
  • bytecode.NewByteCode を bytecode.New にリネームした。もともとなぜ NewByteCode という名前だったのかは分からない(基本的な自分命名規則に従えば、この場合は New になっているはず)

今日は昨日より調子が悪い。最悪のときと比べれば全然マシだが、ちょっと憂鬱な感じだった。また少しづつ落ちていくのだろうか…

05/02

  • f4b9382 bytecode: バイナリ列を int32 と相互変換する関数を追加。int64 との相互変換は既に存在していたが、int32 はまだなかった。いずれ float も必要になる気がするので、今のうちに作っておくべきかも

オブジェクトファイルのグローバル変数の部分に型情報が入っているが、これは不要かもしれないと思った。iadd や iconst のように、命令レベルで型情報が入っているので、グローバル変数はバイト数と名前だけわかれば十分かも(elf とか読んで勉強するべきかも。幸い Go には標準ライブラリに elf が入ってるし)。

ここ数日調子が悪い。今日は天気も悪い。少しつらい日々だけど、以前に比べれば全然良いので、前向きに生きようと思う。

~05/04

コミットはない。オブジェクトファイルの実装を進めたり、ファイルフォーマットを考えたり、ELF 等のフォーマットを勉強したりしていた。

相変わらず、調子は回復しない。けれど、これまでの傾向から、遠くないうちに戻るのは解っているから、いまは耐える。

05/05

  • :tada::octocat::100::100:
  • 324cd12🐈obj フォーマット第一弾。debug/plan9obj を見て、plan9 のオブジェクトファイルのシンプルさに影響を受けた気がする。今のところ最低限のフォーマットなのでかなりシンプル。設計思想としては、シンボルテーブルをなくして、各セクションに名前がついており、それがシンボル名に相当する。関数やグローバル変数は、セクションとしてファイルに含まれることになる予定。これが吉と出るか凶と出るかは、他を実装してみないとわからない。オブジェクトファイル等をあまり良く理解していないのに、あえて他と違うやり方をしてみたので、失敗する可能性も高いような気がする。ただ、物理マシンで実行するコードが入るわけではなく、VM のオブジェクトファイルなので、違いはあるだろう(VM のバイトコードファイルをもっと研究するべきかとも思ったが、実装すること優先の方針なので、頑張るリソースは実装に振っている)。

~ 05/07

  • 36c1571フォーマットの微修正をした。64bit だった部分をいくつか 32bit に変更したり、サイズだったのを個数に変更したり。後者は、ゼロ値をそのまま使えるようにするための変更(マジックナンバー等があるので、空のオブジェクトファイルでもサイズはゼロにならない)。
  • 3c5c9bf テストデータのマジックナンバーが間違っていた。この時点での実装は、マジックナンバーをチェックしていなかった(現在は修正済み)。
  • e50a57bFile だったのを、Object に変えた。Open 等のファイルに関係する部分は削除し、読み取り部分は Reader から読み取る Decode に変更
  • f1f4186 Encode を作ったので、読み込みだけでなく保存もできるようになった。

~ 05/19

日記を書く元気がなく、日記を書くのがかなり久しぶりになってしまいました。今日も細かく書くほどの気力はないですが、このまま書かなくなる危機が見えたので、ざっくりでも書こうと思いました。

  • オブジェクトファイルに関数部分の実装を追加した。
  • VM の実装に取り掛かり始めた。一旦、iconst, idump まで実装。

最近はやる気がでないので、実装が進まない。とはいえ、それでも挫折せずに少しずつは進んでいるので、私エラい。がんばろう。

実装面では、ついに VM が動く所まで来た。あとは、この実装を太らせていけば、動くものになる。一つ大きな壁を超えた。ある程度動いたら、いよいよ C 言語に関わる部分!

05/20

久しぶりに明るい時間に起きた。これで生活リズムを戻したい。生活リズムを一気に変えるのは難しいので、成功すると安心してしまうが、本当に大事なのはそのあとリズムを維持することだと気づいたので、今度は昼夜逆転に戻らないように、維持するのをがんばろう。

たぶん、🐈アーキテクチャを最初から再設計する。というのも、現在のアーキテクチャはスクリプト言語のVM(YARV とか)を参考にしすぎてレイヤが高く抽象化されすぎていて、特にメモリ周りはかなり怪しく(適当に考えすぎてほぼ Go 依存になっている)、ポインタ等が扱えない気がしてきた。

今日は RISCV の仕様を読んでいる。再実装では、基本的には実際のコンピュータと同じようなモデルで、ただし回路で実装することは考慮しない、というような方針のつもり。

05/26

あまり元気がないですが、新アーキテクチャになったので軽くメモを残しておきます。

前のアーキテクチャは Calling convention に相当する部分まで面倒をみていました(バイトコードレベルで関数の概念が存在しました)が、素朴なレジスタマシンになったのでそれはなくなりました。

無限個(ただしバイトコードでは16bitで指定)のレジスタがあるレジスタマシンです。push/pop/shift の概念が少し特徴的で、レジスタの番号をずらしたりできます。

正直、CPU や VM の話は知識が全く足りていないので、あとから見返すと謎設計に見えるかも。ただ、わからないから止まっていたという側面もあって、このまま止まってしまうと良くないので、わからないなりに進めた結果がこうなりました。

まともに使えるようにするために、実装するべき命令がまだまだたくさんあります。でもちょっと息切れしてきたかも。続けることを最優先に、低空飛行でも飛び続けられるように。

05/27

05/28

今日は比較的元気でやる気もあったのですが、Switch のマイクラに 8 時間ほど吸われてなにも進みませんでした

06/03

  • b7fc0e8 pamela に文字クラスを実装した。アセンブラを作るにあたって、Pamela への機能追加が進みそう

06/11

  • b9813b0 7c47cc6 式をトークンとして指定する T( expr ) を実装
  • 26e170a 644a0d4 名前で他の構文を参照したときに、その名前が AST のラベルに残るように修正。
  • 1375805 パースの直前に関数を実行するパーサー を追加 (名前は ruby の Object#tap から)
  • 06d8f7c 式を AST に残さないことを指定する P( expr ) を実装

ある程度元気だけど、なんとなくやる気が起こらない。

Pamela の構文を適当に決めすぎている気がする。T( expr ) は最初は < expr > だったが、記号の空間が足らなくなる気がするのでやめた。けれど、完成させること優先であまり深く悩まないようにしているので、それが仇となってクソ言語が爆誕する可能性は結構ある。自分しか使ってないから変更が容易なのは救い(でも、結局面倒なのでクソ言語のままになるパターンが見える)

06/12

  • fd4b176 仕様上、a -> b ; b -> "hoge"; のような構文をパースすると、AST から b という名前の情報が消えてしまっていた(名前は基本的に上書きなので、木が深くならないような場合は名前が上書きされる。Sequence とか挟むようにするとと木が深くなって上書きされなくなる)。名前ごとに強制的に木を深くするような実装を入れた。これによって、既存の木(as とか)の構造が結構変わってしまっていろいろ落ちたけど、木構造ではなく名前ベースで取得するようにした(CSS で例えると、これまでは隣接セレクタや親子セレクタを多用していたが、クラスセレクタを使うようになった)
  • 87a9af5 まだ途中だが、as をコミットした。ちょっとずつ触っていたが、しばらくコミットできる状態になりそうになかったので、一旦コミットした。

コメント、追える範囲で全部読んでます。いいねでも十分嬉しいのですが、コメントの嬉しさはレイヤが一段上です。 新しいコメントがつくと、比喩ではなくリアルに小躍りする程度には嬉しいです。ちょっとしたコメントでも超うれしいので、もしこれを読んでいたら、ぜひコメントを残してください。私が、おそらくあなたの想像以上に喜びます。

06/13

  • a24093c as をちょっと進めた。シンボル等のない命令列をアセンブルするような、超最低限のアセンブラはもうちょっとでできそう

今日は学校に行って、久しぶりに授業に出た。つかれた。少しずつもとに戻れていて、私がんばってるなあと思った。あと、自分を褒めるのは苦手だけど、ちゃんとがんばってるって言葉にできた私もエラい。

07/09

お久しぶりです。ここのところ調子が悪くて全く体が動かなかったりと、いろいろありました。元気ですとは言えないんですが、がんばって生きてます。
あと、いろいろあってソースコードを非公開にしました。いずれ公開に戻しますが、しばらくは非公開になります。日記は続けたいです。
これは直接は関係ないですが、お仕事復活しました。Web 系で、ionic でアプリを作るお仕事をしています。

  • jessica: Position がおかしいバグを直した。エラーメッセージに含まれる Position 情報が使えるようになったので、かなり楽になった
  • as: シンボル定義を実装(参照は未実装)

07/14

少し前よりはマシですが、相変わらず調子が良くないです。コードを書く元気があるのは一日数時間で、あとは布団に横になってゲームをするのが精一杯。

  • 少しリファクタリング
  • オブジェクトファイルにリロケーション情報っぽいものを追加
  • アセンブラのシンタックスを微調整(オペランドの間にカンマが必要になった)
  • アセンブラでラベルを使えるように(2パスにするのが面倒だったので、リロケーション情報として格納しておいた。解決は ld に委譲)

07/20

低空飛行ですが生きてます。今は耐えつつ、できるときにゆっくりやりたい。今日はこれに加えてお仕事コードもしっかり書いたので、最近と比べるとかなり調子が良かったです。

  • cli を実装し始めた
  • cli に as コマンドを実装
  • ld を作った。オブジェクトファイルをくっつけて、シンボルテーブル等のアドレスを修正して、シンボルを解決するだけ