P-code机

在计算机科学中，P-code机（P-code machine）是一种被设计来执行P-code的虚拟机器。P-code是一种被设计来运行在虚拟CPU上的汇编语言，即是我们现代所称Bytecode的前身。P-code机这个词可用于形容所有这类机器（例如Java虚拟机和MATLAB预编译的代码），或者特指最有名的P-code机，来自于Pascal语言，特别是UCSD Pascal实作。
虽然这个概念在1966左右年就已首次实现（于BCPL的O-code与Euler语言的P - a code），但P-code这个词直到70年代初才首次出现。
1973年Nori, Ammann, Jensen, Hageli和Jacobi编写的Pascal-P编译器
和1975年尼克劳斯·维尔特写的Pascal-S编译器是早期的两个生成P-code的编译器。
P-code可以是一种与特定硬体平台无关的中间码，一种虚拟机器码。程式原始码会先被转换成P-code；转换成P-code的程序，之后会由一个软体来进行直译。这个软体可以模拟出一个假想的CPU来读取p-code，之后将p-code转换成实体机器码来执行。但如果有足够的商业利益，可能可以实作做出该规格CPU的硬件实现（例如Pascal MicroEngine和Java处理器）。

**UCSD p-Machine**

**架构**
如很多其他p-code机一样，UCSD p-Machine是一个堆叠结构机器，这意味着大多数指令从堆栈中获取它们的操作数，并将结果放回堆栈上面。因此，“add”指令将堆栈最顶部的两个元素替换成它们的和。有几条指令就取一个参数。像Pascal一样，p-code是强类型语言，原生支持boolean (b), character (c), integer (i), real (r), set (s)和pointer (a)类型。
一些简单的指令：
Insn.   Stack   Stack   Description
before  after
 
adi      i1 i2   i1+i2   add two integers
adr      r1 r2   r1+r2   add two reals
dvi      i1 i2   i1/i2   integer division
inn      i1 s1   b1      set membership; b1 = whether i1 is a member of s1
ldci     i1      i1      load integer constant
mov      a1      a2      move
not      b1      ~b1     boolean negation

**环境**
与其他基于堆栈的环境（如Forth和Java虚拟机）不同的是，p-系统非常类似于真正的目标CPU，它只有一个堆栈供过程栈帧（提过返回地址等）和局部指令参数共享。机器的其中三个寄存器指向这个堆栈（向上增加）：- SP 指向堆栈顶部（堆栈指针）。- MP 标记活动的栈帧的开始（标记指针)。- EP 指向当前过程的最高堆栈位置（极端指针）。
第五个寄存器 PC 指向当前指令的代码区。

**调用约定**
栈帧是这样的：
EP ->
local stack
SP -> ...
locals
...
parameters
...
return address (previous PC)
previous EP
dynamic link (previous MP)
static link (MP of surrounding procedure)
MP -> function return value
程序调用序列的工作方式如下：下面指令引入调用
mst n
其中 n 指定嵌套级别的差异（记得Pascal支持过程嵌套）。这个指令会标记这个堆栈，即在上述栈帧中保留起始地5个格子，并初始化前面的 EP、动态链接和静态链接。

**范例机器**
尼克劳斯·维尔特在他1976年出的书《算法+数据结构=程序》中详述了一个简单的P-code机。这个机器有3个寄存器——一个程序计数器 p，一个基寄存器 b，和一个栈顶寄存器 t。一共有8个指令，其中一个（opr）有多种形式。
这是机器的Pascal代码：
const
	levmax=3;
	amax=2047; 
type 
	fct=(lit,opr,lod,sto,cal,int,jmp,jpc);
	instruction=packed record 
		f:fct;
		l:0..levmax;
		a:0..amax;
	end;
procedure interpret;
const stacksize = 500;
var
p, b, t: integer; {program-, base-, topstack-registers}
i: instruction; {instruction register}
s: array 1..stacksize of integer; {datastore}
function base(l: integer): integer;
var b1: integer;
begin
b1 := b; {find base l levels down}
while l > 0 do begin
b1 := sb1;
l := l - 1
end;
base := b1
end {base};
begin
writeln(' start pl/0');
t := 0; b := 1; p := 0;
s1 := 0; s2 := 0; s3 := 0;
repeat
i := codep; p := p + 1;
with i do
case f of
lit: begin t := t + 1; st := a end;
opr: 
case a of {operator}
0: 
begin {return}
t := b - 1; p := st + 3; b := st + 2;
end;
1: st := -st;
2: begin t := t - 1; st := st + st + 1 end;
3: begin t := t - 1; st := st - st + 1 end;
4: begin t := t - 1; st := st * st + 1 end;
5: begin t := t - 1; st := st div st + 1 end;
6: st := ord(odd(st));
8: begin t := t - 1; st := ord(st = st + 1) end;
9: begin t := t - 1; st := ord(st  st + 1) end;
10: begin t := t - 1; st := ord(st = st + 1) end;
12: begin t := t - 1; st := ord(st > st + 1) end;
13: begin t := t - 1; st := ord(st 
这个机器是用来运行维尔特的PL/0的，一个为教学开发的Pascal子集编译器。

**注释**

**延伸阅读**
 Steven Pemberton and Martin Daniels:  Pascal Implementation: The P4 Compiler and Interpreterdate=20170813152711 . ISBN 0-85312-358-6; ISBN 0-13-653031-1- Steven Pemberton关于Pascal的网页date=20150219202544 上有P4编译器和解释器的Pascal源代码、使用说明和 编译器的p-code （自身生成的）。- The Jefferson Computer Museum's page on the UCSD p-Systemdate=20150217045428 - 开源实现date=20140524054906 ，包含打包和预编译的二进制文件； Klebsch的实现版本date=20200225210735 的一个友好的fork- Compiling with C# and Java, Pat Terry, 2005, ISBN 0-321-26360-X, 624- Algorithms + Data Structures = Programs, Niklaus Wirth, 1975, ISBN 0-13-022418-9- Compiler Construction, Niklaus Wirth, 1996, ISBN 0-201-40353-6- The Byte Book of Pascal, Blaise W. Liffick, Editor, 1979, ISBN 0-07-037823-1- PASCAL - The Language and its Implementation, Edited by D.W. Barron, 1981, ISBN 0-471-27835-1.  尤其参见文章Pascal-P Implementation Notes和Pascal-S: A Subset and its Implementation.