Project 2: Types and parameter passing mechanisms

Goals of the project

This project will give you implementation experience in the following areas:
In addition, this project will give you experience in using the following concepts:
You will use the Modula-3 programming language for this project.
 

Introduction

The Modula-3 programming language supports two parameter passing modes: by value and by reference but it does not support parameter passing by name.  In this project we will write a preprocessor that takes a program written in a subset of Modula-3 plus some new syntax for parameter passing by name and rewrites it into a legal Modula-3 program that uses parameter passing by name.

Recall from the class notes that parameter passing by name works by passing a thunk instead of the argument.  In C++ like syntax, to implement parameter passing by name you would have to rewrite:

main() {
  int i;
  f(i);
}

as

main() {
  int i;
  int *i_thunk() {
    return &i;
  }
  f(i_thunk);
}

Also the body of "f" needs to be suitably modified so that every time it wants the value of its parameter, it invokes the thunk that is passed in instead of the parameter.  For example,

void f(int x) {
  x = x + 1;
}

would be rewritten as

void f(int * (*x_thunk())) {
  *x_thunk() = *x_thunk() + 1;
}

Note that the parameter to "f" is not "x" as before but a function that takes no arguments and returns a pointer to an integer.

My solution to this project has these phases:
 

My solution to the code you have to write makes up about 300 lines (including all declarations and blank lines between declarations).  However, in order to do this assignment, you will need to understand my code at some level and get a good understanding of Modula-3.  The two parts of Stage 0 will give you a good understanding of the code and a working knowledge of Modula-3.

Background: Modula-3

For a full definition of Modula-3 see the Modula-3 language definition.  Also, this tutorial (maintained by Francisco Reyes and Blair MacIntyre) may also be helpful to you;  amongst other things it shows you how to write a simple, small and self-contained program.  I recommend that you start with the tutorial and work through the examples there and use the language definition as a reference.  The language reference is compact (50 pages) but quite terse and does not have many examples.  The tutorial has several examples.  In addition, we will be giving you additional examples in recitation and class.
 
Modula-3 is not dissimilar to Java; as a matter of fact, some people jokingly call Java "Modula-3 in C++ syntax".  For example, Modula-3 has procedures just like  C++.  In the rest of this section, I'll describe some of the features of Modula-3 that are different from corresponding features in Java.
 

Procedures in Modula-3 versus C/C++


int f(char c) {
  if (ch == 'a') return 1 else return 0;
}

in C/C++ is similar to:

PROCEDURE f(c: CHAR): INTEGER =
  BEGIN
    IF ch = 'a' THEN RETURN 1; ELSE RETURN 0; END;
  END f;

Note that the "=" operator in Modula-3 is a test for equality and not an assignment as in C/C++/Java; ":=" is the assignment operator in Modula-3.
 

Objects in Modula-3 versus C++/Java

Modula-3 also supports objects, inheritance, and exceptions but they have a different syntax than Java.  The tutorial does not contain examples of objects but the language definition, of course, describes how they work.  I'll give a simple example here;  you will see more examples in class, recitation, and in the code I give you as part of the project.

Let's consider a simple class hierarchy in Java:

class T {
  int i;
  void m1();
};

class S extends T {
  int j;
  void m1();
 void m2();
};

void S::m1() {... }
void S::m2() {...}

In this hierarchy, class S inherits from class T and provides its own implementation for method m1.  In addition, it introduces a new method, m2.  An equivalent hierarchy in Modula-3 would be:

TYPE T = OBJECT
   i: INTEGER;
METHODS
   m1();
END;

TYPE S = T OBJECT
  j: INTEGER;
 METHODS
  m2() := mym2;
 OVERRIDES
   m1 := mym1;
  END;

PROCEDURE mym1(this: S) =
  BEGIN ... END mym1;

PROCEDURE mym2(this: S) =
   BEGIN ... END mym2;

There are two big differences between the Modula-3 and Java code: (i) In a modula-3 class overrides and new methods are delimited by OVERRIDES and METHODS respectively; (ii) In Modula-3 one needs to declare the "this" explicitly as the first argument of the method.  In Java (and C++), this is implicit.

Note that this is not intended as a complete or definitive description but just as examples.  You should refer to the tutorial and language definition for more information.

Using the Modula-3 system

The directions here apply to the linux machines in the undergraduate lab (which include  em, en, oh, pee, queue, are, es, tee, you, vee, doubleu, ecks, why, zee). The Modula-3 distribution comes with a debugger m3gdb that works exactly the same as gdb.  I find it very handy for debugging programs.
 

Stages of the project

Resources

The SRC Modula-3 web page contains a wealth of information on how to use the Modula-3 compiler.  It also contains a link to an "alphabetical index" of all libraries that come standard with Modula-3.  You will note that I use several of these standard libraries for input/output, lists, etc. in my code.  Here are some libraries I recommend you look at; I've found them useful in my solution:
  Note that m3makefiles have a special syntax for instantiating generic libraries (templates in C++ lingo).  For examplle, if you want to have a list of ParseNode, simply add this like to the m3makefile:
list(ParseNode, ParseNode)
This will automatically instantiate the template for a list and create a new interface and moule called ParseNodeList.i3 and ParseNodeList.m3 for you to use.  ParseNodeList.i3 has a type called "T" in it which is the type of the list.  You can use this list by importing ParseNodeList in your program.