[Oberon] Intermediate scopes in Oberon-07
Andreas Pirklbauer
andreas_pirklbauer at yahoo.com
Sat Feb 10 13:01:42 CET 2018
Just for the record: Below is a possible implementation of the Oberon-07
compiler that disallows access to ALL intermediate objects, i.e. not just
intermediate variables, but also intermediate types and constants. Five
lines needed to be changed in the Oberon-07 compiler.
This will now catch the type T in the following test program provided earlier:
MODULE Test;
PROCEDURE P;
TYPE T = INTEGER;
PROCEDURE Q(x: T): T; (* this is now caught -> “pos 78 must be strictly local or global" *)
RETURN 0
END Q;
END P;
END Test.
ORP.Compile Test.Mod ~
Everything else stays the same, e.g. local procedures continue to be
allowed, all types of intermediate objects continue to be allowed (i.e.
constants, types, variables can all be declared as local objects inside
any procedure, whether global or local and at any nesting level). It’s
just that the *access* for ALL intermediate objects is now restricted
to either the strictly local level or the strictly global (module) level.
Andreas
IMPLEMENTATION: (see the output of the Unix diff command further down)
---------------
1. ORP.Declarations:
PROCEDURE Declarations(VAR varsize: LONGINT);
VAR obj, first: ORB.Object;
x: ORG.Item; tp: ORB.Type; ptbase: PtrBase;
expo: BOOLEAN; id: ORS.Ident;
BEGIN (*sync*) pbsList := NIL;
IF (sym < ORS.const) & (sym # ORS.end) & (sym # ORS.return) THEN ORS.Mark("declaration?");
REPEAT ORS.Get(sym) UNTIL (sym >= ORS.const) OR (sym = ORS.end) OR (sym = ORS.return)
END ;
IF sym = ORS.const THEN
ORS.Get(sym);
WHILE sym = ORS.ident DO
ORS.CopyId(id); ORS.Get(sym); CheckExport(expo);
IF sym = ORS.eql THEN ORS.Get(sym) ELSE ORS.Mark("= ?") END;
expression(x);
IF (x.type.form = ORB.String) & (x.b = 2) THEN ORG.StrToChar(x) END ;
ORB.NewObj(obj, id, ORB.Const); obj.expo := expo; obj.lev := level;
IF x.mode = ORB.Const THEN obj.type := x.type;
IF x.type.form = ORB.String THEN obj.val := x.a + x.b*10000H ELSE obj.val := x.a END
ELSE ORS.Mark("expression not constant"); obj.type := ORB.intType
END;
Check(ORS.semicolon, "; missing")
END
END ;
...
END Declarations;
2. ORP.CheckLevel (new procedure inserted e.g. after ORP.Check)
PROCEDURE CheckLevel(lev: INTEGER);
BEGIN
IF (lev > 0) & (lev # level) THEN ORS.Mark("must be strictly local or global") END
END CheckLevel;
3. ORG.MakeItem:
PROCEDURE MakeItem*(VAR x: Item; y: ORB.Object; curlev: LONGINT);
BEGIN x.mode := y.class; x.type := y.type; x.a := y.val; x.rdo := y.rdo;
IF y.class = ORB.Par THEN x.b := 0
ELSIF y.class = ORB.Typ THEN x.a := y.type.len; x.r := -y.lev
ELSIF (y.class = ORB.Const) & (y.type.form = ORB.String) THEN
x.a := y.val MOD 10000H; (*strx*) x.b := y.val DIV 10000H (*len*)
ELSE x.r := y.lev
END ;
IF (y.lev > 0) & (y.lev # curlev) THEN ORS.Mark("level error, not accessible") END
END MakeItem;
COMMENTS:
---------
1. ORP.Declarations: In essence one now sets obj.lev := level also for constants
(previously this was done only for types and variables, but not for constants)
I.e. the variable obj.lev is no longer “abused” to hold the length of a (string)
constant, but to hold the scope level (this makes it possible to check for it in
ORP.CheckLevel). Instead both the address and the length of a string constant are
now “encoded” (16 bits each) into a single field (obj.val). This in turn frees up
the obj.lev field (which can now used to hold the actual scope level of the
constant). Note that x.a and x.b are themselves set by ORG.MakeStringItem
(see there; but it does not need to be changed)
2. ORG. MakeItem: It simply performs the inverse operation as in ORP.Declarations.
It also removes the guard (y.class # ORB.Const) in the last line of MakeItem that
used to be there for handle the special case of constants (..was kind of shady anyway).
3. This implementation makes local procedures “self-contained”, i.e.
one can move them around freely, make them global etc.
DIFFERENCES:
-------------
Differences to the Original Oberon 2013 version (as of Feb 10, 2018)
at https://www.inf.ethz.ch/personal/wirth are as follows:
$ diff ORP.Mod OriginalOberon2013/Sources/ORP.Mod
31,35d30
< PROCEDURE CheckLevel(lev: INTEGER);
< BEGIN
< IF (lev > 0) & (lev # level) THEN ORS.Mark("must be strictly local or global") END
< END CheckLevel;
<
45d39
< ELSE CheckLevel(obj.lev)
803,805c797,798
< ORB.NewObj(obj, id, ORB.Const); obj.expo := expo; obj.lev := level;
< IF x.mode = ORB.Const THEN obj.type := x.type;
< IF x.type.form = ORB.String THEN obj.val := x.a + x.b*10000H ELSE obj.val := x.a END
---
> ORB.NewObj(obj, id, ORB.Const); obj.expo := expo;
> IF x.mode = ORB.Const THEN obj.val := x.a; obj.lev := x.b; obj.type := x.type
$ diff ORG.Mod OriginalOberon2013/Sources/ORG.Mod
253c253
< ELSIF (y.class = ORB.Const) & (y.type.form = ORB.String) THEN x.a := y.val MOD 10000H; (*strx*) x.b := y.val DIV 10000H (*len*)
---
> ELSIF (y.class = ORB.Const) & (y.type.form = ORB.String) THEN x.b := y.lev (*len*)
256c256
< IF (y.lev > 0) & (y.lev # curlev) THEN ORS.Mark("level error, not accessible") END
---
> IF (y.lev > 0) & (y.lev # curlev) & (y.class # ORB.Const) THEN ORS.Mark("level error, not accessible") END
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.inf.ethz.ch/pipermail/oberon/attachments/20180210/23a3341a/attachment.html>
More information about the Oberon
mailing list