5.2.1 机器的模型

5.2.1 机器的模型
由make-machine生成的机器模型被表示成一个使用在第三章中开发的
消息传递技术的具有本地状态的程序。为了构建这个模型,make-machine开始于
调用 make-new-machine 程序来组装对于所有的寄存器机器共用的机器模型的各个部分。
这个基本的被make-machine组装的机器模型是一个有一些寄存器和一个栈,加上一个逐条
执行控制器指令的执行机制的容器。

make-machine使用发消息的方式扩展了这个基本的模型,包含了寄存器,操作和
被特定的机器定义的控制器。首先它在新机器上,为给定的每个寄存器名称,
分配一个寄存器,在机器上安装目标操作。然后它使用汇编器(这个汇编器在如下
的5.2.2部分中描述)把控制器列表转换成新机器的指令,并且作为机器的
指令序列安装它们。make-machine返回已修改的机器模型的值。

(define  (make-machine register-names ops controller-text)
     (let   ((machine  (make-new-machine))) 
            (for-each  (lambda  (register-name) 
                                                ((machine 'allocate-register)  register-name))
                             register-names)
            ((machine  'install-operations)  ops)  
            ((machine  'install-instruction-sequence)  
             (assemble  controller-text machine))
            machine
    )
)

*寄存器
正如在第三章中的那样,我们用一个有局部状态的程序来表示一个寄存器。
程序make-register 创建一个寄存器,这个寄存器有一个能被读取与修改的值。

(define (make-register  name)
     (let  ((contents  '*unassigned*)) 
             (define  (dispatch  message)  
                     (cond  ((eq?  message  'get) contents)  
                                ((eq?  message 'set)  
                                         (lambda  (value)  (set!  contents  value))) 
                                (else  (error  ""  message))
                     )
             )
          dispatch
    )
)

以下的程序被用来读取寄存器。

(define  (get-contents  register)
   (register  'get)
)

(define  (set-contents!  register value)
     ((register  'set)  value)
)

*栈
我们也用一个有局部状态的程序来表示一个栈。程序make-stack创建一个栈,
栈的局部状态是由栈上的项的一个列表组成的。一个栈接受压栈,弹栈,返回值,
和把栈初始化为空的请求。

(define  (make-stack)
    (let  ((s   '()))
          (define  (push  x)  (set!   s  (cons  x  s)))  
          (define  (pop)   
                    (if  (null?  s)   (error  "Empty stack  --POP") 
                            (let  ((top  (car  s))) 
                                   (set!   s  (cdr  s))  
                                   top)))  
          (define   (initialize)  
                           (set!  s '()) 
                            'done) 
          (define  (dispatch  message)  
                      (cond   ((eq?  message  'push)  push)  
                                  ((eq?  message  'pop)   pop)  
                                  ((eq?  message  'initialize)  (initialize))  
                                  (else   (error  "Unknown  request  --STACK"  message))))
          dispatch
    )
)

以下的程序被用来读取栈。

(define    (pop  stack) 
    (stack  'pop))

(define    (push stack  value)
    ((stack  'push)  value))

*基本机器
在图5.13中显示的程序make-new-machine,由一个有局部状态的对象组成,
局部状态包括了一个栈,一个初始化的空的指令序列,和一些操作的列表还
有一个寄存器的表格。这些操作初始化时包括了一个对栈进行初始化的操作。
寄存器的表格初始化时包括了两个寄存器,一个叫做flag(标志),一个叫做pc
(程序计数器)。内部的程序allocate-register向寄存器的表格中添加新的记录项。
内部程序lookup-register在表格中查找寄存器。

在模拟的机器中标志寄存器被用来控制分支过程。测试指令根据测试结果设置标志
寄存器的值。分支指令根据检查的标志寄存器的值来决定是否进入分支部分。

程序计数器的寄存器确定着机器运行的指令的序列。通过内部程序execute实现了这个序列。
在模拟的模型中,任何的机器指令都是一个数据结构,它包括了一个没有参数的程序,
叫做指令执行程序,这样,调用这个程序就模拟了执行指令。作为模拟执行,程序计数器指向
指令序列中下一条要被执行的指令开始的地方。指令执行程序execute得到了指令,通过调用
指令执行程序执行它,并且重复这个循环,直到没有更多的指令可以执行了为止。也就是程序计数
器指到了指令序列的末尾了。

(define   (make-new-machine)
     (let   ((pc   (make-register  'pc))  
              (flag  (make-register  'flag))   
              (stack   (make-stack))  
              (the-instruction-sequence  '()))  
             (let   ((the-ops  (list  (list   'initialize-stack    (lambda  ()   (stack  'initialize)))))  
                      (register-table  (list  (list  'pc pc)    (list 'flag  flag))))  
                  (define  (allocate-register  name) 
                           (if  (assoc  name  register-table) 
                                (error  "Multiply defined register:"  name) 
                                (set!   register-table  (cons  (list  name  (make-register  name))  
                                                                            register-table)))
                          'register-allocated
                  ) 
                  (define   (lookup-register  name) 
                            (let  ((val   (assoc name  register-table)))  
                                   (if  val  (cadr  val)  
                                           (error  "Unknown  register:" name)))
                  )
                  (define  (execute)
                          (let  ((insts  (get-contents  pc)))  
                               (if  (null?  insts)  
                                     'done 
                                     (begin  
                                            (instruction-execution-proc  (car  insts)) 
                                            (execute))))
                  )
                  (define  (dispatch  message) 
                      (cond  ((eq?  message  'start)  (set-contents!   pc  the-instruction-sequence)) 
                                 ((eq?  message  'install-instruction-sequence) 
                                     (lambda  (seq)   (set!   the-instruction-sequence  seq)))  
                                 ((eq? message  'allocate-register)  allocate-register) 
                                 ((eq? message  'get-register)   lookup-register)
                                 ((eq? message  'install-operations)  
                                            (lambda  (ops)  (set!  the-ops  (append the-ops ops))))
                                 ((eq?   message  'stack)  stack)  
                                 ((eq?   message  'operations)  the-ops) 
                                 (else  (error  "Unknown  request  --MACHINE"  message))
                      ))  
                 dispatch
             )
    )
)

图5.13 程序make-new-machine,实现了基本的机器模型

作为它的操作的一部分,任何一个指令执行程序都修改了程序计数器,来显示下一条要执行的指令。
分支与去哪的指令修改程序计数器让它指向新的目标地址。所有的其它的指令简化了程序计数器,让它
指向序列中的下一条指令。注意的是任何对execute的调用,也调用了execute,但是这没有生成一个
无限的循环,因为运行的指令执行程序修改了程序计数器的内容。

make-new-machine返回了程序dispatch,程序dispatch实现了消息传递来读取内部的状态。
注意的是通过设置程序计数器到指令序列的开头处和调用执行程序,来完成启动机器。

为了方便,我们提供了一个可选的程序化接口,这个接口是对机器的启动操作的,正如
设置和检查寄存器内容的程序,它被指定在5.2部分的开头处:

(define  (start  machine)
     (machine  'start))

(define   (get-register-contents   machine  register-name) 
    (get-contents   (get-register  machine  register-name)))

(define   (set-register-contents!   machine  register-name  value)
   (set-contents!    (get-register  machine  register-name)  value)   'done)

这些程序(和许多在5.2.2和 5.2.3部分中的程序)使用如下的在一个给定的机器中,
以一个给定的名称,来查找寄存器的程序:

(define  (get-register machine  reg-name)
    ((machine   'get-register)  reg-name))

猜你喜欢

转载自blog.csdn.net/gggwfn1982/article/details/83180578