+
1
|
list
|
skin
|
login
|
editor
α-wwwiki
::
extended_evaluator
user:none
(7272 bytes)
_h1 extended evaluator {sup (2)} {div {@ style="text-align:center; color:red; background:#eee;box-shadow:0 0 8px black;"} [[basic eval|?view=basic_evaluator]] | extended eval | [[regexp eval|?view=regexp_evaluator]] | [[alpha lisp|?view=lisp_evaluator]] | [[monodico lisp|?view=monodicolisp]] } _p The extended evaluator works on valid s-expressions ; it is built on a greater dictionary of primitive javascript functions (see dico) which can be extended dynamically via the operator "define". Each s-expression is transformed via two functions, tokenize() and build_tree(), in a nested array recursively evaluated down to the primitive functions. Several s-expressions can be evaluated in sequence provided they are embedded in a (begin ....) s-expression. The body of the user defined functions must be written in javascript code. _h3 console _p This is how to use the console : _ul First click only once on the "init the evaluator", _ul type any s-expression in the input textarea, _ul then click on the button "evaluate" and do it again with new values. {textarea {@ id="input" style="width:99%; height:250px; font:normal 1em courier; color:red; background:#ffc;"} (begin (+ 1 2) (* 1 2 3 4 5 6) (sqrt (+ (* 3 3) (* 4 4))) (def (pytha (a b) function square (x) °°{ return x*x }°° return Math.sqrt( square(a) + square(b) ) ) ) (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) ) -> 5 (++ 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 (PI () return Math.PI)) (PI) -> 3.141592653589793 // 42) defining a function with one argument (def (carre (a) return a*a)) (carre 12) -> 144 // 43) defining a function with two arguments (def (pytha (a b) return Math.sqrt(a*a+b*b))) (pytha 3 4) -> 5 } _h3 evaluator's code {pre {@ id="code"}°° // HTML interface function do_evaluate() { getId('output').innerHTML = EXTENDED_EVAL.parser(getId('input').value); } var EXTENDED_EVAL = (function () { // 1) parser var parser = function (str) { return evaluate(build_tree(tokenize(str))) }; var tokenize = function ( s ) { return s.replace(/\(/g, ' ( ') .replace(/\)/g, ' ) ') .replace(/\s+/g, ' ') .trim() .split(' '); }; var build_tree = function (tokens) { var token = tokens.shift(); if (token !== '(') return token; var arr = [], i = 0; while (tokens[0] !== ')') { i++ ; if (i>10000) return 'unbalanced s-expression : game over !'; arr.push( build_tree(tokens) ); } tokens.shift(); return arr; }; var evaluate = function(expression) { var first = '', rest = []; if (!Array.isArray(expression)) return expression; // it's a Number or a String first = expression.shift(); if (first == 'def') // extend dico return extend_dico( expression[0] ); if (dico.hasOwnProperty(first)) { // evaluate recursively expression.map(function(a){rest.push(evaluate(a))}); return dico[first].apply(null,rest); } return 'Sorry, [' + first + '] is unknown !'; }; var extend_dico = function ( expr ) { var name = expr.shift(), args = expr.shift().join(','); body = JSON.stringify(expr) .replace(/^\[/, '').replace(/\]$/, '') .replace(/"/g, '').replace(/,/g, ' ') .replace(/\[/g, '(').replace(/\]/g, ')'); dico[name] = new Function( args, body ); return name; }; // 2) dictionary var dico = {}; dico['begin'] = function () { return [].slice.call(arguments).join(' ').replace(/ /g, '\n') }; // 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< arr.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)? false : true }; // (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 EXTENDED_EVAL °°}