JUEXPR(3f)
Version 3.0.0:Use at your own risk.
SYNOPSIS
The JUEXPR(3f) library evaluates
CHARACTER strings containing FORTRANlike expressions and returns
numeric and string values.
It supports named variables and most ANSI FORTRAN 77 functions.
 juexpr.f is the library code
 simple.f is a very simple example that calls the convenience function RNUM0(3f)
 mycalc.f is an example that calls the main routine JUEXPR(3f)
f77 juexpr.f mycalc.f o mycalc
Using the JUEXPR(3f) interface it is easy to make freeformat and
orderindependent input interfaces where values can be expressions
and variable names instead of simple numbers.
It has been used in lieu of NAMELIST in many
programs; and as a basic building block in creating languagelike
input formats.
There are much more powerful and modern expression parsers available
nowadays, but this routine has proven to be very portable and
simple to maintain; and is still useful.
The library is basically written in FORTRAN 77; it uses no recursion and no
dynamically allocated variables and is very portable. It does
not support userdefined arrays, handling of complex numbers,
or interpreted userdefined functions.
The parser is not intended to be used to generate a large number
(hundreds of thousands) of calculations. It was written to be
portable, not optimal. The library has been used on many operating
systems, including NOS, NOS/VE, VMS, COS, Aegis, UNICOS, SunOS,
HPUX, IRIX64, AIX, Solaris, Ultrix, Tru64, OpenBSD, Linux, CygWin,
...
Perhaps the simplest example is a loop that reads input lines
and calls the calculator using the convenience function RNUM0(3f):
PROGRAM simple
CHARACTER*255 line
REAL*8 rnum0
WRITE(*,*)'Enter numeric expressions'
1 CONTINUE
READ(*,'(A)',ERR=1,IOSTAT=ios,END=999) line
WRITE(*,*)rnum0(line)
GOTO 1
999 CONTINUE
END
A run of the example program might look like this:
300+4/31
300.33334
sin(d2r(90))
1.
f2c(210)
98.888885
a=10
10.
b=20
20.
a/b
0.5
?+a+b
30.5
DESCRIPTION
A summary of the syntax rules for the expressions follows:
 The hierarchy of operations is the same as that of
FORTRAN 77 except that adjacent exponents are done from left
to right, not right to left [i.e. in FORTRAN
3**2**4=3**(2**4), in JUEXPR 3**2**4=(3**2)**4]; and +
strings are resolved to a single sign (that is, 3+ 4 is
acceptable instead of 3+(4)).
 The JUEXPR routine provides almost all the ANSI
mathematical functions available in FORTRAN 77, as well as
access to common extensions and custom routines.
 Embedded nonquoted blanks are ignored during the processing of a calculation.
 All numeric values are treated as FORTRAN type REAL*8 variables.
 Input lines should not be longer than 255 characters.
 There are three ways to store results to be used in future calculations:
 Variable names
 The currentvalue
 The x and y arrays
Each of the types will be discussed separately.
VARIABLE NAMES
Names must be 1 to 20 characters long, and are casesensitive. Up
to 2345 names are permitted. Numeric variable names should be
composed of the letters az and underscores and numbers. String
variables are similar but start with a dollar sign($). Names must
not end in a "digitE" combination. For example:
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/500
The 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
8
To allow FORTRANtype Eformat 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.
CURRENT VALUE
The variable name '?' is automatically set by the program to
contain the last calculated value. This currentvalue
register may be used like any variable or number. It is 0 at
program initialization. Example:
> (300+500)
800
> (1/4)*?
200
> ?+?
400
THE X AND Y ARRAYS
Two arrays called X and Y are available that can contain up
to 3333 values each. The arrays are originally initialized
to all zeros. To set values in the arrays, use the xstore (or
ystore) command. The format of the commands is
xstore(start,ex1,ex2,ex3)
ystore(start,ex1,ex2,ex3)
where start=array address to start storing at
and ex(i) are expressions.
The current value is assigned the last value stored.
In addition there are similar string arrays and functions
that can hold up to 50 255character strings:
 $xstore(), $ystore()
 $x() ,$y()
