Expression evaluator
Introduction
This module and test program can parse and evaluate mathematical expressions. It uses Dijkstra's shunting yard algorithm to convert infix notation in postfix (Reverse Polish Notation, RPN), which is trivial to evaluate in the correct order. This was my first try at using pointers in Fortran to create and use stacks. It can also evaluate parametric expressions such as 3*x for a range of values of x.
Quick Overview
The public procedures of this module can be made accessible by USEing the following modules:
use m_expr_eval
use m_precision, only: dp
From the module m_expr_eval, two procedures are public, these are EVAL_EXPR and DEBUG_MOD. The latter can be used to print debug statements during execution, but it should not be necessary to use it. The former subroutine can be supplied with a string containing the expression that must be evaluated,
result = eval_expr( "3+4" )
The following list of operations and intrinsic functions are supported at the moment:
+ - * / ^ atan2 power sign mod modulo tanh atan tan sinh asin sin cosh acos cos sqrt exp log ln log10 aint anint ceiling floor
They work the same as their respective counterparts in Fortran, so except for ATAN2, POWER, SIGN, MOD, and MODULO they accept 1 argument. Note that it is not checked that the input is within the bounds of the functions.
The operations supported are multiplication, division, addition, substraction and exponentiation. The last one uses the caret (^) instead of the double multiplication as in Fortran.
Be aware that the tokenizer might contain errors that can cause segfaults lateron. Use it at your own risk.
A new thing is that it can also parse expressions that contain parameters, which makes it possible to evaluate expressions for a range of parameter values without having to re-tokenize and parse the complete expression.
Sources
The module and a test program can be downloaded here as a compressed tar archive. This archive does not contain build files, but using ifort, the module library and program can be build as follows:
$ wget http://users.telenet.be/tuinbels/fortran/m_expr_eval-2.0.tgz
$ tar -xzf m_expr_eval-2.0.tgz
$ cd m_expr_eval
$ ifort -c -o m_precision.o m_precision.F90
$ ifort -c -o m_constants.o m_constants.f90
$ ifort -c -o m_sys_fun.o m_sys_fun.f90
$ ifort -c -o m_option_parser.o m_option_parser.F90
$ ifort -c -o m_expr_eval.o m_expr_eval.f90
$ ifort -o test_expr_eval test_expr_eval.f90 m_precision.o m_constants.o m_sys_fun.o m_option_parser.o m_expr_eval.o
The supplied test program can then be executed with the option "-h" or "--help", which will print all available options,
$ ./test_expr_eval -h
Usage: ./test_expr_eval [options]
options:
--expression, -e
default expression
[character] default: 4.0*atan(1)-ln(exp(pi))
--parameters, -p
default parameters
[character] default:
--parvals, -v
actual values of parameters
[character] default:
--loop, -l
show an example of an evaluation of an expression for a range of parameter
values
[logical] default: F
--simple_exp, -s
show evaluation of a simple non-parametric expression
[logical] default: F
--help, -h
print help message to screen and quit
[logical] default: F
--debug, -d
print debug statements
[logical] default: F
License
The sources are licensed under a 3-clause BSD license.
API docs
The API docs can be viewed here. They were created using ROBODoc
Public module name, subroutine names and derived types
- m_expr_eval
- expression evaluator module
- debug_mod
- subroutine to turn on debugging statements
- eval_expr
- function evaluates supplied expression and returns result
Example
program test_expr_eval
use m_expr_eval ! load public procedures
use m_precision, only: dp ! double precision kind constant
implicit none
real(dp) :: result
logical :: debug
character(len=*) , parameter :: expr = "3+2*11-sin(pi)"
result = eval_exp( expr )
print *, expr , " = " , result
end program test_expr_eval