📖

謎のプログラミング言語「DNCL」を書いてみたい

2024/12/16に公開

はじめに

この記事はteam411のアドベントカレンダー15日目の記事です。

昨日はみみさんの人類APを受けようでした。自分はFPですらやるやる詐欺師しているのまずいです。まだ出ていませんが出ました

今回の記事は謎のプログラミング言語DNCLのお話です。

本編

DNCLってなんぞや

DNCLとは今年の共通テストから実施される科目「情報Ⅰ」のプログラム分野で使用される言語の事です。Daigaku Nyushi Center Languageの略だと言われています。頭悪すぎ。 そんなわけないと調べましたよ? でも大学入試センターのURLがhttps://www.dnc.ac.jp/ なんです。ツモです。

やりたいこと

DNCLのよくないところの一つとして、日本語すぎる点があります。これにより入試のためにDNCLを一生懸命勉強してきた理系たちは言語を学び直す必要があります。かわいそう!なので、今回はC++をベースとして#defineを乱用してDNCLっぽいものがが書けるようにしようと思います。え?もうすでに処理系があるって?うるせえやりたいからやるんだよ
DNCLはこれで定義されています。(実はこれは現行の共通テストの情報関係基礎用であり新しくできる情報Ⅰで用いられるものと違ったりします。)これの通りに定義したりしなかったりします。仕様上できなかったりするからね。仕方ないね。
この記事を通してDNCLの良さを感じてください。ネガキャンではないです

定義するもの

今回はhppファイルに定義してそれをインクルードすることで日本語で書けるようにしたいと思います。
DNCLは大まかに以下のように定義されています。

  • 変数と値
  • 表示文
  • 代入文
  • 演算
    • 算術演算
    • 比較演算
    • 論理演算
  • 制御文
    • 条件分岐文
    • 条件繰返し文
    • 順次繰返し文
  • 用意された関数の呼び出し
  • 新しい関数の定義

これに則って定義していきたいと思います。また、競プロの名残でstdは省略しています。

変数と値

DNCLでは変数名を英字で始まる英数字と「_」で宣言します。英単語じゃないです。合計の事はGokei、得点の事はTokutenと宣言します。SumやPoint、Scoreなどの英語が分からない高校生もいるのでいい配慮ですね!!!
数字や配列は通常と同じでGyoretu[2]と表します。良心的!
また、文字列は"hogehoge"のように「"」で囲みます。
変数を宣言するのもここでやります。

// 変数
#define 整数 int
#define 実数 double
#define 文字 char
#define 文字列 string
#define 配列 vector<int>

整数、実数(浮動小数)、文字、文字列、配列が使えるようになりました。(え?float? vector<string>?知らない子ですね)

表示文

C言語やC++であるprintf()のやつですね。DNCLでは表示したい要素の後ろに「を表示する」と書くことで表示できます。複数の要素を表示したいときは要素を「と」で区切ることで表示できます。

「整いました」を表示する
kosuと「個見つかった」を表示する

これをC++で再現したいと思います。C++では表示にcout << hoge << endlを用いています。これをDNCLっぽくすると以下のようになります。

// 表示文
#define する cout <<
#define <<
#define を表示 << endl;

ではHello Worldをしてみましょう。

test.cpp
#include <bits/stdc++.h>
#include <dncl.hpp>
using namespace std;

整数 main() {
  する "Hello World!" を表示
}

結果は...

うまく表示できました!!

代入文

DNCLでは代入を矢印で表しています。
c++ではが使えないので<-を用いて代入ができるようにします。

// 代入文
#define <- =

ではテストしましょう。

test.cpp
整数 main() {
  文字列 x;
  x <- "Hello World!";
  する x を表示
}

では実行しましょう。

うまくできてますね!(画像使いまわしてないです)

演算

