[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