-
文字列を扱うユーザ定義関数としてよくある感じのものを作成してみました。
関数定義 引数 戻り値 半角空白文字列生成
Function GfSpc$(byval pintCnt%)[128]
pintCnt%:文字数を指定 GfSpc$:空白文字列 右側半角空白削除
Function GfRTrim$(pstrValue$)[255]
pstrValue$:対象文字列 GfRTrim$:結果文字列 左側半角空白削除
Function GfLTrim$(pstrValue$)[255]
pstrValue$:対象文字列 GfRTrim$:結果文字列 前後の半角空白削除
Function GfTrim$(pstrValue$)[255]
pstrValue$:対象文字列 GfTrim$:結果文字列 文字列繰り返し
Function GfString$(pintSize%, pstrChr$)[255]
pstrChr$:対象文字
pintSize%:文字数(最大1~255)GfString$:結果文字列
エラー処理を各関数に入れましたが、必要ないかもしれません。 また、引数の文字列の長さチェックは行っていませんので、必要ならば追加して下さい。
'--------------------------------------- '定数宣言:共通⇒(これは別ファイルにすべき) '--------------------------------------- Global GcTrue% : GcTrue% = -1 Global GcFalse% : GcFalse% = 0 '--------------------------------------- '半角空白文字列生成 '--------------------------------------- 'Function GfSpc$(byval pintCnt%)[128] '引 数: ' pintCnt% :文字数を指定 '戻り値: ' GfSpc$ :空白文字列 '--------------------------------------- Function GfSpc$(byval pintCnt%)[128] Private strSpc$[128]: strSpc$ = "" Private i% If pintCnt% > 128 Then pintCnt% = 128 Endif For i%=1 To pintCnt% strSpc$ = strSpc$ + " " Next GfSpc$ = strSpc$ End Function '--------------------------------------- '右側半角空白削除(Rtrim) '--------------------------------------- 'Function GfRTrim$(pstrValue$)[255] '引 数: ' pstrValue$ :対象文字列 '戻り値: ' GfRTrim$ :結果文字列 '--------------------------------------- Function GfRTrim$(pstrValue$)[255] 'エラー処理宣言 On Error Goto GfRTrim.ErrProc Private intCnt%, intIdx% '最後尾から空白以外の文字を探す intCnt% = 0 For intIdx% = Len(pstrValue$) To 1 Step -1 If Mid$(pstrValue$, intIdx%, 1) <> " " Then intCnt% = intIdx% intIdx% = 1 'ループを止める Endif Next '右側全ての空白を排除 GfRTrim$ = Left$(pstrValue$, intCnt%) GfRTrim.Return '関数戻り On Error Goto 0 Exit Function '----- 'エラー処理 '----- GfRTrim.ErrProc GfRTrim$ = "" Resume GfRTrim.Return End Function '--------------------------------------- '左側半角空白削除(Rtrim) '--------------------------------------- 'Function GfLTrim$(pstrValue$)[255] '引 数: ' pstrValue$ :対象文字列 '戻り値: ' GfLTrim$ :結果文字列 '--------------------------------------- Function GfLTrim$(pstrValue$)[255] 'エラー処理宣言 On Error Goto GfLTrim.ErrProc Private intCnt% strTemp$ = "" '--- 左端からスペースではない文字を探していく For intCnt% = 1 To Len(pstrValue$) If Mid$(pstrValue$, intCnt%, 1) <> " " Then '空白では無い文字以降の文字列を戻す GfLTrim$ = Mid$(pstrValue$, intCnt%) intCnt% = Len(pstrValue$) End If Next intCnt% GfLTrim.Return '関数戻り On Error Goto 0 Exit Function '----- 'エラー処理 '----- GfLTrim.ErrProc GfLTrim$ = "" Resume GfLTrim.Return End Function '--------------------------------------- '前後の半角空白削除(Trim) '--------------------------------------- 'Function GfTrim$(pstrValue$)[255] '引 数: ' pstrValue$ :対象文字列 '戻り値: ' GfTrim$ :結果文字列 '--------------------------------------- Function GfTrim$(pstrValue$)[255] Private strWK$[255] strWK$ = GfLTrim$(pstrValue$) '左側空白削除 GfTrim$ = GfRTrim$(strWK$) '右側空白削除 End Function '--------------------------------------- '文字列繰り返し '--------------------------------------- 'Function GfString$(pintSize%, pstrChr$)[255] '引 数: ' pstrChr$ :対象文字 ' pintSize% :文字数(最大1~255) '戻り値: ' GfString$ :結果文字列 '--------------------------------------- Function GfString$(pstrChr$, pintSize%)[255] 'エラー処理宣言 On Error Goto GfString.ErrProc Private intCnt%, strTemp$[255] strTemp$ = "" '文字数分の文字列連結 For intCnt% = 1 To pintSize% strTemp$ = strTemp$ + pstrChr$ Next intCnt% GfString$ = strTemp$ GfString.Return '関数戻り On Error Goto 0 Exit Function '----- 'エラー処理 '----- GfString.ErrProc GfString$ = "" Resume GfString.Return End Function
これらの関数の実行ソースは以下の様になります。Sub DispData(Byval strP1$, Byval strP2$) PRINT "[" + strP1$ + "]=>[" + strP2$ + "]" End Sub '----- '実行はここから処理 '----- Main ' PRIVATE Num$, nRet%, intLoop% SCREEN 1 '漢字モード LOCATE , , 2 'カーソルをブロック表示 PRINT "***GfRTrim$" PRIVATE W$, W2$ W$ = "1234 " W2$ = GfRTrim$(W$) CALL DispData(W$, W2$) W$ = "12 34 " W2$ = GfRTrim$(W$) CALL DispData(W$, W2$) W$ = "12 34 A" W2$ = GfRTrim$(W$) CALL DispData(W$, W2$) PRINT "***GfLTrim$" W$ = " 1234" W2$ = GfLTrim$(W$) CALL DispData(W$, W2$) W$ = " 12 34 " W2$ = GfLTrim$(W$) CALL DispData(W$, W2$) W$ = " 1234 A" W2$ = GfLTrim$(W$) CALL DispData(W$, W2$) PRINT "***GfTrim$" W$ = " 1234 " W2$ = GfTrim$(W$) CALL DispData(W$, W2$) W$ = " 12 34 " W2$ = GfTrim$(W$) CALL DispData(W$, W2$) PRINT "***GfString$" W$ = GfString$("@", 10) PRINT W$; WAIT 0, &h01 'キー入力待ち END
これを実行すると以下の様な表示になります。
=====
2016/04/02:の時の情報
PR -
以前、ユーザ定義関数の値渡し・参照渡しについて記事にしましたが、 抜けていた項目もありますので、再度紹介します。
ユーザ定義関数を作成する場合に、何がしかの引数(ひきすう)を持つことはよくあります。 この引数の渡し方には、値渡し(call by value)と、 参照渡し(call by reference)の2種類があります。
値渡しとは、引数で渡された値を関数内では参照・変更できるが 呼出し元の変数に影響を与えない。
参照渡しとは、引数で渡された値を関数内で変更した場合、 呼出し元の変数に影響を与えます。 言い方を変えれば、関数内で参照する変数は、 呼出し元の変数を直接アクセスしています。 C言語的に言えば、参照つまり変数のポインタを引数で渡すことでしょうか。
よく関数は独立性を持たせるために、値渡しが推奨されますが、 参照渡しには参照渡しの良さもあります。 値渡しの値そのものは関数を呼出す時に、ユーザ定義関数用スタックに格納されます。 (スタックなので積むと表現した方がしっくりきますが)
渡される値が文字列で非常に長い場合などは、スタックの消費が多くなりますし、 値そのものをスタックにコピーされる時間が多くかかります。 これを抑えるために参照渡しにすることがあります。
また、配列データを引数で渡す時には値渡しではできなく、 参照渡しにしなければなりません。 配列データは多くのメモリ領域を必要とするため、 BHT-BASICではメモリもそんなに多くないので、 参照渡しの仕様にしたのだと思います。
以下のソースがその例なのですが以下の4個の関数を宣言しています。 ・TestByval の名前で値渡し関数
・TestByref の名前で参照渡し関数
・TestByval2%% の名前で値渡し値を返す関数
・TestArrByref の名前で配列・参照渡し関数
'File [MODULE1.SRC] '値渡し関数テスト Sub TestByval(byval pintWK%) pintWK% = pintWK% + 1 '引数の変数を変更できる PRINT "pintWK%="; pintWK% '変更確認 End Sub '参照渡し関数テスト Sub TestByref(byref pintWK%) pintWK% = pintWK% + 1 '引数の変数を変更できる PRINT "pintWK%="; pintWK% ' End Sub '値渡し関数テスト2 Function TestByval2%(byval pintWK%) pintWK% = pintWK% + 1 TestByval2% = pintWK% '戻り値で引数変数値を返す End Function '配列参照渡し関数テスト Sub TestArrByref(byref pintArrWK%()) PRIVATE I% FOR I% = 1 TO 4 PRINT "pintArrWK%("; I%; ")="; pintArrWK%(I%) '配列データに1加算 pintArrWK%(I%) = pintArrWK%(I%) + 1 NEXT I% End Sub '----- '実行はここから処理 '----- Main SCREEN 1 '漢字モード LOCATE , , 2 'カーソルをブロック表示 PRIVATE WK% WK% = 1 '値渡しの関数コール PRINT "値渡しの関数..." Call TestByval(WK%) PRINT "WK%="; WK% '参照渡しの関数コール PRINT "参照渡しの関数..." Call TestByref(WK%) PRINT "WK%="; WK% '値渡しの関数2コール PRINT "値渡しの関数2..." WK% = TestByval2%(WK%) PRINT "WK%="; WK% '配列を渡すテスト PRIVATE I%, ArrWK%(4) FOR I% = 1 TO 4 ArrWK%(I%) = I% * 10 NEXT I% Call TestArrByref(ArrWK%) PRIVATE W$ WAIT 0, &h01 'キー入力待ち W$ =Input$(1) '入力されたキーを取得して戻す。 PRINT "TestArrByrefコール後" FOR I% = 1 TO 4 PRINT "ArrWK%("; I%; ")="; ArrWK%(I%) NEXT I% WAIT 0, &h01 'キー入力待ち END
このソースの実行の様子は以下の様になります。(最初のキー入力待ちまでの表示)
値渡しの関数ではWK%が変更されないことが確認できます。 また、参照渡しの関数ではWK%が変更さたことが確認できます。
その後、配列データの変更がされたことを確認する表示が以下の様になります。
=====
2016/04/02:の時の情報
-
前回は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:の時の情報
-
今回は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:の時の情報