return page history
α-wwwiki
::
history/regexp_evaluator/20130917-071959.txt
editor : alpha [82.255.141.68] 2013/09/17 07:20:00 _h1 regexp evaluator{sup (3)} {div {@ style="font:bold 0.9em georgia;text-align:center;color:red;background:#eee;box-shadow:0 0 8px black;"} [[basic_evaluator]] | [[extended_evaluator]] | regexp_evaluator | [[lisp_evaluator]]} _p This is a multi s-expressions evaluator based on a unique loop catching the s-expressions through a unique Regular Expression and coming with the special operator "def" allowing to extend the set of basic functions. The dictionary contains two kinds of functions : _ul primitive javascript functions hard-coded in the dictionary, for instance : {b dico['js_mult'] = function(a,b) °°{ return a*b }°°;} which will be called {b (js_mult 3 4)}, _ul user functions dynamically built via the "def" operator using s-expressions, for instance : {b (def ls_mult (x y) (* x y))}, which will be called {b (ls_mult 3 4)}. _p This is how to use the console : _ul first "init the evaluator", only once, _ul copy some s-expressions from the examples in the code, _ul paste them into the field below, _ul then click on the button "evaluate" _ul and do it again with another ones. {hr} {textarea {@ id="input" style="width:99%;height:200px;background:#ffe;font:normal 1em courier;"} (h1 Hello World) (div (@ style="color:blue;")(* 1 2 3 4 5 6)) (def pytha (x y) (sqrt (+ (* x x) (* y y) ) ) ) (pytha 3 4) (def fac (:a :n) (if (lt :n 1) then :a else [fac [* :n :a] [- :n 1] ] )) (fac 1 6) (img (@ src="data/amelie_sepia.jpg" height="200" title="Amélie's smile" ) ) } First {input {@ type="submit" value="init evaluator" onclick="°° var js = document.createElement('script'); var input = getId('code').innerHTML; js.innerHTML = decode_html_entities(input); // < ,> document.head.appendChild( js ); this.value = 'OK, evaluator inited !'; this.disabled='disabled'; °°"}} then {input {@ type="submit" value="evaluate" onclick="do_evaluate()"}} {pre {@ id="output"}} _h3 examples {pre // 1) basic operators (+ 1 2 3 4 5 6) -> 21 (* 1 2 3 4 5 6) -> 720 (- 1) -> -1 (- 1 2) -> -1 (/ 3) -> 0.3333333333333333 (/ 1 2) -> 0.5 (/ 1 2 2) -> 0.25 (/ 1 2 2 2) -> 0.125 (+ (* 3 3) (* 4 4) ) -> 25 (++ 3) -> 4 (-- 3) -> 2 (lt 1 2) -> true (gt 1 2) -> false (eq 1.0 1.000) -> true (not true) -> false (and true false) -> false (or true false) -> true ///////////////////////////////// // 2) the JS Math functions (sqrt 2) -> 1.4142135623730951 (pow 2 8) -> 256 (log (E)) -> 1 (exp 1) -> 2.718281828459045 (max 1 3 2 23 1 56) -> 56 (min -10 3 2 23 1 56) -> 10 (acos 1) -> 0 (sqrt (+ (* 3 3) (* 4 4) ) ) -> 5 (+ (square (cos 0)) (square (sin 0)) ) ///////////////////////////////// // 3) the core defined user functions (square 12) -> 144 (hypo 3 4) -> 5 (fac 6) -> 720 (rand 1000) -> an integer in [1 1000) ///////////////////////////////// // 4) inline defined user functions // 41) defining a constant (def myPI () 3.1416) (myPI) -> 3.1416 // 42) defining a function with one argument (def carre (x) (* x x)) (carre 12) -> 144 // 43) defining a function with two arguments (def pytha (x y) (sqrt (+ (* x x) (* y y) ) ) ) (pytha 3 4) -> 5 // 44) defining a recursion // caution : in the thenterm and elseterm the roound parenthesis // must be replaced by square parenthesis to prevent evaluation. (def fac (:a :n) (if (lt :n 1) then :a else [fac [* :n :a] [- :n 1] ] )) (fac 1 6) ///////////////////////////////// // 5) HTML functions (h1 Hello World) (div (@ style="color:blue;") (* 1 2 3 4 5 6)) (img (@ src="data/amelie_sepia.jpg" height="200" title="Amélie's smile")) } _h3 evaluator's code {pre {@ id="code"}°° // 1) HTML interface function do_evaluate() { getId('output').innerHTML = REGEXP_EVAL.parser(getId('input').value); } // 2) REGEXP_EVAL var REGEXP_EVAL = (function () { // 1) parser function parser( str ) { str = str.trim(); str = catch_defs( str ); str = doLoop( str ); return str; } function doLoop( str ) { // the one-line loop : var loop_rex = /\(([^\s()]*)(?:[\s]*)([^()]*)\)/g; while (str != (str = str.replace( loop_rex, dispatch ))) ; return str; } var dispatch = function (m, f, r) { f = f || '', r = r || ''; if (dico.hasOwnProperty( f )) return dico[f].apply(null, r.split(' ')); else return '{' + f + ' ' + r + '}'; }; function catch_defs( str ) { while (true) { var s = expression_catch( '(def ', str ); if (s === 'none') break; str = str.replace( '(def '+s+')', extend_dico( s ) ); } return str; } function expression_catch ( symbol, str ) { var start = str.indexOf( symbol ); if (start == -1) // no expression return 'none'; var long = symbol.length; var foo = '', nb = 1, index = start; while( nb>0) { if (index > 10000) return 'none'; index++; if ( str.charAt(index) == '(' ) nb++; else if ( str.charAt(index) == ')' ) nb--; } foo = str.substring( start+long, index ); return foo; } function extend_dico( str ) { var name = str.substring(0, str.indexOf(' ')); str = str.substring(str.indexOf(' ')+1); var args = str.substring(1, str.indexOf(')')).split(' '); var body = str.substring(str.indexOf(')')+1).trim(); dico[name] = function () { // params name must be prefixed by a ":" var vals = [].slice.call(arguments); return function (arr) { var _body = body for (var i=0; i< args.length; i++) { var reg = new RegExp(args[i], 'g'); _body = _body.replace( reg, vals[i] ); } return _body; }(vals); }; return name; } // 2) dictionary var dico = {}; // basic operators dico['+'] = function() { for (var r=0, i=0; i< arguments.length; i++) r += Number(arguments[i]); return r; }; dico['*'] = function() { for (var r=1, i=0; i< arguments.length; i++) r *= arguments[i]; return r; }; dico['-'] = function () { // (- 1 2 3 4) -> 1-2-3-4 var r = arguments[0]; if (arguments.length == 1) r = -r; // case (- 1) -> -1 else for (var i=1; i< arguments.length; i++) r -= arguments[i]; return r; }; dico['/'] = function () { // (/ 1 2 3 4) -> 1/2/3/4 var r = arguments[0]; if (arguments.length == 1) r = 1/r; // case (/ 2) -> 1/2 else for (var i=1; i< arguments.length; i++) r /= arguments[i]; return r; }; dico['%'] = function(a,b) { return a % b }; dico['++'] = function(a) { return a + 1 }; // (++ 3) -> 4 dico['--'] = function(a) { return a - 1 }; // (-- 3) -> 2 dico['gt'] = function(a,b) { return a > b }; // (> 2 1) -> true dico['lt'] = function(a,b) { return a< b }; // (< 2 1) -> false dico['eq'] = function(a,b) { return !(a< b) && !(b< a) }; dico['not'] = function (a) { return !a }; dico['or'] = function () { for (var ret=false, i=0; i< arguments.length; i++) if (arguments[i]) return true; return ret; }; dico['and'] = function () { // (and (= 1 1) (= 1 2)) -> false for (var ret=true, i=0; i< arguments.length; i++) if (!arguments[i]) return false; return ret; }; dico['if'] = function () { // (if (lt 1 2) then [+ 2 3] else [* 2 3]) var terms = [].slice.call(arguments).slice(2).join(' ').split('else'); var r = (arguments[0] === "true")? terms[0] : terms[1]; r = r.replace( /\[/g, '(' ).replace( /\]/g, ')' ); // console.log( r ); return doLoop( r ); }; /* this work : (def fac (:a :n) (if (lt :n 1) then :a else [fac [* :n :a] [- :n 1] ] )) (fac 1 6) but this doesn't work : (def fac (:n) (if (lt :n 1) then 1 else [* :n [fac [- :n 1]]] )) (fac 6) */ // JS Math functions var mathfns = ['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'random', 'round', 'sin', 'sqrt', 'tan']; for (var i=0; i< mathfns.length; i++) dico[mathfns[i]] = Math[mathfns[i]]; dico['PI'] = function () { return Math.PI; }; dico['E'] = function () { return Math.E; }; // some user JS functions dico['square'] = function(a) { return a*a }; dico['hypo'] = function(a,b) { return Math.sqrt(a*a+b*b) }; dico['fac'] = function(a) { return (a< 2)? 1 : a*arguments.callee(a-1); }; dico['rand'] = function(a) { return Math.floor((Math.random()*a)+1) }; // in [1,a] // HTML tags var htmltags = [ // register HTML tags, mathML tags 'div', 'span', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'table', 'tr', 'td', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'br', 'hr', 'b', 'i', 'u', 'sup', 'sub', 'del', 'pre','center', 'blockquote', 'code', 'a', 'img']; for (var i=0; i< htmltags.length; i++) { dico[htmltags[i]] = function(tag) { return function() { var args = [].slice.call(arguments).join(' ').replace(/,/g, ' '); return alpha.doLoop('{'+tag+' '+args+'}'); } }(htmltags[i]); } // and so on ... return {parser:parser}; }()); // end REGEXP_EVAL °°}