Commit 3047fa72 authored by Christopher Happe's avatar Christopher Happe
Browse files

Feature: Homeomorphic Embedding für Interpreter

parent 98d1fdca
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__':
......
......@@ -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):
......
......@@ -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)
......@@ -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)
......@@ -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__':
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment