Help us understand the problem. What is going on with this article?

Node.js でつくる Node.js ミニコンパイラ - 01 : 仕様の検討と、LLVMの準備

More than 1 year has passed since last update.

はじめに

「RubyでつくるRuby ゼロから学びなおすプログラミング言語入門」(ラムダノート, Amazon) という本を手を読んで非常に感銘を受けました。そこでも自分でもNode.jsでミニNode.jsインタープリタを作ってみました。なんとか達成して大きな自己満足を味わうことができました。

実はそのチャレンジにはもう一つのきっかけがあります。それは Turing Complete FM のポッドキャストを聴き始めたのことです。
このポッドキャストを聴きなら、そういえば随分昔に「自分で小さなコンパイラを作ること」に憧れていたことを思い出しました。小さなインタープリタを作れた今なら当時挫折したことができそうな気がして、今度はコンパイラ作りを目指します。

目指すもの

ミニインタープリタを作って分かったことは、適切に小さくした目標が重要だということです。今回目指すミニNode.jsコンパイラも、思い切って割り切った言語仕様にすることにしました。

  • FizzBuzzと、フィボナッチ数列の計算ができるようする
  • 仕様はミニNode.js (つまり、ミニRuby)を踏襲する
    • ただし、配列やハッシュは除外する
  • 型は32ビット符号付き整数のみサポート
  • ローカル変数が使える。グーローバル変数は無し
  • if - else, while が使える
  • ユーザ定義関数が使える(再帰呼び出しもできるようにしたい)
  • 組み込み関数として、整数の出力と固定文字列の出力ができるようにする

コンパイラなので型を導入しますが、1種類に割り切るというJavaScriptらしからぬ仕様にしました。これで型宣言も型推論も不要です(ドヤ顔)。

またコンパイラなので、最終的にはNode.js無しで実行できるバイナリを生成しなければなりません。が、そこは便利なツールを利用させてもらいます。

  • 単独で実行できるバイナリを生成することを目指す
    • バイナリ生成は、Node.jsではなくて別のツールを利用する
    • ミニコンパイラでは、中間コードを生成する
  • 自分自身をコンパイルすることは諦める(セフルホストはしない)
    • ミニコンパイラ自体は、ミニNode.jsインタープリタで実行できることを目指す

前提環境

今回は私の環境である Mac OS X 10.12 Sierra を前提に、取り組みを進めます。

コード生成に使うツール

最終的にバイナリを生成するところは、他のツールに任せることにしました。これでかなりコンパイラを作るハードルが下がります。ツールの候補としては、次のものを考えました。

  • Cコンパイラ (gcc or Clang)
  • Goコンパイラ
  • Rustコンパイラ
  • LLVM

最初の3つの場合は、Node.jsから各言語のソースコードに変換することになります。コンパイラを作ったというと、ちょっと違う感じがします。
そこで以前から気になっていたLLVMを使うことにしました。つまり、 Node.jsでLLVMの中間表現(Internal Representation)を生成することになります。

LLVMの準備

LLVMとは

LLVMによると

LLVMプロジェクトは、モジュール化された再利用可能なコンパイラおよびツールチェーン技術の集まりです

とあります。もともとは Low Level Virtual Machine の略語として名付けられたらしいのですが、いまはLLVMが正式な名称とのことです。
最近の言語系ではよく利用さているらしく、例えばClang, Swift, Rustが代表例です。ASM.jsやWebAssemblyを生成するEmscriptenもLLVMを利用しているそうです。
ちなみにGoもLLVMを使っているのかと思っていたのですが、実際は違いました。コンパイラもライブラリも自前で作るのがGoの流儀なようです。

LLVMのインストール

LLVM は Clang と一緒に提供されているようです。(Download page) その中で、今回は次のツールを使います。

  • lli ... LLVM IR(中間表現)やBitcode(バイトコード)を実行するツール
  • llc ... 実行モジュールのバイナリを生成するツール

Mac OS X の場合、clangは /usr/bin/clang にインストールされていますが、このツール群は含まれていません。また Xcode をインストールした場合にも clang がインストールされますが、lli/llcといったツールは無いようです。

Clang/LLVMのインストールには次の方法があります。

  • (1) ソースコードからビルドする
  • (2) homebrewを使ってインストールする(Mac OS Xの場合)
  • (3) ビルド済みのバイナリ(Pre-build)をダウンロードする

今回はなるべく簡単にすませたくて、3番目のビルド済みバイナリをダウンロードする方法をとりました。Mac OS Xで作業しているため、こちらのページから Clang for Mac をダウンロードします。2018年7月現在、v6.0.0のバイナリが最新のようです。

圧縮ファイルを解凍すると中に下記のフォルダーが現れます。

  • bin
  • share
  • include
  • lib
  • libexec

一式をお好きな場所にコピーしてbinにパスを通してください。私の場合はパスを通す代わりに次のようにしました。

  • ~/Application/clang/ 以下に各フォルダーをコピー
  • bashのエイリアスを設定
    • alias llc='~/Applications/clang/bin/llc'
    • alias lli='~/Applications/clang/bin/lli'

次回は

つぎはLLVM IRの書き方を調べてみます。こちらのページを参考にします。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away