編程語(yǔ)言翻譯家族的發(fā)家史
我是編程語(yǔ)言翻譯家族的一員, 我們這個(gè)家族最重要的工作就是將一個(gè)語(yǔ)言描述的源程序翻譯成另外一種語(yǔ)言描述的目標(biāo)程序, 聽(tīng)起來(lái)有些抽象, 通俗一點(diǎn)就是把你們碼農(nóng)寫(xiě)的源碼變成可以執(zhí)行的程序。
我們這個(gè)家族可以說(shuō)是伴隨這計(jì)算機(jī)的發(fā)展而不斷發(fā)展壯大的, 現(xiàn)在已經(jīng)成為計(jì)算機(jī)軟件系統(tǒng)不可缺少的一部分, 如果回顧一下發(fā)家史, 還是挺有趣的。
1.機(jī)器語(yǔ)言
我聽(tīng)說(shuō)計(jì)算機(jī)剛發(fā)明那會(huì)兒, 人們就是撥弄各種開(kāi)關(guān)、操作各種電纜把程序給“輸入”到計(jì)算機(jī)中去。
這所謂的程序, 可真的是0110000111這樣的二進(jìn)制, 我真是佩服這些程序的設(shè)計(jì)者和操作員們, 太不可思議了。
這種原始的方式也決定了難于誕生超大型程序, 因?yàn)樘珡?fù)雜了,遠(yuǎn)遠(yuǎn)能過(guò)人腦能思考的極限。
后來(lái)人們做了點(diǎn)改進(jìn), 把程序打到穿孔紙帶上, 讓機(jī)器直接讀穿孔紙帶, 這下子就好多了, 終于不用撥弄開(kāi)關(guān)了。
但程序的本質(zhì)還是沒(méi)有變化, 依然是在使用二進(jìn)制來(lái)編程。
如果這個(gè)樣子一直持續(xù)下去, 估計(jì)這個(gè)世界上的程序員會(huì)少的可憐: 編程的門(mén)檻太高了。
比如說(shuō)你的腦子里得記住這樣的指令:
- 0000 表示從內(nèi)存中往CPU寄存器裝載數(shù)據(jù)
- 0001 表示把CPU寄存器的值寫(xiě)入內(nèi)存
- 0010 表示把兩個(gè)寄存器的值相加
你還得記住每個(gè)寄存器的二進(jìn)制表示:
- 1000 表示寄存器A
- 1001 表示寄存器B
綜合起來(lái)就像這樣:
- 0000 1000 000000000001 它的意思是說(shuō), 把編號(hào)為1的內(nèi)存中的值裝載到寄存器A當(dāng)中
- 0010 1000 1001 的意思是把寄存器A和寄存器B的值加起來(lái),放到寄存器A中。
整天生活在這樣的世界里, 滿腦子都是0和1, 要是我估計(jì)就抑郁了。
當(dāng)時(shí)的程序員像熊貓一樣稀少, 不, 肯定比熊貓更少, 他們都要二進(jìn)制寫(xiě)程序, 對(duì)我們翻譯家族沒(méi)有任何的需求。
2. 匯編語(yǔ)言
既然二進(jìn)制這么難記, 人們很快就想到: 能不能給這些指令起個(gè)好聽(tīng)的名稱呢?
- 0000 : LOAD
- 0001 : STORE
- 0010 : ADD
寄存器也是一樣的:
- 1000 : AX
- 1001 : BX
這下讀來(lái)容易多了:
- ADD AX BX
人們給這些幫助記憶的助記符起了個(gè)名字: 匯編語(yǔ)言。
但是計(jì)算機(jī)是無(wú)法執(zhí)行匯編語(yǔ)言的, 因?yàn)橛?jì)算機(jī)這個(gè)笨家伙只認(rèn)二進(jìn)制, 所以還得翻譯一下才行。
于是我們家族的一個(gè)重要成員: 匯編器 隆重登場(chǎng)了, 他專門(mén)負(fù)責(zé)匯編語(yǔ)言寫(xiě)的程序翻譯為機(jī)器語(yǔ)言, 這個(gè)翻譯的過(guò)程比較簡(jiǎn)單,幾乎就是一一對(duì)應(yīng)的關(guān)系。
匯編語(yǔ)言解放了人們的部分腦力, 可以把更多的精力集中在程序邏輯上了。 越來(lái)越多的人學(xué)會(huì)了使用匯編來(lái)編程, 寫(xiě)出了很多偉大的軟件。
匯編的優(yōu)點(diǎn)是貼近機(jī)器, 運(yùn)行效率極高, 但是缺點(diǎn)也是太貼近機(jī)器, 直接操作內(nèi)存和CPU寄存器, 不能結(jié)構(gòu)化編程, 每次函數(shù)調(diào)用還得把手動(dòng)把棧幀給管理好, 這對(duì)于一般的程序員來(lái)講太難了!
我的祖先們把穿孔紙帶和匯編語(yǔ)言都稱為低級(jí)語(yǔ)言, 把這個(gè)時(shí)代稱為機(jī)器語(yǔ)言編程時(shí)代。
生活在這個(gè)時(shí)代的祖先們是很幸福的, 因?yàn)榉g工作十分簡(jiǎn)單。
但是用匯編寫(xiě)程序的人還是太少, 找我們做翻譯的也很少, 翻譯家族也只是溫飽而已。
3.高級(jí)語(yǔ)言
人類的欲望是無(wú)止境的, 他們一直在探索用一種更高級(jí)的語(yǔ)言來(lái)寫(xiě)程序的可能性, 這種高級(jí)語(yǔ)言應(yīng)該面向人類編寫(xiě)和閱讀, 而不是面向機(jī)器去執(zhí)行。
人類想要的高級(jí)語(yǔ)言是這樣的:
聲明各種類型的變量來(lái)表示數(shù)據(jù),而不是用寄存器。 例如 :
- int value = 100
能使用復(fù)雜的表達(dá)式來(lái)告訴電腦自己的意圖:
- salary = 1000 + salary * 12
可以用各種控制語(yǔ)句來(lái)控制流程:
- if .. else , while(....) ....
還可以定義函數(shù)來(lái)封裝、復(fù)用一段業(yè)務(wù)邏輯:
- int get_primes(int max) {.....}
但是高級(jí)語(yǔ)言和低級(jí)語(yǔ)言之間存在著巨大的鴻溝, 怎么把高級(jí)語(yǔ)言翻譯成可以執(zhí)行的機(jī)器語(yǔ)言是個(gè)非常難的問(wèn)題!
人類在黑暗中摸索了很久,這才迎來(lái)一絲光明, 1957年,第一個(gè)高級(jí)語(yǔ)言的編譯器才在IBM704的機(jī)器上運(yùn)行成功。 更重要的是喬姆斯基對(duì)自然語(yǔ)言結(jié)構(gòu)的研究, 把語(yǔ)言文法做了分類,有了0型文法,1型文法, 2型文法,3型文法, 這一下子給我們的翻譯工作奠定了理論基礎(chǔ)。
由于翻譯的復(fù)雜性, 除了匯編器之外, 很多新成員加入進(jìn)來(lái), 我們的家族迅速發(fā)展壯大, 甚至形成了一個(gè)專門(mén)翻譯的流水線, 這個(gè)流水線的家族成員分工合作, 把高級(jí)語(yǔ)言翻譯成低級(jí)語(yǔ)言。
我主要做的工作就是第一步詞法分析, 大家經(jīng)常給我開(kāi)玩笑說(shuō): 你這是大刀向源程序頭上砍去。
這其實(shí)挺形象的,比如高級(jí)語(yǔ)言的源程序是這樣:
total = 1000 + salary * 12
我拿著“大刀”, 唰唰唰把他們砍成一個(gè)個(gè)的片段, 每個(gè)片段叫做Token。
1. 標(biāo)識(shí)符 total
2. 賦值符號(hào) =
3. 數(shù)字 1000
4. 加號(hào) +
5. 標(biāo)識(shí)符 salary
6. 乘號(hào) *
7. 數(shù)字12
程序中的空格就被我無(wú)情的刪除了, 我還會(huì)建立一個(gè)符號(hào)表讓后面的人去使用:
接下來(lái)我二叔就會(huì)接管, 他非常厲害, 會(huì)做語(yǔ)法分析,據(jù)說(shuō)他用了一個(gè)叫什么上下文無(wú)關(guān)語(yǔ)法的理論, 竟然能把我生成的Token 按照語(yǔ)法規(guī)則組建成一棵樹(shù)
然后三舅就做語(yǔ)法分析, 他會(huì)看看這些標(biāo)志符的類型,作用域是不是正確,運(yùn)算是否合法, 取值范圍有沒(méi)有問(wèn)題等等。
我大舅的工作最重要, 把中間代碼生成, 代碼優(yōu)化,以及最后的代碼生成都給承包了。
比如大舅根據(jù)語(yǔ)法樹(shù)生成的中間代碼如下:
- temp1 = id2 * 12
- temp2 = 1000 + temp1
- id1 = temp2
(注意:id2 就是salary, id1 就是 total)
然后他再優(yōu)化一下:
- temp1 = id2 * 12
- id1 = 1000 + temp1
然后翻譯成匯編:
- MOV id2 AX
- MUL 12 AX
- ADD 1000 AX
- MOV AX id1
已經(jīng)非常接近運(yùn)行了!
但是等等, 這id1 (total), id2 (salary) 只是兩個(gè)符號(hào), 計(jì)算機(jī)根本不知道是什么東西, 計(jì)算機(jī)只關(guān)心內(nèi)存和寄存器, 所以還得給這兩個(gè)家伙分配空間, 得到他們的地址。
如果這兩個(gè)變量是在別的文件中定義的, 還需要做一件特別的事情: 鏈接!
通過(guò)鏈接的方式,把變量的真正地址獲取到, 然后修改上面的id1, id2, 這樣才能形成一個(gè)可以執(zhí)行的程序。
在翻譯的過(guò)程中,如果有任何步驟出了錯(cuò)誤, 我們就會(huì)通知程序員, 告訴他哪個(gè)地方寫(xiě)錯(cuò)了, 改正后重新再來(lái)。
這就是我們家族的工作, 非常重要,沒(méi)有我們的翻譯工作, 人類就無(wú)法使用高級(jí)語(yǔ)言來(lái)編程, 像C, C++,Pascal, C#, Java 這樣影響力巨大的語(yǔ)言就不會(huì)出現(xiàn), 現(xiàn)在的軟件編程行業(yè)也不會(huì)這么興旺發(fā)達(dá)。
我們家族和操作系統(tǒng)、數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)協(xié)議棧等軟件一起,成為了計(jì)算機(jī)世界底層的基礎(chǔ)軟件。
其實(shí)我們都明白,現(xiàn)在所謂的高級(jí)語(yǔ)言一點(diǎn)也不高級(jí),只有經(jīng)過(guò)訓(xùn)練的專業(yè)人士才能使用 , 也許在未來(lái)會(huì)出現(xiàn)完全用自然語(yǔ)言來(lái)寫(xiě)程序, 到那個(gè)時(shí)候我們家族會(huì)是什么樣子? 估計(jì)只有上天才知道了。
【本文為51CTO專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)作者微信公眾號(hào)coderising獲取授權(quán)】