大学入学共通テスト「情報I」のための学習支援システムの開発 -DNCL to Pythonトランスパイラ-

# What 何をしたのか
大学入試で使われる謎言語DNCLをPythonに変換するPythonモジュールを作った。
Google Colaboratory上での動作確認済み。
Pyton3.10以上で動作確認済み。

https://github.com/Sane21/meizen

https://x.com/Sane21_k/status/1747170999282606086?s=20

# Why 作った理由,背景
令和7年度以降、大学入学共通テストでは「情報I」が必修になる。

「情報I」の試験では一つの大問として、謎の日本語まじりのプログラミング言語らしき構文の読み書きが求められる。
これは大学入試センターが定める言語仕様に基づく「共通テスト手順記述標準言語 (DNCL)」と呼ばれるものだ。
言語仕様は一般に公開されており、検索エンジンで「DNCL」と調べたら出てくる大学入試センター作成のPDFで確認できる。

https://www.dnc.ac.jp/albums/abm.php?d=67&f=abm00000819.pdf&n=R4_%E5%85%B1%E9%80%9A%E3%83%86%E3%82%B9%E3%83%88%E6%89%8B%E9%A0%86%E8%A8%98%E8%BF%B0%E6%A8%99%E6%BA%96%E8%A8%80%E8%AA%9E%EF%BC%88DNCL%EF%BC%89%E3%81%AE%E8%AA%AC%E6%98%8E.pdf

この言語には、有志が作成した動作環境が幾つか存在している。以下は一例。
- PyPEN
    Watayan氏の作成したPyPEN
    https://watayan.net/prog/pypen.html
    https://github.com/watayan/PyPEN
- XTetra
    Takumi Daimon氏の作成したXTetra
    https://t-daimon.jp/XTetra/ 

これらは非常に有用で高校生の学習を支援できるように様々な工夫が凝らされている。
しかし、そのシステム内での動作に限定されている点から、教師と生徒とのやり取りがやや不便であったり、応用性に欠けていたりする。

これを解決すべく、Google Colaboratory上で動作するDNCLの処理系を作成した。

# Abstract 開発概要
1. DNCLファイルをPythonファイルにトランスコンパイルする
2. モジュール化してGitHubで公開する
3. Google Colaboratory上で動作するようにする

## Good 嬉しいポイント
- Pythonに変換されるので応用性が高い
- pip installできるので使いやすい
- colaboratoryで使える=classroomで使えるなので、授業で使いやすい

## Bad 悲しいポイント
- DNCL仕様書の最新版が未公開で推測した仕様に基づいてるため、本来の仕様と異なる可能性がある
~~大学入試センターは23年公開の試作問題中のDNCLの仕様を早く公開して欲しい~~

# How to use 使い方
## ローカル環境
###  モジュールをインストールする
```
pip install git+https://github.com/Sane21/meizen.git
```
### DNCLファイルを作成する
sample.dncl の名前で任意のディレクトリにファイルを作成する。中身の一例は下に示す。
```
Kouka = [1,5,10,50,100]
kingaku = 46
maisu = 0
nokori = kingaku
i を 4 から 0 まで1ずつ減らしながら繰り返す:
    maisu = maisu + nokori ÷ Kouka[i]
    nokori = nokori % Kouka[i]
表示する(maisu)
```
### 変換を実行する
引数 path には、上で作成したsample.dnclのあるディレクトリのパス
引数 filename には、sample.dnclの名前
をそれぞれ入れる。注意点としてfilenameに拡張子は書かない。

```py
import meizen

meizen.make(path="./", filename="sample")
```
これを実行すると、pathのディレクトリにfilename.pyが作成される。sample.dnclを対象にした場合は、sample.pyが作成される。既にファイルが存在している場合は、上書きされる。

### 作成されたPythonファイルを実行する
次に示しているのはあくまで一例のため、ディレクトリやファイル名は実際の環境に合わせてほしい。
```
python3 ./sample.py
```

## Google Colaboratory
次のファイルを参考にしてほしい。概ね上のローカル環境と同じ手順を踏んでいる。
マジックコマンド等を活用することで、DNCLの記述から変換、実行までを全てColaboratory内で完結させることができる。

https://github.com/Sane21/meizen/blob/main/meizen_sample.ipynb

