4.1.3 直譯器的資料結構
除了定義表示式的外部語法,直譯器的實現必須定義其內部操作的資料結構,
作為乙個程式執行的一部分,例如程式和環境的表示,真值與假值的表示。
* 斷言的測試
對於條件,我們接受任何事為真,如果它不是顯式地顯示為假的物件。
(define (true? x)
(not (eq? x false)))
(define (false? x)
(eq? x false))
* 表示程式
為了處理原生的程式,我們假定已經有如下的程式可用了。
(primitive-procedure? )
測試是否是乙個原生的程式。
對於處理原生程式的這些機制,在4.1.4部分中有進一步的描述。
復合程式是由引數,程式體和環境變數這三個部分,使用組裝子make-procedure組裝而成。
(define (make-procedure parameters body env)
(list 'procedure parameters body env))
(define (compound-procedure? p)
(tagged-list? p 'procedure))
(define (procedure-parameters p) (cadr p))
(define (procedure-body p) (caddr p))
(define (procedure-environment p) (cadddr p))
* 對環境的操作
直譯器需要操作環境的操作。正如在3.2部分中的解釋,乙個環境是
乙個幀的序列,任何乙個幀都是乙個繫結了相關的變數和它們的相應的值的**。
我們使用操作環境的如下的操作:
(lookup-variable-value )
返回在環境中的符號繫結的值,如果變數沒有繫結,返回乙個錯誤。
(extend-environment )
返回乙個新的環境,它由乙個新的幀組成,在列表中的符號被繫結
到列表中的相應的元素上,它的父級環境是環境。
(define-variable! )
在環境的第乙個幀中加上乙個新的繫結,它是變數與值的繫結。
(set-variable-value! )
在環境中改變變數的繫結,所以變數現在的繫結的值是,
如果變數沒有繫結,返回乙個錯誤。
為了實現這些操作,我們把乙個環境表示為乙個幀的列表。乙個環境的父級環境是列表的
cdr部分。空的環境是乙個簡單的空列表。
(define (enclosing-environmen env) (cdr env))
(define (first-frame env) (car env))
(define the-empty-environment '())
乙個環境的任何乙個幀被表示為乙個列表的數對:在幀中,乙個變數的列表繫結到
相應的值的列表上。
(define (make-frame variables values) (cons variables values))
(define (frame-variables frame) (car frame))
(define (frame-values frame) (cdr frame))
(define (add-binding-to-frame! var val frame)
(set-car! frame (cons var (car frame)))
(set-cdr! frame (cons val (cdr frame))))
為了擴充套件乙個環境,通過乙個新的幀把變數和值關聯,我們做乙個幀
由變數的列表和值的列表組成,我們把這關聯到環境.如果變數的數量
沒有匹配值的數量,我們報乙個錯誤.
(define (extend-environment vars vals base-env)
(if (= (length vars) (length vals))
(cons (make-frame vars vals) base-env)
(if (< (length vars) (length vals))
(error "too many arugments supplied" vars vals)
(error "too few arguments supplied" vars vals)))
)為了在環境中查詢乙個變數,我們在第乙個幀中掃瞄變數的列表。如果我們發現了
期望的變數,我們返回值的列表中的相應的元素。如果我們沒有找到當前的幀中的
變數,我們搜尋父級環境等等。如果我們到達了空的環境,我們發乙個沒有繫結變數
的報錯。
(define (lookup-variable-value var env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars) (env-loop (enclosing-environment env)))
((eq? var (car vars))
(car vals))
(else (scan (cdr vars) (cdr vals)))
))(if (eq? env the-empty-environment)
(error "unbound variable" var)
(let ((frame (first-frame env)))
(scan (frame-variables frame)
(frame-values frame))))
) (env-loop env))
在乙個特定的環境中,為了把變數設定成乙個新的值,我們掃瞄變數,正如
在lookup-variable-value做的那樣。當我們找到它的時候,修改相應的值。
(define (set-variable-value! var val env)
(define (env-loop env)
(define (scan vars vals)
(cond ((null? vars) (env-loop (enclosing-environment env)))
((eq? var (car vars))
(set-car! vals val))
(else (scan (cdr vars) (cdr vals)))
))(if (eq? env the-empty-environment)
(error "unbound variable --set" var)
(let ((frame (first-frame env)))
(scan (frame-variables frame)
(frame-values frame))))
) (env-loop env))
為了定義乙個變數,我們搜尋為了變數的繫結的第乙個幀,如果它存在,
就改變繫結(正如在set-variable-value!).如果沒有這個繫結存在,
我們把它加到第乙個幀。
(define (define-variable! var val env)
(let ((frame (first-frame env)))
(define (scan vars vals)
(cond ((null? vars)
(add-binding-to-frame! var val frame))
((eq? var (car vars))
(set-car! vals val))
(else (scan (cdr vars) (cdr vals)))
))(scan (frame-variables frame)
(frame-values frame))))
這裡描述的方法僅是表示環境的所有的可能的方式之一。
因為我們使用的資料抽象來隔離直譯器的其它部分與表示
的細節性的選擇,如果我們需要,我們能選擇環境的表示法。
(見練習4.11)在乙個產品級的lisp系統中,直譯器的環境
操作速度,特別是變數的查詢,對系統的效能有重大的影響。
這裡描述的表示法,儘管概念上是簡單的,但是在乙個產品
系統中它沒有效率的也沒有被普遍使用。
練習4.11
代替表示乙個幀為乙個列表的數對,我們能表示乙個幀作為繫結的列表,
任何乙個繫結是乙個名稱和值的數對.使用這個新的表示,重寫環境操作.
練習4.12
為了遍歷環境結構,程式set-variable-value! ,define-variable! 和
lookup-variable-value能被表達使用更抽象的程式。定義抽象來捕獲共同的模式,
重定義這些抽象的這三個程式。
練習4.13
scheme通過使用define方法允許我們建立變數的新的繫結,但是沒有提供處理
繫結的方式。實現直譯器的make-unbound!的內部程式,當make-unbound!表示式
被解釋時從環境中把乙個給定的符號的繫結刪除。這個問題沒有完整的被指定。
例如,我們應該僅移除環境的第一幀中的繫結嗎?完成規範和調整你做的選擇。
資料結構 魔王語言解釋
一 需求分析 1 有乙個魔王總是使用自己的一種非常精煉而抽象的語言講話,沒有人能聽得懂,但他的語言是可以逐步解釋 能聽懂的語言,因為他的語言是由以下兩種形式的規則由人的語言逐步抽象上去的 1 1 2 m 2 1 2 n n n 1 1 在這兩種形式中,從左到右均表示解釋。試寫乙個魔王語言的解釋系統,...
資料結構 名詞解釋
1 資料集合中各個資料元素之間的邏輯關係,即資料的邏輯結構 2 在對資料進行處理時,各資料元素在計算機中的儲存關係,即資料的儲存結構 3 對各種資料結構進行的運算。資料結構 是指相互有關聯的資料元素的集合。在具有相同特徵的資料元素集合中,各個資料元素之間存在有某種關係,這種關係反映了該集合中的資料元...
資料結構迷宮問題 快速迭代器生成的資料結構
c 輸入輸出 string的簡單使用 陣列和向量 對角線問題 陣列和向量的排序 二分查詢原理 陣列二分查詢 向量二分查詢 3n 1問題 抽象資料型別 查詢問題的抽象資料型別視角 初識集合 次序統計量 有序向量與無序向量 以集合描述演算法 stl容器一覽 時空之謎 程式執行時間 量級常見執行時間 執行...