Advertisement
Guest User

Untitled

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