Logo des digitalen Schulbuchs inf-schule.de. Schriftzug in Zustandsübergangsdiagramm eines endlichen Automaten.

Station - Erzeugung eines Strukturgerüsts mit dem Parser

Aufgabe des Parsers

Ein Parser hat in der Regel nicht nur die Aufgabe, die Syntax zu überprüfen, ein Parser erzeugt auch für die weitere Verarbeitung eine strukturierte Darstellung des vorgegebenen Programms, sofern es syntaktisch korrekt ist.

Wir betrachten weiterhin den folgenden Quelltext:

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

Ziel ist es, aus diesem Quelltext ein Strukturgerüst zu erstellen:

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

Die Struktur wird hier mit Hilfe von Listen und Tupeln erzeugt.

Erweiterung der Produktionen

Zur Erzeugung des Strukturgerüsts werden die Produktionregeln der Grammatik um Erzeugungsregeln erweitert.

# erweiterte Produktionen

def p_programm_anweisungsfolge_speicherbelegung(p):
    'programm : anweisungsfolge speicherbelegung'
    p[0] = [p[1], p[2]]

def p_anweisungsfolge_anweisung_anweisungsfolge(p):
    'anweisungsfolge : anweisung anweisungsfolge'
    p[0] = [p[1]] + p[2]

def p_anweisungsfolge_anweisung(p):
    'anweisungsfolge : anweisung'
    p[0] = [p[1]]

def p_anweisung_inc(p):
    'anweisung : ZAHL DP INC ZAHL'
    p[0] = (eval(p[1]), p[3], eval(p[4]))

def p_anweisung_dec(p):
    'anweisung : ZAHL DP DEC ZAHL'
    p[0] = (eval(p[1]), p[3], eval(p[4]))

def p_anweisung_jmp(p):
    'anweisung : ZAHL DP JMP ZAHL'
    p[0] = (eval(p[1]), p[3], eval(p[4]))

def p_anweisung_tst(p):
    'anweisung : ZAHL DP TST ZAHL'
    p[0] = (eval(p[1]), p[3], eval(p[4]))

def p_anweisung_hlt(p):
    'anweisung : ZAHL DP HLT'
    p[0] = (eval(p[1]), p[3])

def p_speicherbelegung_kommentar_anweisungsfolge(p):
    'speicherbelegung : KO ZAHL speicherbelegung'
    p[0] = [eval(p[2])] + p[3]

def p_speicherbelegung(p):
    'speicherbelegung : '
    p[0] = []

# Fehlermeldung
def p_error(p):
    print("Syntaxfehler!")

Wie die Erzeugung des Strukturgerüsts funktioniert, wird ausführlich z.B. im Abschnitt Station - Erzeugung eines Strukturgerüsts mit dem Parser erklärt.

Verwendung von YACC

Das Programm YACC (der Implementierung PLY) ist in der Lage, aus den erweiterten Produktionen das Strukturgerüst eines MiniPython-Programms zu erstellen.

Wir gehen im Folgenden davon aus, dass die Datei syntaxBonsai.py die regulären Ausdrücke zur Beschreibung der Token und die erweiterten Produktionen (s.o.) der Grammatik der Sprache MyWhile enthält. Mit dem gezeigten Testprogramm können jetzt MyWhileList-Programme erstellt werden.

import ply.lex as lex
import ply.yacc as yacc
from syntaxBonsai 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
scanner = lex.lex(debug=0)
# Erzeugung des Parsers
parser = yacc.yacc(debug=False)

# syntaktische Analyse mit Erzeugung des Strukturbaums
if len(quelltext) != 0:
    strukturbaum = parser.parse(quelltext, debug=0)
else:
    strukturbaum = []

# Ausgabe
print(strukturbaum)

Aufgabe 1

Probiere das selbst einmal aus. Lade hierzu die Datei bonsai3.zip herunter und entpacke sie. Führe anschließend die Datei test_parser.py aus. Teste verschiedene Quelltexte, die syntaktisch korrekt sind.

Aufgabe 3

Im Abschnitt Zusammenfassung - JOHNNY-Maschinensprache wird die Maschinensprache des JOHHNY-Rechners erläutert. Entwickle einen Parser zur Erzeugung eines Strukturgerüsts für diese Sprache.

X

Fehler melden

X

Suche