Select Git revision
ANN_Training.py
-
Laura Christine Kühle authoredLaura Christine Kühle authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
interpreter.py 10.35 KiB
import lexer
import sys
import operator
import re
regex_to_token = [(re.compile(r'\d+'), 'NUMBER'),
(re.compile(r'x\d+'), 'IDENTIFIER'),
(re.compile(r'\+'), 'PLUS'),
(re.compile(r'-'), 'MINUS'),
(re.compile(r':=|≔'), 'EQUALS'),
(re.compile(r'LOOP'), 'LOOP'),
(re.compile(r'DO'), 'DO'),
(re.compile(r'END'), 'END'),
(re.compile(r';'), 'SEMICOLON'),
(re.compile(r'BREAK'), 'BREAK'),
(re.compile(r'\n', re.MULTILINE), 'LINEBREAK'),
(re.compile(r'\s+'), 'WHITESPACE'),
(re.compile(r'[^\n]*'), 'UNKNOWN')]
global error_handler, lex, values
class ErrorHandler:
def __init__(self, program):
sys.tracebacklimit = 0
self.program = program
self.line_number = 0
def handle_error(self, message):
msg = ["Fehler in Zeile " + str(self.line_number + 1),
self.program.split("\n")[self.line_number],
message]
raise SyntaxError("\n".join(msg)) from None
def increase_line(self):
self.line_number += 1
def handle_break(self):
print("BREAK in Zeile " + str(self.line_number))
print("Aktueller Zustand:")
for k,v in values.items():
print("Variable " + k + ": " + str(v))
user_input = input("Drücke ENTER zum Fotfahren oder schreibe EXIT zum Beenden:")
if user_input.lower() == 'exit':
raise KeyboardInterrupt
def process_assignment(value_list, forbidden_identifiers, identifier_token_1):
identifier_1 = identifier_token_1.v
if identifier_1 in forbidden_identifiers:
error_handler.handle_error("Identifier " + identifier_1 +
" ist bereits in Loop vorhanden und darf nicht verwendet werden.")
if next_nonempty_token("Zuweisung", ":=") == 'EQUALS':
error_handler.handle_error(":= in Zuweisung erwartet.")
identifier_token_2 = next_nonempty_token("Zuweisung", "IDENTIFIER (x0, x1, ...) oder NUMBER")
if identifier_token_2.k == 'NUMBER':
value_1 = int(identifier_token_2.v)
value_list.update({identifier_token_1.v: value_1})
return next_token(), value_list
if not identifier_token_2.k == 'IDENTIFIER':
error_handler.handle_error("IDENTIFIER in Zuweisung erwartet.")
identifier_2 = identifier_token_2.v
if identifier_2 in forbidden_identifiers:
error_handler.handle_error("Identifier " + identifier_2 +
" ist bereits in Loop vorhanden und darf nicht verwendet werden.")
if identifier_2 in value_list:
value_2 = value_list.get(identifier_2)
else:
value_2 = 0
operator_token = next_nonempty_token("Zuweisung", "+ oder -")
op = None
if operator_token.k == 'PLUS':
op = operator.__add__
elif operator_token.k == 'MINUS':
op = operator.__sub__
else:
error_handler.handle_error("+ oder - in Zuweisung erwartet.")
number_token = next_nonempty_token("Zuweisung", "NUMBER")
if not number_token.k == 'NUMBER':
error_handler.handle_error("NUMBER in Zuweisung erwartet.")
value_1 = max(0, op(value_2, int(number_token.v)))
value_list.update({identifier_1: value_1})
return next_token(), value_list
def verify_assignment(forbidden_identifiers, identifier_token_1):
identifier_1 = identifier_token_1.v
if identifier_1 in forbidden_identifiers:
error_handler.handle_error("Identifier " + identifier_1 +
" ist bereits in Loop vorhanden und darf nicht verwendet werden.")
if not next_nonempty_token("Zuweisung", ":=").k == 'EQUALS':
error_handler.handle_error(":= in Zuweisung erwartet.")
identifier_token_2 = next_nonempty_token("Zuweisung", "IDENTIFIER (x0, x1, ...) oder NUMBER")
if identifier_token_2.k == 'NUMBER':
return next_token()
if not identifier_token_2.k == 'IDENTIFIER':
error_handler.handle_error("IDENTIFIER in Zuweisung erwartet.")
identifier_2 = identifier_token_2.v
if identifier_2 in forbidden_identifiers:
error_handler.handle_error("Identifier " + identifier_2 +
" ist bereits in Loop vorhanden und darf nicht verwendet werden.")
if next_nonempty_token("Zuweisung", "+ oder -").k not in ['PLUS', 'MINUS']:
error_handler.handle_error("+ oder - in Zuweisung erwartet.")
if not next_nonempty_token("Zuweisung", "NUMBER").k == 'NUMBER':
error_handler.handle_error("NUMBER in Zuweisung erwartet.")
return next_token()
def process_loop(value_list, forbidden_identifiers, loop_token):
identifier_token = next_nonempty_token('LOOP', 'IDENTIFIER (x0, x1, ...)')
if not identifier_token.k == 'IDENTIFIER':
error_handler.handle_error('IDENTIFIER in LOOP erwartet.')
if identifier_token.v in forbidden_identifiers:
error_handler.handle_error('Identifier ' + identifier_token.v +
' ist bereits in Loop vorhanden und darf nicht verwendet werden.')
if not next_nonempty_token("LOOP", "DO").k == 'DO':
error_handler.handle_error('DO in LOOP erwartet.')
if identifier_token.v in value_list:
number_of_loops = int(value_list.get(identifier_token.v))
else:
number_of_loops = 0
saved_position = lex.current_position
saved_line = error_handler.line_number
forbidden_identifiers.append(identifier_token.v)
if number_of_loops == 0:
end_found = False
while not end_found:
token = verify_program(forbidden_identifiers, next_token())
if token is None or token.k not in ['SEMICOLON', 'END']:
error_handler.handle_error("SEMICOLON oder END in LOOP erwartet.")
elif token.k == 'SEMICOLON':
continue
elif token.k == 'END':
end_found = True
for index in range(number_of_loops):
lex.current_position = saved_position
error_handler.line_number = saved_line
end_found = False
while not end_found:
token, value_list = process_program(value_list, forbidden_identifiers, next_token())
if token is None or token.k not in ['SEMICOLON', 'END']:
error_handler.handle_error("SEMICOLON oder END in LOOP erwartet.")
elif token.k == 'SEMICOLON':
continue
elif token.k == 'END':
end_found = True
forbidden_identifiers.remove(identifier_token.v)
return next_token(), value_list
def verify_loop(forbidden_identifiers, loop_token):
identifier_token = next_nonempty_token("LOOP", "IDENTIFIER")
if not identifier_token.k == 'IDENTIFIER':
error_handler.handle_error('IDENTIFIER in LOOP erwartet.')
if identifier_token.v in forbidden_identifiers:
error_handler.handle_error("Identifier " + identifier_token.v +
" ist bereits in Loop vorhanden und darf nicht verwendet werden.")
if not next_nonempty_token("LOOP", "DO").k == 'DO':
error_handler.handle_error('DO in LOOP erwartet.')
forbidden_identifiers.append(identifier_token.v)
end_found = False
while not end_found:
token = verify_program(forbidden_identifiers, next_token())
if token is None or token.k not in ['SEMICOLON', 'END']:
error_handler.handle_error("SEMICOLON oder END in LOOP erwartet.")
elif token.k == 'SEMICOLON':
continue
elif token.k == 'END':
end_found = True
forbidden_identifiers.remove(identifier_token.v)
return next_token()
def process_program(value_list, forbidden_identifiers, current_token):
values = value_list
if current_token is None or current_token.k not in ['IDENTIFIER', 'LOOP']:
error_handler.handle_error("Keine passende Anweisung gefunden\n" +
"Erwartet: IDENTIFIER (x0, x1, ...) oder LOOP")
elif current_token.k == 'IDENTIFIER':
current_token, values = process_assignment(value_list, forbidden_identifiers, current_token)
elif current_token.k == 'LOOP':
current_token, values = process_loop(value_list, forbidden_identifiers, current_token)
return current_token, values
def verify_program(forbidden_identifiers, current_token):
if current_token is None or current_token.k not in ['IDENTIFIER', 'LOOP']:
error_handler.handle_error("Keine passende Anweisung gefunden\n" +
"Erwartet: IDENTIFIER (x0, x1, ...) oder LOOP")
elif current_token.k == 'IDENTIFIER':
current_token = verify_assignment(forbidden_identifiers, current_token)
elif current_token.k == 'LOOP':
current_token = verify_loop(forbidden_identifiers, current_token)
return current_token
def next_token():
new_token = lex.next()
if new_token is None:
return None
elif new_token.k == 'BREAK':
error_handler.handle_break()
return next_token()
elif new_token.k == 'LINEBREAK':
error_handler.increase_line()
return next_token()
elif new_token.k == 'WHITESPACE':
return next_token()
else:
return new_token
def next_nonempty_token(current_function, expected_token):
token = next_token()
if token is None:
error_handler.handle_error("Frühzeitiges Ende von " + current_function + "\n" + "Erwartet: " + expected_token)
return token
def interpret(program):
try:
global error_handler, lex, values
lex = lexer.Lexer(regex_to_token, program)
error_handler = ErrorHandler(program)
values = {}
forbidden_identifiers = []
current_token = next_token()
while current_token is not None:
current_token, values = process_program(values, forbidden_identifiers, current_token)
if current_token is not None:
if not current_token.k == 'SEMICOLON':
error_handler.handle_error("Semicolon erwartet")
current_token = next_token()
if current_token is None:
error_handler.handle_error("Semikolons werden nur zur Trennung und nicht zum " +
"Abschluss von Programmen verwendet")
if "x0" in values:
return values.get("x0")
return 0
except KeyboardInterrupt:
return -1