return page history
α-wwwiki
::
history/regexp_evaluator/20130917-190249.txt
editor : alpha [82.248.49.238] 2013/09/17 19:02:49 _h1 regexp evaluator{sup (3)} {div {@ style="text-align:center; color:red; background:#eee;box-shadow:0 0 8px black;"} [[basic evaluator|?view=basic_eval]] | [[extended eval|?view=extended_evaluator]] | regexp eval | [[alpha lisp|?view=lisp_evaluator]] | [[monodico lisp|?view=monodicolisp]] } _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 and operators built in the dictionary, for instance the "*" operator used this way : {b (* 2 3) -> 6}. Have a look to the code to see the dictionary content. _ul user functions dynamically built via the "def" operator using s-expressions, for instance : {b (def mult (:x :y) (* :x :y))}, which will be called {b (mult 2 3) -> 6}. _p {b Notes} _ul 1) params of user defined functions must be prefixed by a semi-colon ":" to prevent possible conflicts in the regexp replace process, _ul 2) until now, in the thenterm and elseterm of {b if} operators, the round parenthesis must be replaced by square parenthesis, in order to delay their evaluation. It may be fixed soon. See examples and code, _ul 3) in booleans, the operators ">" and "<" must be replaced by "gt" and "lt" to prevent conflicts with the wiki engine which breaks HTML code. {hr} _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. {textarea {@ id="input" style="width:99%;height:400px;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 (:n) (if (lt :n 1) then 1 else [* :n [fac [- :n 1]]] ) ) (fac 6) (def ifac (:a :n) (if (lt :n 1) then :a else [ifac [* :n :a] [- :n 1] ] ) ) (ifac 1 123) (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 (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)) ) ///////////////////////////////// // 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 recursion // caution : in the thenterm and elseterm the roound parenthesis // must be replaced by square parenthesis to prevent evaluation. (def fac (:n) (if (lt :n 1) then 1 else [* :n [fac [- :n 1]]] ) ) (fac 6) (def ifac (:a :n) (if (lt :n 1) then :a else [ifac [* :n :a] [- :n 1] ] ) ) (ifac 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 // initial body must not be modified 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 = {}; dico['if'] = function () { // (if (lt 1 2) then [+ 2 3] else [* 2 3]) // caution : in the thenterm and elseterm the roound parenthesis // must be replaced by square parenthesis to prevent evaluation. 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, ')' ).trim(); return r; }; // 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 parseFloat(a) % parseFloat(b) }; dico['gt'] = function(a,b) { return parseFloat(a) > parseFloat(b) }; dico['lt'] = function(a,b) { return parseFloat(a) < parseFloat(b) }; dico['eq'] = function(a,b) { a = parseFloat(a); b = parseFloat(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; }; // 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 built-in JS functions (for memory) /* dico['fac'] = function(a) { // can be defined inline return (a< 2)? 1 : a*arguments.callee(a-1); }; dico['rand'] = function(a) { // in [1,a] return Math.floor((Math.random()*a)+1) }; */ // 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 °°}