实现一个编译器(二)

 

 

接上文实现一个编译器

添加了一些内容:


1. 支持int,float的除法,以分母为准 4/3为1, 4/3.0为1.333
2. 单行注释// , 多行注释/* */
3. 支持闭包, self指代函数本身
4. 支持++,--,+= -=等
5. 内置函数len,str, int。内置list,map,值的读取和设置要用[];成员读取要用.
6. 支持显示的局部变量定义:var a = 1;表示定义a到函数作用域,(只有函数作用域, while if并不是作用域);
7. 报错显示行号
8. 无效的变量默认值为False
9. 字符串对象是只读的,不能通过列表赋值修改

这些是我认为应该有的功能,每个功能实现也不复杂。

现在pym看起来更像是一个脚本语言了。

 

  1 import re
  2 from collections import namedtuple
  3 import functools
  4 
  5 
  6 
  7 #
  8 # __all__ = [
  9 #     "Ready_Registers",
 10 #     "pym_warpper",
 11 #     "patterns",
 12 #     "Token",
 13 #     "Step",
 14 #     "PymError",
 15 #     "PymTokenizeError",
 16 #     "PymStepizeError",
 17 #     "PymBuildinError",
 18 #     "tokenize",
 19 #     "stepize",
 20 #
 21 #     "show_tokens",
 22 #     "show_steps",
 23 #     "show_var",
 24 #     "output_short",
 25 # ]
 26 
 27 Ready_Registers = []
 28 
 29 def pym_warpper(*names):
 30     def dec(func):
 31         @functools.wraps(func)
 32         def swapper(lineno, auto, *arg):
 33             try:
 34                 res = func(*arg) # 执行buildin-function
 35             except PymRunError as ex:
 36                 func_name = auto.namespace.get("__name__", None)
 37                 func_name = "函数"+func_name.value+"" if func_name else ""
 38                 # print("[PythonError]", ex, "(第"+str(lineno)+"行"+func_name+")(大概是因为错误调用了内置函数, 这种错误会直接导致游戏退出)" )
 39                 # raise Exception
 40                 raise PymRunError(str(ex)+"(第"+str(lineno)+""+func_name+")(大概是因为错误调用了内置函数)" )
 41             return res
 42         Ready_Registers.append((names, swapper))
 43         return swapper
 44     return dec
 45 
 46 patterns = [
 47     # ('\n',        r'(\n)'),
 48 
 49     ('comment', r'(\/\/.*)'),
 50     ('comment', r'(\/\*[\s\S]*?\*\/)'),
 51 
 52     ('cmp',        r'(==)'),
 53     ('cmp',        r'(!=)'),
 54     ('cmp',        r'(>=)'),
 55     ('cmp',        r'(<=)'),
 56     ('cmp',        r'(>)'),
 57     ('cmp',        r'(<)'),
 58 
 59     ('float',        r'(\d+\.\d+)'),
 60     ('int',        r'(\d+)'),
 61     ('str',        r"'([^\n']*)'"),
 62     ('str',        r'"([^\n"]*)"'),
 63 
 64     ('or',        r'(\|\|)'),
 65     ('or',        r'(\bor\b)'),
 66     ('and',        r'(&&)'),
 67     ('and',        r'(\band\b)'),
 68 
 69     ('inc',        r'(\+\+)'),
 70     ('dec',        r'(--)'),
 71 
 72     ('assign',    r'(\+=)'),
 73     ('assign',    r'(-=)'),
 74     ('assign',    r'(\/=)'),
 75     ('assign',    r'(\*=)'),
 76     ('assign',    r'(=)'),
 77 
 78     ('+',        r'(\+)'),
 79     ('-',        r'(-)'),
 80     ('*',        r'(\*)'),
 81     ('/',        r'(\/)'),
 82     ('not',        r'(!)'),
 83     ('not',        r'\b(not)\b'),
 84     ('print',    r'\b(print)\b'),
 85 
 86     (';',        r'(;)'),
 87     (':',        r'(:)'),
 88     (',',        r'(,)'),
 89     ('.',        r'(\.)'),
 90     ('(',        r'(\()'),
 91     (')',        r'(\))'),
 92     ('[',        r'(\[)'),
 93     (']',        r'(\])'),
 94     ('{',        r'(\{)'),
 95     ('}',        r'(\})'),
 96 
 97     ('if',        r'(\bif\b)'),
 98     ('else',    r'(\belse\b)'),
 99     ('for',        r'(\bfor\b)'),
100     ('while',    r'(\bwhile\b)'),
101     ('break',    r'(\bbreak\b)'),
102     ('continue', r'(\bcontinue\b)'),
103     ('return',    r'(\breturn\b)'),
104     ('function', r'(\bfunction\b)'),
105     ('True',    r'(\bTrue\b)'),
106     ('False',    r'(\bFalse\b)'),
107     ('var',    r'(\bvar\b)'),
108 
109     ('name',    r'([A-Za-z_][\w_]*)'),
110 
111 ]
112 
113 
114 class Token(namedtuple("Token", ["type", "value", "str", "lineno"])):
115     def __repr__(self):
116         return " {0:9} ==>  {1:8} ({2})"\
117             .format(self.type, self.value.replace("\n", r"\n"), self.str.replace("\n", r"\n"))
118 
119 
120 class Step(namedtuple("Step", ["type", "value", "lineno"])):
121     def __repr__(self):
122         return "[{3}] {0:14} ({2}){1:<12}"\
123             .format(self.type, str(self.value)
124                 .replace("\n", r"\n"), str(type(self.value)).replace("<type '", "").replace("'>", ""), self.lineno)
125 
126 
127 class PymError(Exception):
128     pass
129 
130 class PymTokenizeError(PymError):
131     pass
132 
133 class PymStepizeError(PymError):
134     pass
135 
136 class PymRunError( PymError ):
137     pass
138 
139 class Trans(object):
140     def __init__(self, tokens):
141         self.i = 0
142         self.tokens = tokens
143         self.l = len(tokens)
144         self.steps = []
145         self.continue_point = -1
146         self.break_point = -1
147 
148     def pos(self):
149         return len(self.steps)
150 
151     def type(self):
152         if self.i >= self.l:
153             return None
154         return self.tokens[self.i].type
155 
156     def prestr(self):
157         if self.i >= self.l:
158             return ""
159         return self.tokens[self.i].str
160 
161     def reset(self, pos, value):
162         lineno = self.tokens[self.i].lineno if self.i<self.l else self.tokens[-1].lineno
163         self.steps[pos] = Step(self.steps[pos].type, value, lineno)
164 
165     def value(self):
166         if self.i >= self.l:
167             return None
168         return self.tokens[self.i].value
169 
170     def push(self, t, v=None):
171         lineno = self.tokens[self.i].lineno if self.i<self.l else self.tokens[-1].lineno
172         self.steps.append(Step(t, v, lineno))
173 
174     def match(self, p):
175         if self.i >= self.l:
176             raise PymStepizeError("unexceptable end(第"+str(self.tokens[-1].lineno)+"行)")
177         if self.tokens[self.i].type != p:
178             raise PymStepizeError("缺少“"+p+"”(第"+str(self.tokens[self.i].lineno)+"行)")
179         self.i += 1
180 
181     def stmt(self):
182         if self.type() == ";":
183             self.match(";")
184         elif self.type() == "print":
185             self.i += 1
186             while 1:
187                 if self.type() == ';':
188                     self.i += 1
189                     break
190                 self.expr5()
191                 if self.type() == ',':
192                     self.i += 1
193                 elif self.type() == ';':
194                     self.i += 1
195                     break
196                 else:
197                     raise PymStepizeError("not ok-(第"+str(self.tokens[self.i if self.i<self.l else -1].lineno)+"行)")
198             self.push("PRINT")
199         elif self.type() == 'break':
200             self.break_point = self.pos()
201             self.push("JUMP")
202             self.i += 1
203             self.match(';')
204         elif self.type() == 'continue':
205             self.continue_point = self.pos()
206             self.push("JUMP")
207             self.i += 1
208             self.match(';')
209         elif self.type() == "return":
210             self.i += 1
211             if self.type() == ";":
212                 self.push("PUSH_CONST", None)
213                 self.i += 1
214             else:
215                 self.expr5()
216                 self.match(';')
217             self.push("RETURN")
218         # elif self.type() == 'function':
219         #     self.i += 1
220         #     name = ""
221         #     if self.type() == 'name':
222         #         self.push("PUSH_LOCAL_VAR",self.value())
223         #         name = self.value()
224         #         self.i += 1
225         #     self.match('(')
226         #     names = []
227         #     while 1:
228         #         if self.type() == 'name':
229         #             names.append(self.value())
230         #             self.i += 1
231         #         else:
232         #             self.match(')')
233         #             break
234         #         if self.type() == ',':
235         #             self.i += 1
236         #         elif self.type() == ')':
237         #             self.i += 1
238         #             break
239         #         else:
240         #             raise PymError("bad function")
241         #     s = ''
242         #     self.match('{')
243         #     count = 1
244         #     while 1:
245         #         if self.type() == '{':
246         #             count += 1
247         #         elif self.type() == '}':
248         #             count -= 1
249         #             if count == 0:
250         #                 self.i += 1
251         #                 break
252         #         s += self.prestr()
253         #         self.i += 1
254         #     self.push('PUSH_CONST', s)
255         #     self.push('PUSH_CONST', names)
256         #     self.push('MAKE_FUNCTION')
257         #     if name:
258         #         self.push("ASSIGN")
259         elif self.type() == 'if':
260             self.i += 1
261             self.match('(')
262             self.expr5()
263             self.match(')')
264             jump_pos = self.pos()
265             self.push('JUMP_IF_FALSE')
266             self.block()
267             if self.type() == 'else':
268                 self.i += 1
269                 jump_back_pos = self.pos()
270                 self.push('JUMP')
271                 self.reset(jump_pos, self.pos())
272                 self.block()
273                 self.reset(jump_back_pos, self.pos())
274             else:
275                 self.reset(jump_pos, self.pos())
276         elif self.type() == 'while':
277             self.i += 1
278             self.match('(')
279             jump_here = self.pos()
280             self.expr5()
281             self.match(')')
282             jump_pos = self.pos()
283             self.push('JUMP_IF_FALSE')
284             self.block()
285             self.push('JUMP', jump_here)
286             self.reset(jump_pos, self.pos())
287             if self.break_point != -1:
288                 self.reset(self.break_point, self.pos())
289                 self.break_point = -1
290             if self.continue_point != -1:
291                 self.reset(self.continue_point, jump_here)
292                 self.continue_point = -1
293         elif self.type() == 'var':
294             self.match('var')
295             name = self.value()
296             self.push("PUSH_LOCAL_VAR", name)
297             self.match('name')
298             if self.value() != '=':
299                 raise PymStepizeError('需要“=”(第"+str(self.tokens[self.i].lineno)+"行)')
300             self.match('assign')
301             self.expr5()
302             self.push("ASSIGN")
303             self.match(';')
304         else:
305             self.expr5()
306             if self.type() == ';':
307                 self.i += 1
308             elif self.type() == 'assign':
309                 t = self.value()
310                 self.i += 1
311                 if t != "=":
312                     self.push("PUSH_LAST_VAR")
313                 if t == '=':
314                     self.expr5()
315                     self.push("ASSIGN")
316                 elif t == '+=':
317                     self.expr5()
318                     self.push("ADD")
319                     self.push("ASSIGN")
320                 elif t == '*=':
321                     self.expr5()
322                     self.push("MUL")
323                     self.push("ASSIGN")
324                 elif t == '-=':
325                     self.expr5()
326                     self.push("SUB")
327                     self.push("ASSIGN")
328                 elif t == '/=':
329                     self.expr5()
330                     self.push("DIV")
331                     self.push("ASSIGN")
332                 else:
333                     raise PymStepizeError("bad assign(第"+str(self.tokens[self.i].lineno)+"行)")
334                 self.match(';')
335             elif self.type() == "inc":
336                 self.i += 1
337                 self.push("INC")
338                 self.match(';')
339             elif self.type() == "dec":
340                 self.i += 1
341                 self.push("DEC")
342                 self.match(';')
343             self.push("POP_ALL")
344 
345     def expr(self):
346         if self.type() == "int":
347             self.push("PUSH_CONST", int(self.value()))
348             self.i += 1
349         elif self.type() == 'float':
350             self.push("PUSH_CONST", float(self.value()))
351             self.i += 1
352         elif self.type() == "False":
353             self.push("PUSH_CONST", False)
354             self.i += 1
355         elif self.type() == "True":
356             self.push("PUSH_CONST", True)
357             self.i += 1
358         elif self.type() == "not":
359             self.i += 1
360             self.expr()
361             self.push("NOT")
362         elif self.type() == "-":
363             self.i += 1
364             self.expr()
365             self.push("NEG")
366         elif self.type() == "str":
367             self.push("PUSH_CONST", str(self.value()))
368             self.i += 1
369         elif self.type() == "name":
370             self.push("PUSH_VAR", self.value())
371             self.i += 1
372         elif self.type() == '(':
373             self.i += 1
374             self.expr5()
375             self.match(")")
376         elif self.type() == '[':
377             self.i += 1
378             count = 0
379             while self.type() != ']':
380                 self.expr5()
381                 count += 1
382                 if self.type() == ']':
383                     break
384                 self.match(',')
385             self.match(']')
386             self.push("BUILD_LIST", count)
387         elif self.type() == '{':
388             self.i += 1
389             count = 0
390             while self.type() != '}':
391                 self.expr5()
392                 self.match(':')
393                 self.expr5()
394                 count += 1
395                 if self.type() == '}':
396                     break
397                 self.match(',')
398             self.match('}')
399             self.push("BUILD_MAP", count)
400         elif self.type() == 'function':
401             self.i += 1
402             name = ""
403             if self.type() == 'name':
404                 name = self.value()
405                 self.push("PUSH_LOCAL_VAR", name)
406                 self.i += 1
407             self.match('(')
408             names = []
409             while 1:
410                 if self.type() == 'name':
411                     names.append(self.value())
412                     self.i += 1
413                 else:
414                     self.match(')')
415                     break
416                 if self.type() == ',':
417                     self.i += 1
418                 elif self.type() == ')':
419                     self.i += 1
420                     break
421                 else:
422                     raise PymStepizeError("bad function(第"+str(self.tokens[self.i].lineno)+"行)")
423             functiontokens = []
424             self.match('{')
425             count = 1
426             while 1:
427                 if self.type() == '{':
428                     count += 1
429                 elif self.type() == '}':
430                     count -= 1
431                     if count == 0:
432                         self.i += 1
433                         break
434                 if self.i<self.l:
435                     functiontokens.append(self.tokens[self.i])
436                     self.i += 1
437                 else:
438                     raise PymStepizeError("bad function(第"+str(self.tokens[self.i].lineno)+"行)")
439             self.push('PUSH_CONST', stepize(functiontokens))
440             self.push('PUSH_CONST', names)
441             self.push('MAKE_FUNCTION')
442             if name:
443                 self.push('ASSIGN')
444         self.name_tail()
445 
446     def name_tail(self):
447         while True:
448             if self.type() == "(":
449                 self.i += 1
450                 count = 0
451                 while 1:
452                     if self.type() == ")":
453                         self.i += 1
454                         break
455                     self.expr5()
456                     count += 1
457                     if self.type() == ",":
458                         self.i += 1
459                     elif self.type() == ")":
460                         self.i += 1
461                         break
462                     else:
463                         raise PymStepizeError("not ok(第"+str(self.tokens[self.i].lineno)+"行)")
464                 self.push("CALL", count)
465             elif self.type() == '[':
466                 self.i += 1
467                 self.expr5()
468                 self.match(']')
469                 self.push("GET_ITEM")
470             elif self.type() == '.':
471                 self.i += 1
472                 if self.type() != 'name':
473                     raise PymStepizeError("need a name(第"+str(self.tokens[self.i].lineno)+"行)")
474                 self.push("PUSH_CONST", self.value())
475                 self.i += 1
476                 self.push("GET_METHOD")
477             elif self.type() == "inc":
478                 self.i += 1
479                 self.push("INC")
480             else:
481                 break
482 
483     def expr1(self):
484         self.expr()
485         while self.type() == '*' or self.type() == '/':
486             t = self.type()
487             self.i += 1
488             self.expr()
489             if t == "*":
490                 self.push("MUL")
491             else:
492                 self.push("DIV")
493 
494     def expr2(self):
495         self.expr1()
496         while self.type() == '+' or self.type() == '-':
497             t = self.type()
498             self.i += 1
499             self.expr1()
500             if t == "+":
501                 self.push("ADD")
502             else:
503                 self.push("SUB")
504 
505     def expr3(self):
506         self.expr2()
507         while self.type() == "cmp":
508             t = self.value()
509             self.i += 1
510             self.expr2()
511             if t == ">=":
512                 self.push("GE")
513             elif t == "<=":
514                 self.push("LE")
515             elif t == "<":
516                 self.push("LT")
517             elif t == ">":
518                 self.push("GT")
519             elif t == "==":
520                 self.push("EQ")
521             else:
522                 self.push("NE")
523 
524     def expr4(self):
525         self.expr3()
526         while self.type() == 'or' or self.type() == 'and':
527             t = self.type()
528             self.i += 1
529             self.expr3()
530             if t == "or":
531                 self.push("OR")
532             else:
533                 self.push("AND")
534 
535     def expr5(self):
536         self.expr4()
537 
538     def block(self):
539         if self.type() == '{':
540             self.i += 1
541             while self.type() != '}':
542                 self.stmt()
543             self.i += 1
544         else:
545             self.stmt()
546 
547     def eval(self):
548         while self.i < self.l:
549             self.stmt()
550 
551 def tokenize(buf):
552     if type(buf) == "str":
553         raise PymTokenizeError("not a function")
554     tokens = []
555     lineno = 1
556     i = 0
557     l = len(buf)
558     while i < l:
559         prestr = ""
560         while i < l and buf[i] in " \r\n\t":
561             prestr += buf[i]
562             i += 1
563         if i >= l:
564             break
565         for t, p in patterns:
566             m = re.match(p, buf[i:])
567             if m:
568                 prestr += m.group(0)
569                 lineno += prestr.count("\n")
570                 token = Token(t, m.group(1), prestr, lineno)
571                 tokens.append(token)
572                 i += len(m.group(0))
573                 break
574         else:
575             raise PymTokenizeError("不符合任何匹配规则(第"+str(lineno)+"行)")
576     return tokens
577 
578 def stepize(tokens):
579     # 把tokens里面的注释token去掉
580     tokens = [token for token in tokens if token.type != 'comment']
581     t = Trans(tokens)
582     t.eval()
583     return t.steps
pymtoolkit.py
  1 from pymtoolkit import *
  2 
  3 show_tokens = False
  4 show_steps = False
  5 show_var = False
  6 output_short = False
  7 
  8 class Auto(object):
  9 
 10     def __init__(self, value=None, belongto=None, argnames=None, name=None, buildin=None, code=None):
 11         self.value = value if value is not None else False
 12         self.belongto = belongto
 13         self.argnames = argnames or []
 14         self.buildin = buildin
 15         self.tokens = None
 16         self.code = code
 17         if name:
 18             self.namespace = {'self': self, '__name__': Auto(name, belongto=self)}
 19         else:
 20             self.namespace = {'self': self}
 21 
 22         self.steps = []
 23 
 24         self.stack = []
 25         self.l = 0
 26         self.i = 0
 27 
 28     def copy(self):
 29         name = self.namespace.get("__name__", None)
 30         name = name.value if name else ""
 31         auto = Auto(self.value, self.belongto, self.argnames, name=name, buildin=self.buildin, code=self.code)
 32         auto.steps = self.steps
 33 
 34     def __repr__(self):
 35         if self.code:
 36             name = self.namespace.get("__name__", None)
 37             name = name.value if name else ""
 38             s = "<function "+name+">"
 39         else:
 40             s = str(self.value).replace("\n", r"\n")
 41         if output_short and len(s) > 15:
 42             return s[:10]+'...'
 43         return s
 44 
 45     def get_name(self):
 46         name = self.namespace.get("__name__", None)
 47         return str(name) if name else ""
 48 
 49     def call(self, args=None, lineno=-1):
 50         if self.buildin is not None:
 51             return self.buildin(lineno, self, args)
 52         self.stack = []
 53         # if not self.code:
 54         #     raise PymError(str(self.namespace["__name__"] or "")
 55         #                    +"不是可执行的函数"+("(第{0}行)".format(lineno) if lineno>=0 else ""))
 56         if args:
 57             for x, y in zip(self.argnames, args):
 58                 y.namespace['__name__'] = Auto(x)
 59                 self.namespace[x] = y
 60         self.namespace["self"] = self
 61 
 62         # funcname = ''
 63         # if not self.steps:
 64         #     funcname = self.namespace.get('__name__', None)
 65         #     funcname = str(funcname.value) if funcname else ""
 66         #     if show_tokens:
 67         #         print("\n[TOKENIZE "+funcname+"]")
 68         #     tokens = tokenize(self.code, lineno)
 69         #     stepstmp = stepize(tokens)
 70         #     if show_steps:
 71         #         print("\n[STEPIZE "+funcname+"]")
 72         #         for i, x in enumerate(stepstmp):
 73         #             print(" {0:3}".format(i), x)
 74         #     self.steps = stepstmp
 75 
 76         # run steps
 77         # if show_var:
 78         #     print("\n[CALL "+funcname+"]")
 79         self.l = len(self.code)
 80         self.i = 0
 81         try:
 82             while self.i < self.l:
 83                 self.step_once()
 84         except PymRunError as e:
 85             raise PymRunError(e)
 86         #     lineno = self.code[self.i].lineno if self.i<self.l else self.code[-1].lineno
 87         #     raise PymRunError(str(e)+"(第"+str(lineno)+"行)")
 88         # if show_var:
 89         #     print("[END "+funcname+"]\n")
 90 
 91         return self.stack[0] if self.stack else Auto()
 92 
 93     def step_once(self):
 94         t = self.code[self.i]
 95         if show_var:
 96             print(self.i, ":", t)
 97         self.i += 1
 98         if t.type == "PUSH_LAST_VAR":
 99             self.stack.append(self.stack[-1])
