CS441 Group Home Page
Contents

Home
UMKC Links
   UMKC
   SICE
   VU Home
   CS 441

eMail the group

CS441 - Group Project #1

Block-structured Procedural Languages
Modula-2 and C

Marcus Garrett
Jeff Heckathorn
Tom Heffron
Sedric Hibler
Ali Wajid

Due Date: November 11, 2002


History of Modula-2
Marcus Garrett

Modula-2 was developed by Niklaus Wirth at ETH in Zürich, Switzerland in the late 70's. It is a descendent of Pascal and Modula, and a predecessor of Modula-3, Oberon, Oberon-2, and various object oriented languages. In designing Modula, Wirth built on the strengths of his previous language, Pascal, and tried to eliminate some of its weaknesses. He aimed at creating a type-safe language that would be robust for large scale projects and systems programming, would support data abstraction, could be used for teaching, and could be compiled efficiently. Unfortunately the original description of the language was not structured enough and no compiler was ever released, ending its development after is publication. Wirth probably didn’t pay enough attention to defining a standard set of support libraries, leading to manufacturers producing a variety of incompatible modules.

In 1987, a committee was formed to produce a standard description of Modula-2 and define a set of standard library modules - reasons for Modula's downfall in its infancy. In addition to producing a natural-language description of the semantics of Modula-2, the group set out to define the language in a denotational style. In this endeavor, the focus became blurred. Their work shifted from their original goal and became an overwhelming project. With each meeting came new suggestions for additions, deletions, revisions, and reversals of previously agreed decisions. In the next five years, many of the project members left the group. With the few members that remained, a base language standard was adopted in 1996. The product that remained had a set of library modules which was significantly different from those of Wirth’s description of the language in his book Programming in Modula-2.
 


Overview of Modula-2
Marcus Garrett

Modula-2 is a simple, but powerful procedural, block-structured language widely used for teaching the fundamentals of programming techniques, data structures, and software engineering. It was designed to exhibit good software engineering practices and to fix some of the problems of its root language, Pascal. Its application areas include systems programming, concurrent programming, embedded systems, software engineering, and academics. Modula-2 has also made vast progressions in safety-critical areas, such as traffic control systems.
It supports program modularity - such as data hiding, named modules, and separate compilation. From its inception, Modula-2 was designed to construct and maintain real application software systems. Its inherent features make it ideal for large projects and for programming and real time controllers by supporting modular design which reduces errors and cuts down on maintenance time. This also allows platform dependencies to be isolated, increasing portability. By supporting concurrency and dynamic memory, Modula-2 provides flexibility to the programmer. Lastly, Modula-2 supports function signature type checking a variety of conventional data types, and dynamic arrays across module boundaries.

Its compilers are available for most platforms: UNIX systems, PCs, and VMS, and even some cross-compilers for embedded systems. Both free and commercial compilers are available. A fair number of utility, math, data handling, distributed computing, and other libraries are also available for Modula-2.

References (for Sections 1 and 2):
1) http://sc22wg13.twi.tudelft.nl/docs/m2faq.html
2) http://www.engin.umd.umich.edu/CIS/course.des/cis400/modula2/modula2.html
3) http://www.mactech.com/articles/mactech/Vol.01/01.05/AboutModula-2/
4) http://www.arjay.bc.ca/Modula-2/m2faq.html
5) http://www.chapman.edu/~radenski/research/papers/object.pdf
6) http://burks.bton.ac.uk/burks/language/modula2/m2faq.htm
7) http://www.levenez.com/lang/
8) Sebesta, Robert W. Concepts of Programming Languages. Addison-Wesley 2002
 


Handling of Data Objects
w/Comparison to C
Sedric Hibler

In Modula-2, many of the data types that we are used to in C/C++ - and other block-structured, procedural languages - are included. However, additional objects included in Modula-2, as well as its ADT capabilities (described below), make it almost part of the object-oriented programming family. Modula-2's lack of support for inheritance is why it wasn't classified this way. In Modula-2, one of the main data objects are RECORDS, which are like simple STRUCTs in C/C++. A RECORD is composed of a number of variables any of which can be of any predefined data type, including other RECORDS or ADTs.

A simple example of a RECORD:

TYPE Description = RECORD
    Year   : CARDINAL;
    Model  : ARRAY[0..20] OF CHAR;
    Engine : ARRAY[0..8] OF CHAR END;
    Cars   : ARRAY[1..10] OF Description;
    Index  : CARDINAL;
    END;

Modula-2 also supports variant records, which will allow you to define different data for each record without wasting data storage space in memory. By including a CASE statement in the RECORD's definition, the data needed for that record can be precisely allocated. An example of variant records is shown in VARREC.MOD of the Dodrill tutorial. Notice that the kind of vehicle that is created determines the additional data types allocated in memory to that record.

Details of supported data types in Modula-2:
INTEGER  : Can be any integer value from -32768 to 32767 (machine dependent)
CARDINAL : Similar to 'unsigned int' - can be any integer value from 0 to 65535.
REAL     : Industry standard single-precision floating point value
LONGREAL : Industry standard double-precision floating point value
BOOLEAN  : Enumeration of values TRUE or FALSE
CHAR     :
Enumeration of characters and digits
           Strings are handles as an array of CHAR elements
ARRAY    : Modula-2 allows for two different types of arrays
  FIXED  : Arrays with index range defined at compile time
           Index range is programmer defined
           Ex - ARRAY [-5..10] OF REAL;
  OPEN   :
Arrays with no defined index range - defined at run time
           Index range is not defined - usually used in subprogram declaration
           Ex - ARRAY OF REAL;
Multi-dimensional arrays can be used without (theoretical) limitation of the number of dimensions.
SETS     : Enumerated list of type with. Modula-2 has all set operations built in.
RECORD   : Described above
POINTERS : Memory references with keywords POINTER TO
Union types are not explicitly used in Modula-2, but the use variable records is similar.

Supported data types in C:
Integers, real, characters, Boolean, pointers, arrays, and records.

References:
1) http://burks.bton.ac.uk/burks/pcinfo/progdocs/plbook/oop.htm
2) http://www.inmet.com/~stt/bindings/c2ada/c2ada.html
3) http://cgibin.erols.com/ziring/cgi-bin/cep/cep.pl?_alpha=m
4) Sebesta, Robert W. Concepts of Programming Languages, Sixth Edition. Reading, Massachusetts: Addison-Wesley, 2002.

 


Handling of Sequence Control
w/Comparison to C
Jeff Heckathorn

Modula-2 as a block structured procedural language executes in separately defined program modules. Each module is broken down into executable procedures. The sequence of control moves from module block to procedure sub-block through program execution.

Modula-2 makes no allowances for a
GOTO type of branching statement. The highest level of sequence control in Modula-2 is between the modules themselves. Each module can call any other module. Modules import and export information or function calls. After a module is finished executing it releases control with an EXIT statement. When a module is done the program returns to the statement after the statement that called the module. If the module was the main module for the running program then control is returned to the operating system when the module is ended.

Procedures can call other procedures, themselves or local, and non-local modules. Procedures are ended with a
RETURN statement at which time the program returns to the statement just after the procedure call. Procedure returns must match the procedure type. So that a function procedure return must have a return value.

Modula allows for several looping control statements. They are:
REPEAT...UNTIL, WHILE loop, FOR loop, and the infinite loop. The REPEAT...UNTIL loop begins with the keyword REPEAT. Everything from the repeat to the keyword UNTIL is repeated until the expression after the until keyword evaluates to a Boolean true. The expression can be any expression as long as it has a Boolean value. The WHILE loop is similar to the REPEAT loop except that it is evaluated at the beginning and the loop executes until the condition is false. The end of the loop is designated with an END keyword. The FOR loop has the reserved words FOR, TO, BY, DO, and END. The syntax for the for loop is:

    FOR index := 5 TO 25 BY 4 DO

The for loop executes until an increment equals an ending condition. In the above statement the
FOR keyword denotes the beginning of the for loop. The variable index is the variable that will be indexed up or down until the ending condition is reached. The variable index can be any type except REAL, Including the CHAR type. The starting value for the index variable is given followed by the keyword TO then the ending value. When index equals this value the for loop will end. The BY keyword designate the interval to be added to the index value. If this is omitted then a default of 1 is used. The DO keyword designates the beginning of the actual loop. The end of the for loop is designated by the END keyword. The infinite loop uses the keywords LOOP, and END. This loop has no formal termination criteria. The loop must be stopped by some other means within the loop. Usually a conditional statement with an EXIT command is used to end the loop and execute the rest of the procedure.

