以下の本を読んでいた時のこと…。
もし 価格>100: 表示(価格)
???まじ???そういう感じ???知ってるPythonの話でいいんだよね???
といった記述が出てきました。
というわけで実際にやってみます。
概要
標準のPythonインタプリタはC言語で書かれており、これを改造してソースコードからビルドすることで実現可能。
今回はWindowsを使用し、VisualStudioのビルドツールを使用して検証しています。
Pythonのソースコードをダウンロード
Pythonの公式サイトからダウンロードする。
今回は本に倣って「Python-3.11.3.tgz」をダウンロードしました。
以下のコマンドで解凍:
$ tar -xf Python-3.11.3.tgz
ソースコードの改造
Python-3.11.3\Parser\tokenizer.cを改造する:
tok_get
関数のreturn NAME;
の上に以下を追加する。
if (memcap(tok->start, "もし", 6) == 0){
return MOSHI;
}
if (memcap(tok->start, "ならば", 9) == 0){
return NARABA;
}
if (memcap(tok->start, "ではなくて", 15) == 0){
return DEHANAKUTE;
}
if (memcap(tok->start, "でなければ", 15) == 0){
return DENAKEREBA;
}
return NAME; // ここは元からある行
Python-3.11.3\Grammar\Tokensの先頭に以下を追加する:
MOSHI
NARABA
DEHANAKUTE
DENAKEREBA
ENDMARKER // 元からある行
…
python.gramを編集(2か所)
1か所目:
(変更前)
if_stmt[stmt_ty]:
| invalid_if_stmt
| 'if' a=named_expression ':' b=block c=elif_stmt {
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
| 'if' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
elif_stmt[stmt_ty]:
| invalid_elif_stmt
| 'elif' a=named_expression ':' b=block c=elif_stmt {
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
| 'elif' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
else_block[asdl_stmt_seq*]:
| invalid_else_stmt
| 'else' &&':' b=block { b }
(変更後)
if_stmt[stmt_ty]:
| invalid_if_stmt
| ('if' | MOSHI) a=named_expression (':' | NARABA) b=block c=elif_stmt {
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
| ('if' | MOSHI) a=named_expression (':' | NARABA) b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
elif_stmt[stmt_ty]:
| invalid_elif_stmt
| ('elif' | DEHANAKUTE) a=named_expression (':' | NARABA) b=block c=elif_stmt {
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
| ('elif' | DEHANAKUTE) a=named_expression (':' | NARABA) b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
else_block[asdl_stmt_seq*]:
| invalid_else_stmt
| (('else' &&':') | DENAKEREBA) b=block { b }
2か所目:
(変更前)
compound_stmt[stmt_ty]:
| &('def' | '@' | ASYNC) function_def
| &'if' if_stmt
(変更後)
compound_stmt[stmt_ty]:
| &('def' | '@' | ASYNC) function_def
| &('if' | MOSHI) if_stmt
CPythonの再ビルド
$ cd Python-3.11.3\PCbuild
$ build --regen
# ビルドに成功しました。
$ build
# ビルドに成功しました。
うまくいっていればPCbuild/amd64/python
に生成されます。
動作
以下をtest.pyとしてPCbuild内に保存し、
amd64\python test.py
で実行しました。
表示, 入力, 整数 = print, input, int
温度 = 整数(入力("温度:")) # 仮に温度=11とする
もし 温度 > 25 ならば
表示("冷房")
ではなくて 温度 < 20 ならば
表示("暖房")
でなければ
表示("停止")
# 暖房
if 温度 > 25:
print("冷房")
elif 温度 < 20:
print("暖房")
else:
print("停止")
# 暖房、ifもそのまま使える
ちゃんと使えました。ヤバすぎ!!!
本を読むとなぜこれで良いのかがわかります。