资讯专栏INFORMATION COLUMN

用PHP写一个最简单的解释器Part2

sixleaves / 1878人阅读

摘要:之前写过一个计算器,采用实现的,不过当时没有想到的好的办法,最终采用了的函数来实现字符串的解析和运算。

之前写过一个计算器,采用JS实现的,不过当时没有想到的好的办法,最终采用了JS的eval函数来实现字符串的解析和运算。

这并不是的好的方法,如果实现的计算器比较复杂,最终会发现程序十分臃肿.

接下来部分,在重构https://github.com/rspivak/ls... 的同时,并实现一个完整计算器的解释器

Part2代码实现功能

加法运算

减法运算

去除空格

多位数运算

</>复制代码

  1. type=$type;
  2. $this->value=$value;
  3. }
  4. /**
  5. 通过该方法来获取类的私有属性
  6. */
  7. public function __get($name)
  8. {
  9. return $this->{$name};
  10. }
  11. /**
  12. 用于调试
  13. */
  14. public function __toString()
  15. {
  16. return "type:".$this->type." value:".$this->value;
  17. }
  18. }
  19. //解释器
  20. class Interpreter{
  21. private $current_char ;
  22. private $current_token ;
  23. private $text;
  24. private $pos=0;
  25. /***
  26. $text 需要进行解释的字符串
  27. */
  28. public function __construct($text){
  29. //去除前后可能存在的空格 这些空格是无效的
  30. $this->text=trim($text);
  31. //初始化 获取第一个字符
  32. $this->current_char = $this->text[$this->pos];
  33. }
  34. public function error()
  35. {
  36. throw new Exception("Lexer eroor");
  37. }
  38. /*
  39. 步进方法,每操作一个字符后前进一位
  40. */
  41. public function advance()
  42. {
  43. $this->pos++;
  44. if ($this->pos>strlen($this->text)-1){
  45. $this->current_char=null;
  46. }else{
  47. $this->current_char=$this->text[$this->pos];
  48. }
  49. }
  50. /*
  51. 去除空格
  52. */
  53. public function skip_whitespace()
  54. {
  55. if ($this->current_char!=null&&$this->current_char==WHITESPACE){
  56. $this->advance();
  57. }
  58. }
  59. /*
  60. 如果要支持多位的整数,则需要将每位数字存储起来
  61. */
  62. public function integers()
  63. {
  64. $result="";//用于存储数字
  65. while($this->current_char!=null&&is_numeric($this->current_char)){//只要当前字符是数字就一直循环并将数字存储于$result
  66. $result.=$this->current_char;
  67. $this->advance();//步进方法,每操作一个字符后前进一位
  68. }
  69. return intval($result);//将数字字符串转成整数
  70. }
  71. //获取当前字符的Token
  72. public function get_next_token()
  73. {
  74. while($this->current_char!=null){
  75. if ($this->current_char==WHITESPACE){
  76. $this->skip_whitespace();
  77. continue;
  78. }
  79. if (is_numeric($this->current_char)){
  80. return new Token(ISINTEGER,$this->integers());
  81. }
  82. if ($this->current_char=="+"){
  83. $this->advance();
  84. return new Token(PLUS,"+");
  85. }
  86. if ($this->current_char=="-"){
  87. $this->advance();
  88. return new Token(MINUS,"-");
  89. }
  90. return new Token("EOF", null);
  91. }
  92. }
  93. //如果字符类型和判断的类型一致,则继续,否则输入错误
  94. public function eat($token_type)
  95. {
  96. if ($this->current_token->type==$token_type){
  97. $this->current_token=$this->get_next_token();
  98. }else{
  99. $this->error();
  100. }
  101. }
  102. //解释方法
  103. public function expr()
  104. {
  105. $this->current_token=$this->get_next_token();//获取字符串开头部分的数字
  106. $left=$this->current_token;
  107. $this->eat(ISINTEGER);//判断取得的前半部分字符串是整数不是
  108. $op=$this->current_token;//获取前半部分后紧接的字符 并判断是何种操作符
  109. if ($op->type==PLUS)
  110. $this->eat(PLUS);
  111. else
  112. $this->eat(MINUS);
  113. $right=$this->current_token;//获取最后部分 并判断是否是整数
  114. $this->eat(ISINTEGER);
  115. if ($op->type==PLUS)
  116. $result=$left->value+$right->value;
  117. else
  118. $result=$left->value-$right->value;
  119. return $result;
  120. }
  121. }
  122. do{
  123. fwrite(STDOUT,"xav>");;
  124. $input=fgets(STDIN);
  125. $Interpreter=new Interpreter($input);
  126. echo $Interpreter->expr();
  127. unset($Interpreter);
  128. }while(true);

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29001.html

相关文章

  • 测试你前端代码 - part2(单元测试)

    摘要:单元测试上一节有讨论过,单元测试就是以代码单元为单位进行测试,代码单元可以是一个函数,一个模块,或者一个类。单元测试是最容易理解也最容易实现的测试方式。在写单元测试的时候,尽量将你的单元测试独立出来,不要几个单元互相引用。 showImg(https://segmentfault.com/img/remote/1460000008823416?w=997&h=350); 本文作者:G...

    daydream 评论0 收藏0
  • 测试你前端代码 - part2(单元测试)

    摘要:单元测试上一节有讨论过,单元测试就是以代码单元为单位进行测试,代码单元可以是一个函数,一个模块,或者一个类。单元测试是最容易理解也最容易实现的测试方式。在写单元测试的时候,尽量将你的单元测试独立出来,不要几个单元互相引用。 showImg(https://segmentfault.com/img/remote/1460000008823416?w=997&h=350); 本文作者:G...

    shadajin 评论0 收藏0
  • 《JavaScript设计模式》阅读笔记_part2

    摘要:它属于类创建型模式。基于继承,将复杂的放置在函数中,简单的共同的放置到一个构造函数中。代码与继承类似,但是核心就是将简单的共有的放置到构造函数中,与类的思想类似。单例模式实现代码库,产生命名空间,一次只能实例化一个。 JavaScript设计模式阅读 更多文章查看本专栏 设计模式第一篇:创建型设计模式 1、简单工厂模式 简单工厂模式:又叫静态工厂方法,有一个工厂对象决定创建某一种产品...

    RobinTang 评论0 收藏0
  • Part 2: Containers

    摘要:在默认情况下使用的公共注册表。注意我们将在这里使用的公共注册表,因为它是免费和预配置的,但是有许多公共注册中心可供选择,而且您甚至可以使用可信注册表建立您自己的私有注册表。标记镜像将本地映像与注册表中的存储库关联的符号是。 要求 安装了1.13或者更高版本的Docker 阅读了Part1中的定位(我没写) 介绍 是时候用Docker构建一个app了。我们会从构建这样一个app的最底...

    Soarkey 评论0 收藏0
  • require.js 简洁入门

    摘要:另外一个道理,一部分是依赖另一部分的,比如依赖文件的载入。其实主要做的事情就是这两点。这里只是我虚构一个假的例子,实际应用中要根据自己的实际需求去设计构思自己的项目,再次提醒,不要为了用而用。 前言 提到require.js大多数人会说提到模块化开发,AMD等等,其实require.js并没有这么多复杂的概念,这里我就希望排除这些概念,从实用的角度来简单说一下require.js是干...

    andot 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<