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.