前ページへプログラムの呼び出し システムと開発環境による制限次ページへ

第 3 章 拡張言語機能

この章では、COBOL の拡張開発機能のいくつかを紹介します。これらの機能を使用して開発上の一般的な問題を解決すると、アプリケーションのパフォーマンスを向上させることができます。アプリケーションのコードが、より単純になる場合もあります。

3.1 再帰ルーチン

再帰ルーチンとは自身を呼び出すルーチンのことです。再帰ルーチンは、次の各処理の最も一般的な実装手段です。

再帰ルーチンのかわりに同じルーチンを繰り返し記述することも可能ですが、再帰ルーチンを使用するとプログラムのロジックが単純になります。

3.1.1 再帰ルーチンの作成

Server Express システムでは、他のプログラム内でネストされておらず、局所記憶節 (LOCAL-STORAGE SECTION) を持つプログラムであれば、自身を再帰的に呼び出すことができます。プログラムの再帰的な呼び出しには、プログラム自身の PROGRAM-ID または入口点を使用します。

再帰ルーチンの呼び出しを行うと、そのたびにルーチンのインスタンスが 1 つ開始されます。再帰ルーチンの各インスタンスでは、ルーチン内で使用される一連のデータ項目を、それぞれ独自に確保する必要があります。そのための手段として Server Express システムで利用できるのが局所記憶節です。再帰ルーチンの新しいインスタンスを開始すると、局所記憶節で定義された一連のデータ項目が新たに初期化され、メモリに格納されます。これらのデータ項目は、対応するインスタンスが終了するとクリアされます。局所記憶節を持たないプログラムで再帰呼び出しを試みると、ランタイムエラーのメッセージが表示されます。

次に COBOL の再帰プログラムの具体例を示します。このコード例は、ある人物を頂点とする家系データの表を読み取り、家系内の各個人を次々にチェックして、子供を持たない個人の名前を表示します。

コード例 1 − 階層ツリーの再帰検索

この例では、family-tree 項目に家系データの表が格納されています (この表には、ある人物とその子孫に対応するエントリがあらかじめ登録されているものとします)。表の最初のエントリが、家系の最上位の人物に対応します。各エントリには該当する個人の名前のほか、その個人の第一子に関するエントリの表内での位置 (eldest-pointer 項目)、およびその個人の次の弟または妹に関するエントリの位置 (sibling-pointer 項目) が含まれています。子供を持たない個人の eldest-pointer の値、および弟や妹がいない個人の sibling-pointer の値は、それぞれ 99 に設定されています。

 identification division.
 program-id. family.
    . . .
 working-storage section.
 01  family-tree.
     03  individual    occurs 50.
         05  ind-name           pic x(30).
         05  eldest-pointer     pic 9(2).
         05  sibling-pointer    pic 9(2).

 local-storage section.
 01  tree-pointer      pic 9(2).

 linkage section.
 01  parent-pointer    pic 9(2).

 procedure division.
     move 1 to tree-pointer
     call "children" using tree-pointer
     stop run.

 entry "children" using parent-pointer
     move eldest-pointer(parent-pointer) to tree-pointer
     if tree-pointer = 99
       display ind-name(parent-pointer)
     else
       perform until tree-pointer = 99
         call "children" using tree-pointer
         move sibling-pointer(tree-pointer)to tree-pointer
       end-perform
     end-if.

子供を持たない個人のエントリが見つかると、children ルーチンはその個人名を表示して終了します。それ以外の場合には、children ルーチンはその個人の第一子から順次、すべての子供を対象に自身を再帰的に呼び出します。

コード例 2 − 再帰を利用した数学関数

この例では、入口点 factorl で識別されるルーチンによって、ユーザが入力した数値の階乗が計算されます。

 1 working-storage section.
 2 01 n             pic x(4) comp-x.
 3 01 factorial     pic x(4) comp-x.
 4 01 m             pic x(4) comp-x.
 5
 6 local-storage section.
 7
 8 procedure division.
 9     accept n
10     move 1 to factorial
11     call "factorl" using n
12     display "factorial of " n " is " factorial
13     stop run.
14
15 entry "factorl" using m.
16     if m < 1
17         move 1 to factorial
18     else
19         if m > 1
20             multiply m by factorial
21             subtract 1 from m
22             call "factorl" using m
23         end-if
24     end-if
25
26     exit program.

6 行め

local-storage section

