以前寫過一個計算器,採用JS實現的,不過當時沒有想到的好的辦法,最終採用了JS的eval函數來實現字符串的解析和運算。php
這並非的好的方法,若是實現的計算器比較複雜,最終會發現程序十分臃腫.git
接下來部分,在重構https://github.com/rspivak/ls... 的同時,並實現一個完整計算器的解釋器github
Part2代碼實現功能函數
<?php define('ISINTEGER','ISINTEGER');//定義整數類型描述 define('PLUS','PLUS');//定義操做符號類型描述 加法 define('MINUS','MINUS');//定義操做符號類型描述 減法 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 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);