.PAGE SIZE 58,80
.LEFT MARGIN 8
.RIGHT MARGIN 72
.SET PARAGRAPH 0,,
.ENABLE TOC
.AUTOPARAGRAPH
.LAYOUT 1,4
.TITLE My Calculator
.STYLE HEADER 4
.HEADERS ON
.FIGURE 12
.c80;MY CALCULATOR
.SKIP 6
.c80;16 December 1987
.SKIP 6
.c80;written by:
.SKIP 2
.C80;Thomas Wolfe
.C80;Jet Propulsion Laboratory
.C80;Mail Stop 510/202
.C80;4800 Oak Grove Drive
.C80;Pasadena, CA  91109
.C80;(818) 397-9280
.PAGE
.REQUIRE "CALC.RNT"
.PAGE
.HEADER LEVEL INTRODUCTION
My calculator program started as an exercise to learn
the run-time library routine LIB$TPARSE and the C language.
The functionality provided by my calculator is based on whim
and a vague idea of what I wanted to accomplish.

My calculator provides the capability of evaluating algebraic expression.
The results may be displayed on the terminal or stored as a symbol
and used in further calculations.

100 symbols may be defined with each symbol being up to
31 characters long.  Symbols may be used in calculations,
modified or there value displayed on the terminal.

Over twenty math functions are available including
pseudo random number generation.

Calculator commands can be stored in files and executed.
Command files allow the user to develop there own unique functions.
Command files can also prompt the user for input as well as
execute other command files.

Integer data may be entered in octal, decimal and hexadecimal;
floating-point data may be entered in decimal only.
.HEADER LEVEL THE DESIGN
My calculator program uses LIB$TPARSE to parse command.
Action routines are called when part of a command has
parsed correctly.  The calculator executes parts of commands
before the command is completely parsed.  This means two
separate types of errors are maintained.  Returned values
are used to determine if the command parsed correctly and the internal
flag ERROR__FLAG is used to pass execution error information.
For example, when a command is entered it
may parse correctly but the command may not be able to execute.
The returned value shows that the command parsed
correctly but the error flag indicated that the command could not
be executed. 

If I were to do it all over again I would probably parse the command
completely and then execute it.  However, the choice really depends
on the application.

Evaluation of algebraic expressions is done in two steps.
The expression is first converted to a reverse Polish expression
and then the expression is evaluated.  Appendix B describes the
algorithm used by my calculator.
.PAGE
.HEADER LEVEL COMMAND SUMMARY
This is a brief description of the calculator commands with examples.
.LITERAL

Assignment:   An algebraic expression is evaluated and the
              results is stored in a symbol.

              PI = 3.14159

              RATE = 4.00

Expression:   An algebraic expression is evaluated and the
              results displayed on the terminal.

              123 * (SIN(76.0/PI) + COS(76.0/PI))

              (RATE * 40) - 100.00

Show:         Display on the current value of a symbol.

              SHOW PI, RATE

              SHOW               (shows all defined symbols)

Display:      Change the calculator display characteristics.

              DISPLAY FILES,PRECISION=4

              DISPLAY NOFILES

Input:        Prompt the user for a numeric value.

              INPUT/FLOAT/DEFAULT=98.6 TEMP "ENTER TEMPERATURE"

              INPUT/INTEGER/DEFAULT=4.00 RATE "PAY RATE"

Command File: Execute command files (with a default file
              type of .CALC).

              @ABC, DEF, HIG, XYZ.CMDS

Exit:         Exit the currently executing command file or
              interactive session.

              EXIT

Comment:      Comment commands are not executed.

              ! THIS IS A COMMENT
.END LITERAL
.PAGE
.HEADER LEVEL MODES OF OPERATIONS

The calculator has two modes of operation, single
command and interactive mode.  When an error
occurs, the action taken by the calculator depends the mode.
.SET LEVEL 2
.HEADER LEVEL SINGLE COMMAND MODE
The single command mode assumes that the calculator program has
been defined as a VMS foreign command (see LOGICAL NAMES AND SYMBOLS
for further information).
In this mode, only the command entered on the DCL command line is
executed.  This allows the calculator to be part of DCL command files.

The single command that is entered on the DCL command line may
execute one or more command files containing many calculator commands.

If an error occurs execution of the
calculator is immediately terminated and control return to DCL.

For example:
.LITERAL

     $ CALC 123 + 456

     $ CALC @ABC
