jase:
What if someone tries to put in a calculation of "10+hjfd-2" or "2+*4". Worse is "10/0", or even "echo y|format c:".
Just use what MediaWiki already has and the latter can't happen. The MediaWiki #expr parser is basically a big set of PHP defines
https://git.wikimedia.org/blob...c3bf32830ca/Expr.php If the calculation is gibberish, like 10+hjfd-2 then you'll get gibberish back (or an error, probably you'll get an error).
echo y|format c: isn't a defined PHP command in the MediaWiki file -- it doesn't have one of the magic words in it and as such is just treated like a string. You'll get back what you put in (unless you check for is_numeric and then you'll either get nothing or whatever error message you have checking for that).
For instance:
/ Character classes
define( 'EXPR_WHITE_CLASS', " \t\r\n" );
define( 'EXPR_NUMBER_CLASS', '0123456789.' );
// Token types
define( 'EXPR_WHITE', 1 );
define( 'EXPR_NUMBER', 2 );
define( 'EXPR_NEGATIVE', 3 );
define( 'EXPR_POSITIVE', 4 );
define( 'EXPR_PLUS', 5 );
define( 'EXPR_MINUS', 6 );
define( 'EXPR_TIMES', 7 );
define( 'EXPR_DIVIDE', 8 );
define( 'EXPR_MOD', 9 );
define( 'EXPR_OPEN', 10 );
define( 'EXPR_CLOSE', 11 );
Skipping a bunch...
/**
* Evaluate a mathematical expression
*
* The algorithm here is based on the infix to RPN algorithm given in
* http://montcs.bloomu.edu/~bobmon/Information/RPN/infix2rpn.shtml
* It's essentially the same as Dijkstra's shunting yard algorithm.
* @param $expr string
* @throws ExprError
* @return string
*/
function doExpression( $expr ) {
$operands = array();
$operators = array();
# Unescape inequality operators
$expr = strtr( $expr, array( '<' => '<', '>' => '>',
'−' => '-', '−' => '-' ) );
$p = 0;
$end = strlen( $expr );
$expecting = 'expression';
$name = '';
while ( $p < $end ) {
if ( count( $operands ) > $this->maxStackSize || count( $operators ) > $this->maxStackSize ) {
throw new ExprError( 'stack_exhausted' );
}
$char = $expr[$p];
$char2 = substr( $expr, $p, 2 );
// Mega if-elseif-else construct
// Only binary operators fall through for processing at the bottom, the rest
// finish their processing and continue
// First the unlimited length classes
if ( false !== strpos( EXPR_WHITE_CLASS, $char ) ) {
// Whitespace
$p += strspn( $expr, EXPR_WHITE_CLASS, $p );
continue;
} elseif ( false !== strpos( EXPR_NUMBER_CLASS, $char ) ) {
// Number
if ( $expecting != 'expression' ) {
throw new ExprError( 'unexpected_number' );
}
// Find the rest of it
$length = strspn( $expr, EXPR_NUMBER_CLASS, $p );
// Convert it to float, silently removing double decimal points
$operands[] = floatval( substr( $expr, $p, $length ) );
$p += $length;
$expecting = 'operator';
continue;
} elseif ( ctype_alpha( $char ) ) {
// Word
// Find the rest of it
$remaining = substr( $expr, $p );
if ( !preg_match( '/^[A-Za-z]*/', $remaining, $matches ) ) {
// This should be unreachable
throw new ExprError( 'preg_match_failure' );
}
$word = strtolower( $matches[0] );
$p += strlen( $word );
// Interpret the word
if ( !isset( $this->words[$word] ) ) {
throw new ExprError( 'unrecognised_word', $word );
}
$op = $this->words[$word];
switch( $op ) {
// constant
case EXPR_EXPONENT:
if ( $expecting != 'expression' ) {
continue;
}
$operands[] = exp( 1 );
$expecting = 'operator';
continue 2;
case EXPR_PI:
if ( $expecting != 'expression' ) {
throw new ExprError( 'unexpected_number' );
}
$operands[] = pi();
$expecting = 'operator';
continue 2;
// Unary operator
case EXPR_NOT:
case EXPR_SINE:
case EXPR_COSINE:
case EXPR_TANGENS:
case EXPR_ARCSINE:
case EXPR_ARCCOS:
case EXPR_ARCTAN:
case EXPR_EXP:
case EXPR_LN:
case EXPR_ABS:
case EXPR_FLOOR:
case EXPR_TRUNC:
case EXPR_CEIL:
case EXPR_SQRT:
if ( $expecting != 'expression' ) {
throw new ExprError( 'unexpected_operator', $word );
}
$operators[] = $op;
continue 2;
}
// Binary operator, fall through
$name = $word;
}
// Next the two-character operators
elseif ( $char2 == '<=' ) {
And the code continues from there.
Now, I have no idea how RPoL is coded, other than that a large part of it is PHP. That being said, this PHP document would seem to really do the trick, and it's licensed under the GPLv2 (see
https://www.mediawiki.org/wiki...sion:ParserFunctions ) which means that if you add/modify the RPoL code with this code you wouldn't have to make the RPoL code public.
Edit: And of course the wiki runs on... whatever it is that it runs on, but you could put the GPLv2 code in there without making the rest of the wiki code public. I got sidetracked and started thinking of this code applying to all of RPoL instead of just a wiki for a game.
This message was last edited by the user at 05:35, Mon 18 Aug 2014.