計算機科學中,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

環境

與其他基於堆棧的環境(如ForthJava虛擬機)不同的是,p-系統非常類似於真正的目標CPU,它只有一個堆棧供過程棧幀(提過返回地址等)和局部指令參數共享。機器的其中三個寄存器指向這個堆棧(向上增加):

第五個寄存器 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子集編譯器。

注釋

  1. ^ Wirth, N.; Weber, H. EULER: a generalization of ALGOL, and its formal definition: Part II, Communications of the Association for Computing Machinery, Vol.9, No.2, pp.89-99. New York: ACM. 1966. [永久失效連結]
  2. ^ Nori, K.V.; Ammann, U.; Jensen, K.; Nageli, H. The Pascal P Compiler Implementation Notes. Zurich: Eidgen. Tech. Hochschule. 1975. 

延伸閱讀