![]() |
![]() |
![]() |
General Information
Tutorials
Reference Manuals
Libraries
Translation Tasks
Tools
Administration
![]() |
![]() |
Tutorial on Type AnalysisFunctionsWe now introduce function declarations to our language. A function is characterized by its signature. Function types are an example of types that have properties which are lists of types, the types of the parameters. We extend the concrete grammar by productions for function declarations: Function.con[57]== Declaration: FunctionDecl. FunctionDecl: 'fun' DefIdent Function ';'. Function: FunctionHead Block. FunctionHead: '(' Parameters ')' TypeDenoter. Parameters: [Parameter // ',']. Parameter: TypeDenoter DefIdent. This macro is attached to a product file. Here is an example program that defines some functions. The grammar for function calls and return statements is given below. FunctionExamp[58]== 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.
A function signature consists of the result type and a
list of parameter types. Hence, we use an instance of
the Function.specs[59]== $/Adt/LidoList.gnrc+instance=DefTableKey+referto=deftbl:inst This macro is attached to a product file. The use of the module requires a particular name for the non-existing list element: Function.head[60]== #define NoDefTableKey NoKey This macro is attached to a product file. A function type is described by two properties, the result type and and the list of parameter types as introduced by the following PDL specifications: Function.pdl[61]== ParamTypes: DefTableKeyList; "DefTableKeyList.h" ResultType: DefTableKey [KReset]; This macro is attached to a product file.
We first consider the name analysis aspect of a function
declaration. The FunctionScope.lido[62]== SYMBOL Function INHERITS RangeScope END; This macro is attached to a product file.
Now we consider a function declaration as a definition
of a typed object, and apply the same specification pattern
as used for variable declarations.
Furthermore, each FunctionDecl.lido[63]== 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; DefIdent.IsVariable = 1; END; This macro is attached to a product file.
Now we specify how the type of a function is composed.
The FunctDeclType.lido[64]== SYMBOL FunctionHead INHERITS TypeDenotation END; RULE: FunctionHead ::= '(' Parameters ')' TypeDenoter COMPUTE FunctionHead.GotType = ResetParamTypes (KResetResultType (KResetTypeName (FunctionHead.Type, "function..."), TypeDenoter.Type), Parameters.DefTableKeyList); END; SYMBOL Parameters INHERITS DefTableKeyListRoot END; SYMBOL Parameter INHERITS DefTableKeyListElem END; RULE: Parameter ::= TypeDenoter DefIdent COMPUTE Parameter.DefTableKeyElem = TypeDenoter.Type; END; This macro is attached to a product file.
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. Call.con[65]== Expression: Expression '(' Arguments ')'. Arguments: [Argument // ',']. Argument: Expression. Statement: 'return' ';'. Statement: 'return' Expression ';'. This macro is attached to a product file.
Type analysis for a function call is straight-forward:
We access the Call.lido[66]== SYMBOL Arguments INHERITS DefTableKeyDeListRoot END; RULE: Expression ::= Expression '(' Arguments ')' COMPUTE Expression[1].Type = TransDefer (GetResultType (Expression[2].Type, NoKey)); Arguments.DefTableKeyList = GetParamTypes (Expression[2].Type, NULLDefTableKeyList); END; SYMBOL Argument INHERITS DefTableKeyDeListElem END; RULE: Argument ::= Expression COMPUTE Expression.ReqType = Argument.DefTableKeyElem; END; This macro is attached to a product file.
The computation of the CallCheck.lido[67]== RULE: Expression ::= Expression '(' Arguments ')' COMPUTE Expression[2].ReqType = Expression[2].Type; IF (EQ (Expression[1].Type, NoKey), message (ERROR, "call applied to non function", 0, COORDREF)); IF (NE (Arguments.DefTableKeyListTail, NULLDefTableKeyList), message (ERROR, "arguments missing", 0, COORDREF)); END; RULE: Argument ::= Expression COMPUTE IF (EQ (Argument.DefTableKeyElem, NoDefTableKey), message (ERROR, "too many arguments", 0, COORDREF)); END; This macro is attached to a product file.
A return statement refers to the immediately enclosing function
declaration. We have to check that a value of a type compatible
to the result type is returned if the latter is not Return.lido[68]== SYMBOL Program COMPUTE SYNT.Type = KResetResultType (NewKey(), voidType); END; ATTR resType: DefTableKey; RULE: Statement ::= 'return' ';' COMPUTE .resType = TransDefer (GetResultType (INCLUDING (FunctionDecl.Type, Program.Type), NoKey)) <- INCLUDING Program.GotType; IF (NOT (EqualTypes (.resType, voidType)), message (ERROR, "return value required", 0, COORDREF)); END; RULE: Statement ::= 'return' Expression ';' COMPUTE .resType = TransDefer (GetResultType (INCLUDING (FunctionDecl.Type, Program.Type), NoKey)) <- INCLUDING Program.GotType; IF (EqualTypes (.resType, voidType), message (ERROR, "return value not allowed", 0, COORDREF)); Expression.ReqType = .resType; END; This macro is attached to a product file.
|