Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2020
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.93 KB | None | 0 0
  1. from transitions import Machine
  2. import re
  3.  
  4. class trace_cell:
  5.     def __init__(self, func_name: str, arg: int):
  6.         self.func_name: str = func_name
  7.         self.arg: int = arg
  8.         self.children: list[trace_cell] = []
  9.         self.cell_result: str
  10.  
  11. class trace_tree:
  12.     def __init__(self):
  13.         self.root: trace_cell = None
  14.  
  15.     def build_tree(self, code: str, funcs: list, func_call, type):
  16.         modified = self._modify_code(code, funcs, type)
  17.         exec(compile(modified, "<int>", "exec"), globals())
  18.         eval(func_call)
  19.         self.root = globals()['root']
  20.         return self.root
  21.  
  22.     def _modify_code(self, code: str, funcs: list, type):
  23.         args_dict = {}
  24.         for f in funcs:
  25.             args_dict[f.name] = f.arg
  26.         modified = "globals()['trace_stack'] = []\n" \
  27.                    "globals()['root'] = None\n"
  28.         last_ident = 0
  29.         for line in code.split("\n"):
  30.             ident = self._get_identation_size(line)
  31.             if ident == 0 and last_ident != 0:
  32.                 if type == "int":
  33.                     modified += "    cell.cell_result = str(int_result)\n"
  34.                 else:
  35.                     modified += "    cell.cell_result = globals()['text_result']\n"
  36.                 modified += "    globals()['trace_stack'].pop(0)\n" \
  37.                             "    return int_result\n"
  38.             last_ident = ident
  39.             if "return " in line:
  40.                 modified += line.replace("return ", "int_result = (") + ")\n"
  41.             else:
  42.                 modified += line + "\n"
  43.             if "def " in line:
  44.                 f = line[line.find(" ") + 1: line.find("(")]
  45.                 arg = args_dict[f]
  46.                 modified += "    if len(globals()['trace_stack']) >= 45:\n" \
  47.                             "        raise RecursionError\n" \
  48.                             "    cell = trace_cell('{0}', {1})\n" \
  49.                             "    if len(globals()['trace_stack']) != 0:\n" \
  50.                             "        globals()['trace_stack'][0].children.append(cell)\n" \
  51.                             "    else:\n" \
  52.                             "        globals()['root'] = cell\n" \
  53.                             "    globals()['trace_stack'] = [cell] + globals()['trace_stack']\n" \
  54.                             "    int_result = 0\n".format(f, arg)
  55.         return modified
  56.  
  57.     def _get_identation_size(self, line: str):
  58.         count = 0
  59.         for i in line:
  60.             if i != " " and i != "\t":
  61.                 return count
  62.             count += 1
  63.         return count
  64.  
  65. class condition:
  66.     def __init__(self):
  67.         self.cond = None
  68.         self.action = None
  69.  
  70.     cond: str
  71.     action: str
  72.  
  73.  
  74. class func:
  75.     def __init__(self):
  76.         self.name = None
  77.         self.conditions = []
  78.         self.arg = None
  79.  
  80.     name: str
  81.     arg:str
  82.     conditions: list
  83.  
  84.  
  85. class math_to_py:
  86.     _states = ["empty", "f_reading", "f_open", "f_n", "f_num", "f_n_close", "f_num_close",
  87.                "f_n_reading", "f_num_reading", "f_num_end", "cond_first", "cond_second", "cond_third", "f_n_end"]
  88.  
  89.     def __init__(self):
  90.         self.machine = Machine(model=self, states=math_to_py._states, initial="empty")
  91.         self.cur_symbol: str = ""
  92.         self.cur_string: str = ""
  93.         self.cur_func: func = None
  94.         self._create_casual_transitions()
  95.         self.funcs_dict: dict = {}
  96.         self.funcs: list[func] = []
  97.  
  98.     def _start_again(self):
  99.         self.cur_symbol = ""
  100.         self.cur_string = ""
  101.         self.machine.set_state("empty")
  102.  
  103.     def on_enter_f_num(self):
  104.         cond = condition()
  105.         cond.cond = "n == " + self.cur_symbol
  106.         self.cur_func.conditions.append(cond)
  107.  
  108.     def on_enter_f_num_end(self):
  109.         self.cur_func.conditions[-1].action = self.cur_string[:-1].strip()
  110.         self._start_again()
  111.  
  112.     def on_enter_cond_first(self):
  113.         cond = condition()
  114.         action = self.cur_string[:-1].strip()
  115.         action = action.replace("×", "*")
  116.         action = action.replace("·", "*")
  117.         action = action.replace("−", "-")
  118.         action = action.replace("–", "-")
  119.         action = action.replace("/", "//")
  120.         action = action.replace(":", "//")
  121.         action = action.replace("+", "+")
  122.         cond.action = action
  123.         self.cur_func.conditions.append(cond)
  124.         self.cur_string = ""
  125.  
  126.     def on_enter_f_n_end(self):
  127.         cond = self.cur_string[:-1].strip()
  128.         cond = cond.replace("=", "==")
  129.         cond = cond.replace("≤", "<=")
  130.         cond = cond.replace("≥", ">=")
  131.         self.cur_func.conditions[-1].cond = cond
  132.         self._start_again()
  133.  
  134.     def on_enter_f_open(self):
  135.         self.cur_string = self.cur_string[:-1]
  136.         charRe = re.compile(r'[^a-z_]')
  137.         if bool(charRe.search(self.cur_string)):
  138.             raise Exception()
  139.         if not self.cur_string in self.funcs_dict:
  140.             self.funcs_dict[self.cur_string] = func()
  141.             self.funcs_dict[self.cur_string].name = self.cur_string
  142.             self.funcs_dict[self.cur_string].arg = "n"
  143.         self.cur_func = self.funcs_dict[self.cur_string]
  144.         self.cur_string = ""
  145.  
  146.     def on_enter_f_reading(self):
  147.         self.cur_string += self.cur_symbol
  148.  
  149.     def is_f(self):
  150.         return self.cur_symbol.isalpha()
  151.  
  152.     def is_open_bracket(self):
  153.         return self.cur_symbol == "("
  154.  
  155.     def is_num(self):
  156.         return self.cur_symbol.isdigit()
  157.  
  158.     def is_close_bracket(self):
  159.         return self.cur_symbol == ")"
  160.  
  161.     def is_n(self):
  162.         return self.cur_symbol == "n"
  163.  
  164.     def is_eq(self):
  165.         return self.cur_symbol == "="
  166.  
  167.     def is_c0(self):
  168.         return self.cur_symbol == "п"
  169.  
  170.     def is_c00(self):
  171.         return self.cur_symbol == "р"
  172.  
  173.     def is_c000(self):
  174.         return self.cur_symbol == "и"
  175.  
  176.     def is_end(self):
  177.         return self.cur_symbol == ";" or self.cur_symbol == "."
  178.  
  179.     def _create_casual_transitions(self):
  180.         self.machine.add_transition("move", "empty", "f_reading", conditions="is_f")
  181.         self.machine.add_transition("move", "f_reading", "f_open", conditions="is_open_bracket")
  182.         self.machine.add_transition("move", "f_open", "f_num", conditions="is_num")
  183.         self.machine.add_transition("move", "f_num", "f_num_close", conditions="is_close_bracket")
  184.         self.machine.add_transition("move", "f_open", "f_n", conditions="is_n")
  185.         self.machine.add_transition("move", "f_n", "f_n_close", conditions="is_close_bracket")
  186.         self.machine.add_transition("move", "f_n_close", "f_n_reading", conditions="is_eq")
  187.         self.machine.add_transition("move", "f_num_close", "f_num_reading", conditions="is_eq")
  188.         self.machine.add_transition("move", "f_num_reading", "f_num_end", conditions="is_end")
  189.         self.machine.add_transition("move", "f_n_reading", "cond_first", conditions="is_c0")
  190.         self.machine.add_transition("move", "cond_first", "cond_second", conditions="is_c00")
  191.         self.machine.add_transition("move", "cond_second", "cond_third", conditions="is_c000")
  192.         self.machine.add_transition("move", "cond_third", "f_n_end", conditions="is_end")
  193.  
  194.     def break_to_funcs(self, lines):
  195.         for line in lines:
  196.             for i in line.lower() + ".":  # Точка нужна, чтобы последовательность ТОЧНО закончилась
  197.                 if (i == ","):
  198.                     continue
  199.                 self.cur_symbol = i
  200.                 if (self.machine.is_state("f_num_reading", self) or self.machine.is_state("f_reading", self) or
  201.                         self.machine.is_state("f_n_reading", self) or self.machine.is_state("cond_third", self)):
  202.                     self.cur_string += self.cur_symbol
  203.                 self.move()
  204.         self.funcs = list(self.funcs_dict.values())
  205.         return self.funcs
  206.  
  207.  
  208. class math_to_py_converter:
  209.     def convert(self, funcs: list) -> str:
  210.         code: str = ""
  211.         for f in funcs:
  212.             code += "def " + f.name + "(n):"
  213.             for cond in f.conditions:
  214.                 #ЗАГЛУШКИ
  215.                 if cond.cond.find("любом") != -1:
  216.                     if cond.action.find("print") != -1:
  217.                         code += "\n    " + cond.action
  218.                     else:
  219.                         code += "\n    return " + cond.action
  220.                     continue
  221.  
  222.                 if cond.cond.find("всех остальных") != -1:
  223.                     code += "\n    else:"
  224.                 else:
  225.                     code += "\n    if " + cond.cond + ":"
  226.  
  227.                 if cond.action.find("print") != -1:
  228.                     code += "\n        " + cond.action
  229.                 else:
  230.                     code += "\n        return " + cond.action
  231.             code += "\n"
  232.         return code
  233.  
  234.  
  235. ##УЖНО ОТРЕФАКТОРИТЬ!!!!)))) :( :( :( :( :( :( :(
  236. class py_to_math:
  237.  
  238.     def __init__(self):
  239.         self.cur_cond: condition = None
  240.         self.cur_func: func = None
  241.         self.funcs: list[func] = []
  242.         self.code: str = None
  243.  
  244.     def _get_identation_size(self, line: str):
  245.         count = 0
  246.         for i in line:
  247.             if i != " " and i != "\t":
  248.                 return count
  249.             count += 1
  250.         return count
  251.  
  252.     def _read_func(self, line: str):
  253.         self.cur_func = func()
  254.         self.funcs.append(self.cur_func)
  255.         func_str = line.strip()
  256.         self.cur_func.name = func_str[func_str.find(" ") + 1: func_str.find("(")]
  257.         self.cur_func.arg = func_str[func_str.find("(") + 1: func_str.find(")")]
  258.  
  259.     def _read_if_statement(self, line: str):
  260.         self.cur_cond = condition()
  261.         self.cur_func.conditions.append(self.cur_cond)
  262.         cond = line.strip()
  263.         self.cur_cond.cond = cond[cond.find(" ") + 1: -1]
  264.  
  265.     def _read_else_statement(self):
  266.         self.cur_cond = condition()
  267.         self.cur_func.conditions.append(self.cur_cond)
  268.         self.cur_cond.cond = "else"
  269.  
  270.     def _read_conditionless_action(self, line: str):
  271.         self.cur_cond = condition()
  272.         self.cur_func.conditions.append(self.cur_cond)
  273.         self.cur_cond.cond = "conditionless"
  274.         line = line.strip()
  275.         action = line if line.find("return") == -1 else line[line.find(" ") + 1:]
  276.         self.cur_cond.action = action
  277.  
  278.     def _read_action(self, line: str):
  279.         line = line.strip()
  280.         action = line if line.find("return") == -1 else line[line.find(" ") + 1:]
  281.         self.cur_cond.action = self.cur_cond.action + " + " + action if self.cur_cond.action != None else action
  282.  
  283.     def break_to_funcs(self, lines: list):
  284.         self.code = "globals()['text_result'] = ''\n"  # Для случаев с print
  285.         cur_indentation = -1
  286.         is_previous_cond = False  # Нужен для случаев действий вне блока if
  287.         for line in map(lambda s: s.lower(), lines):
  288.             if "input()" in line:
  289.                 raise Exception()
  290.             if line == "":
  291.                 continue
  292.             indentation = self._get_identation_size(line)
  293.             if indentation != cur_indentation:
  294.                 cur_indentation = indentation
  295.                 if line.find("def") != -1:
  296.                     self._read_func(line)
  297.                     is_previous_cond = False
  298.                 elif line.find("if") != -1:
  299.                     self._read_if_statement(line)
  300.                     is_previous_cond = True
  301.                 elif line.find("else") != -1:
  302.                     self._read_else_statement()
  303.                     is_previous_cond = True
  304.                 elif is_previous_cond:
  305.                     self._read_action(line)
  306.                     is_previous_cond = False
  307.                 else:
  308.                     self._read_conditionless_action(line)
  309.             elif line.find("if") != -1:
  310.                 self._read_if_statement(line)
  311.                 is_previous_cond = True
  312.             else:
  313.                 self._read_action(line)
  314.                 is_previous_cond = False
  315.             self.code += line.replace("print",
  316.                                       "globals()['text_result'] += str") + "\n"  # print(n) => globals()['text_result'] += str(n)
  317.         return self.funcs
  318.  
  319.  
  320. class py_to_math_converter:
  321.     def convert(self, funcs: list) -> str:
  322.         text: str = ""
  323.         for f in funcs:
  324.             for cond in f.conditions:
  325.                 cond_text = cond.cond
  326.                 cond_text = cond_text.replace("==", "=")
  327.                 cond_text = cond_text.replace("<=", "≤")
  328.                 cond_text = cond_text.replace(">=", "≥")
  329.                 if cond.action.strip() == "return":
  330.                     raise Exception()
  331.                 if cond.cond == "conditionless":
  332.                     text += ("{0}({1}) = {2} при любом {1};".format(f.name, f.arg, cond.action))
  333.                 elif cond.cond == "else":
  334.                     text += ("{0}({1}) = {2} при всех остальных {1};".format(f.name, f.arg, cond.action))
  335.                 else:
  336.                     text += ("{0}({1}) = {2} при {3};".format(f.name, f.arg, cond.action, cond_text))
  337.                 text += "\n"
  338.             text += "\n"
  339.         return text
  340.  
  341.  
  342. # exec для math->py: exec(compile(code, "<int>", "exec"), globals()) - код получать через math_to_py_converter
  343. # exec для py->math: exec(compile(code, "<int>", "exec"), globals()) - код в экземпляре класса py_to_math после выполнения break_to_funcs
  344. # в случае с return просто вызываешь функцию (можешь хоть прямо так её написать, типа f(7), но лучше через eval("f(7)")
  345. # в случае со звёздочками и принтами вызываешь функцию, а потом выводишь через globals()["text_result"]
  346.  
  347. def get_int_result_for(func_call: str, code: str):
  348.     exec(compile(code, "<int>", "exec"), globals())
  349.     return eval(func_call)
  350.  
  351.  
  352. def get_str_result_for(func_call: str, code: str):
  353.     exec(compile(code, "<int>", "exec"), globals())
  354.     eval(func_call)
  355.     return globals()["text_result"]
  356.  
  357.  
  358. ##ПРИМЕРЫ
  359. '''
  360. wm = math_to_py()
  361. funcs = wm.break_to_funcs(["f(n) = f(n-1) при n > 3; f(n) = 1 при всех остальных n;",
  362.                           "omg(n) = print('asdsdas') при любом n",
  363.                           "test(n) = print('*') при n > 2; test(n) = 1 при всех остальных n;"])
  364. math_to_py_code = math_to_py_converter.convert(math_to_py_converter, funcs)
  365. print(math_to_py_code)
  366. print(get_int_result_for("f(40)", math_to_py_code))
  367. cm = py_to_math()
  368. cm.break_to_funcs([
  369.    "def F(k):",
  370.    "    if k > 1:",
  371.    "        return F(k-1)+F(k-2)",
  372.    "    else:",
  373.    "        return 1"
  374. ])
  375. print(get_int_result_for("f(3)", cm.code))
  376. print(py_to_math_converter.convert(py_to_math_converter, cm.funcs))
  377. tt = trace_tree()
  378. tt.build_tree(cm.code, cm.funcs, "f(100)", "int")
  379. print(tt.root)
  380. '''
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement