It was 50 years ago this year when the Fortran 66 standard was published. Once you fix the backwardness of the text and the single-character typo in every line, you will get a working Fortran 66 program. Some relevant details:
- If suitable packages are installed, you can compile it on a Linux system with g77 -ff66 source.f which will generate a program a.out which you can run.
- Fortran 66 did not have the concept of opening named files. The program writes its output to unit 42, which might have been a printer, teletype, or even a card punch. On modern computers, this gets written to a file named fort.42 in your current directory.
- All that 1HA, 1HB, ... nonsense is Hollerith string data. Fortran did not get the CHARACTER data type until Fortran 77, and they stored characters in any available variable (usually an array of integers, as many per integer as the machine allowed, though storing just one per integer like this program does was permitted). The number before the H indicated how many of the characters immediately after the H were read as string data. The A specifier in the FORMAT statement prints the Hollerith strings.
- Except in Hollerith strings, and in the first 6 characters of a line, spaces did not matter in Fortran 66. You could insert them anywhere, even inside reserved words.
- Only the first 72 characters in each line counted. When Fortran programs were stored on 80-column punch cards, the last 8 columns were often used to store line numbers which could be used to properly re-sort the program if it spilled (there were even machines for this specific purpose). Those line numbers often survived into versions of the code long after punch cards were no longer used.
- The first character was reserved for a comment indicator, which is not used in this program. The second through fifth were used to store statement labels which code keywords such as DO and GOTO jumped to. The sixth, if it contained any character but 0 or space, indicated the line was a continuation of the previous line. One of these occurs in the DATA statement and you can use it to confirm the column positioning.
As suggested in the flavor text, exactly one character in each line of the program is incorrect. When you succeed in correcting the code, you will get this program:
SUBROUTINE OUTPUT(X,R,L) 00000007 IN TEGER X(L),R(L),L,B(28),J 00000008 DATA B/1HA,1HB,1HC,1HD,1HE,1HF,1HG,1HH,1HI,1HJ,1HK,1HL,1HM,1HN, 00000009 1 1HO,1HP,1HQ,1HR,1HS,1HT,1HU,1HV,1HW,1HX,1HY,1HZ,1H ,1H,/ 00000010 10 FORMAT(45A1) 00000011 DO 20 J=1,L 00000012 R(J)=B(X(J)) 00000013 20 CONTINUE 00000014 WRITE(42,10)R 00000015 END 00000016 SUB ROUTINE DECODE(L,C,N,MSG) 00000017 IN TEGER L,C(L),MDL,MSG(L),PRD,I,J 00000018 DO 40 J=1,L 00000019 MSG(J)=C(J) 00000020 PRD=C(J) 00000021 DO 30 I=1,4 00000022 PRD=MOD(PRD*PRD,N) 00000023 30 CONTINUE 00000024 MSG(J)=MOD(MSG(J)*PRD,N) 00000025 40 CON TINUE 00000026 END 00000027 SUBROUTINE UNCOMP(L,B,Z,MSG,MDL) 00000028 INTEGER L,B,MDL,Z(B),MSG(L),J 00000029 DO 50 J=1,L 00000030 Z(J*3)=MOD(MSG(J),MDL) 00000031 Z(J*3-1)=MOD(MSG(J)/MDL,MDL) 00000032 Z(J*3-2)=MSG(J)/MDL/MDL 00000033 50 CONTINUE 00000034 END 00000035 INTEGER FUNCTION FFOS(N) 00000036 INTEGER J 00000037 FFOS=1 00000038 DO 60 J=1,N 00000039 FFOS=FFOS*J 00000040 60 CONTINUE 00000107 RETURN 00000108 END 00000109 INTEGER FUNCTION FIM(N) 00000110 INT EGER LAST,J,TMP 00000111 LAST=0 00000112 FIM=1 00000113 DO 70 J=2,N 00000114 TMP=LAST 00000115 LAST=FIM 00000116 FIM=TMP+LAST 00000117 70 CONTINUE 00000118 RETURN 00000119 END 00000120 INTEGER FUNCTION PUL(N) 00000121 INTEGER LAST,J,TMP 00000122 LAST=2 00000123 PUL=1 00000124 DO 80 J=2,N 00000125 TMP=LAST 00000126 LAST=PUL 00000127 PUL=TMP+LAST 00000128 80 CONTINUE 00000129 RETURN 00000130 END 00000131 INTEGER FUNCTION CANK(J,K) 00000132 INTEGER I,J,K,FFOS 00000133 CANK=1 00000134 DO 90 I=1,K 00000135 CANK=CANK*(J+1-I) 00000136 90 CONTINUE 00000137 CANK=CANK/FFOS(K) 00000138 RETURN 00000139 END 00000140 INTEGER Z(45),Q(45),I,C(15),MSG(15),N,JET,FFOS,FIM,IE,CANK,PUL 00000207 REAL ELG 00000208 IBENJ(ELG)=INT(EXP(ELG)) 00000209 C(1)=FIM(24) 00000210 C(4)=PUL(2)+FFOS(4)*FFOS(2) 00000211 C(2)=FFOS(5)*FIM(11) 00000212 C(7)=IBENJ(4.0)*FIM(15) 00000213 C(11)=CANK(16,7) 00000214 C(6)=CANK(15,7)+CANK(14,6) 00000215 C(3)=IBENJ(7)*FFOS(4) 00000216 C(13)=C(11)+IBENJ(9) 00000217 C(15)=PUL(21)+CANK(14,7) 00000218 C(8)=C(1)-PUL(19) 00000219 C(12)=PUL(20)+CANK(17,4)+IBENJ(6.0)+PUL(9)-FFOS(1) 00000220 C(13)=C(13)+PUL(10)+PUL(8)+IBENJ(4) 00000221 C(6)=C(6)+PUL(5)+IBENJ(3) 00000222 JET=FFOS(4)+FIM(5) 00000223 C(15)=C(15)+PUL(10)+IBENJ(4)+CANK(4,2) 00000224 C(8)=C(8)-PUL(16)/FIM(3)-PUL(9)-IBENJ(0.0) 00000225 N=FFOS(8)+FIM(17)+3*FFOS(CANK(4,3)) 00000226 C(11)=C(11)-FIM(16)+IBENJ(4)+FFOS(3) 00000227 C(5)=FIM(23)+FIM(19)-IBENJ(6.0)-FIM(7)+FIM(3) 00000228 C(14)=IBENJ(10.0)-IBENJ(4.0)-IBENJ(0.0) 00000229 C(9)=FIM(10)+FIM(24)/FIM(3)-FFOS(4)/FIM(3) 00000230 C(4)=C(4)*(IBENJ(5)-CANK(6,3))+MOD(C(2),2) 00000231 C(7)=C(7)+CANK(13,5)+PUL(5)+1+CANK(8,2) 00000232 C(3)=CANK(11,5)+FFOS(2)+C(3) 00000233 C(10)=FFOS(8)+IBENJ(PUL(4))+IBENJ(5)+FIM(4) 00000234 C(1)=C(1)-IBENJ(9.0)+3*FIM(12)+PUL(5)-FIM(3) 00000235 C(2)=C(2)+IBENJ(6.0)+PUL(2)**FFOS(2) 00000236 CALL DECODE(15,C,N,MSG) 00000237 CALL UNCOMP(15,45,Z,MSG,JET) 00000238 CALL OUTPUT(Z,Q,45) 00000239 END 00000240
It prints one line of output:
OVERPUNCH TYPOS AND CORRECTIONS, THEN OVERLAY
Hopefully you were keeping track of where all those typos were in the code. It's finally time to use those three punch cards (the spooky, backward punch cards which have the upper-right corner cut instead of the upper-left corner). The line numbers (which start at 7, 107, and 207 on each page of the program) should suggest that you start a new card for each printed page, and that you start punching in column 7. The punching format is the standard one for these cards.
The correct letters and typos, per line, are:
- page/card 1: SC, EI, AE, 19, OE, JZ, JD, CM, RH, DZ, RP, NF, OP, SU, DO, OD, RO, UH, PW, UG, DZ, UW, GX, DG, DB, ZY, DZ, UA, EA, OF, NM, SG, DG, OL
- page/card 2: OA, TB, EA, GJ, EA, AO, MX, OT, AI, MB, PI, OA, TX, DB, FJ, PO, SZ, LQ, DT, TS, LZ, LF, CG, RP, ER, TH, TK, AO, OJ, CY, OD, FP, RP, DO
- page/card 3: GE, RH, JT, FA, ST, SA, EU, CY, KZ, OU, BX, UW, PY, KE, UV, UW, FI, PY, UA, CR, IO, FR, JX, MG, KT, CS, SO, JT, UA, PN, AU, NX, PO, EW
Although there were variations with some symbols, the notation for letters and numbers needed here was consistent, and can be found in the Wikipedia article on punch cards.
The program output tells you that you need to overpunch the cards, punching the same card twice, once with the typos and once with the corrections. This will give you cards that may have up to four punches in some columns.
If done correctly, when you overlay the three cards, there will be one hole in many columns where you can see right through all three cards. These holes occur in rows (- for no hole) YY11-143947672-6980-9677-0011-4776.
Further overlay this on the shaded section of the program on page 3, backward (so the cut corner is at the left as it should be, the cards have the printed side down, and characters from the program starting at line 223 show through the holes. Reading column by column, this reads: JEFF SIMONCINI JEFF PAUL PUNK BAND.
This clues the answer, the name of their band, FINAL WARNING.
Program Details
Subroutine OUTPUT does just what its name implies. It takes the L integers in array X and interprets each as an index into the array of characters, B, which contains the alphabet plus a space and a comma, writes the corresponding Hollerith strings into the work array R, and writes it to unit 42.
42 is, of course, the answer to life, the universe, and everything, but was not so until 1979 when Douglas Adams wrote The Hitchhiker's Guide to the Galaxy. Anachronistic! Spooky!
Subroutine DECODE performs a crude RSA decryption of the data it receives, treating each element of the array C as a separate 16-bit message and using a 16-bit key. (Actually 15.5 bit, as the program does not take care to handle the numbers overflowing to negative if they exceed 231-1.) It uses a fixed exponent of 17 which is calculated through repeated squaring and multiplication. And yes, RSA in 1966. More anachronism.
Subroutine UNCOMP unpacks the decrypted message data, in which three numbers for the output have been packed in base 29 into a each element of the INTEGER array.
Functions FFOS, FIM, PUL, and CANK are factorial, Fibonacci, Lucas, and binomial coefficients, respectively, and statement function IBENJ is just the integer truncation of the exponential function.
The rest of the program builds up the values and key for the encrypted message in a convoluted way. All the typos in these lines are in the names of the functions.