摘要:大家對解釋器的吸引,絕對沒有自己動手寫一個腳本語言更有吸引力。前幾篇文章已經實現一個簡易的加減法計算器,想必看了文章之后可以很快的寫出來一個乘除法計算器。
好吧!我承認我想標題黨了。大家對解釋器的吸引,絕對沒有自己動手寫一個腳本語言更有吸引力。不過如果看到標題過來的,可能也是
我承認,之前收藏的減肥視頻,我都是這樣對待他們的。
不過我還是相信很多程序猿or程序媛不僅僅希望可以做出一個牛逼的產品,更想做出來一個牛逼閃閃的編程語言。而這里就是朝著開發一個腳本語言的方向去努力
恩!我就是xxoo語言之父。
前幾篇文章已經實現一個簡易的加減法計算器,想必看了文章之后可以很快的寫出來一個乘除法計算器。那么如果加減乘除混合運算呢?
這節將實現類似6-1*2+4/2這樣的運算方式,大家看到這個式子之后應該已經了解難點在哪里了。好了下面開始,首先展示完整的代碼。
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);
看過前面幾篇文章的已經了解過,這里的代碼結構發生了變化。
首先,分離出來詞法分析類,該類的作用:將字符串進行類似分詞處理,并將每個詞的含義返回
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則進行加法
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中進行運算的。
文中很多描述存在很多不當,我也在積極的學習如何將知識講的通俗易懂。如果您有好的辦法,可以一同探討
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/29037.html
摘要:經過幾天的努力,用已經實現了一個完整的基礎計算器,如下圖上代碼定義整數類型描述定義操作符號類型描述加法定義操作符號類型描述減法定義操作符號類型描述乘法定義操作符號類型描述除法定義操作符號類型描述定義操作符號類型描述定義空格用來存儲輸入字符的 showImg(https://segmentfault.com/img/bVbdNO5?w=900&h=377); 經過幾天的努力,用PHP已經...
摘要:偶然間在朋友圈發現有人在看一本兩周自制腳本語言,覺得寫個腳本語言挺不錯的,方便自己對語言本身進一步了解。,不過同樣,該教程采用的也不是。在這里寫出代碼方便自己查找,同時也希望一些對解釋器感興趣的朋友一同學習。 偶然間在朋友圈發現有人在看一本《兩周自制腳本語言》,覺得寫個腳本語言挺不錯的,方便自己對語言本身進一步了解。于是乎,買了下來看了看,寫的挺通俗易懂,但是不便的是,采用的語言是Ja...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經到來了,總結過去的 2017,相信小伙們一定有很多收獲...
閱讀 1675·2021-11-15 11:37
閱讀 3408·2021-09-28 09:44
閱讀 1649·2021-09-07 10:15
閱讀 2784·2021-09-03 10:39
閱讀 2687·2019-08-29 13:20
閱讀 1291·2019-08-29 12:51
閱讀 2204·2019-08-26 13:44
閱讀 2125·2019-08-23 18:02