JScriptでGrass処理系書け・・・てなかった
ちょこっとGrassが話題になったので,ふと,JScriptで実装してみたら面白くね?と思った.しかし,それが泥沼の始まりだった……
最適化とか考えずにガリガリ書き進んでいった結果,
function grass(code){ // List function N(v, n) { this.n = n; this.v = v; } N.prototype.i = function(s) { var p = this; for(i = 1; i < s; ++i) p = p.n; return p; } N.prototype.s = function(v) { return new N(v, this); } var Eps = new N(null, null); function L(A) { var n = Eps; for(var i = A.length - 1; i >= 0; --i) n = new N(A[i], n); return n; } // Grass op-codes function App(m,n){ this.m = m; this.n = n; } function Abs(n,C){ this.n = n; this.c = C; } // Primitive functions function True(x){ return function(y) { return x; } } function False(x) { return function(y) { return y; } } function gW(c) { function w(s){ return s == w.w ? True : False; }; w.w = c; return w; } function Out(s) { if(!('w' in s)) throw new Error("文字じゃないくさいな(キリッ"); WScript.StdOut.Write(String.fromCharCode(s.w)); return s; } function In(s) { return s; } function Succ(s) { if(!('w' in s)) throw new Error("文字じゃないくさいな(キリッ"); s.w = (s.w+1)&255; return s; } // compile var tokens = code.replace(/[^WwvWwv]/g,'').match(/[ww]+|[WW]+[ww]+|[vv]/g); var stateAbs = 0,stateApp = 1,state = stateAbs, C = []; while (tokens.length) { var tok = tokens.shift(); if (tok.match(/^[ww]+/)) { if (state != stateAbs) return false; var nd = RegExp.lastMatch.length, Cd = []; for (;;) { if (!tokens.length || !tokens[0].match(/([WW]+)([ww]+)/)) break; tokens.shift(); var m = RegExp.$1.length; var n = RegExp.$2.length; Cd.push(new App(m,n)); } if (tokens.length && !tokens.shift().match(/^[vv]/)) return false; C.push(new Abs(nd,L(Cd))); } if (tok.match(/^([WW]+)([ww]+)/)) { if (state == stateAbs) state = stateApp; var m = RegExp.$1.length; var n = RegExp.$2.length; C.push(new App(m,n)); } } // step var VM = { C: L(C), E: L([Out, Succ, gW(119), In]), D: L([[L([new App(1,1)]), Eps],[Eps, Eps]])}; while (VM.C != Eps || VM.D != Eps) { if (VM.C == Eps) { var f = VM.E.v; var d = VM.D.v; VM.C = d[0]; VM.E = d[1].s(f); VM.D = VM.D.n; } else if (VM.C.v instanceof App) { var app = VM.C.v; var em = VM.E.i(app.m).v; var en = VM.E.i(app.n).v; if (!(em instanceof Array)) { // primitive function VM.E = VM.E.s(em(en)); VM.C = VM.C.n; } else { // Grass function VM.D = VM.D.s([VM.C.n, VM.E]); VM.C = em[0]; VM.E = new N(en, em[1]); } } else if (VM.C.v instanceof Abs) { var abs = VM.C.v; VM.E = VM.E.s([(abs.n > 1 ? L(new Abs(abs.n-1, abs.c)) : abs.c), VM.E]); VM.C = VM.C.n; } } } var input = ""; while (!WScript.StdIn.AtEndOfStream) { input += WScript.StdIn.ReadAll(); } grass(input);
と,操作的意味論べったりなひどい処理系が出来上がった.
とりあえず,公式サイトに書かれている不動点演算子で芝生が茂るスクリプトを食わせてみたところ,何故か途中で終了してしまう.なんか芝生もチルダになってるし・・・.
トレースログをとってみると,プログラムの途中で正常終了していることが分かった.恐らくコールスタック周りでエンバグしていると思うんだけど,実装者があまり賢くないので,上手く原因をつかめない.うぎぎ・・・
とりあえず,公式(ちょっと草植えときますね型言語 Grass)に書かれているサンプルをぽちっと実行.
無限に草植えときますねwWWwwwwWWww →wwwwwwwwwwwwwwwwwwwwwwwwwwwwww... YコンビネータwwWWwwWwwvちょwwWWWwWWWwvおまwWWwWwv →(帰ってこない) wwwwvwvwwWWwvwwWwwvwwwwWWWwwWwwWWWWWWwwwwWw (以下略) →~~~~~~~~~~~~~~~~~~~~~
あってるの・・・?なんかものすごく間違っている気がする.