diff --git a/info4/kapitel-8/Interpreter/interpreter.py b/info4/kapitel-8/Interpreter/interpreter.py new file mode 100644 index 0000000000000000000000000000000000000000..088afa1935209694b55fdd0e0583b695bd52757f --- /dev/null +++ b/info4/kapitel-8/Interpreter/interpreter.py @@ -0,0 +1,106 @@ +import lexer + +loop_program = '''x1 := 2; +x2 := 3; +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): + 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.") + if not token_queue[position + 1].k == 'EQUALS': + raise SyntaxError(":= in Zuweisung erwartet.") + + if identifier_1 in value_list: + value_1 = value_list.get(identifier_1) + else: + value_1 = 0 + + if token_queue[position + 2].k == 'NUMBER': + value_1 += int(token_queue[position + 2].v) + value_list.update({identifier_1: value_1}) + return position+3, value_list + + if not token_queue[position + 2].k == 'IDENTIFIER': + raise SyntaxError("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.") + + if identifier_2 in value_list: + value_2 = value_list.get(identifier_2) + else: + value_2 = 0 + + if not token_queue[position + 4].k == 'NUMBER': + raise SyntaxError("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.") + value_list.update({identifier_1: value_1}) + return position + 5, value_list + +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.') + if not token_queue[position+2].k == 'DO': + raise SyntaxError('DO in LOOP erwartet.') + + number_of_loops = int(value_list.get(identifier_token.v)) + saved_position = position + 3 + forbidden_identifiers.append(identifier_token.v) + for index in range(number_of_loops): + position = saved_position + end_found = False + while(not end_found): + position, value_list = process_program(token_queue, position, value_list, 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.") + return position+1, value_list + +def process_program(token_queue, position, value_list, forbidden_identifiers): + 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.") + 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") + else: + raise SyntaxError("Keine passende Anweisung gefunden") + return current_position, values + +def interpret(program): + tokens = lexer.tokenize(program) + 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") + else: + current_position = current_position + 1 + if "x0" in values: + return values.get("x0") + return 0 + +print(interpret(loop_program)) diff --git a/info4/kapitel-8/Interpreter/lexer.py b/info4/kapitel-8/Interpreter/lexer.py new file mode 100644 index 0000000000000000000000000000000000000000..f6eb7a89b19a1cacccd114ec0a3ab7d3cbe9cea7 --- /dev/null +++ b/info4/kapitel-8/Interpreter/lexer.py @@ -0,0 +1,34 @@ +import re + +class Token: + def __init__(self, key, value): + self.k = key + self.v = value + + +def tokenize(program): + token_queue = [] + regex_to_token = [(re.compile(r'\d+'), 'NUMBER'), + (re.compile(r'x\d+'), 'IDENTIFIER'), + (re.compile(r'\+'), 'PLUS'), + (re.compile(r'-'), 'MINUS'), + (re.compile(r':='), 'EQUALS'), + (re.compile(r'LOOP'), 'LOOP'), + (re.compile(r'DO'), 'DO'), + (re.compile(r'END'), 'END'), + (re.compile(r';'), 'SEMICOLON'), + (re.compile(r'\s+'), 'WHITESPACE')] + current_position = 0 + new_position = 0 + while current_position < len(program): + for pattern, value in regex_to_token: + match = pattern.match(program, current_position) + if match: + if not value == 'WHITESPACE': + token_queue.append(Token(value, match.group())) + 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)) + current_position = new_position + return token_queue diff --git a/info4/kapitel-8/LOOP-Programme.ipynb b/info4/kapitel-8/LOOP-Programme.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..3e401844f4b6a3e2068720b95023bacfb4ddf01e --- /dev/null +++ b/info4/kapitel-8/LOOP-Programme.ipynb @@ -0,0 +1,79 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HI\n" + ] + }, + { + "ename": "SyntaxError", + "evalue": "Syntax Error in line: 4 (<string>)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"<string>\"\u001b[0;36m, line \u001b[0;32munknown\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m Syntax Error in line: 4\n" + ] + } + ], + "source": [ + "%run Interpreter/lexer.py" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "HI\n" + ] + }, + { + "ename": "SyntaxError", + "evalue": "Syntax Error in line: 1 (<string>)", + "output_type": "error", + "traceback": [ + "Traceback \u001b[0;36m(most recent call last)\u001b[0m:\n", + " File \u001b[1;32m\"/usr/lib/python3.8/site-packages/IPython/core/interactiveshell.py\"\u001b[0m, line \u001b[1;32m3418\u001b[0m, in \u001b[1;35mrun_code\u001b[0m\n exec(code_obj, self.user_global_ns, self.user_ns)\n", + " File \u001b[1;32m\"<ipython-input-2-93cfbd622072>\"\u001b[0m, line \u001b[1;32m1\u001b[0m, in \u001b[1;35m<module>\u001b[0m\n tokenize(\"LOOP x1 DO P END\")\n", + "\u001b[0;36m File \u001b[0;32m\"/home/christopher/uni/Projektarbeit/prob-teaching-notebooks/info4/kapitel-8/Interpreter/lexer.py\"\u001b[0;36m, line \u001b[0;32m43\u001b[0;36m, in \u001b[0;35mtokenize\u001b[0;36m\u001b[0m\n\u001b[0;31m raise SyntaxError('Syntax Error in line: ' + str(program.count(\"\\n\", 0, current_position) + 1))\u001b[0m\n", + "\u001b[0;36m File \u001b[0;32m\"<string>\"\u001b[0;36m, line \u001b[0;32munknown\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m Syntax Error in line: 1\n" + ] + } + ], + "source": [ + "tokenize(\"LOOP x1 DO P END\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}