Beginner

Operators in ALGOL 60

Learn arithmetic, relational, and logical operators in ALGOL 60, including the language’s distinctive operator set, precedence rules, and Boolean expressions

Introduction

Operators are the verbs of an expression — the symbols that combine values into computations. ALGOL 60 set the template that nearly every later imperative language followed: separate operator categories for arithmetic, relations, and Boolean logic, each with its own precedence level. When you write a * b + c in Python, C, or Java, the rule that multiplication binds tighter than addition was effectively codified by the ALGOL 60 Report.

What makes ALGOL 60’s operators interesting today is the things modern languages quietly dropped. ALGOL 60 distinguishes integer division from real division using two different symbols. It has a built-in exponentiation operator. It treats Boolean as a first-class type with implication and equivalence operators — and in the Report, written impl and eqv in GNU MARST. And assignment is a deliberate :=, not an overloaded =, leaving = free to mean what it does in mathematics: equality.

Because ALGOL 60 is statically and strongly typed, operator behaviour follows the operand types. Mixing integer and real in an arithmetic expression promotes the result to real. The original Report used special mathematical glyphs (, , , , , ¬) that few keyboards could produce; GNU MARST uses ASCII spellings instead, which is what we’ll write below.

Arithmetic Operators

ALGOL 60 provides the standard arithmetic operators plus a few distinctive ones. Create a file named operators.alg:

begin
  integer a, b, q, r, p;
  real x, y, z;

  a := 17;
  b := 5;

  comment ALGOL 60 has two different division operators;
  x := a / b;        comment real division, result is 3.4;
  q := a div b;      comment integer division, result is 3;
  r := a - (a div b) * b;  comment remainder, computed manually, result is 2;

  comment Exponentiation uses ** in MARST;
  p := 2 ** 10;      comment 1024;

  comment Mixed integer and real promotes to real;
  y := 7 + 2.5;      comment result is 9.5;
  z := -y;           comment unary minus, result is -9.5;

  outstring(1, "a / b   = "); outreal(1, x);    outstring(1, "\n");
  outstring(1, "a div b = "); outinteger(1, q); outstring(1, "\n");
  outstring(1, "a mod b = "); outinteger(1, r); outstring(1, "\n");
  outstring(1, "2 ** 10 = "); outinteger(1, p); outstring(1, "\n");
  outstring(1, "7 + 2.5 = "); outreal(1, y);    outstring(1, "\n");
  outstring(1, "-y      = "); outreal(1, z);    outstring(1, "\n")
end

A few things to notice:

  • / is always real division. Even when both operands are integers, / yields a real result. This is the opposite of C and Java, where / between two integers truncates.
  • div is integer division. It requires integer operands and produces an integer. The Report wrote this as ÷.
  • No mod operator. ALGOL 60 has no built-in remainder operator. You compute remainders explicitly as a - (a div b) * b.
  • ** is exponentiation. The Report’s becomes ** in MARST. It accepts integer or real bases and exponents.
  • Unary minus works as expected on numeric values.

Relational and Boolean Operators

Relational operators compare values and produce a Boolean result. ALGOL 60 then combines Booleans using logical operators that include two that most modern languages omit: implication and equivalence. Create a file named boolean_ops.alg:

begin
  integer m, n;
  Boolean p, q, r;

  m := 7;
  n := 12;

  comment Relational operators produce Boolean values;
  p := m < n;              comment true;
  q := m = n;              comment false  (note: = is equality, not assignment);
  r := m >= 7;             comment true;

  outstring(1, "m < n  : "); if p then outstring(1, "true") else outstring(1, "false");
  outstring(1, "\n");
  outstring(1, "m = n  : "); if q then outstring(1, "true") else outstring(1, "false");
  outstring(1, "\n");
  outstring(1, "m >= 7 : "); if r then outstring(1, "true") else outstring(1, "false");
  outstring(1, "\n");

  comment Logical operators: not, and, or, impl (implies), eqv (equivalent);
  outstring(1, "p and r       : ");
  if p and r then outstring(1, "true") else outstring(1, "false");
  outstring(1, "\n");

  outstring(1, "q or  r       : ");
  if q or  r then outstring(1, "true") else outstring(1, "false");
  outstring(1, "\n");

  outstring(1, "not q         : ");
  if not q   then outstring(1, "true") else outstring(1, "false");
  outstring(1, "\n");

  comment p impl q is equivalent to (not p) or q;
  outstring(1, "p impl q      : ");
  if p impl q then outstring(1, "true") else outstring(1, "false");
  outstring(1, "\n");

  comment p eqv q is true when p and q have the same Boolean value;
  outstring(1, "p eqv r       : ");
  if p eqv r then outstring(1, "true") else outstring(1, "false");
  outstring(1, "\n")
end

The full relational set is <, <=, =, >=, >, != (Report glyphs: <, , =, , >, ). Use = for equality comparison — assignment is :=, so there is no ambiguity.

