经过几天的努力,用PHP已经实现了一个完整的基础计算器,如下图

上代码

define('ISINTEGER','ISINTEGER');//定义整数类型描述

define('PLUS','PLUS');//定义操作符号类型描述 加法

define('MINUS','MINUS');//定义操作符号类型描述 减法

define('MUL','MUL');//定义操作符号类型描述 乘法

define('DIV','DIV');//定义操作符号类型描述 除法

define('LPAREN','LPAREN');//定义操作符号类型描述 (

define('RPAREN','RPAREN');//定义操作符号类型描述 )

define('WHITESPACE',' ');//定义空格

/**

Token 用来存储输入字符的类型

*/

class Token{

private $type;

private $value;

/**

$type ISINTEGER/PLUS/MINUS

$value 对应的字符串

*/

public function __construct($type,$value)

{

$this->type=$type;

$this->value=$value;

}

/**

通过该方法来获取类的私有属性

*/

public function __get($name)

{

return $this->{$name};

}

/**

用于调试

*/

public function __toString()

{

return 'type:'.$this->type.' value:'.$this->value;

}

}

class Lexer{

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,'-');

}

if ($this->current_char=="*"){

$this->advance();

return new Token(MUL,'*');

}

if ($this->current_char=="/"){

$this->advance();

return new Token(DIV,'/');

}

if ($this->current_char=="("){

$this->advance();

return new Token(LPAREN,'(');

}

if ($this->current_char==")"){

$this->advance();

return new Token(RPAREN,')');

}

return new Token('EOF', null);

}

}

}

//解释器

class Interpreter{

private $current_token ;

private $lexer ;

public function __construct($lexer){

//去除前后可能存在的空格 这些空格是无效的

$this->lexer=$lexer;

//初始化 获取第一个字符

$this->current_token=$this->lexer->get_next_token();

}

//如果字符类型和判断的类型一致,则继续,否则输入错误

public function eat($token_type)

{

if ($this->current_token->type==$token_type){

$this->current_token=$this->lexer->get_next_token();

}else{

$this->error();

}

}

public function error()

{

throw new \Exception('eroor');

}

public function factor()

{

$token=$this->current_token;

if ($token->type==ISINTEGER){

$this->eat(ISINTEGER);

return $token->value;

}else if ($token->type==LPAREN){

$this->eat(LPAREN);

$result = $this->expr();

$this->eat(RPAREN);

return $result;

}

}

public function term()

{

$result=$this->factor();

while(in_array($this->current_token->type,[MUL,DIV])){

$token=$this->current_token;

if ($token->type==MUL){

$this->eat(MUL);

$result=$result*$this->factor();

}

else if ($token->type==DIV){

$this->eat(DIV);

$result=$result/$this->factor();

}

}

return $result;

}

//解释方法

public function expr()

{

$result=$this->term();

while(in_array($this->current_token->type,[PLUS,MINUS])){

$token=$this->current_token;

if ($token->type==PLUS){

$this->eat(PLUS);

$result=$result+$this->term();

}

else if ($token->type==MINUS){

$this->eat(MINUS);

$result=$result-$this->term();

}

}

return $result;

}

}

do{

fwrite(STDOUT,'xav>');;

$input=fgets(STDIN);

$Interpreter=new Interpreter(new Lexer($input));

echo $Interpreter->expr();

unset($Interpreter);

}while(true);

有时间我得学习下如何把上述逻辑用插图描述,最是最后一篇文章,下次就真的应该是如何写个脚本语言了!

以上所有代码已上传GITHUB ,欢迎star 传送门

php 课程节次周次提取,用PHP写一个最简单的解释器Part5(计算器最后一节,下节开始如何写个脚本语言)...相关推荐

  1. 机电传动控制课程第一周学习笔记

    机电传动课程第一周学习笔记 本周的学习内容主要是第一章绪论和第二章机电传动系统的动力学基础,结合课程学习和预习复习回顾内容如下: 1.绪论:学习了机电传动控制目的与任务.发展历程和我们该如何学习这门课 ...

  2. 柿饼UI入门课程第一周作业

    入门课程第一周 基础 如何看帮助文档 API帮助 控件帮助 设计器使用帮助及反馈 举个例子 附加 目标 架构 范进中举 相册 其他 基础 只需要按照视频里面就可以做到90%.但是,dotIndicat ...

  3. 操作系统课程设计——Shell编程(用c编写一个Linux的外壳Shell)

    文章目录 前言 功能与展示 功能列表 功能展示 依赖库安装 具体实现 Shell工作流程 外部命令工作流程 内置命令工作流程 管道功能与I/O重定向的实现 alias功能的一些思考 Shell的编译与 ...

  4. 亚马逊:我们提取了BERT的一个最优子架构,只有Bert-large的16%,CPU推理速度提升7倍...

    选自arXiv 作者:Adrian de Wynter.Daniel J. Perry 机器之心编译 机器之心编辑部 提取 BERT 子架构是一个非常值得探讨的问题,但现有的研究在子架构准确率和选择方 ...

  5. 腾讯京东要建“反阿里联盟”?Python 或成 Excel 官方脚本语言;百度华为在一起 | 一周业界事

    点击上方"CSDN",选择"置顶公众号" 关键时刻,第一时间送达! 回顾刚刚过去的一周,百度刚与华为达成深度合作,李彦宏与余承东还相互交换了"信物&q ...

  6. EDA实验课课程笔记(四)——TCL脚本语言的学习2

    EDA实验课课程笔记(四)--TCL脚本语言的学习2 控制流 if 循环命令 while for foreach break和continue命令 switch source 过程(procedure ...

  7. EDA实验课课程笔记(三)——TCL脚本语言的学习1

    本文参考资料为<Tcl语言教程>,感谢作者的分享,这里仅仅作为简单常用语法的入门,若有需要后期对本文进行添加补充. EDA实验课课程笔记(三)--TCL脚本语言的学习 前言(TCL综述) ...

  8. 如何拆分PDF文件或提取PDF页面为一个单独文件?

    如何拆分PDF文件或提取PDF页面为一个单独文件?无论是工作还是生活中,我们都经常接触PDF文件,PDF格式文件在阅读体验感上无疑是极佳的,但如果一个PDF文件内容过大,页数过长,每次打开PDF文档速 ...

  9. 用JAVA写一个画图程序(课程设计)

    1.设计思路 首先我直接去了Windows自带画图程序去实践模拟,看看具体方法,进行了布局和按钮的思考. 容器顶层放工具栏,工具栏中存放图形按钮.工具按钮.颜色按钮.对于图形按钮,存放在垂直的Box中 ...

最新文章

  1. MyEclipse6.0注册码算法代码,MyEclipse7.0注册码算法代码
  2. 零开始学python_从零开始学Python
  3. Linux 常用命令笔记
  4. Python print函数不换行操作
  5. [WC 2011]Xor
  6. windows终止处理程序( __try __finally) 简单解析
  7. 方法的重载与重写_我们不一样,不一样,重写与重载
  8. JMeter压力测试高并发测试
  9. 回顾RHCE——邮件收发实验
  10. win7自带桌面便签
  11. Unity爆炸、闪电、火焰、雷雨特效Demo
  12. LabVIEW编程LabVIEW控制Keithley 2400例程与相关资料
  13. C++游戏《Flappy bird》
  14. IP地址转换函数 inet_pton、inet_ntop与 inet_aton、inet_addr、 inet_ntoa
  15. 黎想首谈14大权威新媒体推广平台,教你一招搭建信息流矩阵!
  16. LT8522EX 是 Lontium 的矩阵开关芯片基于两路输入,输出 (VGA 和 HDMI)
  17. Spark-SparkSession.Builder 源码解析
  18. 手外骨骼研究进展综述
  19. doraemon的python 池
  20. MAPSTRUCT(@Mapper用法)

热门文章

  1. Pyotorch自定义损失函数
  2. 大数据可视化平台的价值有哪些
  3. 以数制转换问题讲解栈数据结构的基本概念及其在计算机中的应用
  4. AcWing 836. 合并集合
  5. 查看linux环境下cudnn是否安装,Linux下安装cuda和对应版本的cudnn
  6. import java.io用什么写_问问各位大佬,使用了fiilewrite,为什么写入不到文件
  7. R语言实现︱局部敏感哈希算法(LSH)解决文本机械相似性的问题(一,基本原理)
  8. 极限学习机︱R语言快速深度学习进行回归预测
  9. CSS进阶(4)—— 温和padding中的诡异CSS现象
  10. 自行车中的物理知识汇总