私の備忘録です。順次追加していきます。
何も知らない初心者なので間違いがあればご指摘いただければ幸いです。
尚、RPGIVとRPGLEは厳密には違うようですが、ここではRPGLEに統一しておきます。
登場人物はRPG(III)とRPGLEとFFRPGの3つです。
事前準備
ソースファイルの作成方法、RPGIIIからRPGLEへの変換方法など、コードを書くまでの準備です。
ソースファイルの作成
RPGLEのソースはレコード長が違うのでQRPGSRCには入れられません。
RPGLEやFFRPGは別でソースファイルを作ること。名前はQRPGLESRCかQFFRPGSRCが一般的。
コマンド
[構文] CRTSRCPF FILE(ライブラリ/ソースファイル名) RCDLEN(112) IGCDTA(*YES) TEXT('説明文') [サンプル] CRTSRCPF FILE(HOGELIB/QFFRPGSRC) RCDLEN(112) IGCDTA(*YES) TEXT('FFRPGのソースファイル')
RCDLEN
RCDLENとは最大レコード長、横幅のことです。
指定しないとデフォルトの92になるので、RPGLEの場合は必ず112にすること。
厳密にはRPGLEもFFRPGもコンパイルは通るしちゃんと実行もできるみたいですが、エラーっぽいメッセージが出ます。
特にフリーフォームでは横幅が狭いと文字数を超えたときにRDi上に下記のようなエラーが表示されます。
Error)1つ以上の行がテキスト制限を超えています。ファイルが保存されるときに切り捨てられます。
IGCDTA
IGCDTA(*YES)は必ず指定すること。
これを指定しないとソース内で日本語が使えなくなくなります。
試しにDSPLYを使って「こんにちは」を表示するテストしてみたが、RDI上では表示されるがエミュレーターでは何も表示されないし、DSPLYの出力も文字化けしてしまう。
RDIの表示
SEUの表示
DSPLYを実行した表示
RDiの導入
一番肝心なところですが割愛です。RDiとはエディタのことですが、私の会社は先日のIBMi更新のときにRDiを導入しました。
私の場合はソースファイルにあるコードをつついてエミュレーターに切り替えコンパイルする手法でやります。ゆえに環境はエディタがRDiに変わっただけです。
尚、固定長のRPGIIIやRPGLEは無理ですが、フリーフォームなら無料のマイクロソフトVSCodeでもいいらしいです。ソースといってもただのテキストなので。
やり方は拡張子を.RPGLEや.SQLRPGLEで作ってFTPを使って統合ファイルシステム(IFS)上にアップすればいいそうです。
フリーフォームを習得するには
練習にRPGLEで書かれたコードをフリーフォーム化するのが一番分かりやすいと思います。
私もそれで身につけ中です。
RPGIIIのソースをRPGLEに変換するには
RPGLEではなく、いまだRPGIIIの場合はフリーフォームにする前にRPGLEにしないといけません。
そのためのコンバート(変換)コマンドがあります。
CVTRPGSRC FROMFILE(HOGELIB/QRPGSRC) FROMMBR(HOGEPGM) TOFILE(HOGELIB/QFFRPGSRC) LOGFILE(*NONE)
TOFILEは前述したRCDLEN(112)で設定したソースファイルを指定すること。
通常のQRPGSRCを指定した場合は下記のようなエラーが表示されます。
ライブラリーHOGELIBのTOFILE QRPGSRCのレコード長が推奨値より小さい。 メンバー HOGEPGMがライブラリーHOGELIB、ファイルQRPGSRCに追加された。
前述のとおりコンパイルは通るしプログラムとしてもちゃんと動きますが、やらない方がいいでしょう。
私の場合はLOGFILEが必要が無いので*NONEにしました。
LOGFILEのデフォルトはQRNCVTLGですが、ファイルが存在しない場合はエラーで落ちるので、必要な場合は先に作っておく必要があるようです。
事前準備その他
一応メモで残しておきます。
ソースファイルの削除
ソースファイルの削除。間違って作った場合はこれで消しましょう。
DLTF FILE(HOGELIB/QFFRPGSRC)
ソースの作成
ソースの新規作成。PDMやRDIから操作すればいいけど一応メモ。
ADDPFM FILE(HOGELIB/QFFRPGSRC) MBR(メンバー名) SRCTYPE(RPGLE) TEXT('フリーフォーム練習')
フリーフォームRPGの基本
フリーフォームRPG基本的なお作法について書いておきます。
先頭と終了
フリーフォーム記述の開始は、先頭に**FREEと書くだけです。
先頭以外はダメです。2行目でもダメ。
もちろんRPGIVの固定長の途中に埋めこむのも不可。
プログラムの終了は従来のLR RETURNを下記のように書きます。
DSPLY命令だけのプログラムですが、コンパイルも通りますしちゃんと動きます。
命令の最後はセミコロン(;)で区切る
命令文の終了はセミコロンまで。
途中は改行してもよし。但し、命令文のキーワードの途中での改行はNG。
オープン言語のPHPなどと同じですね。
コメントアウト
コメントアウトはスラッシュを2つ。
/* */のように改行をまたいで複数行をコメントをする方法は無いみたいです。
//コメント書き放題なのでフリーフォームは最高です。 POST = ''; //郵便番号 MONEY = 0; //金額 *IN85 = *OFF; //某フラグ
値の代入
固定長のような面倒な書き方や、RPGLEのようなEVALは要りません。
これで終わりです。
MONEY = 0;
文字の連結
文字の連結は+でできる。
POSTDSP = POST_FRONT + '-' + POST_REAR;
制御ステートメント CTL-OPT
あまり良く分かっていませんが、RPGソースのド先頭にある意味なさげなアレです。
よくあるYの指定
RPGIIIやRPGIVで一番先頭の行で指定するあれです。
CTL-OPT DATEDIT(*YMD);
ファイル定義ステートメント DCL-F
DCL-Fで始まり、その後にファイル名が続き、さらにその後にキーワードが続く。
DCL-F ファイル名 装置キーワード キーワード;
装置キーワードとは、DISK PRINTER WORKSTNなど。
装置キーワードはファイル名の直後に指定しなければならない。
読み書きするファイルの指定
装置キーワードにDISKを指定します。
RPGのF仕様書と同じで、定義をしていないファイルは読み書きができません。
DCL-F ファイル名 DISK KEYED USAGE(*INPUT);
キー順に読む必要があればKEYED。
読むだけの場合はUSAGE(*INPUT)とすればいい。
更新の場合はUSAGE(*UPDATE)とするが、USAGE(*INPUT : *UPDATE)としてもいいみたい。
複数ファイルある場合は複数行書けばOK、区切りのセミコロン(;)をお忘れなく。
表示装置ファイルの指定
DSPFの指定です。装置キーワードはWORKSTNです。
表示装置は入出力するのでUSAGEはINPUTとOUTPUT両方指定します。
DCL-F HOGEDSP WORKSTN USAGE(*INPUT:*OUTPUT)
印刷装置ファイルの指定
装置キーワードはPRINTERです。
印刷に入力はないのでUSAGEはOUTPUTのみ。
オーバーフローはOFLINDで指定します。*INOFでも*IN01-99でも下記のような変数名でもOK。オーバーフロー発生時にオンになる。
DCL-F HOGEPRT PRINTER OFLIND(OVERFLOW) USAGE(*OUTPUT);
こんな感じで使う。
IF OVERFLOW; WRITE HEADER; //ヘッダを書き出す OVERFLOW = *OFF; ENDIF;
サブファイルの指定
サブファイルは画面装置ファイルの中に組み込むものなので、画面装置ファイルの指定の直後に書くようです。
DCL-F HOGEDSP WORKSTN USAGE(*INPUT:*OUTPUT) SFILE(SFL : SFLRRN);
サブファイルが2つある場合は続けて書く。改行はなくてもいいけどあったほうが見やすい。
DCL-F HOGEDSP WORKSTN USAGE(*INPUT:*OUTPUT) SFILE(SFL : SFLRRN) SFILE(SFL2 : SFLRRN);
定義仕様書 DCL
変数、データストラクチャー、パラメータリストなどの定義です。
変数を宣言する DCL-S
RPGIIIではプログラム中で文字数や少数桁を宣言することで型宣言としている節がありました。
RPGLEからのようですが、分かりやすく上部でまとめて宣言できるようです。
変数名にはアンダーバーも使えます。
文字型
郵便番号のように7桁固定で必要なカラムはCHAR、名前のように可変するカラムはVARCHARで良いと思います。
DCL-S POST_CODE CHAR(7) //固定長 DCL-S FIRST_NAME VARCHAR(20) //可変長 //代入例 POST_CODE = '1234567'; FIRST_NAME = 'よしお';
数値型
計算もパックの方が早いらしいので基本的にPACKEDでいいと思います。
詳しくは書きませんがゾーンの方が無駄に記憶域を消費するそうです。
使い分けはあまり考えていませんが、数字をコードのように使うのならゾーンがいいそうです。
DCL-S QUANTITY PACKED(8 : 0) //パック小数点無し DCL-S PRICE PACKED(8 : 2) //パック小数点2桁 DCD-S NUMBER ZONED(6 : 0) //ゾーン //代入例 QUANTITY = 5; PRICE = 5000.22; NUMBER = 0126; //定かではない
標識、真偽値 IND
RPGIIIでは01から99しか無かったフラグですが、RPGLEでは名前を付けることが可能です。
何らかの終了フラグなどは下記のような名前にしたほうが分かりやすいはず。
DCL-S HOGE_END_FLG IND; //真偽値 //代入例 HOGE_END_FLG = *OFF; HOGE_END_FLG = *ON;
もちろん下記のようにIN77というフラグ名にしてもOKですが、解りにくいので標識のクセは治したほうが良さそうです。
DCL-S IN77 IND;
なお、RPGIII時代から*IN〇〇というフラグを使っていましたが、下記は全く違う意味です。
DCL-S IN77 IND; //IN77という名前の真偽値 DCL-S *IN77 IND; //IBMi従来の標識77(宣言不可)
ファンクションキーの打鍵、色変更などのDSPATR、サブファイルクリアなどDDSで必要とする標識は使わざるをえないので、それ以外はなるべく分かりやすい真偽値名に置き換えたほうが良いと思います。
パラメータを受け取る DCL-PI
いわゆるPLISTです。プログラムをコールするとき渡すパラメータです。
このように指定します。
DCL-PI *N; #PARAM CHAR(1); END-PI;
尚、下記のように定義することはできないみたい。
DCL-S #PARAM CHAR(1); DCL-PI *N; #PARAM; END-PI;
外部プログラム使用宣言 DCL-PR
RPG内から別のプログラムをキックする場合は、あらかじめ宣言する必要あるみたい。
RPGIIIなら何もせずロジック内で普通にCALLすればよかったのですが・・
尚、これはCALLする場合です。CHAINの場合は普通にF仕様書に書きます。
書き方とサンプルです。パラメータは適切なものを適切なサイズと型で指定します。
// 書き方 DCL-PR プログラム名 EXTPGM('プログラム名'); パラメーター END-PR; // Hogeプログラムを定義 DCL-PR HOGEPGM EXTPGM('HOGEPGM'); *N CHAR(1); *N CHAR(4); *N PACKED(6 : 1); END-PR;
データストラクチャ DCL-DS
データストラクチャーDSの指定方法です。
カラムをDSで切る
READしたファイルに含まれるカラムの郵便番号7ケタを3桁4桁に切る。
DCL-DS POSTCODE; POST_FRONT CHAR(3) POS(1); POST_REAR CHAR(4); END-DS;
カラムをDSでつなげる
2つのカラムをDSでつなげる。POSで開始位置を決めるみたい。
TIKUとSIMEはテーブルにあるカラムなので変数や型宣言は不要。
DCL-DS *N; DATA CHAR(3) POS(1); //結合した結果 TIKU POS(1); //地区 SIME POS(3); //締め END-DS;
システムデータストラクチャー SDS
これを使えばプログラム実行時のシステム情報を取得できる。
たとえばプログラムIDやワークステーションIDなど。
DCL-DS *N PSDS; PGID CHAR(10) POS(1); //プログラムID WSID CHAR(10) POS(244); //ワークステーションID END-DS;
PGIDやWSIDという変数名は何でもいい。型や文字数やPOSの値が重要。
要するにSDSという大きな変数があってその中の何桁から何桁目にシステム値が入っているということ。
なのでDSのPOSで桁を指定する。RPGIVの場合はSDSだが、フリーフォームの場合はPSDSにする。
修飾名が無い場合は*Nとする・・らしい知らんけど。ま、これで動くから良しとする。
命令コード
四則演算や条件文IFやFORやREADなどの命令文です。
わかりやすく例文で書いておきます。
四則演算
Web系言語などで使える剰余演算の「%」は使えないので、%REM関数を使います。
**FREE DCL-S ADD INT(5); //加算 DCL-S SUB INT(5); //減算 DCL-S MULT INT(5); //乗算 DCL-S DIV INT(5); //除算 DCL-S REM INT(5); //剰余算 ADD = 19 + 4; SUB = 19 - 4; MULT = 19 * 4; DIV = 19 / 4; REM = %REM(19 : 4); DSPLY ADD; //23 DSPLY SUB; //15 DSPLY MULT; //76 DSPLY DIV; //4 DSPLY REM; //3 *INLR = *ON; RETURN;
IF文とFOR文
プログラミングの初心者問題であるFizzBuzzを例にします。
FizzBuzzとは、1・2・3・4・5・・・とカウントしていき
- 3で割り切れるときは「Fizz」
- 5で割り切れるときは「Buzz」
- 両方で割り切れるときは「FizzBuzz」
- それ以外は「その値」
を書き出すというプログラミング初心者にやらせる問題です。
これでFOR文とIF文(ELSEIF、ELSE、AND)の書き方が一気にわかりますね。
**FREE DCL-S I INT(5); FOR I = 1 TO 20; IF %REM(I : 5) = 0 AND %REM(I : 3) = 0; DSPLY 'FIZZBUZZ'; ELSEIF %REM(I : 5) = 0; DSPLY 'BUZZ'; ELSEIF %REM(I : 3) = 0; DSPLY 'FIZZ'; ELSE; DSPLY I; ENDIF; ENDFOR; *INLR = *ON; RETURN;
基本的に一般的なプログラミング言語と同じ感じです。VBAに近いかも。
剰余算は前述のとおり%REMを使用しています。各所にセミコロンがあるのがポイントです。
DOUとREADとCHAIN
顧客リストをREADして、日本郵便のデータ(郵便番号と住所の紐づけ)をCHAINして、顧客名と住所を表示するプログラムです。
これでDo_UntilとReadとChainの書き方と、見つかったかどうかの判定方法がわかるはず。
DCL-F CUSTOMER DISK KEYED USAGE(*INPUT); //顧客リスト DCL-F JAPANPOST DISK KEYED USAGE(*INPUT); //郵便番号と住所の紐付けデータ DCL-S DATA VARCHAR(20); //ワーク DOU %EOF(CUSTOMER); //EOFまで読む READ CUSTOMER; //READ IF NOT %EOF(CUSTOMER); //EOFでなければ CHAIN (POST) JAPANPOST; //郵便番号でCHAIN IF %FOUND(JAPANPOST); //直前のCHAINを判定 WRK = NAME + ':' + ADDRESS; //顧客名と:と住所を合わせて DSPLY WRK; //画面上に吐き出す ENDIF; ENDIF; ENDDO; *INLR = *ON; //終了処理 RETURN;
%EOFはファイルの終わりを判定する関数です。
EOFでなければ処理をする場合は、NOT %EOFとする。
%FOUNDは見つかったらONを返す関数です。
引数にはCHAINしたファイル名を入れてもいいですが、直前のCHAINを判定してくれるので、この場合は何も入れなくてもOKです。
詳しく知りませんがLOOKUPなども%FOUNDで判定するのだと思います。
SETLLとREADE
1対多になるオーダー番号と項番号がある受注情報に対してSETLLとREADEすると仮定。
DCL-F ORDERFILE DISK KEYED USAGE(*INPUT); //受注ファイル DCL-S NO PACKED(5 : 0); //受注番号 DCL-S KOU PACKED(3 : 0); //項番号 NO = 15350; KOU = 1; SETLL (NO : KOU) ORDERFILE; DOU %EOF(ORDERFILE); READE (NO : KOU) ORDERFILE; IF NOT %EOF(ORDERFILE); DSPLY COLUMN; ENDIF; ENDDO;
対象ファイルのキーが複数でも、SETLLなので1つのキーでSETLL/READEすることはもちろん可能。
SQLRPGの書き方
別記事にしました。よろしければご覧ください。
その他
一旦記事はこれで完成です(2021年6月5日)
その他の気付きがあれば追記するかもです。
演算命令でわからないとき
RDi上で「Ctrl」+「Space」を押せば演算命令の一覧が表示されます。
必要な命令を選ぶと、使い方が載ったポップアップも表示される。
READE search-arg | *KEY file-name | record-name {data-structure}
argは実引数の意味。search-argは検索文字という意味。|はor(または)の意味。
上記の場合は「検索文字」または「キー」と「ファイル名」または「レコード様式名」ということ。
プログラム開始時に走らせるサブルーチン *INZSR
フリーフォーム関係ないけど備忘録。
下記のように書けばメインルーチンの前に走らせてくれるみたい。知らなかったです。
BEGSR *INZSR; //初期処理 ENDSR;
挿入モードをデフォルトにする
RDiを開いたらカーソルの形が■になっているので|にする方法を捜しましたが、現時点ではできないそうです。
2016年時点ですが外人さんがIBMコミュニティで質問している記事がありました。
コメント