バイナリツリーバリデータ改
全ての値をバイナリツリーにしてしまうと、switch文だけで文法をチェックできます。
エラーを発見したらthrowすることにすると、returnの値がtrueかfalseかとか
関係なくなるので、アクションとか追加できそうな雰囲気です。
ガードとか無いので、match構文なんていらない!ってところまではならないかもしれないですが、
いい感じなのではないかと。
これを使って、インタプリタや、スタックマシンへのコンパイラを作ってみると、アクションを
どう追加したら良いかが分かってくると思います。
<script> function BTree(a,b,c) { this.l = a; this.op = b; this.r = c; } BTree.prototype.toString = function() { return "B("+this.l+","+this.op+","+this.r+")"; } function toB(a) { switch(typeof(a)) { case "string": case "number": return new BTree(a, typeof(a), null); } return a; } function B(a,b,c) { return new BTree(toB(a),b,toB(c)); } // 2分木の再帰下降バリデータ。 function valid(data) { return statement(data); } function statement(data) { switch (data.op) { case "if": return exp(data.l), else_(data.r); case "C": return valid(data.l), valid(data.r); default: return exp(data); } } function else_(data) { switch(data.op) { case "else": return exp(data.l), exp(data.r); default: return exp(data); } } function id(data) { switch(data.op) { case "number": case "string": return data; default: throw "error"; } } function assignLeft(data) { switch(data.op) { case "[]": return arr(data); default: return id(data); } } function arr(data) { switch(data.op) { case "[]": return assignLeft(data.l), exp(data.r); default: throw "error"; } } function exp(data) { switch (data.op) { case "=": return assignLeft(data.l), exp(data.r); case "+": case "*": return exp(data.l), exp(data.r); default: return id(data); } } function p(d) { document.write("<b>"+d+"</b><br/>"); } function test(data) { try { valid(data); } catch (e) { document.write(e+" "+data+"<br>"); } } test(B(1,"+", B(2, "*", 3))); test(B(1,"*", B(2, "+", 3))); test(B(1,"if", B(2, "else", 3))); test(B(1,"if", B(2, "els", 3))); test(B(1,"if", B(2, "else", B(3,"else",4) ))); test(B(1,"if", 3)); test(B(1,"C",B(1,"if", 3))); test(B(1,"else",2)); test(B("a","=",2)); test(B(B("a","=","b"),"=",2)); test(B("a","=",B("b","=",2))); test(B(B("a","[]",2),"=",2)); test(B(B("a","[]",B("a","=","b")),"=",2)); </script>