[net.lang.mod2] Single Pass Modula-2 Compiler

claudio@ethz.UUCP (Claudio Nieder) (05/02/86)

It seems that a lot of people didn't read our last posting as we receive
a lot of questions concerning points we answered in that posting.
So here it is again:

We received some mail with questions about the public domain modula
compiler. Following the answers to the most frequently asked questions:

>   .. can we have the source .. where can we get the source ..

We didn't have the source of the modula compiler! 
The compiler is a generic 68000 compiler. It produces an objectfile
with a propretary format. To port this compiler to the Amiga, we
had to write a loader, which loads the objectfiles into memory,
translates some addresses and jumps into the program. This loader
was written in C. Additionally we had to write some machine
dependent modules needed by the compiler (FileSystem, Terminal ...).
This was done using a cross compiler.
The source of the compiler can be obtained through Modula Corporation.

>  .. What system stuff does it support? Windows, mouse, menus etc. ..

Yes, but you have to program it. We wrote a Module AMIGADos which
gives access to the AMIGADos functions. In a similiar way you can
handle Intuition routines. Feel free to post YOUR implementation of
Amiga specific modules, so others can use it.

>  .. How should I make the $15 payment ? ..

Please transfer $15 to the account

	Rene Degen
	10 - 995.307.0

	Swiss Bank Corporation
	CH - 4002  Basel, Switzerland

claudio@ethz.UUCP (Claudio Nieder) (05/13/86)

Single Pass Modula-2 Compiler Tutorial             (12-may-86/kussi)
======================================

The group headed by N. Wirth is currently working on Modula-2 Systems
for MC68000 and NS32032 Processors. In this work the MacMETH System for
MacIntosh has been developed. This system consists of a single pass
compiler, a symbolic debugger and an editor.
We claudio, jr, red & kussi are students of computer science and Amiga
owners. The first thought after receiving our self-imported machines was
to port the compiler to the Amiga. After some discussions with the
people who developed the Mac System, we got the object code of a
pre-release of the compiler running on the Mac and a cross compiler for
Lilith. The compiler generates a generic code format containing linking
information that needs a special loader to run. Within a month
we wrote our loader (ALoad) in C on the Amiga and the system interface
modules using the cross compiler.

This work is now distributed in the public domain and we hope that many
people learn to love Modula-2.

All languages change from time to time, N. Wirth changes his Modula
very often and the version supported by this compiler isn't very 
compatible to the first revision of Modula-2:

Our compiler supports:

- Standard Functions:
	ABS, CAP, CHR, FLOAT, FLOATD, HIGH, ODD, ORD, TRUNC, TRUNCD,
	DEC, EXCL, HALT, INC, INCL, MAX, MIN, SIZE, VAL;

- SYSTEM TYPEs & PROCEDUREs:
	ADDRESS, BYTE, WORD,
	ADR, SHORT, LONG, SHIFT, TSIZE, INLINE, REG, SETREG;

Declaration must preceed use, so FORWARD is implemented.
	PROCEDURE a(...); FORWARD;

BUG in AMIGADos.MOD
===================

Sorry, in the implementation of AMIGADos is a bug. (at least one!)

