In summary, the most general form of the IF ... THEN ... ELSIF ... ELSE construction as used in the previous section is as follows:
IF (Boolean Expression 1) THEN Statement Sequence 1; ELSIF (Boolean Expression 2) THEN Statement Sequence 2; ... ELSIF (Boolean Expression n) THEN Statement Sequence n; ELSE Statement Sequence n + 1; END;
All the ELSIFs and the ELSE are optional, depending on the logic required by the program. Note that the form (Boolean Expression i) is used here instead of a specific comparison as in all the examples thus far.
There was a brief discussion of Boolean expressions in section 1.7. The purpose of this section is to specify more exactly what constitute valid boolean expressions in Modula-2, for much more elaborate ones than these can be used in a variety of program structures.
This brings us to the question you may have been ready to ask when you read the heading for this section and the first IF. "What exactly is this thing called a "Boolean expression"? Two related definitions are useful:
An Modula-2 expression is of type BOOLEAN if it can be evaluated unambiguously as "true" or "false".
A Modula-2 variable of type BOOLEAN can have one of the two values TRUE, or FALSE (all three words are standard identifiers).
Previous examples have already illustrated the use of the reserved symbols = and <> (or #) used as comparisons to form boolean expressions and the reserved words OR and AND as connectives to combine two boolean expressions. Here is a complete list of reserved words and symbols for such expressions, together with a translation.
= equals < less than > greater than <= less than or equal to >= greater than or equal to <> or # not equal
Other operators (connectives)
AND or & both of the conditions must be true OR at least one of the conditions must be true NOT or ~ reverses the value of the following logical expression
As in other Modula-2 expressions, any combination of these is allowed, and parentheses can be used to change the natural order of evaluation. Here are a few examples to review the use of these:
Expression BOOLEAN Value 5 <= 5 TRUE (10 < 5) AND (3 < 4) FALSE ('Y' = 'y') OR FALSE FALSE NOT (5 = 6) TRUE (4 = 5) AND ((3 = 7) OR TRUE) FALSE
NOTES: 1. The order of evaluation is:
First NOT (~) Second *, /, DIV, MOD, AND (&) Third +, -, OR Last the relational operators =, <> (or #), >, >=, <, <=
2. When evaluation reaches an AND, if the left expression is FALSE, the right expression is not evaluated. Likewise, if evaluation reaches an OR, if the left expression is TRUE the right expression is not evaluated. Most computer languages cannot be relied upon to take these shortcuts and may evaluate all parts of every boolean expression. Another more formal way of putting this is to say that if p and q are Modula-2 boolean expressions, then:
p AND q means: IF p THEN q ELSE FALSE
p OR q means: IF p THEN TRUE ELSE q
3. Expressions separated by AND or OR should be enclosed in parentheses. If this is not done, the correct order of evaluation may not be followed, for the statement may not be syntactically correct. If x, y, and z are numbers, then
x < y AND y > z is illegal, but
(x < y) AND (y > z) is correct,
because the compiler would attempt to use the proper order of operations and attempt to interpret the first of these as x < (y AND y) > z which makes no sense at all.
Here are some further examples to illustrate these rules.
(6 DIV 3 + 2 = 5) OR NOT (5 <= 7) & (3 < 10)
would be evaluated as:
(6 DIV 3 + 2 = 5) OR FALSE & (3 < 10)
(2 + 2 = 5) OR FALSE (& not evaluated)
(4 = 5) OR FALSE
IF (a < b) OR ((c < d) AND ((y > 0) OR (b - a < 0.05))
Should a in fact be less than b the entire portion on the right of the OR will not be evaluated as the left side alone would be sufficient to give a value of TRUE for the whole expression.
IF (false expression) AND (enormous expression several lines long);
In this case, enormous expression will not be evaluated, again saving considerable time when the code runs.
As indicated above, there are boolean variables in Modula-2 as well as boolean expressions. These are declared like those of any other type, under a VAR heading. They may then be used throughout the program to represent various boolean values. As usual, declaring one of these names does not give it to any particular value--the variable must be initialized before it is known to be either TRUE or FALSE; until then it is undefined. Here is a little program which offers the user a sample choice between two actions and stores the information from the choice in as the value of a boolean variable:
Two groups of students are taking a course in Modula-2 at the same time. The Cmpt141 students have High School computing with high marks and so do a four semester hour course. The Cmpt 143 students attend the same lectures, but have a previous university level course in Pascal. Because it is much easier to learn a second computing notation at this level than a first, these students receive two semester hours credit. They are also exempt from a major assignment. Their marks are calculated as follows:
CMPT 141 CMPT 143
Labs 25% (All must be done to gain credit) 25%
Midterms 30% 35%
Major Paper 10% (essay) Not required
Final Exam 35% 40%
The task is to write a program that will take the percentage marks from the three or four categories and produce a final percentage grade for the course. In what follows, much of the planning has been left out for the sake of brevity.
Print an informative heading Initialize the student's totalMark to zero Print a prompt asking which course the student is taking Set the value of the boolean variable in141 using the answer Print a prompt asking if all assignments were handed in Set the boolean variable assignOK using the answer IF assignOK then Print a prompt asking for the lab percentage Read the result to the real variable labs Set totalMark to 0.25*(labs) Print a prompt asking for the midterm percentage Read the result to the real variable midterms Print a prompt asking for the final exam percentage Read the result to the real variable fExam If in141 then Print a prompt asking for the essay percentage Read the result to the real variable essay totalMark = totalMark+.3*(midterms)+.35*(fExam)+.1*(essay) Else totalMark = totalMark+.35*(midterms)+.4*(fExam) Print the final mark embedded in a course-specific message If Not (assignOK) Then Print an explanation
In addition, the code presented here implements a common technique to allow for a repetition of the entire program at the request of the user. This also employs a boolean variable.
MODULE Modula2CourseMarks; (* Written by R.J. Sutcliffe *) (* to illustrate the use of Boolean variables *) (* using P1 Modula-2 for the Macintosh computer *) (* last revision 1993 02 12 *) FROM STextIO IMPORT WriteString, WriteLn, ReadChar, SkipLine; FROM SRealIO IMPORT ReadReal, WriteFixed; CONST labWt = 0.25; midtermWt141 = 0.3; midtermWt143 = 0.35; finalWt141 = 0.35; finalWt143 = 0.4; essayWt = 0.1; VAR labs, midterms, essay, fExam, totalMark : REAL; answer, cr : CHAR; in141, assignOk, again : BOOLEAN; BEGIN WriteString ("Modula2CourseMarks written by R.J. Sutcliffe"); WriteLn; WriteString ("as an example in the use of Boolean variables"); WriteLn; WriteLn; WriteString ("It computes the final percentage mark for "); WriteLn; WriteString ("students enrolled in Cmpt 141 and Cmpt 143. "); WriteLn; WriteLn; again := TRUE; WHILE again DO totalMark := 0.0; (* Gather the information from the user *) WriteString ("Is the student in Cmpt141? Y/N ==> "); ReadChar (answer); SkipLine; (* consume the carriage return after the char *) WriteLn; in141 := (answer = "Y") OR (answer = "y"); WriteString ("Were all assignments complete? (Y/N) ==> "); ReadChar (answer); (* Note that variables can be re-used *) SkipLine; (* consume the carriage return after the char *) WriteLn; assignOk := (answer = "Y") OR (answer = "y"); IF assignOk THEN WriteString ("What % mark was earned on labs? ==> "); ReadReal (labs); SkipLine; (* consume the carriage return after real *) WriteLn; totalMark := labWt * labs; WriteString ("What was the midterm mark? ==> "); ReadReal (midterms); SkipLine; WriteLn; WriteString ("What was the final exam mark? ==> "); ReadReal (fExam); SkipLine; WriteLn; IF in141 THEN WriteString ("What mark was the essay mark? ==> "); ReadReal (essay); SkipLine; WriteLn; totalMark := totalMark + midtermWt141 * midterms + finalWt141 * fExam + essayWt * essay; ELSE totalMark := totalMark + midtermWt143 * midterms + finalWt143 * fExam; END; (* if in141 *) END; (* if assignOk *) (* print the result *) WriteString ("The final mark for Cmpt"); IF in141 THEN WriteString (" 141 "); ELSE WriteString (" 143 "); END; WriteString (" was "); WriteFixed (totalMark, 2, 0); WriteString ("%."); WriteLn; IF NOT assignOk THEN WriteString ("No credit when assignments not done."); WriteLn; END; WriteLn; WriteString ( "Do another calculation? Y/N ==> "); ReadChar (answer); again := (answer = "Y") OR (answer = "y"); SkipLine; WriteLn; END; (* of the while loop *) END Modula2CourseMarks.
Here is a run from this module:
Modula2CourseMarks written by R.J. Sutcliffe as an example in the use of Boolean variables It computes the final percentage mark for students enrolled in Cmpt 141 and Cmpt 143. Is the student in Cmpt141? Y/N ==> Y Were all assignments complete? (Y/N) ==> Y What % mark was earned on labs? ==> 100 What was the midterm mark? ==> 90 What was the final exam mark? ==> 85 What mark was the essay mark? ==> 72.5 The final mark for Cmpt 141 was 89.00%. Do another calculation? Y/N ==> Y Is the student in Cmpt141? Y/N ==> N Were all assignments complete? (Y/N) ==> N The final mark for Cmpt 143 was 0.00%. No credit when assignments not done. Do another calculation? Y/N ==> N
In programs like this, one sets a boolean from keyboard input and then uses the value one or more times to determine which course to take through the code.
When the value of a boolean variable is used one or more times to determine the appropriate path through a program, the variable is called a flag.
NOTE: It is redundant, superfluous, and too much excess of unnecessary extra code to write IF assignOk = TRUE when it suffices to use IF assignOk.