                          PCALC

Overview

PCALC is arrayless, stackless interpretative programming language based on
the formula processor CALC and integrated with the financial processor STAR.
It also has a database maniupulation facility "pc_dbm".

The PCALC language consists of a series of instructions (called "lines" or
"statements") that are stored in ordinary text files, called "PCALC files".
Each line either begins with a PCALC directive followed by parameters or is
simply a CALC formula. Execution begins at line 1, at a "label" statement or
at an "entry" statement or at a "module" statement.

Evoking PCALC.EXE

PCALC.EXE prompts the user for the program starting address, which is at a
minimum a PCALC file that is to be executed. For instance,

              C:\PCALC.PCL

would be a starting address if there were a text file C:\PCALC.PCL
containing the required PCALC instructions. By default, the starting
module would be the first module in the file.  The user may also specify the
starting module (or entry) and label contained within that file, if desired.
For instance,

              C:\PCALC.PCL\MODULE1

would begin execution in the file PCALC.PCL at module MODULE1. If a particular
location in MODULE1 were desired, such as "LABEL1", enter

              C:\PCALC.PCL\MODULE1+LABEL1

In order to call the module MODULE1 at entry point ENTRY1 (allowing for its own
calling stack) and label LABEL1, enter

              C:\PCALC.PCL\ENTRY1+LABEL1


In the event of ambiguity in the starting address, if the starting address
(less the label) is a file, then it will be used as the file with the
first module as the starting module. Otherwise, the string immediately
preceeding the last "\" will be considered to be the file, the
remainder being the module and label. Module and entry names may not contain
"\". File names should contain "." to avoid ambiguity. For instance

              C:\STAR\PCALC

would be interpretated as the file C:\STAR\PCALC.PCL with no module
if this file existed. Otherwise the file would be C:\STAR.PCL with
module PCALC.

              C:\STAR\PCALC.PCL

would be interpreted as the file C:\STAR\PCALC.PCL with no module specified.

               C:\PCALC.PCL+LABEL1

would be a valid address if C:\PCALC.PCL existed and LABEL1 were a label
in the first module, which would be the starting module. Labels only have
meaning within the context of a module.

The switches "/MAC", "/LST" and "/OBJ" can be added to the end of the starting
address, causing PCALC to print out useful information for debuging.
The switch "/MAC" causes a listing of the executable program as macro
instructions and a list of all executed instructions in order of execution.
"/LST" causes a listing of the executable program as macro instructions.
One should exercise caution when using the "/MAC" switch. If the program
is extensive or has a run-away loop and you are using re-direction to
capture the output file, this file may become very large. In this case,
use "/OBJ" to print out only a listing of the executable program as macro
instructions, without execution.

Evoking PCALC inside the STAR processor

See the documentation for STAR for the flag "=STAR.PCALC" and related
flags. These flags use as a parameter the program starting address with
the same conventions as PCALC.EXE.

PCALC Statements

