FOR
Synopsis
FOR var=forparameter { code } F var=forparameter { code } FOR var=forparameter1,forparameter2,... { code } F var=forparameter1,forparameter2,... { code }
forparameter には、以下を指定できます。
expr start:increment start:increment:end
引数
var | オプション — FOR コマンドで初期化されるローカル変数またはインスタンス変数。これは、一般に、code ブロックが実行されるたびにインクリメントされる数値のカウンタです。 |
expr | オプション — code ブロックを実行する前に、var に割り当てられる値。単一の値、または値のコンマ区切りリストになります。 |
start | オプション — code ブロックの最初の実行前に、var に割り当てられる数値。increment および (オプションの) end と併用して、FOR ループの複数の反復を制御します。 |
increment | オプション — FOR ループの各反復後の var のインクリメント (またはデクリメント) に使用される数値。 |
end | オプション — FOR ループを終了するために使用される数値。ループ処理は、インクリメントされた var が end 以上になったときに終了します。 |
code | 中括弧で囲まれた ObjectScript コマンドのブロックです。 |
概要
FOR はブロック型のコマンドです。一般に、カウンタと、中括弧で囲まれた実行可能なコード・ブロックで構成されます。このコード・ブロックが実行される回数は、カウンタで決定されます。このカウンタは、各ループの先頭でテストされます。あまり一般的ではありませんが、インクリメントするカウンタを指定しない FOR コマンドもあります。これは、引数なし (終了するまでの無限ループ) にすることも、引数として式を指定する (1 回のループ) こともできます。
FOR コマンドには、以下の 2 つの基本的な形式があります。
引数なしの FOR
引数なしの FOR は、コード・ブロック内のコマンドで終了するまで、無限にループ・コード・ブロックを実行します。Caché は、QUIT、RETURN、またはループから抜け出す GOTO コマンドに遭遇するまで、中括弧内のコマンドを繰り返し実行します。以下の例では、x = 3 のときにループを終了します。
SET x=8
FOR { WRITE "Running loop x=",x,!
SET x=x-1
QUIT:x=3
}
WRITE "Next command after FOR code block"
以下の例に示すように、エラーでも FOR ループから抜け出します。この FOR ループは、0 による除算エラーで終了されます。このエラーは、CATCH ブロックで捕捉されます。
TRY {
SET x=8
FOR { SET y=4/x
WRITE "Running loop 4/",x,"=",y,!
SET x=x-1
}
WRITE "Next command after FOR code block"
}
CATCH exp {
WRITE !,"this is the exception handler",!
IF 1=exp.%IsA("%Exception.SystemException") {
WRITE "Name: ",$ZCVT(exp.Name,"O","HTML"),!
WRITE "Location: ",exp.Location,!
WRITE "Code: ",exp.Code
}
ELSE {WRITE "Unexpected exception type",! }
RETURN
}
引数付きの FOR
FOR が実行する動作は、使用する引数形式によって異なります。
FOR var=expr は、code ブロックを 1 回実行し、var を expr の値に設定します。FOR var=expr1,expr2...,exprN は、code ブロックを N 回実行し、ループごとに var を連続する expr のそれぞれの値に設定します。
FOR var=start:increment は、code ブロックを終了するまで無限に実行します。最初の反復で、Caché は var を start の値に設定します。FOR コマンドが実行されるたびに、指定された increment の値で var の値がインクリメントされます。Caché は、code ブロック内で QUIT、RETURN、または GOTO コマンドに遭遇するまで繰り返します。
FOR var=start:increment:end は、var を start の値に設定します。その後 Caché は、以下のテーブルに記述されている条件に基づいて code ブロックを実行します。
increment が正の場合 | increment が負の場合 |
---|---|
start > end の場合は code ブロックを実行しません。var が end 以上の場合、または Caché が QUIT、RETURN、または GOTO コマンドに遭遇した場合にループが終了します。 | start < end の場合は、code ブロックを実行しません。var が end 以下の場合、または Caché が QUIT、RETURN、または GOTO コマンドに遭遇した場合にループが終了します。 |
ループの実行を開始するとき、Caché は start、increment、end の各値を評価します。ループ内でこれらの値が変更されてもそれは無視され、ループ実行回数に影響を与えません。
ループの終了時、var にはループの最後の実行結果によるインクリメントを反映する値が格納されています。ただし、var が end で指定された最大値を超えることはありません。
FOR ループには、複数のコンマ区切り forparameter 引数を含めることができます。しかし、var 引数は 1 つしか含めることができません。有効な構文は、以下のとおりです。
FOR var=start1:increment1:end1,start2:increment2:end2
引数
var
var 引数には、単純なローカル変数、添え字付きローカル変数、またはインスタンス変数 (i%property など) を指定できます。FOR コマンドは、この変数を初期化 (または設定) するため、FOR コマンドの前に var を定義する必要はありません。
-
ループ・カウンタ構文の使用時には、var は、FOR ループの現在のカウンタ値を保持するローカル変数になります。初期値として、start で指定された数値が格納されます。その後、FOR ループの反復ごとに increment を使用して値が再計算されます。
-
var=expr 構文の使用時には、ローカル変数は expr 値に初期化されます。
expr
ループ・コマンドを実行する前に Caché が var に割り当てる値です。expr の値は、リテラルまたは有効な式として指定できます。expr は単一の値、または値のコンマ区切りリストになります。単一の値の場合、Caché は、FOR ループを 1 回実行し、この var 値をコード・ブロックに提供します。値のコンマ区切りリストの場合、Caché は、値の数と同じ回数分 FOR ループを実行し、各ループで値を var に代入して、この var 値をコード・ブロックに提供します。
start
FOR ループの最初の反復時に、Caché が var に割り当てる数値です。start 値は、リテラルあるいは有効な式として指定されます。Caché は start をその数値に対して評価します。数値以外の start 値は 0 として評価されます。
increment
FOR ループの各反復後に、Caché が var をインクリメントするために使用する数値です。start を指定している場合、increment は必須です。increment 値は、リテラルまたは有効な式として指定されます。Caché は increment をその数値に対して評価します。increment には整数値または小数値を指定できます。また、正の数 (インクリメント)、負の数 (ディクリメント) のどちらでもかまいません。
increment の値が 0 または非数値の場合、FOR ループは、終了するまで無限に繰り返されることになります。これは、end=0 の場合にも当てはまります。ただし、start が end より大きいときには、ループは実行されず、0 の increment は無視されます。
end
FOR ループを終了させるために使用する数値です。var が、この値以上になると、FOR ループは、最後の 1 回を実行してから終了します。end 値は、リテラルあるいは任意の有効な式として指定されます。Caché は end をその数値に対して評価します。
start = end の場合、FOR ループは 1 回 だけ実行されます。start が end より大きく、increment が正の整数の場合は、FOR ループは実行されません。
code
中括弧で囲まれた、1 つ以上の ObjectScript コマンドのブロックです。この実行可能なコード・ブロックには、複数のコマンド、ラベル、コメント、改行、インデント、および空白スペースを、必要に応じて含めることができます。FOR コマンドが終了すると、閉じ中括弧の後の次のコマンドが続けて実行されます。
開き中括弧や閉じ中括弧は、1 行で独立して記述するか、コマンドと同じ行に記述できます。開き中括弧や閉じ中括弧は、列 1 に記述してもかまいませんが、お勧めはできません。推奨されるプログラミング手法として、入れ子になったコード・ブロックの開始と終了を示すために、中括弧はインデントするようにしてください。開き中括弧の前後に空白を入れる必要はありません。閉じ中括弧の前に空白を入れる必要はありません。引数のないコマンドに続く中括弧の場合も同様です。中括弧の空白に関する唯一の要件は、閉じ中括弧とその後のコマンドを、スペース、タブ、または改行で区切る必要があるということです。
FOR ループの終了
FOR ループは、QUIT、RETURN、CONTINUE、または GOTO を発行すると終了できます。
-
QUIT は、現在の FOR ブロック構造を終了します。そのため、FOR ブロック内の QUIT では、Caché は FOR ブロックの後にある次の行で実行を開始します。QUIT は、現在の FOR ブロックを終了するだけです。FOR ブロックが別の FOR ブロック内 (または他のブロック構造内) で入れ子になっている場合は、QUIT は内部の FOR ブロックを終了して外側のブロック構造に移動します。
FOR ブロック (および他のブロック構造) 内の QUIT の動作は、ブロック構造内にない場合の QUIT の動作とは異なります。これらのブロック構造のいずれかの外側にある QUIT は、現在のコード・ブロックではなく、現在のルーチンを終了します。詳細については、コマンドのリファレンス・ページの "QUIT" コマンドを参照してください。
QUIT は、QUIT が FOR ブロック内にある場合に限り FOR ブロックを終了します。FOR ループがサブルーチンを呼び出している場合は、サブルーチン内で QUIT を発行すると、呼び出した FOR ループではなくサブルーチンを終了します。
-
RETURN は、FOR ブロック構造内から発行されたかどうかには関係なく、現在のルーチンを終了します。
-
CONTINUE は、現在の FOR ループを終了します。これにより、実行が即座に FOR コマンドに戻ります。次に FOR コマンドは引数をインクリメントして評価し、その評価を基にしてコード・ブロック・ループを再実行するかどうかを決定します。したがって、CONTINUE コマンドの実行にはコード・ブロックの終了中括弧に到達するのとまったく同じ効果があります。
-
GOTO は、制御を FOR コード・ブロックの外側に移動することで、現在の FOR ブロック構造を終了できます。FOR ループは、FOR コード・ブロック内に制御を渡す GOTO では終了されません。
例
引数なしのFOR
以下の例では、引数なしの FOR を示しています。ユーザは、後の DO コマンドで Calc サブルーチンへ渡す数の入力を繰り返し求められます。FOR ループは、ユーザが NULL 文字列を入力する (数値を入力せずに [Enter] を押す) と QUIT コマンドを実行し、終了します。
Mainloop
FOR {
READ !,"Number: ",num
QUIT:num=""
DO Calc(num)
}
Calc(a)
WRITE !,"The number squared is ",a*a
QUIT
FOR var=expr の使用
var=expr を指定すると、Caché は、expr のコンマで区切られた値の数と同じ回数分 FOR ループを実行します。expr の値は、リテラルまたは有効な式です。式を指定する場合、その式は単一の値に評価される必要があります。
以下の例では、FOR コマンドでコード・ブロックを 1 回実行します。num の値には 4 が設定されています。これにより、数値の 12 を書き出します。
Loop
SET val=4
FOR num=val {
WRITE num*3,!
}
WRITE "Next command after FOR code block"
以下の例では、FOR コマンドでコード・ブロックを 1 回実行します。alpha(7) の値には “abcdefg” が設定されています。
Loop
SET val="abc"
FOR alpha(7)=val_"defg" {
WRITE alpha(7),!
}
WRITE "Next command after FOR code block"
以下の例では、FOR コマンドでコード・ブロックを 8 回実行します。連続する各完全数がコード・ブロックに提供されます。
FOR pnum=6,28,496,8128,33550336,8589869056,137438691328,2305843008139952128 {
WRITE "Perfect number ",pnum
SET rp=$REVERSE(pnum)
IF 54=$ASCII(rp,1) {
WRITE " ends in 6",! }
ELSEIF 56=$ASCII(rp,1),50=$ASCII(rp,2) {
WRITE " ends in 28",! }
ELSE {WRITE " is something unknown to mathematics",! }
}
var=start:increment:end の使用
引数 start、increment、end は、それぞれ初期値、増分値、終値を指定します。これら 3 つの値は、数値として評価されます。これは整数または実数、正または負の値です。文字列値を提供する場合は、ループの開始時に同等の数値に変換されます。
Caché は最初にループに入ったときに、start の値を var に割り当てて、var の値と end の値を比較します。var の値が end の値より小さい (increment の値が負のときには、この値より大きい) 場合、Caché はループ・コマンドを実行します。その後 increment の値を使用して、var の値を更新します。(負の increment が使用されている場合、var の値はデクリメントされます。)
ループの実行は、var の値が end の値を上回るまで (または Caché が QUIT、RETURN、または GOTO に遭遇するまで) 続けられます。この時点で、var が end を超えないようにするために、Caché は変数の割り当てを抑制して、ループの実行が終了しないようにします。var 値が end 値と等しい場合、Caché は FOR ループの最後の 1 回を実行してからループを終了します。
以下のコードは、最後の文字を除く string1 のすべての文字に WRITE コマンドの実行を繰り返し、順番に出力します。end 値はlen-1 として指定されているので、最後の文字は出力されません。これは、テストがループのトップで実行され、そのループは変数値 (index) が end 値 (len-1) を (同等ではなく) 超えるときに終了するからです。
Stringwriteloop
SET string1="123 Primrose Path"
SET len=$LENGTH(string1)
FOR index=1:1:len-1 {
WRITE $EXTRACT(string1,index)
}
FOR var=start:increment の使用
この FOR コマンドの形式には、end 値がありません。ループを終了させるための QUIT、RETURN、または GOTO コマンドを含む必要があります。
start と increment の値は、数値として評価されます。これは整数または実数、正または負の値です。文字列値の場合は、ループの開始時に同等の数値に変換されます。ループの実行を開始するとき、Caché は start および increment の値を評価します。ループ内でこれらの値が変更されても、それは無視されます。
Caché は最初にループに入ったときに、start の値を var に割り当てて、ループ・コマンドを実行します。その後 increment の値を使用して、var の値を更新します。(負の increment が使用されている場合、var の値はデクリメントされます。)Caché は QUIT、RETURN、または GOTO コマンドに遭遇するまでループの実行を繰り返します。
以下の例では、start:increment 構文を使用して、桁数が 3 桁未満の 7 の倍数をすべて返します。
FOR i(1)=0:7 {
QUIT:$LENGTH(i(1))=3
WRITE "multiple of 7 = ",i(1),! }
以下の例では、start:increment 構文を使用して、ユーザが提供した一連の数値の平均を計算します。ユーザが NULL 文字列を入力したとき (つまり、数値を入力せずに [Enter] を押したとき) にループを終了するため、後置条件 QUIT が含まれています。後置条件式 (num="") が True と評価されると、Caché は QUIT を実行し、ループを終了します。
ループ・カウンタ (変数 i) は、入力された数字の数を記録するために使用されます。i は、0 に初期化されます。これは、ユーザの数値入力後にカウンタがインクリメントされるためです。Caché は、この最後の実行の後、ループを終了します。ループが終了された後、平均を計算するため、SET コマンドは (ローカル変数として) i を参照します。
Averageloop
SET sum=0
FOR i=0:1 {
READ !,"Number: ",num
QUIT:num=""
SET sum=sum+num
}
SET average=sum/i
複数の forparameter を持つ FOR を使用する
FOR コマンドには、1 つの var = 引数しか含めることができませんが、forparameter 引数は、コンマ区切りリストとして指定することで複数含めることができます。例えば、構文 var=expr1,expr2,expr3 により、code ブロックは、実行ごとに異なる var の値で 3 回実行されます。
これらの forparameter 引数は、厳密に左から右の順序で評価され実行されます。そのため、1 つの forparameter でエラーが発生しても、それより前の forparameter の実行が妨げられることはありません。
1 つの FOR コマンドには、expr 構文と start:increment:end 構文の両方のタイプのパラメータ構文を含めることができます。
以下の例では、expr 構文と start:increment:end 構文を組み合わせています。2 つの forparameter はコンマで区切られています。初めて FOR を使用するとき、Caché は expr 構文を使用し、y の値と等しい x を使用して Test サブルーチンを呼び出します。2 度目 (およびそれ以降) の反復では、Caché は start:increment:end 構文を使用します。x を 1 に、その次は 2 を設定し、最後の繰り返しで x=10 となります。
Mainloop
SET y="beta"
FOR x=y,1:1:10 {
DO Test
}
QUIT
Test
WRITE !,"Running test number ",x
QUIT
以下に示すのは、3 つの forparameter 引数と、start:increment:end 構文が含まれているプログラム例です。これは i に 1 を設定し、1 から 10 までは、1 桁の数値を 1 単位でインクリメントします。2 番目の forparameter は i の値 10 を取り、100 までは 10 単位でインクリメントします。3 番目の forparameter は i の値 100 を取り、1000 までは 100 単位でインクリメントします。この例では、10 と 100 の値を繰り返しています。
FOR i=1:1:10,i:10:100,i:100:1000 {WRITE i,!}
以下の例は、前述の例と同じ操作を実行していますが、10 と 100 の値は繰り返していません。
FOR i=1:1:9,i+1:10:99,i+10:100:1000 {WRITE i,!}
引数なしの FOR のインクリメント
引数なしの FOR は FOR var=start:increment 形式と同じように動作します。唯一の違いは、ループ実行回数を記録する方法を提供していないことです。
以下の例は、前述のループ・カウンタ例を引数なしの FOR を使用して、どのように書き直しているかを表しています。i=i+1 がループ・カウンタの代わりです。
Average2loop
SET sum=0
SET i=0
FOR {
READ !,"Number: ",num QUIT:num=""
SET sum=sum+num,i=i+1
}
SET average=sum/i
WRITE !!,"Average is: ",average
QUIT
メモ
FOR および NEW
NEW コマンドは、var に影響を与える可能性があります。引数なしの NEW コマンドまたは排他的 NEW コマンド (特に var を除外しないもの) を FOR ループ本文内で発行すると、新しいフレーム・コンテキストで var が定義されない場合があります。
以下の例のように、var を含まない NEW コマンドは、FOR ループの実行に影響を与えません。
SET a=1,b=1,c=8
FOR i=a:b:c {
WRITE !,"count is ",i
NEW a,c
WRITE " loop"
NEW (i)
WRITE " again"
}
FOR および監視ポイント
FOR と組み合わせた監視ポイントの使用には制限があります。FOR コマンドの制御 (インデックス) 変数に対する監視ポイントを確立する場合、Caché は、各 FOR コマンド引数を最初に評価するときだけ、指定された監視ポイント・アクションをトリガします。この制約は、パフォーマンスの向上が目的です。
以下の例には、監視される変数 x に対して、3 種類の FOR コマンド引数が含まれています。1 つは初期値、増分値、制限 (最終値) を持つ値域、もう 1 つは単一の値、そしてもう 1 つは初期値、増分値を持ち、制限を持たない値域です。x の初期値が 1、20、50 のときに、ブレークが実行されます。
USER>ZBREAK *x
USER>FOR x=1:1:10,20,50:2 {SET t=x QUIT:x>69}
<BREAK>
USER 2f0>WRITE
x=1
USER 2f0>g
USER>FOR x=1:1:10,20,50:2 {SET t=x QUIT:x>69}
<BREAK>
USER 2f0>WRITE
t=10
x=20
USER> 2f0>g
USER>FOR x=1:1:10,20,50:2 {SET t=x QUIT:x>69}
<BREAK>
USER 2f0>WRITE
t=20
x=50
USER 2f0>g
USER>WRITE
t=70
x=70