Frank Heckenbach wrote:
CBFalconer wrote:
Frank Heckenbach wrote:
... snip ...
Fortunately, most I/O errors (e.g.) in Pascal are not signaled via function results in the first place.
I have always considered this an error in Pascals basic design, at least as far as things that do not fit the format are concerned. Consider:
read(intvar);
which has to cause an i/o error and usually program abort (barring other extensions) if the interactive input is not properly formatted.
I agree. In fact, here's where I prefer (in many situations) Borland's `{$I-}'/`IOResult' extension since it allows me to handle errors from a bunch of I/O statements together. Though exceptions (yet another extension) might be even better in the long run ...
So I have always provided (as an extension) an alternative standard function:
FUNCTION readx(something) : boolean;
which returns true on a formatting error, and extends to reals, etc. just as does the normal read function. Unlike read, it cannot be used as shorthand for multiple reads. Thus interactive usage is normally:
IF readx(something) THEN correctiveaction ELSE BEGIN (* all is well *) END;
with the knowledge that the offensive character is in input^.
BP has `Val (StringValue, TargetVariable, ErrorPosition)'. I usually use this, but I find the procedure-style usage rather clumsy often (the need for an extra variable which is usually just tested in a following conditional).
Therefore I've considered implementing such a Boolean function -- though my thoughts were more about parsing from a string, just like `Val' (it's more general -- you can always read from a file to a string first, but if you have the value in a string already, it would be rather inefficient to write it to a file first), and I'd have the result value the opposite way (True for success) ...
So my proposal is to add (now or later):
function String2Num(???) (const s: String; var n: <numeric type>): Boolean;
Comments?
Pascal is somewhat unique in the way it encourages use of input streams. All input parsing leaves the terminating char in f^, so that the reason for rejection, or the existance of further data in a line, can be detected from that and the eoln condition. So I consider the existance of such things as my "readx(file, var) : boolean;" essential. Combined with a routine as:
PROCEDURE skipblks(f : text);
BEGIN WHILE NOT eoln(f) AND (f^ = ' ') DO get(f); END;
it allows complex input routines to be written as:
WHILE NOT eof(f) AND NOT eoln(f) DO BEGIN skipblks(f); IF readx(f, param[index]) THEN BEGIN (* corrective action, using f^ etc. *) readln(f); (* discard remainder of line *) END ELSE BEGIN (* possible tests on value *) (* possible tests on terminating char *) index := succ(index); END; END;
where param[index] can stand for many things. This sort of thing allows easy handling of input supplied as individual lines, or on one line with comma or blank separators, or whatever. Note especially that there is _no need_ for a buffer string of unknown length.
Once you have this sort of input routine, there is very little need for a string parsing mechanism. The problem is largely that C programmers are used to such a technique, and many will be lost without it.
Therefore I would try to make any such string parser logically equivalent to the use of readx*(f, var), maybe with sreadx*(s, var). There is no need for seof, and seoln(s) can detect the string end. It may be useful to include a var parameter for the current string index, by which time the function looks much like your proposal above, so that the programmers rule is to replace f with the s, index pair.
In PascalP I did not implement the set of sread* functions, preferring to build them to taste for an application. However I did provide a read(f, string) procedure. You already have that.
In PascalP I used the rule that extensions should almost always be in the form of standard functions or procedures, so that the only porting effort to purely standard Pascal was the writing of such functions. Thus there were no such things as unsigned integers, instead there was the "uadd(a, b : integer) : integer;" function, which ignored overflow and implemented the usual modulus rules.