For example, to store into the locations 10,11,and 12
the values 1/10,2/10, and 3/10, the following could be
entered:
xstore( 10 , 1/10 , 2/20 , 3/10 )
^
!
*Start storing evaluated expressions sequentially,
beginning at x(10).
REFERENCING AN ARRAY VALUE
The values stored into the arrays may be referenced by
subscript. For example:
> xstore(1,10,20,30)
30
> fred=x(1)+x(2)+x(3)
60
NOTES:
 x and y array values cannot be used on the left of
equal signs.
x(10)=5 # IS ILLEGAL
 The current value is set to the value of the last
expression by the xstore and ystore commands
AVAILABLE FUNCTIONS
conversion functions
 r2d(arg)  converts from radians to degrees
 d2r(arg)  converts from degrees to radians
 f2c()  convert Fahrenheit to Celcius
 c2f()  convert Celcius to Fahrenheit
logical functions
 ge(val1,val2)  return TRUE if VAL1 is greater than or equal to VAL2, else return FALSE
 gt(val1,val2)  return TRUE if VAL1 is greater than to VAL2, else return FALSE
 eq(val1,val2)  return TRUE if VAL1 is equal to VAL2, else return FALSE
 le(val1,val2)  return TRUE if VAL1 is less than or equal to VAL2, else return FALSE
 lt(val1,val2)  return TRUE if VAL1 is less than VAL2, else return FALSE
 ne(val1,val2)  return TRUE if VAL1 is not equal to VAL2, else return FALSE
 if(expression,val1,val2)  If expression is TRUE, return VAL1 else return VAL2
For example:
a=if(ge(b,c),a,d)
means return a if b is greater than or equal to c else return d.
lexical logical functions
 lge($str1,$str2)  return TRUE if $STR1 is lexically greater than or equal to $STR2, else return FALSE
 lgt($str1,$str2)  return TRUE if $STR1 is lexically greater than to $STR2, else return FALSE
 leq($str1,$strN)  return TRUE if $STR1 is lexically equal to any of the other strings, else return FALSE
 lle($str1,$str2)  return TRUE if $STR1 is lexically less than or equal to $STR2, else return FALSE
 llt($str1,$str2)  return TRUE if $STR1 is lexically less than $STR2, else return FALSE
 lne($str1,$strN)  return TRUE if $STR1 is not equal to all following strings.
 $if(expression,$str1,$str2)  If expression is TRUE, return $STR1 else return $STR2
miscellaneous functions
 ceil(val1)  ceil() returns the least integral value greater than or equal to VAL1.
 floor(val1)  floor() returns the greatest integral value less than or equal to VAL1.
 in(val1,val2,val3)  returns TRUE if VAL1 is between VAL2 and VAL3 else returns FALSE
Stringrelated
 $char(v1,v2,....)  return characters indicated by numeric ADE (ASCII decimal equivalent) values passed.
 $(ex,ex,ex,...) or $str(ex,ex,ex,...)  generate a string from a series of strings and values
 str(ex,ex,ex,...)  same as $str() but convert resulting string to a number IF the string is a simple numeric value
 $substr(string,i,j)  return a string that is columns i thru j of the input string (first character is called column 1).
 ichar($char)  return the ADE (ASCII Decimal Equivalent) value of a letter
 index($str1,$str2)  return column number where $str2 begins in $str1 or zero(0).
 len($str1)  return the length of the string
