Previous: OprdbDepend, Up: RootType
The computation provided for the TypedDefId context sets the
TypeOf property of that identifier's key to the value of
TypedDefId.Type.
TypedDefId.TypeIsSet is the post-condition for that computation.
By default, RootType.TypeIsSet is the conjunction of all of
the TypedDefId.TypeIsSet post-conditions.
If other property values of the identifier's key are set by
user computations in the lower context of TypedDefId
that establish the postcondition SYNT.GotProp,
then the setting of these properties is also guaranteed by the
post-condition TypedDefId.TypeIsSet.
(SYNT.GotProp defaults to the empty postcondition.)
Note that if any of these user computations depend on any results from type
analysis, a cycle will be created.
A computation supplied by the module sets the TypedUseId.Type
attribute to the value of the TypeOf property of that identifier's
definition table key.
TypedUseId.TypeIsSet is a precondition for that computation.
It must guarantee that the TypeOf property of the identifier
has actually been set.
The module provides a default computation for TypedUseId.TypeIsSet
in the lower context of the TypedUseId node, requiring the
pre-condition RootType.TypeIsSet.
Some languages provide initialized variable declarations, and allow the user to omit either the type specification or the initializing expression but not both. If the type specification is omitted, the variable's type is the type returned by the initializing expression. Here are some examples of such declarations in a Mystery-like form:
VAR Both: INTEGER := 3;
VAR NoType := Both + 7;
VAR NoInit: INTEGER;
The default computations for the TypeIsSet attributes in this
example lead to a cycle:
TypedDefId.Type attribute of NoType
depends on TypedUseId.Type for Both.
TypedUseId.Type for Both
has the pre-condition TypedUseId.TypeIsSet.
TypedUseId.TypeIsSet depends on RootType.TypeIsSet in the
default computation.
RootType.TypeIsSet is the conjunction of all
TypedDefId.TypeIsSet attributes.
TypedDefId.TypeIsSet for NoType is the post-condition
for a computation involving the TypedDefId.Type attribute
of NoType.
If the language requires that the initialized declaration of a variable precede any uses of that variable, then we can override the default dependence as follows:
CHAIN TypeDepend: VOID;
CLASS SYMBOL ROOTCLASS COMPUTE
CHAINSTART HEAD.TypeDepend=THIS.GotType;
END;
RULE: VrblDecl ::= 'VAR' VarIdDef ':' Type ':=' Expr
COMPUTE
VrblDecl.Type=Type.Type;
VrblDecl.TypeDepend=VarIdDef.TypeIsSet <- Expr.TypeDepend;
END;
RULE: VrblDecl ::= 'VAR' VarIdDef ':' Type
COMPUTE
VrblDecl.Type=Type.Type;
VrblDecl.TypeDepend=VarIdDef.TypeIsSet <- Expr.TypeDepend;
END;
RULE: VrblDecl ::= 'VAR' VarIdDef ':=' Expr
COMPUTE
VrblDecl.Type=Expr.Type;
VrblDecl.TypeDepend=VarIdDef.TypeIsSet <- Expr.TypeDepend;
END;
SYMBOL VarIdUse COMPUTE
SYNT.TypeIsSet=THIS.TypeDepend;
THIS.TypeDepend=SYNT.TypeIsSet;
END;
If there is no ordering requirement, then a fixed-point computation is required to determine the variable types. In addition, code generated from the initializing expressions must be arranged to ensure that a variable's value is computed before it is used. Finally, such out-of-order dependence makes the program hard to understand. We strongly recommend that declaration before use be required if variables are allowed to obtain their type from their initializers.