再帰ルーチンは複数回にわたって呼び出される可能性があるため、1 つの呼び出しで使用するローカルデータを、同じコードの別の呼び出しから保護する必要があります。この保護機能を実現するのが局所記憶節です。ルーチンのインスタンスが生成されるたびに、局所記憶節で定義された一連のデータ項目が新たに初期化され、メモリ上に確保されます。局所記憶節を持たないプログラムで再帰呼び出しを試みると、ランタイムシステムエラーのメッセージが表示されます。

このコード例にはローカル記憶域を使用するデータ項目はありませんが、そのようなデータ項目の有無にかかわらず、再帰ルーチンには局所記憶節の宣言が必要です。

15 行め

entry 'factorl' using m.

再帰ルーチン factorl の入口点。プログラムの再帰的な呼び出しには、プログラム自身の PROGRAM-ID または入口点を使用します。

19-23 行め

if m > 1
    multiply m by factorial
    subtract 1 from m
    call 'factorl' using m
end-if

このループに再帰呼び出しが含まれています。

22 行め

call 'factorl' using m

再帰呼び出しを行う CALL 文。

3.2 STRING 文と部分参照

COBOL データ項目の内容は、STRING 文と部分参照という 2 通りの手段で操作できます。

次に示す 2 つの文の一方は STRING、もう一方は部分参照を使用して同じ処理を実装しています。どちらの文でも、street-address のサイズは 25 バイトです。

    string street-address delimited by size into print-rec
                          with pointer num-char
    move street-address to print-rec (num-char: 25)

STRING 文と部分参照の詳細については、『言語リファレンスを参照してください。

3.3 組み込み関数の活用

文内で組み込み関数を使用すると、その文の実行中にデータ項目に値を格納できます。

組み込み関数を使用した文の例を次に示します。

    compute x = function cos(y)

この文は、組み込み関数 cos の結果をデータ項目に入れます。cos によって、引数 y で渡した角度 (ラジアン単位) の逆余弦が計算され、x に入れます。

組み込み関数の詳細については、『言語リファレンスを参照してください。

組み込み関数の使用例

このサンプルファイル (intrins.cbl) は、プログラムで組み込み関数を利用するいくつかの方法を示しています。


注: 組み込み関数には、整数型関数、数字型関数、英数字型関数の 3 種類があります。このサンプルで使用している FACTORIAL は、数字型関数の 1 つです。ここで紹介しているコーディング方法が、他の種類の組み込み関数にも有効であるとは限りません。


  1$set mf noosvs ans85
  2
  3*********************************************************
  4* Copyright © 2002 Micro Focus International Limited. All rights reserved.          *
  5* このサンプルプログラム (以下、「本サンプル」と記する) *
  6* は Micro Focus 社製品のユーザ向けに提供されており、当該ユ  *
  7* ーザは自身のアプリケーションの一部として、本サンプル  *
  8* を使用、変更、および配布することができます。ただし、  *
  9* 本サンプルの著作権は Micro Focus 社に帰属します。          *
 10*********************************************************
 11
 12*********************************************************
 13*                                                       *
 14*                     INTRINS.CBL                       *
 15*                                                       *
 16*    このプログラムは、COBOL アプリケーションで組み込み   *
 17*    関数を使用するいくつかの方法を示しています。       *
 18*    具体的には、FACTORIAL 関数を使用して次の各処理を   *
 19*    実行します。                                       *
 20*                                                       *
 21*    1) 関数値をデータ項目に入れる。                    *
 22*    2) 関数を EVALUATE 文内でデータ項目                *
 23*       として使用する。                                *
 24*    3) 関数を IF 文内でデータ項目として                *
 25*       使用する。                                      *
 26*    4) 関数の引数として表要素 (固定) を                *
 27*       使用する。                                      *
 28*    5) 関数の引数として表要素 (可変) を                *
 29*       使用する。                                      *
 30*    6) 関数値を引数として関数に渡し、                  *
 31*       その戻り値をデータ項目に入れる。                *
 32*    7) 関数値を入れたデータ項目を COMPUTE              *
 33*       文で使用する。                                  *
 34*    8) 2 つの関数値の合計をデータ項目に                *
 35*       入れる。                                        *
 36*    9) 関数を PERFORM ... UNTIL 文の                   *
 37*       UNTIL 指定の条件として使用する。                *
 38*                                                       *
 39*                                                       *
 40*    組み込み関数の構文について理解するには、Animator     *
 41*    上で INTRINS を実行する方法が有効です。            *
 42*                                                       *
 43*    プログラムを次の指令でコンパイルします。           *
 44*                                                       *
 45*           COBOL INTRINS ANIM;                         *
 46*                                                       *
 47*    次のコマンドでアニメートします。                   *
 48*                                                       *
 49*           ANIMATE INTRINS                             *
 50*                                                       *
 51*                                                       *
  52*    詳細については、『言語リファレンス』と           *
 53*    『PC Programmer's Guide』を参照してください。      *
 54*                                                       *
 55*********************************************************
 56 working-storage section.
 57 78 fals value 0.
 58 78 tru  value 1.
 59
 60 01 true-or-false               pic 9(1).
 61
 62 01 factor                      pic s9(10).
 63
 64 01 val                         pic s9(10).
 65
 66 01 indx                        pic 9(5) comp-x.
 67
 68 01 arg                         pic 9(2) comp-x  value 5.
 69
 70 01 arr                                    value "40537".
 71     03 elem   occurs 5 times   pic 9.
 72
 73 procedure division.
 74
 75 main-section.
 76
 77*********************************************************
 78* 例 1 − 関数値をデータ項目に入れます。                *
 79*                                                       *
 80*********************************************************
 81
 82     compute factor = function factorial(0)
 83
 84*********************************************************
 85* 例 2 − 関数を EVALUATE 文のデータ項目                *
 86*         として使用します。                            *
 87*********************************************************
 88
 89     evaluate function integer(6.5)
 90      when 6
 91         move tru to true-or-false
 922      when other
 93         move fals to true-or-false
 94     end-evaluate
 95
 96*********************************************************
 97* 例 3 − 関数を IF 文のデータ項目として                *
 98*         使用します。                                  *
 99*********************************************************
