HQ9+のなでしこによる実装

# はじめに
この記事で取り扱う、[日本語プログラミング言語「なでしこ」](https://nadesi.com/)は、日本語話者で、かつプログラミング初心者にとって、[かなり分かりやすく作られている](https://youtu.be/Hpv8DMry9Zg)言語であると言える。
一方で、世の中には、その逆を行く、難解な言語も存在している。

https://ja.wikipedia.org/wiki/%E9%9B%A3%E8%A7%A3%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

そこで、今回は、上記Wikipediaのページに書かれているプログラミング言語の中から、「HQ9+」を実行できるインタプリタを、「なでしこ」で実装してみる。

# HQ9+の仕様
Wikipediaによると、「HQ9+」は以下の4つの命令から構成されている。

> Hコマンドは文字列"Hello, world!"を出力する。
> Qコマンドはプログラムのソースコードを出力する（参考:クワイン (プログラミング)）。
> 9コマンドは『99 Bottles of Beer（英語版）』（アメリカの数え歌で、プログラミングの例題でよく利用される）の歌詞を出力する。
> +コマンドはアキュムレータをインクリメント（1だけ増やす）する。

ということで、インタプリタを実装するのも、命令を4つ実装すれば良いので、簡単そうである。

# 実際のソースコード

「HQ9+」のソースコードは、実行時に尋ねることとし、空文字で区切り、配列化した。インタプリタのソースコードを以下に示す。

```text:なでしこのプログラム
「HQ9+のソースコードを入力...」と尋ねる。
それを「」で区切って《ソースコード》に代入。
《accumulator》に0を代入。
《ソースコード》を反復
　　それで条件分岐
　　　　「H」ならば、「Hello, world!」と表示。ここまで。
　　　　「Q」ならば、《ソースコード》を「」で配列結合して表示。ここまで。
　　　　「9」ならば、Ninety_nine_Bottles_of_Beer歌唱処理。ここまで。
　　　　「+」ならば、《accumulator》に1を足して《accumulator》に代入。ここまで。
　　ここまで。
ここまで。

関数　Ninety_nine_Bottles_of_Beer歌唱処理とは
　　《瓶数》を99から3まで繰り返す
　　　　「｛《瓶数》｝bottles of beer on the wall, ｛《瓶数》｝ bottles of beer.」と表示。
　　　　「Take one down and pass it around, now there's ｛《瓶数》-1｝ more bottles of beer on the wall!」と表示。
　　ここまで。

　　「2 bottles of beer on the wall, 2 bottles of beer.」と表示。
　　「Take one down and pass it around, now there's 1 more bottle of beer on the wall!」と表示
　　「1 bottle of beer on the wall, 1 bottle of beer.」と表示。
　　「Take one down and pass it around, no more bottles of beer on the wall.」と表示
　　「No more bottles of beer on the wall, no more bottles of beer.」と表示
　　「Go to the store and buy some more, 99 bottles of beer on the wall.」と表示
ここまで。
```

メインのプログラムとしては、配列変数`《ソースコード》`を反復し、1つ1つの命令について、条件分岐しているだけである。

https://nadesi.com/v3/doc/index.php?%E6%96%87%E6%B3%95%2F%E5%8F%8D%E5%BE%A9

https://nadesi.com/v3/doc/index.php?%E6%96%87%E6%B3%95%2F%E6%9D%A1%E4%BB%B6%E5%88%86%E5%B2%90

# 大文字小文字を無視する
次のページは、「HQ9+」の製作者、クリフ・ビッフルのサイトである。

https://cliffle.com/esoterica/hq9plus/

ここでは「HQ9+」のコードの例示として`qqqq`というソースコードが掲載されていた。つまり、「HQ9+」の言語仕様として、大文字と小文字は区別しないものと考えられる。「なでしこ」の[ブラウザ版の命令一覧](https://nadesi.com/v3/doc/index.php?wnako)を眺めていたところ、大文字変換という命令があった為、これを用いて実装する。

https://nadesi.com/v3/doc/index.php?plugin_system%2F%E5%A4%A7%E6%96%87%E5%AD%97%E5%A4%89%E6%8F%9B

ついでに、全角で「HQ9+」のソースコードを入力しても正しく動作するように調整する。と言っても、[英数記号半角変換](https://nadesi.com/v3/doc/index.php?plugin_system%2F%E8%8B%B1%E6%95%B0%E8%A8%98%E5%8F%B7%E5%8D%8A%E8%A7%92%E5%A4%89%E6%8F%9B)という命令を挿入するだけである。

```text:なでしこのプログラム（一部）
《ソースコード》を反復
　　それを大文字変換して英数記号半角変換する。
　　それで条件分岐
　　　　「H」ならば、「Hello, world!」と表示。ここまで。
　　　　「Q」ならば、《ソースコード》を「」で配列結合して表示。ここまで。
　　　　「9」ならば、Ninety_nine_Bottles_of_Beer歌唱処理。ここまで。
　　　　「+」ならば、《accumulator》に1を足して《accumulator》に代入。ここまで。
　　ここまで。
ここまで。
```

# HQ9+以外の文字がある場合
[このオンラインインタプリタ](https://almnet.de/esolang/hq9plus.php)では、「H」「Q」「9」「+」という文字以外があった場合に、エラーを発生される仕様になっている。そこで「なでしこ」のエラー発生という命令を用いて、実行時にエラーを発生させることとする。

https://nadesi.com/v3/doc/index.php?plugin_system%2F%E3%82%A8%E3%83%A9%E3%83%BC%E7%99%BA%E7%94%9F

なお、条件分岐内でのキーワード「それ」は、大文字変換して、英数記号半角変換した後の文字が代入されているため、元の文字を表示するために、`《ソースコード》＠対象キー`のように、配列変数`《ソースコード》`から引っ張ってきている。

```text:なでしこのプログラム（一部）
《ソースコード》を反復
　　それを大文字変換して英数記号半角変換する
　　それで条件分岐
　　　　「H」ならば、「Hello, world!」と表示。ここまで。
　　　　「Q」ならば、《ソースコード》を「」で配列結合して表示。ここまで。
　　　　「9」ならば、Ninety_nine_Bottles_of_Beer歌唱処理。ここまで。
　　　　「+」ならば、《accumulator》に1を足して《accumulator》に代入。ここまで。
　　　　違えば、「解釈できない文字（｛《ソースコード》＠対象キー｝）を見つけました。」でエラー発生。ここまで。
　　ここまで。
ここまで。
```

# おわりに
割と簡単にでき、なおかつ繰り返しと条件分岐が含まれていたので、初心者向けの練習問題として良いかもしれない。ただし、「なでしこ」の他に「HQ9+」という別のプログラミング言語の仕様についても知る必要があるので、混乱の原因となる危険性もある点には注意する必要があろう。

　

以上。

# 参考文献

https://ja.wikipedia.org/wiki/HQ9%2B

https://almnet.de/esolang/hq9plus.php

　

# 追記（2024/12/08）
> 個人的にはビールの歌、０まで全部繰り返しの中でなんとかならないかな～。しかも、かっこよさげに？

@snowdrops89 さんにこんなことを言われましたので、少し考えてみました。

```text:かっこいい？なでしこのコード（一部）
関数　Ninety_nine_Bottles_of_Beer歌唱処理とは
　　《複数形》に「s」を代入。
　　《複数セレクト》に["s",空,"!","."]を代入。
　　《瓶数》を99から1まで繰り返す
　　　　《壁掛け》に「｛《瓶数》｝ bottle{《複数形》} of beer」を代入。
　　　　「{《壁掛け》} on the wall, {《壁掛け》}.」と表示。
　　　　《複数セレクト》@((《瓶数》==2)-0)を《複数形》に代入。
　　　　《残り》に["now there's ｛《瓶数》-1｝","no"]を代入。
　　　　「Take one down and pass it around, {《残り》@((《瓶数》==1)-0)} more bottle{《複数形》} of beer on the wall{《複数セレクト》@((《瓶数》==1)--2)}」と表示。
　　ここまで。
　　「No more bottles of beer on the wall, no more bottles of beer.」と表示
　　「Go to the store and buy some more, 99 bottles of beer on the wall.」と表示
ここまで
```
短くなって、99から1までひとつのループに入ったけれど、何をやっているか、分かりにくくなってしまいました。分かりやすく作られている「なでしこ」で書いているのに、これでは、本末転倒ですね。

ところで、このコードを考えているときに気がついたんですが、以下がエラーになる（v3.6.37で検証済）のって、バグでしょうか？
```text
["a","b","c","d"]@2を表示
```
詳しい方がいたら、教えて下さい。