P-Code

Aus C64-Wiki
Zur Navigation springenZur Suche springen

P-Code ist ein Befehlssatz, der typischerweise von einem Interpreter ausgeführt wird. P-Code-Programme werden meist durch Kompilieren aus einem in einer anderen Programmiersprache geschriebenen Programm erzeugt.

Eine bekannte Implementierung von P-Code ist Pascal-P, speziell in seiner der Version von UCSD Pascal.

Im Zusammenhang mit dem C64 wird auch von BASIC-Compilern erzeugter Code häufig als P-Code bezeichnet (insbesondere auch als Abgrenzung zu von manchen Compilern erzeugtem M-Code/Maschinencode, der direkt - ohne Interpreter - von der CPU ausgeführt wird), auch wenn dieser nichts mit dem P-Code von UCSD Pascal zu tun hat.

P-Code kann als früher Vorläufer des Bytecodes der Java Virtual Machine (JVM) verstanden werden.

Beispiel in PL/0[Bearbeiten | Quelltext bearbeiten]

Zur Veranschaulichung eines einfachen P-Codes soll hier ein kleines Beispielprogramm in PL/0 dienen.[1]

var
 x, y;
begin
    x := 3;
    y := 3;
    x := 5 + (2 + x) * 4;
    x := 4 * (2 + x) + 5;
    y := x - y;
end.

Der Compiler erzeugt aus dem Beispielprogramm den folgenden P-Code. Die virtuelle Maschine zur Ausführung des P-Codes ist Stack-basiert und hat gewisse Ähnlichkeiten mit Forth. D.h. bei arithmetischen Operationen wie z.B. Addition werden die beiden zuletzt auf dem Stack abgelegten Werte addiert und durch das Ergebnis der Addition ersetzt. Auch beim Speichern in einer Variablen wird der Wert vom Stack genommen und in der Speicherstelle der Variablen abgelegt.

0000    jmp    0    1   ; zur Position 0001 springen
0001    int    0    5   ; Platz für die Variablen anlegen
0002    lit    0    3   ; Wert 3 auf den Stack legen ...
0003    sto    0    3   ; ... und in der Variablen X speichern
0004    lit    0    3   ; Wert 3 auf den Stack legen ...
0005    sto    0    4   ; ... und in der Variablen Y speichern
0006    lit    0    5   ; Wert 5 auf den Stack legen
0007    lit    0    2   ; Wert 2 auf den Stack legen
0008    lod    0    3   ; Variable X laden
0009    opr    0    2   ; Addition: X + 2
0010    lit    0    4   ; Wert 4 auf den Stack legen
0011    opr    0    4   ; Multiplikation: (X + 2) * 4
0012    opr    0    2   ; Addition: 5 + (X + 2) * 4
0013    sto    0    3   ; Wert (25) in der Variablen X speichern
0014    lit    0    4   ; Wert 4 auf den Stack legen
0015    lit    0    2   ; Wert 2 auf den Stack legen
0016    lod    0    3   ; Variable X laden
0017    opr    0    2   ; Addition: (X + 2)
0018    opr    0    4   ; Multiplikation: 4 * (X + 2)
0019    lit    0    5   ; Wert 5 auf den Stack legen
0020    opr    0    2   : Addition: 4 * (X + 2) + 5
0021    sto    0    3   ; Wert (113) in der Variablen X speichern
0022    lod    0    3   ; Variable X laden
0023    lod    0    4   ; Variable Y laden
0024    opr    0    3   ; Substraktion: X - Y
0025    sto    0    4   ; Wert (110) in der Variablen Y speichern
0026    opr    0    0   ; Programmende (return)

Jedes Mal, wenn ein Wert mit dem Befehl sto in einer Variablen gespeichert wird, gibt der Interpreter den Wert auf dem Bildschirm aus:

START PL/0
3
3
25
113
110
END PL/0

Niklaus Wirth hat den Compiler und Interpreter vollständig in Pascal geschrieben (Quellcode siehe Weblinks). Nachfolgend eine reduzierte Version des Interpreters für G-Pascal, der in der Lage ist, das hier dargestellte Beispiel auszuführen:

CONST
  CXMAX=100;
  (* OPCODES *)
  LIT=1; OPR=2; LOD=3; STO=4;
  INT=6; JMP=7;
  (* OPR ARGUMENTS *)
  NEG=1; ADD=2; SUB=3; MUL=4;
  DIVIS=5; RET=0;