ANSI FORTRAN INTRINSIC MATH FUNCTIONS
The common FORTRAN 77 intrinsic functions are supported.
FORTRAN Functions
abs  acos  aint  anint  asin 
atan  atan2  cos  cosh  dim 
exp  frac  idnint  int  log 
log10  max  min  mod  nint 
real  sign  sin  sinh  sqrt 
tan  tanh 
A full description of the ANSI FORTRAN Functions is available in The
The calculator routine supports many ANSIstandard functions.
The following material briefly describes each of these routines.
For exact details on the bounds values may assume and for other
details relating to these routines, a machinespecific FORTRAN
manual is advised as reference. These descriptions are placed
here as a guide.
The intrinsic functions are listed in alphabetical order along
with a brief description. For specific functions, the argument
type is shown in parentheses.
ANSI FORTRAN FUNCTIONS ALPHABETIZED
 ABS  absolute value
 ACOS  arccosine in radians
 AINT  truncation
 ANINT  nearest whole number
 ASIN  arcsine in radians
 ATAN  arctangent in radians
 ATAN2  arctangent in radians. Both arguments must not be 0
 COS  cosine in radians
 COSH  hyperbolic cosine
 DIM  positive difference
 =arg1arg2 if arg1 > arg2
 =0 if arg1 <= arg2
 EXP  exponential
 INT  type conversion (value returned in REAL storage)
 LOG  natural logarithm
 LOG10  common logarithm
 MAX  largest value (50 instead of 500 parameters allowed)
 MIN  smallest value (50 instead of 500 parameters allowed)
 MOD  remainder of arg1/arg2 =arg1(INT(arg1/arg2)*arg2) if arg2=0 result is undefined
 NINT  nearest integer (value returned in REAL storage)
 REAL  type conversion (real)
 SIGN  sign transfer
 = arg1 if arg2 >=0
 = arg1 if arg2 < 0
 SIN  sine in radians
 SINH  hyperbolic sine in radians
 SQRT  square root
 TAN  tangent in radians
 TANH  hyperbolic arctangent in radians
ANSI FORTRAN FUNCTIONS GROUPED BY FUNCTIONS
 Arc or antitrigonometric functions

 ACOS  arccosine in radians
 ASIN  arcsine in radians
 ATAN  arctangent in radians
 ATAN2  arctangent in radians
 Trigonometric functions

 COS  cosine in radians
 SIN  sine in radians
 TAN  tangent in radians
 Hyperbolic trigonometric functions

 COSH  hyperbolic cosine
 SINH  hyperbolic sine in radians
 TANH  hyperbolic arctangent in radians
 Powers and logarithms

 EXP  exponential
 LOG  natural logarithm
 LOG10  common logarithm
 SQRT  square root
 Maximum/Minimum

 MAX  largest value (50 instead of 500 parameters allowed)
 MIN  smallest value (50 instead of 500 parameters allowed)
 Directly effecting sign of value

 ABS  absolute value
 SIGN  sign transfer
 Converting to a whole number

 INT  type conversion (value returned in REAL storage)
 AINT  truncation
 ANINT  nearest whole number
 NINT  nearest integer (value returned in REAL storage)
 Miscellaneous

 DIM  positive difference
 MOD  remainder of arg1/arg2
 REAL  type conversion (real)
 ABS
 ABS(arg) is a generic function that returns the absolute
value of its argument. The result of ABS(realarg) is
real.
 ACOS
 ACOS(arg) is a generic function that returns the arccosine
of its argument in radians. The result of ACOS(realarg) is
real.
 AINT
 AINT(arg) is a generic function that returns a whole number
after truncation of its argument. The result of AINT(realarg)
is real. The result is 0 if arg < 1. The result is the
largest integer with the same sign as arg that does not exceed
the magnitude of arg if arg >= 1.
 ANINT
 ANINT(arg) is a generic function that returns the nearest
whole number of its argument. The result of ANINT(realarg) is
real.
 ASIN
 ASIN(arg) is a generic function that returns the arcsine of
its argument in radians. The result of ASIN(realarg) is
real.
 ATAN
 ATAN(arg) is a generic function that returns the arctangent
of its argument in radians. The result of ATAN(realarg) is
real.
 ATAN2
 ATAN2(arg1, arg2) is a generic function that returns the
arctangent of its argument in radians. The result of
ATAN2(realarg1, realarg2) is real. The arguments must not
both be 0.
 COS
 COS(arg) is a generic function that returns the cosine of
its argument in radians. The result of COS(realarg) is
real.
 COSH
 COSH(arg) is a generic function that returns the hyperbolic
cosine of its argument. The result of COSH(realarg) is
real.
 DIM
 DIM(arg1, arg2) is a generic function that returns the
positive difference of its arguments. The result of
DIM(realarg1, realarg2) is real. The result is arg1arg2 if
arg1 > arg2, and the result is 0 if arg1 <= arg2.
 EXP
 EXP(arg) is a generic function that returns the exponential
of its argument. The result of EXP(realarg) is real.
 INT
 INT(arg) is a generic function that converts its argument
