diff --git a/info4/kapitel-8/Interpreter/gotointerpreter.py b/info4/kapitel-8/Interpreter/gotointerpreter.py index 1fbeaf031db79fe600c309a56b19c65b47540987..f8cbb8674eb737770535b698964b9100d8903ae4 100644 --- a/info4/kapitel-8/Interpreter/gotointerpreter.py +++ b/info4/kapitel-8/Interpreter/gotointerpreter.py @@ -261,13 +261,15 @@ class GOTOInterpreter: current_token = self.verify_halt(current_token) return current_token - def interpret(self, program): + def interpret(self, program, values=None): try: with Timeout(self.timeout): self.halted = False self.lex = lexer.Lexer(self.regex_to_token, program) self.error_handler = ErrorHandler(program, self) - self.values = {} + self.values=values + if values is None: + self.values = {} current_token = self.next_token() while current_token is not None: current_token = self.process_line(current_token) @@ -282,16 +284,25 @@ class GOTOInterpreter: return -1 -def interpret(program, timeout=60): +def interpret(program, value_list=None, timeout=60): """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]). + Das GOTO-Programm startet mit diesen Werten in x1, ..., xn. :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. :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) - return interpreter.interpret(program) + values = None + if value_list is not None: + values = {} + for index, value in enumerate(value_list): + 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) if __name__ == '__main__': diff --git a/info4/kapitel-8/Interpreter/loopinterpreter.py b/info4/kapitel-8/Interpreter/loopinterpreter.py index 36c7c2c68d4c56e942c280a50bca8828b5e8ec5b..69b8b3e3a763bf73655022a9979a942125486e8f 100644 --- a/info4/kapitel-8/Interpreter/loopinterpreter.py +++ b/info4/kapitel-8/Interpreter/loopinterpreter.py @@ -225,11 +225,13 @@ class LOOPInterpreter: 'Frühzeitiges Ende von ' + current_function + '\n' + 'Erwartet: ' + expected_token) return token - def interpret(self, program): + def interpret(self, program, values=None): try: self.lex = lexer.Lexer(self.regex_to_token, program) self.error_handler = ErrorHandler(program, self) - self.values = {} + self.values = values + if values is None: + self.values = {} forbidden_identifiers = [] current_token = self.next_token() while current_token is not None: @@ -250,13 +252,22 @@ class LOOPInterpreter: return -1 -def interpret(program): +def interpret(program, value_list=None): """Funktion zum Ausführen eines LOOP-Programms. :param program: LOOP-Programm als String 'x1 := 4; LOOP x1 DO x0:=x0+1 END' + :param value_list: Array von Integern ([v1, ..., vn]). + Das LOOP-Programm startet mit diesen Werten in x1, ..., xn. :returns integer: Gibt bei Abbruch -1 und sonst den Wert von x0 nach dem LOOP-Programm zurück. :usage interpret('x1:=10; x2:=8; x0:=x2+0; LOOP x1 DO x0:=x0+1 END')""" interpreter = LOOPInterpreter() - return interpreter.interpret(program) + values = None + if value_list is not None: + values = {} + for index, value in enumerate(value_list): + 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) if __name__ == '__main__': diff --git a/info4/kapitel-8/Interpreter/test_goto_interpreter.py b/info4/kapitel-8/Interpreter/test_goto_interpreter.py index 568e2a8423a3c2ef16e3edd9cd7fa542b51e8080..1f0933508018ec170316aa58b790e94c5bb79920 100644 --- a/info4/kapitel-8/Interpreter/test_goto_interpreter.py +++ b/info4/kapitel-8/Interpreter/test_goto_interpreter.py @@ -7,6 +7,10 @@ def input_continue(prompt): return '' +def str_yes(prompt): + return 'J' + + def input_exit(prompt): return 'EXIT' @@ -182,3 +186,23 @@ class GOTOInterpreterTest(TestCase): def test_end_without_halt(self): with self.assertRaises(SyntaxError): interpret('M1: x0:=2;') + + @mock.patch('whileinterpreter.input', side_effect=str_yes) + def test_infinite_loop(self, custom_input): + self.assertEqual(-1, interpret('M1: x1:=100000; M2: x1:=x1-1; M3: IF x1=0 THEN GOTO M5; M4: GOTO M1; M5:HALT;', + timeout=1)) + + def test_given_values(self): + self.assertEqual(5, interpret('M1: x0:=x1+0; M2: IF x2=0 THEN GOTO M6; M3: x0:=x0+1;' + + 'M4: x2:=x2-1; M5: GOTO M2; M6: HALT;', [2, 3])) + self.assertEqual(4, interpret('M1: x0:=x1+0; M2: IF x2=0 THEN GOTO M6; M3: x0:=x0+1;' + + 'M4: x2:=x2-1; M5: GOTO M2; M6: HALT;', [0, 4])) + self.assertEqual(1, interpret('M1: x0:=x0+1; M2: HALT;', [2,3,4])) + + def test_wrong_given_values(self): + with self.assertRaises(ValueError): + interpret('M1: x0:=2;', [-1]) + with self.assertRaises(ValueError): + interpret('M1: x0:=1;', [0.2]) + with self.assertRaises(ValueError): + interpret('M1: x0:=4;', ['EINS']) diff --git a/info4/kapitel-8/Interpreter/test_loop_interpreter.py b/info4/kapitel-8/Interpreter/test_loop_interpreter.py index aaf5b948758e874d4e3ee0e74437ff930bb19838..e14b136017e16d81264b9f9daa07c811553198ee 100644 --- a/info4/kapitel-8/Interpreter/test_loop_interpreter.py +++ b/info4/kapitel-8/Interpreter/test_loop_interpreter.py @@ -246,3 +246,16 @@ class LOOPInterpreterTest(unittest.TestCase): def test_unknown_tokens(self): with self.assertRaises(SyntaxError): interpret('BLIBLABLUB') + + def test_given_values(self): + self.assertEqual(5, interpret('x0:=x1+0; LOOP x2 DO x0:=x0+1 END', [2, 3])) + self.assertEqual(4, interpret('x0:=x1+0; LOOP x2 DO x0:=x0+1 END', [0, 4])) + self.assertEqual(1, interpret('x0:=x0+1', [2,3,4])) + + def test_wrong_given_values(self): + with self.assertRaises(ValueError): + interpret('x0:=2;', [-1]) + with self.assertRaises(ValueError): + interpret('x0:=1;', [0.2]) + with self.assertRaises(ValueError): + interpret('x0:=4;', ['EINS']) \ No newline at end of file diff --git a/info4/kapitel-8/Interpreter/test_while_interpreter.py b/info4/kapitel-8/Interpreter/test_while_interpreter.py index 96c1e647c5b543652315bc67c16d9227878da101..01fbedf8eb184ccb830b1bfa0b46aa9daff1e73c 100644 --- a/info4/kapitel-8/Interpreter/test_while_interpreter.py +++ b/info4/kapitel-8/Interpreter/test_while_interpreter.py @@ -119,4 +119,17 @@ class WHILEInterpreterTest(LOOPInterpreterTest): @mock.patch('whileinterpreter.input', side_effect=str_yes) def test_infinite_loop(self, custom_input): - self.assertEqual(-1, interpret('x1:=100000; WHILE x1 != 0 DO x0:=1; x1:=x1-1 END', 1)) + self.assertEqual(-1, interpret('x1:=100000; WHILE x1 != 0 DO x0:=1; x1:=x1-1 END', timeout=1)) + + def test_given_values(self): + self.assertEqual(5, interpret('x0:=x1+0; WHILE x2/=0 DO x0:=x0+1; x2:=x2-1 END', [2, 3])) + self.assertEqual(4, interpret('x0:=x1+0; WHILE x2/=0 DO x0:=x0+1; x2:=x2-1 END', [0, 4])) + self.assertEqual(1, interpret('x0:=x0+1', [2,3,4])) + + def test_wrong_given_values(self): + with self.assertRaises(ValueError): + interpret('x0:=2', [-1]) + with self.assertRaises(ValueError): + interpret('x0:=1', [0.2]) + with self.assertRaises(ValueError): + interpret('x0:=4', ['EINS']) diff --git a/info4/kapitel-8/Interpreter/whileinterpreter.py b/info4/kapitel-8/Interpreter/whileinterpreter.py index d5193eeaf35ddc29a44cfb094ee858a32f68ed03..407d5e582b5c6a8b34c34f80424cf56812f6c4d6 100644 --- a/info4/kapitel-8/Interpreter/whileinterpreter.py +++ b/info4/kapitel-8/Interpreter/whileinterpreter.py @@ -159,12 +159,14 @@ class WHILEInterpreter(LOOPInterpreter): return self.next_token() - def interpret(self, program): + def interpret(self, program, values=None): try: with Timeout(self.timeout): self.lex = lexer.Lexer(self.regex_to_token, program) self.error_handler = ErrorHandler(program, self) - self.values = {} + self.values = values + if values is None: + self.values = {} forbidden_identifiers = [] current_token = self.next_token() while current_token is not None: @@ -185,16 +187,25 @@ class WHILEInterpreter(LOOPInterpreter): return -1 -def interpret(program, timeout=60): +def interpret(program, value_list=None, timeout=60): """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]). + Das WHILE-Programm startet mit diesen Werten in x1, ..., xn. :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. :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) - return interpreter.interpret(program) + values = None + if value_list is not None: + values = {} + for index, value in enumerate(value_list): + 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) if __name__ == '__main__':