16

Pascal was intended, in part, to be a simple language to implement. Some of the design decisions reflecting this are

  • Declarations/definitions must be given in a strict order (labels, constants, types, variables, routines); they can't be mixed. (The order allows for the constants to be used in subrange types, and for the types to be used in variable declarations.)
  • Every entity must be declared in some way before use.
  • The symbol denoting a subrange is .., not ..., which can simplify lexical analysis (all punctuator tokens are at most two characters long.)
  • Arrays must have constant bounds.
  • The language does not have the concept of a constant expression, so that 5..10 is OK but 3+2..10 is not.
  • Pointers are restricted to record types created with new.

However, there are also some bewildering decisions (as someone who has recently implemented a parser and semantic analyzer for Pascal):

  • The forward convention, where parameters are omitted at the actual point of definition, is beyond bizarre. And it requires keeping around more parameter information than usual in order to process the body of the subsequent non-forward declaration in the correct lexical environment. People have rightfully pointed out that this isn't actually unusual. Omitting parameter specification is just weird to me, although maybe it's because I'm accustomed to C's convention for prototypes and declarations, where the information is repeated. For what it's worth, Donald Knuth dislikes it as well.
  • Standard procedures and functions can take special arguments not allowed elsewhere in the language, such as width specifiers, and many of them are variadic.
  • Statement labels are numeric.

This question is about the last point: Why have numeric labels? If labels were symbolic, then you could use your existing data structures for maintaining the current environment of identifiers for labels as well.

Putting the language in its historical context makes the choice no less odd:

  • Algol W had symbolic labels.

  • The one part of Algol 60 that most people seem to have agreed was a mistake was the existence of numeric labels (in addition to symbolic labels—at the very least, Pascal sticks with only one kind). Here is what Dahlstrand, Goteborg, and Naur have to say about this in Algol Bulletin AB10.3.

    The admission of integers as labels will produce some peculiar possibilities, like the following:

    procedure Pop(Q); procedure Q; beginQ(3); … end;
    procedure Pip(A); label A; begingo to A; … end;
    procedure Pap(B); real B; beginqB; end;
    Pop(Pap);
    Pop(Pip);

    Evidently the number 3 appearing within the body of procedure Pop will in the first of these two procedure statements be used as a number, while in the second it will be used as a label.

    We do not want to suggest any formal change of the language, since in spite of the peculiarity the above example is well defined. On the other hand we do want to disrecommend the use of integers in labels in actual programs. We would like to see them die from disuse. That we do not accept them in our translators goes without saying.

    Even Randell and Russell's Algol 60 Implementation, which otherwise goes to extraordinary lengths to implement the “hard parts” of a then-complex language, does not discuss the handling of numeric labels except at the very end; their compiler accepted only symbolic labels.

    Such atrocities as Pop/Pip/Pap aren't possible in Pascal, but regardless, every other Algol derivative known to me uses symbolic labels.

20
  • 6
    forward is kind of an issue fix in hindsight to allow the rare case of alternating recursion, otherwise not compatible with the idea of having everything defined before usage. We all know how much Pascal teachers love to use recursion :)) Numeric labels are a solution of essentially the same issue: being able to handle something that hasn't been defined). By using numbers the compiler can assume that they are labels and nothing else and assign according attributes in advance.
    – Raffzahn
    Jul 11 at 19:27
  • 3
    @Raffzahn But in Pascal you do declare labels, at the start of a block: label 1,2;.
    – texdr.aft
    Jul 11 at 19:35
  • 3
    No, label declaration is only required for external labels, that is labels defined in a procedure to be accessed fron another procedure. Kind of like an 'external' definition in Assembler. Labels within a procedure do not require such. - at least according to the original 1970 manual (wich does not know forward).
    – Raffzahn
    Jul 11 at 19:44
  • 3
    The pap/pop/pip example does work!
    – Leo B.
    Jul 11 at 21:50
  • 3
    @Mast No. One has to distinguish between labels and line numbers. One did use line numbers in next to all languages to keep the source organized and patchable, while labels were a language specific issue, including if they could, have to or may not be numeric. BASIC is an outlier here, as they merged line number and label (by using only line numbers) for simplicity.
    – Raffzahn
    Jul 12 at 15:51