100
101     if function integer (function factorial(arg)) = 120
102        then move tru to true-or-false
103     else
104         move fals to true-or-false
105     end-if
106
107*********************************************************
108* 例 4 − 関数の引数として表要素 (固定)                 *
109*         を使用します。                                *
110*********************************************************
111
112     compute factor = function factorial(elem(4))
113
114*********************************************************
115* 例 5 − 関数の引数として表要素 (可変)                 *
116*         を使用します。                                *
117*********************************************************
118
119       move 4 to indx
120       compute factor = function factorial(elem(indx))
121
122*********************************************************
123* 例 6 − 関数値を引数として関数に渡し、その戻り値を    *
124*         データ項目に入れます。                        *
125*********************************************************
126
127     compute factor = function factorial(
128                        function factorial(3))
129
130*********************************************************
131* 例 7 − 関数値を入れたデータ項目を COMPUTE            *
132*         文で使用します。                              *
133*********************************************************
134
135     compute val = function factorial(3) + 5
136
137*********************************************************
138* 例 8 − 2 つの関数値の合計をデータ項目に              *
139*         入れます。                                    *
140*********************************************************
141
142     compute val = function factorial(3) +
143                   function factorial(5)
144
145*********************************************************
146* 例 9 − 関数を PERFORM ... UNTIL 文                   *
147*         の UNTIL 指定の条件として使用します。         *
148*********************************************************
149
150     move 1 to indx
151     perform para-1 until function integer (function 
152           factorial(indx))  = 120
153     stop run.
154
155 para-1.
156     compute indx = indx + 1.

82 行め

 compute factor = function factorial(0)

組み込み関数の値をデータ項目に入れています。

89 〜 94 行め

 evaluate function integer(6.5)
  when 6
     move tru to true-or-false
  when other
     move fals to true-or-false
 end-evaluate

組み込み関数を EVALUATE 文のデータ項目として使用しています。

101 〜 105 行め

 if function integer (function factorial(arg)) = 120 then
     move tru to true-or-false
 else
     move fals to true-or-false
 end-if

組み込み関数を IF 文のデータ項目として使用しています。

数字型関数の結果は浮動小数点型であり、整数値は期待できません。この例では、IF 文の条件として整数を使用するため、integer 関数値を整数に変換しています。

112 行め

 compute factor = function factorial(elem(4))

組み込み関数の引数として、固定の配列要素を使用しています。

119 〜 120 行め

 move 4 to indx
 compute factor = function factorial(elem(indx))

組み込み関数の引数として、可変の表要素を使用しています。

