From 3047fa72a6e05233b37a305c6ccb6524b55c8618 Mon Sep 17 00:00:00 2001 From: Chris <Christopher.Happe@uni-duesseldorf.de> Date: Mon, 21 Dec 2020 09:29:05 +0100 Subject: [PATCH] =?UTF-8?q?Feature:=20Homeomorphic=20Embedding=20f=C3=BCr?= =?UTF-8?q?=20Interpreter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kapitel-8/Interpreter/gotointerpreter.py | 17 +++++++-- .../kapitel-8/Interpreter/loopinterpreter.py | 3 ++ .../Interpreter/test_goto_interpreter.py | 8 ++++ .../Interpreter/test_while_interpreter.py | 7 ++++ .../kapitel-8/Interpreter/whileinterpreter.py | 37 +++++++++++++++++-- 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/info4/kapitel-8/Interpreter/gotointerpreter.py b/info4/kapitel-8/Interpreter/gotointerpreter.py index f8cbb86..5ef4fb6 100644 --- a/info4/kapitel-8/Interpreter/gotointerpreter.py +++ b/info4/kapitel-8/Interpreter/gotointerpreter.py @@ -1,6 +1,7 @@ import lexer from loopinterpreter import ErrorHandler from whileinterpreter import Timeout +from whileinterpreter import State import re import operator @@ -126,6 +127,13 @@ class GOTOInterpreter: self.error_handler.handle_error('GOTO zu nicht vorhandener Markierung') self.lex.current_position = self.marker_to_position.get(marker_number) self.error_handler.line_number = self.marker_to_line.get(marker_number) + if self.test_homeomorphic_embedding: + new_state = State(self.lex.current_position, self.values) + for state in self.state_list: + + if state.less_or_equal(new_state): + self.error_handler.handle_endless_loop() + self.state_list.append(new_state) return self.next_token() def verify_goto(self, goto_token): @@ -261,12 +269,14 @@ class GOTOInterpreter: current_token = self.verify_halt(current_token) return current_token - def interpret(self, program, values=None): + def interpret(self, program, values=None, test_homeomorphic_embedding=False): try: with Timeout(self.timeout): self.halted = False self.lex = lexer.Lexer(self.regex_to_token, program) self.error_handler = ErrorHandler(program, self) + self.state_list = [] + self.test_homeomorphic_embedding = test_homeomorphic_embedding self.values=values if values is None: self.values = {} @@ -284,7 +294,7 @@ class GOTOInterpreter: return -1 -def interpret(program, value_list=None, timeout=60): +def interpret(program, value_list=None, timeout=60, debug=False): """Funktion zum Ausführen eines GOTO-Programms. :param program: GOTO-Programm als String 'M1: A1; M2: A2; ... Mn: An;' :param value_list: Array von Integern ([v1, ..., vn]). @@ -292,6 +302,7 @@ def interpret(program, value_list=None, timeout=60): :param timeout: Zeit nach der die Ausführung eines Programms pausiert wird. Gibt eine Möglichkeit zum Abbrechen bei einer Endlosschleife. Ein Wert von 0 deaktiviert den Timeout. + :param debug Boolean der angibt ob mit Homeomorphic Embedding auf mögliche Endlosschleifen geprüft werden soll. :returns integer: Gibt bei Abbruch -1 und sonst den Wert von x0 nach dem GOTO-Programm zurück. :usage interpret('M1: x0 := x0 + 1; M2: IF x0 = 10 THEN GOTO M4; M3: GOTO M1; M4: HALT;')""" interpreter = GOTOInterpreter(timeout) @@ -302,7 +313,7 @@ def interpret(program, value_list=None, timeout=60): if not isinstance(value, int) or value < 0 or not int(value) == value: raise ValueError("Variablen können nur natürliche Zahlen zugewiesen bekommen.") values.update({'x' + str(index + 1): value}) - return interpreter.interpret(program, values) + return interpreter.interpret(program, values, debug) if __name__ == '__main__': diff --git a/info4/kapitel-8/Interpreter/loopinterpreter.py b/info4/kapitel-8/Interpreter/loopinterpreter.py index 69b8b3e..68823fe 100644 --- a/info4/kapitel-8/Interpreter/loopinterpreter.py +++ b/info4/kapitel-8/Interpreter/loopinterpreter.py @@ -31,6 +31,9 @@ class ErrorHandler: if user_input.lower() == 'exit': raise KeyboardInterrupt + def handle_endless_loop(self): + self.handle_error("Mögliche Endlosschleife gefunden.") + class LOOPInterpreter: def __init__(self): diff --git a/info4/kapitel-8/Interpreter/test_goto_interpreter.py b/info4/kapitel-8/Interpreter/test_goto_interpreter.py index 1f09335..8c11924 100644 --- a/info4/kapitel-8/Interpreter/test_goto_interpreter.py +++ b/info4/kapitel-8/Interpreter/test_goto_interpreter.py @@ -206,3 +206,11 @@ class GOTOInterpreterTest(TestCase): interpret('M1: x0:=1;', [0.2]) with self.assertRaises(ValueError): interpret('M1: x0:=4;', ['EINS']) + + def test_homeomorphic_embedding(self): + with self.assertRaises(SyntaxError): + interpret('M1: x1:=1; M2: IF x1 = 0 THEN GOTO M5;' + 'M3: x1:=x1+1; M4: GOTO M2; M5: HALT;', timeout=0, debug=True) + with self.assertRaises(SyntaxError): + interpret('M1: x1:=100; M2: IF x1 = 0 THEN GOTO M5;' + 'M3: x1:=x1+1; M4: GOTO M2; M5: HALT;', timeout=0, debug=True) diff --git a/info4/kapitel-8/Interpreter/test_while_interpreter.py b/info4/kapitel-8/Interpreter/test_while_interpreter.py index 01fbedf..3fab6da 100644 --- a/info4/kapitel-8/Interpreter/test_while_interpreter.py +++ b/info4/kapitel-8/Interpreter/test_while_interpreter.py @@ -133,3 +133,10 @@ class WHILEInterpreterTest(LOOPInterpreterTest): interpret('x0:=1', [0.2]) with self.assertRaises(ValueError): interpret('x0:=4', ['EINS']) + + def test_homeomorphic_embedding(self): + with self.assertRaises(SyntaxError): + interpret('x1:=1; WHILE x1 != 0 DO x1:=x1+1 END', timeout=0, debug=True) + with self.assertRaises(SyntaxError): + interpret('''x1:=100; WHILE x1 != 0 DO x1:=x1-1 END; + x1 = 1; WHILE x1 != 0 DO x1:=x1+1 END''', timeout=0, debug=True) diff --git a/info4/kapitel-8/Interpreter/whileinterpreter.py b/info4/kapitel-8/Interpreter/whileinterpreter.py index 407d5e5..d5121ca 100644 --- a/info4/kapitel-8/Interpreter/whileinterpreter.py +++ b/info4/kapitel-8/Interpreter/whileinterpreter.py @@ -3,7 +3,7 @@ from loopinterpreter import LOOPInterpreter, ErrorHandler import re import signal from IPython.display import clear_output - +from copy import deepcopy class Timeout: def __init__(self, time): @@ -29,6 +29,25 @@ Möchten sie abbrechen? [J,n]:''') except EOFError: pass +class State: + def __init__(self, linenumber, values): + self.values = deepcopy(values) + self.linenumber = linenumber + + def less_or_equal(self, other): + if self.linenumber > other.linenumber: + return False + values1 = self.values + values2 = other.values + different_keys = [k for k in values1 if values1.get(k) != values2.get(k)] +\ + [k for k in values2 if values1.get(k) is None] + + for key in different_keys: + if values1.get(key) > 0 and (values2.get(key) is None or values2.get(key) < values1.get(key)): + return False + + return True + class WHILEInterpreter(LOOPInterpreter): def __init__(self, timeout=60): @@ -112,6 +131,13 @@ class WHILEInterpreter(LOOPInterpreter): end_found = True while not while_value == 0: + if self.test_homeomorphic_embedding: + new_state = State(self.lex.current_position, self.values) + for state in self.state_list: + if state.less_or_equal(new_state): + self.error_handler.handle_endless_loop() + self.state_list.append(new_state) + self.lex.current_position = saved_position self.error_handler.line_number = saved_line end_found = False @@ -159,11 +185,13 @@ class WHILEInterpreter(LOOPInterpreter): return self.next_token() - def interpret(self, program, values=None): + def interpret(self, program, values=None, test_homeomorphic_embedding=False): try: with Timeout(self.timeout): self.lex = lexer.Lexer(self.regex_to_token, program) self.error_handler = ErrorHandler(program, self) + self.test_homeomorphic_embedding = test_homeomorphic_embedding + self.state_list = [] self.values = values if values is None: self.values = {} @@ -187,7 +215,7 @@ class WHILEInterpreter(LOOPInterpreter): return -1 -def interpret(program, value_list=None, timeout=60): +def interpret(program, value_list=None, timeout=60, debug=False): """Funktion zum Ausführen eines WHILE-Programms. :param program: WHILE-Programm als String 'x1:=10; x2:=8; x0:=x2+0; WHILE x1 /=0 DO x0:=x0+1; x1:=x1-1 END' :param value_list: Array von Integern ([v1, ..., vn]). @@ -195,6 +223,7 @@ def interpret(program, value_list=None, timeout=60): :param timeout: Zeit nach der die Ausführung eines Programms pausiert wird. Gibt eine Möglichkeit zum Abbrechen bei einer Endlosschleife. Ein Wert von 0 deaktiviert den Timeout. + :param debug: Boolean der angibt ob mit Homeomorphic Embedding auf mögliche Endlosschleifen geprüft werden soll. :returns integer: Gibt bei Abbruch -1 und sonst den Wert von x0 nach dem WHILE-Programm zurück. :usage interpret('x1:=10; x2:=8; x0:=x2+0; WHILE x1 /=0 DO x0:=x0+1; x1:=x1-1 END')""" interpreter = WHILEInterpreter(timeout) @@ -205,7 +234,7 @@ def interpret(program, value_list=None, timeout=60): if not isinstance(value, int) or value < 0 or not int(value) == value: raise ValueError("Variablen können nur natürliche Zahlen zugewiesen bekommen.") values.update({'x' + str(index+1): value}) - return interpreter.interpret(program, values) + return interpreter.interpret(program, values, debug) if __name__ == '__main__': -- GitLab