use M_calculator, only : calculator, getvalue, igetvalue, rgetvalue, stuff, stuffa use M_calculator, only : iclen_calc, ixy_calc, icname_calc, x, y, values_len, values ! convenience routines use M_calculator, only : inum0, rnum0, dnum0, snum0, expression, strgarr, strgar2
The M_calculator module and related functions evaluate CHARACTER strings containing FORTRAN-like expressions and returns numeric and string values.
Using this interface it is easy to make free-format and order-independent input interfaces where values can be expressions and variable names instead of simple formatted numbers.
The primary routine CALCULATOR(3f) acts like a powerful desk-top calculator. It supports named variables and has several arrays (of 55555 elements each). Many standard FORTRAN functions are available, plus access to user-written functions is permitted via user-supplied routines via set_mysub(3f) and set_myfunc(3f).
The programmer (generally) uses just the CALCULATOR(3f) routine or several convenience routines (INUM0,RNUM0,SNUM0,STRGAR2,EXPRESSION) that simplify making the most common type of calls to CALCULATOR(3f).
The variables used to hold the X,Y,$X $Y, ... arrays and the dictionaries of variable names and string names and their associated values:
- integer,parameter,public :: iclen_calc=512 ! max length of expression or variable value as a string
- integer,parameter,public :: ixy_calc=55555 ! number of variables in X() and Y() array
- integer,parameter,public :: icname_calc=20 ! max length of a variable name
- real(kind=dp),save,public :: x(ixy_calc)=0.0_dp ! x array for procedure funcs_
- real(kind=dp),save,public :: y(ixy_calc)=0.0_dp ! y array for procedure funcs_
- integer,save,public,allocatable :: values_len(:) ! lengths of the string variable values
- character(len=:),save,public,allocatable :: values(:) ! string variable values
A=sin(3.1416/2) big=200.333E200 $name="Thomas Jefferson"Variables may be defined by equating them to an expression. To define or redefine a variable called FRED, simply enter:
> FRED=300*4/500The last value assigned to a variable will be used to evaluate the expression on the left of the equals sign when this expression redefines the variable. For example:
> A=2 2 > A 2 > A=A+A 4 > A=A+A 8To allow FORTRAN-type E-format numeric entry and yet not cause the calculator routine to do an excessive amount of checking, a variable name ending in the letter E must not have a digit (012345789) in front of that ending E. Attempting to define such a variable name will produce an error. This limitation prevents the calculator from becoming confused by whether 12E+3 is a variable called 12E plus 3 or the exponential number 12E3=12000.
> (300+500) 800 > (1/4)*? 200 > ?+? 400
xstore(start,ex1,ex2,ex3)where start=array address to start storing at and ex(i) are expressions.
ystore(start,ex1,ex2,ex3)
xstore( 10 , 1/10 , 2/20 , 3/10 ) ^ ! *-------Start storing evaluated expressions sequentially, beginning at x(10).
> xstore(1,10,20,30) 30 > fred=x(1)+x(2)+x(3) 60NOTES:
x(10)=5 # IS ILLEGAL
In addition to standard Fortran intrinsics, many other functions are supported ...
a=if(ge(b,c),a,d)means return a if b is greater than or equal to c else return d.
The $now() and $fmtdate() functions can output a date in a multitude of formats and can be used to perform simple date manipulations.
If ITYPE is present different algorithms are used. The system routines vary from platform to platform. The preferred algorithm is the "Numerical Recipes" algorithm. The ITYPE must agree between the SRAND() call and the RAND() call. A call to SRAND() should precede use of RAND().
Any program that calls CALCULATOR(3f) directly or indirectly (via EXPRESSION(3f), STRGAR2(), INUM0(), RNUM0(), SNUM0()) can extend the functions available by supplying two routines:
The following program shows a simple but complete line-mode calculator program.
./compute # run example program a=10 a/2 3**4 sin(3.1416/4) PI=2*asin(1) diameter=20.3+8/4 circumference=PI*diameter funcs dump # use end-of-file (typically control-D) to exit program ctrl-D
program demo_M_calculator ! line mode calculator that calls calculator ! use M_calculator, only: calculator,iclen_calc use M_calculator, only : rnum0 use M_calculator, only : set_mysub, set_myfunc implicit none integer, parameter :: k_dbl = SELECTED_REAL_KIND(15,300) ! real*8 character(len=iclen_calc) :: event, line character(len=iclen_calc) :: outlin integer :: ios integer :: ierr real(kind=k_dbl) :: rvalue character(len=80) :: string INFINITE: do read(*,'(a)',iostat=ios)line if(ios.ne.0)exit INFINITE call calculator(line,outlin,event,rvalue,ierr) ! line -- input expression ! outlin -- result as a string ! event -- ! rvalue -- result as a numeric value ! ierr -- return status ! ! several different meaning to the status flag ... select case(ierr) case(0) ! a numeric value was returned without error write(6,'(a,a,a)')trim(outlin),' = ',trim(line) case(2) ! a string value was returned without error write(6,'(a)')trim(event) case(1) ! a request for a message has been returned ! (from DUMP or FUNC) write(6,'(a,a)')'message===>',trim(event) case(-1) ! an error has occurred write(6,'(a,a)')'error===>',trim(event) case default ! this should not occur write(6,'(a)')'warning===> unexpected ierr value from calculator' end select enddo INFINITE string='A=sind(30)' rvalue=rnum0(string,ierr) if(ierr.eq.0)then write(*,*) rvalue else write(*,*) 'error evaluating '//trim(string) endif rvalue=rnum0('A',ierr) write(*,*) rvalue ! OPTIONAL: contains example routines for adding user-defined ! functions. ! call set_mysub(my_functions) call set_myfunc(c) contains subroutine my_functions(func,iflen,args,iargstp,n,fval,ctmp,ier) ! extend functions available to the calculator routine ! ! if the function ownmode(1) is called this subroutine ! will be accessed to do user-written functions. ! ! func(iend-1)=procedure name. func should not be changed. ! iflen=length of procedure name. ! args=array of 100 elements containing procedure arguments. ! iargstp=type of argument(1=numeric value,2=position of string value) ! n=integer number of parameters ! x=array of 55555 x values ! y=array of 55555 y values ! fval=value to replace function call ! ctmp=string to return when returning a string value ! ier=returned error flag value. ! set to -1 if an error occurs. ! set to 0 if a number is returned ! set to 2 if a string is returned ! use M_calculator, only: x,y,values,values_len,iclen_calc integer, parameter :: k_dbl = SELECTED_REAL_KIND(15,300) ! real*8 ! values: the values of string variables ! values_len: the lengths of the string variable values character(len=*),intent(in) :: func integer,intent(in) :: iflen real(kind=k_dbl),intent(in) :: args(100) integer,intent(in) :: iargstp(100) integer,intent(in) :: n real(kind=k_dbl) :: fval character(len=*) :: ctmp integer :: ier integer :: iwhich integer :: i10 integer :: ilen character(len=iclen_calc) :: temp1 fval=0.0d0 !----------------------------------------------------------------------- write(*,*)'*my_functions* unknown function ', func(1:iflen) write(*,*)'function name length is..',iflen write(*,*)'number of arguments .....',n do i10=1,n if(iargstp(i10).eq.0)then write(*,*)i10,' VALUE=',args(i10) elseif(iargstp(i10).eq.2)then iwhich=int(args(i10)) ilen=values_len(iwhich) write(*,*)i10,' STRING='//values(iwhich)(:ilen) else write(*,*)'unknown parameter type is ',iargstp(i10) endif enddo end subroutine my_functions !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc real function c(fval,n) implicit none ! a built-in calculator function called c must be satisfied. ! write whatever you want here as a function integer, parameter :: k_dbl = SELECTED_REAL_KIND(15,300) ! real*8 integer,intent(in) :: n real(kind=k_dbl),intent(in) :: fval(n) c=0.0_k_dbl end function c !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc end program demo_M_calculator