【追記あり】使いやすいけど使いづらいプログラミング言語「HSP」について

※姉妹記事：[HSPで本格的にプログラムを書きたい人向けのtips](http://qiita.com/YSRKEN/items/7fd6d95e358cc78377d4)

※当記事は追記が施されました。具体的には、vain0さんの指摘を元に、各所を修正しました。

#概要
　私が初めて[HSP](http://hsp.tv/)(Hot Soup Processor)に触れたのは中学生の頃でした。当時はまだVer.2.Xでしたが、それがVer.3.Xになって浮動小数点も扱えるようになり、様々な関数・命令も追加されたことで格段に使いやすくなりました。その手軽さから初心者向け言語として人気で、[毎年夏休みにはゲームプログラミングの講習会を開く](http://www.onionsoft.net/wp/archives/1576)など、普及にも力を入れている印象があります。ただ、前から思っていたことがあります。それは、

　　**この言語、使いやすいはずなのに使いづらいんだよ！！！**

　一体どういう意味なのか、それについて説明します。

#エディタについて
　HSPの場合、「ＨＳＰスクリプトエディタ」(タイトルバーだと何故か**全角英字**なのが気持ち悪い)を使ってコードを書き、実行します。**厳密には他のエディタを使えないこともない**のですが、あまり調べない人はこのエディタをそのまま使ってプログラムを書くことになるでしょうね。
　ただこのエディタが曲者で、**矩形選択できない・grepできない・ファイルタブを入れ替えられない・関数や処理ブロックなどを折りたたみ表示できない・未だに未実装な部分が多い**という有様です。[真っ当なテキストエディタ](http://techacademy.jp/magazine/986)を一度でも使ったことがある人ならば、**二度とこれでプログラムを書きたくなくなる**のではないでしょうか？
　もっとも、HSPについてのヘルプはhdl.exe(HSP Document Library)という実行ファイルを起動して使えるのですが、このエディタでプログラムを書くと、**調べたいワードにカーソルを合わせてF1キーを押すだけで自動的にhdl.exeが起動して、そのワードの意味が分かります**。なので、覚えてない関数・命令が多すぎる**初心者にとっては手放せない存在**だったりします。……まあ[マクロを組めば他のエディタでも使えます](http://samlen.blog.shinobi.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E5%85%A5%E9%96%80/%E7%A7%80%E4%B8%B8%E3%81%A7hsp%E3%81%AE%E3%83%98%E3%83%AB%E3%83%97%E3%82%92%E4%BD%BF%E3%81%86%E3%83%9E%E3%82%AF%E3%83%AD)が。
　また、HSPで実行する際には○○、このエディタを使えばF5キーを押すだけでそのまま実行できます。[マクロで実行処理を行えるエディタを使っている](http://hide.maruo.co.jp/lib/macro/hspcompile-ver110.html)場合ならともかく、そうでない場合は「他のエディタで書いてから、HSPスクリプトエディタで実行」するか、「他のエディタ上でマクロを定義して実行したい際に使用する」といった手間が掛かることになります。[HSPスクリプトエディタを使わずにコンパイルする方法は無いこともない](http://www.onionsoft.net/hsp/v33/doclib/hspcmp.txt)のですが、**若干面倒臭い**のは否定できませんね……。

#デバッガについて
　えーと、まずはこちらの画面をご覧下さい。
![デバッグ画面](http://i.imgur.com/PMiN9FU.png) 
　assert命令などで処理を止めた/止まっている際に表示されるデバッガですが、標準だと見ての通り**なかなかに見づらい**です。なにせ変数名がズラーッと出てくるので、大規模なプログラムになると変数名の羅列をシークするのが大変です。しかも、「多次元配列だと**1次元分**しか表示されない」「長い変数名だと左側の**リストからはみ出て見づらい**」「ソートとモジュールの両方にチェックを入れるとソートが優先させて**余計にごちゃごちゃする**」など、控えめに言って**手抜き**、極論すれば**作者の悪意を感じる**ダメダメ仕様になってしまっています。作者は**HSPでプログラミングする人にデバッグしてほしくない**のでしょうか？
　ただ、HSPには**一応**、[オープンに公開されているソースコード](http://dev.onionsoft.net/trac/openhsp/)が存在し、そこから[このデバッガのソース](http://dev.onionsoft.net/trac/openhsp/browser/trunk/tools/win32/hsp3debug)を読むことが出来ます。これを改造してコンパイルし直せばオリジナルなデバッガを生み出せるわけです(例：[knowbug](https://github.com/vain0/knowbug/releases))。**DLLを差し替えてくださいとかどう考えても「初心者向け」じゃないけどな！**

#コンパイラについて
* **実行ファイルのサイズがデカい**……HSPはその仕様上、ソースコードを中間コード(\*.axファイル)に変換してランタイム上で実行されます。そしてランタイム部分は生成したexeファイルにくっついてくるので、何も書かない空っぽなコードでも実行ファイルのサイズが**200KBを超えます。**……でもまあ、[ライブラリをstaticに含ませるかdynamicに呼ばせるかで実行ファイルのサイズが相当変わる](http://d.hatena.ne.jp/eel3/20150622/1434981139)ものなので、まだ瑣末な問題ですね。
* **それなのに基本的にWindows上でしか動かない**……一応[Mac版](http://www.onionsoft.net/hsp/hspmac.html)や[Linux版](http://www.binzume.net/software/xhsp/)や[DS版](http://peppermint.jp/products/hsp/openhsp.html)が無いわけではありませんし、[Javaに変換](http://www.geocities.co.jp/Playtown-Yoyo/6130/hsp/hsp-hsplet.html)するとか[VC++に変換](http://www.onionsoft.net/wp/archives/433)するとか[スマホで動くように変換](http://hsp.tv/make/hsp3dish.html)するとか互換性改善のために尽力してくださっているのは認めます。ただ、使える関数・命令の成約が厳しかったり、**WinAPIを直叩きしているようなコード**は移植できなかったりするので、移植する際には**[往年のBASIC](http://www.asahi-net.or.jp/~qb3k-kwsk/rpg/program/basic/basic01.html)以上の方言**に苦労することになります。でもまあ、動かすOSを限定すればまだ重大な問題ではありません。
* **ただでさえ遅い上にロクに最適化しない**……[HSPは中間コードを解釈して動作するインタープリタ言語](http://hsp.tv/make/hsp3.html)ですので、素の速度は遅いです。ライブラリ関数・命令はDLL(＝C++)で動作するのが大半なので速いのですが、複雑なロジックだとスクラッチせざるを得ないことも多いので、この欠点が重くのしかかってきます。また、中間コードに翻訳される過程で**コードとしては殆ど最適化されていない**([参考1](http://hsp.tv/play/pforum.php?mode=pastwch&num=51854)、[参考2](http://hsp.tv/play/pforum.php?mode=pastwch&num=23204))のもポイントです。
* **あまりにも逆コンパイルされやすい**……大きな声では言えませんが、前述の中間コード(\*.axファイル)および実行ファイル(\*.exeファイル)は割と簡単に逆コンパイルできます。[axファイルの仕様は公開されている](https://github.com/zakki/openhsp/blob/master/package/win32/hspsdk/hsp3code.txt)のでそっちが逆コンパイルできるのはまだいいのですが、暗号化しているはずの**実行ファイルの方も簡単に割られる**のはどうかと思います。[有志による難読化ツール](http://www.sharkpp.net/blog/2009/09/30/hsp-yabuinu.html)がありますので、不安な方はそちらを利用しましょう。

#文法について
　話が長くなるのでカテゴリ毎に分けました。逆に言えばそれだけ突っ込みどころが多い言語なわけです。
##(ほぼ)全部の変数がグローバル変数である・変数宣言が(ほぼ)不要・gotoやgosubでラベルにジャンプできる
　この辺は**往年のBASICを彷彿とさせる仕様**です。まあ[BASICライクで手軽な言語を目指したのがHSP](http://www.onionsoft.net/hsp/v33/doclib/hsp3.htm#MESSAGE)なので仕方ないと言えなくもありませんが、前述のように**デバッガにズラッと変数名が並んで見づらい**とかが起きるのもこのせいです。gotoはなるべく使わないようにすれば対処できますが、グローバル変数祭りは後述の**システム変数にも絡んでくるので回避不可能**なのが辛いところです。
##暗黙の型変換と自動拡張のせいでコードが読みづらい
　暗黙の型変換は他言語でも普通にありますが、HSPのそれはなかなかにトリッキーです。例として、[この紹介ページ](http://antibayesian.hateblo.jp/entry/20130119/1358611896)のものを見てみましょう。

```sample1.hsp
mes 1+"1"  ;2
mes "1"+1  ;11
mes 1+"1A" ;2 
mes 1+"A1" ;1
mes 1+"１" ;1
```

　HSPのマニュアルには、暗黙の型変換をする際は「計算する最初の項(左結合なので左側)に合わせて変換される」といったことが書いてあります。C言語などと違い、**8+4.5が12.5ではなく12になる**わけです。ただ、上記のような結果になるのは次のような追加規則が働いています(**マニュアルには未掲載**)。

* 文字列を数値化した場合は「数字から始まる連続部分」のみ評価する。つまり、整数にすると**"12A"は12、"1A2"は1、"A12"は0**になります。
* また、数値化出来る文字列数字は半角のみです。よって、**"１"は0**になります。

　もちろん、int・double・str関数を適切に使用すれば暗黙の型変換をせずに済みますが、暗黙の型変換利用時と比べて冗長になりがちなのでケースバイケースですね。
　また、HSPには変数の**自動拡張機能**があります。具体的には、「a(2) = 5」などと代入文を宣言した場合、**自動**で「a(0)～a(2)」までの配列変数が**確保**されます。また、文字列についても+演算子で足し続ければ**延々とサイズを大きくすることが可能**です(ただし遅い)。楽ちんと言いたいところですが、変数および配列の型が分かりづらくなるのは果たして初心者向けと言えるのでしょうか……？

##特殊な変数(システム変数)が多すぎる
**「システム変数はシステム起動時、または特定の命令を実行した時に自動的に 値が代入される変数です。」(原文ママ)**
　こういった変数が恐ろしいことに**60個近く存在します**。当然グローバル変数な上、(ほぼ)代入できないので同名の変数も作れません。頻繁に利用するのは**cnt・stat・strsize・refstr**辺りですが、これらは**1つ関数・命令を処理するだけでコロコロ変わる**ので、値を後々利用したい際には他の変数にコピーする必要があります。「覚えればいい」だけの話なのですが、「覚えなくていい(意図しない[副作用](https://ja.wikipedia.org/wiki/%E5%89%AF%E4%BD%9C%E7%94%A8_%28%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%29)が少ない)」他言語と比べると隔世の感があります。

##if文内を含む論理演算を短絡評価してくれない
　**マニュアルに載ってない初見殺し**です。HSPのif文内で使う「&」「|」は単なるビット演算なので、式全体を読み取らないと真偽が判断できません(C言語などのように、&&や||と区別されているわけではない)。つまり、次のようなコードはエラーになります。

```sample2_1.hsp
dim a, 3
a(0) = 1 :a(1) = 2: a(2) = 3
flg = 0
if flg & a(4) > 0{  ;エラー！
    mes "a"
}
```
「エラーになるような添字にアクセスするようなif文なんて書かない」と思うかもしれませんが、短絡評価できる言語では「if(A && B)」と書けば**Aが偽ならBの処理はそもそも実行されません**ので負荷軽減に繋がります。なので、**HSPの場合は強制的に短絡評価させるためにネストを深くする必要**があったりするのです(実体験)。


```sample2_2.hsp
dim a, 3
a(0) = 1 :a(1) = 2: a(2) = 3
flg = 0
if flg{
    if a(4) > 0{
        mes "a"
    }
}
```

##関数・命令の引数の扱いがややこしい
　例えば、instrという関数があります。やっていることは文字列の検索です。使用例はこちらをご覧ください。

```sample3.hsp
string = "ABCDE"
mes instr(string,,"A")  ;0
mes instr(string,,"E")  ;4
mes instr(string,,"F")  ;-1
mes instr(string,1,"D") ;2
mes instr("FGH",,"G")   ;エラー「変数名が指定されていません」
```
　**……ん？　なんですかこのエラーは？**
　実は、HSPの関数・命令では、引数における変数と値とは明確に区別されます。そして、**変数指定のところに値を書くとエラー**になります。これだけだと普通のこと(C言語だって引数にポインタを使って変数を強制可能)なのですが、HSPの場合は**妙な部分に変数指定があるから面倒**だったりします。それが顕著なのは文字列操作関数(instr・strmid・strtrimなど)ですが、全関数・命令を触ったことがあるわけではないので他にもややこしい箇所があるかもしれません。

##関数・命令を実装する際の文法がややこしい
　HSPでは、モジュールと呼ばれる機能を使うことで**関数・命令を独自に定義できます**。とは言っても、他の言語のようにガンガン定義して使えるかというとそうでもないのがややこしいところです。この辺は非常にややこしいので、次のコードを読んで下さい。

```sample4.hsp
// モジュールを定義する(testはモジュール名)
#module test
    // xと(グローバル変数の)bを足してそれを表示する(命令)
    #deffunc mes_ab int x
        c = x + b@  ;ちなみに、こことその次の行のcをaにすると
        mes c       ;エラー「パラメータ引数名は使用されています」が出る
    return
    // aを2乗してその値を返す(関数)
    #defcfunc square int a
        b = a * a
    return b
#global

b = 3
mes b          ;3  言うまでもありませんね
mes square(5)  ;25  これも問題ないはずです
mes b          ;3  モジュール内の変数とは区別されます
mes b@test     ;25  「変数名@モジュール名」とすれはアクセス可能
mes_ab 5       ;8  「変数名@」とすればグローバル変数側も参照可能
```
　要するに、**全ての変数および関数が強制的にstaticかつpublicであり、インスタンス作成不可で、しかも引数名とメンバ変数の名前を被らせてはならないクラス**です。ぶっちゃけ、**恐ろしく使いづらい**です。そもそも#deffuncと#defcfuncはモジュールの外でも定義できますので、モジュールはクラスというより**名前空間**と呼ぶのが適切でしょう(公式ヘルプにも[似たような記述](http://www.onionsoft.net/hsp/v33/doclib/module.htm#MODNAME)あり)。
　一応、再帰関数でローカル変数をどうしても使いたい人用に「local」というキーワードがあり、~~それを指定したメンバ変数は関数実行の度に毎回破棄されるので真っ当な再帰コードが書けます……が、**配列はlocal指定できない**ので自前でスタックを積むしかありません。こんな仕様の割を食う処理の一例としてはDFSに代表される**探索処理**があるでしょう。~~

**2017/01/13追記：**
打ち消し線を引いた箇所を、以下の通り訂正します。

- 「local」キーワードは、メンバ変数ではなく仮引数に指定するものです。
- また、「関数実行の度に毎回破棄」ではなく「関数実行の度に確保」が正しいです。
- 更に、配列もlocal指定できます。

**2017/01/16追記：**
　命令・関数を定義する際、「`#deffunc local init`」といった風に`local`キーワードを挟めば、同名の命令・関数を別々のモジュールで定義できるようです。ただしその際は、`init@GUI`や`init@DB`といった風に、必ず`@モジュール名`を付加する必要があるようです。また、変数と違い、たとえ当該モジュール内であっても`@モジュール名`を省略できないとのこと。

##その他
* 変数名の大文字と小文字が区別されない(デバッガでは全部小文字になる)
* 構造体がないので、外部と連携する際に構造体データを投げるのが面倒(例:dim配列に数値を入れて先頭ポインタを渡す)
* 配列が四次元までしか定義できない上、[メモリの並び方がCとかと真逆](http://fujidig.s302.xrea.com/2007/08/array-memory.html)
* repeat～loop内からreturn文で脱出すると、ネストが積まれたままになる
* 手続き型言語なのに、buttonやonclickなどのイベントドリブン要素があってややこしい

　主にこんなところでしょうか。エディタやデバッガやコンパイラが改善されたとしても、文法からしてトリッキーなのがHSPですので、本質的な書きづらさはなかなか解消されないでしょう。

#まとめ
**[「プログラミング言語は、易しいとか難しいとかだろ！　コレ、辛いんだよ！」](http://dic.pixiv.net/a/%E3%83%A0%E3%83%89%E3%82%AA%E3%83%B3%E3%82%AB%E3%83%AC%E3%83%BC)**

　……で済むことですが少し補足を。
　ここまで書いておいてなんですが、**HSPは(ちょっとしたツールを作る際には)書きやすい言語です**。ライブラリは豊富な方なので、「*Webカメラの画像を読み込んで画像認識して顔部分だけを検出してボカした後にウィンドウにリアルタイム表示するソフト*」などと、一見大変そうな処理も結構アッサリと書くことができます。なぜかDLLを直接叩けますので、前述のように**WinAPIをガンガン使ったソフト**や**サードパーティDLLを使用するソフト**なんかも気軽に作成できます。要するに[グルー言語](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AB%E3%83%BC%E8%A8%80%E8%AA%9E)として使う分には都合がいいということです。
　ただ、その枠を離れて**大規模なソフトウェアを組もうとすると途端に辛くなります**。もちろん[設計理念からして大規模なコード向けじゃない](http://www.onionsoft.net/hsp/v33/doclib/hsp3.htm#MESSAGE)のは既に触れましたが、せめてモジュール機能はなんとならなかったのかとは思いますね。きちんとスタック管理できて、配列もlocal指定できて、謎の変数名成約が無ければ**ガンガン関数・命令を作成して殆どの処理をそっちに委ねる**(グローバル空間にはmain関数程度の処理しか書かない)という選択肢もあったのですが。

   →[HSPで本格的にプログラムを書きたい人向けのtips](http://qiita.com/YSRKEN/items/7fd6d95e358cc78377d4)