警告??:這將是一個(gè)又臭又長(zhǎng)的系列教程逻炊,教程結(jié)束的時(shí)候,你將擁有一個(gè)除了性能差勁犁享、擴(kuò)展性差余素、標(biāo)準(zhǔn)庫(kù)不完善之外,其他方面都和官方相差無(wú)幾的 Lua 語(yǔ)言解釋器炊昆。說(shuō)白了桨吊,這個(gè)系列的教程實(shí)現(xiàn)的是一個(gè)玩具語(yǔ)言威根,僅供學(xué)習(xí),無(wú)實(shí)用性视乐。請(qǐng)謹(jǐn)慎 Follow洛搀,請(qǐng)謹(jǐn)慎 Follow,請(qǐng)謹(jǐn)慎 Follow佑淀。
前言
編譯原理是計(jì)算機(jī)科學(xué)的一個(gè)重要且復(fù)雜的知識(shí)體系留美。這個(gè)系列教程也只是你入門前的墊腳石。但即使如此伸刃,也并不代表這個(gè)教程就很簡(jiǎn)單独榴,如果決定開(kāi)始,請(qǐng)堅(jiān)持到底奕枝。這是一個(gè)認(rèn)真嚴(yán)肅的教程(咳咳)棺榔,它不像網(wǎng)絡(luò)上的其他類似教程,要么實(shí)現(xiàn)一個(gè)“高級(jí)計(jì)算器”就完事了隘道,要么語(yǔ)法分析還沒(méi)講完症歇,就太監(jiān)了。也不像其他的 Lua 源碼閱讀類的指導(dǎo)教程谭梗,去教你怎么閱讀并理解官方實(shí)現(xiàn)的 Lua 解釋器的源碼忘晤。但我相信完成本教程后再去讀官方實(shí)現(xiàn)的源代碼,也會(huì)輕松很多激捏。
本教程將從零開(kāi)始设塔,一磚一瓦的構(gòu)建出一個(gè)完整的解釋器。不使用任何自動(dòng)化的工具远舅,也不使用任何第三方庫(kù)闰蛔,從詞法分析到虛擬機(jī),全部親力親為图柏。我們將要實(shí)現(xiàn)的語(yǔ)言起名為 SLua序六,意思是 Simple Lua。
前置要求
本教程并不是面向編程初學(xué)者的蚤吹,你至少需要滿足以下要求才可以繼續(xù)閱讀:
本教程使用的編程語(yǔ)言為 Google 出品的 Go 語(yǔ)言例诀。Go 語(yǔ)言上手非常容易,如果你有過(guò)其他任何語(yǔ)言的編程經(jīng)驗(yàn)裁着,請(qǐng)花幾個(gè)小時(shí)閱讀這篇教程:墻外多語(yǔ)言版繁涂、墻內(nèi)中文版。
本教程的定位不是教科書二驰,因此不會(huì)過(guò)多的提及關(guān)于編譯原理的理論性的內(nèi)容扔罪,而更加注重實(shí)踐。所以诸蚕,這要求你至少要知道編譯過(guò)程流水線的基本步驟以及每個(gè)步驟的作用步势,比如:詞法分析氧猬、語(yǔ)法分析、虛擬機(jī)等坏瘩。
既然要實(shí)現(xiàn) Lua 語(yǔ)言的解釋器盅抚,自然要求你熟悉 Lua 語(yǔ)言,即使沒(méi)有用它寫過(guò)項(xiàng)目倔矾,至少要熟悉 Lua 語(yǔ)言的語(yǔ)法及語(yǔ)言特性妄均。
面向人群
- 如果你很想知道腳本語(yǔ)言的解釋器的工作原理,請(qǐng)繼續(xù)閱讀哪自。
- 如果你不僅想知道工作原理丰包,還想親自實(shí)現(xiàn)一個(gè),請(qǐng)繼續(xù)閱讀壤巷。
- 如果你學(xué)完學(xué)校開(kāi)設(shè)的編譯原理課程邑彪,除了學(xué)會(huì)了 LEX 和 YACC,其余的還是一無(wú)所知胧华,請(qǐng)繼續(xù)閱讀寄症。
開(kāi)發(fā)方式
我們不準(zhǔn)備從一開(kāi)始就著手實(shí)現(xiàn)一個(gè)完完整整的解釋器,支持所有的 Feature矩动,這樣無(wú)疑會(huì)顧此失彼有巧,也會(huì)極大的拉高教程的閱讀門檻。所以我們會(huì)先抽取 Lua 中一些最最基本的特性悲没,實(shí)現(xiàn)一個(gè)可以工作的原型篮迎。在原型之上,我們?cè)俨粩嗵砑犹匦允咀耍钡酵瓿蔀橹埂?/p>
在第一個(gè)版本中甜橱,我們會(huì)將一些比較重要的 Feature 都砍掉,將目光集中在整個(gè)流程的實(shí)現(xiàn)上峻凫。
所以渗鬼,第一個(gè)版本將:
- 不支持 Table
- 不支持函數(shù)和閉包
- 不支持 for 循環(huán)語(yǔ)句
- 不支持 repeat...until 循環(huán)語(yǔ)句
- 不支持多行注釋和多行字符串
閹割的差不多了,看看還剩下什么:
- 變量的聲明及賦值(全局變量和局部變量)
- do ... end 代碼塊
- if ... elseif ... else ... end 分支語(yǔ)句
- while 循環(huán)語(yǔ)句
- 單行注釋
- 單行形式的字符串
- 各種單目和雙目的運(yùn)算符
編譯流程
SLua 的編譯共分為以下幾個(gè)階段:
- 詞法分析:將用戶輸入的文本形式的源代碼分解為一個(gè) Token 列表
- 語(yǔ)法分析:將詞法分析的輸出作為輸入荧琼,生成無(wú)語(yǔ)義信息的抽象語(yǔ)法樹(shù)(AST)
- 語(yǔ)義分析:完善 AST 中的語(yǔ)義相關(guān)的信息
- 代碼生成:根據(jù) AST 生成字節(jié)碼
- 虛擬機(jī):解釋并執(zhí)行字節(jié)碼
- 標(biāo)準(zhǔn)庫(kù):提供系統(tǒng)級(jí)的實(shí)用函數(shù)
教程的章節(jié)安排也和編譯流程保持一致。
獲取源代碼
代碼已托管到 Github 上:SLua差牛,每一個(gè)階段的代碼我都會(huì)創(chuàng)建一個(gè) release命锄,你可以直接下載作為參照。雖然提供了源代碼偏化,但并不建議直接復(fù)制粘貼脐恩,因?yàn)檫@樣學(xué)到的知識(shí)會(huì)很容易忘記。
剛開(kāi)始玩 Github 和簡(jiǎn)書侦讨,所以沒(méi)有任何粉絲和關(guān)注量(哭)驶冒,如果你覺(jué)得這篇教程有幫助苟翻,請(qǐng)不要吝嗇給文章點(diǎn)個(gè)喜歡,給 Github 上的項(xiàng)目點(diǎn)個(gè) Star骗污。如果能 Follow 一下簡(jiǎn)書和 Github 的賬號(hào)就更好啦崇猫,我也會(huì)更加有動(dòng)力將這個(gè)系列寫下去。:)