100         elif t.type == "PUSH_VAR":
101             a = self.namespace.get(t.value)
102             b = self.belongto
103             # print("belongto", self.belongto)
104             while a is None and b is not None:
105                 a = b.namespace.get(t.value, None)
106                 b = b.belongto
107             if a is None:
108                 a = Auto(None, belongto=self, name=t.value)
109                 self.namespace[t.value] = a
110             self.stack.append(a)
111         elif t.type == "PUSH_LOCAL_VAR":
112             a = self.namespace.get(t.value)
113             if a is None:
114                 a = Auto(None, belongto=self, name=t.value)
115                 self.namespace[t.value] = a
116             self.stack.append(a)
117         elif t.type == "ASSIGN":
118             value = self.stack.pop()
119             target = self.stack.pop()
120             target.value = value.value
121             # print("[test]", value.belongto)
122             target.belongto = value.belongto
123             target.steps = value.steps
124             target.argnames = value.argnames
125             target.buildin = value.buildin
126             target.code = value.code
127             namespace = value.namespace.copy()
128             namespace["self"] = target
129             namespace["__name__"] = target.namespace.get("__name__") or ""
130             target.namespace = namespace
131         elif t.type == "PUSH_CONST":
132             self.stack.append(Auto(t.value, belongto=self))
133         elif t.type == "POP_ALL":
134             self.stack = []
135         elif t.type == "GE":
136             a = self.stack.pop()
137             b = self.stack.pop()
138             self.stack.append(Auto(b.value >= a.value))
139         elif t.type == "GT":
140             a = self.stack.pop()
141             b = self.stack.pop()
142             self.stack.append(Auto(b.value > a.value))
143         elif t.type == "LE":
144             a = self.stack.pop()
145             b = self.stack.pop()
146             self.stack.append(Auto(b.value <= a.value))
147         elif t.type == "LT":
148             a = self.stack.pop()
149             b = self.stack.pop()
150             self.stack.append(Auto(b.value < a.value))
151         elif t.type == "EQ":
152             a = self.stack.pop()
153             b = self.stack.pop()
154             self.stack.append(Auto(b.value == a.value))
155         elif t.type == "NE":
156             a = self.stack.pop()
157             b = self.stack.pop()
158             self.stack.append(Auto(b.value != a.value))
159         elif t.type == "ADD":
160             a = self.stack.pop()
161             b = self.stack.pop()
162             # print("a,b = ",a,b)
163             self.stack.append(Auto(b.value + a.value))
164         elif t.type == "SUB":
165             a = self.stack.pop()
166             b = self.stack.pop()
167             self.stack.append(Auto(b.value - a.value))
168         elif t.type == "MUL":
169             b = self.stack.pop()
170             a = self.stack.pop()
171             self.stack.append(Auto(b.value * a.value))
172         elif t.type == "DIV":
173             a = self.stack.pop()
174             b = self.stack.pop()
175             if isinstance(a.value, int):
176                 self.stack.append(Auto(b.value // a.value))
177             else:
178                 self.stack.append(Auto(b.value / a.value))
179         elif t.type == "AND":
180             a = self.stack.pop()
181             b = self.stack.pop()
182             self.stack.append(Auto(b.value and a.value))
183         elif t.type == "OR":
184             a = self.stack.pop()
185             b = self.stack.pop()
186             self.stack.append(Auto(b.value or a.value))
187         elif t.type == "NOT":
188             a = self.stack.pop()
189             self.stack.append(Auto(not a.value))
190         elif t.type == "NEG":
191             a = self.stack.pop()
192             if isinstance(a.value, str):
193                 self.stack.append(Auto(a.value[::-1]))
194             else:
195                 self.stack.append(Auto(-a.value))
196         elif t.type == "JUMP_IF_FALSE":
197             a = self.stack.pop()
198             if not a.value:
199                 self.i =  int(t.value)
200         elif t.type == "JUMP":
201             self.i = int(t.value)
202         elif t.type == "PRINT":
203             print(*self.stack)
204             self.stack = []
205         elif t.type == "GET_METHOD":
206             a = self.stack.pop()
207             b = self.stack.pop()
208             c = b.namespace.get(a.value, None)
209             if c is None:
210                 c = Auto(None, belongto=b, name=a.value)
211                 b.namespace[a.value] = c
212             self.stack.append(c)
213         elif t.type == "CALL":
214             args = self.stack[-t.value:] if t.value else []
215             for x in range(t.value):
216                 self.stack.pop()
217             a = self.stack.pop()
218             self.stack.append(a.call(args, lineno=t.lineno))
219         elif t.type == "RETURN":
220             a = self.stack.pop()
221             self.stack = [a]
222             self.i = self.l
223         elif t.type == "MAKE_FUNCTION":
224             a = self.stack.pop()
225             b = self.stack.pop()
226             if isinstance(b.value, list) and isinstance(a.value, list):
227                 self.stack.append(Auto("<function>", argnames=a.value, belongto=self, code=b.value or []))
228             else:
229                 self.stack.append(Auto(None))
230         elif t.type == 'BUILD_LIST':
231             l = self.stack[-t.value:] if t.value else []
232             for x in range(t.value):
233                 self.stack.pop()
234             self.stack.append(Auto(l))
235         elif t.type == 'BUILD_MAP':
236             m = {}
237             for x in range(t.value):
238                 v = self.stack.pop()
239                 i = self.stack.pop()
240                 m[i.value] = v
241             self.stack.append(Auto(m))
242         elif t.type == 'GET_ITEM':
243             a = self.stack.pop()
244             b = self.stack.pop()
245             if isinstance(a.value, int) and isinstance(b.value, list):
246                 if a.value < len(b.value):
247                     c = b.value[a.value]
248                 else:
249                     for x in range(len(b.value), a.value+1):
250                         b.value.append(Auto())
251                     c = b.value[-1]
252             elif isinstance(a.value, int) and isinstance(b.value, str):
253                 if a.value < len(b.value):
254                     c = Auto(b.value[a.value])
255                 else:
256                     c = Auto()
257             elif isinstance(a.value, str) and isinstance(b.value, dict):
258                 c = b.value.get(a.value,None)
259                 if c is None:
260                     c = Auto()
261                     b.value[a.value] = c
262             else:
263                 raise PymRunError("error in getitem"+"(第{0}行)".format(t.lineno))
264             c.belongto = b
265             self.stack.append(c)
266         else:
267             raise PymRunError('canot run '+t.type+"(第{0}行)".format(t.lineno))
268         if show_var:
269             print(" "*40,self.stack)
270             print(" "*40,self.namespace)
271 
272     def func_register(self, name, func):
273         self.namespace[name] = Auto("<buildin-function "+name+'>',
274                                     buildin=func, name=name, belongto=self)
275 
276     def method_register(self, father, name, func):
277         father_auto = self.namespace[father]
278         if father_auto:
279             father_auto.namespace[name] = Auto("<buildin-function "+name+'>',
280                                     buildin=func, name=name, belongto=father_auto)
281 
282     def multi_register(self, func, *names):
283         if len(names) == 1:
284             self.func_register(names[0], func)
285         elif len(names) == 2:
286             self.method_register(names[0], names[1], func)
287 
288 
289 # 使用装饰器pym_warpper自定义内置函数
290 # 内置函数在python中有且仅有一个参数args
291 # args是个数组,其中包含了pym中传过来的Auto变量
292 # 函数需要返回一个Auto变量
293 # 最后内置函数用func_register或method_register挂到pym运行环境里
294 
295 @pym_warpper("str")
296 def function_str(args):
297     return Auto(str(args[0])) if args else Auto()
298 
299 @pym_warpper("int")
300 def function_int(args):
301     return Auto(it(args[0])) if args else Auto()
302 
303 @pym_warpper("len")
304 def function_len(args):
305     return Auto(len(args[0].value)) if args else Auto()
306 
307 @pym_warpper("format")
308 def function_format(args):
309     return Auto(args[0].value.format(*args[1:])) if len(args)>=2 else Auto()
310 
311 
312 @pym_warpper("require")
313 def function_require(args):
314     if not args:
315         return Auto()
316     path = args[0].value
317     if not path or not isinstance(path, str):
318         return Auto()
319     return Auto()
320 
321 @pym_warpper("exec")
322 def function_exec(args):
323     if len(args) != 2:
324         return Auto()
325     # if not isinstance(args[1].value, str):
326     #     raise PymRunError("buildin-function exec need a argument(str)")
327     # print(type(args[0].value), args[0].value)
328     # print("comp", auto.get_name(), args[1].get_name())
329     PymRuntime(args[0], with_buildin=False).exec(args[1].value, args[0].get_name())
330     return Auto()
331 
332 #
333 # @pym_warpper("std")
334 # def function_standard(args):
335 #     return Auto()
336 # @pym_warpper("std", "pow")
337 # def method_standard_pow(args):
338 #     return Auto(args[0].value**args[1].value) if len(args)>=2 else Auto()
339 
340 class PymRuntime:
341     def __init__(self, base=None, with_buildin=True):
342         if not base:
343             base = Auto(code=[], name='__main__')
344         if with_buildin:
345             for names, func in Ready_Registers:
346                 base.multi_register(func, *names)
347             base.call()
348         self.run_time = base
349 
350     def exec(self, code, filename = ""):
351         filename = ("("+filename+")") if filename else ""
352         try:
353             tokens = tokenize(code)
354             stepstmp = stepize(tokens)
355             if show_tokens:
356                 print("\n[TOKENIZE "+filename+"]")
357                 print("\n".join([str(t) for t in tokens]))
358             if show_steps:
359                 print("\n[STEPIZE "+filename+"]")
360                 for i, x in enumerate(stepstmp):
361                     print(" {0:3}".format(i), x)
362 
363             # 函数运行时的压栈(为了实现嵌套调用exec)
364             last_code = self.run_time.code
365             last_i = self.run_time.i
366             last_l = self.run_time.l
367 
368             # 函数执行
369             self.run_time.code = stepstmp or []
370             self.run_time.call()
371 
372             # 函数执行完毕,返回上一层
373             self.run_time.code = last_code
374             self.run_time.i = last_i
375             self.run_time.l = last_l
376         except PymTokenizeError as e:
377             print("[PymTokenizeError]", e, filename)
378         except PymStepizeError as e:
379             print("[PymStepizeError]", e, filename)
380         except PymRunError as e:
381             print("[PymRunError]", e, filename)
382         # finally:
383         #     raise Exception
384         # except Exception as e:
385         #     print("[PythonError]", e, filename)
386 
387 
388 if __name__ == '__main__':
389     pym = PymRuntime()
390     pym.exec(open("hello.pym", encoding='utf-8').read(), filename="hello.pym")
391     # PymRuntime(pym.run_time).exec("a = 1; a += 1; print a;", filename="hello.pym")
392     # pym.exec("a += 1; print a;", filename="hello.pym")
393     # pym.exec("")
394     # pym.exec('a = 1; a += 1; print "ad\ns";')
pym.py

 

另外,做了一个repl服务器:

 

 

 

总之挺帅的。
posted @ 2019-09-16 20:51  backinfile  阅读(259)  评论(0编辑  收藏  举报