VAR
  CODEFCT: ARRAY [CXMAX] OF INTEGER ;
  CODEA: ARRAY [CXMAX] OF INTEGER ;

PROCEDURE INTERPRET;

  CONST STACKSIZE=200;

  VAR
    P,B,T: INTEGER ;
    IFCT, IA: INTEGER ;
    S: ARRAY [STACKSIZE] OF INTEGER ;

  BEGIN
    WRITELN ("START PL/0");
    T:=0; B:=1; P:=0;
    S[0]:=0;
    S[1]:=0; S[2]:=0; S[3]:=0;
    REPEAT
      IFCT:=CODEFCT[P];
      IA:=CODEA[P];
      P:=P + 1;
      CASE IFCT OF
        LIT:
          BEGIN
            T:=T + 1;
            S[T]:=IA;
          END ;
        OPR:
          CASE IA OF (* OPERATOR *)
            RET:
              BEGIN
                T:=B - 1;
                P:=S[T + 3];
                B:=S[T + 2];
              END ;
            NEG:
              S[T]:=- S[T];
            ADD:
              BEGIN
                T:=T - 1;
                S[T]:=S[T] + S[T + 1];
              END ;
            SUB:
              BEGIN
                T:=T - 1;
                S[T]:=S[T] - S[T + 1];
              END ;
            MUL:
              BEGIN
                T:=T - 1;
                S[T]:=S[T] * S[T + 1];
              END ;
            DIVIS:
              BEGIN
                T:=T - 1;
                S[T]:=S[T] DIV S[T + 1];
              END
          END ; (* END CASE IA OF *)
        LOD:
          BEGIN
            T:=T + 1;
            S[T] := S[1 + IA];
          END ;
        STO:
          BEGIN
            S[1 + IA] := S[T];
            WRITELN ("> ",S[T]);
            T:=T - 1;
          END ;
        INT:
          T:=T + IA;
        JMP:
          P:=IA
      END ;
    UNTIL P=0;
    WRITELN ("END PL/0")
  END ;

BEGIN
  CODEFCT[0]:=JMP; CODEA[0]:=1;
  CODEFCT[1]:=INT; CODEA[1]:=5;
  CODEFCT[2]:=LIT; CODEA[2]:=3;
  CODEFCT[3]:=STO; CODEA[3]:=3;
  CODEFCT[4]:=LIT; CODEA[4]:=3;
  CODEFCT[5]:=STO; CODEA[5]:=4;
  CODEFCT[6]:=LIT; CODEA[6]:=5;
  CODEFCT[7]:=LIT; CODEA[7]:=2;
  CODEFCT[8]:=LOD; CODEA[8]:=3;
  CODEFCT[9]:=OPR; CODEA[9]:=ADD;
  CODEFCT[10]:=LIT; CODEA[10]:=4;
  CODEFCT[11]:=OPR; CODEA[11]:=MUL;
  CODEFCT[12]:=OPR; CODEA[12]:=ADD;
  CODEFCT[13]:=STO; CODEA[13]:=3;
  CODEFCT[14]:=LIT; CODEA[14]:=4;
  CODEFCT[15]:=LIT; CODEA[15]:=2;
  CODEFCT[16]:=LOD; CODEA[16]:=3;
  CODEFCT[17]:=OPR; CODEA[17]:=ADD;
  CODEFCT[18]:=OPR; CODEA[18]:=MUL;
  CODEFCT[19]:=LIT; CODEA[19]:=5;
  CODEFCT[20]:=OPR; CODEA[20]:=ADD;
  CODEFCT[21]:=STO; CODEA[21]:=3;
  CODEFCT[22]:=LOD; CODEA[22]:=3;
  CODEFCT[23]:=LOD; CODEA[23]:=4;
  CODEFCT[24]:=OPR; CODEA[24]:=SUB;
  CODEFCT[25]:=STO; CODEA[25]:=4;
  CODEFCT[26]:=OPR; CODEA[26]:=RET;
  INTERPRET;
END .

Quellen[Bearbeiten | Quelltext bearbeiten]

  1. N. Wirth, "Compilerbau", Teubner Studienbücher, 2. Auflage, 1981

Weblinks[Bearbeiten | Quelltext bearbeiten]

WP-W11.png Wikipedia: P-Code
WP-W11.png Wikipedia: P-code_machine Sprache:english
WP-W11.png Wikipedia: Pascal-P#The_Pascal-P_system Sprache:english
WP-W11.png Wikipedia: UCSD_Pascal Sprache:english