The Boolean operators in order of precedence (loosest to tightest, the reverse of typical reading order) are: eqv, impl, or, and, not. impl and eqv are heirlooms of ALGOL 60’s mathematical heritage: p impl q means “if p then q” and equals (not p) or q; p eqv q is true exactly when p and q agree.

Operator Precedence and Assignment

Precedence determines how an expression is parsed when parentheses are absent. ALGOL 60’s precedence order, from highest to lowest, is:

  1. ** (exponentiation)
  2. *, /, div
  3. +, - (binary and unary)
  4. <, <=, =, >=, >, !=
  5. not
  6. and
  7. or
  8. impl
  9. eqv

Create a file named precedence.alg:

begin
  integer result1, result2, result3;
  Boolean t;

  comment 2 + 3 * 4 parses as 2 + (3 * 4) = 14, not (2 + 3) * 4 = 20;
  result1 := 2 + 3 * 4;

  comment Parentheses force a different grouping;
  result2 := (2 + 3) * 4;

  comment ** binds tighter than unary minus: -2 ** 2 is -(2 ** 2) = -4;
  result3 := -2 ** 2;

  outstring(1, "2 + 3 * 4   = "); outinteger(1, result1); outstring(1, "\n");
  outstring(1, "(2+3) * 4   = "); outinteger(1, result2); outstring(1, "\n");
  outstring(1, "-2 ** 2     = "); outinteger(1, result3); outstring(1, "\n");

  comment Assignment with :=  not =;
  comment Multiple targets are allowed: a := b := expr;
  begin
    integer a, b;
    a := b := 99;
    outstring(1, "a, b after a := b := 99 -> ");
    outinteger(1, a); outstring(1, ", "); outinteger(1, b); outstring(1, "\n")
  end;

  comment Boolean precedence: and binds tighter than or;
  t := true or false and false;
  outstring(1, "true or false and false = ");
  if t then outstring(1, "true") else outstring(1, "false");
  outstring(1, "\n")
end

Two things deserve emphasis. First, assignment in ALGOL 60 is a statement, not an expression — you cannot embed a := 5 inside a larger expression the way you can in C. But ALGOL 60 does permit multiple targets on the left, so a := b := 99 assigns 99 to both b and a. Second, the precedence list above means true or false and false is true or (false and false) which is true, not (true or false) and false which would be false.

Running with Docker

Pull the official image and run each example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Pull the official image
docker pull codearchaeology/algol60:latest

# Run the arithmetic operators example
docker run --rm -v $(pwd):/app -w /app codearchaeology/algol60:latest algol60-run operators.alg

# Run the Boolean operators example
docker run --rm -v $(pwd):/app -w /app codearchaeology/algol60:latest algol60-run boolean_ops.alg

# Run the precedence example
docker run --rm -v $(pwd):/app -w /app codearchaeology/algol60:latest algol60-run precedence.alg

Expected Output

Output of operators.alg:

a / b   = +3.40000000000000E+000
a div b = +3
a mod b = +2
2 ** 10 = +1024
7 + 2.5 = +9.50000000000000E+000
-y      = -9.50000000000000E+000

Output of boolean_ops.alg:

m < n  : true
m = n  : false
m >= 7 : true
p and r       : true
q or  r       : true
not q         : true
p impl q      : false
p eqv r       : true

Output of precedence.alg:

2 + 3 * 4   = +14
(2+3) * 4   = +20
-2 ** 2     = -4
a, b after a := b := 99 -> +99, +99
true or false and false = true

GNU MARST formats integers with an explicit sign and real numbers in scientific notation by default; that’s the outinteger/outreal library behaviour, not part of the operator itself.

Key Concepts

  • Two division operators. / always produces a real result; div is integer-to-integer division. There is no built-in mod — compute remainders as a - (a div b) * b.
  • Exponentiation is built in. a ** b (the Report’s ) is part of the language, not a library function, and binds tighter than multiplication.
  • Assignment is :=, equality is =. Because the two are distinct, ALGOL 60 avoids the = vs == confusion that haunts C-family languages.
  • Boolean is a first-class type. Relational operators yield Boolean values you can store, combine, and pass to procedures.
  • impl and eqv are unusual. Few modern languages include logical implication or equivalence as native operators; they survive in ALGOL 60 from its mathematical-logic heritage.
  • Precedence is explicit and well-defined. The hierarchy ** > *,/,div > +,- > relations > not > and > or > impl > eqv was the model copied (with variations) by Pascal, Ada, and Modula.
  • Mixed-type arithmetic promotes to real. Combining an integer and a real produces a real; assigning a real to an integer requires the conversion to be explicit (or rounds, depending on context).
  • No short-circuit guarantees in the Report. Unlike C’s && and ||, ALGOL 60’s and and or are not specified to short-circuit. Don’t rely on the right operand being skipped.

Running Today

All examples can be run using Docker:

docker pull codearchaeology/algol60:latest
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining