[Oberon] Conditional compilation using IF const THEN

Jörg joerg.straube at iaeth.ch
Sun Aug 12 13:12:35 CEST 2018


With a multi-pass compiler this IF optimization is much simpler as you can look for constant IF-branches and prune the tree before code generation.

 

With a single-pass compiler where parsing and code generation is interleaved, there are principally two different approaches:

 

A) add code to only parse. Something like a clever SkipUntilMatchingEnd(). It has to handle nesting...

 

B) influence code generation if the IF-condition is constant. Not very elegant code but something like this should do:

 

      ELSIF sym = ORS.if THEN ORS.Get(sym);     (* optimize: 0 = don’t optimize / 1 = all FALSE / 2 = first TRUE / 3 = subsequent TRUE *)

        expression(x); CheckBool(x);

        IF x.mode # ORB.Const THEN optimize :=0; ORG.CFJump(x);

        ELSIF x.a = 0 THEN optimize := 1; ORG.DisableCode ELSE optimize := 2 END;

        Check(ORS.then, "no THEN"); StatSequence;

        IF optimize = 1 THEN ORG.EnableCode ELSIF optimize = 2 THEN ORG.DisableCode END;

        L0 := 0;

        WHILE sym = ORS.elsif DO ORS.Get(sym);

           IF optimize = 0 THEN ORG.FJump(L0); ORG.Fixup(x) END;

           expression(x); CheckBool(x);

           IF optimize = 1 THEN

              IF x.mode # ORB.Const THEN optimize := 0 ELSIF x.a = 0 THEN ORG.DisableCode ELSE optimize := 2 END

           ELSIF (optimize = 2) & (x.mode = ORB.Const) & (x.a = 1) THEN optimize := 3

           END;

           IF optimize = 0 THEN ORG.CFJump(x) END;

           Check(ORS.then, "no THEN"); StatSequence

           IF optimize = 1 THEN ORG.EnableCode ELSIF optimize = 2 THEN ORG.DisableCode END;

        END;

        IF sym = ORS.else THEN ORS.Get(sym);

           IF optimize = 0 THEN ORG.FJump(L0); ORG.Fixup(x) END;

           StatSequence;

        ELSIF optimize = 0 THEN ORG.Fixup(x)

        END ;

        IF optimize = 0 THEN  ORG.FixLink(L0) 

        ELSIF optimize >=  2 DO ORG.EnableCode

        END;

        Check(ORS.end, "no END")

 

In ORG Enable and Disable have to decrement/increment a code generation status, and all Put / Fix procedures only generate code if status = 0.

 

br

Jörg

 

Am 11.08.18, 09:37 schrieb "Oberon im Auftrag von Andreas Pirklbauer" <oberon-bounces at lists.inf.ethz.ch im Auftrag von andreas_pirklbauer at yahoo.com>:

 

       > I have tried to work out how the authors of ETH-M2 and GPCP

       > achieved this but have been unsuccessful so far.

    

    First, note that the ETH Modula-2 compilers has seen multiple

    re-implementations over the years. As hardware with more and

    more RAM became available, the number of passes was reduced.

    That’s a topic in and by itself, but only of historic interest.

    

    

    A. Here is an excerpt of Pass3 of the ETH Modula-2 Multi-Pass

    Compiler in the Lilith implementation Version C18 of 10.02.82:

    

        PROCEDURE IfStatement;

           ...

        BEGIN (*IfStatement*)

          jumpList := NIL;

          LOOP Expression(lat);

            IF lat.mode=constantMod THEN

              IF BOOLEAN(lat.value) THEN           (*<-------*)

                StatSeq3(endsy, elsifsy, elsesy);

                IF sy<>endsy THEN Skip(endsy, endsy) END;

                EXIT

              ELSE Skip(elsesy, elsifsy);

                IF sy <> elsifsy THEN EXIT END;

                GetSymbol

              END

    

    I have no way to check this today (no access to Lilith ;-),

    but I “believe* this is what is happening.

    

    To replicate that on Project Oberon on RISC you’d need

    to adjust ORP.StatSequence accordingly and check the

    x after Expression(x) whether it is a boolean constant.

    

    a) BOOLEAN converts lat.value

    

       (in M2 on Lilith the field ‘lat’ is an attribute and a

       descriptor of the operand in an expression,

       in Project Oberon it would correspond to x.a)

    

    b) The IF BOOLEAN(lat.value) THEN expression

       then becomes either IF TRUE or IF FALSE

    

    c) If it is FALSE, then Skip(elsesy, elsifsy) is

       executed (see above code), i.e. NO code is generated.

    

    Again, I have no way to check, but I believe that this

    *may* be the way it was done.

    

    

    

    B. And here is an excerpt of MacMETH compiler in MC68000

    which I was most familiar with at the time (and which was based

    on one of the Lilith implementations if I remember correctly):

    

       PROCEDURE StatSe;

    

         ELSIF sym = if THEN

            GetSym; RefPoint; Expression(x); GenCFJ(x, L0);

            CheckSym(then, 27); StatSeq; L1 := 0;

            WHILE (sym = elsif) DO

              GetSym; GenFJ(L1); FixLink(L0); RefPoint; Expression(x);

              GenCFJ(x, L0); CheckSym(then, 27); StatSeq

            END;

            IF sym = else THEN

              GetSym; GenFJ(L1); FixLink(L0); StatSeq

            ELSE FixLink(L0)

            END;

            FixLink(L1); CheckSym(end, 20)

    

    

    So there it is not done. It already looks at lot like Oberon on RISC.

    

    HTH,

    -ap

    

    

    --

    Oberon at lists.inf.ethz.ch mailing list for ETH Oberon and related systems

    https://lists.inf.ethz.ch/mailman/listinfo/oberon

    

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.inf.ethz.ch/pipermail/oberon/attachments/20180812/4172b0aa/attachment.html>


More information about the Oberon mailing list