Compared to FORTRAN and COBOL, Algol is more recognizable because it uses many of the same concepts as C -- that is, structured programming through proper control statements. However, it has one concept that may be unfamiliar to you, nested subprograms. A C program consists of a number of functions that can call each other in any manner. In Algol, a subroutine is embedded inside of another subroutine, or inside the main program. The ability to call a subroutine from another is based on nestedness and order of appearance. For instance, the structure of an Algol program might look like this: Program Subroutine 1 begin ... // subroutine 1 code end Subroutine 2 begin ... // subroutine 2 code end Subroutine 3 Subroutine 4 begin ... // subroutine 4 code end Subroutine 5 begin ... // subroutine 5 code end begin ... // subroutine 3 code end begin ... // main code end Here, main can call subroutines 1, 2 and 3. Subroutine 3 can call subroutine 4 & 5. In addition to being able to call subroutines nested inside, a subroutine can call any subroutine that appear above the subroutine in the code. So 3 can also call 1 and 2. The idea here is that the structure of the program becomes important as it reflects the manner by which subroutines can reference each other. Aside from this difference, there are two other notable differences: the specific syntax used (words like begin and end rather than { }) and the concept of pass-by-name for parameter passing. Below are some of the highlights of ALGOL and the differences you will see between it and C. Variable declarations: As with FORTRAN, variables are declared as TYPE var, var, var; where TYPE is INTEGER, REAL, ARRAY, STRING. Another type allowed is called a SWITCH declaration. This allows you to define a range of values to be stored in a variable, where the values are actually labels (as used in GOTO statements). This was used similarly to a switch or case statement in later languages but was far more primitive and was replaced by a true CASE statement in ALGOL 68. ALGOL 68 also introduced the UNION to the ALGOL languages. I/O: Read statement as in READ (A, B, C); or READ(A); READ(B); READ(C); WRITE("literal message"); and PRINT(variable list); as in PRINT(A, B, C); Notice that you cannot combine a literal output with a variable, they must be split between WRITE and PRINT. Also, PRINT does not appear to have any formatting. Assignment Statements: assign using := rather than = as in C or FORTRAN. The := is also used in Pascal-like languages (Pascal, Modula, Ada). The rationale is to differentiate it from the = as used in equality. Obviously C languages use = for assignment and == for equality, ALGOL uses := for assignment and = for equality. The expression on the right hand side of the assignment statement will be similar to that in C except that ALGOL includes ^ for exponent. There are no type conversions in ALGOL, so the LHS and RHS types must match or be coercible. Selection Statements: ALGOL introduced the block so that if and else clauses could be written that contained more than 1 instruction. Clauses that had only 1 instruction would not need END statements. Thus, if your clause has more than 1 instruction, it is embedded between BEGIN and END statements, otherwise the BEGIN and END may be omitted. The conditions use =, <, >, LE, GE, NE (although you can also use EQ, GT, LT, or spell these out as EQUAL, LESS GREATER, etc). The ELSE clause is optional and if there is a mismatch as with an IF-THEN-IF-THEN-ELSE, then the ELSE is tagged to the most recent condition. Blocks: you can define a block at any time by using BEGIN and END pairs. Once inside a block, you can declare local variables (local to that block). C adopts this idea. Loops: ALGOL uses a FOR-loop only. But the for-loop is flexible in that it contains the ability to iterate like a counter controlled loop, an iterator (looping over a list of values) and a conditional loop. The syntax is: for var := [ list | val1 step val2 until val3 | val1 while cond ] do where list is a list of values separated by commas, val1, val2 and val3 are values or variables, and cond is a condition. Any of these can be combined. Here are some example for loops: for i := 1 step 2 until N do a[i] := b[i]; for newGuess := Improve( oldGuess ) while abs( newGuess - oldGuess ) > 0.0001 do oldGuess := newGuess; for days := 31, if mod( year, 4 ) = 0 then 29 else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 do . . . for i := 3, 7, 11 step 1 until 16, i ÷ 2 while i >= 1, 2 step i until 32 do print( i ); The last example prints 3 7 11 12 13 14 15 16 8 4 2 1 2 4 8 16 32 Arrays: Declared with both the reserved word array and [range] notation. If no type is provided, arrays default to REAL. The range allows you to specify the starting and ending indices for the array. Thus, arrays are not limited to 0..num-1 as in C, or 1..num as in FORTRAN. Instead, you might specify [0:99] or [1:100] or [-50:49]. Arrays with common sizes can be declared with a single range as follows: INTEGER ARRAY A, B, C[5:10]; Declares arrays A, B, C to be int arrays with indices of 5-10. You must specify the range. Multidimensional arrays require multiple ranges, separated by , as in [5:10, 1:10] Any integer or integer expression is legal for lower and upper bounds as long as lower < upper. Note that unlike C, the value in a range can be a variable input or computed elsewhere so that array sizes are determined at run-time, not compile time. Subroutines: One innovation was the nested subroutine. The idea is that a procedure or function could be defined inside of another. There were three reasons to do this: 1. to reflect the top-down design of the task at hand, 2. to control access to a subroutine, 3. to provide a logical scope for non-local variables. If a subroutine is called by another subroutine and only by that subroutine, logically, it makes sense to place the called subroutine inside of the calling subroutine's definition. This also allows access to the inner subroutine to come only from the outer subroutine. We covered static scope rules in chapter 5, the idea behind them came from ALGOL. Parameter Passing: The default parameter passing method was pass by value, which, like in C, means that parameter values are copied into the formal parameters from which point the formal parameters act like local variables. However, ALGOL also introduced pass by name which gave the programmer the ability to change a formal parameter's value and thus affect the actual parameter. The way this worked is through a thunk -- a parameterless function which would perform a textual substitution of the formal parameter name with that of the actual parameter. So in effect, pass by name is merely a form of substitution that then has the program access non-local variables. This is confusing and dangerous and while it can lead to some interesting code, it is far more dangerous than pass by reference or pass by result. What follows is an example. Here is the original code before the thunk executes: begin integer idx; // variable available in the main code real procedure sum (i, lo, hi, term); // function, i and term passed by name value lo, hi; // function declarations integer i, lo, hi; real term; begin // begin of sum function real temp; temp := 0; for i := lo step 1 until hi do temp := temp + term; sum := temp end; print (sum (idx, 1, 100, 1/idx)) // main code contains function call end The above code becomes the following: begin integer idx; real sum; begin // pass by name unfolds the code so that real temp; // hi becomes 100, lo becomes 1 and term temp := 0; // becomes idx for idx := 1 step 1 until 100 do temp := temp + 1/idx; sum := temp end; print (sum) end See example ALGOL code at http://www.masswerk.at/algol60/algol60-sample.htm#examples. Note that the ' ' used in the examples of this web site that go around all reserved words is not part of ALGOL, but required for the given compiler. Normally, the ' ' would not be there. The above notes refer to Algol 58 and 60. Algol 68 had some major changes which we are not going to cover. Algol 68 was a close predecessor to both C and Pascal (moreso Pascal in terms of syntax).