diff --git a/info4/kapitel-8/Interpreter/interpreter.py b/info4/kapitel-8/Interpreter/interpreter.py
index ba38dad1f77e702031bfaab050bdddb168a4ce29..c40f09cffa2f76cac4eb8c770a37c372c0c9069e 100644
--- a/info4/kapitel-8/Interpreter/interpreter.py
+++ b/info4/kapitel-8/Interpreter/interpreter.py
@@ -1,21 +1,38 @@
 import lexer
+import sys
+
+
+class ErrorHandler:
+    def __init__(self, program, tokens):
+        sys.tracebacklimit = 0
+        self.program = program
+        position_to_line = {}
+        position = 0
+        line = 0
+        for token in tokens:
+            if token.k == 'LINEBREAK':
+                line += 1
+            else:
+                position_to_line[position] = line
+                position = position + 1
+        self.position_to_line = position_to_line
+
+    def handle_error(self, position, message):
+        line_number = self.position_to_line[position]
+        msg = ["Fehler in Zeile " + str(line_number + 1), self.program.split("\n")[line_number], message]
+        raise SyntaxError("\n".join(msg)) from None
 
-loop_program = '''x1 := 2;
-x2 := 3;
-x3 := x2 + 0;
-LOOP x1 DO
-    x2 := x3 + 1;
-    x3 := x2 + 0
-END;
-x0 := x2 + 0'''
+
+global error_handler
 
 
 def process_assignment(token_queue, position, value_list, forbidden_identifiers):
     identifier_1 = token_queue[position].v
     if identifier_1 in forbidden_identifiers:
-        raise Exception("Identifier " + identifier_1 + "ist bereits in Loop vorhanden und darf nicht verwendet werden.")
+        error_handler.handle_error(position, "Identifier " + identifier_1 +
+                                   "ist bereits in Loop vorhanden und darf nicht verwendet werden.")
     if not token_queue[position + 1].k == 'EQUALS':
-        raise SyntaxError(":= in Zuweisung erwartet.")
+        error_handler.handle_error(position + 1, ":= in Zuweisung erwartet.")
 
     if identifier_1 in value_list:
         value_1 = value_list.get(identifier_1)
@@ -28,11 +45,12 @@ def process_assignment(token_queue, position, value_list, forbidden_identifiers)
         return position + 3, value_list
 
     if not token_queue[position + 2].k == 'IDENTIFIER':
-        raise SyntaxError("IDENTIFIER in Zuweisung erwartet.")
+        error_handler.handle_error(position + 2, "IDENTIFIER in Zuweisung erwartet.")
     identifier_2 = token_queue[position + 2].v
     if identifier_2 in forbidden_identifiers:
