diff --git a/interpreter/NassiShneidermann.py b/interpreter/NassiShneidermann.py index d3d6882..fc21424 100644 --- a/interpreter/NassiShneidermann.py +++ b/interpreter/NassiShneidermann.py @@ -40,9 +40,8 @@ class NassiShneidermanDiagram: cti.NSD_save(filename) def load_from_file(self, filepath:str): - src_code = itp.load_src(filepath) - global_scope = itp.get_instructions_in_scope(src_code)[0] - self.add_instructions_from_scope(global_scope) + instructions = itp.load_instructions(filepath) + self.add_instructions_from_scope(instructions) def add_instructions_from_scope(self, scope: List[Iinstruction]): for inst in scope: diff --git a/interpreter/interpret_source.py b/interpreter/interpret_source.py index e64e0a7..dadc40a 100644 --- a/interpreter/interpret_source.py +++ b/interpreter/interpret_source.py @@ -1,17 +1,12 @@ import logging from os import remove import re -from typing import List, Text, Tuple +from typing import Callable, List, Tuple from draw.Iinstruction import * -COMMENT_REGEX = r"""^//|^#|^COMMENT|^--""" -REMOVE_KEYWORDS = [' ', "public", "private", "void"] - -WHILE_TAG = "solange " #german for 'while'. Change this depending on your language - -REPLACE = dict((re.escape(k), '') for k in REMOVE_KEYWORDS) -remove_pattern = re.compile("|".join(REPLACE.keys())) +class InterpreterError(Exception): + pass class JavaSyntaxError(Exception): pass @@ -19,6 +14,14 @@ class JavaSyntaxError(Exception): class ScopeNotFoundException(Exception): pass +COMMENT_REGEX = r"""^//|^#|^COMMENT|^--""" +REMOVE_KEYWORDS = [' ', "public", "private", "void", ';'] + +WHILE_TAG = "solange " #german for 'while'. Change this depending on your language + +REPLACE = dict((re.escape(k), '') for k in REMOVE_KEYWORDS) +remove_pattern = re.compile("|".join(REPLACE.keys())) + def replace_all_tags(org: str): return remove_pattern.sub(lambda m: REPLACE[re.escape(m.group(0))], org) @@ -43,80 +46,126 @@ def load_src(filepath: str) -> List[str]: return lines +def check_src(src: List[str], line_index: int, tag: str) -> bool: + if line_index >= len(src): + return False + return src[line_index].__contains__(tag) + +def check_line_start(src: List[str], line_index: int, tag: str) -> bool: + if line_index >= len(src): + return False + return src[line_index].startswith(tag) + def get_next_occurence_of(src: List[str], start_idx:int, tag:str) -> int: + """Returns the index of the next occurence of tag in src from start_idx""" i = start_idx while i < len(src): - if src[i].__contains__(tag): - return i + if check_src(src, i, tag): + break i += 1 + return i -def get_scope_start_offset(src: List[str], start_idx: int) -> int: - i = get_next_occurence_of(src, start_idx, '{') - if i != len(src): - return i + 1 +def get_scope_start_offset(src: List[str], i: int) -> int: + if check_src(src, i, "{"): + return 1 + elif check_src(src, i+1, "{"): + return 2 raise ScopeNotFoundException("Unable to find scope start. Is the program ill-formed?") +def handle_while(line: str, src: List[str], i: int) -> Tuple[Iinstruction, int]: + bracket_idx = line.rindex(')') # throws if while contruct is illformed + + instruction_txt = line[6:bracket_idx] + brace_offset = get_scope_start_offset(src, i) + child_instructions, i = get_instructions_in_scope(src, i+brace_offset) + return while_instruction_front((WHILE_TAG + instruction_txt), child_instructions), i + +def handle_else(src: List[str], i: int) -> Tuple[List[Iinstruction], int]: + brace_offset = get_scope_start_offset(src, i) + return get_instructions_in_scope(src, i+brace_offset) + +def handle_if(line: str, src: List[str], i: int) -> Tuple[Iinstruction, int]: + bracket_idx = line.rindex(')') # throws if the contruct is illformed + instruction_txt = line[3:bracket_idx] + + brace_offset = get_scope_start_offset(src, i) + true_instructions, i = get_instructions_in_scope(src, i+brace_offset) + + false_instructions = None + + #check for else statements + if check_line_start(src, i, "}else"): + logging.debug("found else construct in line: %i", i+1) + false_instructions, i = handle_else(src, i) + + elif check_line_start(src, i+1, "else"): + logging.debug("found else construct in line: %i", i+2) + false_instructions, i = handle_else(src, i+1) + + return if_instruction(instruction_txt, true_instructions, false_instructions), i + +def handle_do_while(line: str, src: List[str], i: int) -> Tuple[Iinstruction, int]: + brace_offset = get_scope_start_offset(src, i) + child_instructions, i = get_instructions_in_scope(src, i+brace_offset) + + instruction_txt = None + if check_line_start(src, i, "}while("): + end_line = src[i] + bracket_index = end_line.rindex(')') #throws if contruct id ill-formed + instruction_txt = end_line[7:bracket_index] + elif check_line_start(src, i+1, "while("): + i += 1 #make sure we return the correct value for i + end_line = src[i] + bracket_index = end_line.rindex(')') + instruction_txt = end_line[6:bracket_index] + else: + raise JavaSyntaxError("Ill-formed do-while construct!") + + return while_instruction_back(instruction_txt, child_instructions), i + +def handle_instruction(line: str, src: List[str], i: int) -> Tuple[Iinstruction, int]: + if line.startswith("while("): + logging.debug("Found while construct in line: %i", i+1) + return handle_while(line, src, i) + + elif line.startswith("if("): + logging.debug("Found if construct in line: %i", i+1) + return handle_if(line, src, i) + + elif line.startswith("do"): + logging.debug("Found do-while construct in line: %i", i+1) + return handle_do_while(line, src, i) + + else: + logging.debug("found generic instruction in line %i", i+1) + return generic_instruction(line), i def get_instructions_in_scope(src: List[str], start_idx: int = 0) -> Tuple[List[Iinstruction], int]: outer_scope: List[Iinstruction] = [] i = start_idx while i < len(src): + line = src[i] try: - if line.__contains__('}'): #We exited this scope, return it - return outer_scope, i + if check_src(src, i, "}"): #We exited this scope, return it + break + + instruction, i = handle_instruction(line, src, i) + outer_scope.append(instruction) - if line.startswith("while("): - logging.debug("Found while construct in line: %i", i+1) - - bracket_idx = line.rindex(')') # throws if while contruct is illformed - - instruction_txt = line[6:bracket_idx] - brace_offset = get_scope_start_offset(src, i) - child_instructions, i = get_instructions_in_scope(src, i+brace_offset) - - outer_scope.append(while_instruction_front((WHILE_TAG + instruction_txt), child_instructions)) - - elif line.startswith("if("): - logging.debug("Found if construct in line: %i", i+1) - - bracket_idx = line.rindex(')') # throws if the contruct is illformed - - instruction_txt = line[3:bracket_idx] - brace_offset = get_scope_start_offset(src, i) - true_instructions, i = get_instructions_in_scope(src, i+brace_offset) - - false_instructions = None - #if there is an else statement, check it - if src[i].__contains__("else"): - logging.debug("found else construct in line: %i", i+1) - brace_offset = get_scope_start_offset(src, i) - false_instructions, i = get_instructions_in_scope(src, i+brace_offset) - elif src[i+1].__contains__("else"): - logging.debug("found else construct in line: %i", i+2) - brace_offset = get_scope_start_offset(src, i+1) - false_instructions, i = get_instructions_in_scope(src, i+1+brace_offset) - - - outer_scope.append(if_instruction(instruction_txt, true_instructions, false_instructions)) - - elif line.startswith("do"): - logging.debug("Found start of do-while construct in line: %i", i+1) - - brace_offset = get_scope_start_offset(src, i) - child_instructions, i = get_instructions_in_scope(src, i+brace_offset) - - end_line = src[i] - bracket_idx = end_line.rindex(");") - instruction_txt = end_line[7: bracket_idx] - - outer_scope.append(while_instruction_back((WHILE_TAG + instruction_txt), child_instructions)) - - else: - logging.debug("Found generic instruction in line: %i", i+1) - outer_scope.append(generic_instruction(line)) + except Exception as e: + logging.error("Encountered error in line %i: %s", i+1, str(e)) + raise except: - logging.error("Encountered error in line: %i", i+1) - raise # rethrow + logging.fatal("Encountered unexpected error in line: %i", i+1) + raise i += 1 - return outer_scope, 0 \ No newline at end of file + + return outer_scope, i + +def load_instructions(filepath: str) -> List[Iinstruction]: + src = load_src(filepath) + instructions, i = get_instructions_in_scope(src) + if i != len(src): + raise InterpreterError("Unknown error during source interpretation! Unsupported language constructs or ill-formed?") + return instructions \ No newline at end of file diff --git a/res/input/input.java b/res/input/input.java index e4c4f8a..ee6e2ac 100644 --- a/res/input/input.java +++ b/res/input/input.java @@ -1,138 +1,74 @@ -// // fahre1(); -// // fahre2(); -// // while(shouldNiet()) - - -// // { -// // niet4(); -// // niet5(); -// // if(if6) -// // { -// // niet7(); -// // niet8(); -// // } else -// // { -// // niet10(); -// // niet11(); -// // } -// // niet13(); -// // } -// // niet15(); -// // niet16(); - -// // do{ -// // niet21(); -// // niet22(); -// // }while(bool23); - -// //the following code was heavily distorted in order to test the interpreter. Sorry to everyone who has to read this - -// void - -// private void - - - -// drehe("links"); -// while(huegelVorhanden("rechts")) -// { -// gesteinSammeln(); -// fahre(); - - - - - -// } -// drehe("rechts"); - - - - -// gesteinSammeln(); - - - -// fahre(); - - -// while(huegelVorhanden("rechts")) -// { -// gesteinSammeln(); -// fahre(); -// } -// drehe("rechts"); - - - - - - - -// gesteinSammeln(); -// fahre(); - - - - - -// while(huegelVorhanden("rechts")) -// { -// gesteinSammeln(); -// if(!huegelVorhanden("vorne")) - - - -// { - - - - - - -// fahre(); -// } -// else - - -// { -// fahre(); -// } -// } - - - - - - - - -// drehe("rechts"); - -// do - - - - -// { -// insideDoWhile(); -// insideDoWhile(); - - -// insideDoWhile(); - - - -// insideDoWhile(); -// } -// while( !huegelVorhanden( "vorne" ) ) ; - -if(bool) { +beforeIf(); +if(if_condition1) { true_case; true_case; -} +} +afterIf(); +beforeIf(); +if(if_condition2) +{ + true_case; + true_case; +} +afterIf(); +beforeIf(); +if(if_else_condition1) { + true_case; + true_case; +} else { + false_case; + false_case; +} +afterIf(); +beforeIf(); +if(if_else_condition2) { + true_case; + true_case; +} +else { + false_case; + false_case; +} +afterIf(); +beforeIf(); +if(if_else_condition3) { + true_case; + true_case; +} else { false_case; false_case; -} \ No newline at end of file +} +afterIf(); +beforeWhile(); +while(while_condition1) { + insideWhile; + insideWhile; +} +beforeWhile(); +while(while_condition2) +{ + insideWhile; + insideWhile; +} +beforeDoWhile(); +do{ + insideDoWhile; + insideDoWhile; +}while(do_while_condition1); +beforeDoWhile(); +do +{ + insideDoWhile; + insideDoWhile; +}while(do_while_condition2); +beforeDoWhile(); +do +{ + insideDoWhile; + insideDoWhile; +} +while(do_while_condition3) + +//since the interpreter ignores all empty lines and spaces, any changes in tabs *should* not have any effect \ No newline at end of file