.END LITERAL
.HEADER LEVEL INTERACTIVE MODE
In interactive mode the calculator prompts the user for commands.
If an error occurs, the interactive command is terminated
and the user is prompted for the next command.
If an error occurs in a command file all executing command files are
terminated and the user is prompted for for the next command.

Interactive mode is entered automatically if the calculator
program is not defined as a VMS foreign command or if no
command is entered on the DCL command line.

For example:
.LITERAL

     $ CALC
     Calc: A = 98.6
     Calc: SHOW A
     A = 98.599998
     Calc: EXIT
.END LITERAL
.SET LEVEL 1
.PAGE
.HEADER LEVEL EXPRESSION COMMAND
.LITERAL
----------------------------------------------------------------
Format:
               <EXPRESSION>

----------------------------------------------------------------
Parameter:
               <EXPRESSION>
.END LITERAL
.LEFT MARGIN +15
Specifies the algebraic expression to be evaluated.  See ALGEBRAIC
EXPRESSIONS for more information.
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Description:
.END LITERAL
.LEFT MARGIN +15
When an algebraic expression is entered, it is
evaluated and the results displayed on the terminal.
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Examples:
               1 + 2 - 3
               log(ln(1.0))
               MAX(LN(10.0),LOG(10.0)) * 42/SIN(0.5)
.END LITERAL
.PAGE
.HEADER LEVEL ASSIGNMENT COMMAND
.LITERAL
----------------------------------------------------------------
Format:
               <SYMBOL>  =  <EXPRESSION>

----------------------------------------------------------------
Parameters:
               <SYMBOL>
.END LITERAL
.LEFT MARGIN +15
Specifies the name of the symbol to receive the results of the
evaluation of the expression.
.LEFT MARGIN -15
.LITERAL

               <EXPRESSION>
.END LITERAL
.LEFT MARGIN +15
Specifies the algebraic expression to be evaluated.  See ALGEBRAIC
EXPRESSIONS for more information.
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Description:
.END LITERAL
.LEFT MARGIN +15
When an assignment command is entered the expression is evaluated
and the results stored in the
specified symbol.
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Examples:
               PAY_RATE       = 5.50
               HOURS_WORKED   = 40.0
               GROSS_EARNINGS = PAY_RATE * HOURS_WORKED
               TAKE_HOME      = GROSS_EARNINGS * 0.50
.END LITERAL
.PAGE
.HEADER LEVEL SHOW COMMAND
.LITERAL
----------------------------------------------------------------
Format:
               SHOW [<SYMBOL> [[,]<SYMBOL>]]

----------------------------------------------------------------
Parameters:
               <SYMBOL>
.END LITERAL
.LEFT MARGIN +15
Specifies the name of the symbol to be displayed.
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Description:
.END LITERAL
.LEFT MARGIN +15
The SHOW command displays the value of one or more symbols
on the terminal.
If no symbols are specified all currently defined symbols
are displayed.  If the show command specifies a symbol
that is currently not defined a warning message is displayed.
This warning in not an error and will not cause the termination
of a command file or interactive command.

Parameters can be separate by commas or blanks.
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Examples:
               SHOW PAY_RATE, HOURS_WORKED, TAKE_HOME
               SHOW A B C
               SHOW
.END LITERAL
.PAGE
.HEADER LEVEL DISPLAY COMMAND
.LITERAL
----------------------------------------------------------------
Format:
               DISPLAY PARAMETER [[,]PARAMETER]

----------------------------------------------------------------
Parameters:
               FILE
.END LITERAL
.LEFT MARGIN +15
Specifies that commands read from command files will be displayed
on the terminal before execution.
An alternate form of the parameter is FILES.
.LEFT MARGIN -15
.LITERAL

               NOFILE (default)
.END LITERAL
.LEFT MARGIN +15
Specifies that commands read from command files will NOT be displayed
on the terminal before execution.
An alternate form of the parameter is NOFILES.
.LEFT MARGIN -15
.LITERAL

               PRECISION=[integer]
.END LITERAL
.LEFT MARGIN +15
Specifies the maximum number of fractional digits to be display
for floating-point values.
If no integer value is entered the default value of 6 is used.

The precision must be an integer between 1 and 16.
If a precision outside this range is entered a warning message
is displayed and the precision set to the default value.
This warning in not an error and will not cause the termination
of a command file or interactive command.
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Description:
.END LITERAL
.LEFT MARGIN +15
ThE DISPLAY command changes the display characteristics of the
calculator.
                            