The if-then statement has the following keywords associated with it:
IF, THEN, ELSE, ELSIF, and END. The if-then statement begins with the IF and a conditional that evaluate to Boolean true or false. If the condition is true then the statements after the then are executed. If the condition is false then if the ELSE is present then the ELSE statements are executed. For the if-then statement the ELSE is optional. The ELSIF statement is another conditional that is listed after the if statement so that if the IF is not true and the ELSIF is trus then the instructions for the ELSIF are executed. It is possible to have multiple ELSIF statements with an IF statement. The END keyword marks the end of the if conditional.

The
CASE statement is a multi-way branching statement and is best explained by using an example:

MODULE CaseDemo;

FROM InOut IMPORT WriteString, WriteInt, WriteLn;

VAR Dummy : INTEGER;

BEGIN

FOR Dummy := 1 TO 25 DO
    WriteInt(Dummy,4);
    WriteString(" ");
    CASE Dummy OF
        1..5 : WriteString("the number is small"); |
        6..9 : WriteString("it is a little bigger"); |
        10,11 : WriteString("it is 10 or 11"); |
        14..17 : WriteString("it is midrange"); |
        18,20,22,24 : WriteString("it is big and even"); |
        19,21,23 : WriteString("it is big and odd");
    ELSE
        WriteString("The number didn't make the list");
    END; (* of CASE *)
    WriteLn;
END; (* of FOR loop *)

END CaseDemo.


From the example the case statement begins with the keyword
CASE followed by the variable name to be used to evaluate the case criteria. The variable can be any type except REAL. The keyword OF denotes the beginning of the case criteria. In this example the variable Dummy is an integer and the first case of 1..5 indicates that this section is to execute the following statements when Dummy is equal to any integer value from 1 to 5 inclusive. A comma between values indicates distinct values - not a range. There can be multiple statements executed before the | token which is used to indicate the end of that case. After all of the listed cases an ELSE statement executes if no match to the cases was found. The end of the case statement is designated by the END statement.

References:
1) http://usuarios.lycos.es/ncabanes/modula2n.htm
2) http://www.modulaware.com/mdlt52.htm
3) http://www.twu.ca/rsbook/ch10/ch10.8.html
 


Handling of Subprograms & Storage Management
w/Comparison to C
Ali Wajid

Subprograms in Modula-2 are referred to as ‘procedures’. Modula-2 requires all procedures’ header and body to be written before the main program. There are two kinds of procedures in Modula-2. One is just simply called ‘procedure’ and the other one is called a ‘function procedure’. ‘Procedure’ basically does not have a return type and it does not return a value to the main program. ‘Function procedure’ is the one that actually has a return type defined and it returns a value to the main program. The return type of a procedure is written at the end of the line in the header. Just like other programming languages, several parameters can be passed to procedures at once. Modula-2 also allows the capability of passing parameters by either value or by reference. Arrays or pointers can also be passed as parameters to procedures. According to my understanding, overloading procedures is not allowed by Modula-2, which means two procedures must have different names otherwise it would cause an error. Moreover, procedures are allowed to call other procedures but there are certain rules that must be followed. Procedures in Modula-2 can only call procedures that have the same parentage or the procedures that are defined within the class of a procedure. For example, consider the procedures defined in the following format:

Procedure1(......)
    {//some code}
Procedure2(.....)
    { //some code
    Procedure3(....)
        {//some code}
    Procedure4(....)
    { //some code
        Procedure5(....)
        {//some code}
    }
}


In this case, the main program can only call
Procedure1 and Procedure2. Procedure2 can call Procedure3 and Procedure4, and Procedure5 can only be called by Procedure4.

Subprograms in C are just simply called ‘functions’. C requires the prototype of all functions to be written before the main program but it does not matter where we actually put the actual function with the body. It is preferred to have it at the end after the main program. Functions in C also have a return type and they return a value back to the main program. In C, unlike Modula-2, we write the return type of the function first in the header, then the name of the function and then parameter list. If a function in C does not return a value, it is called a ‘void’ function. Void is a return type which basically tells the programmer and the compiler that the function that we are calling does not return a value. C also allows us to pass several parameters to the functions at once, and just like in Modula-2, these parameters can be either pass by value or pass by reference. Arrays or pointers can be passed as parameters in C as well. Just like Modula-2, C also does not allow the functions to be overloaded. So, all of the functions in a C program must have different names - otherwise the compiler can not tell which function it is suppose to call. Unlike Modula-2, we do not define a function inside the body of another function. All functions are separately defined in a C program, and any function in a program can call any other function in that program. There are no limitations as to which functions in the program can call which other functions, and all of the functions defined in the program can be called by the main program.

References:
1) http://usuarios.lycos.es/ncabanes/modula2n.ht
2) http://cslibrary.stanford.edu/101/EssentialC.pdf
3) http://www.dcs.ed.ac.uk/home/iok/cforjavaprogrammers.phtml


