(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* File: Exceptionz.m3 *) (* Last Modified On Mon Oct 12 09:31:23 PDT 1992 by kalsow *) (* Modified On Thu Dec 5 17:20:35 PST 1991 by muller *) MODULE Exceptionz; IMPORT Value, ValueRep, String, Type, Scope, Frame; IMPORT Error, Expr, Emit, Temp, MBuf, Token, Decl; IMPORT Target, ArrayType, SetType, RefType, RecordType; FROM Scanner IMPORT GetToken, Match, Match1, MatchID, cur; TYPE T = Value.T BRANDED "Exceptionz.T" OBJECT tipe : Type.T; refTipe : Type.T; OVERRIDES typeCheck := Check; class := MyClass; fingerprint := FPrinter; load := Load; write := Write; declare0 := Declarer; declare1 := Compile; toExpr := ValueRep.NoExpr; toType := ValueRep.NoType; typeOf := ValueRep.TypeVoid; END; PROCEDURE ParseDecl (READONLY fail: Token.Set; att: Decl.Attributes) = TYPE TK = Token.T; VAR t: T; id: String.T; BEGIN IF att.isInline THEN Error.Msg ("a variable cannot be inline"); END; IF att.isExternal THEN Error.Msg ("a variable cannot be external"); END; Match (TK.tEXCEPTION, fail, Token.Set {TK.tIDENT, TK.tSEMI}); WHILE (cur.token = TK.tIDENT) DO id := MatchID (fail, Token.Set {TK.tLPAREN, TK.tSEMI}); t := NEW (T); ValueRep.Init (t, id); t.readonly := TRUE; t.unused := att.isUnused; t.obsolete := att.isObsolete; t.tipe := NIL; t.refTipe := NIL; IF (cur.token = TK.tLPAREN) THEN GetToken (); (* ( *) t.tipe := Type.Parse (fail + Token.Set {TK.tRPAREN, TK.tSEMI}); Match (TK.tRPAREN, fail, Token.Set {TK.tSEMI}); END; Scope.Insert (t); Match1 (TK.tSEMI, fail); END; END ParseDecl; PROCEDURE EmitRaise (v: Value.T; arg: Expr.T) = VAR t: T := Value.Base (v); tmp: Temp.T; BEGIN IF (arg = NIL) THEN Emit.OpN ("_RAISE (& @, _NIL);\n", t); ELSIF NOT ArgByReference (t.tipe) THEN tmp := Expr.Compile (arg); Emit.OpN ("_RAISE (& @, ", t); Emit.OpT ("(_ADDRESS)@);\n", tmp); Temp.Free (tmp); ELSE (* large argument => call the raise procedure *) tmp := Expr.Compile (arg); Emit.OpN ("_RAISE_@ ", t); Emit.OpT (" (& @);\n", tmp); Temp.Free (tmp); END; END EmitRaise; PROCEDURE ArgByReference (type: Type.T): BOOLEAN = VAR fields: Scope.T; index, elem: Type.T; BEGIN RETURN (Type.Size (type) > Target.ADDRSIZE) OR RecordType.Split (type, fields) OR ArrayType.Split (type, index, elem) OR SetType.Split (type, elem); END ArgByReference; PROCEDURE Check (t: T; <*UNUSED*> VAR cs: Value.CheckState) = BEGIN IF (t.tipe # NIL) THEN Type.Check (t.tipe); IF (Type.Size (t.tipe) < 0) THEN Error.Str (t.name, "argument type must have fixed length"); END; IF ArgByReference (t.tipe) THEN t.refTipe := RefType.New (t.tipe, TRUE, NIL); Type.Check (t.refTipe); END; END; END Check; PROCEDURE ArgType (v: Value.T): Type.T = BEGIN TYPECASE Value.Base (v) OF | NULL => RETURN NIL; | T(t) => RETURN t.tipe; ELSE RETURN NIL; END; END ArgType; PROCEDURE Load (t: T): Temp.T = BEGIN RETURN Temp.FromValue (t); END Load; PROCEDURE Write (t: T) = BEGIN Emit.OpN ("@", t); END Write; PROCEDURE Compile (<*UNUSED*> t: T) = BEGIN END Compile; PROCEDURE MyClass (<*UNUSED*> t: T): Value.Class = BEGIN RETURN Value.Class.Exception; END MyClass; PROCEDURE Declarer (t: T): BOOLEAN = VAR save: Emit.Stream; sz: INTEGER; frame: Frame.T; BEGIN Type.Compile (t.tipe); Type.Compile (t.refTipe); save := Emit.Switch (Emit.Stream.ProcHeads); Value.GenStorageClass (t, isVolatile := TRUE); IF t.external OR t.imported THEN Emit.OpN ("_EXCEPTION_NAME @;\n", t); IF (t.refTipe # NIL) THEN Emit.OpN ("_IMPORT _VOID _RAISE_@ ();\n", t); END; ELSE Emit.OpN ("_EXCEPTION_NAME @ = \"", t); Scope.GenName (t, dots := TRUE); Emit.Op ("\";\n"); IF (t.refTipe # NIL) THEN sz := (Type.Size (t.tipe) + Target.CHARSIZE - 1) DIV Target.CHARSIZE; Frame.Push (frame, 2); Emit.OpN ("_EXPORT _VOID _RAISE_@ (arg)\n", t); Emit.Op ("_ADDRESS arg;\n"); Emit.Op ("{\001\n"); Emit.OpF ("_ADDRESS ptr = (_ADDRESS) _TNEW (@_TC);\n", t.refTipe); EVAL Emit.SwitchToBody (); Emit.Op ("\001"); Emit.OpI ("_COPY (arg, ptr, @);\n", sz); Emit.OpN ("_RAISE (& @, ptr);\n", t); Frame.Pop (frame); END; END; EVAL Emit.Switch (save); RETURN TRUE; END Declarer; PROCEDURE FPrinter (t: T; map: Type.FPMap; wr: MBuf.T) = VAR s: String.Stack; BEGIN MBuf.PutText (wr, "EXCEPT "); s.top := 0; Scope.NameToPrefix (t, s); String.PutStack (wr, s); MBuf.PutText (wr, " "); Type.Fingerprint (t.tipe, map, wr); END FPrinter; BEGIN END Exceptionz.