|
Spaces are completely ignored in F77 (and earlier). Columns are significant - specifically col 6. This would be another valid version of the program:
. PROGRAMPROGRAM
INTEGERIF,INTEGER,GOTO,IMPLICIT
REALREAL,DIMENSION,EXTERNAL,FORMAT,END
INTEGERLOGICAL
REALCOMPLEX,DATA,CALL,ASSIGN,CHARACTER
DOFORIF=INTEGER,INTEGER;ENDDO
INTEGER=IF+IF
GOTO=INTEGER*INTEGER*INTEGER*INTEGER-INTEGER-IF
CALLFUNCTION(IMPLICIT,REAL,DIMENSION,EXTERNAL,FORMAT,END
$,LOGICAL,COMPLEX,DATA,CALL,ASSIGN,CHARACTER)
CALLSUBROUTINE(IMPLICIT, LOGICAL, GOTO, IF, INTEGER)
END
SUBROUTINEFUNCTION(IMPLICIT,REAL,DIMENSION,EXTERNAL,FORMAT
$,END,LOGICAL,COMPLEX,DATA,CALL,ASSIGN,CHARACTER)
RETURN
END
SUBROUTINESUBROUTINE(IMPLICIT,LOGICAL,GOTO,IF,INTEGER)
INTEGERGOTO,IMPLICIT(GOTO),LOGICAL(GOTO),IF,INTEGER
$,EXTERNAL,RETURN
DOFOREXTERNAL=IF,GOTO
DOFORRETURN=EXTERNAL,EXTERNAL-IF
IMPLICIT(RETURN)=LOGICAL(RETURN)+LOGICAL(RETURN-IF)
ENDDO
IMPLICIT(IF)=IF
IMPLICIT(EXTERNAL)=IF
DOFORRETURN=IF,GOTO-EXTERNAL
WRITE(IF,'(''$ '')')
ENDDO
DOFORRETURN=IF,EXTERNAL
WRITE(IF,'(''$''I4)')IMPLICIT(RETURN)
ENDDO
WRITE(IF,'( /)')
DOFORRETURN=IF,GOTO
LOGICAL(RETURN)=IMPLICIT(RETURN)
ENDDO
ENDDO
END This is (printable) character by character identical to the first version I presented. I am not 100% sure that F77 allows semicolon to put multiple statements on one line; there is one case of it in the above code, and both the F77 compilers we had access to accepted it. I could have filled up the lines to col.72 to make the code even more compact , but I'll leave that as an exercise for those with extreme tastes in code layout ...
lewist57 wrote: 2) no DATA statements or other initialization of the varables? We had denied ourselves the use of literals (but had to lift those restrictions for the strings in the WRITE statements).
However: F77 specifies that integer values are initialized to zero. Fortran loops are always executed at least once. So INTEGER starts at 0, and when running
DO FOR IF = INTEGER, INTEGER; ENDDO the loop will increment INTEGER from 0 to 1. Then we create 2 by adding IF + IF, and 13 by INTEGER*INTEGER*INTEGER*INTEGER-INTEGER-IF (i.e. 2*2*2*2 - 2 - 1).
In principle, we could have created ASCII character codes for the string constants in a COMMMON block, and addressed the block alternately as integer or string. That would require knowledge about how a string is laid out in memory, and the code would have to be split in two files (one file can only interpret the common block in a single way). I believe that Hollerith constants are defined to be a plain octet sequence in memory - no descriptor, no terminator - but Hollerith was left out of F77 (and all later versions), wasn't it?
Today, I have forgotten why we have this no-op subroutine named FUNCTION. It could be for some other strange initialization purpose. All I remember is that it had to be there. If I dig up an F77 compiler and debugger, maybe I could tell. My life does not depend on knowing the answer, so I doubt that I will acquire and install an F77 for the sole purpose of finding out
|
|
|
|
|
A couple more things
1) I think only IV/66 always went though a do loop, and 77 and beyond does not
2) I asked about the space between FOR and IF because there is not DO FOR ..... loop. I ran your code through Simply Fotran compiler set for legacy code and it thinks "FOR IF" (or "FORIF") is a variable, which does fit the syntax DO FORIF = variable, variable.
Pound to fit, paint to match
|
|
|
|
|
IIRC a satellite was once lost because someone did something like
DO 10 I = 1. 10 (which is an assignment statement setting a real variable named DO10I to 1.1) rather than
DO 10 I = 1, 10 (which is a loop from 1 to 10 using an integer called I ending at statement with a label of 10).
I never really liked F77 as it dropped Hollerith constants and ending loops with ENDDO instead of CONTINUE seemed alien. However, I did appreciate the introduction of the block IF statement; especially as I had written and used in production code a pre-processor that supported structured constructs (including IF ... END IF) that generated FIV/66 code - obviously it was written in FIV/66.
|
|
|
|
|
jsc42 wrote: ... I had written and used in production code a pre-processor that supported structured constructs (including IF ... END IF) that generated FIV/66 code Something like Ratfor[^]? I used it back in the day.
Software rusts. Simon Stephenson, ca 1994. So does this signature. me, 2012
|
|
|
|
|
Not as sophisticated as that! Mine still used FORTRANesque syntax; in fact, it looked not dissimilar to F77 but that was coincidental as I hadn't come across F77 at the time.
|
|
|
|
|
lewist57 wrote: 1) I think only IV/66 always went though a do loop, and 77 and beyond does not In my basement, I found the manual for one of the two F77 compilers we were using (I never owned a manual for the other), and to my surprise, you are right! The test is done at the top of the loop. I am really surprised that this didn't break thousands of old Fortran programs - changing the semantics of something as fundamental as a DO-loop is rather sensitive!
Anyway: This loop is executed once; it isn't terminated until the DO-variable is larger than the terminal value. "DO I = 0,0; ENDDO" is executed once, and I is incremented from 0 to 1.
2) I asked about the space between FOR and IF because there is not DO FOR ..... loop. I ran your code through Simply Fotran compiler set for legacy code and it thinks "FOR IF" (or "FORIF") is a variable, which does fit the syntax DO FORIF = variable, variable. jcs42 reminded us of the Mariner crash, where a comma in a loop spec was mistyped as a decimal point, making the DO statement being compiled as an assignment. In the loop in the code I presented, a comma is used, so that DO statement would never be interpreted as an assignment.
I checked the old Fortran manual, which describes the "DO FOR ... ENDDO" with the "FOR" marked as optional. This might have been a syntax proposed for F77, but taken out a short time before the standard was nailed. Starting to use a standard before it has formally passed all formal approvals is quite common, and it took a long time for the F77 proposals to be sorted out and churning it through the mill; it did not happen in 1977! Especially if the standardization process has been plagued by fights between competing viewpoints, you may see lots of last-minute changes - and the F77 process was most definitely a war ground. So maybe both our compilers included the construct, as an extension of F77, because important customers had already started using it. With "FOR" being optional, it can simply be removed; it shouldn't affect the program behavior.
However, the manual identifies the semicolon, for putting several statements on a single line, as an extension. I came across a web page describing new features of Fortran 90, including this, so obviously both our F77 compilers were ahead of their time
Now that you have tried to compile the program: Will you remove the 'FOR's and tell us if the program produces a meaningful output? I suspect that the lines will be left justified (that's what we got with both compilers) - they really should be centered, symmetric around a vertical line. If you know just a little bit of math, and the output is correct, you should be able to recognize it, even when left justified!
|
|
|
|
|
Thanks for your response.
The Simply Fortran 3 complier did not complain about the "FOR" between DO and variable, I had never seen that syntax, and just wanted to make sure this was not a misunderstanding on my part. My recollection is that prior to, and including F77, there were dozens of "dialects" of Fortran because folks just wanted to add features in their compilers that were not in the standard, resulting in difficulties in porting the program between various machines and compilers.
I also have the Intel Fortran compiler which is supposed to be compliant with F66, and will try to run it through that when I have the time. All of my work is being done as a console program under Windows 10, using the Simply Fortran 3 program.
I am in the process of reverse engineering the code (manually refactoring to a certain degree), and will be happy to share the revised code when done. I do have a few questions for you, my apologies for asking; they involve subroutine SUBROUTINE:
1) The first line in the subroutine (re)declares the variables. I am a little rusty on subs, but it seems that this would reset them all back to zero? (BTW - I had to explicitly declare the variables in the main program as zero; the Simply Fortran compiler is based upon the GNU fortran compiler, and if you don't initialize the variables, it puts a non-zero value in each uninitialized variable, which messes up your program)
2) The compiler does not like it when you have variables declared as integers in the main program, and then re-declare them as one dimensional arrays within the sub (eg - IMPLICIT and LOGICAL)
3) I am reworking the program as a simple console program running under Windows 10. I don't seem to recognize the following syntax:
WRITE(variable, 'string')
what are these WRITE statements actually doing with the variable and then the string?
Last but not least, it appears that the subroutine FUNCTION does absolutely nothing. I did a listing of the variables before and after calling FUNCTION, and there were no changes. Was this by design?
Overall, this is an excellent program to torture new users of Fortran to drive home the point that even though you could use keywords as variables, you really should not. I was also a TA as a mechanical engineer back in the '70s, and would also do things like this to my students.
Pound to fit, paint to match
|
|
|
|
|
lewist57 wrote: My recollection is that prior to, and including F77, there were dozens of "dialects" of Fortran because folks just wanted to add features in their compilers that were not in the standard, resulting in difficulties in porting the program between various machines and compilers. That certainly matches my memories. I guess that is why the discussions to create the F77 standard looked more like mad dogs fighting than like academic style discussions
lewist57 wrote: I do have a few questions for you, my apologies for asking; they involve subroutine SUBROUTINE: Feel free to ask! I fear that I will have to disappoint you: I haven't looked at this code since my student days, 40+ years ago. The detail justifications for how we did it is mostly forgotten long time ago. And, I never programmed Fortran professionally. We did a few projects at the university. Since then, Fortran has just been an entry in the 'competence list' in my CV (and today, that must be considered a lie).
1) I am not sure about the (re)declaration of the values in SUBROUTINE. The code assumes that variables are initialized to zero - I thought that was defined by the Fortran standard. We had denied ourselves the use of (numeric) constants. If you want to honor this requirement, you may e.g. zero INTEGER by adding as the first statement "INTEGER = INTEGER - INTEGER".
2) I am sorry - I can't explain this one. If the compilers we used did allow such redefinition (the non-array arguments are never used), it would be an excellent way of confusing the code reader. Maybe that is why we did it that way. I don't remember.
3) The two arguments are the logical unit number, IF (= 1) being console output. The second argument is a format string. The first WRITE loop is the one indenting the line properly, which apparently is not valid in F77, as both our F77 compilers failed to do proper indentation. Maybe the format string could be updated to F77 standard; it just specifies two space characters to be output. The format is that of the FORMAT statement which requires the format string to be enclosed in parentheses, so the '(' and ')' are just to fulfill this requirement. It seems like the '$' is a quoting, to prevent the tokenizer from stripping away the space.
For the second WRITE loop, it seems to me that the format string could have been written '(I4)'; I have no recollection of why the '$' is there.
I have a vague memory of FUNCTION being there for a purpose, the program not working without it. I may be wrong - maybe we put it in there just to confuse people to believe that it had a purpose
I really appreciate that you spend time trying to make this program work! Unfortunately, I am too far away from you to give you - in the hand, in the meat world - the 🍺 I told I would give to the first one telling what the output of this program is, but you seem to be one who is likely to win the prize. If you decide to spend a vacation in Norway, I'll gladly buy you one!
lewist57 wrote: Overall, this is an excellent program to torture new users of Fortran to drive home the point that even though you could use keywords as variables, you really should not. And then ... Have you noticed my entries in the thread 'General Programming | Algorithms | Aide pour un programme langage c'? Through a lengthy discussion, in particular with jschell, I argue in favor of a programming language being defined in terms of a parser tree, with no (reserved or just predefined) keywords. An IDE working directly on a parse tree would represent structural information in binary format, making it visible to the user by e.g. typographic highlighting, but requiring the user to create structure by function keys or menu selections, rather than by keywords. Just like a document processor - it has no (reserved) keywords that you cannot use freely in your document, and there is nothing you can put into the text body that will confuse the binary structure information.
I really wish we could have a language defined by its abstract syntax rather than by textual keywords. But I am not holding my breath waiting for it to appear.
|
|
|
|
|
Some more progress:
1) the darn dollar sign $
From your response: "The first WRITE loop is the one indenting the line properly, which apparently is not valid in F77, as both our F77 compilers failed to do proper indentation. Maybe the format string could be updated to F77 standard; it just specifies two space characters to be output."
So my interpretation is that WRITE(IF, '(''$ '')') simply writes two spaces, and can be replaced by write(*,*)' ' where there are two spaces between the single quotes. That makes a lot of sense. The $ sign has been used in various compilers to indicate a macro, or as a suppression of line return, so that helps a lot. It might be some compiler specific feature.
2) The compiler is not happy with the first do loop in SUBROUTINE:
DO FOR RETURN = EXTERNAL, EXTERNAL - IF
IMPLICIT(RETURN) = LOGICAL(RETURN) + LOGICAL(RETURN - IF)
END DO
The complier will not throw an error or warning (either when compiling or running), but as I see it, the first time through EXTERNAL = 0 and IF = 1, so you are doing a negative increment
DO FOR RETURN = 0, -1
when I test a program with a do loop like above, there are no errors or warnings from the compiler, and the program runs, but it apparently just skips over the do loop and its contents.
For example, this code
write(*,*)'before do loop'
do RETURN = 0, -1
write(*,*)'inside do loop'
end do
write(*,*)'after do loop'
produces the following output:
before do loop
after do loop
3) The declaration of variables in the main program have IMPLICIT and LOGICAL as scalars, and then are redeclared as arrays in SUBROUTINE; there is no definition of the size of the array (should be 13). Likewise, EXTERNAL is declared as an real in the main program, and redeclared as an integer in SUBROUTINE.
4) last but not least, F66 and F77 limited variables, subroutines, functions, program names to 6 characters; how did your compiler accept the ones that are 7 or more characters long?
Thanks again!
Pound to fit, paint to match
|
|
|
|
|
I just spent two hours debugging a problem with my handheld NES emulator (ESP32 based) not loading a bunch of the ROMs that I have.
When I read certain files I was getting nothing but zeroes back. The file was the right size but it's like all the data was zeroed.
I was pulling my hair out because the same copy of the file on my PC read fine. The one on the SD card I copied from the PC did not.
Turns out the copy was bad somehow. Nothing wrong with my code. However, it seems like (I think, but I need to test more) that if I copy them with long names intact they don't work. If I rename them to a shorter name first, they work. Either way, everything looks like it works until you open the file.
To err is human. Fortune favors the monsters.
|
|
|
|
|
So the doohickey uses the old Windows 95 file scheme? Where your could "name" your file something long but in reality it made an 8.3 name for the file in the background?
I’ve given up trying to be calm. However, I am open to feeling slightly less agitated.
|
|
|
|
|
I don't think so. This seems to all be on my PC end, and I'm on Win11.
I need to investigate this more today before I can be sure about any of this. I've replicated the problem a couple of times but not methodically.
To err is human. Fortune favors the monsters.
|
|
|
|
|
How long filenames are we talking about?
More than 260 characters?
|
|
|
|
|
Oh gosh no. Maybe 20 characters, with spaces. Stuff like "Bionic Commando (U).nes"
To err is human. Fortune favors the monsters.
|
|
|
|
|
Maybe the empty spaces?
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
Shoot. Work distracted me from troubleshooting what the root issue was and forgot all about it. I should dig into that.
To err is human. Fortune favors the monsters.
|
|
|
|
|
hope you find it.
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
For what it's worth, I've seen FAT32 implementations in the wild that didn't handle space characters in filenames correctly or didn't like complete file paths longer than a value much less than Windows' 260 characters.
For example, the sound system in my car let you plug a FAT32 Flash drive in and it would play any MP3's it found. There were some limitations however. You could only have 99 files per folder, and 99 folders hanging from the root. File path length had to be <16 characters.
Software Zen: delete this;
|
|
|
|
|
Any software that has ever been in contact with *nix or *nix developers, even if "ported" to other OSes, is likely to have problems with spaces in filenames. Also be prepared for non-*nix path separators and non-7bitASCII being a potential source of trouble. Even after "porting", expect issues with letter casing.
|
|
|
|
|
line breaks, return carriage and end of file can give / have given some headaches too
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
Bionic Commando???
That was a great game!
I had to hack my C64 version to give myself 255 lives to beat it!
Or else I found the logic that subtracted a life and changed it to NOOPs.
A little fuzzy now, but I was able to finish it.
|
|
|
|
|
Win95? 8.3 format goes back a loooong time before windows was dreamed of.
|
|
|
|
|
|
|
Good point ... Somehow, I doubt the sanity of the inventor of this ...
|
|
|
|
|