PROCEDURE Lock(name: ...

  IF accessWrite THEN
    reg.d[2]:=-1D (* instead of -2D *)
  ELSE
    reg.d[2]:=-2D (* instead of -1D *)
  END

Replace the two absolute values to have a correct working Lock.

NOTE:	Do not compile AMIGADos.DEF! This would result in incompatible
	module importation.



			Have fun, and send us your questions
				kussi/claudio/jr/red

KURKURE@SUSHI.STANFORD.EDU (Uday Kurkure) (09/30/86)

    Having merged Logitech's Modula-2 compiler's pass1 and pass2 into
    a single pass,  I think that if you have identifiers used in
    statments before declaring them, it is not possible to have 
    a one pass compiler because you can not do the type checking in a 
    reasonable way.

    MacMeth's ( Single pass Modula-2 Compiler from ETH ) user
    manual explicitly states it as one of the restrictions on 
    page 23 that no forward references are permitted except in 
    definition of pointer types and in forward procedure declarations.


                                       ..Uday

                                      { kurkure@su-sushi.arpa

                                        !decwrl!logitech!uday
                                      }
   Disclaimer: These are not my employer's views but my own
               personal views.
-------

mwm@cuuxb.UUCP (Marc W. Mengel) (10/02/86)

In article <12243102365.25.KURKURE@Sushi.Stanford.EDU> KURKURE@SUSHI.STANFORD.EDU (Uday Kurkure) writes:
>    Having merged Logitech's Modula-2 compiler's pass1 and pass2 into
>    a single pass,  I think that if you have identifiers used in
>    statments before declaring them, it is not possible to have 
>    a one pass compiler because you can not do the type checking in a 
>    reasonable way.

	Actually, you can note the fact that whatever type the symbol has
    must be compatable with how it is being used, and check that against
    the actual declaration when you see it.  For example, if I see a
    function call:

    intvar := funct( 5.0, "test", 7 );

    I can note that funct must return a type that can be assigned to an int,
    and accept a floating point, char array, and integer argument;  then,
    when I see a declaration of funct, I can check against this usage, and
    determine whether the previous usage was correct.  While this may seem
    to be a lot of bookkeeping, it seems to me the gains in speed for a 
    one pass compiler are sufficient to warrant it.  I may also need to
    back-patch some appropriate type conversions (i.e. integer->real, etc.).

-- 
 Marc Mengel
 ...!ihnp4!cuuxb!mwm

rpd@f.gp.cs.cmu.edu (Richard Draves) (10/08/86)

In article <841@cuuxb.UUCP> mwm@cuuxb.UUCP (Marc W. Mengel) writes:
>	Actually, you can note the fact that whatever type the symbol has
>    must be compatable with how it is being used, and check that against
>    the actual declaration when you see it.  For example, if I see a
>    function call:
>
>    intvar := funct( 5.0, "test", 7 );
>
>    I can note that funct must return a type that can be assigned to an int,
>    and accept a floating point, char array, and integer argument;  then,
>    when I see a declaration of funct, I can check against this usage, and
>    determine whether the previous usage was correct.  While this may seem
>    to be a lot of bookkeeping, it seems to me the gains in speed for a 
>    one pass compiler are sufficient to warrant it.  I may also need to
>    back-patch some appropriate type conversions (i.e. integer->real, etc.).

And what if it turns out that funct is really a type, and that statement
should have been flagged as a syntax error?  I think that if you really
look carefully at what your proposal would do to calling sequences, and
the amount of backpatching that would be needed, you'll agree that it's
impractical at best.

Rich

mwm@cuuxb.UUCP (Marc W. Mengel) (10/09/86)

In article <8@f.gp.cs.cmu.edu> rpd@f.gp.cs.cmu.edu (Richard Draves) writes:
>In article <841@cuuxb.UUCP> mwm@cuuxb.UUCP (Marc W. Mengel) writes:
>>	Actually, you can note the fact that whatever type the symbol has
>>    must be compatable with how it is being used, and check that against
>>    the actual declaration when you see it.  For example, if I see a
>>    function call:
>>
>>    intvar := funct( 5.0, "test", 7 );
>>
>>    I can note that funct must return a type that can be assigned to an int,
>>    and accept a floating point, char array, and integer argument;  then,
>>    when I see a declaration of funct, I can check against this usage, and
>>    determine whether the previous usage was correct.  While this may seem
>>    to be a lot of bookkeeping, it seems to me the gains in speed for a 
>>    one pass compiler are sufficient to warrant it.  I may also need to
>>    back-patch some appropriate type conversions (i.e. integer->real, etc.).
>
>And what if it turns out that funct is really a type, and that statement
>should have been flagged as a syntax error?  

	Then as soon as you realize it, you should print out the fact that
a syntax error was detected, in the original place.  Sure, this may mean
that syntax errors are printed out of order by line number;  but that is
not really a problem.

>I think that if you really
>look carefully at what your proposal would do to calling sequences, and
>the amount of backpatching that would be needed, you'll agree that it's
>impractical at best.

First; I was not argueing practicality, I was arguing possibility.  I
realise that the amount of work required to do this properly in a
strongly typed language like Modula2 is probably large.  The real
question is: does this extra work exceed the slowdown of using a
2-pass compiler?

One simple method of dealing with the backpatch problem, is to compile
any expression you cannot resolve as:
	jsr backpatch<nnnn>
and save up the code and its context someplace.  Then at the end of
the compilation module, put down each backpatch<nnnn>, and generate
the code you could not before.  if you can't NOW, having seen the
entire compilation module, you have a bona-fide error, and can report
it (generating an out of order by line number error message).  If
you can compile it now, you can plunk the code down followed by a
return from subroutine call, and fix the address in the jsr backpatch<nnnn>
call.  The only expense is the "save up the code and its context" part.
I am presenting the proposition that this may be, although costly, still
cheaper than a second pass.

Yes, FORWARD declarations are simpler, and probably a better solution, I
was making a purely "religious" comment on the statement that it was
*impossible* to make a one-pass full-Modula2 compiler.
>
>Rich



-- 
 Marc Mengel
 ...!ihnp4!cuuxb!mwm

randy@oresoft.UUCP (10/13/86)

Declaration after use is an abomination, and should not bear consideration.
FORWARD is acceptable for mutually recursive procedures.

What has been omitted from this discussion is that one-pass restrictions would
prevent mutually importing internal modules.  This is a real and difficult
restriction, which will force one to promote internal modules to become
library modules sooner than one might wish.

The question is can we live with such restrictions to gain compilation speed.
My opinion is yes.  And yours (pl.)?

rpd@f.gp.cs.cmu.edu (Richard Draves) (10/14/86)

First, I want to clarify my definition of a one-pass compiler.  Ideally,
a one-pass compiler can compile program of unbounded size using a bounded
memory.  Problems with symbol table size may make this impossible, but
I think that captures most people's intuition.

This rules out reading the entire program into memory in the form of
a syntax tree and then generating code.  It also rules out saving
large amounts of information (can be as much as every reference to
a non-local variable/function/type in a statement) for later type-checking
and back-patching.

Mutually importing modules are an interesting idea.  This summer
I tried a considerable number of test programs, using both the
Powell compiler and the Hamburg compiler.  If I remember the results
correctly, neither accepted the obvious attempts, but the Powell
compiler would accept some examples when one module was local to the other.
The language definition is so vague that a compiler can do almost anything
it want for programs that are off the beaten path.

Rich

haynes@DECWRL.DEC.COM (10/15/86)

	Re: Declaration after use is an abomination, 
	    and should not bear consideration.

Yeah? And so's your mother! (Proof by assertion refuted by childish ad
hominem attack. Now that I've satisified net protocol...)

What's wrong with declaration "after use"? Especially for procedures
and the destinations of pointer types, declaration after "first
mention" is often a natural programming style. It does make single pass
compilation more difficult, sometimes impossible, and has performance
implications for any compiler that has to translate the language that
allows it. However declaration after use is not the obvious abomination
you would try to hand wave us into believing.

If claim that declaration before use results in more correct, easier to
maintain programs, I will reply that the easiest to maintain large
programs I ever worked on had all procedures declared in strict
alphabetical order. That sure made a given procedure easy to find.

One pass compilers are a boon to compiler writers and people who have
to run on small machines. For them a one pass compiler is often the
only possibility. For others who have large machines, and want an easy
to use language, but don't want to sacrifice correctness or efficient
object code, a multi-pass compiler is often the right thing.

	-- Charles

ehs@magic.DEC.COM (Ed Satterthwaite) (10/16/86)

 Re: Declaration after use is an abomination, and should not bear
     consideration.

I can't accept this.  After many attempts to settle upon a good rule for
arranging (procedure) declarations in a logical and natural order, I've
concluded that there is no single best arrangement.  One that often works
well for me is simple alphabetical order, sometimes with the public entry
points sorted into a separate series at the beginning.  In other
situations, a top-down arrangement of procedures seems best.  In either of
these arrangements, a lot of declarations occur

randy@oresoft.UUCP (Randy Bush) (10/17/86)

And your mother wears combat boots!

Certainly I agree that forward reference is needed to resolve pointer
declarations.  And I agree that PIM-2.[1..3] would allow forward
reference to procedure declarations, although discussion here has not
revealed a method for one-pass compilation of such - forward declaration
being the only technique discussed so far.

What I refer to is that PIM-2[1..3] would seem to allow

  PROCEDURE A ();
  BEGIN
    x := 42
    END A;
  VAR x : CARDINAL;

randy

randy@oresoft.UUCP (Randy Bush) (10/17/86)

The fourth pass of the old ETH compiler had mutually importing internal
modules, both at the outer level of the enclosing implementation module.
As the compiler could compile itself, I am nonplussed that its compilers
derived from it could not.

I would note that if two internal modules are mutually importing, that both
may not have code in their module bodies (the initialization sections, not
procedures), as it is a case of circular initialization.  A degenerate
example might be

  MODULE A;
    MODULE B;
      IMPORT c;
      EXPORT b;
      VAR b : CARDINAL;
      BEGIN
        b := c + 42
        END B;
    MODULE C;
      IMPORT b;
      EXPORT c;
      VAR c : CARDINAL;
      BEGIN
        c := b + 42
        END C;
    END A.

randy

Felton.pa@XEROX.COM@ndmce.uucp (10/18/86)

	Re: Declaration after use is an abomination, 
	    and should not bear consideration.

	If you think about it, requiring that procedures be declared before
they are called is contrary to the ideals of top down programming. 
	
	
John

p.s. I know. You don't have to write the program in the same order that
it appears in the listing. But, in practice this is often the way that
it is done.