Bytecode - 一款 Python 字节码编译工具
查看原文
bytecode 是一款 Python (3.4+) 的字节码编译工具,它可以让你写 bytecode,进而通过 exec(bytecode.to_code())
执行它。
衍生思考:感觉比较有用的场景是写 DSL。用一个语法解析工具解析自定义的语法规则,然后将切分好的 Token 映射成 Bytecode,进而让 Python 解释器执行它。以下的小例子可以用于进制转换,分别展示了运行结果及其源代码。当然,只是为了验证下可行性,要想写出 Robust 的 DSL 代码,还需要很多细节上的考虑。
运行结果:
$ ./simple-pipe '15 | bin'
0b1111
$ ./simple-pipe '15 | oct'
0o17
$ ./simple-pipe '15 | hex'
0xf
源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 | #!/usr/bin/env python3
# -*- encoding: utf-8 -*-
# Save as `simple-pipe` and chmod +x for it.
# `virtualenv venv; source venv/bin/activate; pip install ply bytecode
import sys
import inspect
from bytecode import Instr, Bytecode
tokens = ('PIPE', 'NAME', 'NUMBER')
t_PIPE = r'\|'
t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'
t_ignore = " \t"
def t_NUMBER(t):
r'\d+'
t.value = int(t.value)
return t
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
import ply.lex as lex
lex.lex()
def p_command_single(p):
'command : expression'
p[0] = p[1]
def p_command_group(p):
'command : command PIPE expression'
p[0] = p[3] + p[1] + [
Instr("CALL_FUNCTION", 1),
]
def p_expression_int(p):
'expression : NUMBER'
p[0] = [
Instr('LOAD_CONST', int(p[1]))
]
def p_expression_name(p):
'expression : NAME'
p[0] = [
Instr('LOAD_NAME', p[1])
]
import ply.yacc as yacc
yacc.yacc()
s = sys.argv[1]
command_set = [Instr('LOAD_NAME', 'print')] + yacc.parse(s) + [Instr('CALL_FUNCTION', 1), Instr('LOAD_CONST', None), Instr('RETURN_VALUE')]
exec(Bytecode(command_set).to_code())
|