Parameters can be separate by commas or blanks.
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Examples:
               DISPLAY NOFILE,PRECISION=4
               DISPLAY FILE
               DISPLAY PRECISION=28       (will use the default)
.END LITERAL
.PAGE
.HEADER LEVEL INPUT COMMAND
.LITERAL
----------------------------------------------------------------
Format:
               INPUT  [qualifiers]  <SYMBOL>  <PROMPT>

----------------------------------------------------------------
Parameters:
               <SYMBOL>
.END LITERAL
.LEFT MARGIN +15
The name of the symbol that recieves the data entered by the
user.
.LEFT MARGIN -15
.LITERAL

               <PROMPT>
.END LITERAL
.LEFT MARGIN +15
The prompt string is displayed on the terminal and the calculator
waits for a response from the user.  The prompt string may be up to 80
characters long and must be surrounded by quote marks (").
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Qualifier:
               /INTEGER (default)
.END LITERAL
.LEFT MARGIN +15
Specifies that the users input will be converted into a integer
value.  This is the default data type for user input if none is
specified on the input command.
.LEFT MARGIN -15
.LITERAL

               /FLOAT
.END LITERAL
.LEFT MARGIN +15
Specifies that the users input will be converted into a floating-point
value.
.LEFT MARGIN -15
.LITERAL

               /DEFAULT=numeric_value
.END LITERAL
.LEFT MARGIN +15
Specifies that if the user enters nothing (a carriage return) the
symbol will receive the default value (including the default data type).
.LEFT MARGIN -15
.LITERAL

----------------------------------------------------------------
Examples:      
               INPUT/FLOAT/DEFAULT=99  AGE  "ENTER YOUR AGE:"

.END LITERAL
In the example, the command prompts the user for input and stores
it in the symbol AGE.
If the user enters a carriage return the default
value 99 is stored in the symbol AGE.

The data type of AGE depends on
what the user enters.  The symbol AGE will be forced to a
floating-point value by the /FLOAT qualifier unless the default is chosen.
The default value forces AGE to become the integer value 99.
.PAGE
.HEADER LEVEL EXIT COMMAND
.LITERAL
----------------------------------------------------------------
Format:
               EXIT

----------------------------------------------------------------
Description:
.END LITERAL
.LEFT MARGIN +15
The EXIT command causes a command file or an interactive
session to terminate.
.LEFT MARGIN -15
.HEADER LEVEL COMMENT COMMAND
.LITERAL
----------------------------------------------------------------
Format:
               ! <comment>

----------------------------------------------------------------
Description:
.END LITERAL
.LEFT MARGIN +15
Comments are not true commands and are never executed.
The are provided to help document command files.
The first non-blank character of a comment must be an "!".
.LEFT MARGIN -15
.HEADER LEVEL DEBUG COMMAND
.LITERAL
----------------------------------------------------------------
Format:
               DEBUG

----------------------------------------------------------------
Description:
.END LITERAL
.LEFT MARGIN +15
Toggles on and off the display of calculator debugging information.
This command will eventually go away.
.LEFT MARGIN -15
.PAGE
.HEADER LEVEL ALGEBRAIC EXPRESSIONS
An algebraic expression is a sequence of arithmetic operators,
numeric values, symbols and functions.
.SET LEVEL 2
.HEADER LEVEL DATA TYPES
The calculator maintains internal numeric data in integer
and floating-point form.

Integer values are stored in 32 bit
and can represent integers in the range -2,147,483,648 to
2,147,483,647.

Floating-point values are store 64 bits and can represent
values in the range 0.29E-38 to 1.7E38
with approximately 16 decimal digits of precision.
.HEADER LEVEL DATA TYPE CONVERSION
Functions automatically
convert arguments to the correct data type(s)
(which is usually floating-point) for there needs.

Operators do not change the data type of operands unless
integer and floating__point are mixed together.
When mixed together integers are converted floating-point
before an operation is performed.  

Conversion to a specific data type is accomplished with the functions
FLT and INT.
.HEADER LEVEL CONSTANTS
Integer constants may be entered in octal, decimal and
hexadecimal form. Octal constants must be preceeded
by "%o" or "%O".  Hexadecimal constants must be proceeded
by "%x" or "%X".  Decimal constants may be preceeded by
"%d" or "%D" but it is not required.  For example:
.LITERAL

          %o7777               octal constant

          %xFFFF               hexadecimal constant

          %d12345              decimal constant

          12345                decimal constant

.END LITERAL
Floating-point constants can only be entered in decimal form.
It must have a decimal point and be preceeded by at least one
decimal digit (which may be zero).  It may also be followed
by a signed exponent preceeded by the letter "e" or "E".  For example:
.LITERAL

          1234.5               decimal constant

          0.0001               decimal constant    

          1232.5E10            decimal constant

          0.0001e-10           decimal constant

.END LITERAL
.HEADER LEVEL SYMBOLS
Symbols are named data structures containing numeric data.
The symbol name is a string of one or more alphanumeric characters,
in addition to the dollar sign ($) and the underscore (__).
Symbols must start with an uppercase or lowercase A thru Z to
distinguish them from numeric constants.  Symbols may be of any length
but only the first 31 characters will be used.

Symbols may be used in algebraic expressions any were a
numeric value is required.  When the expression is evaluated
the numeric value of the symbol is substituted in the
calculation.  The data type and value of a symbol
may be modified with the ASSIGNMENT and INPUT commands.
.HEADER LEVEL ARITHMETIC OPERATORS
Symbols and numeric values may be used with operators
to create more complex expressions.  The operators are:
.TEST PAGE 9
.LITERAL

         Operator     Example     Results

         - [unary]      -a        negative of a
         + [unary]      +a        no change in a
         - [binary]     a-b       a plus b
         + [binary]     a+b       a minus b
         * [binary]     a*b       a times b
         / [binary]     a/b       a divided by b
.END LITERAL
.HEADER LEVEL OPERATOR PRECEDENCE
The following is the precedence used by my calculator to
evaluates expressions.  Operators with the highest
precedence appear a the top of the list; those with the lowest
appear at the bottom.
.TEST PAGE 8
.LITERAL

         Category     Operator    Associativity

         Primary        ( )       left to right
         Unary          + -       right to left
         Unary        function    right to left
         Binary         * /       left to right
         Binary         + -       left to right
.END LITERAL
.HEADER LEVEL MATH FUNCTIONS
A variety of math function are are available in the calculator.
Math functions may be used anywhere in an algebraic expression that
a symbol or numeric value is used.  The form of a functions
is:
.TEST PAGE 3
.LITERAL

        F(A1,A2,...An)

.END LITERAL
Where F is the function name and each A is a function argument.
The number of arguments is function dependent.
Arguments are algebraic expressions and may be as complex
as needed.
.SET LEVEL 3
.TEST PAGE 9
.HEADER LEVEL ABS
The ABS function returns the absolute value of an integer or
floating-point value.
.LITERAL

     Format:        ABS(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL ACOS
The ACOS function returns a value in the range zero to pi, which
is the arc cosine of its radian argument.
.LITERAL

     Format:        ACOS(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL ASIN
The ASIN function returns a value in the range -pi/2 to pi/2, which
is the arc sine of its radian argument.
.LITERAL

     Format:        ASIN(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL ATAN
The ATAN function returns a value in the range -pi/2 to pi/2, which
is the arc tangent of its radian argument.
.LITERAL

     Format:        ATAN(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL CEILING
The CEILING function returns a floating-point value which is the smallest
integer which is greater than or equal to its argument.
.LITERAL

     Format:        CEILING(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL COS
The COS function returns the cosine of its radian argument.
.LITERAL

     Format:        COS(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL COSH
The COSH function returns the hyperbolic cosine of its radian argument.
.LITERAL

     Format:        COSH(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL EXP
The EXP function returns the base e raised to the power of the argument.
.LITERAL

     Format:        EXP(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL FLT
The FLT function converts its argument to a floating-point value.
.LITERAL

     Format:        FLT(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL FLOOR
The FLOOR function returns a floating-point value which is the largest
integer which is less than or equal to its argument.
.LITERAL

     Format:        FLOOR(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL INT
The INT function converts its argument to an integer value.
.LITERAL

     Format:        INT(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL LN
The LN function returns the natural logarithm of its argument
which must be a positive and non-zero value.
.LITERAL

     Format:        LN(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL LOG
The LOG function returns the base 10 logarithm of its argument
which must be a positive and non-zero value.
.LITERAL

     Format:        LOG(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL POW
The POW function return the first argument raised to the power of the
second argument.
.LITERAL

     Format:        POW(BASE,EXP)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL RAND
The RAND function uses a multiplicative congruential random number
generator with a repeat factor (period) of 2 to the 32 power.
The function must have a legal argument even though it is not used.
See the SEED function for further information.
.LITERAL

     Format:        RAND(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL MAX
The MAX function return the maximum of two arguments.
.LITERAL

     Format:        MAX(VALUE,VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL MIN
The MIN function return the minimum of two arguments.
.LITERAL

     Format:        MIN(VALUE,VALUE)
.END LITERAL
.TEST PAGE 10
.HEADER LEVEL MOD
The MOD function return an integer which is the remainder
of the first integer argument
divided by the second integer argument.
.LITERAL

     Format:        MOD(VALUE,VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL SEED
The SEED function returns a random number exactly like the RAND function.
The random number generator is reinitialized by calling SEED with the
argument 1, or it can be set to a specific point by calling SEED with
any number.
.LITERAL

     Format:        SEED(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL SIN
The SIN function returns the sine of the radian argument.
.LITERAL

     Format:        SIN(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL SINH
The SINH function returns the hyperbolic sine of the radian argument.
.LITERAL

     Format:        SINH(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL SQRT
The SQRT function returns the square root of its argument
which may not be a negative value.
.LITERAL

     Format:        SQRT(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL TAN
The TAN function returns the tangent of the radian argument.
.LITERAL

     Format:        TAN(VALUE)
.END LITERAL
.TEST PAGE 9
.HEADER LEVEL TANH
The TANH function returns the hyperbolic tangent of the radian argument.
.LITERAL

     Format:        TANH(VALUE)
.END LITERAL
.SET LEVEL 2
.SET LEVEL 1
.HEADER LEVEL POSSIBLE FUTURE IMPROVEMENTS
Modify the actual calculator to be a callable interface so that
it can be incorporated into other programs.  For example, my editor.

Rewrite the calculator in MACRO.

Add more math functions.

Expand the data types from integer and floating-point to
include a greater number of types such as Q floating-point,
complex, etc.

Add special functions, operators, etc. for special data types such 
coordinate pairs, etc.

Add the capability to store calculator results in a VMS symbol
and/or logical name.  This would increase the usefulness of the
calculator in DCL command files.

Not all errors are detected (underflow and overflow).
Make sure that all errors are detected and reported.

Improve the code.  It is somewhat klugy (to say the least).
.PAGE
.HEADER LEVEL LOGICAL NAMES AND SYMBOLS
The following logical name defines the calculator help library.
.LITERAL

  $ DEFINE    CALCULATOR_HELP     DISK:[DIR]CALCULATOR_HELP.HLB

.END LITERAL
The following symbol definition is needed if the calculator
is to be a VMS foreign command.
.LITERAL

  $ CALC  :==  $DISK:[DIR]CALC.EXE

.END LITERAL
.HEADER LEVEL BUILD THE CALCULATOR FROM SOURCE CODE
.LITERAL

    $ LIBRARY/CREATE/HELP CALC_HELP CALC_HELP
    $!
    $ MACRO CALC_TABLE.MAR
    $ CC    CALC.C
    $ CC    CALC_ASSIGNMENT.C
    $ CC    CALC_COMMAND_FILE.C
    $ CC    CALC_DISPLAY.C
    $ CC    CALC_EVALUATION.C
    $ CC    CALC_EXIT.C
    $ CC    CALC_EXPRESSION.C
    $ CC    CALC_FUNCTIONS.C
    $ CC    CALC_HELP.C
    $ CC    CALC_INPUT.C
    $ CC    CALC_SHOW.C
    $ CC    CALC_SYMBOLS.C
    $!
    $ LINK  CALC,              -
            CALC_ASSIGNMENT,   -
            CALC_COMMAND_FILE, -
            CALC_DISPLAY,      -
            CALC_EVALUATION,   -
            CALC_EXIT,         -
            CALC_EXPRESSION,   -
            CALC_FUNCTIONS,    -
            CALC_HELP,         -
            CALC_INPUT,        -
            CALC_SHOW,         -
            CALC_SYMBOLS,      -
            CALC_TABLE
.END LITERAL
.PAGE
.APPENDIX CALCULATOR SYNTAX DIAGRAMS
.REQUIRE "SYNTAX.RNO"
.APPENDIX EXPRESSION EVALUATION ALGORITHM
.REQUIRE "ALGORITHM.RNO"
