Chapter 7 - Overall Program Construction
We have pretty well covered the topic of how to put all the parts together to build up a program. In this chapter we will go over the whole process in order to clear up any loose ends and have the entire process in one place. There is nothing magic about the way the various pieces fit together but the rules must be followed in order to build a usable program.
Load and display the program named OVERPROG.MOD for the first look at the overall structure of the Modula-2 program.
OVERPROG.MOD
(* Chapter 7 - Program 1 *)
MODULE OverProg; (* Overall program construction example *)
FROM InOut IMPORT WriteString, WriteLn;
PROCEDURE Proc1;
BEGIN
WriteString("Procedure 1");
WriteLn;
END Proc1;
PROCEDURE Proc2;
PROCEDURE Proc3;
BEGIN
WriteString("Procedure 3");
WriteLn;
END Proc3;
PROCEDURE Proc4;
PROCEDURE Proc5;
BEGIN
WriteString("Procedure 5");
WriteLn;
END Proc5;
BEGIN
WriteString("Procedure 4");
WriteLn;
Proc5;
Proc3;
END Proc4;
BEGIN
WriteString("Procedure 2");
WriteLn;
Proc3;
Proc4;
END Proc2;
BEGIN
WriteString("Main Program");
WriteLn;
Proc2;
Proc1;
END OverProg.
It would be well for you to keep in mind that there is a major category that we have not even hinted at yet, the issue of modules. They will be covered in Part III of this tutorial, and although they are very important, you can begin writing meaningful programs before you even hear what modules are or how they are used.
NESTED PROCEDURES
The program on display contains several levels of nested procedures as an illustration for you. The main program has lines 1 through 37 as its declaration part, and lines 38 through 43 as its statement part. Since the procedure definitions actually define the procedures called for by the main program, they correctly belong in the declaration part of the program. Only two of the procedures are actually callable by the main program, "Proc1", and "Proc2". The procedure "Proc1" is a simple procedure, but "Proc2" has additional procedures in its declaration part.
Procedure "Proc2" contains a declaration part in lines 13 through 30, and a statement part in lines 31 through 36. Its declaration part contains two procedures, "Proc3" and "Proc4". The nesting is carried one step farther in "Proc4" which contains the procedure "Proc5" in its declaration part. Procedures can be nested to whatever level desired according to the definition of Modula-2.
WHO CAN CALL WHO?
It is important for you to clearly understand which procedure can call which other procedures. A procedure can call any procedure on the same level as itself provided that both have the same parentage, or any procedure that is included in its own declaration part at the level of its own declaration part. For example, the main program can only call "Proc1", and "Proc2". The others are nested within "Proc2" and are not available to the main program. Likewise the statement part of "Proc2" can call "Proc1", because it is on the same level, and "Proc3" and "Proc4", because they are within its declaration part. The procedure "Proc5" can only be called by "Proc4", because no other procedure is at its level. Note that if another triple nesting were included in "Proc1", its third level procedure could not be called by "Proc5" because they would not have the same parentage.
Nested procedures can be very useful when you wish to use a procedure that you don't want any other part of the program to be able to access or even see. A private procedure can therefore be written with no concern that the name may clash with some other part of the program and cause undesirable effects.
The important thing to gain from this program is that nesting is possible and can be very useful, and the definition of a procedure is the same as that of the main program. This means that procedures can be nested within procedures in any way that aids in designing the program.
Compile and run this program and see if you understand the output from it.
WHERE DO WE PLACE CONSTANTS, TYPES, AND VARIABLES?
Load MOREPROG.MOD, for examples of where you can put the other definitions in the declaration part of the program and the procedures.
MOREPROG.MOD
(* Chapter 7 - Program 2 *)
MODULE MoreProg; (* More program construction examples *)
FROM InOut IMPORT WriteString, WriteLn;
CONST MainC = 27;
TYPE MainT = ARRAY[3..7] OF CARDINAL;
VAR MainV : MainT;
PROCEDURE Proc1;
CONST Proc1C = 33;
TYPE Proc1T = ARRAY[-23..-15] OF CHAR;
VAR Proc1V : MainT;
Proc11 : Proc1T;
BEGIN
WriteString("Procedure 1");
WriteLn;
END Proc1;
PROCEDURE Proc2;
CONST Proc2C = 22;
TYPE Proc2T = ARRAY[3..5],[-4..0] OF BOOLEAN;
VAR Proc2V : MainT;
Proc21 : Proc2T;
PROCEDURE Proc3;
CONST Proc3C = -234;
TYPE Proc3T = ARRAY[12..13] OF MainT;
VAR Proc3V : MainT;
Proc31 : Proc2T;
Proc32 : Proc3T;
BEGIN
WriteString("Procedure 3");
WriteLn;
END Proc3;
PROCEDURE Proc4;
CONST Proc4C = 111;
TYPE Proc4T = CARDINAL;
VAR Proc4V : MainT;
Proc41 : Proc2T;
Proc42 : Proc4T;
PROCEDURE Proc5;
CONST Proc5C = "A";
TYPE Proc5T = ARRAY[22..222] OF CHAR;
VAR Proc5V : MainT;
Proc51 : Proc2T;
Proc52 : Proc4T;
Proc53 : Proc5T;
BEGIN
WriteString("Procedure 5");
WriteLn;
END Proc5;
BEGIN
WriteString("Procedure 4");
WriteLn;
Proc5;
Proc3;
END Proc4;
BEGIN
WriteString("Procedure 2");
WriteLn;
Proc3;
Proc4;
END Proc2;
BEGIN
WriteString("Main Program");
WriteLn;
Proc2;
Proc1;
END MoreProg.
This is a repeat of the last program with CONST, TYPE, and VAR declarations added in every place where it is legal to put them. This is done as an example to you of where they can be put, so no explanation of details will be given. Some time spent studying this program should aid you in understanding even better the overall program construction problem.
WHAT ABOUT ORDER OF DECLARATIONS?
Load the program LASTPROG.MOD for an example of how the various fields can be ordered in the declaration part of the program.
LASTPROG.MOD
(* Chapter 7 - Program 3 *)
MODULE LastProg;
FROM InOut IMPORT WriteString, WriteLn;
PROCEDURE Dummy;
BEGIN
END Dummy;
VAR Index : CARDINAL;
TYPE Stuff = ARRAY[34..55] OF CHAR;
PROCEDURE Smart;
BEGIN
END Smart;
CONST Number = 120;
TYPE TypeOf = ARRAY[1..Number] OF Stuff;
CONST Neater = -345;
VAR Count23 : TypeOf;
Counter : INTEGER;
BEGIN
WriteString("This is really a stupid program.");
WriteLn;
END LastProg.
Notice that there are 2 procedures, two CONST's, two TYPE's, and two VAR's defined, but they are defined in a seemingly random order. The order is random and was done only to illustrate to you that the order doesn't matter as long as everything is defined before it is used.
In only one case does the order matter. The compiler is very picky about where the IMPORT list goes because the Modula-2 language definition requires it to be first. In addition, the EXPORT list must immediately follow the IMPORT list. We will cover both of these in detail later, for now simply remember that the order of all declarations can come in random order as long as they follow the IMPORT/EXPORT lists and come before the statement part of the program.
PROGRAMMING EXERCISES
- Using the program OVERPROG, add some calls to illegal places to see what messages the compiler displays.
- Using the program MOREPROG, add some illegal variable references to see what messages the compiler displays.