ここでは算術演算、比較演算、論理演算の三つを再現しようと思います。
算術演算
DNCLでは加減乗除の計算を「+」「ー」「✕」「÷」で表現されています。
これをC++で表現しようとしましたがなんかエラーで出来ませんでした。これ何でかわかる人いたら教えてほしいです。(演算子は#defineが使えないのかも?)

比較演算
DNCLでは比較の演算に「=」「≠」「>」「≧」「<」「≦」を採用しています。
これをC++で表現しようとしたら「≠」「≧」「≦」の表現ができませんでした。なんでだろう

論理演算
論理演算は「かつ」「または」「でない」で定義されています。これはできそう!

これらの演算をC++出保湧現すると以下のようになります。

// 演算
// 比較演算
#define ==
#define >
#define <
// 論理演算
#define かつ &&
#define または ||
#define でない !

これらをテストしましょう。

test.cpp
int main() {
  配列 Data = {-1,2,0};
  for(整数 i = 0; i < 3; i++){
    if(Data[i]0){
      する "Data[" と i と "]は負の数です" を表示
    } else if(Data[i]0){
      する "Data[" と i と "]は正の数です" を表示
    } else {
      する "Data[" と i と "]は0です" を表示
    }
  }
}

実行すると...

うまく動いてくれました!だんだん日本語が多くなってきましたね

制御文

ここでは条件分岐(if)、条件繰り返し文(for)、順次繰返し文(while)を使えるようにします。
条件分岐
よくあるif文です。DNCLでは<条件>によって<処理>を実行するかが決まります。

DNCL
もし <条件> ならば
    <処理>
を実行する

これでは<条件>が偽のときにはなにも実行しません。偽のときだけ事項する処理がある場合以下のように書きます。

DNCL
もし <条件> ならば
    <処理1>
を実行し、そうでなければ
    <処理2>
を実行する

条件が二つ以上の場合もありますね。else ifを使うには以下のようになります。

DNCL
もし <条件1> ならば
    <処理1>
を実行し、そうでなくもし <条件2> ならば
    <処理2>
を実行し、そうでなければ
    <処理3>
を実行する

これを再現できるようにしたいと思います。

// 制御文
// 条件分岐
#define もし if(
#define ならば ){
#define を実行し,そうでなければ }else{
#define を実行し,そうでなくもし }else if(
#define を実行する }

ではさっきの例を書き直してみましょう。

test.cpp
int main() {
  配列 Data = {-1,2,0};
  for(整数 i = 0; i < 3; i++){
    もし Data[i]0 ならば
      する "Data[" と i と "]は負の数です" を表示
    を実行し,そうでなくもし Data[i]0 ならば
      する "Data[" と i と "]は正の数です" を表示
    を実行し,そうでなければ
      する "Data[" と i と "]は0です" を表示
    を実行する
  }
}

実行すると...

うまく実行できていますね!(画像使いまわしてないです)

条件繰返し文
DNCLではwhileは次のように扱っています。

前判定
<条件> の間
    <処理>
を繰り返す
後処理
繰返し
    <処理>
を、<条件>になるまで実行する

ではこれを再現しましょう。

// 条件繰り返し分
// 前判定
#define この while(
#define の間 ){
#define を繰り返す }
// 後判定
#define 繰り返し {
#define これを }while(
#define になるまで実行する )

はじめが少し違いますがまあ許容範囲内でしょう(?)。
ではこれを使ってみましょう。コラッツ予想を書いてみようと思います。

test.cpp
int main() {
  整数 x = 20;
  この x != 1 の間
    もし x%20 ならば
      x <- x / 2;
    を実行し,そうでなければ
      x <- 3 * x + 1;
    を実行する
    する x を表示
  を繰り返す
}

これを実行すると...

うまく動いてますね!

順次繰返し文
DNCLではforを次のように扱っています。

DNCL
<変数> を <初期値> から <終了値> まで <差分>ずつ増やしながら、
    <処理>
を繰り返す

ではこれを再現しましょう。

// 順次繰り返し分
#define 変数の for(
#define を初期値 =
#define から ; 
#define までの間 ;
#define を1ずつ増やしながら ++){
#define を1ずつ減らしながら --){
#define を繰り返す }

これを使って条件分岐分の例を書き直してみましょう。

test.cpp
int main() {
  配列 Data = {-1,2,0};
  変数の 整数 i を初期値 0 から i < 3 までの間 i を1ずつ増やしながら
    もし Data[i] < 0 ならば
      する "Data[" と i と "]は負の数です" を表示
    を実行し,そうでなくもし Data[i] > 0 ならば
      する "Data[" と i と "]は正の数です" を表示
    を実行し,そうでなければ
      する "Data[" と i と "]は0です" を表示
    を実行する
  を繰り返す
}

これを実行すると...

うまく動いてます!(写真使いまわしてないです2)

ここまでに再現してきたものでもう9割できたも同然です。

用意された関数の呼び出し

これは現行の共通テストで利用されるDNCL2ではない機能(確認してない)なのでここはパスします。この記事の最後の方にあるgithubにはあります。

新しい関数の定義

DNCLでも新しく自分で関数を定義することができます。

DNCL
関数 <関数名> (<引数列>) を
    <処理>
と定義する

これを再現します。関数といってもvoid型とint型があるので分けます。関数に必要(になりやすい)ものも一緒に定義します。

// 新しい関数の定義
#define を {
#define 整数を返す関数 int
#define 関数 int
#define 表示する関数 void
#define の要素数 size();
#define 返す return

要素数に.が含まれていないのはDataの要素数としたときにDataの要素数で一つの変数として認識してしまうためです。
ではいつもの例を書き直してみましょう。

test.cpp
表示する関数 正負判定(配列 Data)を
  変数の 整数 i を初期値 0 から i < 3 までの間 i を1ずつ増やしながら
    もし Data[i]0 ならば
      する "Data[" と i と "]は負の数です" を表示
    を実行し,そうでなくもし Data[i]0 ならば
      する "Data[" と i と "]は正の数です" を表示
    を実行し,そうでなければ
      する "Data[" と i と "]は0です" を表示
    を実行する
  を繰り返す
と定義する

関数 main()を
  配列 Data = {-1,2,0};
  正負判定(Data);
と定義する

もう全部日本語ですね。ではこれを実行しましょう。

使いまわしじゃないです
うまく実行できていますね!

これでもうDNCLが書けるようになりました!では実践しましょう。

実践

では実践として二分探索のコードを書いてみましょう。また比較として情報Ⅰで扱うJS、Python、VBA、Scratchでも書いてみます。

DNCL
DNCL
#include <bits/stdc++.h>
#include "dncl.hpp"
using namespace std;

関数 main()を
  配列 Data = {3,18,29,33,48,52,63,77,89,97};
  整数 kazu = Data.の要素数
  する "0~99の数字を入力してください" を表示
  整数 atai = 外部からの入力();
  整数 hidari = 0, migi = kazu - 1;
  整数 owari = 0;
  この hidari <= migi かつ owari == 0 の間
    整数 aida = (hidari+migi)/2;
    もし Data[aida] == atai ならば
      する atai と "は" と aida と "番目にありました" を表示
      owari = 1;
    を実行し,そうでなくもし Data[aida] < atai ならば
      hidari = aida + 1;
    を実行し,そうでなければ
      migi = aida - 1;
    を実行する
  を繰り返す
  もし owari == 0 ならば
    する atai と "は見つかりませんでした" を表示
  を実行する
  する "添字"' '"要素" を表示
  変数の 整数 i を初期値 0 から i < kazu までの間 i を1ずつ増やしながら
    する i と "    " と Data[i] を表示
  を繰り返す
を実行する
JavaScript
binsearch.js
data = [3,18,29,33,48,52,62,77,89,97];
kazu = data.length;
atai = Number(prompt("0~99の数字をを入力してください"));
hidari = 0;migi = kazu - 1;
owari = 0;
while(hidari <= migi && owari == 0){
  aida = Math.floor((hidari+migi)/2);
  if(data[aida] == atai){
    document.write(atai + 'は' + aida + '番目にありました','<br>');
    owari = 1;
  } else if(data[aida] < atai){
    hidari = aida + 1;
  } else {
    migi = aida - 1;
  }
}
if(owari == 0){
  document.write(atai + 'は見つかりませんでした','<br>');
}
document.write('添字',' ','要素','<br>');
for(i=0;i<kazu;i++){
  document.write(i,'  ',data[i],'<br>');
}
Python
binsearch.py
data = [3,18,29,33,48,52,62,77,89,97]
kazu = len(data)
atai = int(input("0~99の数字を入力してください\n"))
hidari = 0; migi = kazu - 1
owari = 0
while hidari <= migi and owari == 0:
  aida = (hidari + migi) // 2
  if data[aida] == atai:
    print(atai, "は", aida, "番目にありました")
    owari = 1
  elif data[aida] < atai:
    hidari = aida + 1
  else:
    migi = aida - 1
if owari == 0:
  print(atai, "は見つかりませんでした")
print('添字',' ','要素')
for i in range(kazu):
  print(i,'    ',data[i])
VBA
binsearch.xlsm
Sub binsearch()
    Data = Array(3, 18, 29, 33, 48, 52, 62, 77, 89, 97)
    kazu = UBound(Data)
    atai = Val(InputBox("0~99の数字を入力してください"))
    hidari = 0: migi = kazu
    owari = 0
    Do While hidari <= migi And owari = 0
        aida = (hidari + migi) \ 2
        If Data(aida) = atai Then
            msg = atai & "は" & aida & "番目にありました" & vbCrLf
            owari = 1
        End If
        If Data(aida) < atai Then
            hidari = aida + 1
        Else
            migi = aida - 1
        End If
    Loop
    If owari = 0 Then
        msg = atai & "は見つかりませんでした" & vbCrLf
    End If
    msg = msg & "添字" & " " & "要素" & vbCrLf
    For i = 0 To kazu
        msg = msg & i & "      " & Data(i) & vbCrLf
    Next i
    MsgBox msg
End Sub
Scratch


binsearch.sb3

では実行してみましょう。(JSの実行だけなぜかできなかったのでないですゴメンナサイ)

DNCLの実行

Pythonの実行

VBAの実行1

VBAの実行2

Scratchの実行1

Scratchの実行2

全部見つけられていますね!Scratchだけ配列が1番目から始まっているので9番目と答えていますが...

最後に

今回は謎のプログラミング言語「DNCL」とやらを書けるようにしてきました。結果としてまだ日本語じゃない部分(;とか)や完璧に再現できていない部分があったのでちょっと悔しいです。まあ日本語でコードが書けるのはなかなか面白いです。めんどくさいですが。
今回のコード達はgithubにあげているのでいつでもどこでもDNCLを書くことができます。やったね! もしDNCLで大作を作ったら見せてほしいです。そんな野蛮な人いないと思いますが。
https://github.com/kazutatsu/DNCL

明日はあくあさんの「MO フロント編 #1」です。調布祭で一世を風靡したMOのフロントのお話です。#2はあるのでしょうか。ぜひ読んでみてください!

Discussion