[表紙へ]
▼ 変更履歴

RPL言語(4 Level RPNが大幅に進化)

前回の記事の続きです。RPN と 4 Level RPN については前回の記事をお読み下さい。

目次

はじめに

ここではヒューレット・パッカード社(HP社)の RPL言語 のことを説明します。
RPL言語には User RPL と System RPL の2種類があるのですが、一般的には User RPLのことを RPL言語と言います。

System RPL はOSとシステム記述用の言語で通常は使いません。私は System RPL の知識がないので、説明もできません。

実験に使った電卓はHP 50gです。ファームウェアのバージョンは下図のように2.15です。

f:id:nekosuki2017:20170224214917j:plain
ただし、ここで説明するのはRPL言語の使い方ではなくて、RPL言語とはどのようなものか?ということです。つまり実用的な説明はありません(やろうと思っても仕様が膨大で不可能だが)。

RPL言語搭載グラフ電卓( HP-28シリーズ HP 48シリーズ HP 49シリーズ HP 50g )の操作はRPL言語をGUIから呼び出しているだけです。
ですからRPL言語を理解することによって、RPL言語搭載グラフ電卓の仕組みが見えてきます。

RPL は Reverse Polish Lisp (逆ポーランドLisp)の略です。
しかし、実際の文法は Lisp言語 と全く似てなくて、 Forth言語 に似た言語です。
RPL言語は1984年に開発されたと言われています。そして、1987年にグラフ電卓HP-28Cとして商品化されました。
RPL言語のおかげで 4 Level RPN では実現できない 変数を含んだ代数式 を扱えるようになったのです。

4 Level RPN との違い

4 Level RPN は数値だけを扱うものです。
一方、RPL言語のRPNは「 先に引数を書いて、関数やコマンドを後ろに書く言語 」という意味になっています。RPL言語で言う引数は数値とは限りません。変数、文字列、リスト、数式、プログラムかもしれません。つまり、4 Level RPNと違って、数値以外のものが扱える拡張された概念になっているのです。

例えば、中置記法(普通の数式の記法)の COS(2*X) をRPL言語プログラムで表現すると、

« 2 X * COS »

となります。RPNと同じ考えです。
RPL言語はプログラムを« »で囲む必要があります。

