Skip to content
Snippets Groups Projects
Commit 8c83627c authored by Chris's avatar Chris
Browse files

Fehlerbehandlung überarbeitet

parent da836c18
No related branches found
No related tags found
1 merge request!1Master
import lexer 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; global error_handler
x3 := x2 + 0;
LOOP x1 DO
x2 := x3 + 1;
x3 := x2 + 0
END;
x0 := x2 + 0'''
def process_assignment(token_queue, position, value_list, forbidden_identifiers): def process_assignment(token_queue, position, value_list, forbidden_identifiers):
identifier_1 = token_queue[position].v identifier_1 = token_queue[position].v
if identifier_1 in forbidden_identifiers: 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': 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: if identifier_1 in value_list:
value_1 = value_list.get(identifier_1) value_1 = value_list.get(identifier_1)
...@@ -28,11 +45,12 @@ def process_assignment(token_queue, position, value_list, forbidden_identifiers) ...@@ -28,11 +45,12 @@ def process_assignment(token_queue, position, value_list, forbidden_identifiers)
return position + 3, value_list return position + 3, value_list
if not token_queue[position + 2].k == 'IDENTIFIER': 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 identifier_2 = token_queue[position + 2].v
if identifier_2 in forbidden_identifiers: if identifier_2 in forbidden_identifiers:
raise Exception( error_handler.handle_error(position + 2,
"Identifier " + identifier_2 + " ist bereits in Loop vorhanden und darf nicht verwendet werden.") "Identifier " + identifier_2 +
" ist bereits in Loop vorhanden und darf nicht verwendet werden.")
if identifier_2 in value_list: if identifier_2 in value_list:
value_2 = value_list.get(identifier_2) value_2 = value_list.get(identifier_2)
...@@ -40,13 +58,13 @@ def process_assignment(token_queue, position, value_list, forbidden_identifiers) ...@@ -40,13 +58,13 @@ def process_assignment(token_queue, position, value_list, forbidden_identifiers)
value_2 = 0 value_2 = 0
if not token_queue[position + 4].k == 'NUMBER': 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': if token_queue[position + 3].k == 'PLUS':
value_1 = value_2 + int(token_queue[position + 4].v) value_1 = value_2 + int(token_queue[position + 4].v)
elif token_queue[position + 3].k == 'MINUS': elif token_queue[position + 3].k == 'MINUS':
value_1 = max(0, value_2 + token_queue[position + 4].v) value_1 = max(0, value_2 + token_queue[position + 4].v)
else: 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}) value_list.update({identifier_1: value_1})
return position + 5, value_list return position + 5, value_list
...@@ -54,81 +72,41 @@ def process_assignment(token_queue, position, value_list, forbidden_identifiers) ...@@ -54,81 +72,41 @@ def process_assignment(token_queue, position, value_list, forbidden_identifiers)
def verify_assignment(token_queue, position, forbidden_identifiers): def verify_assignment(token_queue, position, forbidden_identifiers):
identifier_1 = token_queue[position].v identifier_1 = token_queue[position].v
if identifier_1 in forbidden_identifiers: 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': 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': if token_queue[position + 2].k == 'NUMBER':
return position + 3 return position + 3
if not token_queue[position + 2].k == 'IDENTIFIER': 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 identifier_2 = token_queue[position + 2].v
if identifier_2 in forbidden_identifiers: if identifier_2 in forbidden_identifiers:
raise Exception( error_handler.handle_error(position + 2,
"Identifier " + identifier_2 + " ist bereits in Loop vorhanden und darf nicht verwendet werden.") "Identifier " + identifier_2 +
" ist bereits in Loop vorhanden und darf nicht verwendet werden.")
if not token_queue[position + 4].k == 'NUMBER': 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']: 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 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): def process_loop(token_queue, position, value_list, forbidden_identifiers):
identifier_token = token_queue[position + 1] identifier_token = token_queue[position + 1]
if not identifier_token.k == 'IDENTIFIER': 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: if identifier_token.v in forbidden_identifiers:
raise SyntaxError( error_handler.handle_error(position + 1,
"Identifier " + identifier_token.v + "ist bereits in Loop vorhanden und darf nicht verwendet werden.") "Identifier " + identifier_token.v +
"ist bereits in Loop vorhanden und darf nicht verwendet werden.")
if not token_queue[position + 2].k == 'DO': 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: if identifier_token.v in value_list:
number_of_loops = int(value_list.get(identifier_token.v)) number_of_loops = int(value_list.get(identifier_token.v))
...@@ -137,7 +115,6 @@ def process_loop(token_queue, position, value_list, forbidden_identifiers): ...@@ -137,7 +115,6 @@ def process_loop(token_queue, position, value_list, forbidden_identifiers):
saved_position = position + 3 saved_position = position + 3
forbidden_identifiers.append(identifier_token.v) forbidden_identifiers.append(identifier_token.v)
# TODO increment position without changing values when number of loops = 0
if number_of_loops == 0: if number_of_loops == 0:
end_found = False end_found = False
position = saved_position position = saved_position
...@@ -149,7 +126,7 @@ def process_loop(token_queue, position, value_list, forbidden_identifiers): ...@@ -149,7 +126,7 @@ def process_loop(token_queue, position, value_list, forbidden_identifiers):
elif token_queue[position].k == 'END': elif token_queue[position].k == 'END':
end_found = True end_found = True
else: else:
raise SyntaxError("SEMICOLON oder END erwartet.") error_handler.handle_error(position, "SEMICOLON oder END erwartet.")
for index in range(number_of_loops): for index in range(number_of_loops):
position = saved_position position = saved_position
...@@ -162,45 +139,94 @@ def process_loop(token_queue, position, value_list, forbidden_identifiers): ...@@ -162,45 +139,94 @@ def process_loop(token_queue, position, value_list, forbidden_identifiers):
elif token_queue[position].k == 'END': elif token_queue[position].k == 'END':
end_found = True end_found = True
else: else:
raise SyntaxError("SEMICOLON oder END erwartet.") error_handler.handle_error(position, "SEMICOLON oder END erwartet.")
forbidden_identifiers.remove(identifier_token.v) forbidden_identifiers.remove(identifier_token.v)
return position + 1, value_list 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): def process_program(token_queue, position, value_list, forbidden_identifiers):
current_position = position
values = value_list
current_key = token_queue[position].k current_key = token_queue[position].k
if current_key == 'IDENTIFIER': if current_key == 'IDENTIFIER':
try: try:
current_position, values = process_assignment(token_queue, position, value_list, forbidden_identifiers) current_position, values = process_assignment(token_queue, position, value_list, forbidden_identifiers)
except IndexError: except IndexError:
raise Exception("Frühzeitiges Ende einer Zuweisung.") error_handler.handle_error(current_position, "Frühzeitiges Ende einer Zuweisung.")
elif current_key == 'LOOP': elif current_key == 'LOOP':
try: try:
current_position, values = process_loop(token_queue, position, value_list, forbidden_identifiers) current_position, values = process_loop(token_queue, position, value_list, forbidden_identifiers)
except IndexError: except IndexError:
raise Exception("Frühzeitiges Ende eines LOOPs") error_handler.handle_error(current_position, "Frühzeitiges Ende eines LOOPs")
else: else:
raise SyntaxError("Keine passende Anweisung gefunden") error_handler.handle_error(current_position, "Keine passende Anweisung gefunden")
return current_position, values 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): def interpret(program):
tokens = lexer.tokenize(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 current_position = 0
values = {} values = {}
forbidden_identifiers = [] forbidden_identifiers = []
while current_position < len(tokens): while current_position < len(tokens):
current_position, values = process_program(tokens, current_position, values, forbidden_identifiers) current_position, values = process_program(tokens, current_position, values, forbidden_identifiers)
if current_position < len(tokens) and not tokens[current_position].k == 'SEMICOLON': 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: 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 current_position = current_position + 1
if "x0" in values: if "x0" in values:
return values.get("x0") return values.get("x0")
return 0 return 0
print(interpret(loop_program))
print(interpret('''x1:= 2;
LOOP x1 DO x2 := 2 END; x0 := x2 + 1'''))
import re import re
class Token: class Token:
def __init__(self, key, value): def __init__(self, key, value):
self.k = key self.k = key
...@@ -17,6 +18,7 @@ def tokenize(program): ...@@ -17,6 +18,7 @@ def tokenize(program):
(re.compile(r'DO'), 'DO'), (re.compile(r'DO'), 'DO'),
(re.compile(r'END'), 'END'), (re.compile(r'END'), 'END'),
(re.compile(r';'), 'SEMICOLON'), (re.compile(r';'), 'SEMICOLON'),
(re.compile(r'\n', re.MULTILINE), 'LINEBREAK'),
(re.compile(r'\s+'), 'WHITESPACE')] (re.compile(r'\s+'), 'WHITESPACE')]
current_position = 0 current_position = 0
new_position = 0 new_position = 0
...@@ -29,6 +31,9 @@ def tokenize(program): ...@@ -29,6 +31,9 @@ def tokenize(program):
new_position = match.span()[1] new_position = match.span()[1]
break break
if current_position == new_position: 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 current_position = new_position
return token_queue return token_queue
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment