2.7 Expressions for Constants and Variables

This material follows up on the general comments about expressions made in section 1.7. Here, the specific concern is the kinds of things one is allowed to write on the right-hand-side of a Modula-2 assignment statement. This section will be concerned only about type INTEGER and CARDINAL. Additional expressions that are appropriate for other data types will be discussed later.

A Modula-2 expression is a combination of literals, constants, and variables using addition, subtraction, multiplication, division, and/or such other operations as may be defined for the type of entity being combined.
In an expression, symbols such as +, -, and * are called operators and the entities being combined are called operands.

Here are some examples of valid expressions:

  4 + 5
  7 - firstNum
  secondNum + thirdNum - fourthNum

If firstNum and fourthNum are large enough cardinals the last two may cause errors at runtime. As in other notations, multiplication is indicated by an asterisk.

  3 * 5		(* three times five *)
  4 * num	(* one cannot write 4num, 4(num) or 4  num *)

Division of INTEGER or CARDINAL values uses the / or DIV operators. The answer will have any fractional part removed, so that it will still be an entire number of the same type. For both / and DIV, the dividend (left operand) may be negative, but DIV requires that the divisor (right operand) be positive. The / operator simply does a division and throws away the fractional part. However, the DIV operator has the effect of reducing the dividend to the next lower multiple of the divisor first, then dividing. The effect is the same for positive dividend, but not for negative ones.

  7 / 2 		(* result:  3 *)
  9 DIV 4	(* result:  2 *)
  -35 / 2	(* result:  -17 *)
  -35 DIV 12 	(* result:  -3  first reduce to -36, then divide *)
  -42 / 10	(* result:  -4 *)
  -42 DIV 10 	(* result:  -5  first reduce to -50, then divide *)
  7 / -2		(* result:  -3 *)
  9 DIV -2	(* result:  the compiler reports an error *)
  -15 / -3	(* result:  5 *)
  -12 DIV -4 	(* result:  an error *)
  card / 0	(* result:  a divide-by-zero error *)
  int DIV 0  	(* result:  a divide-by-zero error *)

NOTE: Care must be taken to ensure that the result of an arithmetic expression is neither too large nor too small to fit in the allowable range for the type of the variable one is attempting to assign it to.

An attempt to assign to a variable name a value which is larger than the maximum allowable, or smaller than the minimum allowable is said to overflow or underflow, the variable respectively.

That is, the expressions (a - b) and (a + b) may not be valid CARDINALs, even though both a and b have been correctly assigned CARDINAL values.


Suppose one had:

 firstCard, secondCard, thirdCard : CARDINAL;
 firstInt, secondInt : INTEGER;

Then these assignments are correct:

  firstCard := 6000;
  secondCard := 5000;
  firstInt := -4000;
  thirdCard := firstCard + secondCard; (* no problem here *)

and these may cause overflows, depending on the respective ranges:

  thirdCard := firstCard * secondCard;
    (* answer may be too big for CARDINAL *)
  secondInt := firstCard * 30;
    (* answer may be too big for INTEGER *)

WARNING: Compilers are supposed to generate code to check at run time for overflows and underflows of CARDINAL/INTEGER (and similar) assignments. However, there are Modula-2 implementations in which this is not done, and this fact could make errors difficult to track down.

Another pair of operators worth mentioning here are REM and MOD. On the one hand, c := a DIV b and c := a / b assign only the whole number part of the appropriate division to c, with the remainder being discarded. REM and MOD do the opposite, discarding the quotient to the division and retaining only the remainder. REM works for both positive or negative divisors and dividends, but MOD requires that the divisor be positive. REM produces the remainder of a / division, and MOD the remainder of a DIV division. Therefore, the results are the same for positive dividends, but different for negative ones. A REM result always has the same sign as the dividend, but a MOD result is always positive (the distance from the next lower multiple of the divisor to the dividend.)

    4 REM 2 produces 0
    4 MOD 2 produces 0
   12 REM 5 produces 2
   12 MOD 5 produces 2
  -22 REM 6 produces -4
  -22 MOD 6 produces 2 (* distance from -24 to -22 *)
   32 REM -3 produces 2
   32 MOD -3 produces an error
   49 REM 0 produces an error
   49 MOD 0 produces an error

NOTES: 1. Another way to obtain a MOD b is to compute a REM b first. Then, a MOD b = a REM b if a REM b = 0, and, a MOD b = b - a REM b if a REM b < 0

2. REM, MOD and DIV are all reserved words, as are all words indicating an operation.

Parts of an arithmetic expression that are joined by a multiplication or division are called factors and those joined by an addition or subtraction are called terms. More complex expressions can be formed by combining factors and terms. Figure 2.9 is a diagram of a simple expression. Note that it may start with a "+" or a "-" and that a "muloperator" can be *, /, REM, DIV or MOD (thus far.)

Expressions can be used anywhere on the right-hand side of a variable assignment (a := a + 2) or a constant equate (octave = 2 * unison). To further illustrate the latter, suppose three constants were used in a program, namely 20, 40, and 70, and the programmer knew that even if these changed, the second would always be twice the first, and third would be thirty more than the second. The constants could be declared as:

  firstConst = 20;
  secondConst = 2 * firstConst;
  thirdConst = secondConst + 30;

2.7.1 Precedence in Modula-2

Refer to section 1.7.1 for a general discussion of this topic, where it is explained that Mathematicians adopt a convention or set of rules to evaluate otherwise ambiguous expressions such as:

4 + 5 * 8 or 6 - 12 / 2 or (12 - 5) (3 + 9) - 4 (6 - 3 / (-1))

Modula-2 is capable of following these standard rules for evaluating arithmetic expressions. That is, multiplication and division are performed before addition and subtraction, and parentheses can modify this order. This is not the case with many calculators, which evaluate expressions as they are entered. Here are a number of assignments, with the results shown at right.

  firstNum := 4 + 5 * 6			Answer:  34
  secondNum := 4 DIV 3 + 5 MOD 4	Answer:   2
  thirdNum := (3 - 4) * 6		Answer:  -6
  fourthNum := 9 * (5 - 20 DIV

Of course, both thirdNum and fourthNum must be of type INTEGER, or the last two assignments will fail to work. Notice that the "*" operator is necessary in the last case; one cannot simply write fourthNum := 9(5 - 20 DIV 3), using the parenthesis to imply multiplication.

2.7.2 Mixed Expressions and Modula-2

In Modula-2, mixed expressions, say, those involving both INTEGER and CARDINAL types, are forbidden. That is, in the terminology of section 1.7.2, INTEGER and CARDINAL are not expression compatible, even though (over their common range) we have seen that they are assignment compatible. For instance, if firstCard is of type CARDINAL and firstInt and secondInt are both of type INTEGER, then it is illegal to write either:

  firstInt := firstCard + secondInt;
  firstCard := firstCard + firstInt;

because the right-hand side of the expression contains two different data types. The way to get around this, if necessary, is to convert the value of one of the members on the right to the data type of the other as follows:

  firstInt := VAL (INTEGER, firstCard) + secondInt;
  firstCard := firstCard + VAL (CARDINAL, firstInt);

Of course, the numbers being converted must be in the correct range for the other variable, or there will be an overflow error. Conversions using VAL will be covered in more detail in section 2.10.1.