Hello,
All the tests below were on the latest (?) binary release of GNU Pascal for mingw. The result of "gpc -v" is:
gpc version 2.1 (20020510), based on 2.95.3-6 (mingw special)
I'm interested in standard (ISO) modes, especially ISO 7185, so I have been using the "--classic-pascal" option. I'm only indicating that (in FLAG comments) where I suspect that, what GNU Pascal currently does may be appropriate, when standard compliance is not requested.
First, some test programs with non-standard features:
program az1(output); (* FLAG --classic-pascal *) const c=2+2; (* WRONG - violation of 6.3 of ISO 7185 *) begin writeln('failed') end.
program az2(output); (* FLAG --classic-pascal *) const p=nil; (* WRONG - violation of 6.3 of ISO 7185 *) begin writeln('failed') end.
program az3(output); (* FLAG --classic-pascal *) procedure q(x:integer); const xx=x*x; (* WRONG - violation of 6.3 of ISO 7185 *) begin end; begin writeln('failed') end.
program az4(output); (* FLAG --classic-pascal *) begin case 4 of 2+2: (* WRONG - violation of 6.8.3.5 of ISO 7185 *) end; writeln('failed') end.
program az5(output); (* FLAG --classic-pascal *) var r:record case boolean of false..true:() (* WRONG - violation of 6.8.3.5 of ISO 7185 *) end; begin writeln('failed') end.
program az6(output); (* FLAG --extended-pascal *) begin if ord('')=32 then; (* WRONG - violation of 6.7.6.4 of ISO 10206 *) writeln('failed') end.
program az7(output); (* FLAG --classic-pascal *) begin if []<[1] then; (* WRONG - violation of 6.7.2.5 of ISO 7185 *) writeln('failed') end.
program az8(output); (* FLAG --classic-pascal *) type t=set of char; function f:t; (* WRONG - violation of 6.6.2 of ISO 7185 *) begin f:=[] end; begin writeln('failed') end.
program az9(output); (* FLAG --classic-pascal *) type t=record end; var x:t; function f:t; (* WRONG - violation of 6.6.2 of ISO 7185 *) begin f:=x end; begin writeln('failed') end.
program az10(output); (* FLAG --classic-pascal *) procedure q(procedure r); begin end; begin q(nil); (* WRONG - violation of 6.6.3.4 of ISO 7185 *) writeln('failed') end.
program az11(output); (* FLAG --classic-pascal *) var a:record case b:boolean of true,false:() end; procedure p(var x:boolean); begin end; begin p(a.b); (* WRONG - violation of 6.6.3.3 of ISO 7185 *) writeln('failed') end.
program az12(output); (* FLAG --classic-pascal *) procedure q(procedure r); begin r:=r (* WRONG - violation of 6.4.6 of ISO 7185 *) end; begin writeln('failed') end.
program az13(output); (* FLAG --classic-pascal *) var t:array [boolean] of integer; begin if t=t then; (* WRONG - violation of 6.7.2.5 of ISO 7185 *) writeln('failed') end.
program az14(output); (* FLAG --classic-pascal *) begin if 'ab'='abc' then; (* WRONG - violation of 6.7.2.5 of ISO 7185 *) writeln('failed') end.
program az15(output); (* FLAG --classic-pascal *) begin write('failed'); writeln('1':0,'22':0,3:0) (* WRONG - violation of 6.9.3.1 of ISO 7185 *) (* Besides, writing "13" seems inconsistent *) end.
program az16(output); (* FLAG --classic-pascal *) var r:record end; begin with (r) do; (* WRONG - violation of 6.8.3.10 of ISO 7185 *) writeln('failed') end.
program az17(output); (* FLAG --classic-pascal *) var p:^integer; begin new((p)); (* WRONG - violation of 6.6.5.3 of ISO 7185 *) writeln('failed') end.
program az18(output); (* FLAG --classic-pascal *) var a:array [1..1] of integer; begin (a)[1]:=10; (* WRONG - violation 6.5.3.2 of ISO 7185 *) writeln('failed') end.
Correct programs, which don't compile:
(* az19.pas: In main program: az19.pas:4: division by zero *) program az19(output); begin if false then writeln('failed: ',1/0) else writeln('OK') end.
(* az20.pas: In main program: az20.pas:7: warning: ISO Pascal forbids this use of packed array components *) program az20(output); (* FLAG --classic-pascal -Werror *) var t:packed array [1..1,1..1] of boolean; i:integer; begin i:=1; t[1,i]:=false; writeln('OK') end.
(* az21.pas: In main program: az21.pas:11: type mismatch in array index az21.pas:11: array subscript is not of ordinal type *) program az21(output); var t:array [1..1] of integer; procedure r(x:integer); begin end; function q:integer; begin q:=1 end; begin r(t[q]); writeln('OK') end.
(* az22.pas: In procedure `P': az22.pas:5: function definition does not match previous declaration az22.pas: In function `X': az22.pas:6: undeclared identifier `Y' (first use in this routine) az22.pas:6: (Each undeclared identifier is reported only once az22.pas:6: for each routine it appears in.) az22.pas:7: warning: return value of function not assigned *) program az22(output); function x:integer;forward; procedure p; function x(y:integer):integer; begin x:=y end; begin end; function x; begin x:=1 end; begin writeln('OK') end.
(* az23.pas: In main program: az23.pas:3: parse error before `..' az23.pas:5: parse error before `Else' *) program az23(output); begin if []=(..) then writeln('OK') else writeln('failed') end.
Incorect programs - should not compile:
program az24(output); begin if 1.1 in [] then; (* WRONG - real is not an ordinal type *) writeln('failed') end.
program az25(output); var real:real; (* WRONG - can't create new definition and use the old one *) begin writeln('failed') end.
program az26(output); begin writeln('failed: ',1:2.3) (* WRONG - field width should be integer *) end.
program az27(output); begin writeln('failed: ','xx':true) (* WRONG - field width should be integer *) end.
program az28(output); var i:integer; begin for i:=0 to nil do; (* WRONG - type of final value not compatible with integer *) writeln('failed') end.
program az29(output); var f:file of file of char; (* WRONG - file type is an illegal component type *) begin writeln('failed') end.
program az30(output,output); (* WRONG - program parameters are not distinct *) begin writeln('failed') end.
program az31(output); type t=record x:^r(* WRONG *)eal end; begin writeln('failed') end.
program az32(output); procedure q;forward; (* WRONG - no definition of procedure q *) begin writeln('failed') end.
program az33(output); begin writeln('failed: ',3:2:1) (* WRONG - that form is only applicable to reals *) end.
program az34(output); function f:integer; begin f:=1 end; procedure p(function f); (* WRONG - incorrect declaration of functional parameter *) begin end; begin writeln('failed') end.
program az35(output); var output:file of real; begin writeln('failed') (* WRONG - output is not of type "text" *) end.
Programs demonstrating internal compiler error:
(* d:\src\gcc-2.95.3-20010828\gcc\p\gpc-common.c:1390:build_pascal_binary_op: failed assertion `result' az36.pas: In main program: az36.pas:4: Internal compiler error. *) program az36(output); begin if 0 in ([]*[1]) then writeln('failed') else writeln('OK') end.
(* az37.pas: In main program: az37.pas:3: ISO Pascal requires an entire `for' variable az37.pas:3: invalid operands to binary <= az37.pas:3: invalid lvalue in assignment az37.pas:3: Internal compiler error in `do_abort', at toplev.c:2301 *) program az37(output); begin for char:=1 to 1 do; (* WRONG *) writeln('failed') end.
Programs crashing compiler:
program az38(output); begin if 1 in 1 then; (* WRONG *) writeln('failed') end.
program az39(output); var s:set of boolean; begin s:=1; (* WRONG *) writeln('failed') end.
program az40(output); procedure q(x:integer);forward; procedure q; begin end; function r; (* WRONG *) begin r:=1 end; begin writeln('failed') end.
program az41(output); var t:array [(a)] of integer; begin t[char]:=1; (* WRONG *) writeln('failed') end.
program az42(output); const s=1; type t=^s; (* WRONG *) begin writeln('failed') end.
Finally, programs giving incorrect results:
program az43(output); (* FLAG --classic-pascal *) (* The reason, I'm including that option is that there may be some dialect implemented by GNU Pascal, which does not define the order of evaluation for parameters of "write". ISO standards are clear about it *) var a,b,c,d,x:integer; f:text; (* Result is correct if you change that to f:file of integer *) function g(y:integer):integer; begin write(f,x*y); x:=x+2; g:=x+y; end; begin rewrite(f); x:=1; write(f,g(3),g(1)); reset(f); read(f,a,b,c,d); if (a=3) and (b=6) and (c=3) and (d=6) then writeln('OK') else writeln('failed: ',a,b,c,d) end.
program az44(output); var x:integer; function f:integer; begin f:=x; x:=2 end; begin x:=1; if [1]=[f] then writeln('OK') else writeln('failed') end.
program az45(output); var x:boolean; function f:integer; begin f:=1; x:=true end; begin x:=false; if 1 in [1,f] then if x then writeln('OK') else writeln('failed') end.
Artur Zaroda wrote:
All the tests below were on the latest (?) binary release of GNU Pascal for mingw. The result of "gpc -v" is:
gpc version 2.1 (20020510), based on 2.95.3-6 (mingw special)
I'm interested in standard (ISO) modes, especially ISO 7185, so I have been using the "--classic-pascal" option. I'm only indicating that (in FLAG comments) where I suspect that, what GNU Pascal currently does may be appropriate, when standard compliance is not requested.
Thanks very much for the test programs. This was certainly the largest set of bug reports submitted at any one time. :-)
Apparently you've been very thorough, since you've covered some issues that were discussed here recently (such as declaring an identifier as a variable while using it as a type).
BTW, we've had some alpha versions after 2.1, and a few of your tests (31, 38, 40, 41, 42) have been fixed meanwhile.
Fortunately, most of the other ones seem rather easy to fix, but there are some tricky problems. I'll have to see when I can get to them ...
Some comments to a few tests:
Correct programs, which don't compile:
(* az19.pas: In main program: az19.pas:4: division by zero *) program az19(output); begin if false then writeln('failed: ',1/0) else writeln('OK') end.
I've read the discussion in the newsgroup. I tend to agree with Chuck (IIRC) that it would be better to reject this at compile time, but it seems we have no choice. :-(
So I'll turn this error into a warning (which seems to satisfy the second alternative of 5.1 f) plus a runtime error -- but I think only in CP/SP mode.
program az33(output); begin writeln('failed: ',3:2:1) (* WRONG - that form is only applicable to reals *) end.
Just to be sure, assignment compatibility from integer to real doesn't come into play here? After looking in the standard, it seems it doesn't, so one can't say that an integer value can be used wherever a real value is expected. Right?
program az35(output); var output:file of real; begin writeln('failed') (* WRONG - output is not of type "text" *) end.
Is it not already an error to (re)declare `Output' as a variable?
Frank
Hello,
On Thu, 19 Dec 2002, Frank Heckenbach wrote:
Artur Zaroda wrote:
All the tests below were on the latest (?) binary release of GNU Pascal for mingw. The result of "gpc -v" is:
gpc version 2.1 (20020510), based on 2.95.3-6 (mingw special)
I'm interested in standard (ISO) modes, especially ISO 7185, so I have been using the "--classic-pascal" option. I'm only indicating that (in FLAG comments) where I suspect that, what GNU Pascal currently does may be appropriate, when standard compliance is not requested.
Thanks very much for the test programs. This was certainly the largest set of bug reports submitted at any one time. :-)
Apparently you've been very thorough, since you've covered some issues that were discussed here recently (such as declaring an identifier as a variable while using it as a type).
It wasn't my intension to repeat things you already know about. In particular, I omitted bugs I reported on comp.lang.pascal.ansi-iso, like the "-1 mod 2" problem.
BTW, we've had some alpha versions after 2.1, and a few of your tests (31, 38, 40, 41, 42) have been fixed meanwhile.
I wrote all the test programs a month ago. The only change I made before re-posting them to the list was inserting question mark after the word "latest".
program az33(output); begin writeln('failed: ',3:2:1) (* WRONG - that form is only applicable to reals *) end.
Just to be sure, assignment compatibility from integer to real doesn't come into play here? After looking in the standard, it seems it doesn't, so one can't say that an integer value can be used wherever a real value is expected. Right?
That is my understanding of the standard. Not that it would mean anything, but even in Turbo Pascal "writeln(3:2:1)" is an error.
For a somewhat less obvious case try:
program az46(output); (* FLAG --classic-pascal *) begin writeln('failed: ',round(1)) (* WRONG - parameter of "round" should be of real-type *) end.
GNU Pascal issues a warning here; I believe that ISO says it is illegal.
program az35(output); var output:file of real; begin writeln('failed') (* WRONG - output is not of type "text" *) end.
Is it not already an error to (re)declare `Output' as a variable?
Yes, I think it is.
Regards,
Artur Zaroda zaroda@mimuw.edu.pl
Artur Zaroda wrote:
Thanks very much for the test programs. This was certainly the largest set of bug reports submitted at any one time. :-)
Apparently you've been very thorough, since you've covered some issues that were discussed here recently (such as declaring an identifier as a variable while using it as a type).
It wasn't my intension to repeat things you already know about. In particular, I omitted bugs I reported on comp.lang.pascal.ansi-iso, like the "-1 mod 2" problem.
Yes, that's also on my list.
BTW, we've had some alpha versions after 2.1, and a few of your tests (31, 38, 40, 41, 42) have been fixed meanwhile.
I wrote all the test programs a month ago. The only change I made before re-posting them to the list was inserting question mark after the word "latest".
My comments weren't meant as criticism. Quite the opposite -- since you found the same problems that were discussed here (independently) or fixed meanwhile, this suggests that your tests did indeed cover the whole standard quite thorougly.
That is my understanding of the standard. Not that it would mean anything, but even in Turbo Pascal "writeln(3:2:1)" is an error.
Indeed, it doesn't mean anything. ;-)
For a somewhat less obvious case try:
program az46(output); (* FLAG --classic-pascal *) begin writeln('failed: ',round(1)) (* WRONG - parameter of "round" should be of real-type *) end.
GNU Pascal issues a warning here; I believe that ISO says it is illegal.
Incidentally, BP accepts this, and BTW, this was the reason why I allowed these things in GPC -- someone did exactly this in a BP program that I should support in GPC. But I'll disable it in CP/EP mode then.
Frank
Frank Heckenbach wrote:
Artur Zaroda wrote:
... snip ...
For a somewhat less obvious case try:
program az46(output); (* FLAG --classic-pascal *) begin writeln('failed: ',round(1)) (* WRONG - parameter of "round" should be of real-type *) end.
GNU Pascal issues a warning here; I believe that ISO says it is illegal.
Incidentally, BP accepts this, and BTW, this was the reason why I allowed these things in GPC -- someone did exactly this in a BP program that I should support in GPC. But I'll disable it in CP/EP mode then.
For some peculiar reason my gut would be to go along with BP here. Before changing it let's locate the appropriate passages in 7185 and 10206. It is much like accepting "2 * 2.0" as an expression, where there should be an automatic conversion of the 2. It makes little sense to have:
v := round(1 * 2.0); (* legal *) and v := round(1.0 * 2); (* legal *) yet v := round(1 * 2); (* illegal *)
noting that the real portions may be references to variables, whose type is not immediately obvious.
LATER - I looked them up, and Mr Zaroda is correct. I still feel the expression should either be converted or the function call optimized out. Maybe some grist for the gnu variety. I suggest complaining only with 'pedantic' and generating the appropriate code anyhow. That should minimize the changes.
CBFalconer wrote:
[ Round (IntegerValue) ]
LATER - I looked them up, and Mr Zaroda is correct. I still feel the expression should either be converted or the function call optimized out. Maybe some grist for the gnu variety. I suggest complaining only with 'pedantic' and generating the appropriate code anyhow. That should minimize the changes.
What I do now is:
- In standard mode, give an error,
- otherwise, give a warning and optimize the conversion (which is generally inlined, not a function call, BTW).
Frank
On Thu, Dec 19, 2002 at 05:21:11AM +0100, Frank Heckenbach wrote:
Artur Zaroda wrote:
[...]
program az35(output); var output:file of real; begin writeln('failed') (* WRONG - output is not of type "text" *) end.
Is it not already an error to (re)declare `Output' as a variable?
`Output' is an identifier, not a keyword, so it may be redefined freely. But then it stops to be magic, i.e. it can't be used as an implicit file parameter of Write(Ln), it needs an explicit Rewrite, and (contrary to usual Pascal conventions for shadowing predefined identifiers) it mustn't occur in the program parameter list (see ISO 10206 6.12). Thus az35 is faulty for at least three separate reasons, which may be isolated as follows (Out1 fails in GPC, Out[23] work):
program Out1 (Output); (* FLAG --classic-pascal *)
var Output: Text; { WRONG - Output already used as program parameter }
begin end.
program Out2; (* FLAG --classic-pascal *)
var Output: Text;
begin WriteLn ('failed') { WRONG - missing file variable } end.
program Out3 (Output); (* FLAG --classic-pascal *)
var F: file of Char;
begin Rewrite (F); WriteLn (F); { WRONG - not a text file } WriteLn ('failed') end.
However, the following is allowed (and it works in GPC):
module Out4m; (* FLAG --extended-pascal *)
export Out4i = (OK);
procedure OK;
end;
import StandardOutput;
procedure OK; begin WriteLn ('OK') end;
end.
program Out4; (* FLAG --extended-pascal *)
import Out4i;
var Output: Text;
begin Rewrite (Output); WriteLn (Output, 'failed'); OK end.
The following should also work, IIUC the rules in 6.11.4.2. (Currently it just crashes the compiler.)
program Out5; (* FLAG --extended-pascal *) import StandardOutput only (Output => Brecks);
begin WriteLn ('OK') end.
[~/pascal/test]% gpc -O2 -fextended-pascal out5.pas out5.pas:3: internal error: NeoprĂĄvnĂŹnĂ˝ pøĂstup do pamĂŹti (SIGSEGV) Please submit a full bug report, with preprocessed source if appropriate. See URL:http://www.gnu-pascal.de/todo.html for instructions.
On Mon, Dec 16, 2002 at 08:15:34AM +0100, Artur Zaroda wrote:
program az45(output); var x:boolean; function f:integer; begin f:=1; x:=true end; begin x:=false; if 1 in [1,f] then if x then writeln('OK') else writeln('failed') end.
I don't think this should write 'OK'. The standard says:
6.8 Expressions
6.8.1 General
[...] The member-designator x, where x is an expression, shall denote the member that shall be the value of x. The member-designator x..y, where x and y are expressions, shall denote zero or more members that shall be the values of the base-type in the closed interval from the value of x to the value of y. The order of evaluation of the expressions of a member-designator shall be implementation-dependent. The order of evaluation of the member-designators of a set-constructor shall be implementation-dependent.
6.8.3 Operators
6.8.3.1 General
[...] A primary, a factor, a term, or a simple-expression shall be designated an operand. Except for the and_then and or_else operators, the order of evaluation of the operands of a dyadic operator shall be implementation-dependent.
NOTE -- This means, for example, that the operands may be evaluated in textual order, or in reverse order, or in parallel, or they may not both be evaluated.
3.5 Implementation-dependent
Possibly differing between processors and not necessarily defined for any particular processor.
IMHO this means that the compiler is allowed not to call `f' when evaluating `1 in [1,f]', if it doesn't want to.
An unrelated bug report: GPC fails to compile the program below.
program SchemaFunc (Output);
type Sch (I: Integer) = array [1 .. I] of Integer; S = Sch (13);
var A: S;
function G: S; begin G := A end;
begin A[7] := 42; if G[7] = 42 then WriteLn ('OK') else WriteLn ('failed') end.
[~/pascal/test]% gpc schfunc.pas schfunc.pas: In function `G': schfunc.pas:13: incompatible types in assignment schfunc.pas: In main program: schfunc.pas:18: subscripted object is not an array or string
Emil
Emil Jerabek wrote:
On Thu, Dec 19, 2002 at 05:21:11AM +0100, Frank Heckenbach wrote:
Artur Zaroda wrote:
[...]
program az35(output); var output:file of real; begin writeln('failed') (* WRONG - output is not of type "text" *) end.
Is it not already an error to (re)declare `Output' as a variable?
`Output' is an identifier, not a keyword, so it may be redefined freely.
I didn't mean to imply it was a keyword, rather a duplicate identifier.
But then it stops to be magic, i.e. it can't be used as an implicit file parameter of Write(Ln), it needs an explicit Rewrite, and (contrary to usual Pascal conventions for shadowing predefined identifiers) it mustn't occur in the program parameter list (see ISO 10206 6.12). Thus az35 is faulty for at least three separate reasons, which may be isolated as follows (Out1 fails in GPC, Out[23] work):
Thanks for the diagnosis. Fixed now (emil23*.pas).
Just to be sure, the following is also correct, isn't it?
program Out6 (Output); (* FLAG --classic-pascal *)
procedure Foo; var Output: Text; begin WriteLn ('OK') end;
begin Foo end.
On Mon, Dec 16, 2002 at 08:15:34AM +0100, Artur Zaroda wrote:
program az45(output); var x:boolean; function f:integer; begin f:=1; x:=true end; begin x:=false; if 1 in [1,f] then if x then writeln('OK') else writeln('failed') end.
I don't think this should write 'OK'. The standard says:
[...]
IMHO this means that the compiler is allowed not to call `f' when evaluating `1 in [1,f]', if it doesn't want to.
I think you're correct -- and therefore GPC as well. :-) However, I'm adding a warning in this case (maybe also in similar cases in the future, such as `0 * f' or `False and (f = 1)').
An unrelated bug report: GPC fails to compile the program below.
program SchemaFunc (Output);
[...]
Fixed now (emil22*.pas).
Frank
On Mon, Jan 27, 2003 at 06:09:42AM +0100, Frank Heckenbach wrote:
Emil Jerabek wrote:
On Thu, Dec 19, 2002 at 05:21:11AM +0100, Frank Heckenbach wrote:
Artur Zaroda wrote:
[...]
program az35(output); var output:file of real; begin writeln('failed') (* WRONG - output is not of type "text" *) end.
Is it not already an error to (re)declare `Output' as a variable?
`Output' is an identifier, not a keyword, so it may be redefined freely.
I didn't mean to imply it was a keyword, rather a duplicate identifier.
But then it stops to be magic, i.e. it can't be used as an implicit file parameter of Write(Ln), it needs an explicit Rewrite, and (contrary to usual Pascal conventions for shadowing predefined identifiers) it mustn't occur in the program parameter list (see ISO 10206 6.12). Thus az35 is faulty for at least three separate reasons, which may be isolated as follows (Out1 fails in GPC, Out[23] work):
Thanks for the diagnosis. Fixed now (emil23*.pas).
Just to be sure, the following is also correct, isn't it?
program Out6 (Output); (* FLAG --classic-pascal *)
procedure Foo; var Output: Text; begin WriteLn ('OK') end;
begin Foo end.
It is, IIUIC.
Emil