用C語言編寫直譯器 一 我們的目標

2022-08-17 23:09:13 字數 4964 閱讀 2044

宣告為提高教學質量,我位址的學院正在規畫編寫c說話教材。《用c說話寫詮釋器》系列文章經清算後將收入書中「綜合嘗試」一章。是以該系列的文章首要閱讀物件定為剛學完c說話的學生(不要求有資料結構等其他常識),所以行文鬥勁羅嗦,請勿見責。本人水平有限,若有描述不適當或錯誤之處請不惜賜教!特此宣告。

原由比來,我們學院教員聯絡我,但願我能供給一段用 c 說話編寫的 basic 詮釋器,用於 c 說話課程設計教學。我前段時刻也正好陷溺於「說話」自己,本就有籌算寫乙個詮釋器,這下正中我下懷,於是欣然接管。

以前在藏書樓看過梁肇新的《程式設計高手規語》,第四章「程式設計說話的執行機理」中就包含了一段 c 說話編寫的 basic 詮釋器**,但**彷彿並不完整(我翻了好幾遍,都沒發現函式 get_token 的實現**);再者,此次的**還有其他用處,不宜牽扯版權問題;最後的原因是我有「想自己編碼」的感動 ^_^。綜上所述,我要從零起頭用 c 說話來編寫乙個 basic 詮釋器。

前置常識

1. 要編寫詮釋器,首先就要年夜白什麼是詮釋器(具體的詮釋請參看維基百科:詮釋器)。盜用《程式設計高手規語》裡的話:詮釋軌範就是乙個字串的詮釋器(p165 詮釋說話的事理)。所以,若是僅僅是為我小我編寫的話,我寧可會借助 lex & yacc 甚至 perl,而不會純粹用 c 說話來寫。

2. 在原由中已經提過,這個軌範會在學弟學妹們學完 c 說話後作為綜合嘗試。是以需要你熟悉 c 說話的語法、單鏈表新增/刪除節點等操作以及棧的概念(這些內容年夜部門都能在 c 說話的教材中找到),一些相對偏僻的手藝(例如 setjmp/longjmp)則不會呈此刻軌範中。

關於說話

我在《程式設計和說話之我見》一文中提過,程式設計是乙個很寬泛的概念。從某種意義上來說所有的軟體都是一種特定的說話,但按照軌範自己的矯捷性可以分為「硬編碼」、「可設定裝備擺設」、「可節制」和「可程式設計」四類(詳見《四類軌範》)。若是乙個軌範的矯捷性達到了「可程式設計」,它的設定裝備擺設檔案就可以被看作一種「程式設計說話」,而該軌範自己也就是乙個「詮釋器」。

要做到「可程式設計」,軌範至少應該具備「輸入/輸出」、「表示式運算」、「記憶體打點」和「按前提跳轉」四個功能(詳見《用dos批措置來做數字影象措置》)。這正好對應了馮?諾依曼計較機的結構:以運算器和節制器為中心,輸入/輸出裝置與儲存器之間的資料傳輸都要經由運算器。下面具體介紹各個部門。

我們的方針

我們要編寫詮釋器,自然也逃不出上面的條條例例。語法就參考 basic,但因為是設計我們自己的說話,當然可以按照小我興趣進行「添枝接葉」(好比表示式裡供給神往已久的階乘運算 ^_^)。下面是一段 basic 的示例**(example.bas):

0009 n = 0

0010 while n < 1 or n > 20

0011 print "請輸入乙個1-20之間的數"

0012 input n

0013 wend

0020 for i = 1 to n

0030 l = "*"

0040 for j = 1 to n - i

0050 l = " " + l

0060 next

0070 for j = 2 to 2 * i - 1 step 2

0080 l = l + "**"

0090 next

0100 print l

0110 next

0120 i = n - 1

0130 l = ""

0140 for j = 1 to n - i

0150 l = l + " "

0160 next

0170 for j = 1 to ((2*i) - 1)

0180 l = l + "*"

0190 next

0200 print l

0210 i = i - 1

0220 if i > 0 then

0230 goto 130

0240 else

0250 print "by redraiment"

0260 end if

basic 語法要求行首供給乙個 1->9999 之間的數字作為該行的行號(當前行的行號不小於上一行的行號),供 goto 語句跳轉時挪用。basic 的語法比 c 嚴酷,這不僅可以降低**的複雜性還使說話自己更易學。上面的**差不多涵蓋了我們需要實現的所有功能,若是能被正確解析,你將看到下面的執行下場:

下面來依次談判要實現的功能。

輸入/輸出(io)

經由過程輸入/輸出來和外部軌範某人互動,這是脫離「硬編碼」的最基本要求。輸入/輸出也是很抽象的概念,它並不侷限於尺度輸入輸出端(鍵盤、顯示器等),也可以經由過程檔案、網際網路等體例獲得資料(是以 c 說話中除了 scanf、printf 等,其實 #include 指令也算是一種 io 操作)。我們這個軌範並不強調 io,是以只要求實現 input 和 print 兩條指令,分袂用於從鍵盤輸入資料和列印到螢幕。指令的名目如下:

input var[, var ...]

其中 var 代表變數名(下同),變數之間用逗號離隔。

作用:從鍵盤獲得乙個或多個值,並賦值到響應的變數。同時輸入多個變數時,輸入的每個數之間用空格、回車或製表符離隔。

例如:input a, b, c

print expression[, expression ...]

其中 expression 為表示式(下同),表示式之間用逗號離隔。

作用:對表示式求值,將功效輸出到螢幕並換行。若是有多個表示式,表示式之間用製表符( )離隔。

例如:print i * 3 + 1, (a + b)*(c + d)

表示式運算   在《dos》中我稱號它為「算術運算」。但對於計較機來說,「算術運算」不僅包含諸如「四則運算」等算術運算,還蒐羅「關係運算」和「邏輯運算」。為了避免歧義,在此就改稱它為「表示式運算」。「表示式運算」是整個軌範的焦點,地位相當於計較機的運算器。在我們的軌範中,需要實現以下幾種運算子:

符號 名稱 優先順序 連繫性

( 左括號 17 left2right

) 右邊 17 left2right

+ 加 12 left2right

- 減 12 left2right

* 乘 13 left2right

/ 除 13 left2right

% 取模 13 left2right

^ 求冪 14 left2right

+ 正號 16 right2left

- 負號 16 right2left

! 階乘 16 left2right

> 年夜於 10 left2right

< 小於 10 left2right

= 等於 9 left2right

<> 不等於 9 left2right

<= 不年夜於 10 left2right

>= 不小於 10 left2right

and 邏輯與 5 left2right

or 邏輯或 4 left2right

not 邏輯非 15 right2left

記憶體打點

在我們這個迷你型的詮釋器中,可以不用考慮記憶體空間動態分配的問題,只要實現簡單的變數打點。我們預設供給 a-z 26個可用的弱型別變數(可以隨意賦值為整數、浮點數或字串)。變數要求先賦值才能使用,否則就會提醒變數不成用(是以示例**中第一行就是給 n 賦值為 0)。賦值語句的名目為

[let] var = expression

其中 let 是可選的關頭字。basic 中不許可呈現 var1 = var2 = expression 這樣的賦值語句,

因為在表示式中「=」被翻譯為「等於」,所以賦值合適沒有呈此刻上面的**中。

作用:計較表示式的值,並將功效賦值給變數 var。

例如:i = (123 + 456) * 0.09

按前提跳轉

若是設計一門最精練的說話,那它的節制語句就只需供給像彙編中的 jmp、jnz 等按照前提跳轉的語句即可,經由過程它們的組合即可模擬出 if、while、for、goto 等節制語句。但 basic 作為一門高階說話,需要供給更高層、更抽象的語句。我們將會實現以下四條語句:

1)goto expression

其中 expression 是乙個數值表示式,計較功效必需為可用的行號。因為它是乙個表示式,經由過程動態計較就能模擬子軌範挪用。

作用:無前提跳轉到指定行。

例如:goto 120+10

2)if expression then

sentence1

[else

sentence2]

end if

其中 sentence 是語句塊(下同),包含一條或多條可執行語句。else 為可選部門。

作用:分支結構。但表示式值為真(數字不等於0或者字串不為空)時執行語句塊1;否則,有 else 語句塊時執行 else 語句塊。

例如:if 1=1 then

print "true"

else

print "false"

end if

3)for var = expression to expression [step expression]

sentence

next

所有表示式均為數值表示式。step 為可選部門,為迭代器的步長。步長表示式的值不許可為 0。

作用:輪迴迭代結構

例如:for i = 1 to 10 step 3

print i

next

4)while expression

sentence

wend

作用:迭代執行語句塊,直到表示式的值為假。

例如:while n < 10

n = n + 1

wend

更多細節

basic 的源**不區分鉅細寫;

本軌範在實現中沒有措置字元轉義,是以無法無法輸出雙引號。在介紹完所有原始碼後,若是你有興趣可以考試考試自行完美;

本軌範同樣沒有考慮注釋(rem 關頭字)。其實這很簡單,但這個問題同樣留給你來措置 ^_^;

也許你也會有興趣新增 gosub 和 return 關頭字,讓子軌範功能從 goto 中解放出來。

總結

C語言編寫Linux shell直譯器的問題

include include include include include include define maxargs 20 最多接受20個引數 define arglen 100 長度最多100 intmain else return0 void execute char arglist c...

C 編寫乙個直譯器

一直想知道如何編寫一門指令碼語言,現在終於有機會實現了。非常感謝 thorsten ball 的大作 writing an interpreter in go 幫助我實現了這個想法!可能你比較好奇為啥這個專案叫 autumn,因為剛好這個專案是在國慶節開始的,正好是秋天,就以當時的季節命名了。c 是...

用c語言編寫乙個日期計算器

前提概述 用c語言 編寫乙個日期計算器思路 1 首先我要確定二個年份之間天數 當成滿年來看 j1值 2 然後我們再來確定月份 第一種是前年份的月份小於後年份的月份 那我們就先不看二個年份的本月份 計算二個年份除本月外還剩月份的天數 然後我們再加上前月份剩的天數和後月份過的天數。相加 第一種j2值 第...