Craig writes:
> Most of our (old) Pascal code represents the CALENDAR format (in Pascal) as:
>
> CALRECORD = PACKED RECORD
> CASE BOOLEAN OF
> TRUE : (CALINT : SHORTINT);
> FALSE : (
> CALYEAR: 0..99;
> CALDAY : 0..366;
> )
> END;
I'd suggest changing it to:
calrecord = crunched record {or: calendar_type = ... }
calyear : bit7; {or: 0..127}
calday : bit9; {or: 0..511}
end;
Someone screwed you up by going out of their way to incorrectly
define the calyear field, limiting the values to a max of 99 (which you
know, of course). (more on the dropping of the "case" further below)
> Please note the CALYEAR range of 0..99. The Pascal compiler reserves
> 7 bits for that info in the shortint; however, should an Intrinsic
> return a CALENDAR-type date with 100<= CALYEAR <= 127, then the run-time
> execution of the program should fail with an out of bounds range-check
> violation. But not always is this the case - read on.
It depends upon how the data is transferred from the intrinsic result
and into a variable of type calrecord. Here are two examples where the
compiler has no way of knowing that you'd ever want the upper 7 bits of
of such a variable checked:
(using the original "case" version of caltype)
var
c : calrecord;
c.int := calendar;
and
ffileinfo (fid, 36, c); {36 is allocation date (calendar)}
In the first, you're going out of your way to tell the compiler: hey,
this isn't really a record composed of two limited-range fields, instead
please treat it as a single glob of 16 bits.
In the second, you're telling the compiler: pass the address of a variable
to this intrinsic ... I hope the intrinsic won't store more data into it
than will fit ... Pascal has no clue that you'll be putting stuff into
the variable.
If you have:
var
c : caltype;
d : caltype;
and do:
c := d;
I'd expect no range checking ... Pascal should assume that "d" is legitimate,
and therefore doesn't need to check the range (because c and d are the
same type).
> 2000 and beyond. In particular, the FFILEINFO Intrinsic item 28 returns
> the expiration of an ANSI-labeled tape date in CALENDAR format.
Interesting...my intrinsics manual documents 28 and 32 as type "julian",
and item 36 as "CALENDAR". So, (after reading your note), I thought
I should test it. On disk files, both 28 and 32 seem to return 0, and
no error/warning (ugh!), and 36 returns the CALENDAR date.
On unlabelled tapes, 28 and 32 return -1, and 36 returns 0.
On labelled tapes, 28 and 32 indeed return CALENDAR format dates (I'm
updating my manual, and the CSEQ database).
> In tests I found the above code *worked* after retrieving the expiration
> date from an ANSI-labeled tape with an expiration date of 2001; that is,
> CALYEAR contained 101. This should have generated a run-time range-
> check violation, but didn't. Hmmm...
Even with range checking on, I'd expect the following to work when
c.calyear = 101:
var
c : caltype;
i : integer;
i := c.calyear;
> My point is this: It is a Good Idea (tm) to hand-check any code that
> deals with dates in CALENDAR format and expects the CALYEAR (of my
> example) to be less than 100.
Yep!
BTW, my example avoids the "tagless variant", Pascal's most evil aspect.
Instead, when I absolutely positively need to get at the value of
a variable of type caltype as 16 bits, I'd do:
$standard_level 'os_features'$
$type_coercion 'representation'$
var
c : caltype;
i16 : shortint;
...
i16 := shortint (c);
Many PC implementations of Pascal have a similar "cast" ability. The
nice thing about Pascal/iX's type coercion is that is is possible to
constrain it (as above) to working only when the type-name and the
value are exactly the same size. Although Pascal/iX does allow you to
say "$type_coercion 'noncompatible'$, every use of it I've seen has been
a mistake.
--
Stan Sieler [log in to unmask]
http://www.allegro.com/sieler.html
|