return page history
α-wwwiki
::
history/regexp_evaluator/20130709-103105.txt
editor : alpha [82.254.102.173] 2013/07/09 10:31:05 _h1 regexp evaluator {div {@ style="font:bold 1.0em georgia;text-align:center;color:red;background:#eee;box-shadow:0 0 8px black;"} [[basic_evaluator]] | [[extended_evaluator]] | regexp_evaluator | [[alphalisp|data/alphalisp/]]} _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 it into the field below, _ul then click on the button "evaluate" _ul and do it again with new values. {hr} {textarea {@ id="input" style="width:99%;height:200px;background:#ffe;font:normal 1em courier;"} (def pytha (x y) (sqrt (+ (* x x) (* y y) ) ) ) (pytha 3 4) } 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 (< 1 2) -> true (> 1 2) -> false (= 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 } _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 = catch_def( str ); str = doLoop( str ); return str; } function doLoop( str ) { // the one-line loop : var loop_rex = /\(([^\s()]*)(?:[\s]*)([^()]*)\)/g; str = str.replace(/^\s+|\s+$/g, ''); while (str != (str = str.replace( loop_rex, dispatch ))) ; return str; } var dispatch = function (m, f, r) { f = (f !== undefined)? f : ''; r = (r !== undefined)? r.split(' ') : ''; if (dico.hasOwnProperty( f )) return dico[f].apply(null, r); else return '{' + f + ' ' + r + '}'; }; function catch_def( str ) { var s = expression_catch( '(def ', str ); return str.replace( '(def '+s+')', extend_dico( s ) ); } function extend_dico( str ) { // pytha (x y) ( .... ) 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).replace(/^\s+|\s+$/g,''); dico[name] = function () { var vals = [].slice.call(arguments); return function (arr) { 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; } function expression_catch ( symbol, str ) { // catch (symbol rest) var start = str.indexOf( symbol ); if (start == -1) // no symbol return 'none'; var long = symbol.length; var foo = '', nb = 1, index = start; while( nb>0) { if (index > 100) return 'Oups'; index++; if ( str.charAt(index) == '(' ) nb++; else if ( str.charAt(index) == ')' ) nb--; } foo = str.substring( start+long, index ); return foo; } // 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) { return a + 1 }; // (++ 3) -> 4 dico['--'] = function(a) { return a - 1 }; // (-- 3) -> 2 dico['>'] = function(a,b) { return a > b }; // (> 2 1) -> true dico['< '] = function(a,b) { return a< b }; // (< 2 1) -> false dico['='] = function(a,b) { return !(a< b) && !(b< a) }; // (= 1 1) -> true dico['not'] = function (a) { return !a }; // (not (= 1 1)) -> false dico['or'] = function () { // (or (= 1 1) (= 1 2)) -> true 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; }; // 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] dico['mod'] = function(a,b) { return a % b }; // and so on ... return {parser:parser}; }()); // end REGEXP_EVAL °°}