好吧!我認可我想標題黨了。你們對解釋器的吸引,絕對沒有本身動手寫一個腳本語言更有吸引力。不過若是看到標題過來的,可能也是php
我認可,以前收藏的減肥視頻,我都是這樣對待他們的。編程
不過我仍是相信不少程序猿or程序媛不單單但願能夠作出一個牛逼的產品,更想作出來一個牛逼閃閃的編程語言。而這裏就是朝着開發一個腳本語言的方向去努力編程語言
恩!我就是xxoo語言之父。函數
前幾篇文章已經實現一個簡易的加減法計算器,想必看了文章以後能夠很快的寫出來一個乘除法計算器。那麼若是加減乘除混合運算呢?學習
這節將實現相似6-1*2+4/2這樣的運算方式,你們看到這個式子以後應該已經瞭解難點在哪裏了。好了下面開始,首先展現完整的代碼。this
<?php define('ISINTEGER','ISINTEGER');//定義整數類型描述 define('PLUS','PLUS');//定義操做符號類型描述 加法 define('MINUS','MINUS');//定義操做符號類型描述 減法 define('MUL','MUL');//定義操做符號類型描述 乘法 define('DIV','DIV');//定義操做符號類型描述 除法 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,'/'); } 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; $this->eat(ISINTEGER); return $token->value; } 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);
看過前面幾篇文章的已經瞭解過,這裏的代碼結構發生了變化。spa
首先,分離出來詞法分析類,該類的做用:將字符串進行相似分詞處理,並將每一個詞的含義返回調試
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,'/'); } return new Token('EOF', null); } } }
其實四則運算最爲複雜的部分就是若是解決先乘除後加減。這裏將其分紅了兩個部分。term函數就是在進行乘除法部分,expr則進行加法code
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; }
圖很醜,不過仍是但願你能夠看懂,也就是4-2*3-1 ,expr中乘除都是一個總體,其會被在term中進行運算返回,這樣這個式子就分紅了,4-積-1.而積是在term中進行運算的。視頻
文中不少描述存在不少不當,我也在積極的學習如何將知識講的通俗易懂。若是您有好的辦法,能夠一同探討