Station - Ein Interpreter für Bonsai-Assemblerprogramme

Aufgabe des Interpreters

Aufgabe des Interpretes ist es, Bonsai-Assemblerprogramme - die als Strukturgerüste vorliegen - Schritt für Schritt auszuführen.

Die Arbeitsweise des Interpreters soll am folgenden Beispiel-Programm verdeutlicht werden.

0: tst 1
1: jmp 3 
2: jmp 6
3: dec 1
4: inc 0
5: jmp 0
6: hlt
#3
#5

Das Strukturgerüst zu diesem Quelltext sieht so aus:

[
    [(0, 'tst', 1),
     (1, 'jmp', 3), 
     (2, 'jmp', 6), 
     (3, 'dec', 1), 
     (4, 'inc', 0), 
     (5, 'jmp', 0), 
     (6, 'hlt')], 
    [3, 5]
]

Der Interpreter führt die Befehle des Programms Schritt für Schritt aus und verändert dabei die Registerbelegung (bzw. den Datenteil).

aktueller Befehl aktuelle Daten

(0, 'tst', 1)    [3, 5]

(1, 'jmp', 3)    [3, 5]

(3, 'dec', 1)    [3, 5]

(4, 'inc', 0)    [3, 4]

(5, 'jmp', 0)    [4, 4]

(0, 'tst', 1)    [4, 4]

(1, 'jmp', 3)    [4, 4]

(3, 'dec', 1)    [4, 3]

(4, 'inc', 0)    [5, 3]

(5, 'jmp', 0)    [5, 3]

...

(5, 'jmp', 0)    [8, 0]

(0, 'tst', 1)    [8, 0]

(2, 'jmp', 6)    [8, 0]

(6, 'hlt')       [8, 0]

Alles klar?

Bei der Verarbeitung muss jeweils die "richtige" Befehlszeile ausgewählt werden. Diese jeweils aktuelle Befehlszeile kann man mit einem sogenannten Programmzähler (kurz PC für program counter) verwalten. Die Abarbeitung des oben gezeigten Programms kann mit dem PC auch so beschrieben werden:

PC Daten

0  [3, 5]

1  [3, 5]

3  [3, 5]

4  [3, 4]

5  [4, 4]

0  [4, 4]

1  [4, 4]

3  [4, 3]

4  [5, 3]

5  [5, 3]

...

5  [8, 0]

0  [8, 0]

2  [8, 0]

6  [8, 0]

Implementierung des Interpreters

Der Interpreter wird durch ein Objekt der Klasse Interpreter realisiert. Dieses Objekt verfügt insbesondere über eine Methode anweisungAusfuehren, die letztlich für das Auswerten von Anweisungen zuständig ist.

class Interpreter(object):
    def __init__(self):
        self.programm = None
        self.pc = 0
        self.daten = None

    def initProgrammDaten(self, strukturbaum):
        self.programm = strukturbaum[0]
        self.pc = 0
        self.daten = strukturbaum[1]

    def getProgramm(self):
        return self.programm

    def getAktuelleAnweisung(self, nummer):
        aktuelleAnweisung = None
        for anweisung in self.programm:
            if anweisung[0] == nummer:
                aktuelleAnweisung = anweisung
        return aktuelleAnweisung

    def getPC(self):
        return self.pc

    def anweisungAusfuehren(self, anweisung):
        op = anweisung[1] 
        if op == 'hlt':
            pass
        else:
            adr = anweisung[2]     
            if op == 'inc':
                self.daten[adr] = self.daten[adr] + 1
                self.pc = self.pc + 1
            elif op == 'dec':
                if self.daten[adr] > 0:
                    self.daten[adr] = self.daten[adr] - 1
                else:
                    print('Fehler - kein Dekrementieren möglich')
                    exit() 
                self.pc = self.pc + 1
            elif op == 'jmp':
                self.pc = adr
            elif op == 'tst':           
                if self.daten[adr] != 0:
                    self.pc = self.pc + 1
                else:
                    self.pc = self.pc + 2

    def programmAusfuehren(self):
        aktuelleAnweisung = self.getAktuelleAnweisung(self.pc)
        op = aktuelleAnweisung[1]
        protokoll = [aktuelleAnweisung, self.daten]
        while op != 'hlt':
            self.anweisungAusfuehren(aktuelleAnweisung)
            aktuelleAnweisung = self.getAktuelleAnweisung(self.pc)
            op = aktuelleAnweisung[1] 
            protokoll = protokoll + [aktuelleAnweisung, self.daten]
        return protokoll

Objekte der vorgestellten Klassen können jetzt direkt genutzt werden, um Bonsai-Assemblerprogramme - dargestellt in Form eines Strukturgerüsts - auszuführen.

import ply.lex as lex
import ply.yacc as yacc
from syntaxBonsai import *
from interpreter import *

# Testprogramm
quelltext = '''
0: tst 1
1: jmp 3 
2: jmp 6
3: dec 1
4: inc 0
5: jmp 0
6: hlt
#3
#5
'''

# Erzeugung des Scanners
scannerBonsai = lex.lex(debug=0)
# Erzeugung des Parsers
parserBonsai = yacc.yacc(debug=False)
# Aktivierung von Scanner und Parser
strukturbaum = parserBonsai.parse(quelltext, debug=0)
# Erzeugung des Interpreters
interpreter = Interpreter()
# Aktivierung des Interpreters
interpreter.initProgrammDaten(strukturbaum)
protokoll = interpreter.programmAusfuehren()
# Ausgabe
for zeile in protokoll:
    print(zeile)

Aufgabe 1

Probiere das selbst einmal aus. Lade hierzu die Datei bonsai4.zip herunter und entpacke sie. Führe anschließend die Datei test_interpreter.py aus. Teste verschiedene Quelltexte.

X

Fehler melden

X

Suche