[JavaScript Interpreter]動手寫一個JavaScript直譯器 | Part 2 特殊符號

處理特殊符號

Huashen
Dec 27, 2021

上一篇文章裡我們講解了直譯器的基本架構,並實作出一個可以進行基礎四則運算的直譯器。但這個直譯器遇到正負號、空白字元、小數點、括號等等字元時會因為無法解析而出錯,因此本篇文章將會著手解決這些問題。

空白字元

要解決空白字元的問題非常簡單,只需要在讀取到空白字元時自動跳過就可以了,因此需要對我們的Lexer稍加修改 :

src/lexer.ts

Lexer在讀取文字時若遇到空白字元,直接呼叫advance()跳過。

執行程式進行測試 :

js>    1         +              2
3
js> 12 + 345 * 2 / 10
81

測試成功 !

小數點

要能夠解析小數點的話,需要擴展我們Lexer裡面的number()定義,在解析數字時遇到第一個小數點,可以接受這個字元並繼續向後解析,但若是同一個數字中出現多個小數點則會拋出錯誤 :

src/lexer.ts

同樣的執行測試 :

js> 1.3 + 2.45
3.75
js> 345.2 + 9.8
355

測試成功 !

括號

括號處理起來會稍微麻煩一點,因為它會改變我們的語法規則,當初我們的規則是先乘除後加減,但括號的優先程度又要大於這些四則運算符號,因此我們會需要改變我們的Parser,但在修改Parser之前,需要先新增代表左右括號的TokenType :

src/token.ts

接著修改Parser的factor()解析方式 ,讓我們遇到到左括號時,會重新呼叫expr()來解析括號中的內容,解析完畢後再檢查是否有出現右括號,並將解析出來的子樹回傳 :

src/parser.ts

最後別忘了也要修改Lexer,讓遇到括號時能夠解析並產生對應的Token :

src/lexer.ts

開始進行測試 :

js> (1+2)*3
9
js> (1+2*3)*4-5*6
-2

測試成功 !

上一篇文章有提到過,括號的出現會影響我們的抽象語法樹結構,因此我們可以將剛剛測試用的案例當作目標,練習建構出對應的抽象語法樹 :

解析帶有括號的抽象語法樹

正負號

若要處理正負號的狀況,我們需要一個新的抽象語法樹節點類型 : 一元運算符 Unary,Unary接受一個子節點,而我們可以在走訪的時候將子節點的值先進行正負操作再回傳,以此達到我們想要的效果,我們首先在src/ast.ts裡定義Unary節點 :

src/ast.ts

接著在Parser解析時,實作Unary的建構,我們在factor()裡面處理他,因為正負號的優先度是最高的 :

src/parser.ts

最後在Interpreter裡面實作走訪到Unary時的行為 :

src/interpreter.ts

這樣就完成正負號的部份了,一樣執行專案進行測試 :

js> +++---+-+-++---87
87
js> -(2+3)*-5
25
js> -2 * -(3-11) / ---4
4

測試成功 !

本篇文章的內容到這裡就結束了,這次我們將一些簡單但是重要的功能實作出來,雖然內容篇幅不長,但是剛好Lexer、Parser、Interpreter這三個最重要的核心功能都有涵蓋到,正好能藉此機會更加熟悉直譯器的整個解析與執行流程。

接下來我們會介紹JavaScript程式碼的基本組成,包含函數、作用區塊、變量的型別、賦值與計算等等,並開始以真正的文本來進行解析,讓我們的直譯器更有架式。

這個系列的完整內容可以到我的Github Repo上參考。

下一篇

動手寫一個JavaScript直譯器 | Part 3 語法結構(上)>

References :

Let’s Build A Simple Interpreter.

如果對於我的文章或程式碼有任何問題,歡迎在下方留言指教。

若有幫助到你,也歡迎給文章拍手一下,讓我在寫文章的路上更加進步!

--

--

Huashen

嗨,我是Huashen,一位軟體工程師,這裡會記錄我的程式設計心得與筆記。