用php写一个最简单的解释器part4(写一个最简单的脚本语言)
在前几篇文章中,我们已经介绍了如何用PHP来写一个最简单的解释器,可以解释加、减、乘、除四种运算。在本篇文章中,我们将会进一步发挥这个解释器,给它加上支持变量和输出的能力,从而写出一个最简单的脚本语言。
语法规则
我们的脚本语言支持如下几个语法规则:
-
变量赋值:使用 "=" 符号给一个变量赋值
-
输出语句:使用 "print" 命令输出字符串
实现
在原来的 Interpreter 类的基础上,我们需要添加对变量赋值和输出语句的解释能力。具体实现如下:
class Interpreter {
private $tokens;
private $position = 0;
private $currentToken;
public function __construct($input) {
$this->tokens = preg_split('/\s+/', $input);
$this->getNextToken();
}
private function getNextToken() {
if ($this->position < count($this->tokens)) {
$this->currentToken = $this->tokens[$this->position];
$this->position++;
} else {
$this->currentToken = null;
}
}
private function eat($token) {
if ($this->currentToken == $token) {
$this->getNextToken();
} else {
throw new Exception("Error: expected token '$token'");
}
}
public function parse() {
$result = $this->expr();
if ($this->currentToken != null) {
throw new Exception("Error: unexpected token '{$this->currentToken}'");
}
return $result;
}
private function expr() {
$result = $this->term();
while(in_array($this->currentToken, array('+', '-'))) {
$operator = $this->currentToken;
$this->eat($operator);
$term = $this->term();
if ($operator == '+') {
$result += $term;
} else {
$result -= $term;
}
}
return $result;
}
private function term() {
$result = $this->factor();
while(in_array($this->currentToken, array('*', '/'))) {
$operator = $this->currentToken;
$this->eat($operator);
$factor = $this->factor();
if ($operator == '*') {
$result *= $factor;
} else {
$result /= $factor;
}
}
return $result;
}
private function factor() {
if ($this->currentToken == '(') {
$this->eat('(');
$result = $this->expr();
$this->eat(')');
return $result;
} else if (is_numeric($this->currentToken)) {
$result = $this->currentToken;
$this->eat($this->currentToken);
return $result;
} else {
throw new Exception("Error: unexpected token '{$this->currentToken}'");
}
}
}
$input = "x = 1 + 2\nprint x";
$interpreter = new Interpreter($input);
$variables = array();
while($interpreter->currentToken != null) {
if ($interpreter->currentToken == 'print') {
$interpreter->eat('print');
echo $interpreter->parse() . "\n";
} else {
$name = $interpreter->currentToken;
$interpreter->eat($name);
$interpreter->eat('=');
$variables[$name] = $interpreter->parse();
}
}
在上述代码中,我们首先定义了一个数组 $variables
来保存变量和它们的值,然后将原先的 parse
方法拆分成两个方法: expr
和 factor
。在 expr
方法中,我们增加了对加减运算和乘除运算的支持,从而能够解释更复杂的表达式。在 factor
方法中,我们增加了对变量的支持。如果当前的 token 是一个数字,那么我们会把它作为 factor 的返回值;如果当前的 token 是一个变量名,那么我们会从 $variables
数组中查找它对应的值,并将它作为 factor 的返回值。
在 while($interpreter->currentToken != null)
循环中,我们通过判断当前的 token 是 "print" 还是一个变量名,来决定接下来要执行的操作。如果当前的 token 为 "print",那么我们会输出调用 parse
方法的返回值;如果当前的 token 是一个变量名,那么我们会在 $variables
数组中保存它和它的值。
测试
我们将下面的脚本保存到一个文件中(例如 test.script
):
x = 1 + 2
print x
然后执行下面的命令:
php -f test.script
输出将会是:
3
从输出结果中我们可以看到,解释器成功地解释了我们写的脚本语言,将变量 x
的值计算出来并输出了出来。当然,这只是最简单的脚本语言的实现,我们可以通过不断地增加新的语法规则和功能,来发挥它更加强大的潜力。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:用php写一个最简单的解释器part4(写一个最简单的脚本语言) - Python技术站