素朴な自作言語のコンパイラをDartに移植した


移植一覧に戻る


Dart で書いてみました。やっつけなので汚いです。Dart よく知らないけどライフゲームが動いたのでヨシ、というレベルのものです。

github.com


移植元

memo88.hatenablog.com

ベースになっているバージョン: tag:46 のあたり

  • 追記 2021-03-21: Dart のバージョンアップ(2.9.1 => 2.12.0)に合わせて修正
    • null safety まわりを適当に修正
  • 追記 2021-03-21: ステップ56の修正まで適用しました

メモ

  • アセンブラVM は移植対象から外しました。Ruby 版のものを使います。
  • トークナイザとパーサを分けてみた
  • テストのステップを細かくした
  • ファイルを直接まじめに読まなくても、 標準入力が読めればあとはシェルスクリプトでラップしてあげたりすればいいので、 もうそれでいいかなという気持ちになった。

Dart でプログラムを書くのは今回初めてでしたが、JavaScriptJava あたりを知っていればかなりスムーズに書き始められるなーという感想でした。引っかかるところがほとんどなかったです(今回書いた範囲では)。適当にググりながら 1日で書けてしまいました。


今回の実験的な要素としては、パーサをいじって set を不要にしてみました。

(追記 2021-03-21: この修正はいったん revert しましたが、一応 trial ブランチに残してあります。)

 func main() {
   var a;
-  set a = 42;
+  a = 42;
 }

文の先頭の set で判別するのをやめて、識別子だったら parseSet_v2() を呼ぶ。 もうちょっとめんどくさいかなと思ってましたが、これだけだったら意外と簡単ですね。

List parseSet_v2() {
  // consume("set"); ... これが不要になる
  final t = peek();
  pos++;
  final varName = t.value;
  consume("=");
  final expr = parseExpr();
  consume(";");
  return ["set", varName, expr];
}

List parseStmt() {
  final t = peek();

  if (t.value == "}") {
    return null;
  }

  if      (t.value == "func"    ) { return parseFunc();      } 
  // ...
  // else if (t.value == "set"     ) { return parseSet();       }
  // ...
  else if (t.value == "_cmt"    ) { return parseVmComment(); }
  else {
    if (t.type == "ident") {
      return parseSet_v2();
    } else {
      throw notYetImpl([ t ]);
    }
  }
}