Modula-2 || Compiler & Tools || Library || Search Engine

Ulm's Modula-2 Library:


Functions - definition and evaluation of functions


TYPE Function;
TYPE StdFunc1 = PROCEDURE (Real) : Real;
TYPE StdFunc2 = PROCEDURE (Real, Real) : Real;

VAR errpos: CARDINAL; (* error position in expr of ParseFunction *)

PROCEDURE InstallStdFunc1(funcname: ARRAY OF CHAR; stdfunc: StdFunc1); PROCEDURE InstallStdFunc2(funcname: ARRAY OF CHAR; stdfunc: StdFunc2); PROCEDURE InstallStdConst(constname: ARRAY OF CHAR; constval: Real);

PROCEDURE ParseFunction(expr: ARRAY OF CHAR; VAR func: Function) : BOOLEAN;

PROCEDURE FirstParam(func: Function); PROCEDURE NextParam(func: Function; VAR parname: ARRAY OF CHAR) : BOOLEAN;

PROCEDURE SetFuncParam(func: Function; parname: ARRAY OF CHAR; value: Real);

PROCEDURE EvalFunction(func: Function) : Real;

PROCEDURE DisposeFunction(VAR func: Function);


This module allows to define and evaluate real-valued functions at runtime. A function is defined by an expression whose grammar is Modula-2 oriented with following exceptions:
The ?: operator has been added (semantic close to C). ?: has lowest priority and right-to-left associativity.
Integer constants are real constants, too.
Operator-keywords are not supported, so use
    &   instead of AND
    |   instead of OR, and
    ~   instead of NOT.
TRUE is represented as 1.0 and FALSE as 0.0. Anything but 0.0 is taken to be TRUE in conditions.

The grammar in EBNF:
CondExpression =     Expression
                     [ "?" CondExpression ":" CondExpression ] .
Expression =         SimpleExpression
                     [ RelOp SimpleExpression ] .
SimpleExpression =   ["+"|"-"] Term { AddOp Term } .
Term =               Factor { MulOp Factor } .
Factor =             Constant | IDENT | FunctionCall |
                     "~" Factor | "(" CondExpression ")" .
FunctionCall =       IDENT "(" CondExpression
                     [ "," CondExpression ] ")" .
RelOp =              "=" | "#" | "<" | ">" | "<=" | ">=" .
AddOp =              "+" | "-" | "|" .
MulOp =              "*" | "/" | "&" .

The start symbol is CondExpression. Identifiers are sequences of letters and digits. The first character must be a letter.

Syntax of constants:
Digit { Digit } [ "." { Digit } ] [ ("E"|"e") Digit { Digit } ]

ParseFunction parses expr and returns the function in func for further referencing. On errors ParseFunction returns FALSE after errpos has been set to the error position. Errors can result from

Syntax errors.
Bad constants, e.g. exponent is too large.
Bad number of arguments to a function.

Each identifier not declared as a constant or a function (using InstallStdFunc1, InstallStdFunc2, or InstallStdConst) is considered to be a parameter. The value of a parameter is predefined to 0.0. FirstParam and NextParam give the parameter names in alphabetical order. Parameter values can be changed using SetFuncParam. EvalFunction evaluates the function with the parameters set previously. EvalFunction does not check for division by zero or any other operations which can result in a floating point exception.

DisposeFunction releases the storage associated with func.

To get a standard set of functions and constants StdFuncs should be imported.


   functxt, parname: ARRAY [0..63] OF CHAR;
   func: Function;
   val: Real;

(* ... *)
WriteString("func: "); ReadString(functxt);
IF ParseFunction(functxt, func) THEN
   WHILE NextParam(func, parname) DO
      WriteString(parname); WriteString(" = ");
      SetFuncParam(func, parname, val);
   WriteReal(EvalFunction(func), 1); WriteLn;
   (* error at errpos *)

Instead of reading real values it is possible to read parameters as strings and to parse and evaluate them. This enables the user to give standard constants and expressions as parameter values (e.g. pi/2).


ParseFunction returns FALSE on syntax errors. The error position is stored in errpos.




There is no good solution to handle floating point exceptions during the evaluation of functions. The only way to detect all exceptions is to catch the signal SIGFPE. But a signal catching routine of SIGFPE must not return else this would result in an infinite loop. The same problem occures if SIGFPE is ignored.

The only way to let functions call functions is to introduce standard functions via InstallStdFunc1 or InstallStdFunc2 which call EvalFunction.

Edited by: borchert, last change: 1999/01/13, revision: 1.4, converted to HTML: 1999/01/13

Modula-2 || Compiler & Tools || Library || Search Engine