RPL言語の場合、*もコマンドです。通常のプログラミング言語(C/C++, JAVA, C#など)の場合、*は演算子ですが、RPL言語ではコマンドです。RPL言語はRPNの考え方で記述するので、コマンドの前に引数があります。
ですからプログラム « 2 X * COS » の*の前にある2とXは*コマンドの引数です。*コマンドの結果はCOS関数の引数となります。*コマンドが前にある2つの引数を取るのは前回説明した 4 Level RPN に似ています。しかし、数値ではない変数Xが使えるようになっています。RPL言語は前述のように数値と変数以外のものも使えます。

オブジェクトとスタック

RPL言語ではコマンドと関数が取ることができる引数を オブジェクト と言います。
オブジェクトは数値、変数、文字列、リスト、数式、プログラムなどの総称です。
先程のプログラム « 2 X * COS » の場合、2とXがオブジェクトになります。そして、そのプログラム自身もオブジェクトになります。

ここでRPL言語のスタック(念のために書いておくが、CPUのスタックではない)を見て下さい。下図はRPL言語搭載電卓HP 50gのスタックに色々なオブジェクトが入っている様子です。

f:id:nekosuki2017:20170224220737j:plain

オブジェクトの種類は、6:数値、5:変数、4:文字列、3:リスト、2:代数式、1:プログラムです。

このようにスタックに様々な種類のオブジェクトを入れることができるようになったのです。画像を見ても分かるように4 Level RPNのスタックと違ってX,Y,Z,Tのような名前はなく、下から1: , 2: , 3: ,・・・と番号が振られているだけです。オブジェクトの出し入れは下の1:から行います。

スタックの中を見ると代数式が中置記法で書かれています。実はRPNは代数式を扱うのが苦手なので、代数式はRPNではなくて中置記法で書く必要があるのです。

数値以外のものがスタックに入っているものをRPN(逆ポーランド記法)と言うのは妙な気もしますが、スタックを数値だけでなくオブジェクトを置く場所に拡張したのです。RPL言語が変数の入った代数式を扱うにはどうしてもこのような拡張が必要だったのです。

RPL言語が解釈・実行される手順

RPL言語は インタープリタ言語 です。インタープリタとはコンピュータ言語を少しずつ読みながら逐次実行する方式です。

インタープリタの対語に コンパイラ があります。コンパイラはプログラム全体を一括で機械語(CPUが直接実行できる命令)に変換する方式です。インタープリタよりも高速に動作しますが、部分的な修正をする度に コンパイル という機械語への変換をやり直す必要があります。プログラムが長いとコンパイルは時間がかかります。
一方、インタプリタではコンパイルの必要がありません。そのため、即興的にプログラムを作りたい電卓ではインタープリタ言語を使うことが多いのです。

RPL言語のインタープリタはプログラムを左から右、上から下へ読んでいきます。
« 2 X * COS » の場合、一行ですので、上から下へ読む必要はありません。左から右に読むだけです。
下図はスタック1:に « 2 X * COS » を手入力で入れた状況です。

f:id:nekosuki2017:20170224221257j:plain

RPL言語搭載電卓のEVAL(評価)ボタンを押すと実行されます。
1:のオブジェクトを評価するとプログラムなので実行するべきものと評価されて実行されます。

以下のような動作になります。

  1. インタープリタは「2」に遭遇して、それをオブジェクトと判断し、スタックにいれます。
  2. インタープリタは「X」に遭遇して、それをオブジェクトと判断し、スタックにいれます。
  3. インタープリタは「*」に遭遇して、それをコマンドと判断し実行します。スタックに入っている2つのオブジェクトが取り出されて乗算されます。このとき、変数Xが存在するかどうかと関係なく'2・X'という結果にして、スタックに戻します。
  4. インタープリタは「COS」に遭遇して、それを数学関数と判断し実行します。
    変数Xが存在しない時の結果はCOS(2・X)になります。
    変数Xが存在するときは(2・X)が計算されてCOS(数値)になります。
    そして、その結果をスタックに戻します。

実行後、スタックの1:にはCOS(2・X)あるいはCOS(数値)が入ります。

変数Xが存在しない場合は下図のようになります。Xは未知数として扱われます。

f:id:nekosuki2017:20170224221540j:plain

変数 X = 'π+1' の場合、下図のようになります。

f:id:nekosuki2017:20170224221611j:plain

変数 X = 'π+1' のときでも結果が数値にならないのは、今回の実験で使ったHP 50gのCAS(数式処理システム)は初期設定でFLAG -3(関数を数値化するシステムフラグ)が無効になっているからです。

強制的に COS(数値) を数値にするには→NUMコマンドを使います。
つまり、プログラムを « 2 X * COS →NUM » と変更すれば、結果は数値になります。
ただし、Xが未定義のときは数値化できないのでエラーになります。

前述の動作から分かるようにRPL言語インタープリタの動作は基本的に以下の2つです。

  1. オブジェクトに遭遇したらオブジェクトをスタックに入れる。
  2. 関数やコマンドに遭遇したら実行する。

以上のようにスタックの動きを念頭に入れてプログラミングをする必要があります。
そのため、コードの可読性は低めになっています。

条件分岐命令は厳密な後置記法(RPN)になっていない

IF文のような条件分岐命令は厳密な 後置記法( RPN)になっていません。
例えば、スタックの1:の値が10よりも大きいかどうかを判断して、10よりも大きい場合は"LARGER THAN 10"という文字列をスタックに返すプログラムを見てみましょう。(このプログラムを実行すると1:にあった数値は消えてしまいます)

RPL言語では「>」ですらコマンドであることに注意して下さい。

« IF 10 > THEN "LARGER THAN 10" END »

「10 >」がIF文の条件文です。 後置記法を徹底するならIF文の前に条件文があるべきです。 実際に後置記法を徹底したForth言語ではIF文の前に条件式を書きます。しかし、さすがにそれは読み難いので、RPL言語ではIF文の後ろに条件式を書くことになっています。
(あるテクニックを使うとForth言語のようにIF文の前に条件式を書くこともできます。しかし、Forth言語のようにTHENとELSEの前に文を書くことはできないので、あまり意味はないと思います)

IF文が厳密な後置記法でなくても条件文「10 >」は後置記法の考えで実行されます。
ここでプログラムの実行前にスタックの1:に11が入っていると仮定します。

f:id:nekosuki2017:20170224222557j:plain
この11という値が10より大きいかどうかを比較することになります。

先ほどと違ってプログラムはファイル化されたものを実行するという仮定にします。そのためスタックにプログラムを入れる必要はありません。
プログラムを実行するとIFの右にある10はオブジェクトなので、スタックに入れられます。
そのため、>コマンドを実行する前のスタックの状態は下図のようになります( 下図は説明のために作成した図であり、実際にはこのようなプログラム動作中の状態は表示されません )。

f:id:nekosuki2017:20170224222705j:plain

次に>コマンドが実行されスタックから2つの値を取り出します。そして、

「 2:に入っていた数値 > 1:に入っていた数値 」

の真偽を判断します。

この場合、「11>10」なので真です。よって、>コマンドはスタックに真(1)を返します。
IF文はスタックから値を1つだけ取り出して、それが真(1)なのか偽(0)なのかを判断します。
真(1)の場合は、THENを実行し、偽(0)の場合はELSEを実行します。ただし、上のプログラムではELSEがないので偽のときは何もしません。
この例の場合、真なので、THENが実行されます。THENの次の"LARGER THAN 10"はオブジェクトなのでスタックに入れられます。その結果、下図のようになります。

f:id:nekosuki2017:20170224223806j:plain

これで期待通りの結果になりました。

ところで、画面の一番下に表示されている [IOPAR] [RPLBR] などを ソフトメニュー と言います。他の図とソフトメニューの表示が変わっていますが、この図では画面の上の方に表示されている {HOME} ディレクトリのファイル名をソフトメニューに表示させています(ファイル名だけではなく関数や機能も表示できます)。

左から2番目の [RPLBR] と表示されているのがファイル化された上のプログラムです。液晶画面の下にソフトメニューと同じ数(つまり6個)のボタンが並んでいます。 [RPLBR] の下にあるボタンを押すとプログラムが実行されます。RPL言語搭載電卓はこのようにファイル化したプログラムをボタンで呼び出すことができます。

RPL言語搭載電卓の操作はRPL言語をGUIから呼び出しているだけ

最初の方で書いたようにRPL言語搭載グラフ電卓の操作はRPL言語をGUIから呼び出しているだけです。

例えば、COS(X)のマクローリン展開をしたいときにスタックの底辺に'COS(X)'という数式を入れておきます。

f:id:nekosuki2017:20170224223946j:plain

TAYLOR0関数を呼ぶと、TAYLOR0関数がスタックから COS(X) を取り出してマクローリン展開を行います(何故TAYLOR0がマクローリン展開を意味するのかは数学の知識があれば分かるでしょう)。

電卓を操作して下図のように画面下のソフトメニューに [TAYLO] を表示します。表示する操作方法についてはここでは触れません。

f:id:nekosuki2017:20170224224121j:plain

画面下のソフトメニューの [TAYLO] を押すと、TAYLOR0関数が実行されます(ソフトメニューは5文字しか表示できないため)。

TAYLR0関数はスタックからCOS(X)を取り出し、マクローリン展開を行い、その結果をスタックに返します。

f:id:nekosuki2017:20170224225256j:plain

COS(X)がマクローリン展開されました。このように 4 Level RPN よりも格段に強力なことができるようになったのです。

上の例からも分かるようにRPL言語搭載電卓はGUIからRPL言語を呼び出しているだけなのです。GUIからRPL言語を使うか、プログラムから直接RPL言語を使うかだけの違いなのです。

RPL言語の資料と開発環境

全てのRPL言語搭載電卓はすでに製造終了になっています。
最後のRPL言語搭載電卓はHP 50gでしたが、2015年に製造終了在庫のみとなっています。

しかし、2017年2月時点では資料やWindowsで動くエミュレータと開発環境もまだ残っています。

RPL言語のマニュアル
http://support.hp.com/us-en/product/hp-50g-graphing-calculator/3235173/manuals

ここの "HP 48gII and 50g Graphing Calculator Advanced User's Reference Manual (V2)" がRPL言語の資料です。
ただし、電卓の操作を覚えてこそのプログラミング言語ですので、これだけを読むことに意味はないと思います。

Debug 4x
http://www.hpcalc.org/details/5441

HP 48シリーズ/HP 49シリーズ/HP 50gのエミュレータ(Emu48)が付いた統合開発環境(IDE)です。Windows用。
実機を持っていなくてもRPL言語を試すことができます。

GUIが煩雑で使いやすいとは思いません。テキストエディタでRPL特有の文字(«,»など)を打つ時はHELPに書いてあるエスケープシーケンスを覚える必要があります。

Version 2.2 Build 168a を使ったことがあるのですが、IDEで.hpファイル(実行ファイル)を生成してSDカードに入れてもHP 50gで何故か認識できませんでした。エミュレータの方で.hpファイルを生成するとHP 50gがちゃんと認識してくれるのですが。

2015年8月を最後に更新されていません。HP社がHP 50gの製造終了を発表したのが2015年ですので、更新がもう終わったのかもしれません。

2017年6月に更新されたようです。今後の更新については、上のリンク先で確認されると良いでしょう。

HPUserEdit
http://www.hpcalc.org/details/6600

HP 48シリーズ/HP 49シリーズ/HP 50gのエミュレータ(Emu48)が付いた統合開発環境(IDE)です。Windows用。
実機を持っていなくてもRPL言語を試すことができます。

Debug4xより分かりやすいと思います。テキストエディタの左側にコマンド一覧とRPL言語用記号が表示されていて使いやすくなっています。
IDE自体で.hpファイルを生成することはできないようでプログラムをエミュレータに送って.hpファイルを生成します。

初期設定時はスペイン語で表示されるので、設定で英語に切り替える必要があります。
しかし、英語に切替えてもメニューの一部が文字化けします(Windows7 64bit 日本語版で試したとき)。

残念ながら2009年5月から更新が止まっています。

Emu48
http://hp.giesselink.com/emu48.htm

前述のDebug4xとHPUserEditに付属しているエミュレータですが、単体で動作させるのはかなり面倒です。機種毎にKML (Keyboard Mapping Language) ファイルの入手やROMイメージの作成(実機のROMイメージを付属コマンドラインツールで変換)が必要です。

前述のDebug4xとHPUserEditをインストールするとその手間が必要ないので、Debug4xやHPUserEditをインストールすることをお勧めします。


以上です。

[表紙へ]