Skip to content

Instantly share code, notes, and snippets.

@renskiy
Last active August 29, 2015 13:56
Show Gist options
  • Save renskiy/9293674 to your computer and use it in GitHub Desktop.
Save renskiy/9293674 to your computer and use it in GitHub Desktop.
Reverse Polish notation executor
<?php
function rpn($opn, $operators='+-/*') {
$stack = []; $operands = [];
foreach (explode(' ', trim($opn)) as $member) {
if ($member === '') continue;
if (strpos($operators, $member) !== false) {
if (count($operands) < 2) {
array_unshift($operands, array_pop($stack));
}
list($first, $second) = $operands;
$result = @eval("return $first $member $second;");
if ($result === false) {
throw new RuntimeException;
}
$operands = [$result];
} else {
if (! is_numeric($member)) {
throw new UnexpectedValueException;
}
$operands[] = $member;
If (count($operands) > 2) {
$stack[] = array_shift($operands);
}
}
}
if (count($operands) != 1 || count($stack) != 0) {
throw new UnderflowException;
}
return $operands[0];
}
<?php
require('rpn.php');
class RpnTest extends PHPUnit_Framework_TestCase {
/**
* @dataProvider provider_rpn
*/
public function test_rpn($rpn, $expected, $operators='+-/*') {
$actual = rpn($rpn, $operators);
$this->assertEquals($expected, $actual, "$rpn didn't match expected: $expected");
}
public static function provider_rpn() {
return [
['1', 1],
['2 1 <<', 4, '+-/*>><<'],
['1 2 +', 3],
[' 3 4 + ', 7],
['5 0 +', 5],
['5 8 3 + *', 55],
['3 4 2 * 1 5 - 2 * / +', 2],
];
}
/**
* @dataProvider provider_rpn_throws_exception_on_error
*/
public function test_rpn_throws_exception_on_error($rpn, $expected_exception, $operators='+-/*') {
$this->setExpectedException($expected_exception);
rpn($rpn, $operators);
}
public static function provider_rpn_throws_exception_on_error() {
return [
['+', 'RuntimeException', '+'],
['a', 'UnexpectedValueException', ''],
['1 b +', 'UnexpectedValueException'],
['1 2 a', 'RuntimeException', 'a'],
['1 2 a', 'RuntimeException', 'a'],
['1 2', 'UnderflowException'],
['1 2 3 +', 'UnderflowException'],
];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment