Skip to content

Instantly share code, notes, and snippets.

@theking2
Last active March 27, 2025 17:32
Show Gist options
  • Save theking2/0f3184ba8f4a9fd604d8e9cfeb64fbc9 to your computer and use it in GitHub Desktop.
Save theking2/0f3184ba8f4a9fd604d8e9cfeb64fbc9 to your computer and use it in GitHub Desktop.
Polish notation
<?php
/**
* Polish notation
* @param $expression - Space seperated operators and param indices
* @param $param - two or more params for the calculation
*/
function pn(string $expression, mixed ...$param) {
$operators = "+-*/%"; $delimiter = " ";
$expression = explode($delimiter, $expression);
$stack = [];
do {
$itm=array_pop($expression);
if( !strstr($operators, $itm) ) { // treat everything not an operator as operand
if( !ctype_digit( $itm ) ) {
throw new \InvalidArgumentException( "Operand index not integer: $itm\n" );
}
if(! (0 <= $itm and $itm < count( $param )) ) {
throw new \OutOfBoundsException ( "Operand index out of range: $itm\n" );
}
if( !is_numeric( $param[$itm] ) ) {
throw new \InvalidArgumentException( "Operand not numeric: $param[$itm]\n" );
}
array_push($stack, $param[$itm]);
continue;
}
// we have an operator
switch($itm) {
case '+': array_push( $stack, array_pop($stack) + array_pop($stack) ); break;
case '-': array_push( $stack, array_pop($stack) - array_pop($stack) ); break;
case '*': array_push( $stack, array_pop($stack) * array_pop($stack) ); break;
case '/': array_push( $stack, array_pop($stack) / array_pop($stack) ); break;
case '%': array_push( $stack, array_pop($stack) % array_pop($stack) ); break;
//default: throw new \InvalidArgumentException( "Unknown operator $itm" );
}
} while ($expression);
return array_pop($stack);
}
// Parameters are indexed from 0 upwards
try{
echo pn("/ + 3 0 / 2 1", 30, 40, 50, 69), "\n";
} catch( Exception $e) {echo $e->getMessage();}
try{
echo pn("/ + 3 0 / 2 1", 30, 40, 50), "\n";
} catch( Exception $e) {echo $e->getMessage();}
try{
echo pn("/ + 3 3 / 2 1.1", 30, 40, 50, "a"), "\n";
} catch( Exception $e) {echo $e->getMessage();}
try{
echo pn("/ + 3 3 / 2 1", 30, 40, 50, "a"), "\n";
} catch( Exception $e) {echo $e->getMessage();}
// If parameters are in an array already use unpacking
$operants = [3, 4, 5, 6];
$expresion = "/ + 0 1 / 2 3";
echo pn($expresion, ...$operants), "\n";
@theking2
Copy link
Author

theking2 commented Mar 25, 2025

for a rpn remove the array_reverse()

for a rpn use array_shift() in line 13

or use a foreach($expression as $itm);

@theking2
Copy link
Author

theking2 commented Mar 25, 2025

FSR
Make this into a class to

  1. be able to (not) reverse
  2. be able to specify a delimiter other than ' '
  3. checking of a parameters and better exception handling.
  4. custom operators (add swap, dup(icate), drop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment