General Information
Tutorials
Reference Manuals
Libraries
Translation Tasks
Tools
Administration
|
Oil Reference ManualRelating an OIL specification to library function callsTo explain the relationship between the specification and the abstract data type we will examine different extractions from some possible specifications and review the behavior of some of the related functions in the abstract data type. Using Names
Each entity defined in an OIL specification is represented by a definition
table key.
The OIL value is accessible as a property of that definition table key.
For example, suppose that
In order to avoid the overhead of querying a property for constant
information, OIL also defines an identifier as the actual OIL operator.
This identifier is constructed by prefixing the OIL identifier with
Similar conventions are used for OIL types and OIL classes:
The OIL identifier denotes a known key, and the actual OIL entity (of type
A simple exampleLet us consider the following OIL specification:
iAdd ( int_t, int_t ): int_t; /* the usual '+' operators for Pascal */ rAdd ( real_t, real_t ): real_t; sUnion ( set_t, set_t ): set; Plus: iAdd, rAdd, sUnion; /* will be identified together */ COERCION Float( int_t ): real_t; /* usual Pascal coercion from int to real */
Definitions from the specificationAll of the identifiers in this specification will denote values to the library functions. The functions in the library will be applied to values constructed from these identifiers and will return values represented by these identifiers. Operator Identification
The most basic operation is that of operator identification so we will
start there. When semantically analyzing a binary expression formed with a
plus sign (+), the compiler would use the function
The invocation
Any combination of operand types like real_t and set_t
would return a value denoting an erroneous operator.
Example: Operator SignaturesOnce we have identified an operator will need to know its type signature so that we may return the type of the subexpression computed by the operator and so we may determine the types required by the operator from its respective operands. The functionOilGetArg gives us that facility.
The expression Coercion sequence
Once we have the type returned by an operator and know the type required
of this sub-expression (from the parent context) we may need to apply a
sequence of coercions on the result of the operator to satisfy the requirements
of the parent context. The function
In the case of our example we might require a real_t result from an
iAdd operator (which returns int_t.)
The expression
If no coercions were necessary then
A more complex exampleNot all operator identification schemes can be implemented with the simple bottom-up type evaluation shown in the previous section. Sometimes the desired result type will affect which operator denotation is identified with a given operator indication. OIL supplies this capability with the set of types operations.
Below is an example OIL specification which is designed
to use set of types.
The specification shows that there are two multiplication
operators(
sMulS ( single, single ): single; sMulD ( single, single ): double; dMulD ( double, double ): double; COERCION iCvtStoD ( single ): double; Mul: dMulD, sMulD, sMulS Using type sets
To use type set functions we must begin with constructing the
possible result type set of a terminal. For this we use the function
For the rest of this example we will use the identifiers
To analyze an entire expression with type sets we must
also be able to determine the set of types associated with
an operator indication and its set of operands. For this we use the
When we get to the root of an expression (like in an assignment) we would
then use a desired type determined from the context of the root of the
expression (like the destination type of the assignment)
to determine which operator we wanted to
select. For this we use the
By using type sets, the operator indication Mul with single operands can identify sMulD, thus directly producing a double result; whereas with the simple scheme used previously (see A simple example.) an additional coercion would be needed to return a double result.
Using Classes
There are three steps to using classes: (1)specifying them with OIL,
(2)instantiating them using the
The following OILspecification allows us to define any number of
CLASS Set( element ) BEGIN COERCION coElemToSet(element):Set; OPER soUnion(Set,Set):Set; END; OPER soIadd(tInt,tInt):tInt; OPER soRadd(tReal,tReal):tReal; INDICATION loPlus: soIadd, soRadd, soUnion;We can then construct a simple binary expression compiler which uses a constant set for one of its possible operand types. NONTERM Expr: op:tOilOp, st:tOilType; RULE Dyadic: Expr::= Term Ind Term STATIC Expr.st:= OilClassInst1( Set, Set_name, tInt ); Expr.op:= OilIdOp2( Ind.op, Term[1].type, Term[2].type ) END; NONTERM Term: type:tOilType; RULE Set: Term::= 's' STATIC Term.type:= INCLUDING Expr.st END; RULE Integer: Term::= 'i' STATIC Term.type:= tInt END; RULE Real: Term::= 'r' STATIC Term.type:= tReal END; NONTERM Ind: op:tOilOp; RULE Plus: Ind::= '+' STATIC Ind.op:= loPlus END;We use the following request to construct the compiler: test3.specs :exe>test3.exe
|