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.
|