Python/AST作成を読む
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[Pythonを読む]]
#contents
*PyAST_FromNodeObject (Python/ast.c) [#qe7c696b]
スクリプトをノードにできたので次に進みます。Rubyだとこの...
AST変換のトップレベル関数であるPyAST_FromNodeObjectではノ...
single_input
simple_stmt
small_stmt
expr_stmt
(以下略)
以下のコードが実行されることがわかります。
#code(C){{
case single_input:
if (TYPE(CHILD(n, 0)) == NEWLINE) {
// こっちじゃない
}
else {
n = CHILD(n, 0);
num = num_stmts(n);
stmts = _Py_asdl_seq_new(num, arena);
if (num == 1) {
s = ast_for_stmt(&c, n);
asdl_seq_SET(stmts, 0, s);
}
else {
// こっちじゃない
}
res = Interactive(stmts, arena);
}
break;
}}
simple_stmtを引数にしてast_for_stmtが呼び出されます。
*ast_for_stmt [#wa0c2f04]
ここからはノードに対応するast_*関数を使って変換が行われて...
#code(C){{
static stmt_ty
ast_for_stmt(struct compiling *c, const node *n)
{
if (TYPE(n) == stmt) {
assert(NCH(n) == 1);
n = CHILD(n, 0);
}
if (TYPE(n) == simple_stmt) {
assert(num_stmts(n) == 1);
n = CHILD(n, 0);
}
if (TYPE(n) == small_stmt) {
n = CHILD(n, 0);
/* small_stmt: expr_stmt | del_stmt | pass_stmt |...
| import_stmt | global_stmt | nonlocal_...
*/
switch (TYPE(n)) {
case expr_stmt:
return ast_for_expr_stmt(c, n);
}}
と、ast_for_expr_stmtに処理が回されます。なお、
+simple_stmtなのでCHILD取り出す→small_stmt
+small_stmtなのでCHILD取り出す→expr_stmt
と徐々にnが指すものが変わっていっているので注意してくださ...
*ast_for_expr [#c6cd5399]
関数はast_for_expr_stmt、ast_for_testlist、ast_for_exprと...
ここまでの知識を使って前回構築したノードをもう少しシンプ...
single_input
expr_stmt
power
atom_expr
atom
testlist_comp
power
atom_expr
atom
NAME(n)
comp_for
exprlist
power
atom_expr
atom
NAME(n)
power
atom_expr
atom
NAME(range)
trailer
arglist
argument
power
atom_expr
atom
NUMBER(10)
comp_iter
comp_if
comparison
term
power
atom_expr
atom
NAME(n)
*
power
atom_expr
atom
NAME(n)
comp_op
>
power
atom_expr
atom
NUMBER(10)
だいぶシンプルになりました。多分ここもシンプルになるとい...
*ast_for_atom [#i8d50db5]
処理はast_for_power、ast_for_atom_expr、ast_for_atomと進...
single_input
expr_stmt
testlist_comp
NAME(n)
comp_for
exprlist
NAME(n)
atom_expr
NAME(range)
trailer
arglist
argument
NUMBER(10)
comp_iter
comp_if
comparison
term
NAME(n)
*
NAME(n)
comp_op
>
NUMBER(10)
となります。一画面に収まるようになりました。
なお、NAMEの場合、
#code(C){{
case NAME: {
PyObject *name;
const char *s = STR(ch);
// None, True, Falseの処理
name = new_identifier(s, c);
/* All names start in Load context, but may later be ...
return Name(name, Load, LINENO(n), n->n_col_offset, c...
}
}}
とNameが返されています。第二引数のコンテキストというもの...
さて、実はast_for_atomを見ていると'['などもノードの子とし...
*ast_for_itercomp [#yab5368d]
ast_for_listcompはast_for_itercompを呼び出すだけです。エ...
#code(C){{
static expr_ty
ast_for_itercomp(struct compiling *c, const node *n, int ...
{
/* testlist_comp: (test|star_expr)
* ( comp_for | (',' (test|star_expr))...
expr_ty elt;
asdl_seq *comps;
node *ch;
ch = CHILD(n, 0);
elt = ast_for_expr(c, ch);
comps = ast_for_comprehension(c, CHILD(n, 1));
if (type == COMP_GENEXP)
return GeneratorExp(elt, comps, LINENO(n), n->n_c...
else if (type == COMP_LISTCOMP)
return ListComp(elt, comps, LINENO(n), n->n_col_o...
else if (type == COMP_SETCOMP)
return SetComp(elt, comps, LINENO(n), n->n_col_of...
}
}}
子ノードの1つ目に対してast_for_exprが呼びだされています。...
その後、ast_for_comprehensionが呼ばれています。この部分は...
ast_for_comprephensionはforやifが何回も書けるのに対応する...
#code(C){{
static asdl_seq *
ast_for_comprehension(struct compiling *c, const node *n)
{
int i, n_fors;
asdl_seq *comps;
n_fors = count_comp_fors(c, n);
comps = _Py_asdl_seq_new(n_fors, c->c_arena);
for (i = 0; i < n_fors; i++) {
comprehension_ty comp;
asdl_seq *t;
expr_ty expression, first;
node *for_ch;
for_ch = CHILD(n, 1);
t = ast_for_exprlist(c, for_ch, Store);
expression = ast_for_expr(c, CHILD(n, 3));
first = (expr_ty)asdl_seq_GET(t, 0);
if (NCH(for_ch) == 1)
comp = comprehension(first, expression, NULL,...
if (NCH(n) == 5) {
int j, n_ifs;
asdl_seq *ifs;
n = CHILD(n, 4);
n_ifs = count_comp_ifs(c, n);
ifs = _Py_asdl_seq_new(n_ifs, c->c_arena);
for (j = 0; j < n_ifs; j++) {
n = CHILD(n, 0);
expression = ast_for_expr(c, CHILD(n, 1));
asdl_seq_SET(ifs, j, expression);
}
comp->ifs = ifs;
}
asdl_seq_SET(comps, i, comp);
}
return comps;
}
}}
n_forsもn_ifsも1です。というわけでforの直後のexprlist、in...
exprlistは名前の通り、exprをリスト処理しています。ここで...
*ast_for_trailer [#w9d2046f]
次、inの後のexpr、具体的にはrange(10)、関数呼び出しです。...
atom_expr
NAME(range)
trailer
arglist
argument
NUMBER(10)
ast_for_atom_exprに来た時に今度はast_for_trailerが呼び出...
#code(C){{
ast_for_trailer(struct compiling *c, const node *n, expr_...
{
/* trailer: '(' [arglist] ')' | '[' subscriptlist ']'...
subscriptlist: subscript (',' subscript)* [',']
subscript: '.' '.' '.' | test | [test] ':' [test] ...
*/
REQ(n, trailer);
if (TYPE(CHILD(n, 0)) == LPAR) {
if (NCH(n) == 2)
return Call(left_expr, NULL, NULL, LINENO(n),
n->n_col_offset, c->c_arena);
else
return ast_for_call(c, CHILD(n, 1), left_expr);
}
}
}}
が処理されます。なお、NCH(n)が2になるのは引数なしの場合な...
ast_for_callも結構長いです。まあ関数呼び出しはプログラム...
で、ast_for_call。arglistに普通の引数なのかキーワード引数...
*comparison(ast_for_expr) [#vdc75aa9]
これで「in range(10)」まで終わったので後はifの部分、「if ...
comparison
term
NAME(n)
*
NAME(n)
comp_op
>
NUMBER(10)
comparisonの処理がされているのはast_for_exprです。
#code(C){{
expr_ty expression;
asdl_int_seq *ops;
asdl_seq *cmps;
ops = _Py_asdl_int_seq_new(NCH(n) / 2, c->c_arena);
cmps = _Py_asdl_seq_new(NCH(n) / 2, c->c_arena);
for (i = 1; i < NCH(n); i += 2) {
cmpop_ty newoperator;
newoperator = ast_for_comp_op(c, CHILD(n, i));
expression = ast_for_expr(c, CHILD(n, i + 1));
asdl_seq_SET(ops, i / 2, newoperator);
asdl_seq_SET(cmps, i / 2, expression);
}
expression = ast_for_expr(c, CHILD(n, 0));
if (!expression) {
return NULL;
}
return Compare(expression, ops, cmps, LINENO(n),
n->n_col_offset, c->c_arena);
}}
なんでループしているのかと思ったらそういえばPythonは「0 <...
*ast_for_binop [#gda5853e]
というわけで先頭の子ノード、termです。ast_for_binopで処理...
*最終結果 [#ua447475]
以上、ノード(CSTというらしいです)がASTに変換される様子...
Interactive
Expr
ListComp
Name(n) Load
Comprephension
Name(n) Store
Call
Name(Range) Load
Num(10)
Compare
BinOp
Mult
Name(n) Load
Name(n) Load
Gt
Num(10)
非常にシンプルになりました。実際には単一の値ではなくシー...
終了行:
[[Pythonを読む]]
#contents
*PyAST_FromNodeObject (Python/ast.c) [#qe7c696b]
スクリプトをノードにできたので次に進みます。Rubyだとこの...
AST変換のトップレベル関数であるPyAST_FromNodeObjectではノ...
single_input
simple_stmt
small_stmt
expr_stmt
(以下略)
以下のコードが実行されることがわかります。
#code(C){{
case single_input:
if (TYPE(CHILD(n, 0)) == NEWLINE) {
// こっちじゃない
}
else {
n = CHILD(n, 0);
num = num_stmts(n);
stmts = _Py_asdl_seq_new(num, arena);
if (num == 1) {
s = ast_for_stmt(&c, n);
asdl_seq_SET(stmts, 0, s);
}
else {
// こっちじゃない
}
res = Interactive(stmts, arena);
}
break;
}}
simple_stmtを引数にしてast_for_stmtが呼び出されます。
*ast_for_stmt [#wa0c2f04]
ここからはノードに対応するast_*関数を使って変換が行われて...
#code(C){{
static stmt_ty
ast_for_stmt(struct compiling *c, const node *n)
{
if (TYPE(n) == stmt) {
assert(NCH(n) == 1);
n = CHILD(n, 0);
}
if (TYPE(n) == simple_stmt) {
assert(num_stmts(n) == 1);
n = CHILD(n, 0);
}
if (TYPE(n) == small_stmt) {
n = CHILD(n, 0);
/* small_stmt: expr_stmt | del_stmt | pass_stmt |...
| import_stmt | global_stmt | nonlocal_...
*/
switch (TYPE(n)) {
case expr_stmt:
return ast_for_expr_stmt(c, n);
}}
と、ast_for_expr_stmtに処理が回されます。なお、
+simple_stmtなのでCHILD取り出す→small_stmt
+small_stmtなのでCHILD取り出す→expr_stmt
と徐々にnが指すものが変わっていっているので注意してくださ...
*ast_for_expr [#c6cd5399]
関数はast_for_expr_stmt、ast_for_testlist、ast_for_exprと...
ここまでの知識を使って前回構築したノードをもう少しシンプ...
single_input
expr_stmt
power
atom_expr
atom
testlist_comp
power
atom_expr
atom
NAME(n)
comp_for
exprlist
power
atom_expr
atom
NAME(n)
power
atom_expr
atom
NAME(range)
trailer
arglist
argument
power
atom_expr
atom
NUMBER(10)
comp_iter
comp_if
comparison
term
power
atom_expr
atom
NAME(n)
*
power
atom_expr
atom
NAME(n)
comp_op
>
power
atom_expr
atom
NUMBER(10)
だいぶシンプルになりました。多分ここもシンプルになるとい...
*ast_for_atom [#i8d50db5]
処理はast_for_power、ast_for_atom_expr、ast_for_atomと進...
single_input
expr_stmt
testlist_comp
NAME(n)
comp_for
exprlist
NAME(n)
atom_expr
NAME(range)
trailer
arglist
argument
NUMBER(10)
comp_iter
comp_if
comparison
term
NAME(n)
*
NAME(n)
comp_op
>
NUMBER(10)
となります。一画面に収まるようになりました。
なお、NAMEの場合、
#code(C){{
case NAME: {
PyObject *name;
const char *s = STR(ch);
// None, True, Falseの処理
name = new_identifier(s, c);
/* All names start in Load context, but may later be ...
return Name(name, Load, LINENO(n), n->n_col_offset, c...
}
}}
とNameが返されています。第二引数のコンテキストというもの...
さて、実はast_for_atomを見ていると'['などもノードの子とし...
*ast_for_itercomp [#yab5368d]
ast_for_listcompはast_for_itercompを呼び出すだけです。エ...
#code(C){{
static expr_ty
ast_for_itercomp(struct compiling *c, const node *n, int ...
{
/* testlist_comp: (test|star_expr)
* ( comp_for | (',' (test|star_expr))...
expr_ty elt;
asdl_seq *comps;
node *ch;
ch = CHILD(n, 0);
elt = ast_for_expr(c, ch);
comps = ast_for_comprehension(c, CHILD(n, 1));
if (type == COMP_GENEXP)
return GeneratorExp(elt, comps, LINENO(n), n->n_c...
else if (type == COMP_LISTCOMP)
return ListComp(elt, comps, LINENO(n), n->n_col_o...
else if (type == COMP_SETCOMP)
return SetComp(elt, comps, LINENO(n), n->n_col_of...
}
}}
子ノードの1つ目に対してast_for_exprが呼びだされています。...
その後、ast_for_comprehensionが呼ばれています。この部分は...
ast_for_comprephensionはforやifが何回も書けるのに対応する...
#code(C){{
static asdl_seq *
ast_for_comprehension(struct compiling *c, const node *n)
{
int i, n_fors;
asdl_seq *comps;
n_fors = count_comp_fors(c, n);
comps = _Py_asdl_seq_new(n_fors, c->c_arena);
for (i = 0; i < n_fors; i++) {
comprehension_ty comp;
asdl_seq *t;
expr_ty expression, first;
node *for_ch;
for_ch = CHILD(n, 1);
t = ast_for_exprlist(c, for_ch, Store);
expression = ast_for_expr(c, CHILD(n, 3));
first = (expr_ty)asdl_seq_GET(t, 0);
if (NCH(for_ch) == 1)
comp = comprehension(first, expression, NULL,...
if (NCH(n) == 5) {
int j, n_ifs;
asdl_seq *ifs;
n = CHILD(n, 4);
n_ifs = count_comp_ifs(c, n);
ifs = _Py_asdl_seq_new(n_ifs, c->c_arena);
for (j = 0; j < n_ifs; j++) {
n = CHILD(n, 0);
expression = ast_for_expr(c, CHILD(n, 1));
asdl_seq_SET(ifs, j, expression);
}
comp->ifs = ifs;
}
asdl_seq_SET(comps, i, comp);
}
return comps;
}
}}
n_forsもn_ifsも1です。というわけでforの直後のexprlist、in...
exprlistは名前の通り、exprをリスト処理しています。ここで...
*ast_for_trailer [#w9d2046f]
次、inの後のexpr、具体的にはrange(10)、関数呼び出しです。...
atom_expr
NAME(range)
trailer
arglist
argument
NUMBER(10)
ast_for_atom_exprに来た時に今度はast_for_trailerが呼び出...
#code(C){{
ast_for_trailer(struct compiling *c, const node *n, expr_...
{
/* trailer: '(' [arglist] ')' | '[' subscriptlist ']'...
subscriptlist: subscript (',' subscript)* [',']
subscript: '.' '.' '.' | test | [test] ':' [test] ...
*/
REQ(n, trailer);
if (TYPE(CHILD(n, 0)) == LPAR) {
if (NCH(n) == 2)
return Call(left_expr, NULL, NULL, LINENO(n),
n->n_col_offset, c->c_arena);
else
return ast_for_call(c, CHILD(n, 1), left_expr);
}
}
}}
が処理されます。なお、NCH(n)が2になるのは引数なしの場合な...
ast_for_callも結構長いです。まあ関数呼び出しはプログラム...
で、ast_for_call。arglistに普通の引数なのかキーワード引数...
*comparison(ast_for_expr) [#vdc75aa9]
これで「in range(10)」まで終わったので後はifの部分、「if ...
comparison
term
NAME(n)
*
NAME(n)
comp_op
>
NUMBER(10)
comparisonの処理がされているのはast_for_exprです。
#code(C){{
expr_ty expression;
asdl_int_seq *ops;
asdl_seq *cmps;
ops = _Py_asdl_int_seq_new(NCH(n) / 2, c->c_arena);
cmps = _Py_asdl_seq_new(NCH(n) / 2, c->c_arena);
for (i = 1; i < NCH(n); i += 2) {
cmpop_ty newoperator;
newoperator = ast_for_comp_op(c, CHILD(n, i));
expression = ast_for_expr(c, CHILD(n, i + 1));
asdl_seq_SET(ops, i / 2, newoperator);
asdl_seq_SET(cmps, i / 2, expression);
}
expression = ast_for_expr(c, CHILD(n, 0));
if (!expression) {
return NULL;
}
return Compare(expression, ops, cmps, LINENO(n),
n->n_col_offset, c->c_arena);
}}
なんでループしているのかと思ったらそういえばPythonは「0 <...
*ast_for_binop [#gda5853e]
というわけで先頭の子ノード、termです。ast_for_binopで処理...
*最終結果 [#ua447475]
以上、ノード(CSTというらしいです)がASTに変換される様子...
Interactive
Expr
ListComp
Name(n) Load
Comprephension
Name(n) Store
Call
Name(Range) Load
Num(10)
Compare
BinOp
Mult
Name(n) Load
Name(n) Load
Gt
Num(10)
非常にシンプルになりました。実際には単一の値ではなくシー...
ページ名: