piner@pur-phy.UUCP (Richard Piner) (02/23/84)
I have found two bugs in the Microsoft FORTRAN80 and MACRO80 system sold by Radio Shack. I assume they are in the CP/M version as well. I will detail these bugs, because they have caused me a great deal of trouble in tracking them down. It takes a long time to find things like this, since compiler bugs are not what you think of first. I hope this may save some of you some time in the future. The first bug has to do with the logical IF statement. Here is a sample subroutine. SUBROUTINE BUG2 LOGICAL CHAR (,STBKEY) 10 IF(.NOT.STBKEY(CHAR)) RETURN GO TO 10 END STBKEY is a logical function to strobe the keyboard. It is false if there are no keys down, and true if there are. If a key is down, it is returned in CHAR. The idea of this subroutine is to wait till someone lets go of a key. Now, STBKEY should be declared as a logical function, and if it is, everything works. But if it is not declared, the compiler compiles incorrect code. The compiler should flag this as a fatal error, but it doesn't. I tried it on the Dec f4p compiler and the MNF compiler on the CDC, and indeed they did refuse to compile it. Now I will list the compiler output and show the error. First the correct code: FORTRAN-80 VER. 3.4 COPYRIGHT 1978, 79, 80 (C) BY MICROSOFT CREATED: 01-DEC-80 1 SUBROUTINE BUG2 2 LOGICAL CHAR,STBKEY 3 10 IF(.NOT.STBKEY(CHAR)) RETURN ***** 0000' LD HL,CHAR {point HL at CHAR} ***** 0003' CALL STBKEY {result in A, -1=true} ***** 0006' CPL {do the .NOT.} ***** 0007' LD (T:000002),A {save results into T} ***** 000A' OR A {test for false} ***** 000B' JP Z,0000 {if false go to line 0000'} ***** 000E' RET {else return} 4 GO TO 10 5 END ***** 000F' JP 10L {go to label 10} PROGRAM UNIT LENGTH=0012 (18) BYTES DATA AREA LENGTH=0004 (4) BYTES SUBROUTINES REFERENCED: STBKEY VARIABLES: CHAR 0001" T:000002 0003" LABELS: 10L 0000' Now the incorrect code: FORTRAN-80 VER. 3.4 COPYRIGHT 1978, 79, 80 (C) BY MICROSOFT 1 SUBROUTINE BUG1 2 LOGICAL CHAR 3 10 IF(.NOT.STBKEY(CHAR)) RETURN ***** 0000' LD HL,CHAR {point HL at CHAR} ***** 0003' CALL STBKEY {result in A, -1=true} ***** 0006' CPL {do the .NOT.} ***** 0007' LD HL,T:000001 {point to memory loc. T} ***** 000A' CALL $T1 {copy floating acc. to T} ***** 000D' JP Z,0000 {if .false. loop 0000'} ***** 0010' RET {else return} 4 GO TO 10 5 END ***** 0011' JP 10L {go to label 10} PROGRAM UNIT LENGTH=0014 (20) BYTES DATA AREA LENGTH=0006 (6) BYTES SUBROUTINES REFERENCED: STBKEY $T1 VARIABLES: CHAR 0001" T:000001 0002" LABELS: 10L 0000' Now since the FORTRAN library routine $T1 is supposed to copy the floating point accumulator to memory (& test for zero?) the value of the Z flag may or may not be what you want. Certainly the compiler is confused about what it should be doing. Most compilers just won't compile it since STBKEY is not a logical function. If the compiler wanted to carry type conversion and mixing to the max, it should have called the floating point to byte conversion routine before the CPL instruction. As it is, the result is random. If the value in the floating point accumulator (which is never set and hence random) causes $T1 to return with the Z flag set, this routine goes into an infinite loop. Indeed, the result depends on what ever floating point operation has taken place before this subroutine was called. The result for me was an undetected bug that poped up months later when some other unrelated subroutine was changed. Finding it took almost a week. While this would seem to support the case for strong type checking in a language, what we have here is one the few places FORTRAN is supposed to do type checking, but the compiler failed to do so. So watch out for this one, it can really sneak up on you. The second bug also sent me up the wall. If you plan to only use the Microsoft linker it will not affect you. But if you play around with the relocateable binary it will cause trouble. I ran into this with my own linker which links to disk instead of memory, so I can link a program that runs all the way up to the top of memory. FORTRAN and MACRO80 store common block names differently. The first character of a common block name stored by FORTRAN has bit 8 set. MACRO80 does it right. This drove me crazy since my linker claimed that there were two different common blocks but printed the same name on the map. My linker now mask characters in names so bit 8 is ignored. Hope this very long article may save some of you some grief in the future. Rich Piner Purdue Physics Dept.