Schemeをつくろう(22) - JavaScriptのメモ

JavaScriptSchemeを作る為に必要なことをメモっとく。

字句解析

tokenize = function(src) {
    return src.match(/\(|\)|'|[^\s()']+/g);
};
// tokenize("(hello Javascript and Scheme world !!)")
//   => #(( hello Javascript and Scheme world !! ))

配列に分解出来る。ステキ。

ほうほう。

/\"(?:[^"])*\"/

二重引用符の正規表現っぽいが、(?: )が何やってんのかよーわからん。エスケープ入れると更に大変そうだ・・・。

eval

<div onclick="eval(this.firstChild.nodeValue)">alert("hello")</div>

タグの中をeval。便利。

apply

無いと死ねる。

var scm = new Scheme();

function len() {
    return arguments.length
}

alert(len.apply(this, [1, 2, 3, 4])); // => 4

関数.apply(環境, 引数の配列)

JavaScriptにはクロージャがある。
thisの部分で遊ぶと時空を越えられるかも知れない。

  • 連想配列はObject型
  • 配列はArray型
  • null,undefinedはObjectを継承していない。。

括弧って便利ね

コロンで区切って複数式が書ける。

(alert("hello"),
 alert("world"))

構文はエラーになるので、無名関数で囲む。

Biwa Schemeを読む(3) - コンパイラ〜インタプリタ

ここからが本題。CompilerとInterpreterは一緒に読んだ方がよさげ。

Biwa Scheme中間言語は[命令,値(複数),次の命令]という形になっていて再帰的な構造をしているようだ。

命令一覧

  • halt
    • 終わり。
  • constant 値
  • argument
  • refer-global 名前,-local 名前, refer-free 名前
    • 環境を参照する,assignで書く。
  • apply 引数の数
    • 命令の実行。
  • frame 命令・・・
    • ローカル環境っぽい。

まだ読み中。

突っ込み

0.5の時点では積み方が逆。

(define (p x)
 (display x)
 (newline)
 x)
(+ (p 1) (p 2))

2
1
3

破壊的でなければ何の問題も無い。

感想

  • 中間言語を利用することで最適化を促す事が出来、速度向上に繋がる。
  • 判ったことは、S式という状態だけでも充分過ぎるほどの中間言語である。
  • 結局のところ写像をしてるだけなんだ。

Biwa Schemeを読む(2) - パーサー

まずはパーサーを読む。

2段階に分けてある様子。

  • トークンに分ける(tokenize)
    • 一気にS式に変換するのではなく、文字列をトークンに分解している。
  • S式に変換(getObject)
    • 型付けをしながらS式に変換。
    • 正規表現があると楽チンらしい。

感想など

  • ここまでは今まで読んだモノと変わらない。
  • パーサー作るのが楽なのがSchemeの特徴であり、コンパイラの学習には最適だと感じる。

Biwa Schemeを読む(1) - データ構造

stackbase.jsを読み進める。データ構造を理解していこう。

環境系

  • TopEnv
    • トップクラスの環境。いわゆるグローバル変数とか、グローバル関数だとか。
  • CoreEnv
    • 今のところ謎。
  • Symbols
    • シンボルテーブル。Symbolクラスが入ってる。

データ構造

  • eof
    • なんだろ。
  • Set
    • 配列らしい。
  • Pair
    • 対。
  • Values
    • 値?
    • JSだと楽チン仕様だ
  • nil
    • null
  • Symbol
    • シンボル。
  • Char
    • 文字。
  • Port
    • ストリーム。
  • Syntax
    • マクロ
  • Call


やばい。楽しくなってきた。

Biwa Schemeを読む(0) - 斜め読み

仮想マシン

クロージャやら末尾再帰の最適化やら継続やらをなんとか理解できるようになってきた。しかし、中間コードを生成し,
仮想マシンで・・・と言われると何のことやらちんぷんかんぷんだ。

こんな感じ?

僕のイメージとしては、パーサーを通してS式に変換して、S式を順番に読み上げてリスト形式のForth(アセンブリ言語に毛が生えたような言語)作る。で、リスト形式のForthを実行してるのかなぁと。しかし、謎の部分が多すぎていきなり作る訳にもいかなそうだ。

そうだBiwa Schemeを読もう

ということで、JavaScriptで書かれたスタックベースのSchemeBiwaScheme0.5を簡単に写経しながら読み解いていきたいと思います。


とりあえずファイル構造から理解する事に。

  • index.html
    • ブラウザで動作確認が取れる。メインっぽい。
    • ブラウザのボタン押したら、bs_evalを呼ぶ。
    • new WebScheme.Interpreter()がメインのクラスかな?
    • コードを取得して、コンパイルしたものを表示しているようだ。
    • evaluate(コード,継続?)で評価して表示。
      • 2番目の引数はイマイチ謎なので、後で追う事にする。
  • lib/prototype.160.js
    • prototype1.6使ってるらしい。これも未読なので、積読にしておこう。
  • lib/stackbase.js
    • たぶんコア部分。次回からはここを中心に読むと思われる。
  • lib/r6rs_lib.js
    • R6RSのライブラリ。0.5の時点では未完っぽい。
  • lib/webscheme_lib.js
  • lib/extra_lib.js
    • SRFIとか。無いと困っちゃいそうな関数群。
  • サンプルコード色々。
    • ネットワーク関連が充実してるっぽい。

ここまでの感想

  • 丁寧なソースで非常に読みやすいです。
  • そういやJavaScriptをずっと書いてなかった気がする。