实现一个编译器(二)
接上文实现一个编译器
添加了一些内容:
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
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";')
另外,做了一个repl服务器:
总之挺帅的。