Scalaでシンプルな自作言語のコンパイラを書いた

image.png

かんたんな自作言語のコンパイラをいろんな言語で書いてみるシリーズ 28番目の言語は Scala です。

できたもの

github.com

不慣れな人が見様見真似で書いていますので、Scala のコードとして拙いところはご容赦ください。 Scala に詳しくなるのは後回しにしてとにかく動くものを作るぞ、という方向性です。

サイズ

(
  cd src/main/scala/mini_ruccola
  LANG=C wc -l *.scala lib/*.scala
)

  358 CodeGenerator.scala
   67 Lexer.scala
   25 Main.scala
  302 Parser.scala
   92 lib/Json.scala
   40 lib/Node.scala
   62 lib/Token.scala
   16 lib/Utils.scala
  962 total

コンパイラのコア部分だけに絞ればこのくらい:

(
  cd src/main/scala/mini_ruccola
  LANG=C wc -l {Lexer,Parser,CodeGenerator}.scala lib/{Node,Token}.scala
)

   67 Lexer.scala
  302 Parser.scala
  358 CodeGenerator.scala
   40 lib/Node.scala
   62 lib/Token.scala
  829 total

動かし方の例

$ ./docker.sh build
$ ./docker.sh run bash -l -c "sbt assembly"

$ echo '
  func add(a, b) {
    return a + b;
  }

  func main() {
    call add(1, 2);
  }
' | ./run.sh lex | ./run.sh parse | ./run.sh codegen

# ↓アセンブリが出力される

  call main
  exit
label add
  push bp
  mov bp sp
  mov reg_a [bp:2]
  push reg_a
  mov reg_a [bp:3]
  push reg_a
  pop reg_b
  pop reg_a
  add reg_a reg_b
  mov sp bp
  pop bp
  ret
  mov sp bp
  pop bp
  ret
label main
  push bp
  mov bp sp
  mov reg_a 2
  push reg_a
  mov reg_a 1
  push reg_a
  _cmt call~~add
  call add
  add sp 2
  mov sp bp
  pop bp
  ret
(snip)

移植元

Ruby 版から移植しています。

github.com

<自作言語処理系(Ruby版)の説明用テンプレ>

自分がコンパイラ実装に入門するために作った素朴なトイ言語とその処理系です。

<説明用テンプレおわり>

メモ

  • いつも通り Emacs で書いた
    • 1,000行足らずの小さなプログラムなのでこれでも十分
  • Dockerfile を書いて動かせるようになるまでに時間がかかった
    • コンパイラ本体の実装よりこっちの方が面倒だった
    • 最近は coursier というのも加わったようなので、これについての知識も必要

blog.3qe.us

そんな中、ずっと自分が勉強したいな〜と思いつつ放置している分野がコンパイラだ。 (略) 手間暇かかること請け合いの分野なので手が出せずにいる。

私も昔同じように考えていましたが、今は「入門用の簡単なものならそこまでハードル高くないですよ」「割とカジュアルに入門できますよ」と思っています。

この記事を読んだ人は(ひょっとしたら)こちらも読んでいます

memo88.hatenablog.com

memo88.hatenablog.com

memo88.hatenablog.com

memo88.hatenablog.com