# 5.2.1机器型号

> 译者： [https://sicp.comp.nus.edu.sg/chapters/102](https://sicp.comp.nus.edu.sg/chapters/102)

`make_machine`生成的机器模型使用第3章开发的消息传递技术表示为具有局部状态的函数。要构建此模型，`make_machine`首先调用函数`make_new_machine`来构造机器的各个部分 所有注册机通用的模型。 由`make_new_machine`构造的这种基本机器模型实质上是一些寄存器和堆栈的容器，以及一种用于逐一处理控制器指令的执行机制。

然后，`Make_machine`扩展此基本模型（通过发送消息），以包括要定义的特定计算机的寄存器，操作和控制器。 首先，它在新机器中为每个提供的寄存器名称分配一个寄存器，并在该机器中安装指定的操作。 然后，它使用_汇编程序_（在下面的 [5.2.2](103) 部分中进行描述）将控制器列表转换为新机器的指令，并将其作为机器的指令安装 序列。 `Make_machine`返回修改后的机器模型作为其值。

```js
function make_machine(register_names, ops, controller_text) {
    const machine = make_new_machine();

    map(reg_name => machine("allocate_register")(reg_name), register_names);
    machine("install_operations")(ops);
    machine("install_instruction_sequence")(assemble(controller_text, machine));

    return machine;
}
```

## 寄存器

我们将在第3章中将寄存器表示为具有局部状态的函数。函数`make_register`创建一个寄存器，该寄存器包含一个可以访问或更改的值：

```js
function make_register(name) {
    let contents = "*unassigned*";

    function dispatch(message) {
        if (message === "get") {
            return contents;

        } else {
            if (message === "set") {
                return value => { contents = value; };

            } else {
                error(message, "Unknown request: REGISTER");
            }
        }
    }

    return dispatch;
}
```

以下功能用于访问寄存器：

```js
function get_contents(register) {
    return register("get");
}

function set_contents(register, value) {
    return register("set")(value);
}
```

## 堆栈

我们还可以将堆栈表示为具有局部状态的函数。 函数`make_stack`创建一个堆栈，其本地状态由堆栈中的项目列表组成。 堆栈接受将项目推入堆栈，将最上面的项目从堆栈中弹出并返回并将其初始化为空的请求。

```js
function make_stack() {
    let stack = null;

    function push(x) { 
        stack = pair(x, stack); 
        return "done";
    }

    function pop() {
        if (is_null(stack)) {
            error("Empty stack: POP");

        } else {
            const top = head(stack);
            stack = tail(stack);
            return top;
        }
    }

    function initialize() {
        stack = null;
        return "done";
    }

    function dispatch(message) {
        return message === "push"
            ? push
            : message === "pop"
            ? pop()
            : message === "initialize"
            ? initialize()
            : error("Unknown request: STACK", message);
    }

    return dispatch;
}
```

以下功能用于访问堆栈：

```js
function pop(stack) {
    return stack("pop");
}

function push(stack, value) {
    return stack("push")(value);
}
```

## 基本机

`make_new_machine`函数，如图 [5.13](102#fig_5.13)程序计数器&lt;/quote&gt;）。 内部函数将新条目添加到寄存器表中，内部函数`lookup_register`在表中查找寄存器。

标志寄存器用于控制仿真机中的分支。 测试指令将标志的内容设置为测试结果（对或错）。 分支指令通过检查标志的内容来决定是否分支。

pc寄存器确定机器运行时指令的顺序。 该排序由内部函数execute实现。 在仿真模型中，每条机器指令都是一个数据结构，其中包含不带任何参数的函数，称为_指令执行函数_，因此调用此函数可模拟指令的执行。 在仿真过程中，pc指向指令序列中从要执行的下一条指令开始的位置。 Execute获取该指令，通过调用指令执行函数执行该指令，并重复此周期，直到没有更多指令要执行（即直到pc指向指令序列的末尾）为止。

<figure>

```js
function make_new_machine() {
    const pc = make_register("pc");
    const flag = make_register("flag");
    const stack = make_stack();
    let the_instruction_sequence = null;
    let the_ops = list(list("initialize_stack", () => stack("initialize")));
    let register_table = list(list("pc", pc), list("flag", flag));
    function allocate_register(name) {
        if (assoc(name, register_table) === undefined) {
            register_table = pair(list(name, make_register(name)), register_table);
        } else {
            error(name, "Multiply defined register: ");
        }
        return "register_allocated";
    }
    function lookup_register(name) {
        const val = assoc(name, register_table);
        return val === undefined
            ? error(name, "Unknown register:")
            : head(tail(val));
    }
    function execute() {
        const insts = get_contents(pc);
        if (is_null(insts)) {
            return "done";
        } else {
            const proc = instruction_execution_proc(head(insts)); 
            proc(); 
            return execute();
        }
    }
    function dispatch(message) {
        return message === "start"
                ? () => { set_contents(pc, the_instruction_sequence);
                          return execute();                          }
            : message === "install_instruction_sequence"
                ? seq => { the_instruction_sequence = seq; }
            : message === "allocate_register"
                ? allocate_register
            : message === "get_register"
                ? lookup_register
            : message === "install_operations"
                ? ops => { the_ops = append(the_ops, ops); }
            : message === "stack"
                ? stack
            : message === "operations"
                ? the_ops
            : error(message, "Unknown request: MACHINE");
    }
    return dispatch;
}
```

**[图5.13](102#fig_5.13)** `make_new_machine`功能，它实现了基本的机器模型 。</figure>

作为其操作的一部分，每个指令执行功能都会修改pc，以指示要执行的下一条指令。 分支和`go_to`指令将pc更改为指向新目的地。 所有其他指令仅使pc前进，使其指向序列中的下一条指令。 请注意，每次执行调用的调用都会再次执行，但这不会产生无限循环，因为运行指令执行函数会更改pc的内容。

`Make_new_machine`返回一个调度功能，该功能实现对内部状态的消息传递访问。 注意，通过将pc设置为指令序列的开头并调用execute来完成启动机器。

为了方便起见，我们为机器的启动操作提供了一个替代的程序接口，以及用于设置和检查寄存器内容的功能，如 [5.2](101) 的开头所指定的：

```js
function start(machine) {
    return machine("start")();
}

function get_register_contents(machine, register_name) {
    return get_contents(get_register(machine, register_name));
}

function set_register_contents(machine, register_name, value) {
    set_contents(get_register(machine, register_name), value);
    return "done";
}
```

这些功能（以及 [5.2.2](103)[5.2.3](104) 部分中的许多功能）使用以下内容查找带有 给定机器上的给定名称：

```js
function get_register(machine, reg_name) {
    return machine("get_register")(reg_name);
}
```