[GPF Home Page]
NAME
M_calculator_programmer_notes(5f) - [M_calculator] Programmer notes for module M_calculator (LICENSE:PD)
SYNOPSIS

Internal routines:

  • parens_ crack out the parenthesis and pass each subexpression to JFUNS or args_
  • funcs_ processes function call strings of form "fun(a1,a2,a3,...pi)"
  • stufftok_ stores a string being returned by a function into the string dictionary
  • args_ separates a list of expressions that do not contain parenthesis and passes them to expressions_
  • expressions_ resolve a single expression into a value and restring it
  • pows_ process power expressions "a**b" in expressions from expressions_
  • factors_ process multiplies and divides in expressions from expressions_
  • squeeze_ removes spaces and tokenizes strings before the calculator starts to crack the input expression.
  • a_to_a_ given a string variable name return its value
  • JUFIND given a function name find the line funcs_() should go to

public convenience routines in M_calculator(3f) module

  • EXPRESSION returns the results of evaluating an expression but in addition it displays error messages and other information. It calls CALCULATOR(3f) to evaluate the expression.
  • STRGAR2 returns an array of numeric values from a list of expressions by separating the expressions and calling expression.
  • INUM0 returns an integer value from an expression by calling expression.
  • RNUM0 is a function that returns a REAL value from an expression by calling expression.
  • SNUM0 is a function that returns a CHARACTER value from an expression by calling expression.

Programmer Notes

  • Changing the number of variable names.
  • Adding a new function directly to the calculator code.
  • Adding a procedure to customize an application by allowing for user-defined functions
  • Points to ponder
    • added substitute_subroutine(3f) and substitute_c(3f) to make it easier for people to use the calculator library. Programmers could override with their own version at load time.
    • 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
    • User-defined arrays, handling of complex numbers, and user-defined functions would all be useful additional features.
    • The parser is not intended to be used to generate a large number as in the order of 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, HP-UX, IRIX64, AIX, Solaris, ...
  • Known bugs and limitations
    • There is no type-checking to make sure that numeric values are not used where strings are required and vice-versa. That is,
      
              sin("hello there")
              
      can cause problems.

Changing number of variable names

The number of values in the X() and Y() arrays is controlled by


      parameter(ixy_calc=55555)

and the number of strings in the $X() and $Y() arrays is controlled by


      parameter(ixyc_calc=50)

Warning: If these parameter values are changed in size, any user-written substitute_subroutine(3f) routines must change to reflect the changes. Make a new library version and document the new size if your copy is being used by others or people reloading from your library could encounter problems.

Adding a new function directly to the calculator

To add a new function directly to the calculator go into funcs_() and add a new case to the SELECT. See the many existing case statements for examples on how to pass and return arguments.


    !=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    case("NEW")
          ! 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
    !=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    case("$NEW")
          ! $NEW(string) function

          ! GETTING A STRING ARGUMENT
          ii=args(1)   ! assume argument 1 is a string, then this is
                       ! pointer to where the string is
          ctmp=values(ii) ! get the string argument
          iend=values_len(ii) ! get the length of string

          ! RETURNING A STRING
          ctmp=newchar(ctmp(:iend)) ! set returned value
          iend=len_trim(ctmp) ! set significant length of returned value
          ! do something based on string
          goto 5002   ! set ctmp and goto 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 funcs_().


Adding a new function for a particular application

A special routine can be added to allow add your own functions for a particular program that you don't want in the main CALCULATOR(3f) utility code. It will be called when any function name is not recognized and the expression 'ownmode(1)' has previously been entered into the calculator. The example program shows a fully functional substitute_subroutine(3f) routine that should make it clear how to add your own functions. Here is a session using the example program:

At first any unknown function name causes an error in funcs_().


    aa(10)
    error===>*funcs_* function not found: aa

But if the special function OWNMODE() is called with its first parameter set to 1 then unknown function calls are now passed to the substitute_subroutine() routine if it has been defined.


    ownmode(1)
    1.                   = ownmode(1)

    aa(10)
     *juown1* unknown function aa
     function name length is..  2
     number of arguments .....  1
       1 VALUE=   10.0000000000000
    0.                   = aa(10)

By default substitute_subroutine(3f) echoes the name of the unknown function, how many characters long the function name is, how many parameters were on the function call, and an array of argument values. Note that a second array and a common block can be used to pass string variables too.


    $XX="This is a string"
    This is a string

    aa(10,"hello there",40/3,$XX)
     *juown1* unknown function aa
     function name length is..  2
     number of arguments .....  4
       1 VALUE=   10.0000000000000
       2 STRING=hello there
       3 VALUE=    13.333333333333
       4 STRING=This is a string
    0.                   = aa(10,"hello there",40/3,$XX)

Hopefully, the example code makes this clear.

So to add your own custom functions just construct branches in substitute_subroutine(3f) based on your new function names!