在電腦科學中,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),[1]但P-code這個詞直到70年代初才首次出現。 1973年Nori, Ammann, Jensen, Hageli和Jacobi編寫的Pascal-P編譯器[2] 和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 := s[b1];
l := l - 1
end;
base := b1
end {base};
begin
writeln(' start pl/0');
t := 0; b := 1; p := 0;
s[1] := 0; s[2] := 0; s[3] := 0;
repeat
i := code[p]; p := p + 1;
with i do
case f of
lit: begin t := t + 1; s[t] := a end;
opr:
case a of {operator}
0:
begin {return}
t := b - 1; p := s[t + 3]; b := s[t + 2];
end;
1: s[t] := -s[t];
2: begin t := t - 1; s[t] := s[t] + s[t + 1] end;
3: begin t := t - 1; s[t] := s[t] - s[t + 1] end;
4: begin t := t - 1; s[t] := s[t] * s[t + 1] end;
5: begin t := t - 1; s[t] := s[t] div s[t + 1] end;
6: s[t] := ord(odd(s[t]));
8: begin t := t - 1; s[t] := ord(s[t] = s[t + 1]) end;
9: begin t := t - 1; s[t] := ord(s[t] <> s[t + 1]) end;
10: begin t := t - 1; s[t] := ord(s[t] < s[t + 1]) end;
11: begin t := t - 1; s[t] := ord(s[t] >= s[t + 1]) end;
12: begin t := t - 1; s[t] := ord(s[t] > s[t + 1]) end;
13: begin t := t - 1; s[t] := ord(s[t] <= s[t + 1]) end;
end;
lod: begin t := t + 1; s[t] := s[base(l) + a] end;
sto: begin s[base(l)+a] := s[t]; writeln(s[t]); t := t - 1 end;
cal:
begin {generate new block mark}
s[t + 1] := base(l); s[t + 2] := b; s[t + 3] := p;
b := t + 1; p := a
end;
int: t := t + a;
jmp: p := a;
jpc: begin if s[t] = 0 then p := a; t := t - 1 end
end {with, case}
until p = 1;
writeln(' end pl/0');
end {interpret};
這個機器是用來執行維爾特的PL/0的,一個為教學開發的Pascal子集編譯器。
註釋
延伸閱讀
Wikiwand in your browser!
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.