Python改造してみた

以下の本を読んでいた時のこと…。

https://info.nikkeibp.co.jp/media/NSW/atcl/books/062100066/

```
もし 価格>100: 表示(価格)
```
？？？まじ？？？そういう感じ？？？知ってるPythonの話でいいんだよね？？？
といった記述が出てきました。

というわけで実際にやってみます。

## 概要
標準のPythonインタプリタはC言語で書かれており、これを改造してソースコードからビルドすることで実現可能。

今回はWindowsを使用し、VisualStudioのビルドツールを使用して検証しています。

## Pythonのソースコードをダウンロード
Pythonの公式サイトからダウンロードする。

https://www.python.org/downloads/source/

今回は本に倣って「Python-3.11.3.tgz」をダウンロードしました。
以下のコマンドで解凍：
```sh
$ tar -xf Python-3.11.3.tgz
```

## ソースコードの改造
Python-3.11.3\Parser\tokenizer.cを改造する：
```tok_get```関数の```return NAME;```の上に以下を追加する。
```c
        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か所目：
(変更前)
```gram
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 }
```

(変更後)
```gram
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の再ビルド
```sh
$ cd Python-3.11.3\PCbuild
$ build --regen
# ビルドに成功しました。
$ build
# ビルドに成功しました。
```

うまくいっていれば```PCbuild/amd64/python```に生成されます。

## 動作
以下をtest.pyとしてPCbuild内に保存し、
```amd64\python test.py```
で実行しました。
```python
表示, 入力, 整数 = print, input, int

温度 = 整数(入力("温度:")) # 仮に温度=11とする

もし 温度 > 25 ならば
    表示("冷房")
ではなくて 温度 < 20 ならば
    表示("暖房")
でなければ
    表示("停止")
# 暖房
    
if 温度 > 25:
    print("冷房")
elif 温度 < 20:
    print("暖房")
else:
    print("停止")
# 暖房、ifもそのまま使える
```

ちゃんと使えました。ヤバすぎ！！！

本を読むとなぜこれで良いのかがわかります。