-        raise Exception(
-            "Identifier " + identifier_2 + " ist bereits in Loop vorhanden und darf nicht verwendet werden.")
+        error_handler.handle_error(position + 2,
+                                   "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)
@@ -40,13 +58,13 @@ def process_assignment(token_queue, position, value_list, forbidden_identifiers)
         value_2 = 0
 
     if not token_queue[position + 4].k == 'NUMBER':
-        raise SyntaxError("NUMBER in Zuweisung erwartet.")
+        error_handler.handle_error(position + 4, "NUMBER in Zuweisung erwartet.")
     if token_queue[position + 3].k == 'PLUS':
         value_1 = value_2 + int(token_queue[position + 4].v)
     elif token_queue[position + 3].k == 'MINUS':
         value_1 = max(0, value_2 + token_queue[position + 4].v)
     else:
-        raise SyntaxError("PLUS oder MINUS in Zuweisung erwartet.")
+        error_handler.handle_error(position + 3, "PLUS oder MINUS in Zuweisung erwartet.")
     value_list.update({identifier_1: value_1})
     return position + 5, value_list
 
@@ -54,81 +72,41 @@ def process_assignment(token_queue, position, value_list, forbidden_identifiers)
 def verify_assignment(token_queue, position, forbidden_identifiers):
     identifier_1 = token_queue[position].v
     if identifier_1 in forbidden_identifiers:
-        raise Exception("Identifier " + identifier_1 + "ist bereits in Loop vorhanden und darf nicht verwendet werden.")
+        error_handler.handle_error(position,
+                                   "Identifier " + identifier_1 +
+                                   "ist bereits in Loop vorhanden und darf nicht verwendet werden.")
     if not token_queue[position + 1].k == 'EQUALS':
-        raise SyntaxError(":= in Zuweisung erwartet.")
+        error_handler.handle_error(position + 1, ":= in Zuweisung erwartet.")
 
     if token_queue[position + 2].k == 'NUMBER':
         return position + 3
 
     if not token_queue[position + 2].k == 'IDENTIFIER':
-        raise SyntaxError("IDENTIFIER in Zuweisung erwartet.")
+        error_handler.handle_error(position + 2, "IDENTIFIER in Zuweisung erwartet.")
     identifier_2 = token_queue[position + 2].v
     if identifier_2 in forbidden_identifiers:
-        raise Exception(
-            "Identifier " + identifier_2 + " ist bereits in Loop vorhanden und darf nicht verwendet werden.")
+        error_handler.handle_error(position + 2,
+                                   "Identifier " + identifier_2 +
+                                   " ist bereits in Loop vorhanden und darf nicht verwendet werden.")
 
     if not token_queue[position + 4].k == 'NUMBER':
-        raise SyntaxError("NUMBER in Zuweisung erwartet.")
+        error_handler.handle_error(position + 4, "NUMBER in Zuweisung erwartet.")
     if not token_queue[position + 3].k in ['PLUS', 'MINUS']:
-        raise SyntaxError("PLUS oder MINUS in Zuweisung erwartet.")
+        error_handler.handle_error(position + 3, "PLUS oder MINUS in Zuweisung erwartet.")
 
     return position + 5
 
 
-def verify_loop(token_queue, position, forbidden_identifiers):
-    identifier_token = token_queue[position + 1]
-    if not identifier_token.k == 'IDENTIFIER':
-        raise SyntaxError('IDENTIFIER in LOOP erwartet.')
-    if identifier_token.v in forbidden_identifiers:
-        raise SyntaxError(
-            "Identifier " + identifier_token.v + "ist bereits in Loop vorhanden und darf nicht verwendet werden.")
-    if not token_queue[position + 2].k == 'DO':
-        raise SyntaxError('DO in LOOP erwartet.')
-
-    forbidden_identifiers.append(identifier_token.v)
-
-    end_found = False
-    while not end_found:
-        position = verify_program(token_queue, position, forbidden_identifiers)
-        if token_queue[position].k == 'SEMICOLON':
-            position = position + 1
-            continue
-        elif token_queue[position].k == 'END':
-            end_found = True
-        else:
-            raise SyntaxError("SEMICOLON oder END erwartet.")
-
-    forbidden_identifiers.remove(identifier_token.v)
-    return position + 1
-
-
-def verify_program(token_queue, position, forbidden_identifiers):
-    current_key = token_queue[position].k
-    if current_key == 'IDENTIFIER':
-        try:
-            current_position = verify_assignment(token_queue, position, forbidden_identifiers)
-        except IndexError:
-            raise Exception("Frühzeitiges Ende einer Zuweisung.")
-    elif current_key == 'LOOP':
-        try:
-            current_position = verify_loop(token_queue, position, forbidden_identifiers)
-        except IndexError:
-            raise Exception("Frühzeitiges Ende eines LOOPs")
-    else:
-        raise SyntaxError("Keine passende Anweisung gefunden")
-    return current_position
-
-
 def process_loop(token_queue, position, value_list, forbidden_identifiers):
     identifier_token = token_queue[position + 1]
     if not identifier_token.k == 'IDENTIFIER':
-        raise SyntaxError('IDENTIFIER in LOOP erwartet.')
+        error_handler.handle_error(position + 1, 'IDENTIFIER in LOOP erwartet.')
     if identifier_token.v in forbidden_identifiers:
-        raise SyntaxError(
-            "Identifier " + identifier_token.v + "ist bereits in Loop vorhanden und darf nicht verwendet werden.")
+        error_handler.handle_error(position + 1,
+                                   "Identifier " + identifier_token.v +
+                                   "ist bereits in Loop vorhanden und darf nicht verwendet werden.")
     if not token_queue[position + 2].k == 'DO':
-        raise SyntaxError('DO in LOOP erwartet.')
+        error_handler.handle_error(position + 2, 'DO in LOOP erwartet.')
 
     if identifier_token.v in value_list:
         number_of_loops = int(value_list.get(identifier_token.v))
@@ -137,7 +115,6 @@ def process_loop(token_queue, position, value_list, forbidden_identifiers):
     saved_position = position + 3
     forbidden_identifiers.append(identifier_token.v)
 
-    # TODO increment position without changing values when number of loops = 0
     if number_of_loops == 0:
         end_found = False
         position = saved_position
@@ -149,7 +126,7 @@ def process_loop(token_queue, position, value_list, forbidden_identifiers):
             elif token_queue[position].k == 'END':
                 end_found = True
             else:
-                raise SyntaxError("SEMICOLON oder END erwartet.")
+                error_handler.handle_error(position, "SEMICOLON oder END erwartet.")
 
     for index in range(number_of_loops):
         position = saved_position
@@ -162,45 +139,94 @@ def process_loop(token_queue, position, value_list, forbidden_identifiers):
             elif token_queue[position].k == 'END':
                 end_found = True
             else:
-                raise SyntaxError("SEMICOLON oder END erwartet.")
+                error_handler.handle_error(position, "SEMICOLON oder END erwartet.")
 
     forbidden_identifiers.remove(identifier_token.v)
     return position + 1, value_list
 
 
+def verify_loop(token_queue, position, forbidden_identifiers):
+    identifier_token = token_queue[position + 1]
+    if not identifier_token.k == 'IDENTIFIER':
+        error_handler.handle_error(position + 1, 'IDENTIFIER in LOOP erwartet.')
+    if identifier_token.v in forbidden_identifiers:
+        error_handler.handle_error(position + 1,
+                                   "Identifier " + identifier_token.v +
+                                   "ist bereits in Loop vorhanden und darf nicht verwendet werden.")
+    if not token_queue[position + 2].k == 'DO':
+        error_handler.handle_error(position + 2, 'DO in LOOP erwartet.')
+
+    forbidden_identifiers.append(identifier_token.v)
+
+    end_found = False
+    while not end_found:
+        position = verify_program(token_queue, position, forbidden_identifiers)
+        if token_queue[position].k == 'SEMICOLON':
+            position = position + 1
+            continue
+        elif token_queue[position].k == 'END':
+            end_found = True
+        else:
+            error_handler(position, "SEMICOLON oder END in LOOP erwartet.")
+
+    forbidden_identifiers.remove(identifier_token.v)
+    return position + 1
+
+
 def process_program(token_queue, position, value_list, forbidden_identifiers):
+    current_position = position
+    values = value_list
     current_key = token_queue[position].k
     if current_key == 'IDENTIFIER':
         try:
             current_position, values = process_assignment(token_queue, position, value_list, forbidden_identifiers)
         except IndexError:
-            raise Exception("Frühzeitiges Ende einer Zuweisung.")
+            error_handler.handle_error(current_position, "Frühzeitiges Ende einer Zuweisung.")
     elif current_key == 'LOOP':
         try:
             current_position, values = process_loop(token_queue, position, value_list, forbidden_identifiers)
         except IndexError:
-            raise Exception("Frühzeitiges Ende eines LOOPs")
+            error_handler.handle_error(current_position, "Frühzeitiges Ende eines LOOPs")
     else:
-        raise SyntaxError("Keine passende Anweisung gefunden")
+        error_handler.handle_error(current_position, "Keine passende Anweisung gefunden")
     return current_position, values
 
 
+def verify_program(token_queue, position, forbidden_identifiers):
+    current_key = token_queue[position].k
+    current_position = position
+    if current_key == 'IDENTIFIER':
+        try:
+            current_position = verify_assignment(token_queue, position, forbidden_identifiers)
+        except IndexError:
+            error_handler.handle_error(current_position, "Frühzeitiges Ende einer Zuweisung.")
+    elif current_key == 'LOOP':
+        try:
+            current_position = verify_loop(token_queue, position, forbidden_identifiers)
+        except IndexError:
+            error_handler.handle_error(current_position, "Frühzeitiges Ende eines LOOPs")
+    else:
+        error_handler.handle_error(current_position, "Keine passende Anweisung gefunden")
+    return current_position
+
+
 def interpret(program):
     tokens = lexer.tokenize(program)
+    global error_handler
+    error_handler = ErrorHandler(program, tokens)
+    tokens = [token for token in tokens if not token.k == 'LINEBREAK']
     current_position = 0
     values = {}
     forbidden_identifiers = []
     while current_position < len(tokens):
         current_position, values = process_program(tokens, current_position, values, forbidden_identifiers)
         if current_position < len(tokens) and not tokens[current_position].k == 'SEMICOLON':
-            raise SyntaxError("Semicolon erwartet")
+            error_handler.handle_error(current_position, "Semicolon erwartet")
         else:
+            if current_position == len(tokens) - 1:
+                error_handler.handle_error(current_position, "Semikolons werden nur zur Trennung und nicht zum " +
+                                                             "Abschluss von Programmen verwendet")
             current_position = current_position + 1
     if "x0" in values:
         return values.get("x0")
     return 0
-
-
-print(interpret(loop_program))
-print(interpret('''x1:= 2; 
-LOOP x1 DO x2 := 2 END; x0 := x2 + 1'''))
diff --git a/info4/kapitel-8/Interpreter/lexer.py b/info4/kapitel-8/Interpreter/lexer.py
index f6eb7a89b19a1cacccd114ec0a3ab7d3cbe9cea7..1cf0024e976543121350d89afd9a22f9baf14be9 100644
--- a/info4/kapitel-8/Interpreter/lexer.py
+++ b/info4/kapitel-8/Interpreter/lexer.py
@@ -1,5 +1,6 @@
 import re
 
+
 class Token:
     def __init__(self, key, value):
         self.k = key
@@ -17,6 +18,7 @@ def tokenize(program):
                       (re.compile(r'DO'), 'DO'),
                       (re.compile(r'END'), 'END'),
                       (re.compile(r';'), 'SEMICOLON'),
+                      (re.compile(r'\n', re.MULTILINE), 'LINEBREAK'),
                       (re.compile(r'\s+'), 'WHITESPACE')]
     current_position = 0
     new_position = 0
@@ -29,6 +31,9 @@ def tokenize(program):
                 new_position = match.span()[1]
                 break
         if current_position == new_position:
-            raise SyntaxError('Syntax Error in line: ' + str(program.count("\n", 0, current_position) + 1))
+            msg = ['Fehler in Zeile : ' + str(program.count("\n", 0, current_position) + 1),
+                   'Erwartet: xi, :=, NUMBER, LOOP, DO, END, ;',
+                   'Bekommen :' + re.compile(r'[^\n]*').match(program, current_position).group()]
+            raise SyntaxError("\n".join(msg))
         current_position = new_position
     return token_queue