Created
June 12, 2012 08:47
-
-
Save jelmervdl/2916265 to your computer and use it in GitHub Desktop.
Interpreter in PHP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
error_reporting(E_ALL); | |
ini_set('display_errors', true); | |
class Scope | |
{ | |
public $variables; | |
public $functions; | |
public function __construct() | |
{ | |
$this->variables = array(); | |
$this->functions = array(); | |
} | |
public function extend(array $variables) | |
{ | |
$new_scope = clone $this; | |
$new_scope->variables = array_merge($this->variables, $variables); | |
return $new_scope; | |
} | |
} | |
abstract class Expression | |
{ | |
abstract public function evaluate(Scope $scope); | |
} | |
abstract class BinaryExpression extends Expression | |
{ | |
protected $left; | |
protected $right; | |
public function __construct(Expression $left, Expression $right) | |
{ | |
$this->left = $left; | |
$this->right = $right; | |
} | |
} | |
class AdditionExpression extends BinaryExpression | |
{ | |
public function evaluate(Scope $scope) | |
{ | |
return $this->left->evaluate($scope) + $this->right->evaluate($scope); | |
} | |
} | |
class MultiplyExpression extends BinaryExpression | |
{ | |
public function evaluate(Scope $scope) | |
{ | |
return $this->left->evaluate($scope) * $this->right->evaluate($scope); | |
} | |
} | |
class NumberExpression extends Expression | |
{ | |
private $value; | |
public function __construct($value) | |
{ | |
$this->value = $value; | |
} | |
public function evaluate(Scope $scope) | |
{ | |
return $this->value; | |
} | |
} | |
class VariableExpression extends Expression | |
{ | |
private $name; | |
public function __construct($name) | |
{ | |
$this->name = $name; | |
} | |
public function evaluate(Scope $scope) | |
{ | |
return $scope->variables[$this->name]; | |
} | |
} | |
class FunctionDefinition | |
{ | |
private $body; | |
public function __construct(array $arguments, Expression $body) | |
{ | |
$this->body = $body; | |
$this->arguments = $arguments; | |
} | |
public function call(Scope $scope, array $arguments) | |
{ | |
$variables = array_combine($this->arguments, $arguments); | |
$function_scope = $scope->extend($variables); | |
return $this->body->evaluate($function_scope); | |
} | |
} | |
class FunctionCallExpression extends Expression | |
{ | |
private $name; | |
private $arguments; | |
public function __construct($name, array $arguments) | |
{ | |
$this->name = $name; | |
$this->arguments = $arguments; | |
} | |
public function evaluate(Scope $scope) | |
{ | |
$arguments = array(); | |
foreach ($this->arguments as $argument) | |
$arguments[] = $argument->evaluate($scope); | |
return $scope->functions[$this->name]->call($scope, $arguments); | |
} | |
} | |
class TestExpression extends Expression | |
{ | |
private $test; | |
private $case_true; | |
private $case_false; | |
public function __construct(Expression $test, Expression $case_true, Expression $case_false) | |
{ | |
$this->test = $test; | |
$this->case_true = $case_true; | |
$this->case_false = $case_false; | |
} | |
public function evaluate(Scope $scope) | |
{ | |
$answer = $this->test->evaluate($scope); | |
return $answer | |
? $this->case_true->evaluate($scope) | |
: $this->case_false->evaluate($scope); | |
} | |
} | |
class EqualsExpression extends BinaryExpression | |
{ | |
public function evaluate(Scope $scope) | |
{ | |
return $this->left->evaluate($scope) == $this->right->evaluate($scope); | |
} | |
} | |
class GreaterThanExpression extends BinaryExpression | |
{ | |
public function evaluate(Scope $scope) | |
{ | |
return $this->left->evaluate($scope) > $this->right->evaluate($scope); | |
} | |
} | |
// if n == 0 then 1 else n * fac (n - 1) | |
// sum (n) = n > 0 ? n + sum (n - 1) : 0 | |
function test() | |
{ | |
$scope = new Scope(); | |
$scope->variables['a'] = 24; | |
$sum = new FunctionDefinition( | |
array('n'), | |
new TestExpression( | |
new GreaterThanExpression( | |
new VariableExpression('n'), | |
new NumberExpression(1) | |
), | |
new AdditionExpression( | |
new VariableExpression('n'), | |
new FunctionCallExpression('sum', | |
array(new AdditionExpression( | |
new VariableExpression('n'), | |
new NumberExpression(-1) | |
)) | |
) | |
), | |
new NumberExpression(0) | |
) | |
); | |
$fac = new FunctionDefinition( | |
array('n'), | |
new TestExpression( | |
// test | |
new EqualsExpression( | |
new VariableExpression('n'), | |
new NumberExpression(0) | |
), | |
// if true | |
new NumberExpression(1), | |
// else | |
new MultiplyExpression( | |
new VariableExpression('n'), | |
new FunctionCallExpression('fac', | |
array(new AdditionExpression( | |
new VariableExpression('n'), | |
new NumberExpression(-1) | |
))) | |
) | |
)); | |
$add = new FunctionDefinition( | |
array('b'), | |
new AdditionExpression( | |
new VariableExpression('a'), | |
new VariableExpression('b') | |
)); | |
$scope->functions['fac'] = $fac; | |
$scope->functions['sum'] = $sum; | |
$scope->functions['add'] = $add; | |
// $expr = new FunctionCallExpression('sum', array(new NumberExpression(3))); | |
// $expr = new FunctionCallExpression('fac', array(new NumberExpression(10))); | |
$expr = new FunctionCallExpression('add', array(new NumberExpression(2))); | |
echo $expr->evaluate($scope) . "\n"; | |
var_dump($scope->variables); | |
} | |
test(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment