Classic Computer Magazine Archive START VOL. 4 NO. 2 / SEPTEMBER 1989

Programming
in Modula-2

An Introduction
to Modula-2

BY CAROLYN ROGERS

Among the many languages currently available for the Atari ST, Modula-2 is an often overlooked gem. This column is aimed at introducing both the novice and professional programmer to this powerful language.

In the Beginning
Modula-2 (Modular Language 2) was created by Swiss computer scientist Niklaus K. Wirth as a successor to Pascal, which he also developed. It was designed to correct some of Pascal's problems, such as its inability to support separate module compilation and lack of access to low-level machine operations and multiprocessing. Although Modula-2 retains some surface similarities to Pascal, it contains syntactical and conceptual differences that indicate a more mature, refined language.

Modula-2 is a highly structured language. A Modula-2 program is composed of small blocks of code designed to handle one or two specialized functions required by the main program. In Modula-2 there are three distinct types of modules:

1. Program module: This is the master module which controls program flow. The program module accesses independently developed libraries of procedures and functions. (The difference between a procedure and a function is that a function returns a value of some type and a procedure does not.) When compiled, the program module will produce an .LNK file which is used by a linker to pull all the independent parts together.


Modula-2 corrects
some of the problems
with Pascal.

2. Definition module: This module contains information needed to interface with a calling program. It includes the declaration of any constants, types, variables, procedures or functions that must be made available to a calling program. When compiled, the definition module produces an .SYM file. This .SYM file contains a unique identification code which is incorporated into any .LNK file created when an implementation or program module is compiled. The definition module must therefore be compiled first. A new value is created whenever the definition module is compiled. This means that even if you made no changes to the actual code, an error occurs if you don't recompile all programs that call it. This is to prevent the master interface from being changed without the programmer's knowledge.

3. Implementation module: This module contains the actual code to perform whatever functions are defined by the definition module. All information is private, or opaque, to a calling program. When compiled, the implementation module will produce an .LNK file. This file is used by a linker program to pull together the code in the program module .LNK file and the library .LNK files to create an executable .PRG program.

The beauty of separating the definition and implementation code of a module is that you may modify the implementation module without incurring complications in a calling program. Of course, if the definition module is modified, those changes must be reflected in any existing code.


There are three
distinct types of
modules.

As with any programming language, the syntax of Modula-2 consists of a set of rules that govern the building of a Modula-2 program. In his book, Programming in Modula-2, Niklaus Wirth divided these rules into five classes:

1. Identifiers: A sequence of letters and digits used to identify a variable or constant. The first character of the sequence must be a letter. Identifers in Modula-2 are case-sensitive; therefore, LoopCount and LOOPCOUNT would be seen as two different variables. Modula-2 reserved word cannot be used as identifiers.

2. Numbers: These can be either integers or real numbers and cannot contain non-numeric characters. However real numbers must have a decimal point and may also contain the letter E, used to denote an exponential value Integers may be designated as octal or hexadecimal numbers by following the number with a B for octal or H for hexadecimal.

3. Strings: Strings are a sequence of characters that are enclosed in quotation marks.

4. Operators and delimiters: These are special characters and reserved words, written in capital letters, which are the most basic building blocks of the language. They may not be used as identifiers.

5. Comments: These are sequences of characters enclosed between the comment brackets (* and *). They may be placed anywhere in the code and are ignored by the compiler

Sort 'em Up
Now that we have the rules, let's illustrate them by following the development of a selection sort program. Copy SORTDEMO.ARC and ARCX.TTP onto a blank, formatted disk and un-ARC SORTDEMO.ARC, following the Disk Instructions elsewhere in this issue.

Figure 1 is the main program file, SORTDEMO.MOD. The first line contains the reserved word MODULE, used to indicate the module name SortDemo. The FROM and IMPORT statements import procedures from other modules, making them available to the SortDemo program. In this case SelectSort and MAXSIZE are imported from Sort, which we are going to create WriteCard, WnteLn and WriteString are imported from the standard library InOut. BConIn and Device are imported from the BIOS library, ConOut is imported from the GEMDOS library and Random is imported from the XBIOS library.

In Modula-2, the core syntax is used to build libraries of code to handle input and output. These are not part of the definition of Modula-2, but are included as part of a standard library supplied with a particular compiler VAR denotes the beginning of the variable declaration section. Modula-2 requires that all variables and constants be declared explicitly before use. The variables Numbers and SortedNumbers are declared as arrays of CARDINAL numbers. The variables x and y are declared as CARDINAL. The type CARDINAL is for positive whole numbers and zero. The variable wait is a LONGCARD variable, which is for whole numbers with a range greater than CARDINAL. There are also the following types:
 
INTEGER : a positive or negative whole number
REAL : a real number
BOOLEAN : one of two logical truth values: TRUE or FALSE
CHAR : an ASCII character from 0 to 128
LONGINT : a whole number with a greater range than INTEGER
ARRAY : a fixed number of elements of the same type that are identified through an index
RECORD :a group of different types, for example:
TYPE Doglnfo =  RECORD
           Breed : ARRAY10..201 OF CHAR;
           Sex : CHAR;
           Name : ARRAY[0..20] OF CHAR;
                        END;
SET : a subrange or enumeration of a specified set, for example:
TYPE WeekDays = (Sun,Mon,Tue,Wed,Thr,Fii,Sat);
Day  = SET of WeekDays;
POINTER : pointer to a block of dynamic storage, for example:
NAME = POINTER to ARRAY[0. .20] OF CHAR;

The reserved word BEGIN denotes the beginning of the program code The first statement clears the screen. The second statement, WriteLn, is a standard library function to skip a line. Next there is a FOR ioop that fills the Numbers array with random CARDINAL values. The program then calls the SelectSort procedure, sending as parameters the array to be sorted and the array that will contain the sorted values when the procedure returns. After the sort there is another FOR loop used to print both arrays. The program then waits for the user to press a key. Finally there is an END statement fpllowed by the program name.

Figure 2 shows the definition module for the sort program, SORT.DEF The reserved words DEFINITION MODULE identify the module name as Sort. This name must also be used by the corresponding implementation module. The declaration section consists of one constant MAXSIZE and one procedure SelectSort.


The core syntax is
used to build libraries
of code to handle
input and output.

Finally, the implementation module for the sort demo, SORTMOD is shown in Figure 3. The reserved words IMPLEMENTATION MODULE followed by the name Sort indicates that this is the corresponding module for the Sort definition module.

Next, the PROCEDURE SelectSort is defined. The following VAR declares variables that are local to the SelectSort procedure. The code between BEGIN and END SelectSort marks the boundaries of this procedure. The first code statement is a FOR loop to copy the values of the original array into the sort array The next loop starts at the beginning of the array and within the second loop compares each y value with the current x position. If a lesser value is found they are swapped. At the end of each pass the current x position in the array is correctly sorted. The last statement END Sort marks the end of the implementation module.

If you are familiar with BASIC, C or Pascal, I have included the comparable source code for the selection sort for each language I attempted to make the program demo for each language as generic as possible. However, the Random-Number function will require a compiler-specific call. The demo files are as follows: Modula-2 (SORT.DEF, SORT.MOD, SORTDEMO.MOD), Pascal (SORTDEMO. PAS), ST BASIC (SORTDEMO.BAS) and C (SORTDEMO.C).

Figure 1: This is the main module of the Modula-2 sort demo. It is on your START disk as SORTDEMO.MOD in the archive file SORTDEMO.ARC.

MODULE                SortDemo;
FROM BIOS           IMPORT BConIn,Device;
FROM GEMDOS   IMPORT ConOut;
FROM InOut          IMPORT WriteCard,WriteString,WriteLn;
FROM Sort            IMPORT SelectSort,MAXSIZE;
FROM XBIOS        IMPORT Random;
 

VAR

   Numbers,SortedNumbers: ARRAYEO..MAXSIZE] OF CARDINAL;
    x,y                                          : CARDINAL;
    wait                                        : LONGCARD;
 

BEGIN
   ConOut(CHR(27)); ConOut("E");  (* Clear the screen*)
    WriteLn;                                              (* Skip a line *)
    FOR x := 0 TO MAXSIZE DO           (* Fill the array with random values *)
        NumbersEx] := CARDINAL(Random() MOD 200);
   END;
   SelectSort(Numbers,SortedNumbers);
   WriteString(" UNSORTED ARRAY          SORTED ARRAY' ');        WriteLn;
   FORx:= 0 TO MAXSIZE DO
       WriteString("                           "); WriteCard(Numbers[x],5);
        WriteString('' 'I); WriteCard(SortedNumbers[x],5); WriteLn;
   END;
   wait := BConIn(CON); (* Wait for a keypress *)
END SortDemo.
 

Figure 2: This is the definition module of the Modula-2 sort demo. It is on your START disk as SORT.DEF in the archive file SORTDEMO.ARC.
 

DEFINITION MODULE Sort;
CONST
MAXSIZE = 20;
 

PROCEDURE SelectSort(VAR Numbers,SortedNumbers : ARRAY OF CARDINAL);
END Sort.
 

Figure 3: This is the implementation module of the Modula-2 sort demo. It is on your START disk as SORT. MOD in the archive file SORTDEMO.ARC.
 

IMPLEMENTATION MODULE Sort;
PROCEDURE SelectSorf(VAR Numbers,SortedNumbers: ARRAY OF CARDINAL);
 

VAR
     x,y,temp : CARDINAL;
BEGIN
     FOR x:= 0 TO MAXSIZE DO
         SortedNumbers[x] := Numbers[x];
    END;
    FOR x : 0 TO MAXSIZE-1 DO
        FOR y := x+1 TO MAXSIZE DO
            IF SortedNumbers(x]> SortedNumbers[y] THEN
                temp := SortedNumbers[x];
                SortedNumbers[x] := SortedNumbers[y];
                SortedNumbers[y] := temp;
            END;
        END;
    END;
END SelectSort;
END Sort.

Further Reading
If you are interested in additional information the book Modula-2: A Seafarer's Manual and Shipyard Guide by Edward J. Joyce is good for beginners. For more advanced information Programming in Modula-2 by Niklaus Wirth is the definitive book on the language.

Carolyn Rogers is a professional programmer living in North Little Rock, Arkansas. She wrote STARTs first Modula-2 program, Poker Solitaire, which was published in the April 1989 issue.

PRODUCTS MENTIONED

Modula-2: A Seafarer's Manual and Shipyard Guide, by Edward J. Joyce, 1985, Addison-Wesley, 1 Jacob Way, Redding, MA 01867, (800) 447-2226. Call for price.
CIRCLE 174 ON READER SERVICE CARD

Programming in Modula.2, by Niklaus Wirth, $20.50. SpringerVerlat, 175 Fifth Avenue, New York, NY 10010, (800) 526-7254.
CIRCLE 175 ON READER SERVICE CARD