Handling of Abstraction and Encapsulation
w/Comparison to C
Tom Heffron

Block-structured procedural languages seem to have been the breeding ground for different levels of abstraction and encapsulation. Block languages fall in the range from almost fully object-oriented down to some examples that have very few of these capabilities. Modula-2 and C are examples of block-structured languages at different ends of this spectrum.

As noted in the Sebesta text, encapsulation is a necessary component of data abstraction - and most languages in the block-structured family include some sort of capability for encapsulation. Particularly because Wirth's goals were to include support for data abstraction, Modula-2 has been designed around its form of encapsulation called modules - even the main program is defined as a module. These modules (as the definition of encapsulation suggests) aid the programmer in the organization of code and provides separate compilation. Separate compilation is accomplished with
.MOD and .DEF file names to create libraries of logically related data and subprograms. Similarly, C allows for encapsulation by incorporating separate compilation units in the form of .c and .h file names.

Block-structured languages are mostly distinguished from each other by the level of abstraction available to programmers in each language. Almost all languages - not just block structured - incorporate process abstraction, which is implemented by subprograms (procedures and functions). These allow a programmer to organize and reuse a set of processing code, as well as make large programs easier to read. Subprograms were discussed in the previous section, so we will concentrate on data abstraction.

Data abstraction is not only the ability to encapsulate data structures and associated operations for readability, but can also control access to certain data elements and procedures - this is where the family of block-structured languages begin to separate in functionality. Modula-2 incorporates information hiding by separating the specification and implementation of the these user-defined data types. The
DEFINITION MODULE (keywords) identifies the data structures and procedures that can be used by the client, but only shows the data definitions and procedure declarations. This module is usually encapsulated in the .DEF file name mentioned earlier. An example of this can be seen Dodrill's online Modula tutorial where he defines some functions on circles in CIRCLES.DEF. A separate encapsulation in the .MOD file name holds the hidden details and structure of this data type. This is identified by the IMPLEMENTATION MODULE keywords. Details of the 'circles' example is shown in the CIRCLES.MOD file. The program using this data type (the client) then uses the keyword IMPORT to tell the compiler where it can find certain externally defined procedures. Dodrill uses the program named GARDEN.MOD to call the 'circles' functions.

The power of data abstraction can be seen in the above examples by noticing that the subprogram called
GetPi(X), as well as variables such as Pie and Cake cannot be called directly by the GARDEN.MOD module - some texts call this 'opaque typing' - where the client program can declare variables, but cannot manipulate any details that are not explicitly EXPORTed. Modula-2 aids in the writability of a program by using the FROM keyword in the client module - this keeps the programmer from needing to use explicit notation. For example,

IMPORT Circles;
...
x := Circles.AreaOfCircle(Radius, Area);
...

can be written as

FROM Circles IMPORT AreaOfCircle;
...
x := AreaOfCircle(Radius, Area);
...


One final note about Modula-2 that adds to the capabilities of its data abstraction is that opaque data types must be scalar or pointer type. Therefore, any ADT that creates a
RECORD variable must actually EXPORT a POINTER TO that record to be used by the client module. Although this may complicate programming in terms of writability, this method allows for changes to an IMPORTed module to be recompiled separately from the calling module. If pointers were not used then after a change in an ADT's RECORD the client module must also be recompiled.

C, on the other hand, adds no capability for implementation hiding. Any abstraction other than the encapsulation of related data definitions and subprograms in libraries is not available. Any measures for data security - like the public/protected/private implementation many students are familiar with in C++ - does not exist in C.

References:
1) Dodrill, Gordon. "Coronado Enterprises Modula-2 Tutorial". March 16, 1987. http://www.ise.fhg.de/personal_home_pages/hubertus/texte/tabcont.html. (Oct. 27, 2002).
2) Louden, Kenneth C. Programming Languages Principles and Practice. Boston: PWS Publishing Company, 1993.
3) Sebesta, Robert. Concepts of Programming Languages, Fourth Edition. Reading, Massachusetts: Addison-Wesley, 1999.