はじめに
C 言語で作っていた FORTH もどき言語(frtm) を Java に移植し,Java のス タンドアロンのアプリケーションとして動作するようにしました.その際に, 実数の計算に対応した他,三角関数等の算術関数のワードを追加しました.た だし,C 言語の UNIX+X11 版等にあったグラフィクス関係のワードは実装して おりません.
更に,Android OS 用のアプリケーション化も行いました.こちらは Google Play において有料で公開しています.下記のリンクからアクセスしてください.
Android アプリの公式開発言語が Java から Kotlin に変わったということで, Java から Kotlin への移植も行いました.Ver. 1.7.0 としましたが,BigInteger を使った分数(有理数)の計算を組み込みました.
ソースコード及び Applet, JAR
Java アプリケーション版のソースコードは下記のリンクから入手できます.gzip で圧縮してあります.ライセンスは GPL です.Java 版を簡単に試験できる Applet 版もあります.Kotlin 版の JAR も公開しました.
- Java ソースコード
- Java Applet による実行(Java Web Start 対応)
- Java Application による実行(Java Web Start 対応)
- Kotlin Runtime 付き JAR ファイル(java -jar frtmkr.jar で実行可能)
Android OS 用アプリケーション
Kotlin アプリケーション版に,Android OS 独自の機能を追加して Android OS 4.0 以上対応のスマートフォン用のアプリケーションを作成しました.言語の コアの部分は上の JAR のものと変わりありません.
Android 用に追加している機能は次の通りです.
- スタックと辞書の初期サイズの設定
- 辞書のワードをワードブックに保存する機能.ただしワードブックは3つまでに限定されています.
- 表示する文字のサイズを3段階から選ぶ機能
- 画面をワードの評価毎に初期化するモードと、画面を残すモードを選択する機能
Ver 1.6.0 からグラフィクス機能を復活させました.次のコマンドが利用可能です.
Ver 1.6.1 でグラフィクス用のワードの名称を短いものに変更しました.
gm グラフィクス・モードへ tm テキスト・モードへ x y moveto (x, y) へ移動 x y lineto 現在位置から (x, y) まで直線描画 x y rmoveto 現在位置から (x, y) だけ移動 x y rlineto 現在位置から (x, y) だけ直線描画 x y w h rect 矩形領域の描画 x y w h rectf 矩形領域の塗り潰し x y point 点の描画 x y w h ellips 楕円の描画 x y w h ellipsf 楕円の塗り潰し c setcol 色設定(0: 黒 〜青緑水赤紫黄〜 15: 白) ** setcolor から改称 ** h l s setHLS HLS 表色系で色指定(h 0:赤〜120:緑,240:青〜359, l,s: 0 〜 100) n setfsz フォントのサイズ指定 ** setfsize から改称 ** x y s drawstr (x, y) に文字列 s を表示 □ 例題 ・ 色を変えながら矩形領域を塗り潰す. : boxes 16 0 for I setcol 10 20 I * + dup 100 100 rectf loop ; gm boxes : hls 16 0 for I 45 * 2 / 50 100 setHLS 10 20 I * + dup 100 100 rectf loop ; gm hls ・再帰図形(Koch 曲線) : pre 5 copy drop ; : genx 3 ndup 6 ndup - * minus 100 / swap 4 ndup 7 ndup - * 100 / + 5 ndup + 5 nrotr 4 ndrop ; : geny swap 3 ndup 6 ndup - * 100 / swap 4 ndup 7 ndup - * 100 / + 4 ndup + 5 nrotr 4 ndrop ; : gen 6 copy genx 7 nrotr geny ; : keep 7 nrotr 7 nrotr pre ; : post 9 nrot 9 nrot 4 nrot 4 nrot 5 ndup 1- ; : line moveto lineto ; : koch dup 0= if drop line else pre 0 0 gen keep 33 0 gen post koch pre 33 0 gen keep 50 -28 gen post koch pre 50 -28 gen keep 66 0 gen post koch pre 66 0 gen keep 100 0 gen post koch 5 ndrop endif ; : kochs 10 setcol 89 440 551 440 4 koch 11 setcol 551 440 320 40 4 koch 12 setcol 320 40 89 440 4 koch ; gm kochs
内部では ReGIS graphics 端末のエスケープシーケンスを部分的に実装して いるため,グラフィクスモードに移行後,コマンドを直接出力することで作画 を行うことができます.
gm (W\(I15\)P[50,50]C\(S\)[][+40,+40][+40,-40][+40,+40][+40,-40][+40,+40][+40,-40][]\(E\)) . (W\(I12\)P[50,150]F\(C\(B\)[200,+200][+200,-150]\(E\)\)) . (W\(I11\)P[70,170]T\(S16\)[16,12]'Hello World') .
grdemo というワードを使って,グラフィクスのサンプル用のワードをユー ザー辞書に追加することができます.
ドキュメント
FoRTh Modoki on Kotlin ver 1.7.0 Mar. 3, 2019. Copyright (C) 1999-2019 浪花 智英 (Tomohide Naniwa) naniwa@rbt.his.u-fukui.ac.jp I. はじめに このプログラムは FORTH を模擬したソフトですが,完全に FORTH を再現した ものではありません.コンパイラは持ちませんが,ユーザー定義ワードでは定 数やワードを定義時に解釈します. 式の解釈は逆ポーランド記法に従って行われます.if による条件分岐. do-while, for-loop などのループのための構造もあります.また,ワードを 組み合わせて新たなワードを作ることもできます. スタックには整数および実数と,文字列を直接保存します.数字の入力は 10 進数,16 進数(頭に0x を付ける),8 進数(頭に 0 を付ける)で行えます. frtm で使用される各種スタックのサイズ等は自動的に拡大しますが,適切な 初期値を与える事で実行時の効率をあげる事ができます.初期値は次の通りと なっています. STMAX 200 ; 数値計算用スタック CSMAX 200 ; ユーザー定義ワードの本体の記憶領域 コンストラクターの引数を変更する事で,適宜変更してください. II. 基本機能 □ 定義済ワード . 表示 .h 16 進表示 .o 8 進表示 cr 改行表示 sp 空白表示 + 和 - 差 * 積 / 商 // 有理数を作る % 余り(整数のみ対応) = 同値 < より小さい <= 以下 > より大きい >= 以上 ! 真偽反転 1+ 1 加算 1- 1 減算 0= 0 と同値 abs 絶対値 max 2数の最大 min 2数の最小 dup 複製 swap 交換 drop 除去 over スタックの2番目の複製 rot スタックの上位3つを回転し,3番目をトップへ rotr スタックの上位3つを回転し,トップを3番目へ ndup スタックの n 番目を複製 nrot スタックを回転し,n 番目をトップへ nrotr スタックを回転し,トップを n 番目へ ndrop スタックの上位 n 個を除去 copy スタックの上位 n 個を複製 SP 呼び出した時点のスタックの深さをスタックのトップに追加 minus 符合変換 spaces 複数個の空白表示 help 定義ワード一覧表示 %PI 円周率 %E 自然対数の底 sin 正弦 cos 余弦 tan 正接 asin 逆正弦 acos 逆余弦 exp 自然対数の底の巾乗 ln 自然対数 log 常用対数 sqrt 平方根 ceil 切り上げて整数に floor 切捨てて整数に round 四捨五入して整数に deg 度へ rad ラジアンへ atan2 逆正接 pow 巾乗 sinh 双曲線正弦 cosh 双曲線余弦 tanh 双曲線正接 asinh 双曲線逆正弦 acosh 双曲線逆余弦 atanh 双曲線逆正接 recip 逆数 fact 階乗 permut 順列 combin 組み合わせ and Bit AND or Bit OR not Bit 反転 xor Bit 排他OR # 直前に ., .o, .h で出力した値をスタックに積む quit 終了 □ 文字列に対する処理 ◇ 表示 echo (Hello_World) echo cr echo は以前のバージョンとの互換のためのワードで,文字列の表示も '.' に よって行える. 文字列中で \ (バックスラッシュ)によるコントロール・コードのエスケープ が可能である.利用可能な文字定数は '\n'(改行),'\t'(水平タブ), '\b'(バッ クスペース)と '\ddd' (ddd は8進数) である.ただし,8進数の文字定数で は最上位の数が 0 であることを仮定している.尚,これ以外の文字はそのま ま文字列中に追加される. ◇ 文字列の分解・結合 pack/unpack (Hello_World) unpack スタック上の文字列を1文字ずつに分解する.スタックには 0 'd' 'l' 'r' 'o' 'W' '_' 'o' 'l' 'l' 'e' 'H' と分解された整数が入る. pack unpack で1文字ずつに分解されたスタック上の整数を,再び文字列にパックする. □ 有理数の計算 数値の計算の際には,次の優先順位で数値の型を自動で変換して計算を行う. 実数 > 有理数 > 整数 有理数の分子が分母より大きくなっても,帯分数にはしない.また,分母が 1 となった場合にも,整数に戻す処理は行なわない.尚、分子・分母は Java (Kotlin) の BigInteger 型で表現されている.分母を 1 としておくことで, 無限長精度整数とみなして計算を行うこともできる. 例題 1 3 // 1 6 // + . cr 1 3 // 1 6 // - . cr 1 2 // 1 4 // * . cr 1 2 // 1 4 // / . cr III. プログラム構造 □ 条件分岐 <cond> if <block 1> endif <cond> if <block 1> else <block 2> endif 仕様 <cond> が 0 以外なら <block 1> を実行. <cond> が 0 なら <block 2> を実行. 制限 else ブロックは複数書ける. 例題 0 if 1 else 2 endif . cr □ do ループ do <block 1> <cond> while 仕様 <cond> が 0 であれば終了.0 以外なら do に戻って繰り返し. 例題 1 do dup . cr 1 + dup 5 < while drop 1 do dup . sp 1 do dup . sp 1 + dup 5 < while cr drop 1 + dup 4 < while drop □ for ループ <n1> <n2> for <block> loop <n1> <n2> for <block> <n3> +loop 仕様 <block> 終了後 n2 + 1(またはn3) を実行し,n1 より小さければ for に戻っ て繰り返し. I リターンスタック上の n2 をスタックに追加する. 制限 n1, n2 は非負の数とする. 例題 5 0 for I . cr loop 10 0 for I . sp 5 1 for I . sp loop cr 2 +loop □ ワードの定義 : name <block> ; 仕様 name を持つワードを作成する. 制限 do や for のループの中ではワードの登録はできない. ユーザー辞書は新しく定義されたものから順に検索するため,再帰が可能になっ ている.また,ワードを再定義しても古いワードの定義はそのまま残る. □ 例題 ・平均 : ave + 2 / ; 10 28 ave . cr ・n 個の平均 : nave swap over 1 for rot + loop swap 1.0 * / ; 1 2 3 4 5 5 nave . cr ・n 個の母分散 : nvarp dup 1+ copy nave SP nrotr swap dup * over 1 for rot dup * + loop swap 1.0 * / SP nrot dup * - ; 1 2 3 4 5 5 nvarp . cr ・n 個の不偏分散 : nvar dup 1+ copy nave SP nrotr swap dup * over 1 for rot dup * + loop SP nrot dup * 3 ndup * - swap 1- 1.0 * / ; 1 2 3 4 5 5 nvar . cr ・最大公約数 : gcd abs swap abs do swap over % dup 0 > while drop ; 1001 819 gcd . cr ・階乗 [fact(1) = 1, fact(n) = n*fact(n-1)] : facti 1 swap 1+ 1 for I * loop ; : factr dup 1 = if else dup 1- factr * endif ; 10 facti . cr 10 factr . cr ・フィボナッチ数列 [fib(0) = 0, fib(1) = 1, fib(n) = fib(n-1) + fib(n-2)] : fib dup 0= if else dup 1 = if else dup 1- fib swap 2 - fib + endif endif ; 7 fib . cr : fibi dup 0= if else 0 1 rot 1 for swap over + loop swap drop endif ; 30 fibi . cr 20 0 for I fibi . sp loop cr ・ハノイの塔 : move1 (Move disk ) echo . swap ( from ) echo . ( to ) echo . cr ; : hanoi dup 1 = if move1 else 3 ndup 3 ndup + 6 - minus 4 ndup swap 3 ndup 1- hanoi 3 ndup 3 ndup 3 ndup move1 1- rotr swap over + 6 - minus swap rot hanoi endif ; 1 2 2 hanoi 1 2 4 hanoi ・N Queens : N 2 * 3 + ; : disp dup N ndup 0 for dup N ndup 0 for over I = if (Q ) echo else (. ) echo endif loop cr drop drop loop drop ; : check over 0 for 3 ndup 6 ndup = if drop 0 else 3 ndup 6 ndup - abs 3 ndup 6 ndup - = if drop 0 else 1 = endif endif 5 nrot 5 nrot drop drop loop rotr drop drop ; : nq dup N ndup 0 for I over 1+ dup N 1- copy 1 check if dup N ndup over 1+ = if dup N copy disp cr else nq endif endif drop drop loop ; : queens dup 0 for I 0 nq drop drop loop drop ; 4 queens [puzzle というワードを使って上記のハノイの塔と N Queens パズルを解く ワードをユーザー辞書に追加することができる.] □ 辞書コマンド help システム定義ワード,ユーザー定義ワードの一覧を表示. forget <name> <name> という名前を持つワード以降にユーザーが定義したワードを全部消去する. fgall ユーザーが定義したワードを全て消去する. def <name> <name> という名前を持つワードの定義を,再評価可能な形式で表示する. □ ワードの探索 ワードはシステム辞書,ユーザー辞書の順に探索される.ユーザー辞書は新し く登録されたものから検索される. IV. 変数 □ 変数の定義 var name 仕様 name という変数を作成する.変数は辞書に登録される.見かけ上はユーザー定義 ワードの形態を取る.name を評価すると,ユーザー辞書のインデックスがスタッ クに保存される. 制限 変数の宣言は実行可能状態でのみ可能.ワードの定義中や,do や for のループの 中では変数の定義は出来ない. □ 値の呼出し @ 仕様 スタックから辞書のインデックスを取りだし,その番地に含まれる数値をスタッ クに置く. □ 値の代入 $ 仕様 スタックから辞書のインデックスと数値を取りだし,その番地に登録する. □ 例題 var x x @ . cr 10 x $ x @ . cr : test x @ . cr ; test