FOR I := A TO B DO == I := A;
<Statement Sequence> WHILE I < B DO
END <Statement Sequence>;
I := I + 1
IF I = B THEN
This set-up makes I come out of the loop with the value B.
An alternative, which is closer to the original intent of making
the "control variable" a LOCAL VARIABLE of the FOR-LOOP, is the
FOR I := A TO B DO = PFOR(A, B) where PFOR is declared as the procedure
<Statement Sequence> PROCEDURE PFOR( A, B : TypeName);
VAR I : TypeName;
Enclose the statements above
This does not make the troubles associated with I disappear, but it does
make the restrictions on I less ad-hoc.
_Programming_In_Modula-2_ essentially defines the for statement as the following
"FOR" ident ":=" expression1 "TO" expression2 [ "BY" ConstExpression ] "DO"
is equivalent to
ident ":=" expression1;
"WHILE" ident "<=" expression2 "DO"
[ident ":=" ident "+" ConstExpression (* if "BY" clause used *) |
ident ":=" ident "+ 1" (* if "BY" clause not used *) ]";"
(* ident := undefined *)
This means that you can replicate any FOR statement by a WHILE statement with
only two additional lines. Since this is also more explicit and flexible than
a FOR loop, I've started using the WHILE loop exclusively. I imagine Wirth
had similar reasons for dropping the FOR loop from Oberon.
If _Programming_in_Modula-2_ says this,...
well, it's a mistake, plain and simple.
FOR ch := 0C TO 255C DO
which supposedly is equivalent to
ch := 0C;
WHILE ch <= 255C DO
If you don't like playing with characters, try FOR i := -2^31 TO 2^31-1
(for 32 bit integers... i.e., MININT and MAXINT, or whatever they happen
to be called these days...).
The WHILE loop will bomb at runtime when it tries to increment 255C.
If you were doing this with integers, you won't be this lucky.
in C, for(ch=0;ch<=255;ch++) is an infinite loop when ch is an 8-bit char).
You really do need that second IF statement (or something similar;
if you don't like writing the statement body twice, then you have to
go through contortions like
ident := expression1;
IF ident <= expression2 THEN
IF ident = expression2 THEN EXIT END;
And even this general form fails miserably for
FOR ch := 0C TO 255C BY 2 DO
(unless, or course, you cheat by changing 255C to 254C)
Roger (cr...@polya.stanford.edu) ``Beam Wesley into the sun!''
]_Programming_In_Modula-2_ essentially defines the for statement as the following
]"FOR" ident ":=" expression1 "TO" expression2 [ "BY" ConstExpression ] "DO"
]is equivalent to
]ident ":=" expression1;
]"WHILE" ident "<=" expression2 "DO"
] [ident ":=" ident "+" ConstExpression (* if "BY" clause used *) |
] ident ":=" ident "+ 1" (* if "BY" clause not used *) ]";"
](* ident := undefined *)
It does. And thereby perpetuates the design or implementation error that
has cursed FOR-loops since the days of Algol-60: a loop set to end on the
largest value of the associated type will fail.
This is 1988. Let's at least put THAT right!
>... thereby perpetuates the design or implementation error that
>has cursed FOR-loops since the days of Algol-60: a loop set to end on the
>largest value of the associated type will fail.
>This is 1988. Let's at least put THAT right!
This is purely an implementation issue. MacMETH does it correctly, as
I'm sure some other compilers do. At the bottom of the loop, MacMETH
generates an ADDI or SUBI, followed by either a BVC (INTEGER or LONGINT)
or a BCC back to the top of the loop. Note that this correctly handles
FOR u := 0 TO MAX(CARDINAL) BY 2 DO ... END;
Stopping on >= before the increment, rather than > after the increment,
would not help in this case, although I suppose the generated code could
decrement the limit by (stepsize-1) before the loop, and then use a >=
test before increment.
If your compiler doesn't handle these limit situations correctly, gripe
at the vendor until they fix it. (Hi, Eli! :-))
Of course this means that a FOR loop is not EXACTLY equivalent to the
corresponding WHILE, since the WHILE version will either ignore the
carry/overflow or abort execution, depending on the implementation.