This is a minimal Fortran library for parsing and evaluating mathematical functions given as strings. It supports basic arithmetic operations, parentheses, common mathematical functions, scientific notation, unary operators, and variable definitions.
- Parse mathematical expressions from strings
- Evaluate expressions with variable substitution
- Support for 35+ mathematical functions (trigonometric, hyperbolic, logarithmic, special functions)
- Case-insensitive function names (e.g.,
SIN,sin,Sinall work) - Case-sensitive variable names (e.g.,
xandXare different variables) - Scientific notation support (e.g., 1E-9, 2.5E3)
- Unary operators (+/-)
- User-defined variables with inline definitions
- Built-in constants (pi, e, R)
To compile the library, use the provided Makefile:
make main
This will generate an executable named main.exe.
The library provides a simple interface through the fp_evaluate function:
program example
use function_parser
implicit none
character(len=100) :: expr
real(kind=real64) :: result
expr = "3.5 + 2.1 * 4"
result = fp_evaluate(trim(expr))
write(*,*) "Result: ", result
end program exampleOutput:
Result: 11.900000000000000
You can read mathematical expressions from a text file using fp_get_string_from_file:
program example
use function_parser
implicit none
character(len=1000) :: expr
real(kind=real64) :: result
! Read expression from file
call fp_get_string_from_file("./math_exp.txt", expr)
! Evaluate the expression
result = fp_evaluate(trim(expr))
write(*,*) "Result: ", result
end program exampleExample file content (math_exp.txt):
a + b - c * d
[
a = 10,
b = 5 ,
c = 1.,
d = -8.
]
Output:
Verbose from fp_get_string_from_file:
Successfully read from file: ./math_exp.txt
Read expression from file: a + b - c * d[ a = 10, b = 5 , c = 1., d = -8. ]
Result: 23.000000000000000
(10 + 5 - 1 Γ (-8) = 10 + 5 + 8 = 23)
Notes:
- The file can contain multiple lines; they will be concatenated into a single expression
- The subroutine provides verbose output showing the file path and expression read
- If the file is not found or cannot be opened, an error message is displayed and an empty string is returned
You can set variable values programmatically using fp_set_variable_value before evaluating an expression:
program example
use function_parser
implicit none
character(len=100) :: expr
real(kind=real64) :: result
! Set variable values from code
call fp_set_variable_value("x", 5.0_dp)
call fp_set_variable_value("y", 3.0_dp)
call fp_set_variable_value("myvar", 10.5_dp)
! Evaluate expression using the set variables
expr = "x**2 + y**2 + myvar"
result = fp_evaluate(trim(expr))
write(*,*) "Result: ", result
end program exampleOutput:
Result: 44.500000000000000
(25 + 9 + 10.5 = 44.5)
Notes:
- Works with both built-in variables (
x,y,z,t,r,theta,phi,T,P) and user-defined variables - If the variable doesn't exist, it will be created automatically
- Variable names are case-sensitive
- This method is useful when variable values are computed or come from other parts of your program
You can also define variables inline within the expression using square brackets. Both formats are supported:
[var1=value1, var2=value2] expression
or
expression [var1=value1, var2=value2]
Examples:
[myvar1=23, myvar2=22] myvar1*myvar2 β Result: 506
myvar1*myvar2 [myvar1=23, myvar2=22] β Result: 506
x + y [x=3, y=2] β Result: 5
Numbers can be expressed in scientific notation:
1E-9 β 0.000000001
2.5E3 β 2500.0
-1.5E-2 β -0.015
Unary plus and minus are supported:
-5 + 3 β -2
3 * -2 β -6
(-5 + 3) * 2 β -4
5 - -3 β 8
exp(-200000/R/1000) β 3.0865917343815912E-011
sin(pi/4) + cos(pi/4) β 1.4142135623730951
sqrt(x**2 + y**2) [x=3, y=4] β 5.0
SINH(1) + COSH(1) β 2.7182818284590451 (β e)
gamma(5) β 24.0 (4! = 24)
log10(1000) + LN(e) β 4.0 (3 + 1)
[r=-10] r + R β -1.6855373819999997 (-10 + 8.314)
- Addition:
+ - Subtraction:
- - Multiplication:
* - Division:
/ - Exponentiation:
** - Unary Plus:
+x - Unary Minus:
-x
Note: All function names are case-insensitive (e.g., SIN, sin, Sin all work the same).
- Sine:
sin(x) - Cosine:
cos(x) - Tangent:
tan(x) - Arcsine:
asin(x) - Arccosine:
acos(x) - Arctangent:
atan(x) - Two-argument arctangent:
atan2(y, x)
- Hyperbolic sine:
sinh(x) - Hyperbolic cosine:
cosh(x) - Hyperbolic tangent:
tanh(x) - Inverse hyperbolic sine:
asinh(x) - Inverse hyperbolic cosine:
acosh(x) - Inverse hyperbolic tangent:
atanh(x)
- Exponential:
exp(x) - Natural logarithm:
log(x)orln(x) - Base-10 logarithm:
log10(x) - Logarithm of gamma function:
log_gamma(x)
- Gamma function:
gamma(x) - Error function:
erf(x) - Complementary error function:
erfc(x) - Scaled complementary error function:
erfc_scaled(x) - Bessel function J0:
bessel_j0(x) - Bessel function J1:
bessel_j1(x) - Bessel function Jn:
bessel_jn(n, x)- n must be integer - Bessel function Y0:
bessel_y0(x) - Bessel function Y1:
bessel_y1(x) - Bessel function Yn:
bessel_yn(n, x)- n must be integer - Euclidean distance:
hypot(x, y)- returns sqrt(xΒ²+yΒ²)
- Modulus:
mod(a, b) - Minimum:
min(a, b) - Maximum:
max(a, b) - Absolute value:
abs(x) - Square root:
sqrt(x)
Note: Constant names are case-sensitive.
- Pi:
pi(3.141592653589793) - Euler's Number:
e(2.718281828459045) - Gas Constant:
R(8.314462618)
Note: Variable names are case-sensitive (e.g., x and X are different variables).
The following variables are available and can be set using variable definitions:
x,y,z,t,r,theta,phi,T,P
Here is a simple example of how to use the library:
program test_function_parser
use function_parser
implicit none
character(len=200) :: expr
real(kind=real64) :: result
! Simple arithmetic
expr = "3.5 + 2.1 * 4"
result = fp_evaluate(trim(expr))
write(*,*) "Result: ", result ! 11.9
! With variables (case-sensitive)
expr = "[x=5, y=3] x**2 + y**2"
result = fp_evaluate(trim(expr))
write(*,*) "Result: ", result ! 34.0
! Case-insensitive functions
expr = "SIN(pi/2) + COS(0)"
result = fp_evaluate(trim(expr))
write(*,*) "Result: ", result ! 2.0
! Scientific notation and special functions
expr = "gamma(5) * exp(-1E-3)"
result = fp_evaluate(trim(expr))
write(*,*) "Result: ", result ! ~23.976
! Hyperbolic functions
expr = "SINH(1) + COSH(1)"
result = fp_evaluate(trim(expr))
write(*,*) "Result: ", result ! e β 2.718
end program test_function_parser - Function names are case-insensitive:
SIN(x),sin(x), andSin(x)all work identically - Variable names are case-sensitive:
xandXare treated as different variables - Constant names are case-sensitive: Use lowercase
pi,e,rfor the built-in constants
Due to Fortran fixed-form syntax limitations with the / character, the division operator is internally represented as div token. This is handled automatically during tokenization and is transparent to the user.
The library implements standard mathematical operator precedence:
- Functions (sin, cos, exp, etc.) - Highest precedence
- Exponentiation (
**) - Right associative - Unary operators (
+,-) - Multiplication and Division (
*,/) - Addition and Subtraction (
+,-) - Lowest precedence
This project is licensed under the LGPL2.1 License. See the LICENSE file for details.
Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.
AI assistance provided by Visual Studio Code Copilot. I didn't even know what infix and postfix were, and still don't fully understand them (actually I don't care that much). It took about a couple of hours to write this library with Copilot's help.
src=src/main.for src/function_parser.for
FC=gfortran
FFLAGS=-O2 -Wall
.PHONY: main clean
main: $(src)
$(FC) $(FFLAGS) -o main.exe $(src)
clean:
rm -f main.exe