共通テスト「情報」試作問題のプログラミング言語を作ってみた

大学入試共通テスト「情報」試作問題で使われている独自の日本語プログラミング疑似言語を実際に実行できる環境を作りました。

[DNCL2 - 大学入試共通テスト「情報」試作問題言語](https://nodai2hitc.github.io/ictl/)

# はじめに

2022年度より高等学校でプログラミングを扱う「情報Ⅰ」の授業が必須となります。そして今後大学入試共通テスト（旧センター試験）において、「情報」を出題教科の１つにすることが検討されています。

ところで「情報Ⅰ」ではプログラミングを扱うこと自体は決まっているのですが、**どのプログラミング言語を使うかは現場に任されています。** ですので仮に共通テスト「情報」の試験問題で Python が使われたとしたら、Python を使っていた高校の生徒が有利になってしまいます。

そのため昨年末に公開された[「情報」試作問題](http://www.ipsj.or.jp/education/9faeag0000012a50-att/sanko2.pdf)では、独自の擬似言語を使っています。試作問題の解説中でも以下のように書かれています。

> ※高等学校の授業で多様なプログラミング言語が利用される可能性があることから，問題中で使用するプログラミング言語は，公平性を鑑みて，大学入試センター独自の日本語表記の疑似言語としている。

その「独自の日本語表記の擬似言語」とは、以下のようなものです。（試作問題から引用）

```
(01)Angoubun = ["p","y","e","b",…（省略）…"k","b","d","r","."]
(02)配列 Hindo のすべての要素に 0 を代入する
(03)i を 0 から 要素数(Angoubun)-1 まで 1 ずつ増やしながら:
(04)｜ bangou = 差分( Angoubun[i] )
(05)｜ もし bangou != -1 ならば:
(06)⎿ ⎿ Hindo[bangou] = Hindo[bangou] + 1
(07)表示する(Hindo)
```

確かにメジャーなプログラミング言語を学んだ人であれば初見でもなんとなく文法を理解できそうで、学んだ言語による有利不利はあまり無さそうです。[^lang]

[^lang]: たぶん無いと思いますけど、仮に関数型言語とかを採用する高校があった場合には不利になりそうですね。さらに無いと思いますが BrainF*ck とかを（以下略

さて、擬似言語と言われつつも、プログラムを見れば実行してみたくなるのが人情というもの。というわけで実行環境を作ってみました。

# 方針

プログラミング言語を１から作成するのは大変です。Ruby の作者である Matz 氏によれば、Ruby は「Hello World」を出力できるようになるのに半年かかったのだとか。[^quora] さすがにそんな労力をかける気にはなりません。

[^quora]: [hello worldまでが長いプログラミング言語は何ですか？に対するYukihiro Matsumotoさんの回答 - Quora](https://jp.quora.com/hello-world%E3%81%BE%E3%81%A7%E3%81%8C%E9%95%B7%E3%81%84%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E%E3%81%AF%E4%BD%95%E3%81%A7%E3%81%99%E3%81%8B-1/answers/234834042)

幸い、この擬似言語は基本的な部分は Ruby や JavaScript とそれほど違いはありません。そこで、この擬似言語をまず JavaScript に変換する一種のトランスコンパイラを作成し、その変換された JavaScript を eval で実行するという方向で進めていきます。

とりあえず、試作問題内の２つのプログラムが実行できることと FizzBuzz が書けることを目標にして、最低限の実装をしていきたいと思います。

まずはプログラミングには名前が重要。この言語を **ICTL** と名付けることにします。Information Common Test Language の略です。英語として怪しいですが気にしないことにします。

【追記】…と思ったらすでに「DNCL2」という通称名があるようです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おっ，いわゆるDNCL2（DNCLのPython類似版）の実装！ <a href="https://t.co/BwJ03SZnO1">https://t.co/BwJ03SZnO1</a></p>&mdash; Haruhiko Okumura (@h_okumura) <a href="https://twitter.com/h_okumura/status/1422055031532974085?ref_src=twsrc%5Etfw">August 2, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

# 変換手法

この言語の明確な仕様が無いので分からない点が多々ありますが、できるだけ実装が簡単になるように解釈していきたいと思います。

まず行頭の `(01)` はプログラムの一部なのか、それとも単に行番号を表示しているだけでプログラムの一部では無いのか…とりあえずこの部分は変換して消去してしまいます。

```
Angoubun = ["p","y","e","b",…（省略）…"k","b","d","r","."]
配列 Hindo のすべての要素に 0 を代入する
i を 0 から 要素数(Angoubun)-1 まで 1 ずつ増やしながら:
｜ bangou = 差分( Angoubun[i] )
｜ もし bangou != -1 ならば:
⎿ ⎿ Hindo[bangou] = Hindo[bangou] + 1
表示する(Hindo)
```

`｜` は Python のインデントのように必須のものなのかもしれませんが、実装上 `⎿` さえあれば済みそうなのでこれも消去します。

```
Angoubun = ["p","y","e","b",…（省略）…"k","b","d","r","."]
配列 Hindo のすべての要素に 0 を代入する
i を 0 から 要素数(Angoubun)-1 まで 1 ずつ増やしながら:
  bangou = 差分( Angoubun[i] )
  もし bangou != -1 ならば:
⎿ ⎿ Hindo[bangou] = Hindo[bangou] + 1
表示する(Hindo)
```

行頭の `⎿` は、行末の `}` に変換します。

```
Angoubun = ["p","y","e","b",…（省略）…"k","b","d","r","."]
配列 Hindo のすべての要素に 0 を代入する
i を 0 から 要素数(Angoubun)-1 まで 1 ずつ増やしながら:
  bangou = 差分( Angoubun[i] )
  もし bangou != -1 ならば:
    Hindo[bangou] = Hindo[bangou] + 1 } }
表示する(Hindo)
```

`i を 0 から 要素数(Angoubun)-1 まで 1 ずつ増やしながら:` とか `もし bangou != -1 ならば:` は、`for` や `if` に機械的に変換できそうです。

```
Angoubun = ["p","y","e","b",…（省略）…"k","b","d","r","."]
配列 Hindo のすべての要素に 0 を代入する
for (i = 0; i <= 要素数(Angoubun)-1; i += 1) {
  bangou = 差分( Angoubun[i] )
  if (bangou != -1) {
    Hindo[bangou] = Hindo[bangou] + 1 } }
表示する(Hindo)
```

少し首を傾げたくなるのが、`配列 Hindo のすべての要素に 0 を代入する` という命令。「長さ 10 の配列のすべての要素に 0 を代入する」とかなら分かるんですが、長さ不定の配列のすべての要素に 0 を代入するとはどういうことなのか…とりあえず配列に「デフォルトの値」を持たせておき、`undefined` な要素にアクセスした際にはデフォルトの値に置き換えるようにします。

```javascript
Angoubun = ["p","y","e","b",…（省略）…"k","b","d","r","."]
Hindo = []; Hindo.default = 0
for (i = 0; i <= 要素数(Angoubun)-1; i += 1) {
  bangou = 差分( (Angoubun[i] == undefined ? Angoubun.default : Angoubun[i]) )
  if (bangou != -1) {
    Hindo[bangou] = (Hindo[bangou] == undefined ? Hindo.default : Hindo[bangou]) + 1 } }
表示する(Hindo)
```

JavaScript は日本語の関数名も許容してくれるので、`要素数()` とか `差分()` とか `表示する()` はそのまま JavaScript 上で実装してしまいます。

以上の変換を `replace` と正規表現を使ってゴリゴリ書いていくことで、実際に実行できる JavaScript に変換することができました！

# FizzBuzz を書く

では、この言語で FizzBuzz を書いてみましょう。`else if` が使えないのでネストが深くなってしまいますが、こんな風に書けばいいはずです。

```
(01)i を 1 から 100 まで 1 ずつ増やしながら:
(02)｜ もし i % 15 == 0 ならば:
(03)｜ ｜ 表示する("FizzBuzz")
(04)｜ そうでなければ:
(05)｜ ｜ もし i % 3 == 0 ならば:
(06)｜ ｜ ｜ 表示する("Fizz")
(07)｜ ｜ そうでなければ:
(08)｜ ｜ ｜ もし i % 5 == 0 ならば:
(09)｜ ｜ ｜ ｜ 表示する("Buzz")
(10)｜ ｜ ｜ そうでなければ:
(11)⎿ ⎿ ⎿ ⎿ 表示する(i)
```

これを JavaScript に変換したものがこちら。

```javascript
for (i = 1; i <= 100; i += 1) {
  if (i % 15 == 0) {
    表示する("FizzBuzz")
  } else {
    if (i % 3 == 0) {
      表示する("Fizz")
    } else {
      if (i % 5 == 0) {
        表示する("Buzz")
      } else {
        表示する(i) } } } }
```

FizzBuzz も正しく実行することができました。これならそれなりにいろいろな計算等ができそうです。

# 高校関係者の方々へお願い

この実行環境は自由に使って構いません。たとえば実際に「情報」が共通テストに加わりこの言語でのプログラミング問題が出題されるようになったとしたら、共通テストに向けた演習に使うことができるでしょう。

ですが、「最初からテストと同じ言語で授業もやったほうがいいに違いない！」と考えてこの言語を「情報Ⅰ」の授業でメインに扱う言語には**絶対にしないでほしい**と思っています。Ruby や Python、JavaScript といった一般的なプログラミング言語を使ってください。

あなたの生徒の中には、授業をきっかけにプログラミングに興味を持つ人もいるでしょう。一般的な言語であれば、そうした生徒は自ら調べてゲームだとか GUI アプリだとかを作ったりと、授業でやったことの先へと進み出すことでしょう。

ですが、この言語には「先」がほとんどありません。せっかく興味を持った生徒に、その先の楽しさを伝えることができないのです。

せっかく始まるプログラミングの授業、一人でも多くの高校生が、プログラミングの楽しさを感じてくれることを願っています。