-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompiler.py
More file actions
176 lines (151 loc) · 5.17 KB
/
compiler.py
File metadata and controls
176 lines (151 loc) · 5.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import re
# Lexer: Zerlegt den Code in Tokens
def lexer(code):
"""
Lexer-Funktion, die den Quellcode in eine Liste von Tokens umwandelt.
Ein Token ist eine eindeutige Einheit (wie Schlüsselwörter, Variablennamen, Operatoren etc.).
Parameter:
code (str): Der Quellcode, der lexikalisch analysiert werden soll.
Returns:
list: Eine Liste von Tokens, jedes Token ist ein Tupel aus (Token-Typ, Wert).
"""
tokens = []
token_specification = [
('COMMAND', r'\b(PRINT|SET|ADD|SUB)\b'), # Befehle wie PRINT, SET, ADD, SUB
('NUMBER', r'\d+(\.\d*)?'), # Integer oder Dezimalzahl
('ASSIGN', r'='), # Zuweisungsoperator
('END', r';'), # Zeilenende
('ID', r'[A-Za-z]+'), # Bezeichner (Variablenname)
('OP', r'[+\-*/]'), # Arithmetische Operatoren
('WHITESPACE', r'[ \t]+'), # Leerzeichen (ignoriert)
('NEWLINE', r'\n'), # Neue Zeile
]
token_re = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
for match in re.finditer(token_re, code):
token_type = match.lastgroup
value = match.group()
if token_type != 'WHITESPACE': # Ignoriere Leerzeichen
tokens.append((token_type, value))
return tokens
# Abstract Syntax Tree (AST) Klassen
class AST:
"""Basisklasse für alle Knoten im Abstract Syntax Tree (AST)."""
pass
class BinOp(AST):
def __init__(self, left, op, right):
self.left = left
self.op = op
self.right = right
class Num(AST):
def __init__(self, value):
self.value = value
class Assign(AST):
def __init__(self, var, expr):
self.var = var
self.expr = expr
class PrintCommand(AST):
def __init__(self, var):
self.var = var
class AddCommand(AST):
def __init__(self, var, value):
self.var = var
self.value = value
class SubCommand(AST):
def __init__(self, var, value):
self.var = var
self.value = value
# Parser: Erstellt einen AST aus Tokens
def parse(tokens):
it = iter(tokens)
token = next(it, None)
def eat(expected_type):
nonlocal token
if token and token[0] == expected_type:
old_token = token
token = next(it, None)
return old_token
else:
raise SyntaxError(f"Expected {expected_type}")
def expr():
left = term()
while token and token[0] == 'OP':
op = eat('OP')
right = term()
left = BinOp(left, op[1], right)
return left
def term():
if token[0] == 'NUMBER':
value = eat('NUMBER')
return Num(float(value[1]))
elif token[0] == 'ID':
return eat('ID')
def assignment():
var = eat('ID')
eat('ASSIGN')
value = expr()
eat('END')
return Assign(var[1], value)
def command():
cmd_token = eat('COMMAND')
if cmd_token[1] == 'PRINT':
var = eat('ID')
eat('END')
return PrintCommand(var[1])
elif cmd_token[1] == 'SET':
var = eat('ID')
eat('ASSIGN')
value = expr()
eat('END')
return Assign(var[1], value)
elif cmd_token[1] == 'ADD':
var = eat('ID')
value = expr()
eat('END')
return AddCommand(var[1], value)
elif cmd_token[1] == 'SUB':
var = eat('ID')
value = expr()
eat('END')
return SubCommand(var[1], value)
while token:
if token[0] == 'COMMAND':
yield command()
else:
yield assignment()
# Interpreter-Klasse
class Interpreter:
def __init__(self):
self.variables = {}
def visit(self, node):
if isinstance(node, Num):
return node.value
elif isinstance(node, BinOp):
left = self.visit(node.left)
right = self.visit(node.right)
if node.op == '+':
return left + right
elif node.op == '-':
return left - right
elif node.op == '*':
return left * right
elif node.op == '/':
return left / right
elif isinstance(node, Assign):
value = self.visit(node.expr)
self.variables[node.var] = value
return value
elif isinstance(node, PrintCommand):
print(f"Wert von {node.var}: {self.variables.get(node.var, 'undefiniert')}")
elif isinstance(node, AddCommand):
self.variables[node.var] += self.visit(node.value)
elif isinstance(node, SubCommand):
self.variables[node.var] -= self.visit(node.value)
# Beispiel
if __name__ == "__main__":
code = input("Gib den Code ein, den du ausführen möchtest (z. B. 'SET x = 10; ADD x 5; PRINT x;'): ")
tokens = lexer(code)
print("Tokens:", tokens)
interpreter = Interpreter()
# Mehrere Anweisungen parsen und ausführen
for ast in parse(tokens):
interpreter.visit(ast)