Io風味パーサ
かなり、適当ですが、Io風味のパーサを作ってみました。
a(b,c,d[][]) e f{} []
といった式をパースして、以下のような構造を作ります。
call{ call{ call{a(b,c,call{d[],[]}), e}, f{} }, [] }
Ioと互換ではなくて、拡張したり、手を抜いたりしてます。
Ioはかなり強力だということがわかりました。
<script> function cparse (str) { var pop = function () { str = str.replace(/^[ \t\r\n]+/, ""); var s = str.charAt(0); str = str.substring(1); return s; }; var peek = function () { str = str.replace(/^[ \t\r\n]+/, ""); return str.charAt(0); }; var isParen = function(p) { return p=="(" || p=="[" || p=="{"; } var isEndParen = function(p) { return p==")" || p=="]" || p=="}"; } var cexp = function() { var m = list(); while (peek() != "" && peek() != "," && !isEndParen(peek())) { var m = [m, list()]; m.name = "call"; m.type = "{"; } return m; }; var list = function () { var name = isParen(peek()) ? "" : atom(); if (!isParen(peek())) return name; var type = pop();// ( var end = {"(":")", "[":"]", "{":"}"}[type]; var a = new Array(); a.name = name; a.type = type; a.end = end; while(peek() != end) { a[a.length] = cexp(); if (peek() == end) break; if (peek() == ",") {// 括弧の連続 pop(); } else { throw "error " + str; } } pop();// ) return a; }; var atom = function () { var cut = function(m) { var m; if (m = str.match(m)) { str = str.substring(m[0].length); return m[0]; } return null; }; var m; if (m = cut(/^[0-9]+/)) return Number(m); if (m = cut(/^[a-zA-Z_][a-zA-Z0-9_]*/)) return m; if (m = cut(/^[\+\-\*\/]*/)) return m; throw "syntax error [" + str + "]"; } return cexp(); }; Array.prototype.toString = function() { var type = "("; var end = ")"; switch (this.type) { case "{": type = "{"; end = "}"; break; case "[": type = "["; end = "]"; break; } var str = ((this.name) ? this.name : "") + type; var sepa = ","; if (this.name == "call") { sepa = str = end = ""; } var sepf = ""; for (var i = 0; i < this.length; i++) { str += sepf + this[i]; sepf = sepa + " "; } return str + end; }; Array.prototype.t_s = function() { var type = "("; var end = ")"; switch (this.type) { case "{": type = "{"; end = "}"; break; case "[": type = "["; end = "]"; break; } var str = ((this.name) ? this.name : "") + type; var sepa = ","; var sepf = ""; for (var i = 0; i < this.length; i++) { var a = (this[i]["t_s"]) ? this[i].t_s() : this[i]; str += sepf + a; sepf = sepa + " "; } return str + end; }; try { var c = cparse("if(a,b,c[][]) b c{}[]"); alert("parse result:\n" + c + "\n" + c.t_s()); } catch(e) { alert(e); } </script>