■閉鎖した昔のブログの記事復活
[2025/05/14] BHT-BASIC4.0:数値用キー入力関数(ユーザ定義関数)について(BHT-1300) (No.443)
[2025/05/14] BHT-BASIC4.0:キー入力について(BHT-1300) (No.442)
[2025/05/14] BHT-BASIC4.0:画面への表示について(BHT-1300) (No.441)
[2025/05/14] BHT-BASIC4.0:演算子について(BHT-1300) (No.440)
[2025/05/14] BHT-BASIC4.0:ユーザ定義関数について(BHT-1300) (No.439)
[2025/05/14] BHT-BASIC4.0:キー入力について(BHT-1300) (No.442)
[2025/05/14] BHT-BASIC4.0:画面への表示について(BHT-1300) (No.441)
[2025/05/14] BHT-BASIC4.0:演算子について(BHT-1300) (No.440)
[2025/05/14] BHT-BASIC4.0:ユーザ定義関数について(BHT-1300) (No.439)
-
前回はBHT-BASICのキー入力の INPUT 命令はいまいち使いにくいのを記事にしましたが、 それを補うために汎用的な数値用キー入力関数を作ってみました。
以下のソースがその関数なのですが GfGetNum% の名前で、 引数は入力文字列を返す変数と、入力桁数を指定する変数があります。 この関数の戻り値としては[ENT]キー、[F1]キーのどちらで戻ったかを示す整数値フラグです。
実際のプログラムの実行はラベル Main の次からです。 プログラムの中で使用されるユーザ定義関数は、 使用される位置よりも前に宣言されていなければなりません。 そのため、実行開始がユーザ定義関数より下の方に位置しています。
この件ですが、一般的なコンパイラであれば、同じソース内のローカルなユーザ定義関数の 宣言を上の方で出来る様にして、ユーザ定義関数よりも前に実行している行が在っても 良いようにしてほしいものです。 共通関数的なユーザ定義関数は常にソースの最初の方に持ってこないといけないので ソースの位置制限があるのは問題だと思います。 (もっとも、共通関数は別ファイルにして関数定義のみを宣言させる方法もありますが)
'File [MODULE1.SRC] '--------------------------------------- '定数宣言:共通⇒(これは別ファイルにすべき) '--------------------------------------- Global GcTrue% : GcTrue% = -1 Global GcFalse% : GcFalse% = 0 Global GcGetRetNormal% : GcGetRetNormal% = 0 '[ENT]キーでの終了 Global GcGetRetF1% : GcGetRetF1% = 1 '[F1]キーでの終了 '--------------------------------------- '1文字キー入力関数 '--------------------------------------- 'Function GfGetKey$ '戻り値: ' GfGetKey$ :1文字を文字列で返す '--------------------------------------- Function GfGetKey$ Wait 0, &h01 'キー入力待ち GfGetKey$ =Input$(1) '入力されたキーを取得して戻す。 End Function '--------------------------------------- '数値入力 '--------------------------------------- 'Function GfGetNum%(Byref pstrNum$, Byval intUnit%) '引 数: ' pstrNum$ :数値文字列(新規入力の場合は、空白文字列を指定) ' intUnit% :入力桁数を指定 '戻り値: ' GfGetNum% :どのキーで終了したかを示す以下のフラグを返す ' : GcGetRetNormal% = 0 '[ENT]キーでの終了 ' : GcGetRetF1% = 1 '[F1]キーでの終了 '--------------------------------------- Function GfGetNum%(Byref pstrNum$, Byval intUnit%) 'エラー処理宣言 On Error Goto GfGetNum.ErrProc Private intX%, intY%, intLoop%, strInp$, intRet%, strBuf$, strSpace$ '空白文字列・指定桁数 strSpace$ = LEFT$(" ", intUnit%) 'カーソル位置退避 intY% = CSRLIN intX% = POS(0) '結果格納領域の初期化 strInp$ = pstrNum$ '数字入力方式に設定 OUT .pnKeyEnt, .pvKyNm intLoop% = GcTrue% While intLoop% = GcTrue% '数値表示 Cursor OFF Locate intX%, intY% Print strSpace$; Locate intX%, intY% Print strInp$; Cursor ON strBuf$ = GfGetKey$ 'キーを1文字取得 IF "0" <= strBuf$ And strBuf$ <= "9" THEN '数字の場合 If strBuf$ = "0" Then If 0 < LEN(strInp$) AND LEN(strInp$) < intUnit% Then strInp$ =strInp$ + strBuf$ Endif Else If LEN(strInp$) < intUnit% Then strInp$ =strInp$ + strBuf$ Endif Endif ELSE '数字以外の場合 SELECT strBuf$ CASE CHR$(13) '[ENT]キー文字の場合 If strInp$ <> "" Then pstrNum$ = strInp$ intLoop% = GcFalse% intRet% = GcGetRetNormal% Endif CASE CHR$(8) '[BS]キーの場合 If LEN(strInp$) > 0 Then strInp$ = LEFT$(strInp$, LEN(strInp$) - 1) Else Endif CASE CHR$(24) '[クリア]キーの場合 strInp$ = "" CASE "A" '[F1]キー文字の場合 intLoop% = GcFalse% intRet% = GcGetRetF1% END SELECT ENDIF WEnd '戻り値 GfGetNum% = intRet% GfGetNum.Return '関数戻り On Error Goto 0 Exit Function '----- 'エラー処理 '----- GfGetNum.ErrProc GfGetNum% = GcGetRetNormal% pstrNum$ = "0" Resume GfGetNum.Return End Function '----- '実行はここから処理 '----- Main PRIVATE Num$, nRet%, intLoop% SCREEN 1 '漢字モード LOCATE , , 2 'カーソルをブロック表示 intLoop% = GcTrue% 'ループ実行フラグON WHILE (intLoop%) LOCATE 1, 1 PRINT "数量="; nRet% = GfGetNum%(CNT$, 5) '数字文字列入力 If nRet% = GcGetRetF1% Then '[F1]キー戻り?? intLoop% = GcFalse% 'ループ実行フラグOFF ENDIF LOCATE 1, 3 PRINT "入力=" + CNT$; WEND WAIT 0, &h01 'キー入力待ち END
このソースの実行の様子は以下の様になります。
この関数ですが、[F1]キー戻りはありますが、F2,F3,F4での戻りも必要かとは思いますので、 この関数を利用される場合は、それらの拡張をしてみてください。
=====
2016/04/02:の時の情報
PR -
今回はBHT-BASICのキー入力について説明したいと思います。
私が使った BHT-1306B ですが、 商品コードなどはバーコードでスキャンすれば入力できますが、 数量などを入力するにはキー入力が必要になります。
以下のソースは、画面モードを「漢字モード」に設定し、キー入力を数字入力方式に設定して 文字列入力を行います。 カーソル表示の制御は LOCATE 命令で、ブロック表示になる様に行います。
PRIVATE CD$ SCREEN 1 '漢字モード OUT .pnKeyEnt, .pvKyNm '数字入力方式に設定 LOCATE , , 2 'カーソルをブロック表示 INPUT "コード=", CD$ '文字列入力 WAIT 0, &h01 'キー入力待ち END
このソースの実行の様子は以下の様になります。
この場合、入力はずっとできるのかと思いきや、40文字を入力したところでカーソルが止まります。 BHT-BASICでは INPUT 命令では文字変数の最大文字列長までしか入力できない様です。
当然以下の様に文字列変数の領域を4文字までとすれば、4文字までしか入力できません。
PRIVATE CD$[4] '4文字がMAX SCREEN 1 '漢字モード OUT .pnKeyEnt, .pvKyNm '数字入力方式に設定 LOCATE , , 2 'カーソルをブロック表示 INPUT "コード=", CD$ '文字列入力 WAIT 0, &h01 'キー入力待ち END
この INPUT 命令の仕様は便利なように思いますが、 キー入力の途中で何かを行いたい場合は別の方法が必要だと思います。
PRIVATE NN& '長整数変数 SCREEN 1 '漢字モード OUT .pnKeyEnt, .pvKyNm '数字入力方式に設定 LOCATE , , 2 'カーソルをブロック表示 INPUT "数量=", NN& '数値入力 WAIT 0, &h01 'キー入力待ち END
このソースでは桁数が短い場合は問題無く数値入力ができますが、 下図の様に桁数を長く入力すると以下の実行時エラーが発生します。
エラーコード(&H06)(演算結果が許容範囲をこえています。)
この結果から業務プログラムでは INPUT 命令は使えない様に思います。
ではどうすればいいのかは今後の記事にご期待ください。
=====
2016/04/02:の時の情報
-
今回はBHT-BASICの画面への表示について説明したいと思います。
私が使った BHT-1306B ですが、液晶画面の仕様は以下の様になっています。
・ドット数:240(横)×320(縦)ドット
・表示文字数:(文字フォントサイズと画面モードで変わります)
フォントサイズ 画面モード 表示文字数(桁×行) 文字ドット数(横×縦) 標準
ANKモード 20桁×20行 12×16 標準
漢字モード 8桁×10行(16桁×10行) 30×30(15×30) 小
ANKモード 20桁×20行 12×16 小
漢字モード 10桁×13行(20桁×13行) 24×24(12×24) 40
ANK・漢字 6桁×8行(12桁×8行) 40×40(20×40) 30
ANK・漢字 8桁×10行(16桁×10行) 30×30(15×30) 24
ANK・漢字 10桁×13行(20桁×13行) 24×24(12×24) 16
ANK・漢字 15桁×20行(30桁×20行) 16×16(8×16)
画面モードの切り替えはSCREENステートメント(命令)で行います。
また、フォントサイズの指定は、 OUT命令により&H6080のアドレスに値を出力することで行います。
ソース的には以下の様な感じです。
SCREEN 0 'ANKモード SCREEN 1 '漢字モード OUT & H6080, 0 '標準フォント OUT &H6080, 1 '小フォント OUT &H6080, 40 '縦横40ドット OUT &H6080, 30 '縦横30ドット OUT &H6080, 24 '縦横24ドット
そこで各モードとフォント設定でどの様な表示なるのかを試してみました。
■標準フォント・ANKモード
OUT &H6080, 0 '標準フォント SCREEN 0 'ANKモード DIM I% FOR I% = 1 TO 20 '20×20 PRINT "01234567890123456789"; NEXT I% WAIT 0, &h01 'キー入力待ち END
ここで、FOR文が出てきましたが、 このステートメントはいろんな言語で既によく使われていますのでFOR文自体の 説明はしませんが、20文字の文字列を20回画面に表示を行います。 実行結果は以下の様になります。
■標準フォント・漢字モード
OUT &H6080, 0 '標準フォント SCREEN 1 '漢字モード DIM I% FOR I% = 1 TO 10 '8×10 PRINT "01234567"; NEXT i% WAIT 0, &h01 'キー入力待ち END
■小フォント・ANKモード
SCREEN 0 'ANKモード OUT &H6080, 1 '小フォント DIM I% FOR I% = 1 TO 20 '20×20 PRINT "01234567890123456789"; NEXT i% WAIT 0, &h01 'キー入力待ち END
シミュレーションでの表示ですが、「標準フォント・ANKモード」と同じになりました。
■小フォント・漢字モード
SCREEN 1 '漢字モード OUT &H6080, 1 '小フォント DIM I% FOR I% = 1 TO 13 '10×13 PRINT "0123456789"; NEXT i% WAIT 0, &h01 'キー入力待ち END
■40ドットフォント
OUT &H6080, 40 '縦横40ドット DIM I% FOR I% = 1 TO 8 '6×8 PRINT "012345"; NEXT i% WAIT 0, &h01 'キー入力待ち END
■30ドットフォント
OUT &H6080, 30 '縦横30ドット DIM I% FOR I% = 1 TO 10 '8×10 PRINT "01234567"; NEXT i% WAIT 0, &h01 'キー入力待ち END
■24ドットフォント
OUT &H6080, 24 '縦横24ドット DIM I% FOR I% = 1 TO 13 '10×13 PRINT "0123456789"; NEXT i% WAIT 0, &h01 'キー入力待ち END
この最後の表示は、「小フォント・漢字モード」と同じ結果になります。
私がBHT-1306Bを使ったシステムを作成した時には、 漢字の文字数などから判断して「小フォント・漢字モード」の表示を採用しました。
=====
2016/04/02:の時の情報
-
今回はBHT-BASICの演算子について説明したいと思います。
BHT-BASICには、算術演算子、関係演算子、論理演算子、関数演算子、文字列演算子と 普通の言語にはだいたいそろっている演算子があります。
■演算子の優先順位
優先順位 演算子名称 演算子 1
括弧 ( ) 括弧の中が優先して演算 2
関数演算子 組込み関数,ユーザ関数の実行 3
算術演算子 ※演算子の中で更に優先度がある
優先順位 演算 演算子 1
負号 - 2
乗算、除算 * , / 3
剰余演算 MOD 4
加算、減算 + , - 4
関係演算子 = , <> , >< , < , > , <= , >= , =< , => 5
論理演算子 ※演算子の中で更に優先度がある
優先順位 演算 演算子 1
否定 NOT 2
論理積 AND 3
論理和 OR 4
排他的論理和 XOR 6
文字列演算子
演算子は特に目新しいものは無く、よくあるものばかりですので、 各演算子毎に細かくは記しませんが、少し注意するものをピックアップします。
■算術演算子・剰余演算(MOD)
MODは割り算の余りを返すものです。 以下の例の様に数値は四捨五入し整数にしてからMOD演算が行われます。
PRIVATE X%, Y%, R% X% = 10 Y% = 3 R% = X% MOD Y% 'X%をY%で割った余り PRINT "R%=" ; R% R% = 10 MOD 4.1 '4.1を四捨五入し結果 10 MOD 4 PRINT "R%=" ; R% R% = -10 MOD -4.5 '-4.5を四捨五入し結果 -10 MOD -5 PRINT "R%=" ; R% Wait 0, &h01 'キー入力待ち END
■オーバーフローとゼロによる除算
演算結果がオーバーフローしたり、ゼロで割った場合には実行時エラーが発生します。 以下のソースはその例を示します。
ON ERROR GOTO MAIN.ERR 'エラー宣言 PRIVATE X%, Y% X% = 32767 '整数型のMAX値 PRINT "TEST-1" Y% = X% / 0 'ゼロで割る PRINT "TEST-2" Y% = X% + 1 '整数型のオーバーフロー Wait 0, &h01 'キー入力待ち END MAIN.ERR: 'エラーコードと発生アドレス表示 PRINT "ERR=" + HEX$(ERR) + " : ERL=" + HEX$(ERL) RESUME NEXT 'エラー発生の次の行に戻る
■関係演算子について
関係演算子は2個の式を比較して、真「-1」または偽「0」を返します。 この値を使って、プログラムの流れを制御できます。 以下のソースは、IF文を使った各関係演算子の例を示します。
また、関係演算子の計算結果を変数に入れて使うこともできます。
SCREEN 1 '標準漢字モードを指定 PRIVATE X% '各関係演算子の例 IF 1 = 1 THEN PRINT "[=] :等しい" ENDIF IF 0 <> 1 THEN PRINT "[<>]:等しくない" ENDIF IF 0 < 1 THEN PRINT "[<] :小さい" ENDIF IF 1 > 0 THEN PRINT "[>] :大きい" ENDIF IF 0 <= 1 THEN PRINT "[<=]:以下" ENDIF IF 1 => 0 THEN PRINT "[=>]:以上" ENDIF PRINT "-----" '比較を式に代入 X% = (1 = 1): PRINT "等しい="; X% X% = (0 = 1): PRINT "等しくない="; X% Wait 0, &h01 'キー入力待ち END
■論理演算子を式で使う
論理演算子は、複数の関係演算子での判定結果を関連付ける演算子です。
OUT &H6080, 1 '小フォントを指定 PRIVATE X%, Y%, Z% 'NOT Z% = NOT(0): PRINT "NOT (0)=" ;Z% Z% = NOT(NOT(0)): PRINT "NOT(NOT((0))=" ;Z% Z% = NOT(1): PRINT "NOT (1)=" ;Z% 'AND Z% = 0 AND 0: PRINT "(0) AND (0)=" ;Z% Z% = 0 AND 1: PRINT "(0) AND (1)=" ;Z% Z% = 1 AND 0: PRINT "(1) AND (0)=" ;Z% Z% = 1 AND 1: PRINT "(1) AND (1)=" ;Z% 'OR Z% = 0 OR 0: PRINT "(0) OR (0)=" ;Z% Z% = 0 OR 1: PRINT "(0) OR (1)=" ;Z% Z% = 1 OR 0: PRINT "(1) OR (0)=" ;Z% Z% = 1 OR 1: PRINT "(1) OR (1)=" ;Z% 'XOR Z% = 0 XOR 0: PRINT "(0) XOR (0)=" ;Z% Z% = 0 XOR 1: PRINT "(0) XOR (1)=" ;Z% Z% = 1 XOR 0: PRINT "(1) XOR (0)=" ;Z% Z% = 1 XOR 1: PRINT "(1) XOR (1)=" ;Z% Wait 0, &h01 'キー入力待ち END
■文字列演算子について
文字列の演算では結合しかなく、+マークで行います。 また、数値の様に文字列の比較ができます。SCREEN 1 '標準漢字モードを指定 '文字列連結 PRIVATE X$, Y$, Z$ X$ = "123": Y$ = "ABC" Z$ = "連結=" + X$ + ":" + Y$ PRINT Z$ PRINT "-----" '各関係演算子の例 IF "123" = "123" THEN PRINT "[=] :等しい" ENDIF IF "012" <> "123" THEN PRINT "[<>]:等しくない" ENDIF IF "001" < "002" THEN PRINT "[<] :小さい" ENDIF IF "003" > "002" THEN PRINT "[>] :大きい" ENDIF PRINT "-----" '文字列の長さが異なる IF "123" <> "12" THEN PRINT "[<>]:等しくない" ENDIF IF "12" < "123" THEN PRINT "[<] :小さい" ENDIF IF "123" > "12" THEN PRINT "[>] :大きい" ENDIF Wait 0, &h01 'キー入力待ち END
=====
2016/04/02:の時の情報
-
ハンディターミナルの開発言語であるBHT-BASIC4.0についての4回目になります。 今回はユーザ定義関数について説明したいと思います。
■ユーザ定義関数
ユーザ定義関数とは、BHT-BASICが既に備わっている関数ではなく、 ユーザが任意で作成する関数のことです。 ユーザが定義できる関数には大きく分けて2種類のものがあり、 DEF FN及びFUNCTIONで定義される値を返す関数と、 SUBで定義される値を返さない関数があります。
このうちFUNCTION関数、SUB関数はDECLAREステートメントで宣言することで 別モジュールで使用することができます。
DEF FN関数及びFUNCTION関数には返す値により 関数の最後にデータ型を示す記号を付加します。
ユーザ定義関数のデータ型 DEF FN関数の書式 FUNCTION関数の書式 整数型
FN関数名% 関数名% 長整数型
FN関数名& 関数名& 実数型
FN関数名 関数名 文字型
FN関数名$ 関数名$ 文字型
(文字列長指定)FN関数名$(・・・)[NNN]
(NNN:に文字列長指定)関数名$(・・・)[NNN]
(NNN:に文字列長指定)
値を返す関数は、私は専らFUNCTION関数を使い、DEF FN関数は殆んど使っていません。 なぜならば、DEF FN関数ではSTATIC変数が使えませんし、 他のモジュールから参照することができないからです。
尚、値を返さない関数は当然のことSUB関数で宣言します。
関数には値を渡さない場合は引数の宣言をしませんが、 値が必要な場合には関数の宣言のところで引数の宣言を行います。 この引数の渡し方には、値渡し(call by value)と、 参照渡し(call by reference)の2種類があります。
■値渡し・参照渡し
以下のソース「MODULE1.SRC」を見てください。
'File [MODULE1.SRC] FUNCTION Func1%(BYVAL P%) Func1% = P% * 2 '引数を2倍して戻す END FUNCTION FUNCTION Func2%(BYREF P%) Func2% = P% * 2 '引数を2倍して戻す P% = P% + 1 '引数に+1する END FUNCTION DIM I% I% = 10 PRINT "Func1%=" ; Func1%(I%) PRINT "I%=" ; I% 'I%は変わらない PRINT "Func2%=" ; Func2%(I%) PRINT "I%=" ; I% 'I%は変化した!! Wait 0, &h01 'キー入力待ち END
これを実行すると以下の表示の様になります。
FUNCTION関数の宣言はFUNCTIONで始まり、END FUNCTIONで終わります。 関数の引数は仮引数名で宣言し、値渡しはBYVALキーワードで宣言し、 参照渡しはBYREFキーワードで宣言します。 BYVAL、BYREFが無い場合はデフォルトで値渡しになりますが、 引数の意味合いをはっきりさせるため、必ずこのキーワードを付加すべきだと思います。
関数の戻り値は関数名に値を代入することで戻します。
このソースでは、Func1%は値渡し、Func2%は参照渡しの例です。
=====
2016/04/02:の時の情報