m3tk/src/sem/M3CBackEnd.i3


INTERFACE M3CBackEnd;
************************************************************************* Copyright (C) Olivetti 1989 All Rights reserved Use and copy of this software and preparation of derivative works based upon this software are permitted to any person, provided this same copyright notice and the following Olivetti warranty disclaimer are included in any copy of the software or any modification thereof or derivative work therefrom made by any person. This software is made available AS IS and Olivetti disclaims all warranties with respect to this software, whether expressed or implied under any law, including all implied warranties of merchantibility and fitness for any purpose. In no event shall Olivetti be liable for any damages whatsoever resulting from loss of use, data or profits or otherwise arising out of or in connection with the use or performance of this software. *************************************************************************

IMPORT Text;

IMPORT M3AST_AS, M3AST_SM;

IMPORT M3CStdProcs, M3CWordProcs;
This module defines the interface for the information required by the compiler front-end from a back-end . In order to support multiple back-ends simultaneously, the interface is in terms of procedure variables, which must be assigned by an appropriate implementation.

TYPE
  NumStatus = {Valid,         (* computed an ok value *)
               Unknown,       (* input error, no computation possible *)
               Overflow};     (* overflow on computation *)
The implementor of these procedures can usually assume that appropriate error checks/computations have already been performed before a procedure is called. The big exception to this rule is that type checking has not usually been done; type checking can require constants to be evaluated so the back end is called to evaluate them before type checking is done. Any other checks or computations which are left to these back end procedures are given in the comments describing the procedure.

TYPE
  LiteralValueProc =
    PROCEDURE (lit: M3AST_AS.EXP;
        VAR (*out*) er: M3AST_SM.Exp_value): NumStatus RAISES {};
  (* Compute the value of the given literal. *)

  ConstructorValueProc =
    PROCEDURE (cons: M3AST_AS.Constructor;
        VAR (*out*) er: M3AST_SM.Exp_value): NumStatus RAISES {};
  (* Ditto for constructors.  The value of 'sm_actual_s' can be relied upon, as
  can the fact that all values of the components have been computed (which
  implies that no types are unset).
    The back end is expected to do all the work for set constructors and
  operations - i.e. it must provide a 'ConstructorValueProc' which will build
  something representing the set and must be prepared to do set operations e.g.
  '+' and 'IN' on such values. The set type is guaranteed to have valid bounds
  and all elements on the 'sm_actual_s' list are guaranteed to be ordinal and
  in range.
    Array and record constructors are easier; most of the work can be done in
  a portable way by the front-end. The only operation the front end will ever
  require on an array or record constructor value is the one specified by the
  'ConstructorOriginalProc' given below. *)

  ConstructorOriginalProc =
      PROCEDURE(e: M3AST_SM.Exp_value): M3AST_AS.Constructor RAISES {};
  (* 'e' is guaranteed to be an array or record constructor value; returns the
  original constructor from which the value was derived.
    The front end uses this constructor and its 'sm_actuals_s' list to do
  selection, indexing and testing for (in)equality which are the only
  operations allowed on constructors in constant expressions. *)

  IsOrdinalProc = PROCEDURE(e: M3AST_SM.Exp_value): BOOLEAN RAISES {};
  (* Returns TRUE if 'e' represents an ordinal value, FALSE otherwise. 'e' may
  be NIL in which case FALSE should be returned. An 'IsOrdinalProc' is
  permitted to be lax and classify 'e' as ordinal even if it is not; a result
  of TRUE indicates that 'e' looks ordinal to the back end and that the back
  end will be happy to do ordinal style operations upon it *)

  ValProc =
    PROCEDURE (n: INTEGER; ts: M3AST_AS.TYPE_SPEC;
        VAR (*out*) er: M3AST_SM.Exp_value): NumStatus RAISES {};
  (* Return an 'Exp_value' representing the member of an ordinal type
  corresponding to the integer 'n'.
    This is not always the 'n'th member of the ordinal type; for example if
  'ts' represented the subrange [2..3] and 'n' was 2 the 'Exp_value' returned
  would represent the first member of the subrange; 'n' is absolute, not
  relative to the first value of the given type.
    Enumerations are considered to be numbered from 0 upward e.g. if 'ts'
  represented the enumeration Animal = {Pig,Cow,Sheep} and 'n' was 1 the
  'Exp_value' returned would represent the member 'Cow'. If 'n' was 1 and 'ts'
  was the subrange [Animal.Cow..Animal.Sheep] the 'Exp_value' returned would
  still represent 'Cow'.
    'ts' is guaranteed to be ordinal and 'n' is guaranteed to be in the range
  of integer values which correspond to members of 'ts'. 'er' should not be
  updated unless 'NumStatus.Valid' is returned. *)

  OrdProc =
    PROCEDURE(e: M3AST_SM.Exp_value;
        VAR (*out*) i: INTEGER): NumStatus RAISES {};
  (* Return the integer value corresponding to 'e'. Barring overflow 'OrdProc'
  is the inverse of 'ValProc' e.g. given 'Ord' of type 'OrdProc' and 'Val' of
  type 'ValProc':
    IF Val(n, someType, e) = NumStatus.Valid AND
        Ord(e, nn) = NumStatus.Valid THEN
      (* Assert: n = nn *)
    END;
  'e' is guaranteed to be an ordinal value. 'i' should be updated only if
  'NumStatus.Valid' is returned. *)

  ConvertOrdinalProc = PROCEDURE(e: M3AST_SM.Exp_value; ts: M3AST_AS.TYPE_SPEC;
      VAR (* out *) er: M3AST_SM.Exp_value): NumStatus RAISES {};
  (* Convert the given ordinal expression 'e' into an ordinal expression with
  the same value but the given type, 'ts'. 'e' is guaranteed to be ordinal and
  'ts' is guaranteed to be an ordinal type.
    This has a similar effect to using 'OrdProc' then 'ValProc' but it avoids
  the conversion to an intermediate integer *)

  BinaryOpProc =
    PROCEDURE (op: M3AST_AS.BINARY;
        el: M3AST_SM.Exp_value; e2: M3AST_SM.Exp_value;
        VAR (*out*) er: M3AST_SM.Exp_value): NumStatus RAISES {};
  (* Set 'er' to the value of 'e1' 'op' 'e2'.
   Assert: op # In (below).
   Assert: e1 is not a record or array constructor value
   WARNING: No type checking has been done at the stage (because type checking
  may depend on expression values which are not yet computed) hence there is
  no guarantee that 'e1' and 'e2' will be compatible and suitable for the
  given operation. The only guarantee is that both will be non NIL.
    Typically the start of the 'BinaryOpProc' will be a check that the values
  are at least compatible enough for the back end to work with. The check is
  free to relax the type rules (indeed it will have to as they cannot be
  enforced at this point). The only constraint is that the check must accept
  anything that is legal in the language.
     'er' should not be updated unless 'NumStatus.Valid' is returned. *)

  InOpProc =
    PROCEDURE (e1, e2: M3AST_SM.Exp_value;
        VAR (*out*) er: M3AST_SM.Exp_value): NumStatus RAISES {};
  (* 'e1' can be relied on to be ordinal and to be within the bounds of the set
   base type. 'e2' can be relied upon to be a set. 'er' should not be updated
   unless 'NumStatus.Valid' is returned. *)

  UnaryOpProc =
    PROCEDURE (op: M3AST_AS.UNARY; e: M3AST_SM.Exp_value;
        VAR (*out*) er: M3AST_SM.Exp_value): NumStatus RAISES {};
  (* As 'BinaryOpProc' but for unary ops. Assert 'op # Deref' *)

  StdUnaryOpProc =
    PROCEDURE (f: M3CStdProcs.Func;
        e: M3AST_SM.Exp_value;
        VAR (*out*) er: M3AST_SM.Exp_value;
        intType: M3AST_AS.INT_TYPE := NIL;
        floatType: M3AST_AS.FLOAT_TYPE := NIL): NumStatus  RAISES {};
  (* As UnaryOp, but standard function identified by 'f'. 'f' will be one of:
    M3CStdProcs.T.{Abs,Float,Floor,Ceiling,Round,Trunc}. Iff 'f=Float'
    then 'floatType' indicates the expected type of the result. Iff 'f=Int'
    then 'intType' indicates the expected type of the result. *)

  StdBinaryOpProc =
    PROCEDURE (f: M3CStdProcs.Func;
        el: M3AST_SM.Exp_value; e2: M3AST_SM.Exp_value;
        VAR (*out*) er: M3AST_SM.Exp_value): NumStatus RAISES {};
  (* As BinaryOp, but standard function identified by 'f'. 'f' is limited to
   be M3CStdProcs.T.{Min,Max}. The arguments may not be compatible. *)

  StdUnaryTypeOpProc =
    PROCEDURE (
        f: M3CStdProcs.Func;
        ts: M3AST_SM.TYPE_SPEC_UNSET;
        VAR (*out*) er: M3AST_SM.Exp_value): NumStatus RAISES {};
  (* M3CStdProcs.T.{BitSize,ByteSize,AdrSize,First,Last}.
  For First/Last, Assert(TypeOf(ts) = INT_TYPE). The standard function
  Number is handled elsewhere. *)

  WordOpProc = PROCEDURE(
      w: M3CWordProcs.T;
      READONLY args: ARRAY OF M3AST_SM.Exp_value;
      VAR (* out *) er: M3AST_SM.Exp_value)
      : NumStatus
      RAISES {};
  (* Set 'er' to the result of the word operation given by 'w'. 'args'
  contains the correct number of arguments, which are guaranteed to be all
  integer. They may, however, be out of range e.g. the 'i' and 'n' arguments
  to 'Insert' might be non CARDINAL or out of range (in which case
  'NumStatus.Unknown' is returned). 'er' should only be updated if the result
  is 'NumStatus.Valid'.  *)

  CompareProc =
    PROCEDURE (el: M3AST_SM.Exp_value;
               e2: M3AST_SM.Exp_value): INTEGER RAISES {};
  (* Return 0 if values are of same general type and equal; else non-zero.
  Iff they are both ordinal, then return  -1 if e1 < e2, +1 if e1 > e2; this
  behaviour must be maintained even if 'e1' and 'e2' are not compatible
  ordinals according to the M3 type rules.
    Note that no check for strict type equivalence is required; the back end
  will typically do minimal type checking. Hence to do strict equality checking
  a use of a 'CompareProc' must be guarded by a further check that the types
  of the two corresponding expressions are compatible.
    'e1' and 'e2' are guaranteed to be non NIL. 'CompareProc' does not handle
  array or record constructors (use 'M3CExpValue.Equal' to check these for
  equality. *)

  LoopholeOKProc =
    PROCEDURE (e: M3AST_AS.EXP;
        ts: M3AST_AS.TYPE_SPEC): BOOLEAN RAISES {};
  (* Returns TRUE if 'LOOPHOLE(e, ts)' is valid. *)

  BitsOKProc =
    PROCEDURE (e: M3AST_AS.EXP;
        ts: M3AST_AS.TYPE_SPEC): BOOLEAN RAISES {};
  (* Returns TRUE if 'BITS e [ALIGN a] FOR ts' is valid. 'e' is guaranteed to
  be an integer expression and 'e.sm_exp_value' is guaranteed to be non NIL. *)

  VarParamOKProc =
    PROCEDURE (ts: M3AST_AS.TYPE_SPEC): BOOLEAN RAISES {};
  (* Returns TRUE if this type is a legal VAR parameter, i.e. can be
  addressed. (packed types) *)

  BitSizeAndAlignProc =
    PROCEDURE (ts: M3AST_AS.TYPE_SPEC) RAISES {};
  (* Given that all components of 'ts' have already had their size
  and alignment computed, compute and set the sm_bitsize, sm_align
  attributes of 'ts'.
    If 'ts' is a packed type its 'as_exp' is guaranteed to be integer (or
  subrange of integer) and it will have a non NIL 'sm_exp_value'.
    If 'ts' is a subrange type its bounding expressions are both guaranteed
  to be ordinal with non NIL 'sm_exp_value' fields; the ordinals are not
  guaranteed to be related by the subtype relation *)

  ExpValueToTextProc =
    PROCEDURE(e: M3AST_SM.Exp_value): Text.T RAISES {};
  TextToExpValueProc =
    PROCEDURE(t: Text.T): M3AST_SM.Exp_value RAISES {};
  (* Because types can contain constants these procedures are needed when
  writing or reading type texts. They provide a way of encoding an exp value
  as a text and then recreating it from that text. When converting to a text
  'e' is guaranteed not to be a record or array constructor. When converting
  from a text 't' is guaranteed to have been produced by a call of an
  'ExpValueToTextProc' *)
Violation of naming conventions here - to avoid editing all the code that used to call these procs before they were made variable.
VAR
  LiteralValue: LiteralValueProc;
  ConstructorValue: ConstructorValueProc;
  ConstructorOriginal: ConstructorOriginalProc;
  IsOrdinal: IsOrdinalProc;
  Val: ValProc;
  Ord: OrdProc;
  ConvertOrdinal: ConvertOrdinalProc;
  BinaryOp: BinaryOpProc;
  InOp: InOpProc;
  UnaryOp: UnaryOpProc;
  StdUnaryOp: StdUnaryOpProc;
  StdBinaryOp: StdBinaryOpProc;
  StdUnaryTypeOp: StdUnaryTypeOpProc;
  WordOp: WordOpProc;
  Compare: CompareProc;
  LoopholeOK: LoopholeOKProc;
  BitsOK: BitsOKProc;
  VarParamOK: VarParamOKProc;
  BitSizeAndAlign: BitSizeAndAlignProc;
  ExpValueToText: ExpValueToTextProc;
  TextToExpValue: TextToExpValueProc;

END M3CBackEnd.