|
|
|
General Information
Tutorials
Reference Manuals
Libraries
Translation Tasks
Tools
Administration
|
|
Tutorial on Type AnalysisFunctionsThis chapter introduces definitions and calls of parameterized functions. Type analysis has to check that the signature of a function call matches the signature of the called function, and that functions return a value of the specified type. Here is an example program that defines some functions. The grammar for function calls and return statements is given below. FunctionExamp[90]==
begin
var int i, int j,
bool b, bool c,
real r, real s;
fun f (int x, real y) real
begin r = x * y; return r;end;
fun g (real z) void
begin r = z; return; end;
s = f (i+1, 3.4);
g (f (j, s));
return;
end
This macro is attached to a product file. We first extend the grammar by productions for function declarations: Abstract function syntax[91]==
RULE: Declaration ::= FunctionDecl END;
RULE: FunctionDecl ::= 'fun' DefIdent Function ';' END;
RULE: Function ::= FunctionHead Block END;
RULE: FunctionHead ::= '(' Parameters ')' TypeDenoter END;
RULE: Parameters LISTOF Parameter END;
RULE: Parameter ::= TypeDenoter DefIdent END;
This macro is invoked in definition 100. A function type is characterized by its signature, i.e. the sequence of the types of its parameters and the result type. (Note: If we had more than one mode of parameter passing, the abstraction of a parameter in the function signature would be a pair: parameter passing mode and parameter type.)
We first consider the name analysis aspect of a function
declaration: The Function range[92]== SYMBOL Function INHERITS RangeScope END; This macro is invoked in definition 100.
Now we consider a function declaration as a definition
of a typed entity, and apply the same specification pattern
as used for variable declarations.
Furthermore, each Function declaration types[93]== SYMBOL FunctionDecl INHERITS TypedDefinition END; RULE: FunctionDecl ::= 'fun' DefIdent Function ';' COMPUTE FunctionDecl.Type = Function.Type; END; RULE: Function ::= FunctionHead Block COMPUTE Function.Type = FunctionHead.Type; END; SYMBOL Parameter INHERITS TypedDefinition END; RULE: Parameter ::= TypeDenoter DefIdent COMPUTE Parameter.Type = TypeDenoter.Type; END; This macro is invoked in definition 100.
Next, we specify how the type of a function is composed.
The Function type[94]== SYMBOL FunctionHead INHERITS TypeDenotation, OperatorDefs END; This macro is invoked in definition 100.
Furthermore, a function declaration introduces an operator.
This is indicated by the role Function signature[95]==
RULE: FunctionHead ::= '(' Parameters ')' TypeDenoter COMPUTE
FunctionHead.GotOper +=
ListOperator (
FunctionHead.Type,
FunctionHead.Type,
Parameters.OpndTypeList,
TypeDenoter.Type);
END;
SYMBOL Parameters INHERITS OpndTypeListRoot END;
SYMBOL Parameter INHERITS OpndTypeListElem END;
RULE: Parameter ::= TypeDenoter DefIdent COMPUTE
Parameter.DefTableKeyElem = TypeDenoter.Type;
END;
This macro is invoked in definition 100.
Function calls are integrated in the expression syntax of
our language. We chose a very general form of an We also introduce return statements into our language: Abstract call syntax[96]==
RULE: Expression ::= Expression '(' Arguments ')' END;
RULE: Arguments LISTOF Argument END;
RULE: Argument ::= Expression END;
RULE: Statement ::= 'return' ';' END;
RULE: Statement ::= 'return' Expression ';' END;
This macro is invoked in definition 100.
Type analysis for a function call is straight-forward:
A call is treated as an operation which takes the arguments
as operands. Call types[97]==
SYMBOL Arguments INHERITS OpndExprListRoot END;
SYMBOL Argument INHERITS OpndExprListElem END;
RULE: Expression ::= Expression '(' Arguments ')' COMPUTE
ListContext (Expression[1], , Arguments);
Indication (Expression[2].Type);
IF(BadOperator,
message
(ERROR,
"Call does not match the functions' signatures",
0, COORDREF));
END;
This macro is invoked in definition 100.
The following context connects the
Hence, we use a Arguments[98]== RULE: Argument ::= Expression COMPUTE ConversionContext (Argument, , Expression); Indication (assignOpr); END; This macro is invoked in definition 100.
A return statement refers to the immediately enclosing function
declaration. It has to be checked that a value of a type is returned
that is compatible to the result type, if the latter is not
The attribute value Return statements[99]==
ATTR ResultType: DefTableKey;
RULE: Statement ::= 'return' Expression ';' COMPUTE
RootContext (
INCLUDING (Function.ResultType, Program.ResultType), , Expression);
Indication (assignOpr);
END;
RULE: Statement ::= 'return' ';' COMPUTE
IF (NOT (EQ (voidType,
FinalType (
INCLUDING (Function.ResultType,
Program.ResultType)))),
message (ERROR, "return value required", 0, COORDREF))
<- INCLUDING Program.TypeIsSet;
END;
SYMBOL Program COMPUTE
SYNT.ResultType = voidType;
END;
RULE: Function ::= FunctionHead Block COMPUTE
Function.ResultType = FunctionHead.ResultType;
END;
RULE: FunctionHead ::= '(' Parameters ')' TypeDenoter COMPUTE
FunctionHead.ResultType = TypeDenoter.Type;
END;
This macro is invoked in definition 100. Function.lido[100]== Abstract function syntax[91] Abstract call syntax[96] Function declaration types[93] Function range[92] Function type[94] Function signature[95] Call types[97] Arguments[98] Return statements[99] This macro is attached to a product file. Function.con[101]== Function declaration syntax[140] Call syntax[141] This macro is attached to a product file.
|