摘要:之前写过一个计算器,采用实现的,不过当时没有想到的好的办法,最终采用了的函数来实现字符串的解析和运算。
之前写过一个计算器,采用JS实现的,不过当时没有想到的好的办法,最终采用了JS的eval函数来实现字符串的解析和运算。
这并不是的好的方法,如果实现的计算器比较复杂,最终会发现程序十分臃肿.
接下来部分,在重构https://github.com/rspivak/ls... 的同时,并实现一个完整计算器的解释器
Part2代码实现功能
加法运算
减法运算
去除空格
多位数运算
</>复制代码
type=$type;
$this->value=$value;
}
/**
通过该方法来获取类的私有属性
*/
public function __get($name)
{
return $this->{$name};
}
/**
用于调试
*/
public function __toString()
{
return "type:".$this->type." value:".$this->value;
}
}
//解释器
class Interpreter{
private $current_char ;
private $current_token ;
private $text;
private $pos=0;
/***
$text 需要进行解释的字符串
*/
public function __construct($text){
//去除前后可能存在的空格 这些空格是无效的
$this->text=trim($text);
//初始化 获取第一个字符
$this->current_char = $this->text[$this->pos];
}
public function error()
{
throw new Exception("Lexer eroor");
}
/*
步进方法,每操作一个字符后前进一位
*/
public function advance()
{
$this->pos++;
if ($this->pos>strlen($this->text)-1){
$this->current_char=null;
}else{
$this->current_char=$this->text[$this->pos];
}
}
/*
去除空格
*/
public function skip_whitespace()
{
if ($this->current_char!=null&&$this->current_char==WHITESPACE){
$this->advance();
}
}
/*
如果要支持多位的整数,则需要将每位数字存储起来
*/
public function integers()
{
$result="";//用于存储数字
while($this->current_char!=null&&is_numeric($this->current_char)){//只要当前字符是数字就一直循环并将数字存储于$result
$result.=$this->current_char;
$this->advance();//步进方法,每操作一个字符后前进一位
}
return intval($result);//将数字字符串转成整数
}
//获取当前字符的Token
public function get_next_token()
{
while($this->current_char!=null){
if ($this->current_char==WHITESPACE){
$this->skip_whitespace();
continue;
}
if (is_numeric($this->current_char)){
return new Token(ISINTEGER,$this->integers());
}
if ($this->current_char=="+"){
$this->advance();
return new Token(PLUS,"+");
}
if ($this->current_char=="-"){
$this->advance();
return new Token(MINUS,"-");
}
return new Token("EOF", null);
}
}
//如果字符类型和判断的类型一致,则继续,否则输入错误
public function eat($token_type)
{
if ($this->current_token->type==$token_type){
$this->current_token=$this->get_next_token();
}else{
$this->error();
}
}
//解释方法
public function expr()
{
$this->current_token=$this->get_next_token();//获取字符串开头部分的数字
$left=$this->current_token;
$this->eat(ISINTEGER);//判断取得的前半部分字符串是整数不是
$op=$this->current_token;//获取前半部分后紧接的字符 并判断是何种操作符
if ($op->type==PLUS)
$this->eat(PLUS);
else
$this->eat(MINUS);
$right=$this->current_token;//获取最后部分 并判断是否是整数
$this->eat(ISINTEGER);
if ($op->type==PLUS)
$result=$left->value+$right->value;
else
$result=$left->value-$right->value;
return $result;
}
}
do{
fwrite(STDOUT,"xav>");;
$input=fgets(STDIN);
$Interpreter=new Interpreter($input);
echo $Interpreter->expr();
unset($Interpreter);
}while(true);
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/29001.html
摘要:单元测试上一节有讨论过,单元测试就是以代码单元为单位进行测试,代码单元可以是一个函数,一个模块,或者一个类。单元测试是最容易理解也最容易实现的测试方式。在写单元测试的时候,尽量将你的单元测试独立出来,不要几个单元互相引用。 showImg(https://segmentfault.com/img/remote/1460000008823416?w=997&h=350); 本文作者:G...
摘要:单元测试上一节有讨论过,单元测试就是以代码单元为单位进行测试,代码单元可以是一个函数,一个模块,或者一个类。单元测试是最容易理解也最容易实现的测试方式。在写单元测试的时候,尽量将你的单元测试独立出来,不要几个单元互相引用。 showImg(https://segmentfault.com/img/remote/1460000008823416?w=997&h=350); 本文作者:G...
摘要:它属于类创建型模式。基于继承,将复杂的放置在函数中,简单的共同的放置到一个构造函数中。代码与继承类似,但是核心就是将简单的共有的放置到构造函数中,与类的思想类似。单例模式实现代码库,产生命名空间,一次只能实例化一个。 JavaScript设计模式阅读 更多文章查看本专栏 设计模式第一篇:创建型设计模式 1、简单工厂模式 简单工厂模式:又叫静态工厂方法,有一个工厂对象决定创建某一种产品...
摘要:在默认情况下使用的公共注册表。注意我们将在这里使用的公共注册表,因为它是免费和预配置的,但是有许多公共注册中心可供选择,而且您甚至可以使用可信注册表建立您自己的私有注册表。标记镜像将本地映像与注册表中的存储库关联的符号是。 要求 安装了1.13或者更高版本的Docker 阅读了Part1中的定位(我没写) 介绍 是时候用Docker构建一个app了。我们会从构建这样一个app的最底...
摘要:另外一个道理,一部分是依赖另一部分的,比如依赖文件的载入。其实主要做的事情就是这两点。这里只是我虚构一个假的例子,实际应用中要根据自己的实际需求去设计构思自己的项目,再次提醒,不要为了用而用。 前言 提到require.js大多数人会说提到模块化开发,AMD等等,其实require.js并没有这么多复杂的概念,这里我就希望排除这些概念,从实用的角度来简单说一下require.js是干...
阅读 2877·2021-11-23 09:51
阅读 3381·2021-11-22 14:44
阅读 4946·2021-11-22 09:34
阅读 5510·2021-10-08 10:14
阅读 2891·2021-09-22 15:47
阅读 3661·2021-09-22 15:40
阅读 1644·2019-08-30 15:44
阅读 1753·2019-08-28 18:23