Feedback Search Top Backward Forward
EDM/2

Modula-2 Legacy Code: Problems and Solutions

Written by Dmitry Leskov

Linkbar

  Modula-2 and OS/2 have one common fact in their histories: shortly after they were introduced they were called "the programming language of the future" and "the operating system of the future", respectively. Back in 1980s, a significant number of companies had chosen Modula-2 as a major instrumental language. A few years later many companies had staked on OS/2. Apparently, there were companies that developed their OS/2 applications using Modula-2 compilers, such as TopSpeed and Logitech.

As it turned out, most of those companies have to regret that decisions now: the Win32 customer base is much larger and grows dramatically, while the OS/2 one is stalled, if not reducing because of the movement to Win32.

The situation with Modula-2 is not much better. Most OS/2 compiler vendors have dropped their Modula-2 products long ago. TopSpeed sells a new 32-bit compiler only as part of the Clarion package, which is very expensive and is not available for OS/2.

If you develop custom applications that are shipped to clients along with the source code, you may be 100% sure nobody will order anything that relies on an unsupported 16-bit compiler. In addition, customers no longer want to buy programs written in "exotic" languages, which are those that are neither C nor C++. The ISO 10514 Modula-2 Standard [1], voted in 1996, appeared too late to seriously influence public attitude to the language.

So, is there a chance for applications written in Modula-2 to catch up? There are two ways: (a) migration of the source code to a modern 32-bit ISO Modula-2 compiler; and (b) conversion of the source code to an industry standard language, such as C or C++. Technical problems that may arise in the process of migration or conversion are discussed in the following two sections, along with some possible solutions.

Migration

So you think Modula-2 is a better language than C or C++, but the old 16-bit compiler ties you up. Apparently, moving to a new 32-bit ISO compiler is quite a job; this section tries to give you some idea how to solve the problems you are likely to encounter.

Language

Old Modula-2 compilers, such as TS or Logitech, implement the language described in Wirth's "Programming in Modula-2" (PIM) - the book that had been a de facto standard for years. Modern compilers comply with the ISO 10514 Standard, which added a lot to PIM, but is not a superset of it. Also, probably due to the lack of an official standard, PIM compiler vendors introduced plenty of language extensions. Usually, these problems are relatively easy to solve (context search and replace can be sufficient in some cases), but, for instance, TopSpeed Modula-2 OO extensions have no analogy in other products.

So, if your new compiler has no PIM compatibility mode, you'll have to modify your sources by hand. Of course, in most cases the compiler will display an error message upon encountering a language construct that it does not recognize, but there are subtle differences that it probably does not detect. For instance, absence of the ELSE clause in a CASE statement is equivalent to presense of an empty ELSE clause in PIM. In contrast, according to ISO 10514, if the value of the case selector is not contained in any case label list and the ELSE clause is not present, an exception shall be raised. Therefore, the following CASE statement:

  CASE x OF
  |0: p0;
  |1: p1;
  END;
does nothing if compiled by a PIM compiler, and raises an exception if compiled by an ISO compiler, provided that the value of 'x' is neither 0 nor 1.

Some ISO Modula-2 compilers detect situations like the above and produce warning messages.

Sizes of base types

Another thing to consider is the sizes of the base types. INTEGER, CARDINAL, and BITSET are 16 bits wide in old 16-bit compilers, whereas in modern compilers these types are 32 bits wide. Unfortunately, this problem resembles the famous Year 2000 problem - no one can tell where in a million of source lines your program relies on base types being exactly 16 bits wide.

There are "passive" solutions provided by some of the current compilers, such as a compiler option that forces base types to be 16-bit, or a set of fixed size types in the module SYSTEM, e.g. INT16, CARD32, etc. But in general, it is recommended to use 32-bit types anywhere except when there is a need to represent externally defined data structures, such as network packet layouts or database records.

Libraries

Wirth proposed just a few simple library modules in PIM, so each actual implementation included its own set of library modules. The International Standard introduced yet another one. Some of the currently available Modula-2 programming systems contain library modules compatible with those shipped with old compilers, usually TopSpeed.

If your application intensively uses library facilities, you may consider re-implementing some of the library modules (probably on top of the ISO library); otherwise you will have to replace library calls.

API calls

All Modula-2 programming systems provide capabilities to access the underlying operating system API, but the ways they map C API headers to Modula-2 may significantly differ.

In addition, many OS/2 16-bit calls are now obsoleted by 32-bit ones and are not included in the latest issues of the IBM OS/2 Developer's Toolkit. Some of the modern compilers provide no support for 16-bit system calls, except VIO*, Mou*, and Kbd*. You may need to replace 16-bit calls with their 32-bit equivalents or write C wrappers for them.

Programming systems

Of course, each compiler has its own set of options. Project systems are incompatible as well. Special care should be taken with compiler options and pragmas which affect program semantics, such as TopSpeed's "call (o_a_copy -> off)".

Conversion

So you do not want to stay with Modula-2 or simply cannot do it because of the customers, but neither can you afford rewriting hundreds of thousands lines in C or C++. In this case, consider using a Modula-2 to C translator - there are some on the market.

Conversion to C/C++ involves some extra efforts in addition to those listed in the previous section, because of the differences between these languages and Modula-2. Major differences are discussed in this section.

Scopes

C and C++ have no local modules and nested procedures. It is still possible to correctly translate nested procedures, but the resulting code lacks readability - a converter has to introduce extra parameters for outer procedure's locals that are used in nested procedures. It is recommended to get rid of nested procedures before conversion.

  PROCEDURE proc(a: INTEGER);     static void loc1(int * b, int a)
    VAR b,c,d: INTEGER;           {
                                    *b=a;
    PROCEDURE loc1(a: INTEGER);   } /* END loc1 */
    BEGIN
      b:=a;                       static void loc2(int * b,
    END loc1;                                      int * a,
                                                   int * d)
    PROCEDURE loc2;               {
    BEGIN                           loc1(b, *d+*a);
      loc1(d+a);                  } /* END loc2 */
    END loc2;
                                  static void proc(int a)
  BEGIN                           {
    c:=1;                           int c;
    loc2;                           int b;
  END proc;                         int d;
                                    c=1;
                                    loc2(&b, &a, &d);
                                  } /* END proc */
Note: In this example the variable "c" needs not be passed as an additional parameter, as it is only used in "proc" itself.

Data types mapping

Some Modula-2 data types have no direct equivalents in C/C++. In particular, there are problems with large set types and arrays indexed from a value other than zero. Sophisticated macros or C++ classes have to be used to preserve semantics of declarations and operations or these types. Macros are more error prone than classes, but usually give better performance. A conversion tool may support both options.

  // Arrays indexed from arbitrary values

  #define ArrayOf(T,L,H) Array

  template
  class Array
  {
     public:
        inline T& operator[]( const long index ) const
        {
           return (T&) ( storage[index-L] );
        };
     private:
        T storage[H-L+1];
  };

Statements mapping

All Modula-2 statements seem to have an obvious mapping to C/C++. But a closer look shows that this is not true. In the example below, although the first translation is correct, the second is not because of the possible side effects of P() and Q().

  FOR i:= 1 TO 10 DO          for (i = 1; i<=10; i++) {
    S(i);                         S(i);
  END;                        } /* end for */

  FOR i:= P() TO Q() DO       for (i = P(); i<=Q(); i++) {
    S(i);                         S(i);
  END;                        } /* end for */
As P() and Q() have to be evaluated only once, the correct translation of the second FOR statement might look like:
  FOR i:= P() TO Q() DO       tmp = Q();
    S(i);                     i = P();
  END;                        if (i<=tmp) for (;; i++) {
                                  S(i);
                                  if (i==tmp) break;
                              } /* end for */
Notice the introduction of a temporary variable.

You may want to rewrite some of your FOR statements before conversion to improve the resulting program.

Library Mapping

Straightforward translation of Modula-2 library calls typically produces code that a C programmer would never write, e.g.:

  Storage.ALLOCATE(p,SIZE(A));   Storage_ALLOCATE(&p, sizeof(A));
whereas the desirable result is:
  p = malloc(sizeof(A));
An advanced conversion tool could translate standard Modula-2 library calls to ANSI C or POSIX calls, but due to diversity of libraries in pre-ISO Modula-2 programming systems such tools are only available on a custom basis.

Most current Modula-2 implementations support interfacing to C libraries, so an alternative approach is to replace Modula-2 library calls with C library calls right in the Modula-2 code prior to conversion.

The Universal Solution

There are still several vendors of Modula-2 compilers and some freeware Modula-2 compilers and translators to C are still maintained by educational institutions and language enthusiasts. More information can be found in the Modula-2 FAQ at:

  ftp://FTP.twu.ca/pub/modula 2/m2faq.html
XDS Ltd. (http://www.xds.ru) is a single vendor that offers a full range of Modula-2 legacy code solutions. First of all, it has a family of Modula-2 products that could assist you in both migration and conversion. The family includes 32-bit native code Modula-2/Oberon-2 compilers (Native XDS-x86) and translators to ANSI C/C++ (XDS-C) for OS/2, Windows NT/95, and Linux. All compilers and translators support the ISO Modula-2 Standard, as most of the modern Modula-2 compilers do. Native code compilers for OS/2 and Windows NT/95 come with a set of TopSpeed-like library modules to facilitate porting from TopSpeed Modula-2.

The currently available XDS-C package (version 2.31) is capable of translating ISO Modula-2 to ANSI C/C++, preserving identifiers, program structure, types, comments, etc. However, as it was not originally developed as a conversion tool, XDS-C 2.31 still lacks some important features. For instance, it evaluates constant expressions instead of translating them. The next generation of XDS-C will address these issues and is expected to improve conversion quality to the maximum extent possible. It is scheduled for release in 4Q98.

Then, the company now offers Modula-2 migration and conversion services. For instance, you may order a custom conversion tool based on XDS-C that supports the Modula-2 dialect implemented by the vendor of your old compiler, thus saving a lot of working hours and reducing the risk of introducing errors during migration from that dialect to ISO Modula-2. In fact, you may even order a converter for a language other than Modula-2, but this topic is beyond the scope of this article.

Finally, you may outsource the entire migration or conversion process.

You may read more about XDS Modula-2 products and services at

http://www.xds.ru/

The XDS Modula-2 product pages are mirrored at

http://www.dct.com/~johnm/xds.html

XDS Ltd. can be contacted by e-mail at info@xds.ru.

Further Reading

  1. ISO/IEC 10514-1:1996 - Modula-2 (Base Language) - The Modula-2 International Standard.
  2. The Modula-2 FAQ ( ftp://FTP.twu.ca/pub/modula2/m2faq.html)
  3. TopSpeed-to-XDS Porting Notes ( http://www.xds.ru/xds/xdsdoc/tspn.html)
This on-line document covers TopSpeed->XDS porting issues, but some of the remarks are applicable to the more general PIM->ISO case.
 

Linkbar