The COMMENT symbol

       "!" is the comment symbol. Any text to the right of "!" outside of
       double quotes (") is ignored.

The MODULE statement

       module <module_name> [( dummy_arg1 , ... , dummy_argN )]
             This defines the current module name. Each module must have a name
             and thus must begin with this statement. The dummy_args
             are non-executable and consequently ignored. They exist
             only for documentation purposes. It is the calling statement
             that defines the calling stack of a module.

             Examples:

                         module module1
                         module module2 ( xxx = input )

       Each module must terminate with an END statement, described below.

The ENTRY statement

       entry <entry_name> [( dummy_arg1 , ... , dummy_argN )]
             The syntax for an "entry" statement is identical to that for a
             "module" statement, allowing for a separate calling stack with
             the same local variable space as the module containing it.

The GLOBAL statement
       CALC variables can either be local to the module that contains them,
       allowing for the same variable name to be used as different variables
       in different modules or they can be unique to the entire program, known
       as "global".

       global <var1> [, <var2> , ... , <varN> ]
             This defines the CALC variables <var1> thru <varN> to be
             visible to all modules, meaning all modules may access
             and alter their values. However, this statement must be
             executed previous to accessing the variables.

             By default, CALC variables are local to the module in which
             they appear. Local variables have their value dependent on
             the module of reference. Global variables have a single value
             across all modules. Module names are automatically entered as
             global variables, facilitating the return of values from called
             modules. See the CALL statement below for more information.

The PARAMETER statements

       parameter maxexe <value>
             This defines the maximum number of instructions that may be
             executed. It is used to prevent run-away processing. The default
             is 1,000,000. Setting this to 0 will disable it. Example:

                         parameter maxexe 10000

       parameter stardef <default file>
            This provides a file path to access for the PCALC function
            "pc_star(arg1, arg2, ...)", as described below, when no file path
            is specified for an argument "arg". This statement may be omitted
            if PCALC is being evoked by the STAR file processor using one of
            the "=star.pcalc..." commands, as described in the STAR
            documentation. In this case, the default path for "arg"
            will lead to the executing program STAR's memory, giving the
            same result if "star.pcalc.out" were specified for <default file>.
            Using the file path in the "arg" to the same file STAR is
            processing will also give the same result as omitting both the path
            entirely and the stardef parameter.

            Example:

                         parameter stardef star.act

       parameter ignore <directive>
            If <directive> = "nofind" then star variables that are not found
            via the "pc_star" function are defined to be zero with no error
            message.

            If <directive> = "find" then star variables that are not found
            via the "pc_star" function create a fatal error condition. This
            is the default setting.

            When this parameter statement is executed, the CALC variable
            PC_IGNORE_STS is set to zero. When a star variable is not found,
            the variable will be set to 1.

            Example:

                       parameter ignore nofind
                       sum=sum+pc_star(*xxx)
                       if(eq(pc_ignore_sts,0)) then
                           print "*xxx was found"
                       else
                           print "*xxx was not found"
                       endif


The PCALC functions
       PCALC functions are used to translate STAR, CALC or PCALC variables to
       text format. They then can be used as input to expressions or strings
       that they themselves are processed by CALC or PCALC.

       pc_star( [file]<variable> [,format] )
            This determines the value of a STAR <variable> and formats it
            as a text string. [file] is an optional file name for the location
            of <variable>. If [file] is omitted, the parameter statement
            "stardef" provides a path to <variable> or if STAR is active,
            it will provide the path to memory.

            Examples: pc_star(*car), pc_star(c:\star\star.act\*car,F10.2)

            <variable> can be one of the following:
                 *<star account>     A star account. Example: "*car".
                 &<budget account>   A budget account. Example: "&misc".

                                     Budget accounts can have the following
                                     extensions:
                                     Case "=STAR.EARN.BUDGET Y"
                                            .net (default)
                                            .revenue
                                            .expense
                                            .$cur
                                     Case "=STAR.EARN.BUDGET N"
                                            .used (default)
                                            .target
                                            .left
                                            .$cur
                                            .etgt
                                     Example: &misc.used

                 #                   The main account balance
                 #prev               The initial main account balance
                 #staraccounts       The sum of all star accounts.
                 #balance            The current balance.
                 #audit              The audit balance.
                 #ebal               The "ebal" amount
                 #eaud               The "eaud" amount
                 #abal               The "abal" amount
                 #used               The "&used" amount.
                 #left               The "&left" amount.
                 #$cur               The "&$cur" amount.
                 #etgt               The "&etgt" amount.
                 #dpay               The "&dpay" amount.
                 #premonbal          The "premonbal" amount.
                 #premonaud          The "premonaud" amount.
                 #tottgt             The "&tottgt" amount.
                 #over               The "&over" amount.
                 #net                "&revenue" less "&expense".
                 #revenue            The "&revenue" amount.
                 #expense            The "&expense" amount.
                 #bal_adj.<account>  The autopay adjustment of <account>.
                 #futurbal           The final "=star.futurbal" amount.

            See STAR.TXT for further explanations of these terms.

            [,format] can be one of the following:
                 ",Ixx"    where "xx" is the length of the output string,
                           formatted as an integer. If "xx" is omitted the
                           length is the smallest possible. Examples:"I10",
                           "I".
                 ",Fxx.yy" where "xx" is the length of the output string,
                           formatted as a fixed decimal with "yy" the number
                           of decimal positions. If "xx" is omitted the
                           length is the smallest possible. "yy" defaults to 2.
                           Examples: "F10.2", "F.2", "F10", "F".
                 ",Exx.yy" where "xx" is the length of the output string,
                           formatted as a floating point decimal, with "yy"
                           the length of the mantissa. If "xx" is omitted,
                           the smallest possible length is used. "yy" defaults
                           to 8. Examples: "E14.8", "E14","E.8", "E".

       pc_calc(<expression>[,format])
            This determines the value of a CALC <expression> and formats it
            as a text string in the same manner as for "pc_star" above.
            <expression> can contain references to "pc_star" but not to
            "pc_calc". Examples: pc_calc(x+y), pc_calc(x+pc_star(*car),F10.2).
            All residual variables in <expression> must be CALC variables.
            Any STAR variables must be translated with the use of "pc_star".

       pc_line(<loop>)
            This is used in conjunction with the PCALC statements "beginline"
            and "nextline", described below. <loop> is the construct name.
            "pc_line" returns the PCALC line specified by <loop>. See below
            for more.

       pc_date(<offset>[,<format>])
            This returns the date in format YYMMDD as specified by <offset>,
            which may be "today", "yesterday", "tomorrow" or a number offset
            from today's date. <format> can be "YYYYMMDD", "YYMMDD", "YYYY,
            "YY", "MM", or "DD", representing 8 digit dates, 6 digit dates,
            4 digit year, 2 digit year, month or day. Examples:

            "pc_date(0)"            = today's date in a 6 digit format (def)
            "pc_date(today)"        = same
            "pc_date(today,YYMMDD)" = today's date in a 6 digit format.
            "pc_date(-1)"           = yesterday's date in a 6 digit format.
            "pc_date(yesterday)"    = same
            "pc_date(yesterday,DD)" = yesterday as a day of the month
            "pc_date(1)"            = tomorrow's date in a 6 digit format.
            "pc_date(tomorrow)"     = same

The PRINT statement

       print "<message>"
            This will output to stdout <message>. The PCALC functions
            contained in <message> will be translated before output.

The SPAWN statement

       spawn <command>
            This will pass <command> to the shell processor.
            A path must be defined to %systemroot%\system32.
            %systemroot%\system32\autoexec.nt has all initial settings.

The SPAWNQ statement

       spawnq <command>
            This performs the same as "spawn", however in "quiet" mode,
            (no echo of the command). A path must be defined to
            %systemroot%\system32.

The SPAWNC statement

       spawnc <day> <control_file> <control_status> <quiet_mode> <command>
            This will spawn <command> to the shell processor if
            <control_file> has been last written on or after <day>.
            A path must be defined to %systemroot%\system32.

            The definition of the parameters is as follows:

            If <day> is a 1 digit integer, it represents a day of the
            week. The range is 1-7, with 1 representing Monday.
            0 represents today.

            If <day> is a 2 digit integer, it represents a day of the current
            month. The range is 01-31, with 31 representing the last day
            of the month for all months.

            If <day> is a 3 digit integer, it represents a month and the
            number of months between months in the cycle. For example,
            quarterly starting with January would be 013 and semi-annually
            would be 016.

            If <day> is a 4 digit integer, it represents a month and a day
            of the current year. The range is 0101 - 1231, with xx31
            representing the last day of the month for all months.

            If <day> is a 6 or 8 digit integer, it represents a date
            in the YYMMDD format.

            If <day> is a 9 or 10 digit integer, it represents a date
            in the YYMMDD format and the number of days in the cycle.
            For example, 060204014 would be every 2 weeks (14 days)
            starting with February 4, 2006. 20060204014 could also be used.

            <control_file> is a file which is used to check if this
            command has already been executed for the day condition.

            <control_status> is either 1 or 0, indicating whether or not
            the <control_file> is to be maintained by the spawnc
            proceedure. If it is, the <control_file> will be deleted
            and re-created by the proceedure.

            <quiet_mode> is either 1 or 0, indicating whether or not
            the spawned command is to be in quiet mode (no echo of
            command).

            <command> is the command to be executed, if the condition
            for <day> is met.

The NEWFILE statement

       newfile <file>
            This is used in conjunction with the "write" statement. If
            <file> has already been opened with the "newfile" command or
            written to with the "write" command, it will cause all writing
            to append to the existing file. Otherwise it will rewind <file>,
            causing the previously existing data to be lost once the file is
            written to or if <file> is "star.pcalc.out". If <file> is not
            yet open, it will open <file> in a rewinded state, deleting any
            previously existing data if <file> is "star.pcalc.out".

            If "newfile" is not specified before writing to a file, and that
            file already existed before writing, that file will be appended
            to (default).

The WRITE statement

       write [<file>] "<expression>"
            This will write <expression> to <file>, appending to
            an existing file if "newfile" was not previously given.
            <expression> is any text string with the PCALC functions
            translated. If <file> is omitted, "star.pcalc.out" will be
            used by default.

The CLOSE statement

       close <file>
            This will close the <file> and announce such.

The CAL$FILE statement

       cal$file = <file>
            This will send the contents of <file> to the CALC processor.
            For instance, if CALC formulae need to be used, they could be
            stored in <file> and accessed by CALC using this statement.
            Also, the WRITE or SPAWN statement could be used to pass values
            to an external program, which then processes those values,
            writes the results to <file> and returns them to PCALC using
            this statement. This is an intrinsic CALC command, but is
            documented here for convenience.

The IF statement

       if ( <expression> ) <statement>
            This will evaluate the CALC <expression>, translating any
            PCALC functions first. If <expression> is zero ("false")
            <statement> will not be executed. Otherwise, non-zero or "true",
            <statement> will be executed. CALC has special funtions to
            evaluate the truth or falsehood of numerical/string comparisons,
            such as "eq(x,y)", "ne(x,y)" etc. Using these operators, whose
            values are restricted to 0 and 1, multiplication becomes equivalent
            to logical AND and addition equivalent to logical OR. For
            instance "eq(x,y)+ne(a,b)" is equivalent to "(x EQUAL y) OR
            (a NOT EQUAL b)" and "eq(x,y)*ne(a,b)" is equivalent to
            (x EQUAL y) AND (a NOT EQUAL b)". More simply, "eq(x,y)" is
            equivalent to "x EQUAL y". An example:

                      if(eq(x,y)) print "x equals y"

            An example of string comparison:

                      if(eq("pc_line(loop1)","abc")) print "at line = "abc" in loop1"

            Enter the command "help" at the CALC.EXE prompt for further details
            concerning CALC logical operators.

       if ( <expression> ) then
            This transfers control to the next statement if <expression>
            is "true", i.e. non-zero. It must be terminated by and "endif"
            statement, described below. If can be used in conjunction with
            the "else if" and "else" statements also described below. If
            <expression> is "false", i.e. zero, control is transfered
            to the next "else if", "else" statement or the next statement
            after "endif", depending on which comes first.

       else if ( <expression> ) then
            This transfers control to the next statement if "true", i.e.
            non-zero. It behaves similiarly to the "if" statement. It
            must be part of an "if" - "endif" chain of statements.

       else ( <expression> ) then
            This uncoditionally transfers control to the next statement.
            It must be part of an "if" - "endif" chain of statements and
            must come after any "else if" statements in the chain.

       endif
            This terminates an "if" - "endif" chain. Unless otherwise
            directed by a "goto" statement, all processing that executes
            an "if" statement must eventually execute the next statement
            after the terminating "endif".

            Example:

            if ( eq(x,y) ) then
                print "x equals y"
                print "a was not tested against b"
            else if ( eq(a,b) ) then
               print "x does not equal y but a does equal b"
            else
                print "x does not equal y and a does not equal b"
            endif
            print "if-endif chain completed"

The STAR statement

       star <expression>
            This evaluates all PCALC functions in <expression> then
            passes the resulting string to STAR for processing. It
            only has an effect when executing inside of STAR using
            the =STAR.PCALC... flags. PCALC.EXE will issue an error
            message if it encounters this statement, but it will
            continue processing, as PCALC.EXE is useful as a testing tool
            for PCALC code that will eventually be run inside of STAR.

The LIST statement

       list <wildcard character> <expression>
            This is to be used in conjunction the "pc_star" function
            to create a list of either star accounts (leading "*") or
            budget accounts (leading "&"). PCALC is an arrayless language.
            However, the LIST statement allows for lists that resemble
            arrays. <wildcard character> is a terminating wildcard
            character for the argument in the "pc_star" function. The
            LIST statement will substitute for each matching argument,
            creating a list of instructions, all identical with the
            exception of the substitutions. For instance, suppose
            you had defined a list of 3 pseudo star accounts "~STOCK_IBM",
            "~STOCK_GE" and "~STOCK_ATT" which you wished to sum. You could
            arrive at this sum using

            sum = pc_star(*~stock_ibm)
            sum = sum + pc_star(*~stock_ge)
            sum = sum + pc_star(*~stock_att)

            However, if the stocks you owned were subject to change, you
            would have to re-code the above instructions each time there
            was a change. In order to avoid that, use

            sum=0
            list % sum = sum + pc_star(*~stock_%)

            in which case, PCALC will produce the necessary instructions.

            Several cautions are in order.

            1. Since this is a pre-execution proceedure, the default STAR file
            is not available via the parameter statement "stardef".
            Consequently, if this code were to be executed outside of the STAR
            processor, you would have to code the complete address of the star
            account, such as pc_star(c:\star\star.act\*~stock_%). Inside the
            STAR processor, the default address "star.pcalc.out" would be used.
            See the STAR documentation for more information about this.

            2. If multiple wildcard expressions are present, they will be filled
            in a multiplexed manner. For instance, if there are 3 possible
            choices for the first wildcard and 4 for the second, the result
            will be 12 = 3 x 4 substitutions. This may not produce the
            result you wish. For example, supposed you wished to add
            all your stock accounts (*stock_%) and all your mutual fund
            accounts (*mutual_%). The statement

            list % sum = sum + pc_star(*~stock_%) + pc_star(*~mutual_%)

            would compute the sum = s * M + m * S, where there are s stocks
            summing to S and m mutual funds summing to M. The correct
            way to code this would be

            list % sum = sum + pc_star(*~stock_%)
            list % sum = sum + pc_star(*~mutual_%)

            3. LIST is a pre-execution statement. The actual values
            used for the accounts will be those at the time of execution.

The LABEL statement

       label <label>
            This is used in conjunction with the "program starting address"
            parameter of the =STAR.PCALC... flags, the PCALC.EXE prompt or
            the "call" and "goto" statements. It is used for transfer of
            control and has no executable effect other than that. "Label"
            statements do not allow for a calling stack. Use the "entry"
            statement when calling a module with a calling stack and the
            starting point is other than the beginning of the module.

The CALL statement

       call <[file]module[+label]>[( i1 , ... , iN [:: o1 , ... , oM )]
            This transfers control to <[file]module[+label]>. "module"
            must be present in the <[file]module[+label]>, contrary to the
            convention for "program starting address" mention previously.
            "[file]" and "+label" are optional, However if "module" is in a
            different file other than the ones already processed, "[file]" is
            required. "label" must be a label in module "module". "i1" to
            "iN" are "input args", CALC statements that preceed the call.
            "o1" to "oN" are "output args", CALC statements that follow the
            call. Examples:

            call module2
            call module2+label3
            call c:\star\star.pc2\module5( xxx = 1 , yyy = 2 )+label1
            call module4 ( xxx = 10 , yyy = 20 )
            call module1 ( xxx = 5 , yyy = 3 :: zzz = module1)

            This last example requires a little explaining. The CALC
            statements "xxx = 5" and "yyy = 3" are executed before "module1"
            is called. After it is called, "zzz = module1" is executed,
            which implies the result of the call is contained in a CALC
            variable "module1", named the same as the module.

            As noted initially, PCALC is a stackless programming language.
            This implies the call

                      call module1 ( 10 )

            will only pass the value 10 to module1, if module1 makes
            a reference to the CALC variable "]" immediately. Note this
            type of argument will not allow multiple values to be passed.
            The proper way to influence the workings of module1 is to know
            which variable in that module is to be initialized, say "xxx",
            then initialize that variable with the call

                      call module1 (  xxx = 10 )

            Obviously, a knowledge of the inner workings of module1
            need to be known by the caller. PCALC is not meant to be
            a highly diverse set of modules linked together. It is
            meant to be simple. Therefore this calling method is
            appropriate and has some advantages, not mentioned here.

            The variables before the "::" are by default considered local
            to the module called. Variables after the "::" are considered
            by default local to the calling module. However, if one of those
            variables is declared as "global", then it will be visible to
            both modules. Thus the default is that "xxx" and "yyy" are
            local to "module1" while "zzz" is local to the module that called
            "module1".

            Module names are automatically entered as global variables and thus
            are never local. The return instruction "zzz = module1" makes sense
            as long as module "module1" defines the variable "module1" before
            ending.

            The following example passes the character string "abc" to the
            module5.

            call module5 ( vs ( " x = 'abc' " ) , y = 10 )

            This uses the "vs" function of CALC, which is basically
            a string manager that returns the numerical address of the
            string variable ("x") that is defined in the expression.
            Literal strings are enclosed in single quotes " ' ".
            Once the call to module5 is executed, the string variable
            "x" will contain the string "abc", which then can be accessed
            in module5 using the function PC_CALC as follows:

                            pc_calc ( vs ( "x" ) )

            You can also pass arguments to a called module when using the
            "=star.pcalc..." label in a STAR file. Thus

            =star.pcalc.now   c:\for\pstar.b1\ssec1 ( x = 304.85 )

            will assign the value 304.85 to the ssec1 local variable "x".
            The STAR macro fill-ins "<arg>" can also be used as in

            =star.pcalc.now   c:\for\pstar.b1\ssec2 ( x = <amt> )

            PCALC is not a fully recursive programming language. It is
            recursive when applied to STAR calls. This means a PCALC
            command may invoke a STAR command, which in turn invokes a
            PCALC module. Upon completion of the STAR command and its
            childern commands, PCALC will return successfully to the next
            instruction in the originating module. However, if a module
            eventually calls itself, the local variables will be the same.

The DO WHILE and END DO statements

       do while ( <expression> )
            This allows the execution of the next instruction if the
            CALC expression <expression> is non-zero. Otherwise, control
            is transferred to the next statement following the "end do"
            statement.

       end do
            This terminates the preceeding "do while" statement.
            If <expression> in the "do while" statement is non-zero
            at the time "end do" is executed, control will be transferred
            to the line immediately following the "do while" statement.
            Otherwise, control is passed to the next statement after "end do".

            Example:

            sum = 0
            i = 0
            do while ( le(i,5) )
                sum = sum + 1
                i = i + 1
            end do

            This will repeat the two statements between the "do while" and
            "end do" statements until "i" is greater than 5. "sum" will
            equal 6 when this "do loop" is exited.

The LINE statements

       PCALC does not have arrays as it is not intended as an algebraic
       language but as a financial one. However having lists of things
       is still a useful idea, which the "line" statements allow for,

       beginline <loop> <[file]module[+label1]>
            This defines the beginning of the "line" construct <loop> to
            begin at the next statement after <[file]module[+label1]>.
            The PCALC function "pc_line(loop)" will translate to this statement.
            until "nextline" is executed. If "[+label]" is omitted, "beginline"
            begins at the next statement after the first statement of "module".

       nextline <loop> <[file]module[+label2]>
            This does two things. First, it defines the end of the "line"
            construct <loop> to end at the line immediately preceeding
            <[file]module[+label2]>. If "[+label]" is omitted, <loop>
            ends at the next to last statement of the module "module".
            Secondly, "nextline" also re-defines the line "pc_line(loop)" will
            translate to, as the next line after the last one used, until
            the line before <[file]module[+label2]> is reached. Any empty
            loop will produce a fatal error. "pc_nextline_sts" is a CALC
            variable that is set to 0 if "nextline" reaches its end. Otherwise
            it is set to 1. The use of this variable enables one to control
            the execution of "nextline". For example:

            beginline loop1 module2 + start_loop1
            do while (pc_nextline_sts)
                star pc_line(loop1)
                nextline loop1 module2 + end_loop1
            end do

            In the above example, "start_loop1" is a label in module
            "module2". "beginline" assigns the next line after this label
            to be the result returned by "pc_line(loop1)", which will
            continue to produce this until either "nextline" or "beginline"
            is evoked. When "nextline" is evoked, the label "end_loop1" in
            module "module2" is designated as the terminating line and the next
            line after the current line for "loop1", if any, is now assigned to
            be the result returned by "pc_line(loop1)". If a line results from
            the execution of "beginline" and "nextline", "pc_nextline_sts" will
            be equal 1, otherwise 0. Consequently, the "do while" loop will end
            after the label "end_loop1" is reached.

The PC_DBM statement

       The ability to read and write existing databases can be accomplished
       using the PC_DBM statement. Databases currently supported are FoxPro,
       CSV and STAR. Separate databases may be joined with their fields
       appearing in a single selected database. The syntax is as follows:

                 call pc_dbm(session,command,parameters)

       After any call to pc_dbm, the CALC variable "pc_dbm_sts" is set to
       non-zero ("true") if the operation was successful. In the case of
       a READ command (defined below), this variable will be zero ("false")
       if there are no further records to be read.

       The Open command.

           There are three Open commands: open_dbf, open_csv, open_star

           These commands open a DBF, CSV or STAR database respectively. A
           STAR database is simply a star-formatted file. In this case there
           are precisely two fields: "star_var" (a star account or other
           attribute) and "star_val", the value of the field star_var.

           The Open command has the following parameters:

           1. The input database. This must be parameter 1.
           2. The output database. This is parameter 2 for DBF and CSV
              but not for STAR, which has no output database. In the case
              of DBF and CSV, if there is no output database, parameter 2
              must still be specified (blank).
           3. The "show_fields" parameter which displays the field names.
           4. The "verbose" parameter which displays output statistics.
           5. The "field_names" parameter which is only used with "open_csv".


           Examples of the Open command:

               An DBF example where the session name is "me", the input
               database is "me.dbf" and the output database is "me.new":

                   call pc_dbm(me,open_dbf,me.dbf,me.new,show_fields,verbose)

               The above example with no output database specified:

                   call pc_dbm(me,open_dbf,me.dbf,,show_fields,verbose)

               A minimal example:

                   call pc_dbm(me,open_dbf,me.dbf,)

               A CSV example which specifies the field names are included in
               the first record of the CSV file:

                   call pc_dbm(me,open_csv,csvmod.csv,csvmod.new,field_names)

               A STAR example:

                   call pc_dbm(me,open_star,pcalc.b1,show_fields,verbose)

       The Read command.

           The Read command reads the next record for the session. It sets
           the CALC variable "pc_dbm_sts" to non-zero ("true") if the read
           has been successful otherwise it sets it to zero ("false").
           The Read command has no parameters.

           If there are no further records, the Read commmand closes all files
           associated with the session.

           Example of the Read command:

               call pc_dbm(me,read)
               do while (pc_dbm_sts)
                   .......
                   call pc_dbm(me,read)
               end do

       The Fld(u) command.

           The Fld(u) command returns a string which corresponds to the field
           specified by the first parameter. The second and subsequent
           parameters (optional) format the string to "Ax" (size "x", size-
           adjusted if "A" only), "R" (right-adjusted) or "L" (left-adjusted).
           "fldu" returns the field as uppercase, allowing for
           comparisons, while "fld" returns the field as it is in the database.
           The field may be qualified by the substring delimitor "/a:b", where
           b >= a >= 1.

           Examples of the Fld(u) command:

               The following compares the field "firstname" with "salut" in the
               current record and causes the execution of the "if" statement
               if both fields are equal:

                   if(eq("pc_dbm(me,fldu,firstname)","pc_dbm(me,fldu,salut)")) then

               An example of use of the substring delimitor would be:

                   if(eq("pc_dbm(me,fldu,firstname/1:3)","pc_dbm(me,fldu,salut/1:3)")) then

               The following outputs to the console the uppercase name and
               value of each variable. The name is entered into a 15 character
               space:

                   print "pc_dbm(me,fldu,star.var,a15) = pc_dbm(me,fldu,star.val)"

       The Write command.

           The Write command modifies the field given by the first parameter
           with the field or value in the second. Values are specified by
           using quotes.

           Examples of the Write command:

               This enters a "1" in the field "nameformat":

                   call pc_dbm(me,write,nameformat,"1")

               This moves the value of "join_env_no" into "env_no".

                   call pc_dbm(db1,write,env_no,join_env_no)

       The Close command.

           The Close command closes all open files for the session. There
           are no parameters.

           An example of the Close command.

               call pc_dbm(me,close)

       The Join command.

           The Join command creates new "joined" fields in session 1
           using fields from session 2. These joined fields are not
           permanent, as they only exist as long as the Join
           session is open. The Write command must be used to
           write the value of a "joined" field into a permanent field
           of session 1 in order to preserve that value in session 1.
           The parameters are as follows:

           1. Session 1. This must be parameter 1 and is the database
              to receive the new field.
           2. Session 2. This must be parameter 2 and is the database
              that provides the new field's value.
           3. The next series of parameters are the key fields from session 1
              that must terminate in a blank parameter.
           4. The next series of parameters are the key fields from session 2
              that must terminate in a blank parameter. These fields will
              be used to match the fields in 3.
           5. The next series of parameters occur in pairs, with the first
              element the name of a field from session 2 and the second element
              the name of the new field in session 1 that will have the value
              of the field from session 2.

           An example of the Join command.

              In this example, a new field "join_env_no" is created in session 1
              "db1" using the value of "env_no" from session 2 "db2". The link
              between the two sessions occurs when the key fields "lastname"
              and "firstname" from both sessions are equal. For instance,
              if the lastname "smith" with first name "sam" occurs somewhere
              in both sessions, with env_no "123" in session 2, then the new
              field join_env_no will have the value "123" in the record of
              session 1 if that record has lastname "smith" and firstname "sam".

              call pc_dbm(db3,join,db1,db2,lastname,firstname,,lastname,firstname,,env_no,join_env_no)

           An example of writing the joined field "join_env_no" to the
           permanent field "env_no" of session 1. This is a case of
           over-writing whatever is in env_no of session 1 with the
           corresponding value from session 2.

              call pc_dbm(db1,write,env_no,join_env_no)


The PC_HASH statement

       The ability to store, recall and compare strings can be accomplished
       using the PC_HASH statement. The syntax is as follows:

                 call pc_hash(hash,command,parameters)

       where "hash" can be any string indicating the particular table.

       After any call to pc_hash, the CALC variable "pc_hash_sts" is set to
       non-zero ("true") if the operation was successful. For many of the
       commands listed below, this variable will be either true or false
       depending on whether or not the operation was completely successful.

       The Init command.

           The Init command initializes the hash table "hash", which can be
           any table name. The 1st parameter is the maximum key size, the
           remaining parameters, with the exception of the last, are the
           various data field sizes and the last parameter is the maximum
           table size. This command does not return a value.

           An example of the Init command in which the table name is "hash",
           the maximum key size is 80, there is one data field of size zero
           and the maximum table size is 1000.

                 call pc_hash(hash,init,80,0,1000)

           And example of a similiar command with two data fields of sizes
           5 and 10 respectively.

                 call pc_hash(hash,init,80,5,10,1000)

       The End command.

           The End command closes the hash table. It does not return a value.
           An example is

                 call pc_hash(hash,end)

       The Insert command.

           The Insert command insert a string "key" into the table. The
           CALC variable "pc_hash_sts" is set to non-zero ("true")
           if this string is not already in the table, otherwise zero
           ("false"). This command returns a non-zero value in the
           former case and a zero value in the latter.

           An example is

                 call pc_hash(hash,insert,string)

           where "string" is any string, including commas.

           Note: All arguments to pc_hash are left and right reduced
           which implies the string "  a b c  " equals "a b c". Thus

                 call pc_hash(hash,insert,  a b c  )

           is equivalent to

                 call pc_hash(hash,insert,a b c)

           In order to keep leading or trailing blanks use double
           double quotes, as is shown in this example

                 call pc_hash(hash,insert,""  a b c  "")

           The use of single double quotes is consider part of the string,
           i.e. the following two commands are NOT the same

                 call pc_hash(hash,insert,""  a b c  "")
                 call pc_hash(hash,insert,"  a b c  ")

           The former begins and end with two spaces, while the
           latter begins and ends with a double quote ".

       The Save command.

           The save command saves a string to the last defined hash
           location. If the last defined location was null (as with the
           "delete" command) a fatal error will result. It does not return
           a value. An example:

                 call pc_hash(hash,save,string)

           where "string" can be any string.

           The command can be either "save" or "savex" where "x" is a number
           between 1 and the number of data fields. For example,

                 call pc_hash(hash,save,a b c)

           is equivalent to

                 call pc_hash(hash,save1,a b c)

           while

                 call pc_hash(hash,save2,a b c)


           this saves to the second data field. The number of data fields
           defined by the INIT command must not be exceeded by "x".

       The Key command.

           This returns the key used by the last command that defined a
           hash location. An example

                 call pc_hash(hash,key)

       The Data command.

           This returns the data of the last defined hash location.
           An example

                 call pc_hash(hash,data)

           As with the SAVE command, "data" may be "datax" where "x"
           if the data field required. The two following commands
           are equivalent

                 call pc_hash(hash,data)
                 call pc_hash(hash,data1)


       The Find command.

           This returns a non-zero value if the key is present in the
           table, otherwise it returns a zero. An example

                 call pc_hash(hash,find,string)

       The Delete command.

           This returns a non-zero value if the key is present, in which case
           it is deleted from the hash table, otherwise it returns a zero. An
           example

                 call pc_hash(hash,delete,string)

       The Loop command.

           This initializes the hash location. It is to be called
           before using the "next" or "sort" commands. It does not
           return a value. An example:

                 call pc_hash(hash,loop)


       The Next and Sort commands.

           These commands define the next hash location. If this
           is a non-null location, a non-zero value is returned,
           otherwise a zero is returned. The Sort command defines
           the next key sorted location. Examples:

                 call pc_hash(hash,next)
                 call pc_hash(hash,sort)

The RETURN statement

       This terminates execution of the current module and passes
       control to the calling module, if any. If there is no calling
       module, it terminates execution of PCALC.

The EXIT statement

       This is an alias for the RETURN statement.

The END statement

       All modules must end in an END statement, which indicates the
       end of the module during the compilation phase. During the
       execution phase, this statement functions the same as a RETURN
       statement.

Sample programs

       The files "pcalc.pc*" are sample PCALC programs. "pcalc.pcl" has every
       possible language statement but doesn't have any real computational
       purpose. "pcalc.pc5" computes PI to 14 decimal places of accuracy.
       The files "pcalc.b*" are companion STAR files, required by some of
       these included PCALC programs.