127 〜 128 行め

 compute factor = function factorial (function factorial(3))

関数値を引数として関数に渡し、その戻り値をデータ項目に入れています。

135 行め

 compute val = function factorial(3) + 5

組み込み関数値を入れたデータ項目を COMPUTE 文で使用しています。

142 〜 143 行め

 compute val = function factorial(3) + function factorial(5)

2 つの組み込み関数値を合計し、その結果をデータ項目に入れています。

150 〜 156 行め

    move 1 to indx
    perform para-1 until function integer (function
         factorial(indx)) = 120
  stop run.

para-1.
    compute indx = indx + 1.

組み込み関数を PERFORM ... UNTIL 文の UNTIL 指定の条件として使用しています。

3.4 環境変数の操作

環境変数の操作には X/Open で定義された構文を使用します。DISPLAY ... UPON ENVIRONMENT-NAME 構文で環境変数の名前を ENVIRONMENT-NAME に格納し、続いて ACCEPT ... FROM ENVIRONMENT-VALUE 構文でその値を取得する、または DISPLAY ... UPON ENVIRONMENT-VALUE 構文で変更します。

これらの構文を使用すると、アプリケーションの実行中に環境変数の設定を動的に変更できます。

アプリケーションが使用する環境変数空間を X/Open の構文で読み取り、更新を行うと、物理ファイルに関連付けられた論理ファイルを変更できます。変更後のファイルには、COBOL の入出力構文でアクセスします。

アプリケーションの実行中に変更した環境変数の値は、そのアプリケーションが終了するとオリジナルの値に戻ります。アプリケーションの実行中には、最大 64 KB のメモリ領域を環境変数で使用できます (この値は上限値であり、実際の値は物理メモリの空き容量に左右されます)。

3.5 論理演算子 (BOOL 演算子) によるビット操作

COBOL による開発では、文字や項目、レコード、ファイルなどのほか、ビット単位でのデータ操作も必要になります。たとえば、次のような処理を行うアプリケーションにはビット操作が必要です。

Server Express ランタイムシステムの COBOL システムライブラリルーチンには論理演算ルーチンが含まれており、ビット操作を容易に実行できます。

各種の論理演算における入力ビットと出力ビットの関係を次に示します。

A 0 0 1 1
B 0 1 0 1

CBL_NOT (NOT A) 1 1 0 0
CBL_AND (A AND B) 0 0 0 0
CBL_OR (A OR B) 0 1 1 1
CBL_EQ (A EQ B) 1 0 0 1
CBL_XOR (A XOR B) 0 1 1 0
CBL_IMP (A IMP B) 1 1 0 1

たとえば、ビット A とビット B の CBL_EQ (論理等価) では、A と B がともに 0 (または 1) であれば結果ビットは 1、それ以外であれば 0 になります。

3.5.1 ビット操作ルーチンの呼び出し

論理演算ルーチンの構文を紹介する前に、構文で使用するデータ項目を次に示します。

データ項目
説明
source 入力データ項目。形式は任意。
target 出力データ項目。形式は任意。
length sourcetarget のバイト長。左端のバイトから開始される。

CBL_NOT 以外の各ルーチンは次の規則に従います。

すべての論理演算ルーチンは、次の規則に従います。


警告: sourcetargetlength の値より短い場合は、該当するデータ項目の直後のバイトが、不足するバイト数だけ処理されます。


CBL_NOT ルーチンは次の構文で使用します。

call "CBL_NOT" using target by value length
CBL_NOT データ項目の target の各ビットの論理否定。

その他のビット操作ルーチンの構文では、以下のとおりです。

  call "log_oper" using source target by value length

log_operには、次のいずれかを指定します。

CBL_AND 2 つのデータ項目の対応するビット間の論理積。
CBL_OR 2 つのデータ項目の対応するビット間の論理和。
CBL_EQ 2 つのデータ項目の対応するビット間の論理等価。
CBL_XOR 2 つのデータ項目の対応するビット間の排他的論理和。
CBL_IMP 2 つのデータ項目の対応するビット間の論理包含。

論理演算用のライブラリルーチンの詳細については、『ライブラリルーチン』の章を参照してください。


Copyright © 2002 Micro Focus International Limited. All rights reserved.
本書、ならびに使用されている固有の商標および商品名は国際著作権法で保護されています。

前ページへプログラムの呼び出し システムと開発環境による制限次ページへ