17

[Preface: It's about genuine Pascal history, thus I will answer this based on the original 1970 Pascal Manual. Since then many different implementations have been made, so it might not be true for all variations out there]

Why have numeric labels?

To start with, one has to keep in mind that Pascal is intended to do away with labels and goto. It is not to be encouraged nor should it get much support making its usage easy. Still providing both is rather about offering a last resort in complex situations, more of a hack to make it - the black sheep of Pascal :))

Using an integer is kind of an easy escape during parsing when looking at how the original 1970 Manual The Programming Language Pascal (*1) defines a Compound Statement (9.2.1), which includes the label definition:

Compound Statement in Pascal

A compound statement is thus either a statement, or a label in front of a statement, concatenated by a colon.

Now, when looking what a statement is:

Statement in Pascal

It's easy to note (*2) that all possible variations (assignment, procedure, goto and structured) start with either an identifier or a keyword - which both always start with a non-numeric (letter) character. Thus, if the parser detects a numeric character where a compound statement should start, it can go ahead, collect up to 4 of them (Labels may only go 0..9999), look for a single colon, assign the actual location to this label, and continue with parsing a statement (but no label).

That's the whole magic here.


Well, that plus the issue that labels can be forward references which are not defined at the point of usage in a goto statement. Which BTW is another oddity in Pascal, as the language is in general built in a way that everything used has to be defined before usage. Unlike often assumed, the label declaration within a procedure declaration is only needed for labels that are supposed to be accessed from outside a procedure as the goto definition explains:

Goto Statement in Pascal

Essentially the label declaration is much like an EXTERNAL declaration in Assembler (or C). I guess, since goto already breaks the whole idea of structured programming, Wirth didn't care to provide a nice solution, but simply hacked his way to satisfy a few exceptions, which he may have hoped to go away :)


Speaking of forward (and since it has been mentioned in the question), the forward statement to allowing to define a procedure declaration without its implementation is something Pascal only acquired later, kind of an issue fix in hindsight to allow the rare case of mutual recursion. Something like:

Procedure Two; forward; 
Procedure One; 
begin  
  WriteLn ('Procedure One');  
  Two;  
end;  
Procedure Two;  
begin  
  WriteLn ('Procedure Two');
  One;  
end;  

(*3)

That is, two procedures calling each other. Without a forward definition Two could call One, but not the other way around. There is no way to formulate this in a sequential source file without a way to tell the compiler something about the second procedure before defining the first. So Wirth had to add a solution.


Since we're already here, the requirement of a complete procedure definition when using forward and leaving out all the details when writing the deferred statement part serves two purposes:

  • The compiler needs to know all details of a procedure when it is to be called.
  • Not writing any of the information in the second occurrence avoids all possible errors due to conflicting definitions.

These two go hand in hand. Pascal wants to know everything about a procedure when it's called (*4), so it has to be there upfront - and there is exactly zero need to write it later again. Doing so would not provide any advantage to the compiler, beside a chance to insert new issues that should not arise in the first place.


*1 - The site is BTW a treasure trove for early Pascal.

*2 - With a bit of forwarding :)

*3 - I tried to write some cool character handling here first, until I realized that it would hide the basic idea, so just the basics.

Yes, it's a recursion - we all know how much Pascal teachers love recursion - but there are non-recursive situations as well, except they will need a bit more context, so again not really cool for an easy to understand write-up.

And yes again, I know it's missing a stop condition, but who cares, you get the idea anyway, don't you?

*4 - Think parameter compliance and alike - stuff C omitted and had to 'relearn' the hard way.

3
  • 3
    I was unaware that early Pascal did not require all labels to be declared. The "final" version of the language, described by Wirth and Jensen's Pascal User Manual and Report does. Regardless, I think this is the correct answer.
    – texdr.aft
    Jul 11 at 21:51
  • 4
    @texdr.aft In fact, the label definition and the goto text in the 1970 Manual do leave some room for interpretation, while the 1974 one is much more clear - plus puttin a way bigger emphasis on not using goto when ever possible. Then again, no language is perfect in it'S first iteration - there are way to many nice litte special cases :))
    – Raffzahn
    Jul 11 at 22:12
  • @Raffzahn /it'S/its/
    – JDługosz
    Jul 14 at 13:56
12

Pascal can be parsed without using a table of user symbols. If general symbols were allowed as labels, a compiler that encounters a user identifier when a statement is expected would have no way of knowing in advance whether it was a statement label without having to refer to a symbol table.

As for the way forward declarations work, it simplifies the process of single-pass code generation. A compiler can generate a stub for a forward-declared function and treat the address of that sub like the address of any other function. Once the real function is defined, the stub can be made to call the real function, either by patching the stub or by having the stub jump to an address stored in a variable that will get initialized with the address of the real function. Code which would want to call the function can call the stub just as it would any other function.

5
  • 1
    Right, the need for forward declarations is clear. The problem is that in Pascal you include parameter information at the point of the forward declaration, but not at the point of the real definition, so the compiler needs to hold on to the information.
    – texdr.aft
    Jul 11 at 19:43
  • 4
    @texdr.aft: For every function that has been declared, the compiler will have to keep track of everything but the parameter names in order to handle function calls. Keeping the names while process a function and then jettisoning them once a function definition was complete (but keeping the argument type information) was probably seen as harder than simply keeping the names, and would offer the benefit of allowing diagnostic messages to identify mismatched arguments by name rather than position.
    – supercat
    Jul 11 at 19:48
  • 5
    It is logical (at least to an academic language designer) to enforce the fact that nothing can ever be declared twice. That way, nothing in the program text can ever be inconsistent. (And by the same principle, you need to full parameter specification at the point of the "forward" declaration, otherwise you can't check the "forward" use of what you declared.
    – alephzero
    Jul 11 at 20:54
  • 2
    If also avoids the "no reserved keywords" nonsense of a language like PL/1 where IF (GOTO) THEN GOTO IF; might (or might not) be part of a legal program.
    – alephzero
    Jul 11 at 21:11
  • 2
    @texdr.aft Sure, but it needs to hold on to that information (parameter declaration) anyway - how else should it check for parameter matching? As soon as a procedure is defined, it's definition needs to be stored. Using forward just deffer the compilation of 'executable statements' (aka code) until later.
    – Raffzahn
    Jul 11 at 21:40
7

This is not an answer as I don't know the real reason. It is just a comment about parsing

label:

In pascal

varname:

is expected to be followed by either = or a variable type. If a statement were added, then parsing would be a lot more complicated. If, however, you get

number:

it is relatively unique. If it is followed by anything else other than a statement, it is a compilation error.

6
  • 5
    Surely any decent parser/lexical analyzer would treat := as it's own symbol, rather than : followed by =. But I can see how a number makes recognizing a label easier.
    – texdr.aft
    Jul 11 at 19:39
  • 2
    It depends on how you write your lexical analyser/scanner. Being a teaching language, students could do all sorts when writing their scanner. If you are a teacher, you don't want your students to be bogged down with complex problems. The better ones would pick out := as a symbol but the struggling ones might not.
    – cup
    Jul 11 at 19:51
  • 6
    You are applying 21st century (and probably multi-pass) compiler design to a mid-20th century problem. Suppose you adopt the simplest possible way to write a one-pass compiler - i.e. "read one input character, process it completely, rinse and repeat until end of input." Sure, you wouldn't do it that way using lex and yacc, but they hadn't been invented yet.
    – alephzero
    Jul 11 at 20:59
  • 3
    @alephzero If you're talking to me, then yeah, you're right :-). But I was also basing my statement on the P4 compiler developed around the same time as the language, which does treat them as separate symbols.
    – texdr.aft
    Jul 11 at 21:15
  • 3
    I'm just recalling what my classmates did during my 1975 compiler course. We were writing one-pass compilers for a cut down pascal type language. Not everyone worked out the state machine correctly and, being students not everyone knew how to connect data input with a state machine.
    – cup
    Jul 11 at 21:20
