MODULE; IMPORT Fmt, M3ID, M3AST, M3Scope, M3Type, Target, TInt, TFloat, TWord, Text; IMPORT M3SetVal, M3RecVal, M3ArrVal, M3Builtin; FROM M3AST IMPORT NodeIndex; M3Const
*** IMPORT Stdio, Wr, Thread; ***
TYPE State = RECORD env : ImportOracle; ast : M3AST.T; max_loc : CARDINAL; loc : NodeIndex; op : M3AST.OP; info : INTEGER; n_ch : CARDINAL; ch : ARRAY [0..9] OF NodeIndex; END; TYPE EvalProc = PROCEDURE (VAR s: State; VAR(*OUT*) val: T) RAISES {Error}; VAR init_done := FALSE; eval_procs: ARRAY M3AST.OP OF EvalProc; PROCEDUREEval (ast : M3AST.T; loc : NodeIndex; env : ImportOracle; VAR(*OUT*) val : T) RAISES {Error} = VAR s: State; BEGIN IF (NOT init_done) THEN Init(); END; IF (ast.nodes = NIL) THEN BadAST(); END; s.env := env; s.ast := ast; s.max_loc := NUMBER (ast.nodes^); EvalX (s, loc, val); END Eval; PROCEDUREEvalX (VAR s: State; loc: NodeIndex; VAR val: T) RAISES {Error} = BEGIN IF (loc > s.max_loc) THEN BadAST (); END; WITH z = s.ast.nodes [loc] DO WITH desc = M3AST.OpMap [z.op] DO s.loc := loc; s.op := z.op; s.info := z.info; s.n_ch := M3AST.GetChildren (s.ast, loc, s.ch);
*** Out (eval
, Fmt.Int (loc),=>
, Fmt.Int (z.op) &n_ch =
& Fmt.Int (s.n_ch)); ***
IF (s.n_ch < desc.min_ch) THEN BadAST (); END; IF (s.n_ch > desc.max_ch) AND (desc.max_ch # 255) THEN BadAST (); END; eval_procs [s.op] (s, val); END; END; END EvalX;******** PROCEDURE Out (a, b, c, d: TEXT := NIL) = <*FATAL Wr.Failure, Thread.Alerted*> VAR wr := Stdio.stdout; BEGIN IF (a # NIL) THEN Wr.PutText (wr, a); END; IF (b # NIL) THEN Wr.PutText (wr, b); END; IF (c # NIL) THEN Wr.PutText (wr, c); END; IF (d # NIL) THEN Wr.PutText (wr, d); END; Wr.PutText (wr, Wr.EOL); Wr.Flush (wr); END Out; ********
------------------------------------------------------------------ types ---
PROCEDURE---------------------------------------------------- expression operators ---EvalArray (VAR s: State; VAR val: T) RAISES {Error} = VAR index := s.ch[0]; elt := s.ch[1]; arr := NEW (M3Type.Array); BEGIN val.class := Class.Type; val.type := arr; arr.index := EvalType (s, index); arr.element := EvalType (s, elt); END EvalArray; PROCEDUREEvalOpenArray (VAR s: State; VAR val: T) RAISES {Error} = VAR elt := s.ch[0]; arr := NEW (M3Type.OpenArray); BEGIN val.class := Class.Type; val.type := arr; arr.element := EvalType (s, elt); END EvalOpenArray; PROCEDUREEvalEnum (VAR s: State; VAR val: T) RAISES {Error} = VAR base := s.loc + 1; elts := NEW (REF ARRAY OF M3ID.T, s.n_ch); enum := NEW (M3Type.Enum); BEGIN val.class := Class.Type; val.type := enum; enum.elements := elts; FOR i := 0 TO s.n_ch - 1 DO WITH z = s.ast.nodes [base + i] DO IF z.op # M3AST.OP_EnumDefn THEN Err ("bad enumerated type"); END; elts[i] := z.info; END; END; END EvalEnum; PROCEDUREEvalNamedType (VAR s: State; VAR val: T) RAISES {Error} = VAR xx: T; BEGIN val.class := Class.Type; val.type := M3Type.Integer; (* to prevent disasterous cycles *) EvalX (s, s.ch[0], xx); IF (xx.class # Class.Type) THEN Err ("bad type (class = " & Fmt.Int (ORD (val.class)) & ")" ); END; val.type := xx.type; END EvalNamedType; PROCEDUREEvalPacked (VAR s: State; VAR val: T) RAISES {Error} = VAR bits := s.ch[0]; tipe := s.ch[1]; pack := NEW (M3Type.Packed); n_bits : T; BEGIN val.class := Class.Type; val.type := pack; EvalX (s, bits, n_bits); IF (n_bits.class # Class.Integer) OR NOT TInt.ToInt (n_bits.int, pack.bits) THEN Err ("bad size specified in BITS FOR"); END; pack.element := EvalType (s, tipe); END EvalPacked; PROCEDUREEvalProcType (VAR s: State; VAR val: T) RAISES {Error} = VAR ast := s.ast; self := s.loc; info := s.info; n_ch := s.n_ch; n_formals : CARDINAL := 0; n_raises : CARDINAL := 0; loc, ch : NodeIndex; cnt : CARDINAL; proc := NEW (M3Type.Procedure); BEGIN val.class := Class.Type; val.type := proc; (* get the calling convention *) IF (info = M3ID.NoID) THEN proc.callingConv := Target.DefaultCall; ELSE proc.callingConv := Target.FindConvention (M3ID.ToText (info)); IF (proc.callingConv = NIL) THEN Err ("unrecognized calling convention: " & M3ID.ToText (info)); END; END; (* count the formals *) FOR i := 0 TO n_ch - 3 DO loc := M3AST.NthChild (ast, self, i); cnt := M3AST.NumChildren (ast, loc); IF (cnt <= 2) THEN BadAST (); END; INC (n_formals, cnt - 2); END; proc.formals := NEW (REF ARRAY OF M3Type.FormalDesc, n_formals); (* accumulate the formals *) n_formals := 0; FOR i := 0 TO n_ch - 3 DO loc := M3AST.NthChild (ast, self, i); AddFormals (s, loc, n_formals, proc.formals); END; (* grab the return type *) proc.return := EvalTypeOrEmpty (s, M3AST.NthChild (ast, self, n_ch - 2)); (* grab the exceptions *) loc := M3AST.NthChild (ast, self, n_ch - 1); WITH z = ast.nodes [loc] DO IF (z.op = M3AST.OP_RaisesAny) THEN n_raises := 1; proc.raises := NEW (REF ARRAY OF M3Type.ExceptDesc, 1); proc.raises[0].ast := NIL; proc.raises[0].decl := 0; ELSIF (z.op = M3AST.OP_Raises) THEN n_raises := M3AST.NumChildren (ast, loc); proc.raises := NEW (REF ARRAY OF M3Type.ExceptDesc, n_raises); n_raises := 0; FOR i := 0 TO n_raises - 1 DO ch := M3AST.NthChild (ast, loc, i); AddException (s, ch, n_raises, proc.raises); END; ELSE Err ("bad procedure type"); END; END; END EvalProcType; PROCEDUREAddFormals (VAR s: State; loc: NodeIndex; VAR n_formals: CARDINAL; formals: REF ARRAY OF M3Type.FormalDesc) RAISES {Error} = VAR ast := s.ast; n_ids := M3AST.NumChildren (ast, loc) - 2; ftype : M3Type.T; default : T; ch : NodeIndex; mode : M3Type.Mode; BEGIN (* get the formal's mode *) WITH z = ast.nodes [loc] DO CASE z.info OF | 0 => mode := M3Type.Mode.Value; | 1 => mode := M3Type.Mode.Var; | 2 => mode := M3Type.Mode.Readonly; ELSE Err ("bad formal parameter mode"); END; END; (* get the formal type *) ch := M3AST.NthChild (ast, loc, n_ids); ftype := EvalTypeOrEmpty (s, ch); (* get the default value *) ch := M3AST.NthChild (ast, loc, n_ids + 1); WITH z = ast.nodes [ch] DO IF (z.op = M3AST.OP_Empty) THEN default.type := M3Type.Integer; ELSE EvalX (s, ch, default); END; END; (* fix the missing type if possible *) IF (ftype = NIL) THEN ftype := default.type; END; FOR i := 0 TO n_ids - 1 DO ch := M3AST.NthChild (ast, loc, i); WITH z = ast.nodes [ch] DO IF (z.op # M3AST.OP_FormalDefn) THEN Err ("bad formal parameter"); END; WITH f = formals [n_formals] DO f.name := z.info; f.type := ftype; f.mode := mode; (* f.default := ?? *) END; INC (n_formals); END; END; END AddFormals; PROCEDUREAddException (VAR s: State; loc: NodeIndex; VAR n_raises: CARDINAL; raises: REF ARRAY OF M3Type.ExceptDesc) RAISES {Error} = VAR val: T; BEGIN EvalX (s, loc, val); IF (val.class # Class.Exception) THEN Err ("bad exception in RAISES clause"); END; WITH z = raises [n_raises] DO z.ast := val.ref; z.decl := val.info; END; INC (n_raises); END AddException; PROCEDUREEvalObject (<*UNUSED*> VAR s: State; VAR val: T) RAISES {Error} = BEGIN val.class := Class.Type; val.type := NEW (M3Type.Object); Err ("object types not implemented yet"); END EvalObject; PROCEDUREEvalRecord (VAR s: State; VAR val: T) RAISES {Error} = VAR ast := s.ast; self := s.loc; n_ch := s.n_ch; n_fields : CARDINAL := 0; loc : NodeIndex; rec := NEW (M3Type.Record); BEGIN val.class := Class.Type; val.type := rec; (* count the fields *) FOR i := 0 TO n_ch - 1 DO loc := M3AST.NthChild (ast, self, i); INC (n_fields, M3AST.NumChildren (ast, loc) - 2); END; rec.fields := NEW (REF ARRAY OF M3Type.FieldDesc, n_fields); (* accumulate the fields *) n_fields := 0; FOR i := 0 TO n_ch - 1 DO loc := M3AST.NthChild (ast, self, i); AddFields (s, loc, n_fields, rec.fields); END; END EvalRecord; PROCEDUREAddFields (VAR s: State; loc: NodeIndex; VAR n_fields: CARDINAL; fields: REF ARRAY OF M3Type.FieldDesc) RAISES {Error} = VAR ast := s.ast; n_ch := M3AST.NumChildren (ast, loc); ftype : M3Type.T; default : T; ch : NodeIndex; BEGIN (* get the field type *) ch := M3AST.NthChild (ast, loc, n_ch - 2); ftype := EvalTypeOrEmpty (s, ch); (* get the default value *) ch := M3AST.NthChild (ast, loc, n_ch - 1); WITH z = ast.nodes [ch] DO IF (z.op = M3AST.OP_Empty) THEN default.type := M3Type.Integer; ELSE EvalX (s, ch, default); END; END; (* fix the missing type if possible *) IF (ftype = NIL) THEN ftype := default.type; END; FOR i := 0 TO n_ch - 3 DO ch := M3AST.NthChild (ast, loc, i); WITH z = ast.nodes [ch] DO IF (z.op # M3AST.OP_FieldDefn) THEN Err ("bad field name"); END; WITH f = fields [n_fields] DO f.name := z.info; f.type := ftype; (* f.default := ?? *) END; INC (n_fields); END; END; END AddFields; PROCEDUREEvalRef (VAR s: State; VAR val: T) RAISES {Error} = VAR brand := s.ch[0]; target := s.ch[1]; ref := NEW (M3Type.Ref, traced := TRUE); BEGIN val.class := Class.Type; val.type := ref; ref.brand := GetBrand (s, brand); ref.target := EvalType (s, target); END EvalRef; PROCEDUREEvalRoot (<*UNUSED*> VAR s: State; VAR val: T) = BEGIN val.class := Class.Type; val.type := M3Type.Root; END EvalRoot; PROCEDUREEvalSet (VAR s: State; VAR val: T) RAISES {Error} = VAR dom := s.ch[0]; set := NEW (M3Type.Set); BEGIN val.class := Class.Type; val.type := set; set.domain := EvalType (s, dom); END EvalSet; PROCEDUREEvalSubrange (VAR s: State; VAR val: T) RAISES {Error} = VAR min, max : T; subrange := NEW (M3Type.Subrange); BEGIN val.class := Class.Type; val.type := subrange; EvalPair (s, min, max); subrange.min := min.int; subrange.max := max.int; subrange.super := min.type; END EvalSubrange; PROCEDUREEvalUntracedRef (VAR s: State; VAR val: T) RAISES {Error} = VAR brand := s.ch[0]; target := s.ch[1]; ref := NEW (M3Type.Ref, traced := FALSE); BEGIN val.class := Class.Type; val.type := ref; ref.brand := GetBrand (s, brand); ref.target := EvalType (s, target); END EvalUntracedRef; PROCEDUREEvalUntracedRoot (<*UNUSED*> VAR s: State; VAR val: T) = BEGIN val.class := Class.Type; val.type := M3Type.UntracedRoot; END EvalUntracedRoot; PROCEDUREGetBrand (VAR s: State; loc: NodeIndex): TEXT RAISES {Error} = VAR op := s.ast.nodes[loc].op; val: T; BEGIN IF (op = M3AST.OP_NoBrand) THEN RETURN NIL; ELSIF (op = M3AST.OP_DefaultBrand) THEN RETURN NewBrand (); ELSE EvalX (s, loc, val); IF (val.class # Class.Text) THEN Err ("brand is not a TEXT constant"); END; RETURN NARROW (val.ref, TEXT); END; END GetBrand; PROCEDURENewBrand (): TEXT = BEGIN RETURN "oops"; END NewBrand; PROCEDUREEvalTypeOrEmpty (VAR s: State; loc: NodeIndex): M3Type.T RAISES {Error} = BEGIN WITH z = s.ast.nodes [loc] DO IF (z.op = M3AST.OP_Empty) THEN RETURN NIL; ELSE RETURN EvalType (s, loc); END; END; END EvalTypeOrEmpty; PROCEDUREEvalType (VAR s: State; loc: NodeIndex): M3Type.T RAISES {Error} = VAR val: T; BEGIN EvalX (s, loc, val); IF (val.class # Class.Type) THEN Err ("not a type"); END; RETURN val.type; END EvalType;
PROCEDURE----------------------------------------------------------- literals ---EvalOr (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (a.class # Class.Enum) OR (b.class # Class.Enum) OR (M3Type.Base (a.type) # M3Type.Boolean) OR (M3Type.Base (b.type) # M3Type.Boolean) THEN Err ("bad operand for OR"); END; val.class := Class.Enum; val.type := M3Type.Boolean; val.info := MAX (a.info, b.info); END EvalOr; PROCEDUREEvalAnd (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (a.class # Class.Enum) OR (b.class # Class.Enum) OR (M3Type.Base (a.type) # M3Type.Boolean) OR (M3Type.Base (b.type) # M3Type.Boolean) THEN Err ("bad operand for AND"); END; val.class := Class.Enum; val.type := M3Type.Boolean; val.info := MIN (a.info, b.info); END EvalAnd; PROCEDUREEvalNot (VAR s: State; VAR val: T) RAISES {Error} = BEGIN EvalX (s, s.ch[0], val); IF (val.class # Class.Enum) OR (M3Type.Base (val.type) # M3Type.Boolean) THEN Err ("bad operand for NOT"); END; val.class := Class.Enum; val.type := M3Type.Boolean; val.info := 1 - val.info; END EvalNot; PROCEDUREEvalEQ (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); val.class := Class.Enum; val.type := M3Type.Boolean; val.info := ORD (IsEQ (a, b)); END EvalEQ; PROCEDUREEvalNE (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); val.class := Class.Enum; val.type := M3Type.Boolean; val.info := ORD (NOT IsEQ (a, b)); END EvalNE; PROCEDUREIsEQ (READONLY a, b: T): BOOLEAN = VAR eq: BOOLEAN; BEGIN IF (a.class # b.class) THEN RETURN FALSE; END; CASE a.class OF | Class.Integer => eq := TInt.EQ (a.int, b.int); | Class.Float => eq := TFloat.EQ (a.float, b.float); | Class.Enum => eq := (a.info = b.info) AND M3Type.IsEqual (a.type, b.type); | Class.Text => eq := (a.ref # NIL) AND (b.ref # NIL) AND Text.Equal (a.ref, b.ref); | Class.Type => eq := M3Type.IsEqual (a.type, b.type); | Class.Addr => eq := (a.info = b.info); | Class.Set => eq := M3SetVal.Compare (a.ref, b.ref) = 0; | Class.Record => eq := M3RecVal.Compare (a.ref, b.ref) = 0; | Class.Array => eq := M3ArrVal.Compare (a.ref, b.ref) = 0; | Class.Exception => eq := (a.ref = b.ref) AND (a.info = b.info); | Class.Proc => eq := (a.ref = b.ref) AND (a.info = b.info); | Class.Var => eq := (a.ref = b.ref) AND (a.info = b.info); | Class.GenericArg => eq := (a.ref = b.ref) AND (a.info = b.info); | Class.Formal => eq := (a.ref = b.ref) AND (a.info = b.info); | Class.Module => eq := (a.ref = b.ref) AND (a.info = b.info); | Class.Builtin => eq := (a.info = b.info); END; RETURN eq; END IsEQ; PROCEDUREEvalLT (VAR s: State; VAR val: T) RAISES {Error} = BEGIN EvalCompare (s, val, -1, -1); END EvalLT; PROCEDUREEvalLE (VAR s: State; VAR val: T) RAISES {Error} = BEGIN EvalCompare (s, val, -1, 0); END EvalLE; PROCEDUREEvalGT (VAR s: State; VAR val: T) RAISES {Error} = BEGIN EvalCompare (s, val, +1, +1); END EvalGT; PROCEDUREEvalGE (VAR s: State; VAR val: T) RAISES {Error} = BEGIN EvalCompare (s, val, +1, 0); END EvalGE; PROCEDUREEvalCompare (VAR s: State; VAR val: T; s1, s2: INTEGER) RAISES {Error} = VAR a, b: T; sign: INTEGER; BEGIN EvalPair (s, a, b); IF (a.class = Class.Integer) AND (b.class = Class.Integer) THEN IF TInt.LT (a.int, b.int) THEN sign := -1; ELSIF TInt.LT (b.int, a.int) THEN sign := +1; ELSE sign := 0; END; ELSIF (a.class = Class.Enum) AND (b.class = Class.Enum) THEN IF a.info < b.info THEN sign := -1; ELSIF b.info < a.info THEN sign := +1; ELSE sign := 0; END; ELSIF (a.class = Class.Float) AND (b.class = Class.Float) AND (a.float.pre = b.float.pre) THEN IF TFloat.LT (a.float, b.float) THEN sign := -1; ELSIF TFloat.LT (b.float, a.float) THEN sign := +1; ELSE sign := 0; END; ELSIF (a.class = Class.Addr) AND (b.class = Class.Addr) THEN IF a.info < b.info THEN sign := -1; ELSIF b.info < a.info THEN sign := +1; ELSE sign := 0; END; ELSIF (a.class = Class.Set) AND (b.class = Class.Set) THEN sign := M3SetVal.Compare (a.ref, b.ref); ELSE Err ("bad operand for comparison"); END; val.class := Class.Enum; val.type := M3Type.Boolean; val.info := ORD ((sign = s1) OR (sign = s2)); END EvalCompare; PROCEDUREEvalMember (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (b.class # Class.Set) THEN Err ("bad operand for IN"); ELSIF (a.class = Class.Integer) AND TInt.ToInt (a.int, a.info) THEN (* ok *) ELSIF (a.class = Class.Enum) THEN (* ok *) ELSE Err ("bad operand for IN"); END; val.class := Class.Enum; val.type := M3Type.Boolean; val.info := ORD (M3SetVal.IsMember (b.ref, a.info)); END EvalMember; PROCEDUREEvalAdd (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (a.class = Class.Integer) AND (b.class = Class.Integer) AND (a.type = b.type) AND TInt.Add (a.int, b.int, val.int) THEN val.class := Class.Integer; val.type := a.type; ELSIF (a.class = Class.Float) AND (b.class = Class.Float) AND (a.float.pre = b.float.pre) AND TFloat.Add (a.float, b.float, val.float) THEN val.class := Class.Float; val.type := a.type; ELSIF (a.class = Class.Addr) AND (b.class = Class.Integer) THEN TWord.Add (a.int, b.int, val.int); val.class := Class.Addr; val.type := M3Type.Address; ELSIF (a.class = Class.Set) AND (b.class = Class.Set) THEN val.class := Class.Set; val.ref := M3SetVal.Union (a.ref, b.ref); val.type := a.type; ELSE Err ("bad operand for '+'"); END; END EvalAdd; PROCEDUREEvalSubtract (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (a.class = Class.Integer) AND (b.class = Class.Integer) AND (a.type = b.type) AND TInt.Subtract (a.int, b.int, val.int) THEN val.class := Class.Integer; val.type := a.type; ELSIF (a.class = Class.Float) AND (b.class = Class.Float) AND (a.float.pre = b.float.pre) AND TFloat.Subtract (a.float, b.float, val.float) THEN val.class := Class.Float; val.type := a.type; ELSIF (a.class = Class.Addr) AND (b.class = Class.Integer) THEN TWord.Subtract (a.int, b.int, val.int); val.class := Class.Addr; val.type := M3Type.Address; ELSIF (a.class = Class.Set) AND (b.class = Class.Set) THEN val.class := Class.Set; val.ref := M3SetVal.Difference (a.ref, b.ref); val.type := a.type; ELSE Err ("bad operand for '-'"); END; END EvalSubtract; PROCEDUREEvalConcat (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (a.class = Class.Text) AND (b.class = Class.Text) THEN val.class := Class.Text; val.type := M3Type.Txt; val.ref := NARROW (a.ref, TEXT) & NARROW (b.ref, TEXT); ELSE Err ("bad operand for '&'"); END; END EvalConcat; PROCEDUREEvalMultiply (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (a.class = Class.Integer) AND (b.class = Class.Integer) AND (a.type = b.type) AND TInt.Multiply (a.int, b.int, val.int) THEN val.class := Class.Integer; val.type := a.type; ELSIF (a.class = Class.Float) AND (b.class = Class.Float) AND (a.float.pre = b.float.pre) AND TFloat.Multiply (a.float, b.float, val.float) THEN val.class := Class.Float; val.type := a.type; ELSIF (a.class = Class.Set) AND (b.class = Class.Set) THEN val.class := Class.Set; val.ref := M3SetVal.Intersection (a.ref, b.ref); val.type := a.type; ELSE Err ("bad operand for '*'"); END; END EvalMultiply; PROCEDUREEvalDivide (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (a.class = Class.Float) AND (b.class = Class.Float) AND (a.float.pre = b.float.pre) AND TFloat.Divide (a.float, b.float, val.float) THEN val.class := Class.Float; val.type := a.type; ELSIF (a.class = Class.Set) AND (b.class = Class.Set) THEN val.class := Class.Set; val.ref := M3SetVal.SymDifference (a.ref, b.ref); val.type := a.type; ELSE Err ("bad operand for '/'"); END; END EvalDivide; PROCEDUREEvalDiv (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (a.class = Class.Integer) AND (b.class = Class.Integer) AND (a.type = b.type) AND TInt.Div (a.int, b.int, val.int) THEN val.class := Class.Integer; val.type := a.type; ELSE Err ("bad operand for 'DIV'"); END; END EvalDiv; PROCEDUREEvalMod (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; BEGIN EvalPair (s, a, b); IF (a.class = Class.Integer) AND (b.class = Class.Integer) AND (a.type = b.type) AND TInt.Mod (a.int, b.int, val.int) THEN val.class := Class.Integer; val.type := a.type; ELSIF (a.class = Class.Float) AND (b.class = Class.Float) AND (a.float.pre = b.float.pre) AND TFloat.Mod (a.float, b.float, val.float) THEN val.class := Class.Float; val.type := a.type; ELSE Err ("bad operand for 'MOD'"); END; END EvalMod; PROCEDUREEvalUnaryPlus (VAR s: State; VAR val: T) RAISES {Error} = BEGIN EvalX (s, s.ch[0], val); END EvalUnaryPlus; PROCEDUREEvalUnaryMinus (VAR s: State; VAR val: T) RAISES {Error} = VAR a: T; zero: Target.Float; BEGIN EvalX (s, s.ch[0], a); IF (a.class = Class.Integer) AND TInt.Subtract (TInt.Zero, a.int, val.int) THEN val.class := Class.Integer; val.type := a.type; ELSIF (a.class = Class.Float) THEN IF (a.float.pre = Target.Precision.Short) THEN zero := TFloat.ZeroR; ELSIF (a.float.pre = Target.Precision.Long) THEN zero := TFloat.ZeroL; ELSE zero := TFloat.ZeroX; END; IF NOT TFloat.Subtract (zero, a.float, val.float) THEN Err ("bad operand for unary '-'"); END; val.class := Class.Float; val.type := a.type; ELSE Err ("bad operand for unary '-'"); END; END EvalUnaryMinus; PROCEDUREEvalSubscript (VAR s: State; VAR val: T) RAISES {Error} = VAR a, b: T; min_index, max_index, offs: Target.Int; index: INTEGER; BEGIN EvalPair (s, a, b); IF (a.class # Class.Array) THEN Err ("bad operand for subscript operation"); ELSIF (b.class = Class.Integer) THEN (* ok *) ELSIF (b.class = Class.Enum) AND TInt.FromInt (b.info, Target.Integer.bytes, b.int) THEN (* ok *) ELSE Err ("bad operand for subscript operation"); END; TYPECASE a.type OF | M3Type.Array (x) => IF NOT M3Type.GetBounds (x.index, min_index, max_index) THEN Err ("bad operand for subscript operation"); END; | M3Type.OpenArray => min_index := TInt.Zero; ELSE Err ("bad operand for subscript operation"); END; IF NOT TInt.Subtract (b.int, min_index, offs) OR NOT TInt.ToInt (offs, index) OR (index < 0) OR NOT M3ArrVal.Index (a.ref, index, val) THEN Err ("bad operand for subscript operation"); END; END EvalSubscript; PROCEDUREEvalCallExpr (VAR s: State; VAR val: T) RAISES {Error} = VAR ast := s.ast; loc := s.loc; n_ch := s.n_ch; ch0 := s.ch[0]; ch : NodeIndex; proc : T; args : ARRAY [0..4] OF T; BEGIN EvalX (s, ch0, proc); IF (proc.class # Class.Builtin) THEN Err ("not a constant") END; FOR i := 1 TO n_ch-1 DO ch := M3AST.NthChild (ast, loc, i); EvalX (s, ch, args[i-1]); END; M3Builtin.Eval (VAL (proc.info, M3Builtin.Proc), SUBARRAY (args, 0, n_ch-1), val); END EvalCallExpr; PROCEDUREEvalConsExpr (VAR s: State; VAR val: T) RAISES {Error} = VAR self := s.loc; tipe := EvalType (s, s.ch[0]); BEGIN IF (tipe = NIL) THEN Err ("bad type on constructor"); END; TYPECASE M3Type.Base (tipe) OF | NULL => Err ("bad type on constructor"); | M3Type.Array(array_type) => EvalArrayCons (s, array_type, self, val); | M3Type.OpenArray => EvalOpenArrayCons (s, self, val); | M3Type.Set(set_type) => EvalSetCons (s, set_type, self, val); | M3Type.Record(record_type) => EvalRecordCons (s, record_type, self, val); ELSE Err ("bad type on constructor"); END; val.type := tipe; END EvalConsExpr; PROCEDUREEvalArrayCons (VAR s: State; tipe: M3Type.Array; loc: NodeIndex; VAR val: T) RAISES {Error} = VAR ast := s.ast; n_ch := M3AST.NumChildren (ast, loc); arr : M3ArrVal.T; ch : NodeIndex; elt : T; n_elts : INTEGER; dots : BOOLEAN; BEGIN IF NOT TInt.ToInt (M3Type.Number (tipe.index), n_elts) OR (n_elts < 0) THEN Err ("bad array constructor"); END; arr := M3ArrVal.NewEmpty (n_elts); (* check for a trailing ".." element *) ch := M3AST.NthChild (ast, loc, n_ch-1); IF (ast.nodes[ch].op = M3AST.OP_Etc) THEN dots := TRUE; DEC (n_ch); IF (n_ch < 2) THEN Err ("bad array constructor"); END; IF (n_ch > n_elts+1) THEN Err ("bad array constructor"); END; ELSE IF (n_ch # n_elts+1) THEN Err ("bad array constructor"); END; dots := FALSE; END; (* get the explicit elements *) FOR i := 1 TO n_ch-1 DO ch := M3AST.NthChild (ast, loc, i); EvalX (s, ch, elt); IF NOT M3ArrVal.Set (arr, i-1, elt) THEN Err ("illegal array constructor"); END; END; (* fill in the ones implied by ".." *) FOR i := n_ch TO n_elts-1 DO IF NOT M3ArrVal.Set (arr, i-1, elt) THEN Err ("illegal array constructor"); END; END; val.class := Class.Array; val.ref := arr; END EvalArrayCons; PROCEDUREEvalOpenArrayCons (VAR s: State; loc: NodeIndex; VAR val: T) RAISES {Error} = VAR ast := s.ast; n_ch := M3AST.NumChildren (ast, loc); arr : M3ArrVal.T; ch : NodeIndex; elt : T; BEGIN (* check for a trailing ".." element *) ch := M3AST.NthChild (ast, loc, n_ch-1); IF (ast.nodes[ch].op = M3AST.OP_Etc) THEN DEC (n_ch); IF (n_ch < 2) THEN Err ("bad open array constructor"); END; END; arr := M3ArrVal.NewEmpty (n_ch-1); (* get the explicit elements *) FOR i := 1 TO n_ch-1 DO ch := M3AST.NthChild (ast, loc, i); EvalX (s, ch, elt); IF NOT M3ArrVal.Set (arr, i-1, elt) THEN Err ("illegal array constructor"); END; END; val.class := Class.Array; val.ref := arr; END EvalOpenArrayCons; PROCEDUREEvalSetCons (VAR s: State; tipe: M3Type.Set; loc: NodeIndex; VAR val: T) RAISES {Error} = VAR ast := s.ast; n_ch := M3AST.NumChildren (ast, loc); min, max, t0, t1: Target.Int; n_elts : INTEGER; set : M3SetVal.T; ch : NodeIndex; v1, v2 : T; x1, x2 : INTEGER; BEGIN IF NOT M3Type.GetBounds (tipe.domain, min, max) OR NOT TInt.Subtract (max, min, t0) OR NOT TInt.Add (t0, TInt.One, t1) OR NOT TInt.ToInt (t1, n_elts) THEN Err ("illegal set constructor"); END; set := M3SetVal.NewEmpty (n_elts); FOR i := 2 TO n_ch - 1 DO ch := M3AST.NthChild (ast, loc, i); IF (ast.nodes[ch].op = M3AST.OP_RangeExpr) THEN s.n_ch := M3AST.GetChildren (s.ast, ch, s.ch); EvalPair (s, v1, v2); ELSE EvalX (s, ch, v1); v2 := v1; END; IF v1.class = Class.Integer AND TInt.ToInt (v1.int, x1) THEN (* ok *) ELSIF v1.class = Class.Enum THEN x1 := v1.info; ELSE Err ("illegal set constructor element"); END; IF v2.class = Class.Integer AND TInt.ToInt (v2.int, x2) THEN (* ok *) ELSIF v2.class = Class.Enum THEN x2 := v2.info; ELSE Err ("illegal set constructor element"); END; FOR z := x1 TO x2 DO set := M3SetVal.Include (set, z); END; END; val.class := Class.Set; val.ref := set; END EvalSetCons; PROCEDUREEvalRecordCons (VAR s: State; tipe: M3Type.Record; loc: NodeIndex; VAR val: T) RAISES {Error} = VAR ast := s.ast; n_ch := M3AST.NumChildren (ast, loc); rec := M3RecVal.NewEmpty (); next_field := 0; by_name := FALSE; field_name : M3ID.T; v1 : T; ch : NodeIndex; BEGIN FOR i := 1 TO n_ch-1 DO ch := M3AST.NthChild (ast, loc, i); IF (ast.nodes[ch].op = M3AST.OP_NameBind) THEN s.n_ch := M3AST.GetChildren (ast, ch, s.ch); WITH z = ast.nodes[s.ch[0]] DO IF z.op # M3AST.OP_Id THEN Err ("illegal record constructor"); END; field_name := z.info; END; EvalX (s, s.ch[1], v1); by_name := TRUE; ELSIF (by_name) OR (next_field >= NUMBER (tipe.fields^)) THEN Err ("illegal record constructor"); ELSE field_name := tipe.fields [next_field].name; EvalX (s, ch, v1); END; rec := M3RecVal.SetField (rec, field_name, v1); END; val.class := Class.Record; val.ref := rec; END EvalRecordCons; PROCEDUREEvalQualify (VAR s: State; VAR val: T) RAISES {Error} = VAR id := s.info; ast := s.ast; BEGIN EvalX (s, s.ch[0], val); CASE val.class OF | Class.Module => IF ResolveID (val.ref, 0, id, s.env, val) THEN s.ast := ast; RETURN; ELSE s.ast := ast; END; | Class.Record => IF M3RecVal.Qualify (val.ref, id, val) THEN RETURN; END; | Class.Type, Class.Var, Class.GenericArg, Class.Formal => (* nope, not handled yet... *) | Class.Integer, Class.Float, Class.Enum, Class.Text, Class.Addr, Class.Set, Class.Array, Class.Exception, Class.Proc, Class.Builtin => (* nope, illegal *) END; Err ("unknown qualification: " & M3ID.ToText (id)); END EvalQualify; PROCEDUREEvalPair (VAR s: State; VAR v1, v2: T) RAISES {Error} = VAR ch0 := s.ch[0]; ch1 := s.ch[1]; BEGIN EvalX (s, ch0, v1); EvalX (s, ch1, v2); END EvalPair;
PROCEDUREEvalId (VAR s: State; VAR val: T) RAISES {Error} = VAR id := s.info; BEGIN IF FindBuiltin (id, val) THEN
*** IF (val.class = Class.Builtin) THEN Out (, M3ID.ToText (id),
=> builtin #
, Fmt.Int (val.info)); ELSIF (val.class = Class.Type) THEN Out (, M3ID.ToText (id),
=> builtin type
); ELSE Out (, M3ID.ToText (id),
=> builtin ??? ****
); END; ***
(* ok, we got it... *) ELSIF ResolveID (s.ast, s.loc, id, s.env, val) THEN (* ok, we got it *) ELSE Err ("undefined symbol: " & M3ID.ToText (id)); END; END EvalId; PROCEDURE------------------------------------------------- user defined identifiers ---EvalInt (VAR s: State; VAR val: T) RAISES {Error} = BEGIN val.class := Class.Integer; val.type := M3Type.Integer; IF NOT TInt.FromInt (s.info, Target.Integer.bytes, val.int) THEN Err ("illegal integer value"); END; END EvalInt; PROCEDUREEvalLInt (VAR s: State; VAR val: T) RAISES {Error} = BEGIN val.class := Class.Integer; val.type := M3Type.Longint; IF NOT TInt.FromInt (s.info, Target.Longint.bytes, val.int) THEN Err ("illegal integer value"); END; END EvalLInt; PROCEDUREEvalBigInt (VAR s: State; VAR val: T) = BEGIN val.class := Class.Integer; val.type := M3Type.Integer; val.int := s.ast.ints [s.info]; END EvalBigInt; PROCEDUREEvalBigLInt (VAR s: State; VAR val: T) = BEGIN val.class := Class.Integer; val.type := M3Type.Longint; val.int := s.ast.ints [s.info]; END EvalBigLInt; PROCEDUREEvalReal (VAR s: State; VAR val: T) = BEGIN val.class := Class.Float; val.type := M3Type.Real; val.float := s.ast.floats [s.info]; END EvalReal; PROCEDUREEvalLReal (VAR s: State; VAR val: T) = BEGIN val.class := Class.Float; val.type := M3Type.LongReal; val.float := s.ast.floats [s.info]; END EvalLReal; PROCEDUREEvalEReal (VAR s: State; VAR val: T) = BEGIN val.class := Class.Float; val.type := M3Type.Extended; val.float := s.ast.floats [s.info]; END EvalEReal; PROCEDUREEvalChar (VAR s: State; VAR val: T) = BEGIN val.class := Class.Enum; val.type := M3Type.Char; val.info := s.info; END EvalChar; PROCEDUREEvalText (VAR s: State; VAR val: T) = BEGIN val.class := Class.Text; val.type := M3Type.Txt; val.ref := s.ast.texts [s.info]; END EvalText;
TYPE RefConst = REF T; PROCEDUREResolveID (ast: M3AST.T; loc: NodeIndex; id: M3ID.T; env: ImportOracle; VAR(*OUT*) val: T): BOOLEAN RAISES {Error} = VAR sym : M3Scope.Defn; n_ch : CARDINAL; ch : ARRAY [0..1] OF NodeIndex; defn : RefConst; BEGIN IF FindWordBuiltin (ast, id, val) THEN
*** Out (, M3ID.ToText (id),
=> builtin #
, Fmt.Int (val.info)); ***
RETURN TRUE; END; IF NOT M3Scope.LookUp (ast, loc, id, sym) THEN
*** Out (*** M3Scope.LookUp failed:
, M3ID.ToText (id),@
, Fmt.Int (loc)); ***
RETURN FALSE; END;
*** Out (, M3ID.ToText (id),
=> defn @
, Fmt.Int (sym.loc)); ***
(* check for a cached evaluation... *) TYPECASE sym.info OF | NULL => (* nothing defined yet. *) defn := NEW (RefConst); M3Scope.Define (sym, defn); | RefConst (r) => val := r^; RETURN TRUE; ELSE (* ouch, somebody else is using this slot! *) defn := NEW (RefConst); END; CASE sym.class OF | M3Scope.Class.Import => WITH z = sym.ast.nodes [sym.loc] DO IF (z.op = M3AST.OP_Import) THEN defn.class := Class.Module; defn.info := 0; defn.ref := env.find (z.info); IF (defn.ref = NIL) THEN RETURN FALSE; END; ELSIF (z.op = M3AST.OP_ImportAs) THEN defn.class := Class.Module; defn.info := 0; defn.ref := env.find (sym.ast.nodes[sym.loc+1].info); IF (defn.ref = NIL) THEN RETURN FALSE; END; ELSIF (z.op = M3AST.OP_FromImport) THEN ast := env.find (sym.ast.nodes[sym.loc+1].info); IF (ast = NIL) THEN RETURN FALSE; END; IF NOT ResolveID (ast, 0, z.info, env, defn^) THEN RETURN FALSE; END; ELSE RETURN FALSE; END; END; | M3Scope.Class.Const => WITH z = sym.ast.nodes [sym.loc] DO IF (z.op # M3AST.OP_ConstDecl) THEN RETURN FALSE; END; n_ch := M3AST.GetChildren (sym.ast, sym.loc, ch); Eval (sym.ast, ch[1], env, defn^); END; | M3Scope.Class.Type => n_ch := M3AST.GetChildren (sym.ast, sym.loc, ch); WITH z = sym.ast.nodes [sym.loc] DO IF (z.op = M3AST.OP_TypeDecl) THEN Eval (sym.ast, ch[0], env, defn^); ELSIF (z.op = M3AST.OP_OpaqueDecl) THEN Eval (sym.ast, ch[0], env, defn^); IF (defn.class = Class.Type) THEN defn.type := NEW (M3Type.Opaque, super := defn.type); END; ELSE RETURN FALSE; END; END; IF (defn.class # Class.Type) THEN
*** Out (***??? Didn't find a type for
, M3ID.ToText (id),=> class
, Fmt.Int(ORD(defn.class))); ***
RETURN FALSE; END; | M3Scope.Class.Var => defn.class := Class.Var; defn.info := sym.loc; defn.ref := sym.ast; | M3Scope.Class.GenericArg => defn.class := Class.GenericArg; defn.info := sym.loc; defn.ref := sym.ast; | M3Scope.Class.Formal => defn.class := Class.Var; defn.info := sym.loc; defn.ref := sym.ast; | M3Scope.Class.Exception => defn.class := Class.Exception; defn.info := sym.loc; defn.ref := sym.ast; | M3Scope.Class.Procedure => defn.class := Class.Proc; defn.info := sym.loc; defn.ref := sym.ast; | M3Scope.Class.Module => defn.class := Class.Module; defn.info := sym.loc; defn.ref := sym.ast; END; val := defn^; RETURN TRUE; END ResolveID;------------------------------------------- built-in types and procedures ---
CONST BuiltinNames = ARRAY [0..42] OF TEXT { "ABS", "ADDRESS", "ADR", "ADRSIZE", "BITSIZE", "BOOLEAN", "BYTESIZE", "CARDINAL", "CEILING", "CHAR", "DEC", "DISPOSE", "EXTENDED", "FALSE", "FIRST", "FLOAT", "FLOOR", "INC", "INTEGER", "ISTYPE", "LAST", "LONGCARD", "LONGINT", "LONGREAL", "LOOPHOLE", "MAX", "MIN", "MUTEX", "NARROW", "NEW", "NIL", "NULL", "NUMBER", "ORD", "REAL", "REFANY", "ROUND", "SUBARRAY", "TEXT", "TRUE", "TRUNC", "TYPECODE", "VAL" }; VAR init_builtins := FALSE; BuiltinIDs : ARRAY [0..41] OF M3ID.T; PROCEDURE-------------------------------------------------------------- errors ---InitBuiltins () = BEGIN FOR i := FIRST (BuiltinNames) TO LAST (BuiltinNames) DO BuiltinIDs[i] := M3ID.Add (BuiltinNames [i]); END; init_builtins := TRUE; END InitBuiltins; PROCEDUREFindBuiltin (id: M3ID.T; VAR(*OUT*) val: T): BOOLEAN = BEGIN IF (NOT init_builtins) THEN InitBuiltins () END; FOR i := FIRST (BuiltinIDs) TO LAST (BuiltinIDs) DO IF BuiltinIDs[i] = id THEN CASE i OF | 00 => (* ABS *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Abs); RETURN TRUE; | 01 => (* ADDRESS *) val.class := Class.Type; val.type := M3Type.Address; RETURN TRUE; | 02 => (* ADR *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Adr); RETURN TRUE; | 03 => (* ADRSIZE *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.AdrSize); RETURN TRUE; | 04 => (* BITSIZE *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.BitSize); RETURN TRUE; | 05 => (* BOOLEAN *) val.class := Class.Type; val.type := M3Type.Boolean; RETURN TRUE; | 06 => (* BYTESIZE *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.ByteSize); RETURN TRUE; | 07 => (* CARDINAL *) val.class := Class.Type; val.type := M3Type.Cardinal; RETURN TRUE; | 08 => (* CEILING *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Ceiling); RETURN TRUE; | 09 => (* CHAR *) val.class := Class.Type; val.type := M3Type.Char; RETURN TRUE; | 10 => (* DEC *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Dec); RETURN TRUE; | 11 => (* DISPOSE *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Dispose); RETURN TRUE; | 12 => (* EXTENDED *) val.class := Class.Type; val.type := M3Type.Extended; RETURN TRUE; | 13 => (* FALSE *) val.class := Class.Enum; val.info := ORD (FALSE); val.type := M3Type.Boolean; RETURN TRUE; | 14 => (* FIRST *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.First); RETURN TRUE; | 15 => (* FLOAT *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Float); RETURN TRUE; | 16 => (* FLOOR *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Floor); RETURN TRUE; | 17 => (* INC *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Inc); RETURN TRUE; | 18 => (* INTEGER *) val.class := Class.Type; val.type := M3Type.Integer; RETURN TRUE; | 19 => (* ISTYPE *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.IsType); RETURN TRUE; | 20 => (* LAST *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Last); RETURN TRUE; | 21 => (* LONGCARD *) val.class := Class.Type; val.type := M3Type.Longcard; | 22 => (* LONGINT *) val.class := Class.Type; val.type := M3Type.Longint; | 23 => (* LONGREAL *) val.class := Class.Type; val.type := M3Type.LongReal; RETURN TRUE; | 24 => (* LOOPHOLE *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Loophole); RETURN TRUE; | 25 => (* MAX *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Max); RETURN TRUE; | 26 => (* MIN *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Min); RETURN TRUE; | 27 => (* MUTEX *) val.class := Class.Type; val.type := M3Type.Mutex; RETURN TRUE; | 28 => (* NARROW *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Narrow); RETURN TRUE; | 29 => (* NEW *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.New); RETURN TRUE; | 30 => (* NIL *) val.class := Class.Addr; val.info := 0; val.type := M3Type.Null; RETURN TRUE; | 31 => (* NULL *) val.class := Class.Type; val.type := M3Type.Null; RETURN TRUE; | 32 => (* NUMBER *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Number); RETURN TRUE; | 33 => (* ORD *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Ord); RETURN TRUE; | 34 => (* REAL *) val.class := Class.Type; val.type := M3Type.Real; RETURN TRUE; | 35 => (* REFANY *) val.class := Class.Type; val.type := M3Type.Refany; RETURN TRUE; | 36 => (* ROUND *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Round); RETURN TRUE; | 37 => (* SUBARRAY *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Subarray); RETURN TRUE; | 38 => (* TEXT *) val.class := Class.Type; val.type := M3Type.Txt; RETURN TRUE; | 39 => (* TRUE *) val.class := Class.Enum; val.info := ORD (TRUE); val.type := M3Type.Boolean; RETURN TRUE; | 40 => (* TRUNC *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Trunc); RETURN TRUE; | 41 => (* TYPECODE *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Typecode); RETURN TRUE; | 42 => (* VAL *) val.class := Class.Builtin; val.info := ORD (M3Builtin.Proc.Val); RETURN TRUE; END; (*CASE*) END; END; RETURN FALSE; END FindBuiltin; CONST BuiltinWordNames = ARRAY [0..20] OF TEXT { "Plus", "Times", "Minus", "Divide", "Mod", "LT", "LE", "GT", "GE", "And", "Or", "Xor", "Not", "Shift", "LeftShift", "RightShift", "Rotate", "LeftRotate", "RightRotate", "Extract", "Insert" }; BuiltinWordProc = ARRAY [0..20] OF M3Builtin.Proc { M3Builtin.Proc.WordPlus, M3Builtin.Proc.WordTimes, M3Builtin.Proc.WordMinus, M3Builtin.Proc.WordDivide, M3Builtin.Proc.WordMod, M3Builtin.Proc.WordLT, M3Builtin.Proc.WordLE, M3Builtin.Proc.WordGT, M3Builtin.Proc.WordGE, M3Builtin.Proc.WordAnd, M3Builtin.Proc.WordOr, M3Builtin.Proc.WordXor, M3Builtin.Proc.WordNot, M3Builtin.Proc.WordShift, M3Builtin.Proc.WordLeftShift, M3Builtin.Proc.WordRightShift, M3Builtin.Proc.WordRotate, M3Builtin.Proc.WordLeftRotate, M3Builtin.Proc.WordRightRotate, M3Builtin.Proc.WordExtract, M3Builtin.Proc.WordInsert }; VAR init_word := FALSE; WordID : M3ID.T; BuiltinWordIDs : ARRAY [0..20] OF M3ID.T; PROCEDUREInitWordIDs () = BEGIN WordID := M3ID.Add ("Word"); FOR i := FIRST (BuiltinWordIDs) TO LAST (BuiltinWordIDs) DO BuiltinWordIDs[i] := M3ID.Add (BuiltinWordNames [i]); END; init_word := TRUE; END InitWordIDs; PROCEDUREFindWordBuiltin (ast: M3AST.T; id: M3ID.T; VAR(*OUT*) val: T): BOOLEAN = BEGIN IF (NOT init_word) THEN InitWordIDs (); END; IF (ast = NIL) OR (NOT ast.interface) THEN RETURN FALSE; END; IF (ast.nodes = NIL) THEN RETURN FALSE; END; IF (ast.nodes[0].op # M3AST.OP_Unit) THEN RETURN FALSE END; IF (ast.nodes[0].info # WordID) THEN RETURN FALSE; END; FOR i := FIRST (BuiltinWordIDs) TO LAST (BuiltinWordIDs) DO IF BuiltinWordIDs[i] = id THEN val.class := Class.Builtin; val.info := ORD (BuiltinWordProc[i]); RETURN TRUE; END; END; RETURN FALSE; END FindWordBuiltin;
PROCEDURE------------------------------------------------------- initialization ---NotConst (<*UNUSED*> VAR s: State; <*UNUSED*> VAR val: T) RAISES {Error} = BEGIN Err ("not a constant"); END NotConst; PROCEDUREBadAST () RAISES {Error} = BEGIN Err ("malformed AST"); END BadAST; PROCEDUREErr (msg: TEXT) RAISES {Error} = BEGIN RAISE Error (msg); END Err;
PROCEDUREInit () = BEGIN init_done := TRUE; FOR op := FIRST (eval_procs) TO LAST (eval_procs) DO eval_procs [op] := NotConst; END; eval_procs [M3AST.OP_Array] := EvalArray; eval_procs [M3AST.OP_OpenArray] := EvalOpenArray; eval_procs [M3AST.OP_Enum] := EvalEnum; eval_procs [M3AST.OP_NamedType] := EvalNamedType; eval_procs [M3AST.OP_Packed] := EvalPacked; eval_procs [M3AST.OP_ProcType] := EvalProcType; eval_procs [M3AST.OP_Object] := EvalObject; eval_procs [M3AST.OP_Record] := EvalRecord; eval_procs [M3AST.OP_Ref] := EvalRef; eval_procs [M3AST.OP_Root] := EvalRoot; eval_procs [M3AST.OP_Set] := EvalSet; eval_procs [M3AST.OP_Subrange] := EvalSubrange; eval_procs [M3AST.OP_UntracedRef] := EvalUntracedRef; eval_procs [M3AST.OP_UntracedRoot] := EvalUntracedRoot; eval_procs [M3AST.OP_Or] := EvalOr; eval_procs [M3AST.OP_And] := EvalAnd; eval_procs [M3AST.OP_Not] := EvalNot; eval_procs [M3AST.OP_EQ] := EvalEQ; eval_procs [M3AST.OP_NE] := EvalNE; eval_procs [M3AST.OP_LT] := EvalLT; eval_procs [M3AST.OP_LE] := EvalLE; eval_procs [M3AST.OP_GT] := EvalGT; eval_procs [M3AST.OP_GE] := EvalGE; eval_procs [M3AST.OP_Member] := EvalMember; eval_procs [M3AST.OP_Add] := EvalAdd; eval_procs [M3AST.OP_Subtract] := EvalSubtract; eval_procs [M3AST.OP_Concat] := EvalConcat; eval_procs [M3AST.OP_Multiply] := EvalMultiply; eval_procs [M3AST.OP_Divide] := EvalDivide; eval_procs [M3AST.OP_Div] := EvalDiv; eval_procs [M3AST.OP_Mod] := EvalMod; eval_procs [M3AST.OP_UnaryPlus] := EvalUnaryPlus; eval_procs [M3AST.OP_UnaryMinus] := EvalUnaryMinus; eval_procs [M3AST.OP_Subscript] := EvalSubscript; eval_procs [M3AST.OP_CallExpr] := EvalCallExpr; eval_procs [M3AST.OP_ConsExpr] := EvalConsExpr; eval_procs [M3AST.OP_Qualify] := EvalQualify; eval_procs [M3AST.OP_Id] := EvalId; eval_procs [M3AST.OP_Int] := EvalInt; eval_procs [M3AST.OP_LInt] := EvalLInt; eval_procs [M3AST.OP_BigInt] := EvalBigInt; eval_procs [M3AST.OP_BigLInt] := EvalBigLInt; eval_procs [M3AST.OP_Real] := EvalReal; eval_procs [M3AST.OP_LReal] := EvalLReal; eval_procs [M3AST.OP_EReal] := EvalEReal; eval_procs [M3AST.OP_Char] := EvalChar; eval_procs [M3AST.OP_Text] := EvalText; END Init; BEGIN END M3Const.