Most language definitions allow a user to supply operands of one type
to an operator requiring operands of another under certain circumstances.
For example, it would be reasonable for the extended version of Mystery
(see Overloaded Indications and Procedures)
to allow an addition with one integer and one real operand.
In that case, analysis computation would assume a coercion operator
to convert the value of the integer operand to a real value.
rAddOpr would then be applied to the result of the coercion and
the original real operand.
Expression module uses applicable coercions automatically,
provided that one or more coercion operators have been defined.
Like normal operators, the language-defined coercions can be specified in
the file whose name is the
referto parameter of the
(see Language-Defined Operators).
'), specifies a coercion:
(see Relating operators to indications)
invocations with the same `opr' values are not allowed.
A coercion from integer to real for the extended Mystery can be specified by:
The known key
iTor is defined by the module.
No further specification is necessary.
A coercion defines an edge of the coercion graph, a directed graph
whose nodes correspond to types used in the program.
If the coercion graph contains cycles, then it is difficult to describe the
semantics of an expression.
For example, suppose that we defined a coercion from real values to integer
values in addition to
iTor, creating a cycle in the coercion graph.
Given that cycle, what is the effect of the following expression?
1.2 + 3
The extended Mystery has only two operators for which
is the indication:
Should we coerce 1.2 to an integer value and use
or coerce 3 to a real value and use
Of course we could define the language in such a way that this decision is unambiguous, and guarantee the appropriate coercions by defining them with appropriate costs (see Overload resolution), but the definition would be more complex because of the cycle. Thus we recommend that the coercion graph not contain cycles.
A cast context is an expression context in which a specific type is required. For example, consider the extended Mystery program:
VAR i: INTEGER; VAR a: REAL; BEGIN i := 1; i := 2.3; a := 4; a := 5.6 END;
In each assignment, the type of the left-hand side determines the type that must be yielded by the right-hand side (see Values).
is used to provide the necessary type computations:
If a result of type `type' cannot be obtained directly
from the tree rooted in `expr',
a cast operator can be selected from those overloading
the indication `rator'.
Argument `type' is a definition table key, `rator' is a grammar
symbol playing the
OperatorSymbol role, and `expr' is a grammar
symbol playing the
Here is the definition of assignment for extended Mystery:
RULE: Stmt ::= Expr ':=' Expr COMPUTE CastContext(Expr.Type,,Expr); Indication(castInd); ChkRator; END;
Consider how the type analysis would proceed for each of the assignments in our extended Mystery program:
i := 1
i := 2.3
castIndindication must be available to provide the conversion.
a := 4
a := 5.6
The cast operator might be defined by:
PreDefOpr(castInd, rToi, (realType):intType)
Many languages also provide explicit cast contexts, which break the normal type relationship between two adjacent expression nodes (see Values). Here is an example, using C syntax:
RULE: Expr ::= '(' Type ')' Expr COMPUTE PrimaryContext(Expr,Type.Type); CastContext(Type.Type,,Expr); Indication(castInd); ChkRator; END;
The type of
Expr is known to be of the type
Expr acts as a leaf of the expression
tree containing it.
Expr, on the other hand, acts as the root of an expression tree:
the type of value it should produce is known.