1

It should be noted that some implementors of Pascal compilers have, like you, questioned this restriction, and decided to allow alphanumeric labels as a language extension. For example:

  • Turbo Pascal (mentioned on page 48)
  • Compaq Pascal (Section 3.2, noting that this is provided "as an extension".)
  • Free Pascal (Though, because goto is "evil", you have to explicitly opt in to allowing it with a compiler directive.)

This does not break Pascal's single-pass compilation model, due to the requirement that all labels be declared before use.

So the question, then, is why the original definition of Pascal published by Niklaus Wirth in 1970 (referenced in Raffzahn's answer) used numeric labels. The text does not give a rationale. However, there is a subtle hint in the restrictions on goto listed on page 28:

  1. The scope (cf. 10) of a label is the procedure within which it is defined. It is therefore not possible to jump into a procedure.
  2. If a goto statement leads outside of a procedure, then its label must be specified in a label declaration in the heading of the procedure in which the label is defined.

So, if you jump into a procedure, it's an error, and if you jump out of a procedure, you have to declare the label, but if you're jumping within a procedure, you don't have to the declare the label. This exception to Pascal's declare-before-use rule complicates parsing somewhat, so may motivate restricting labels to look different from other identifiers.

Still, this wouldn't necessarily be a deal-breaker for alphanumeric labels, as recognizing a labelled statement only requires checking that the : after the label isn't immediately followed by =, and goto statements are easily recognized by the keyword goto. Maybe this was more difficult with 1970 compiler technology, but I think there's something else inspiring this rule.

And this is just speculation, but possibilities are:

  • Wirth was copying FORTRAN and BASIC, in which all GOTO targets are numeric. (In pre-"structured" dialects of BASIC, all statements had a numeric label, whereas FORTRAN required it only for GOTO targets.)
  • Pascal was intended to be a "structured" language. You're supposed to be using block statements (begin...end) and for/while/repeat loops instead of goto and if...goto everywhere. Pascal's goto statement was intentionally made awkward and ugly in order to discourage programmers from using it. (Though, that raises the question of why implement it at all.)
7
  • 2
    I'm fairly sure the reason for "why implement it at all" was because some users would've insisted on having it. The accepted wisdom at the time was essentially that "goto is necessary and sufficient for all flow control; everything else is just syntactic sugar." Wirth obviously (and vociferously) disagreed, and Pascal was to a large extent his attempt to prove that one could do practical programming without using goto. But at least in the beginning (and, to be honest, for many decades) getting people to use a language without goto at least as a fall-back option would've been a hard sell. Jul 13 at 9:22
  • 1
    I suspect this is the correct answer. Wirth didn't want goto and labels in his language, but his thinking was "if you must insist on bringing Fortran into this, then do it the way Fortran does." Jul 13 at 16:54
  • 2
    @IlmariKaronen Wirth provides support for this hypothesis in "Recollections about the development of Pascal": "In hindsight, one cannot but agree; at the time, [the goto statement's] absence would have deterred too many people from trying to use Pascal"
    – texdr.aft
    Jul 13 at 18:48
  • 3
    @JDługosz Back to a calling procedure or the main program, as many levels of invocation as desired. For example, a non-local goto in Pascal can be used to "throw an exception" in case of a fatal error.
    – Leo B.
    Jul 14 at 17:30
  • 1
    @JDługosz: Pascal allows procedures or functions to be declared entirely within other procedures or functions. Such procedures and functions have access to the enclosing function's variables, but can only be called from that function. The enclosing function will always be in scope when the nested function performs any goto, but in order to process a goto within a nested method, a compiler will need to know whether the target will be within the current method or an enclosing one.
    – supercat
    Jul 14 at 19:13

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.