摘要:經(jīng)過幾天的努力,用已經(jīng)實(shí)現(xiàn)了一個(gè)完整的基礎(chǔ)計(jì)算器,如下圖上代碼定義整數(shù)類型描述定義操作符號(hào)類型描述加法定義操作符號(hào)類型描述減法定義操作符號(hào)類型描述乘法定義操作符號(hào)類型描述除法定義操作符號(hào)類型描述定義操作符號(hào)類型描述定義空格用來存儲(chǔ)輸入字符的
經(jīng)過幾天的努力,用PHP已經(jīng)實(shí)現(xiàn)了一個(gè)完整的基礎(chǔ)計(jì)算器,如下圖
上代碼
type=$type; $this->value=$value; } /** 通過該方法來獲取類的私有屬性 */ public function __get($name) { return $this->{$name}; } /** 用于調(diào)試 */ public function __toString() { return "type:".$this->type." value:".$this->value; } } class Lexer{ private $current_char ; private $current_token ; private $text; private $pos=0; /*** $text 需要進(jìn)行解釋的字符串 */ public function __construct($text){ //去除前后可能存在的空格 這些空格是無效的 $this->text=trim($text); //初始化 獲取第一個(gè)字符 $this->current_char = $this->text[$this->pos]; } public function error() { throw new Exception("Lexer eroor"); } /* 步進(jìn)方法,每操作一個(gè)字符后前進(jìn)一位 */ 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(); } } /* 如果要支持多位的整數(shù),則需要將每位數(shù)字存儲(chǔ)起來 */ public function integers() { $result="";//用于存儲(chǔ)數(shù)字 while($this->current_char!=null&&is_numeric($this->current_char)){//只要當(dāng)前字符是數(shù)字就一直循環(huán)并將數(shù)字存儲(chǔ)于$result $result.=$this->current_char; $this->advance();//步進(jìn)方法,每操作一個(gè)字符后前進(jìn)一位 } return intval($result);//將數(shù)字字符串轉(zhuǎn)成整數(shù) } //獲取當(dāng)前字符的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; //初始化 獲取第一個(gè)字符 $this->current_token=$this->lexer->get_next_token(); } //如果字符類型和判斷的類型一致,則繼續(xù),否則輸入錯(cuò)誤 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);
有時(shí)間我得學(xué)習(xí)下如何把上述邏輯用插圖描述,最是最后一篇文章,下次就真的應(yīng)該是如何寫個(gè)腳本語言了!
以上所有代碼已上傳GITHUB ,歡迎star 傳送門
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/29055.html
摘要:偶然間在朋友圈發(fā)現(xiàn)有人在看一本兩周自制腳本語言,覺得寫個(gè)腳本語言挺不錯(cuò)的,方便自己對(duì)語言本身進(jìn)一步了解。,不過同樣,該教程采用的也不是。在這里寫出代碼方便自己查找,同時(shí)也希望一些對(duì)解釋器感興趣的朋友一同學(xué)習(xí)。 偶然間在朋友圈發(fā)現(xiàn)有人在看一本《兩周自制腳本語言》,覺得寫個(gè)腳本語言挺不錯(cuò)的,方便自己對(duì)語言本身進(jìn)一步了解。于是乎,買了下來看了看,寫的挺通俗易懂,但是不便的是,采用的語言是Ja...
摘要:大家對(duì)解釋器的吸引,絕對(duì)沒有自己動(dòng)手寫一個(gè)腳本語言更有吸引力。前幾篇文章已經(jīng)實(shí)現(xiàn)一個(gè)簡(jiǎn)易的加減法計(jì)算器,想必看了文章之后可以很快的寫出來一個(gè)乘除法計(jì)算器。 好吧!我承認(rèn)我想標(biāo)題黨了。大家對(duì)解釋器的吸引,絕對(duì)沒有自己動(dòng)手寫一個(gè)腳本語言更有吸引力。不過如果看到標(biāo)題過來的,可能也是 showImg(https://segmentfault.com/img/bVbdItC?w=771&h=37...
摘要:入門,第一個(gè)這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運(yùn)行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個(gè)這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運(yùn)行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個(gè)這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運(yùn)行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
閱讀 3396·2021-09-22 15:17
閱讀 2747·2021-09-02 15:15
閱讀 1770·2019-08-30 15:54
閱讀 2007·2019-08-30 14:02
閱讀 2534·2019-08-29 16:58
閱讀 2995·2019-08-29 16:08
閱讀 1335·2019-08-26 12:24
閱讀 1660·2019-08-26 10:41