to integer type. The result of INT(realarg) is zero if
realarg < 1. The result is the largest integer with the
same sign as realarg that does not exceed the magnitude of
realarg if realarg >= 1.
 LOG
 LOG(arg) is a generic function that returns the natural
logarithm (base e) of its argument. The result of LOG(realarg)
is real.
 LOG10
 LOG10(arg) is a generic function that returns the common
logarithm (base 10) of its argument. The result of
LOG10(realarg) is real.
 MAX
 MAX(arg1, arg2 [,..., arg500]) is a generic function that
returns the largest value in its argument list. The result of
MAX(realarg1, realarg2 [,..., realarg500]) is real.
 MIN
 MIN(arg1, arg2 [,..., arg500]) is a generic function that
returns the smallest value in its argument list. is integer.
The result of MIN(realarg1, realarg2 [,..., realarg500]) is
real.
 MOD
 MOD(arg1, arg2) is a generic function that returns the
remainder of arg1 divided by arg2. The result of MOD(realarg1,
realarg2) is real. The result is arg1  (INT(arg1/arg2)*arg2).
If arg2 = 0, the result is undefined. Arg1 and arg2 must not
exceed 2**481.
 NINT
 NINT(arg) is a generic function that returns the integer
that is nearest to its argument. The result of NINT(realarg)
is integer. If arg >= 0, the result is (INT(arg+.5)). If arg
< 0, the result is (INT(arg.5)).
 REAL
 REAL(arg) is a generic function that performs type
conversion on its argument. The result of REAL(realarg) is
real.
 SIGN
 SIGN(arg1, arg2) is a generic function that returns a value
after a sign transfer. The result of SIGN(realarg1, realarg2)
is real. The result is arg1 if arg2 >= 0. The result is
arg1 if arg2 < 0.
 SIN
 SIN(arg) is a generic function that returns the sine of its
argument in radians. The result of SIN(realarg) is real.
 SINH
 SINH(arg) is a generic function that returns the hyperbolic
sine of its argument in radians. The result of SINH(realarg)
is real.
 SQRT
 SQRT(arg) is a generic function that returns the principal
square root of its argument. The result of SQRT(realarg) is
real.
 TAN
 TAN(arg) is a generic function that returns the tangent of
its argument in radians.
 TANH
 TANH(arg) is a generic function that returns the hyperbolic
tangent of its argument in radians.
MISCELLANEOUS COMMANDS

Displaying variable values: dump
 The current value and all defined variable names are
displayed via the dump command.
 Listing Available Functions:
funcs
 A display of all available functions can be obtained
when executing JUEXPR by entering the command 'funcs'. No
descriptions are provided.
Known bugs and limitations
 There is no typechecking to make sure that numeric values are not used where strings are required and viceversa. That is,
sin("hello there")
can cause problems.
 If you are looking for another type of parser, some useful keywords would be "Shunting yard algorithm" for converting infix notation to postfix notation; "bytecode interpreters" which can be used to rapidly repeat a series of operations on a vector;...
Programmer Notes
 Changing the number of variable names.
 Adding a new function directly to the calculator code.
 Points to ponder
 Using C or Fortran 90 it would be easier to make a version
that uses recursion and allocatable arrays to handle array
syntax and to run more efficiently by avoiding almost all
string manipulations
The calculator library is composed of the following routines:

JUEXPR is the main calculator
interface. All other routines are internal routines that
the user does not (generally) call directly or routines
that simplify making the most common forms of calls to
JUEXPR.
Internal routines:
 JUPARS crack out the parenthesis and pass each subexpression to JFUNS or JUARGS
 JUFUNS processes function call strings of form "fun(a1,a2,a3,...pi)"
 STUFFTOK stores a string being returned by a function into the string dictionary
 JUARGS separates a list of expressions that do not contain parenthesis and passes them to JUCALS
 JUCALS resolve a single expression into a value and restring it
 JUPOWS process power expressions "a**b" in expressions from JUCALS
 JUFACS process multiplies and divides in expressions from JUCALS
 JUATOR return a REAL value from a numeric string
 JURTOA return a numeric string from a REAL value
 JUSQES removes spaces and tokenizes strings before the calculator starts to crack the input expression.
 JUBOUS find where a new variable name should be stored or where an old name and it's associated value can be found
 JUADDR Add a new variable name and it's value to the dictionary.
 JUADDS add a new string variable and it's value to the string dictionary
 JUATOA given a string variable name return it's value
 JUFIND given a function name find the line JUFUNS() should go to
 STUFF directly store a value into calculator variable name table. This routine can be directly called when need warrants.
 STUFFA directly store a string into calculator variable name table This routine can be directly called when need warrants.
 BLOCKDATA JUINIT The BLOCKDATA defines the commons
