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