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.