P-Code
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]
- ↑ N. Wirth, "Compilerbau", Teubner Studienbücher, 2. Auflage, 1981
Weblinks[Bearbeiten | Quelltext bearbeiten]
Wikipedia: P-Code |
Wikipedia: P-code_machine |
Wikipedia: Pascal-P#The_Pascal-P_system |
Wikipedia: UCSD_Pascal |
- ISO 7185 Pascal Source code Webseite mit Download-Link zum Pascal-Sourcecode von PL/0
- PL/0 - Pascal for small machines Webseite mit weiteren Informationen zu PL/0