HLASM Toolkit Feature
「構造化プログラミング(SP:Structured Programming)マクロ」
SPマクロは、アセンブラーのソース・コードでDO、IF、SELECTといった構造化プログラミング用記述を行う為のマクロ命令です。アセンブラー・プログラムでは分岐命令は当たり前のように使いますが、これらの構造化マクロを使うことで分岐命令で飛びまくるようなコードを書きにくくして、他の言語同様の論理展開を可能にするものです(アセンブラー用の構造化マクロでも実際に生成されるコードでは分岐命令は多用されるが、ソース・コード上に現れないように隠してしまうコード記述ができる)。ユーザーによってはアセンブラー言語のアプリケーション・プログラムでも、構造化コードでの記述が標準化されている場合があります。SPマクロの存在を知っていれば、業務で携わるようなことになった場合でも慌てなくて済むかも知れません。元々はIMSやJES328Xのライブラリーに入っていたものと聞いていますが、現在では高水準アセンブラーのツールキット・フィーチャーの1機能として提供されています(*1)。
構造化セット | 含まれるステートメント(マクロ)名 |
---|---|
IF | IF / ELSE / ELSEIF / ENDIF |
DO | DO / DOEXIT / ITERATE / ASMLEAVE / ENDDO |
CASE | CASENTRY / CASE / ENDCASE |
SEARCH | STRTSRCH / EXITIF / ORELSE / ENDLOOP / ENDSRCH |
SELECT | SELECT / WHEN / OTHRWISE / ENDSEL |
SPマクロによる構造化はソース・コード上での構造化記述を可能にするだけで、アセンブルの結果として生成される機械語コードでは比較や分岐命令が使用されます。プログラマーが直接書かなくなるだけです。構造化ステートメントの機能を実現することを優先していて、実行効率の面では必ずしも最適な機械語コードになるとは限りません。また、他言語と異なりIFやDOの条件式では、比較用の命令や成立条件を機械命令のニーモニックで書かねばならないことも多く、「機械命令を覚えなくてもプログラムが書ける」というものでもありません。性能面でのコード最適化やコード記述の省力化に寄与するものではないですが、「ソース・コード上での論理表現を統一化できることを優先したい」という場合には有用でしょう。
ドキュメントとマクロ・ライブラリー
- High Level Assembler for z/OS & z/VM & z/VSE Toolkit Feature User’s Guide(クリックするとIBM Documentationのサイトにリンクします)
- HLA.SASMMAC2
第2章に「Chapter 2. Using structured programming macros」として解説されています。
構造化マクロ定義済みメンバー「ASMMSP」が入っているライブラリーです。このデータセットをアセンブル時のSYSLIB DDに連結します。
1 2 3 4 5 6 |
//ASMEX3A EXEC ASMACL,COND.L=(8,LE,C), // PARM.C='ASA,TEST,US(WARN(11))',PARM.L='MAP,LET,LIST,TEST' //C.SYSLIB DD // DD DISP=SHR,DSN=HLA.SASMMAC2 <=== SP MACRO LIBRARY //C.SYSIN DD * : |
SPマクロを使うプログラム・ソースの冒頭でASMMSPをCOPY命令で読み込んでおく。
SPマクロ(抜粋)
IF、ELSE、ENDIF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
IF 条件式1[,OR|AND,条件式2][,OR|AND,条件式3]・・・ENDIF : [ELSE] [ELSEIF] : ENDIF IF (compare instruction,operand1,condition,operand2) 又は IF (other instruction,operand1,operand2,condition) THENの時に実行する命令1 THENの時に実行する命令2 THENの時に実行する命令3 : THENの時に実行する命令n ELSE ELSEの時に実行する命令1 ELSEの時に実行する命令2 ELSEの時に実行する命令3 : ELSEの時に実行する命令n ELSEIF ELSEIFの時に実行する命令1 ELSEIFの時に実行する命令2 ELSEIFの時に実行する命令3 : ELSEIFの時に実行する命令n ENDIF |
条件式の記述パターンは複数あり、上記は基本的なもの。その他についてはマニュアルを参照。
【記述例】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
IF (CLI,BYTE1,EQ,C'A') THEN (THENはただのコメント:パラメーターの後ろに空白を置けば行末迄コメント) LHI R0,123 (THENの時に実行する命令) AHI R0,456 (THENの時に実行する命令) ELSE LHI R0,-789 (ELSEの時に実行する命令) MHI R0,123 (ELSEの時に実行する命令) ENDIF (IF~THEN~ELSEの論理ブロックの終了を示す:他言語と違い記述必須) ST R0,RESULT (どちらであっても実行する命令) IF (CLI,BYTE1,EQ,C'A'),AND,(TM,FLAG1,X'02',Z) THEN (比較命令とTM等の比較以外の命令ではオペランドと条件の書き順が変わるので注意) LHI R0,123 (THENの時に実行する命令) AHI R0,456 (THENの時に実行する命令) ELSEIF (CLC,CHARS(3),EQ,=C'ABC') LHI R0,-789 (ELSEの時、追加条件を満たせば実行する命令) MHI R0,123 (ELSEの時、追加条件を満たせば実行する命令) ENDIF ST R0,RESULT (何れであっても実行する命令) IF (CLI,BYTE1,EQ,C'A'),AND,(TM,FLAG1,X'40',O), + OR,(CLC,CHARS,NE,=C'ABCDEFGH') THEN LHI R0,123 (THENの時に実行する命令) AHI R0,456 (THENの時に実行する命令) ELSE LHI R0,-789 (ELSEの時に実行する命令) MHI R0,123 (ELSEの時に実行する命令) ELSEIF (CLC,CHARS(3),EQ,=C'ABC') LHI R0,456 (THENの時、追加条件を満たせば実行する命令) AHI R0,-321 (THENの時、追加条件を満たせば実行する命令) ENDIF ST R0,RESULT (何れであっても実行する命令) |
DO、ENDDO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
DO 条件式 : ENDDO DO FROM=(reg,counts) (回数ループ:指定した回数だけループする) 実行する命令1 実行する命令2 実行する命令3 : 実行する命令n ENDDO DO WHILE|UNTIL=(条件式) (条件ループ:条件を満たしている間又は満たす迄ループする) 実行する命令1 実行する命令2 実行する命令3 : 実行する命令n ENDDO DO INF (無限ループ:EOD等ループから抜けるイベントが発生しないと無限ループに陥る) 実行する命令1 実行する命令2 [ITERATE] (ENDDO迄スキップする) [DOEXIT [条件式]] (DOループから抜ける) 実行する命令3 : 実行する命令n ENDDO |
条件式の記述パターンはIFと同じ。複合条件も記述できる。
【記述例】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
DO FROM=(R3,COUNT) LOOP BY COUNT(回数格納領域名) AHI R6,123 MHI R6,3 ENDDO DO FROM=(R3,100) LOOP BY COUNT(即値) AHI R6,123 MHI R6,3 ENDDO DO WHILE=(CLI,BYTE1,NE,C' ') LOOP BY CONDITION AHI R6,123 MHI R6,3 ENDDO DO UNTIL=(TM,FLAG1,X'01',O, LOOP BY COMPOUND CONDITION + OR,CLI,BYTE1,NE,C' ') AHI R6,123 MHI R6,3 ENDDO DO INF INFINITE LOOP LHI R0,123 MHI R6,3 ENDDO DO ONCE TIME LHI R0,123 MHI R6,3 ENDDO |
SELECT、WHEN、OTHRWISE、ENDSEL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
SELECT 命令,領域,条件 WHEN 値1 領域=値1の時に実行する命令1 領域=値1の時に実行する命令2 : 領域=値1の時に実行する命令n WHEN (値2[,値3,値4]) 領域=値2か値3か値4の時に実行する命令1 領域=値2か値3か値4の時に実行する命令2 : 領域=値2か値3か値4の時に実行する命令n OTHRWISE 領域内容が何れでもない時に実行する命令1 領域内容が何れでもない時に実行する命令2 : 領域内容が何れでもない時に実行する命令n ENDSEL |
【記述例】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
SELECT CLI,BYTE1,EQ WHEN C'A' AHI R6,123 (BYTE1がC'A'の時に実行する命令) MHI R6,3 (BYTE1がC'A'の時に実行する命令) WHEN (C'B',C'C',X'88') AHI R6,456 (BYTE1がC'B'orC'C'orX'88'の時に実行する命令) MHI R6,4 (BYTE1がC'B'orC'C'orX'88'の時に実行する命令) OTHRWISE AHI R6,789 (何れでもない時に実行する命令) MHI R6,5 (何れでもない時に実行する命令) ENDSEL SELECT TM,FLAG1,O WHEN X'80' AHI R6,123 (FLAG1のビットx80が1(on)の時に実行する命令) MHI R6,3 (FLAG1のビットx80が1(on)の時に実行する命令) WHEN (X'40',X'20') AHI R6,456 (FLAG1のビットx80又はx20が1(on)の時に実行する命令) MHI R6,4 (FLAG1のビットx80又はx20が1(on)の時に実行する命令) OTHRWISE AHI R6,789 (何れでもない時に実行する命令) MHI R6,5 (何れでもない時に実行する命令) ENDSEL SELECT CHI,R15,EQ WHEN 4 MVC MSG1,=CL5'RC=4' (GR15が4の時に実行する命令) WHEN 8 MVC MSG1,=CL5'RC=8' (GR15が8の時に実行する命令) WHEN 12 MVC MSG1,=CL5'RC=12' (GR15が12の時に実行する命令) ENDSEL |
SPコーディング例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
COPY ASMMSP Include SP-MACROS * *----------------------------------* * * BUILD ADDRESS SPACE LIST TABLE * * *----------------------------------* L R3,CVTPTR LOAD CVT ADDRESS L R4,CVTASVT-CVTMAP(,R3) LOAD ASVT ADDRESS USING ASVT,R4 DEFINE ASVT BASE REG=4 USING ASCB,R5 DEFINE ASCB BASE REG=5 LA R6,ASTABLE LOCATE TO ASTABLE 1ST ENTRY USING ASTABLE,R6 DEFINE ASTABLE BASE REG=6 DO FROM=(R3,ASVTMAXU) LOOP FOR MAXIMUM ASIDS IF (TM,ASVTENTY,ASVTAVAL,NO) IS HERE ASSIGNED ASCB ? L R5,ASVTENTY LOAD CURRENT ASCB LA R4,4(,R4) LOCATE NEXT ASCB ENTRY IN ASVT L R1,ASCBJBNI LOAD BATCH JOBNAME POINTER ELSE LA R4,4(,R4) LOCATE NEXT ASCB ENTRY IN ASVT ITERATE , ESCAPE FROM LOOP ENDIF IF (LTR,R1,R1,Z) ACTIVE BATCH JOB ? L R1,ASCBJBNS NO, LOAD STC/TSO NAME POINTER ENDIF MVC JOBNAME,0(R1) MOVE JOBNAME MVC ASID,ASCBASID MOVE ASID L R1,ASCBASSB LOAD ASSB ADDRESS L R1,ASSBJSAB-ASSB(,R1) LOAD JSAB ADDRESS USING JSAB,R2 DEFINE JSAB BASE REG=2 IF (LTR,R2,R1,NZ) HAVE JSAB ? IF (TM,JSABFLG1,JSABNVAL,O) INVALID ONE ? L R2,JSABNEXT YES, LOAD ORIGIN JSAB ADDRESS ELSE MVC JOBID,JSABJBID NO, MOVE JES JOBID ENDIF ENDIF DROP R2 FORGET JSAB LA R6,LNGENTRY(,R6) LOCATE NEXT ASTABLE ENTRY ENDDO , DROP R4,R5,R6 FORGET ASVT, ASCB, ASTABLE * *----------------------------------* * * READ RECORD FROM PS DATASET * * *----------------------------------* OPEN (DCBSYSPR,OUTPUT) OPEN THE SYSPRINT DATASET OPEN (DCBSYSIN,INPUT) OPEN THE SYSIN DATASET DO INF (LOOP FOR INFINITY) GET DCBSYSIN,RECORD READ NEXT SYSIN CARD PUT DCBSYSPR,RECORD COPY IT TO SYSPRINT DATASET ENDDO EODPROC DS 0H CLOSE (DCBSYSIN) CLOSE THE SYSIN DATASET CLOSE (DCBSYSPR) CLOSE THE SYSPRINT DATASET |