Extension:RpnCalc

The RpnCalc extension allows mathematics via a RPN (Reverse Polish Notation) calculator MediaWiki extension.

Features

 * Allows long and complex expressions
 * Exposes several useful php functions
 * Allows local variable assignment
 * Allows page variable assignment and reusage in other blocks

Install
Create a file called 'RpnCalc.php' in your  directory, and add the following code...  ...  # the second parameter is the callback function for # processing the text between the tags $wgParser->setHook( "rpncalc", "RpnCalcDoMath" ); } $rpnCalcGlobalVars = array; $rpnCalcGlobalVarsNames = array;

function RpnCalcDoMath( $input, $argv) { global $wgOut; global $rpnCalcGlobalVars; global $rpnCalcGlobalVarsNames; # Parser $input = $wgOut->parse($input,false); try { # obs: comment try and catch if php4 if($argv["separator"]) $array = preg_split($argv["separator"], $input, -1, PREG_SPLIT_NO_EMPTY); else { $input = preg_replace('/<[^>]*>/', '', $input); # remove html $array = preg_split('/[\r\n ]/', $input, -1, PREG_SPLIT_NO_EMPTY); }   $stack = array ; $vars = array; $varsNames = array; $dbg = ""; while(count($array)>0) { $op = array_shift($array); $dbg .= '['. $op. ']; ';     if(is_numeric($op)) { array_push($stack, $op); continue; }      switch($op) { # operations case "rand": array_push($stack, rand); continue 2; case "lcg_value": array_push($stack, lcg_value); continue 2; case "pi": array_push($stack, pi); continue 2; }     if($rpnCalcGlobalVarsNames[$op]) { # global variable access array_push($stack, $rpnCalcGlobalVars[$op]); continue; }     if($varsNames[$op]) { # local variable access array_push($stack, $vars[$op]); continue; }     if(preg_match('/^".*"$/',$op)) { # string array_push($stack, preg_replace('/^"(.*)"$/',"$1",$op)); continue; }     if(count($stack)>=1) { # One parameter operations $p1 = array_pop($stack); if(preg_match("/^=@@/",$op)) { # global variable assignment $op = preg_replace("/^=/","", $op); $rpnCalcGlobalVars[$op] = $p1; $rpnCalcGlobalVarsNames[$op] = 1; continue; }       if(preg_match("/^=@/",$op)) { # local variable assignment $op = preg_replace("/^=/","", $op); $vars[$op] = $p1; $varsNames[$op] = 1; continue; }       switch($op) { # operations case "incr": case "++": array_push($stack, $p1 + 1); continue 2; case "decr": case "--": array_push($stack, $p1 - 1); continue 2; # date case "date":  array_push($stack, date($p1));  continue 2; # php math funcions case "abs": array_push($stack, abs($p1));   continue 2; case "acos":  array_push($stack, acos($p1));  continue 2; case "acosh": array_push($stack, acosh($p1)); continue 2; case "asin":  array_push($stack, asin($p1));  continue 2; case "asinh": array_push($stack, asinh($p1)); continue 2; case "atan":  array_push($stack, atan($p1));  continue 2; case "ceil":  array_push($stack, ceil($p1));  continue 2; case "cos": array_push($stack, cos($p1));   continue 2; case "exp": array_push($stack, exp($p1));   continue 2; case "deg2rad": array_push($stack, deg2rad($p1)); continue 2; case "rad2deg ": array_push($stack, rad2deg($p1)); continue 2; case "log10": array_push($stack, log10($p1)); continue 2; case "logn":  array_push($stack, log($p1)); continue 2; case "log1p": array_push($stack, log1p($p1)); continue 2; case "floor": array_push($stack, floor($p1)); continue 2; case "round": array_push($stack, round($p1)); continue 2; case "sin": array_push($stack, sin($p1));   continue 2; case "sqrt":  array_push($stack, sqrt($p1));  continue 2; case "tan": array_push($stack, tan($p1));   continue 2; case "dup": array_push($stack, $p1); array_push($stack, $p1); continue 2; case "preg_quote": array_push($stack, preg_quote($p1)); continue 2; }            }           if(count($stack)>=1) { # Two parameters operations $p2 = $p1; $p1 = array_pop($stack); switch($op) { # operations case "add": case "+": array_push($stack, $p1 + $p2); continue 2; case "sub": case "-": array_push($stack, $p1 - $p2); continue 2; case "mul": case "*": array_push($stack, $p1 * $p2); continue 2; case "div": case "/": array_push($stack, $p1 / $p2); continue 2; case "pow": case "^": array_push($stack, pow($p1,$p2)); continue 2; case "mod": case "%": array_push($stack, $p1 % $p2); continue 2; case "shr": case ">>": array_push($stack, $p1 >> $p2); continue 2; case "shl": case "<<": array_push($stack, $p1 << $p2); continue 2; case "concat": case ".": array_push($stack, $p1 . $p2); continue 2; # php math funcions case "fmod":  array_push($stack, fmod($p1,$p2)); continue 2; case "log": array_push($stack, log($p1,$p2));  continue 2; case "max": array_push($stack, max($p1,$p2));  continue 2; case "min": array_push($stack, min($p1,$p2));  continue 2; case "roundn": array_push($stack, round($p1,$p2)); continue 2; # stack operations case "swap": array_push($stack, $p2); array_push($stack, $p1); continue 2; case "dup2": array_push($stack, $p1); array_push($stack, $p2); array_push($stack, $p1); array_push($stack, $p2); continue 2; }     }      if(count($stack)>=1) { # Two parameters operations $p3 = $p2; $p2 = $p1; $p1 = array_pop($stack); switch($op) { # operations case "preg_replace": array_push($stack, preg_replace($p1,$p2,$p3)); continue 2; }     }      # error: invalid operation return "Invalid operation or insufficient parameters: " . $op. "<" . "p><". "nowiki>". $dbg . "<" . "/nowiki><". "p>"; }   if(count($stack)>0) return array_pop($stack); return ""; } catch (Exception $e) { return $e->getMessage; } } ?>
 * 1) The callback function for converting the input text to HTML output

Then simply add the following line to the end of your  file:

include("extensions/RpnCalc.php");

and you are ready to go! Go to the sandbox and see if it works!

Obs.: If you are using php4, comment the try and catch lines.

Usage
The following code describes the usage of this extension (which you are invited to extend (and improve!) via the very simple code design ;-)