11

I'm having an argument with my friend, who told me that when she was learning programming in the 1980s, the compiler gave errors without line numbers.

I'm pretty sure that compilers have always given a line number (or card number) for errors, going all the way back to the 1960s, not matter what language (Fortran, COBOL, Algol, whatever), especially considering that even back then, compilers supported programs that were thousands or tens of thousands of lines long.

This kind of sounds like a "you kids today have it so easy.... in my day..." type of tall tale.

10
  • 7
    Seems like, if we can find one vintage compiler that does not give line numbers with error messages, that makes the answer "no". Aug 5 at 21:55
  • 9
    @another-dave Black Swan questions are ill defined by nature. Even if all we find is an endless number of White Swans (compilers that point out error lines), it does not prove that there is no Black Swan.
    – Raffzahn
    Aug 5 at 22:45
  • 5
    @JoelFan College students especially were exposed to strange one-off tools. Think of teachers doing their own compilers. Quite common especially in the early days (of each iteration).
    – Raffzahn
    Aug 5 at 23:08
  • 2
    Can you ask her what type of system she remembers using? I.e. Digital, IBM, Control Data Corporation, Data General, etc.?
    – LAK
    Aug 6 at 2:30
  • 6
    It was (and is) certainly common for a runtime error to just produce "Segmentation fault. Core dumped" with no line number (and source line numbers might not even be present in the executable). Could the friend have been confusing runtime errors (produced by the OS) with compile-time errors (produced by the compiler)?
    – The Photon
    Aug 6 at 15:40
23

In some sense, the question is ill-defined. Error messages themselves often did not need to include line numbers, because the typical paper-to-paper compile-and-run cycle would already be producing a (line-numbered) listing.

Compile-time error messages would then appear underneath the erroneous line, often with an arrow or similar mark pointing to the character where the error was detected.

The line number could be discovered from the listing, but the error message did not itself mention the line number.

12
  • 1
    It occiurs to me - what use is a line number in a thousands-of-cards program? Line numbers do not appear on the cards. So when you tell me my error is on line 1234, I'll have to count to find the 1234;th card. (Sequence info in columns 72-80 are not line numbers, they're just card content like the rest of the card). Contextual information is much more useful. Aug 5 at 23:31
  • 2
    @another-dave Unless the sequence numbers appear in the listing, then you can go from the line number to the sequence number to the card. Aug 6 at 1:11
  • 2
    Who punched sequence numbers? Not I. They were not mandatory. FWIW, I think the systems I used would have listed the whole card,, but early IBM 70x systems would not - the computer/card reader could only read 72 cols. Aug 6 at 2:16
  • 3
    As a working programmer (not a student!) I would never punch up a long program anyway. I would write it on paper, desk check the logic etc, and then let the professional punch card operators do the job. Writing sequence numbers on the paper input was very useful, because if you discovered a logic error you didn't erase and rewrite lines, you appended the corrections to the end with the correct sequence numbers and let a sorting machine shuffle them into the correct order after they were punched.
    – alephzero
    Aug 6 at 2:40
  • 3
    @another-dave When a subroutine had 10 lines each saying "N = 0" and only one of them should have been "M = 0", sequence numbers on the cards might save you making a few more errors before you fixed the right card :)
    – alephzero
    Aug 6 at 2:43
16

There is an online copy of a paper titled Compiler Error Messages Considered Unhelpful by Becker et al.

Partway through the paper, there is a discussion of error messages in FORTRAN, Logo, Basic, and Pascal. These are languages that were extensively used for teaching programming in the 1960s and 1970s. It doesn't get down to line numbers, but it does deal with localising errors based on error messages. There are several languages where unbalanced parentheses or brackets aren't going to be detected until the end of the source file. A line number here is not very helpful for localising the error.

Many early versions of FORTRAN did not interpret columns 73 through 80 of the source program. They were generally used for including a card number (in effect, a line number) on every line. Any error reporting scheme that included these columns would end up reporting line numbers, provided the author had used them for this purpose.

