class AbacusCore: def __init__(self): self._input_string = "" self._vars = dict() self._funcs = dict() self._vars['result'] = 0 self._operators = ['+', '-', '/', '*'] self._delimiters = ['(', ')', '[', ']', ';', ' '] def get_vars(self): return self._vars def get_funcs(self): return self._funcs def add_var(self, name, value): name = name.strip() if not name: raise ValueError("Имя переменной не может быть пустым") self._vars[name] = value def add_func(self, name, value): name = name.strip() if not name: raise ValueError("Имя функции не может быть пустым") self._funcs[name] = value def parse_input(self, input_str): """ Execute a multiline input sequentially, line by line. All lines share the same variable/function dictionaries, so a variable created on one line is immediately available on the next. """ if input_str is None: raise ValueError("Leere Eingabe") if not input_str.strip(): raise ValueError("Leere Eingabe") lines = input_str.splitlines() results = [] last_comment = None last_name = None last_value = None for line in lines: if not line.strip(): continue result = self._parse_line(line) if result is None: continue orig, name, value, comment = result results.append(result) last_name = name last_value = value last_comment = comment if not results: raise ValueError("Leere Eingabe") # The notebook displays the result of the last executable line. return input_str, last_name, last_value, last_comment def _parse_line(self, input_str): """Execute exactly one line.""" orig_input_str = input_str input_str = input_str.strip() if not input_str: return None input_str, comment = self._get_input_wo_commentar(input_str) if input_str is None or not input_str.strip(): return None input_str = input_str.strip() chunks = input_str.split("=") if len(chunks) > 2: raise ValueError("Mehrfachzuweisung wird nicht unterstützt") if len(chunks) == 2: name = chunks[0].strip() expression = chunks[1].strip() if not name: raise ValueError("Имя переменной не может быть пустым") if not expression: raise ValueError("Значение переменной не может быть пустым") value = self._with_variable_another_way(expression) self._vars[name] = value return orig_input_str, name, value, comment chunks = input_str.split(":", 1) if len(chunks) == 2: name = chunks[0].strip() expression = chunks[1].strip() if not name: raise ValueError("Имя функции не может быть пустым") if not expression: raise ValueError("Тело функции не может быть пустым") self._funcs[name] = expression return orig_input_str, name, expression, comment result = self._with_variable_another_way(input_str) self._vars["result"] = result return orig_input_str, None, result, comment def _with_variable_another_way(self, input_str): input_str, comment = self._get_input_wo_commentar(input_str) input_str = ''.join(input_str.split()) # entferne alle leerzeichen input_str = input_str.replace(',', '.') opdel = self._operators + self._delimiters chunks = list() last_index = 0 for i, v in enumerate(input_str): if v in opdel: chunk = input_str[last_index:i] chunk = self._is_a_variable_or_func(chunk) chunks.append(chunk) chunks.append(input_str[i]) last_index = i+1 elif i == len(input_str)-1: chunk = input_str[last_index:i+1] chunk = self._is_a_variable_or_func(chunk) chunks.append(chunk) return eval(''.join(chunks)) def _is_a_variable_or_func(self, chunk): chunk = chunk.strip() var = self._vars.get(chunk) if not var: var = self._funcs.get(chunk) if var: var = self._with_variable_another_way(var) if var: return str(var) else: return chunk def _replace_vars(self, input_str): ''' try to find vars and replace them :param input_str: :return: ''' first_position = None new_input_str = '' op_del = self._operators + self._delimiters if input_str[0] in self._operators: input_str = 'result' + input_str input_str_len = len(input_str) for i, c in enumerate(input_str): if c in op_del or i == input_str_len-1: # and first_position is not None: if first_position is not None: last_position = i if i == input_str_len-1: last_position += 1 temp_var = input_str[first_position:last_position] var = self._vars.get(temp_var) if var is not None: new_input_str += str(var) else: func = self._funcs.get(temp_var) if func: new_input_str += str(func) else: raise NotImplemented() first_position = None if i == input_str_len - 1: continue new_input_str += input_str[i] elif c.isalpha() or c=='_': if first_position is None: first_position = i else: new_input_str += input_str[i] return new_input_str def _get_input_wo_commentar(self, input_str): ''' Zerlege input in input und kommentar :param input_str: :return: ''' input_str = input_str.strip() comment_index = input_str.find('#') if comment_index == 0: # die ganze zeile ist ein kommentar return None, input_str elif comment_index == -1: return input_str, None else: comment = input_str[comment_index + 1:] input_str = input_str[:comment_index] return input_str, comment def _is_new_variable(self, input_str): ''' ''' chunks = input_str.split('=') chunks_len = len(chunks) if chunks_len > 2: raise ValueError() # chunks.reverse() elif chunks_len == 2: return chunks[1].strip(), chunks[0].strip() else: return chunks[0].strip(), None