# Idea 活用方法の提案
こんな感じでGoogle classroomで課題として共有すると、先生と生徒は常に同じ環境で実行でき、かつ、その進行状況を相互に確認できるため、指導に役立てやすいのではないだろうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/884897/05e5fbf1-e1b5-9e26-a4c4-db54bd5a86e7.png)
実践された方がいれば、感想等を共有いただけると非常に嬉しいです。改良につなげます。


# Specific 実装の詳細
## ファイルの読み取り、書き出し
特記事項はなし。Pythonの基本機能を使うだけ。

https://github.com/Sane21/meizen/blob/main/meizen/dncl/io.py

```py
# 読み込み
def load(path: str) -> list:
    file = open(path, 'r', encoding="utf-8")
    data: list = file.readlines()
    file.close()
    return data


# 書き込み
def write(path: str, code_list: list[str]):
    file = open(path, 'w')
    for code in code_list:
        file.write(code+"\n")
        print(code)
    file.close()
    return
```
## トランスコンパイル
トランスコンパイルは、コードを意味ごとに切り分ける字句解析、字句から意味のあるコードを生成する構文解析の2段階に分かれる。

### 字句解析
コードを意味のある単語ごとに区切っていく処理。
```
msg = "Hello, World!"
```
を
```
["msg", " ", "=", " ", ""Hello, World!""]
```
に切り分ける。その際に、
```
[変数名, 空白, 代入記号, 空白, 文字列]
```
という情報も保持できるようにする。

詳細は書ききれないのでざっくりした処理のフローだけ示す。
1行ごとに、1文字ずつ読み取ってそれを分類していくイメージ。
```py
code_list: list = load(path=path) # DNCLファイルの読み取り

code_symbol = [] # 区切った単語の種類を格納
code_word = [] # 区切った単語の内容を格納

word = "" # 単語を記憶
symbol = Symbol.NULL # 種類を記憶

# code_listから1行ずつ読み取る
for code in code_list:
    # codeから1文字ずつ読み取る
    for character in code:
        if character == 予約語や記号, 値の頭文字:
            symbol = Symbol.対応する種類
            while その記号や予約語が終わるまで:
                word += character
            code_word.append(word)
            code_symbol.append(symbol)
        else:
            while 何らかの予約語や記号, 値の頭文字が次に来るまで:
                word += character
            code_word.append(word)
            code_symbol.append(名前)
```

### 構文解析
単語ごとに区切ったものをPythonの処理に書き改めていく。
```
もし <条件式> ならば:
```
を
```
if <条件式>:
```
に書き直すような処理。

こちらも処理の概要だけ示す。
シンボルを基準に上から順番に見ていき、PythonとDNCLで記法が異なるものは書き改めて、同じ部分はそのままにする感じ。
```py
code_word, code_symbol = 字句解析結果()

code_list = []

while symbol in code_symbol:
    if symbol == DNCLとPythonで記法が異なる場合:
        code = Pythonの記法
        code_list.append(code)
    else:
        code = code_word[]
        code_list.append(code)
```

## モジュールとして公開
こちらの記事を参考にさせていただきました。以上。

https://qiita.com/studio_haneya/items/9aad8f9ede11e58b41a8

## Google Colaboratory上での動作確認
Google ColaboratoryはPython 3.10で機能しているようだったので、その環境で動くように一部修正をした。

次のコマンドでモジュールを導入。
```
!pip install git+https://github.com/Sane21/meizen.git
```

Colab内でのファイルの作成や編集は次のコマンドで可能だった。
```
%%write ファイル名
内容
```
これを利用して、DNCLファイルを作成した。

こちらの記事を参考にさせていただきました。

https://qiita.com/sakaia/items/c8367e75d9c8fd38e7bf


また、作成したpythonファイルを以下のコマンドで実行した。
```
!python3 sample.py
```


# Conclusion 最後に
高校生の役に立つ！というよりは、情報の高校教員の役に立つことで間接的に生徒の役にも立つ。ぐらいの塩梅だと思われる。
良い感じに役に立てば嬉しい。
使いにくい部分やエラー、バグ等あればお伝えいただけると大変、助かります。

日本の情報教育がより良くなることを願って、
お世話になった先生方の力に少しでもなれると良いな。と思います。