return page history
α-wwwiki
::
history/regexp_evaluator/20130709-085757.txt
editor : alpha [82.254.102.173] 2013/07/09 08:57:57 _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 RegExp and coming with the special operator "def" allowing to extend the set of basic functions. There are two dictionaries : _ul the initial {b jsdico} with functions whose body is in javascript code, for instance : {b jsdico['js_mult'] = function(a,b) °°{ return a*b }°°;} _ul the {b lsdico} storing the user functions via the "def" operator ; the function's body must be written with valid s-expressions, for instance : {b jsdico['ls_mult'] = °°{args:'x,y', body:'(* x y)'}°°;}. _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() { var input = getId('input').value; getId('output').innerHTML = parser(input); } // 2) 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 (jsdico.hasOwnProperty( f )) return eval_jsdico(f,r); else if (lsdico.hasOwnProperty( f )) return eval_lsdico(f,r); else return '{' + f + ' ' + r + '}'; }; var eval_jsdico = function (f,r) { return jsdico[f].apply(null, r) }; var eval_lsdico = function (f,r) { var args = lsdico[f].args, body = lsdico[f].body, vals = r; for (var i=0; i< args.length; i++) { var reg = new RegExp(args[i], 'g'); body = body.replace( reg, vals[i] ); } return body; }; function catch_def( str ) { var s = symbol_catch( '(def ', str ); return str.replace( '(def '+s+')', extend_lsdico( s ) ); } function symbol_catch ( symbol, str ) { // (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; } function extend_lsdico( 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,''); lsdico[name] = {args:args, body:body}; return name; } // 3) dictionaries var lsdico = {}; lsdico['add'] = {args:'x,y', body:'(+ x y)'}; lsdico['mult'] = {args:'x,y', body:'(* x y)'}; lsdico['pythagore'] = {args:'x,y', body:'(sqrt (add (mult x x) (mult y y)))'}; var jsdico = {}; // basic operators jsdico['+'] = function() { for (var r=0, i=0; i< arguments.length; i++) r += Number(arguments[i]); return r; }; jsdico['*'] = function() { for (var r=1, i=0; i< arguments.length; i++) r *= arguments[i]; return r; }; jsdico['-'] = 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; }; jsdico['/'] = 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; }; jsdico['++'] = function(a) { return a + 1 }; // (++ 3) -> 4 jsdico['--'] = function(a) { return a - 1 }; // (-- 3) -> 2 jsdico['>'] = function(a,b) { return a > b }; // (> 2 1) -> true jsdico['< '] = function(a,b) { return a< b }; // (< 2 1) -> false jsdico['='] = function(a,b) { return !(a< b) && !(b< a) }; // (= 1 1) -> true jsdico['not'] = function (a) { return !a }; // (not (= 1 1)) -> false jsdico['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; }; jsdico['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++) jsdico[mathfns[i]] = Math[mathfns[i]]; jsdico['PI'] = function () { return Math.PI; }; jsdico['E'] = function () { return Math.E; }; // some user JS functions jsdico['square'] = function(a) { return a*a }; jsdico['hypo'] = function(a,b) { return Math.sqrt(a*a+b*b) }; jsdico['fac'] = function(a) { return (a< 2)? 1 : a*arguments.callee(a-1); }; jsdico['rand'] = function(a) { return Math.floor((Math.random()*a)+1) }; // in [1,a] jsdico['mod'] = function(a,b) { return a % b }; // and so on ... °°}