>prg = """print 2*2"""
>pprint.pprint(parser.suite(prg).totuple())
>def pprint_ast(ast, level=0):
> if type(ast) == type(()):
> for a in ast:
> pprint_ast(a, level+1)
> elif type(ast) == type(""):
> print repr(ast)
> else:
> print " "*level,
> try:
> print symbol.sym_name[ast]
> except:
> print "token."+token.tok_name[ast],
>print
>pprint_ast(parser.suite(prg).totuple())
Эта программа выведет следующее (структура дерева отражена отступами):
>(257,
> (264,
> (265,
> (266,
> (269,
> (1, 'print'),
> (292,
> (293,
> (294,
> (295,
> (297,
> (298,
> (299,
> (300,
> (301,
> (302,
> (303, (304, (305, (2, '2')))),
> (16, '*'),
> (303, (304, (305, (2, '2')))))))))))))))),
> (4, ''))),
> (0, ''))
> file_input
> stmt
> simple_stmt
> small_stmt
> print_stmt
> token.NAME 'print'
> test
> and_test
> not_test
> comparison
> expr
> xor_expr
> and_expr
> shift_expr
> arith_expr
> term
> factor
> power
> atom
> token.NUMBER '2'
> token.STAR '*'
> factor
> power
> atom
> token.NUMBER '2'
> token.NEWLINE ''
> token.ENDMARKER ''
Получение байт-кода
После того как получено дерево синтаксического разбора, компилятор должен превратить его в байт-код, подходящий для исполнения интерпретатором. В следующей программе проводятся отдельно синтаксический анализ, компиляция и выполнение (вычисление) кода (и выражения) в языке Python:
>import parser
>prg = """print 2*2"""
>ast = parser.suite(prg)
>code = ast.compile('filename.py')
>exec code
>prg = """2*2"""
>ast = parser.expr(prg)
>code = ast.compile('filename1.py')
>print eval(code)
Функция >parser.suite()
(или >parser.expr()
) возвращает AST–объект (дерево синтаксического анализа), которое методом >compile()
компилируется в Python байт-код и сохраняется в кодовом объекте >code
. Теперь этот код можно выполнить (или, в случае выражения — вычислить) с помощью оператора >exec
(или функции >eval()
).
Здесь необходимо заметить, что недавно в Python появился пакет >compiler
, который объединяет модули для работы анализа исходного кода на Python и генерации кода. В данной лекции он не рассматривается, но те, кто хочет глубже изучить эти процессы, может обратиться к документации по Python.
Изучение байт-кода
Для изучения байт-кода Python–программы можно использовать модуль >dis
(сокращение от «дизассемблер»), который содержит функции, позволяющие увидеть байт-код в мнемоническом виде. Следующий пример иллюстрирует эту возможность:
>>>> def f():
>... print 2*2
>...
>>>> dis.dis(f)
> 2 0 LOAD_CONST 1 (2)
> 3 LOAD_CONST 1 (2)
> 6 BINARY_MULTIPLY
> 7 PRINT_ITEM
> 8 PRINT_NEWLINE
> 9 LOAD_CONST 0 (None)
> 12 RETURN_VALUE
Определяется функция >f()
, которая должна вычислить и напечатать значение выражения >2*2
. Функция