CBFalconer wrote:
Expanding, all that is required is a single routine (or in line instruction sequence) as long as chars and booleans are represented by integers, which is called or emitted just before assignment or indexing. The value to be checked is already on the stack, and it would look like:
push min push max call chk
which would normally simply absorb min and max, and let the code continue to the assignment, indexing, function call, etc. For failure, it aborts with appropriate messages. In C terms it would look like:
inline int chk(value, min, max) { if ((value < min) || (value > max)) abort(value, min, max); return value; }
which is adequate because Pascal has no concept of unsigned, outside of subranges of integer. As far as possible everything is passed in registers, but that is only an implementation detail.
For booleans (common) I created an additional routine, chkb, which implied the 0 and 1 limits and avoided the overhead of pushing parameters. I also created chkp, which only checked for a non-NIL pointer and a value known to lie somewhere within the system heap. chkb and chkp need no parameters, but must normally leave the top-of-stack value unaltered. Of course proper use of chkp means the compiler has to distinguish between pointers and VAR references, and is the reason such things are not feasible in C.
The hard part is deciding when *NOT* to emit it. One case is when run-time checks have been disabled, and is easy. The basic idea is to keep track of the possible range of expressions (including unknown). For example:
TYPE ix = 1..maxix; whatever = ....
VAR a : ARRAY[ix] OF whatever; x : ix; y : whatever; i : integer;
.... y = a[x];
needs no checking because x is of type ix, already checked, and a[x] is of type whatever, again already checked. y = a[3] can be checked (for index) at compile time, but y = a[i] needs a check call.
Thanks for trying to help, but I don't think these are the main issues we'd have to deal with.
For one, when we do it, we'll certainly use inline comparisons, so we won't need to worry about parameter passing and optimizing special cases in this regard.
Secondly, the ranges of all expressions are already kept track of. I also don't think there are any "unknown" ranges. If, e.g. an operation is done on Integers, the result generally has the range MinInt .. MaxInt.
The main thing seems to be to find all places where to do it (assignments, parameters passing, array indexed, initializers, ...)
I think I'll look into it after 2.1 ...
Frank