used to hold the X,Y,$X $Y, ... arrays and the
dictionaries of variable names and string names and
their associated values.
 EXPRESSION returns the results of evaluating an expression
but in addition it displays error messages and other
information. It calls JUEXPR to evaluate the
expression.
The number of variable names permitted is
controlled by the line
parameter(ic=2345)
Change all occurrences in juexpr.f to increase this value.
The number of values in the X() and Y() arrays is similarly
controlled by
parameter(ixy=3333)
and the number of strings in the $X() and $Y() arrays is controlled by
parameter(ixy=50)
To add a new function
directly to the calculator go into JUFUNS() and increase the
number of branches in the large computed GOTO. For example, to
add the new functions NEW and $NEW make a change like this:
BEFORE:
if(i.gt.0.and.i.lt.35)then
goto (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
& 21,22,23,24,25,26,27,28,29,30,31,32,33,34) i
elseif(i.gt.0.and.i.lt.70)then
goto (35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,
& 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69) i34
endif
AFTER:
if(i.gt.0.and.i.lt.35)then
goto (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
& 21,22,23,24,25,26,27,28,29,30,31,32,33,34) i
elseif(i.gt.0.and.i.lt.70)then
goto (35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,
& 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69) i34
elseif(i.gt.0.and.i.lt.72)then
goto (70,71)i69
endif
Then go and add the new line numbers:
!====================================
70 continue ! NEW(value) function
! numeric parameters are in args(n)
! set fval and goto 5000 to set the returning numeric value
fval=new(args(1))
goto 5000 ! go to 5000 to return a numeric value
!====================================
71 continue ! $NEW(string) function
ii=args(1) ! assume argument 1 is a string, then this is
! pointer to where the string is
ctmp=values(ii) ! get the string
iend=valuer(ii) ! get the length of string
! set ctmp and goto 5002 to return a string value
ctmp=newchar(ctmp(:iend)) ! set returned value
iend=julen(ctmp) ! set significant length of returned value
! do something based on string
goto 5002 ! go to 5002 to return a string value
!====================================
Exactly how to extract and return character strings may seem
a little confusing. Remember there are over 70 examples in JUFUNS()
In function JUFIND() increase ICF by 2 and add new lines to
record the names of the functions, what line number to goto in
JUFUNCS(), and how many parameters the functions have. Use a 1
to suppress checking for a specific number of parameters.
do NOT alter the line that begins ixn(icf)=
BEFORE:
parameter(icf=71) ! the number of commands
:
:
! !function name !goto !number of parameters
ixn( 1)='!!!!!!!!!!!!!!!!!!!!0000000000111111111'
ixn( 2)='acos 1 1 '
ixn( 3)='asin 2 1 '
:
:
ixn( 68)='$x 67 1 ' !
ixn( 69)='egg 68 1 ' !
ixn( 70)='nog 69 1 ' !
ixn(icf)='~~~~~~~~~~~~~~~~~~~~0000000000111111111'
AFTER:
parameter(icf=73) ! the number of commands
:
:
! !function name !goto !number of parameters
ixn( 1)='!!!!!!!!!!!!!!!!!!!!0000000000111111111'
ixn( 2)='acos 1 1 '
ixn( 3)='asin 2 1 '
:
:
ixn( 68)='$x 67 1 ' !
ixn( 69)='egg 68 1 ' !
ixn( 70)='nog 69 1 ' !
ixn( 71)='new 70 1 ' !
ixn( 72)='$new 71 1 ' !
ixn(icf)='~~~~~~~~~~~~~~~~~~~~0000000000111111111'