10
  • One note: the first FORTRAN was on computers (701, 704) that could only read 72 columns (read row-wise, two 36-bit words per row, program in a "copy" loop, one copy instruction per half-row, conversion to characters after the card was read) so 73-80 could not be known. Aug 6 at 13:16
  • 11
    Worthwhile to mention that the mismatched braces thing is not limited to retro computing, but even fairly modern languages will sometimes just give you the finger and leave you to figure it out on your own. (Not to mention many interpreted languages that technically don't have a compiler but will give you such an error when you try to load your program/function/etc....thanks JavaScript and Oracle.) stackoverflow.com/questions/7597752/… Aug 6 at 18:06
  • 4
    Perhaps we should also mention that the actual "error message" was often to be found posted on the wall in the computer lab, or else in a manual which you could not locate. Compiler output merely mentioned the error number for you to look up. Kids today, eh? Aug 6 at 23:01
  • Odd bit of trivia. If you take 72 characters, at 8 bits per character, you get the number of bits in 16 accumulators, as in the PDP-10. 72*8 == 16*36 Aug 7 at 10:36
  • 1
    One language where error messages seem to leave you in the dark is SQL. I think this has to do with the syntax of the language. The SQL interpreter can't always distinguish between a misspelled data name and a misspelled keyword. Aug 7 at 10:42
12

Here's a slightly truncated job output from an IBM 1130 Fortran compiler, c.1968, as run in an emulator:

// JOB
// FOR
*ONE WORD INTEGERS
*LIST ALL
*IOCS(1132 PRINTER)
      DO 100 I=1,185,5
      WRITE(3,90) I, I
      FORMAT(1X,I8,I8)
  100 CONTINUE
      CALL EXIT
      END
VARIABLE ALLOCATIONS
     I(I )=0000

INVALID STATEMENTS
 C 46 ERROR AT STATEMENT NUMBER 00000+002
 C 28 ERROR AT STATEMENT NUMBER 00000+003

COMPILATION DISCONTINUED

// XEQ

M 12 EXECUTION SUPPRESSED

The FORMAT declaration has no line number: it should be 90. Had I put in line numbers before 100, it would have reported the highest number seen before the error.

The errors are:

  • C46 — FORMAT statement number missing or incorrect in a READ or WRITE statement.

  • C28 — FORMAT statement without statement number.

Another language that's not great about reporting errors is PostScript. While it's interpreted, it will only report stream position of the error, and a display of the top items on the stack. This is fairly nearly useless for all but the very simplest code.

11

Did they? Yes. They do even today. To wit:

% cat bad.lsp
(defun triple (X)
  "Compute three times X."  ; Inline comments can
  (* 3 X))                  ; be placed here.

;;
;; Negate the sign of a number
;;

(defun negate (X)
  "Negate the value of X."  ; This is a documentation string.
  ((- X))

;; main

(format t "hello world ~a~%" (triple (negate 2)))

I've even left included comments in subtly broken example so it is easy to understand. Now when you go compile it with GNU Common Lisp compiler:

% gcl -compile bad.lsp

Compiling bad.lsp.


Error: END-OF-FILE :STREAM #<input stream #p"bad.lsp">
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by APPLY.

%

Granted gcl-2.6.12 on my Debian Buster system has last been updated in 2006, with no real source changes since 2002, but still much more recent than 1980s.

(BTW Fix is trivial in this example, just remove the erroneous parenthesis. It might be nontrivial to find correct one if the program was not so trivial as this one)

Also note that few languages popular today (like SQL, RegEx etc) do not even have a concept of line numbers (even if users often split them to multiple lines for readability). True, often they are interpreted, but in some cases they are compiled, and you won't be helped much by knowing that the error is in the only line of your split-into-hundreds-lines-with-comments-regex.

4
  • 1
    To be fair, in your example the reported error (end of file) doesn't really occur on any line, since the file has been completely read by the time the problem can be detected. But the compiler should definitely indicate what it was reading when the file ended, including the line number of the innermost unmatched left parenthesis.
    – texdr.aft
    Aug 6 at 23:32
  • @texdr.aft No, the error is clearly at line 11 (if you count from 1). But yeah, what you say it is exactly the trouble due to Lisp structure: GCL will only tell you at the EOF that there is error somewhere before EOF, which is useless (eg. no line numbers for error, which OP asked about). If you do match your parenthesis in your code it will compile, eg. (this(is(valid(()()(lisp((that(compiles)(perfectly)))))))()) (though it likely won't link :-) Aug 6 at 23:43
  • What do you mean by "concept of line numbers"? If the input code is text, line numbers are simply a count of newlines in the input. The reason why Lisp has trouble with this is that the input to the compiler is Lisp list structure -- the original text structure has been discarded. But this is unusual among compilers.
    – Barmar
    Aug 7 at 17:11
  • "has no concept of line numbers" was referring to SQL and RegEx, not lisp. If essence, all (non-string) whitespace there is equal as used only as token separator (eg. newline=tab=space), and is thus often removed/replaced/ignored before being compiled/JIT/interpreted. Thus your whole 500 line SQL statement (or extended RegEx) will be the same as 1-line SQL/RegEx as far as its compiler is concerned. Aug 8 at 22:03
7

Here is an actual listing from the FORTRAN compiler #XFAM, running on an ICL 1903A in December 1973 under a single-programming operator's exec.

This part of the listing is little more than what was on the cards. You'll notice the total absence of line numbers. I therefore submit, but cannot prove it since my code had no errors :-) that error messages would have not referenced a line number.

Schoolboy code

So, there we have it: (almost) proof that not all compilers user line numbers in error messages.

9
  • 3
    But couldn't the compiler have referenced a relative line number even without printing line numbers on each line? Finding it wouldn't be so hard - standard paper was 11" long, 6 lines per inch, if there was autoskip over perf that could be factored in (often made it a simple 60 lines per page, as in later laser printes), etc. Aug 6 at 14:04
  • 4
    I believe that rulers exist that measure in units of ⅙", specifically for finding the right place on printout. Aug 6 at 15:14
  • However, others have said that the compiler error would be printed under the line, so you would not need line numbers. My question is really about, was it so bad that you would get an error message with no way to locate the line it referred to, not specifically line numbers
    – JoelFan
    Aug 6 at 15:40
  • 1
    @manassehkatz-Moving2Codidact, that is the most awesome concept I've seen in a while... using a ruler to find a line of code :)
    – JoelFan
    Aug 6 at 16:16
  • 1
    @TobySpeight I used to use 1/6" marked rulers (and also marked typically 1/10 and 1/12 for 10 and 12 CPI) all the time to format output either to match customer specs or to fill in pre-printed forms. Aug 6 at 16:22
4

The code generated by Turbo Pascal 2.0 and 3.0 (and likely 1.0) would flag runtime errors not with a line number, but with the address of the generated machine code that triggered the fault. This might not sound very useful, except that Turbo Pascal generated machine code directly from source code, and included a "find runtime error" function that prompted a user to type in a machine-code address and would then run the compiler without sending output anywhere, counting how many bytes were written. When the proper number of bytes were written, the process would stop and open up the editor at whatever part of the program was being compiled at that moment.

6
  • 4
    Run-time errors, not compile-time errors? Aug 6 at 18:06
  • 1
    @PeterMortensen: Run-time errors, but generated by code produced by the compiler for the purpose of being fed back into the compiler to yield a source-code location.
    – supercat
    Aug 6 at 18:11
  • 2
    The key is that location in compiled code was reliable /consistent since unlike most previous compilers, there was no separate linking stage. It effectively have you line location without having to store line numbers in the compiled code, which would be significant overhead, especially in the 8 bit (64k code data and os) version of turbo pascal. Aug 6 at 21:30
  • 2
    Now I'm thinking that she may have been remembering run-time errors and is confusing them with compile-time errors. A run-time error could definitely not include any indication of where in the program it occurred, especially back then. Of course Turbo Pascal was ahead of its time in that respect :) Actually I think it was often possible to trace the compile time error back to the line of code, even in those days, but it involved extra steps and knowing how to read core dumps and enter memory addresses / offsets into a debugger. Similar to what you describe with Turbo Pascal but more arcane
    – JoelFan
    Aug 6 at 21:50
  • On the PDP we'd get address errors like this from Pascal, but they're runtime errors. Not compile time errors. Typically, these were simple index out of bounds errors. To find them, you have to compile to Macro with source code comments, assemble the file, and then search through the listing for the address in question and then scan up to find the source code line. This took forever and enormous disk space. I had my account locked by administrators once because I had a terminal time out with one of those listing files for being WAY over quota. Aug 6 at 22:54
2

Even today, when using languages where use of an identifier will implicitly import it, misspelling an identifier will often cause a linker error which supplies the names of the identifier and the file in which it was identified, but gives no clue as to where within the file it was identified. While a linker error isn't an error in the compiler per se, it would be an error produced by the build system.

Additionally, there may be some cases where a compiler generates assembly code and the assembler generates an error without having any reference to the source line available. The most common situation where I've seen that is where a compiler estimates that a branch will be within range to avoid a springboard, but the assembled code ends up being slightly larger than expected. That would ideally never happen with a good compiler, but compiler designers would have to trade off the possibility of such errors with the cost of needless springboards.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.