Pythonを読む

Py_Main (Modules/main.c)

読んだことないので先頭から。main関数はPrograms/python.cにあります。argvがwchar_t**じゃないときは前処理が行われていますがさくっと無視して本体らしいPy_Main関数に移ります。こちらはディレクトリが変わってModules/main.cにあります。

Py_Main関数は500行ぐらいありますが、初めの300行ぐらいはコマンドラインの処理をしていますが無視します。

コマンドライン処理が終わったぐらいのところでPy_Initialize関数(Python/pylifecycle.c)を呼び出しています。この関数(から呼ばれている_Py_InitializeEx_Private)でインタプリタやらスレッドやらオブジェクトシステムやらを初期化していますがまあ呼ばれている関数は名前の通りの動作をしているのだろうということでその先を深追いはしません。

その後、コマンド指定(-c)がされているか、モジュール指定(-m)がされているか、ファイルが指定されているかによって処理が行われていますが今回は何も指定していないので、ファイルオープンなしのままrun_fileが呼ばれることになります。余計な部分を削ると、

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 
-
|
|
|
-
-
!
 
 
 
 
 
!
run_file(FILE *fp, const wchar_t *filename, PyCompilerFlags *p_cf)
{
    char *filename_str;
    int run;
 
    if (filename) {
        // 省略
    }
    else
        filename_str = "<stdin>";
 
    run = PyRun_AnyFileExFlags(fp, filename_str, filename != NULL, p_cf);
    return run != 0;
}

fpはstdinです。

PyRun_InteractiveOneObject (Python/pythonrun.c)

PyRun_AnyFileExFlags。入力がインタラクティブの時はInteractiveLoopに入って期待通りです。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 
 
 
-
-
|
|
|
|
!
|
|
!
int
PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit,
                     PyCompilerFlags *flags)
{
    if (Py_FdIsInteractive(fp, filename)) {
        int err = PyRun_InteractiveLoopFlags(fp, filename, flags);
        if (closeit)
            fclose(fp);
        return err;
    }
    else
        return PyRun_SimpleFileExFlags(fp, filename, closeit, flags);
}

PyRun_InteractiveLoopFlagsに進みます。エラー処理とかを省くと以下のような感じ。

Everything is expanded.Everything is shortened.
  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
 
 
-
|
|
|
|
|
|
-
|
|
!
|
-
|
|
!
|
-
|
-
|
|
!
!
|
|
!
int
PyRun_InteractiveLoopFlags(FILE *fp, const char *filename_str, PyCompilerFlags *flags)
{
    PyObject *filename, *v;
    int ret, err;
 
    filename = PyUnicode_DecodeFSDefault(filename_str);
 
    v = _PySys_GetObjectId(&PyId_ps1);
    if (v == NULL) {
        _PySys_SetObjectId(&PyId_ps1, v = PyUnicode_FromString(">>> "));
        Py_XDECREF(v);
    }
    v = _PySys_GetObjectId(&PyId_ps2);
    if (v == NULL) {
        _PySys_SetObjectId(&PyId_ps2, v = PyUnicode_FromString("... "));
        Py_XDECREF(v);
    }
    err = -1;
    for (;;) {
        ret = PyRun_InteractiveOneObject(fp, filename, flags);
        if (ret == E_EOF) {
            err = 0;
            break;
        }
    }
    Py_DECREF(filename);
    return err;
}

PyRun_InteractiveOneObjectと、シェルに入力した式が実行される雰囲気が漂います。長いのでざっくり必要な部分だけ残すと以下のような感じ。

Everything is expanded.Everything is shortened.
  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
 
 
-
|
|
|
|
|
|
|
|
|
-
|
|
-
|
|
|
!
!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
!
int
PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags)
{
    PyObject *m, *d, *v, *w, *oenc = NULL, *mod_name;
    mod_ty mod;
    PyArena *arena;
    char *ps1 = "", *ps2 = "", *enc = NULL;
    int errcode = 0;
    _Py_IDENTIFIER(encoding);
    _Py_IDENTIFIER(__main__);
 
    mod_name = _PyUnicode_FromId(&PyId___main__); /* borrowed */
    if (fp == stdin) {
        /* Fetch encoding from sys.stdin if possible. */
        v = _PySys_GetObjectId(&PyId_stdin);
        if (v && v != Py_None) {
            oenc = _PyObject_GetAttrId(v, &PyId_encoding);
            if (oenc)
                enc = _PyUnicode_AsString(oenc);
        }
    }
    arena = PyArena_New();
    mod = PyParser_ASTFromFileObject(fp, filename, enc,
                                     Py_single_input, ps1, ps2,
                                     flags, &errcode, arena);
    Py_XDECREF(v);
    Py_XDECREF(w);
    Py_XDECREF(oenc);
    m = PyImport_AddModuleObject(mod_name);
    d = PyModule_GetDict(m);
    v = run_mod(mod, filename, d, d, flags, arena);
    PyArena_Free(arena);
    Py_DECREF(v);
    flush_io();
    return 0;
}

入力からASTを作り、実行しています。PyParser_ASTFromFileObjectはpythonrun.cの下の方にあります。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 
 
 
 
-
|
|
|
|
|
|
|
-
|
|
|
!
|
|
!
mod_ty
PyParser_ASTFromFileObject(FILE *fp, PyObject *filename, const char* enc,
                           int start, char *ps1,
                           char *ps2, PyCompilerFlags *flags, int *errcode,
                           PyArena *arena)
{
    mod_ty mod;
    perrdetail err;
    int iflags = PARSER_FLAGS(flags);
 
    node *n = PyParser_ParseFileObject(fp, filename, enc,
                                       &_PyParser_Grammar,
                                       start, ps1, ps2, &err, &iflags);
    if (n) {
        flags->cf_flags |= iflags & PyCF_MASK;
        mod = PyAST_FromNodeObject(n, flags, filename, arena);
        PyNode_Free(n);
    }
    err_free(&err);
    return mod;
}

run_mod。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 
 
 
-
|
|
|
|
|
|
!
static PyObject *
run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
            PyCompilerFlags *flags, PyArena *arena)
{
    PyCodeObject *co;
    PyObject *v;
    co = PyAST_CompileObject(mod, filename, flags, -1, arena);
    v = PyEval_EvalCode((PyObject*)co, globals, locals);
    Py_DECREF(co);
    return v;
}

というわけで、教科書のように以下の順番で処理が行われているようです。

  1. スクリプトからノードへの変換:PyParser_ParseFileObject (Parser/parsetok.c)
  2. ノードからASTへの変換:PyAST_FromNodeObject (Python/ast.c)
  3. ASTからバイトコードへの変換:PyAST_CompileObject (Python/compile.c)
  4. バイトコードの実行:PyEval_EvalCode (Python/ceval.c)

スクリプト解析は長くなるので別ページで書きます。

ここまでの感想、ってほどでもないですが、慣れてないせいかRubyに比べてどこに関数が書かれているかわかりにくくgrepで探して進んでいます。タグジャンプ使えばいい気がしてきたw


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-09-22 (木) 18:21:57 (2770d)