+
1
|
list
|
skin
|
login
|
editor
α-wwwiki
::
evaluator3
user:none
(6023 bytes)
_h3 20-lines-evaluator _p After the 8 lines [[evaluator2]], this is another one on less then 20 lines coming with the special operators "quote" and "def", extending the set of basic functions. The number of functions has strongly increased in the 'dictionary' (see dico in the code). Note that the functions' body accept only JS expressions. _p This is how to use the console : _ul first "init the evaluator", only once, _ul copy a line 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} 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()"}} {input {@ id="input" type="texte" value="['sqrt', ['+', ['*',3,3], ['*',4,4]]]" style="width:99%; font:normal 1em courier; color:red;background:#ffc;"}} {pre {@ id="output"}} _h3 evaluator's code {pre {@ id="code"}°° // HTML interface function do_evaluate() { getId('output').innerHTML = evaluate( getId('input').value ); } // evaluator var evaluate = function(str) { var expression = eval( str ), first = '', rest = []; if (!Array.isArray(expression)) return expression; // it's a Number or a String first = expression.shift(); if (first == 'quote') // don't evaluate return expression; if (first == 'def') { // extend dico var body = expression[0][1], name = body.shift(), args = body.shift(); dico[name] = new Function( args.join(','), body ); return name; } 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 !'; } // functions 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< 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 ... °°} _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', ['quote', ['PI',[''],'return Math.PI'] ] ] ['PI'] -> 3.141592653589793 // 42) defining a function with one argument ['def', ['quote', ['carre',['a'],'return a*a'] ] ] ['carre',12] -> 144 // 43) defining a function with two arguments ['def', ['quote', ['pytha', ['a','b'],'return Math.sqrt(a*a+b*b)'] ] ] ['pytha',3,4] -> 5 } _h3 todo _ul def operators with a body made of s-expressions, _ul lambdas, inline defs _ul ... I think that [[amlisp]] was not so bad ... and I will return to it. Have a look to [[amlisp]]