home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Troubleshooting Netware Systems
/
CSTRIAL0196.BIN
/
attach
/
pcc
/
v08n03
/
math.exe
/
PARSER21.ZIP
/
FORMULC.DOC
< prev
next >
Wrap
Text File
|
1994-08-23
|
11KB
|
251 lines
/* FORMULC.DOC as of 8/21/94 (v2.1) */
/* Copyright (c) 1994 Harald Helfgott (E-MAIL: seiere@uwyo.edu) */
/* This file must be distributed with its corresponding
README.DOC. You should read it, for you will find my regular
address and the copyright and availability information there. */
Overview of the FORMULC 2.0 functions
-------- -- --- ------- --- ---------
The FORMULC set of functions is written in ANSI C. It has
been tested in a 386SX running GNU CC (DJGPP 1.11), in another
386SX running Turbo C++ v3.0 and in a VAX/VMS, but it will probably
run in any machine with an ANSI C compiler. The functions enable
the user of a C program to enter mathematical functions and to
evaluate them very rapidly. This project was undertaken for the
Finite Elements Laboratory of the School of Mathematics in the
Universidad Mayor de San Marcos, Lima, Peru.
Any programmer who handles mathematical problems must
sometimes require the users of his or her programs to enter a
mathematical function by the keyboard. Embedding the function in
the program is time-consuming and not user friendly. Consequently,
there is a large number of programs in C and Pascal that parse
strings representing mathematical formulas. In fact, most good
Pascal and C books have a more or less inchoate parser. However,
all the formula interpreters I have seen are extremely slow.
On May 1993, a mathematics professor in Lima, Peru asked me
whether I could write a quick formula interpreter. His program
needed to compute a formula entered by the user hundreds of
thousands of times. I decided, therefore, to write a two-stage
interpreter. First, a string containing a mathematical function is
translated into another string in a postfix format. Every formula
goes through this stage once. Then, the string in postfix format is
interpreted whenever one wants to evaluate the mathematical
function. Since this string's structure makes the use of a stack
rapid, lacks white space and has additional characters to ensure
that the computer understands the formula swiftly, interpretation
is little time consuming. Although extra space is needed for the
intermediate string, the velocity of the two-stage method
compensates the space overhead.
The FORMULC routines are easy to use. They are all in one
file, FORMULC.C; one only needs to type
#include "formula.h"
and to link FORMULC with one's program to use the functions.
There are no initialization routines. There are utilities that
describe and extend the types of expressions that the formula
interpreter can understand. Moreover, I expect the program to be
error free and resistant to the human fallibility of the users.
Please read TIME.DOC to know about the velocity of my formula
interpreter. My address, the instructions for reporting bugs, the
statement of what you are allowed to do with the program and the
registration information are in README.DOC.
Description of the functions
----------- -- --- ---------
unsigned char *translate(char *source, char *args, int *length,
int *error);
Examples:
f = translate("x^2 + sin(3*x) + 0.1", "x", plength, perror);
f = translate("1E+5 * x/x \n", "x", plength, perror);
gets(gsource);
g=translate(gsource, "xyz", plength, perror);
/* g is a function of x, y and z */
This function transforms a legible mathematical function in
string source[] into a coded function which is returned. The
arguments of source are in string arg[]; they must be lower-case
letters. If source uses an undeclared argument, translate stops
coding and returns the index of the argument in *error. In fact,
if any error occurs, *error contains an approximation of the index
of the character in source[] that causes the error, *length acquires
the value 0 and translate returns NULL. However, if source[] contains
a valid mathematical function, the transformation occurs, *length
contains the length of function[] (not including the final \0) and
*error contains -1.
The result string is dynamically allocated. It is likely to be
far larger than source[]. If it does not fit in memory, or if any other
out-of-memory error occurs, translate returns NULL, but *error contains
-1. The result string can always be deallocated using free().
source[] | Length of function[]
| (VMS 5.5 CC)
|
"4", "4.0" or "4.0E-3" | 9 chars
"x" | 2 chars
"(x+3)^2" | 22 chars
"(x+3)*(x+3)" | 25 chars
"atan2(x^2,sqrt(x)-x))" | 21 chars
"acos(cos(x)-x)" | 9 chars
The syntax of source is the following one (in Extended
Backus-Naur Form):
source = expression "\0"
expression = [-] summand {("+" | "-") summand}
summand = factor {("*" | "/") factor}
/*Please, don't forget "*" ! */
factor = base {"^" base}
base = "(" expression ")" | function "(" expression ")" |
number | parameter
function = a string in the function table
parameter = a lower-case letter mentioned by arg[]
number = any nonnegative number /* the sign is considered in
the definition of expression */
/* please write 3.5E-3, not 3.5e-3 */
This description of the syntax mimics the algorithm in
translate(...). It must be noticed that -3+5*6 and 3+5*(-6) are
allowed, but 3+5*-6 and 3+-5*6 are not. Moreover, following standard
C notation, -x^2 and -6^2 mean (-x)^2 and (-6)^2, the unary minus
operator having higher precedence than the power operator.
White space is ignored. Moreover, translate(...) is not case-
sensitive.
translate(...) works recursively. First, it locates the
operator with the lowest order of precedence. Then, it calls
itself to translate each operand. Thereafter, it adds the operator
at the end and stops. If both operands are constants, translate
executes fval to evaluate the expression at "compile time". (Beware
of overflows! They can be perceived by the standard methods.) If
there is no operator, translate(...) checks whether its input is
a variable or a constant. If the input is invalid, translate(...)
points out the error. Otherwise, *error contains -1.
The coded function in string function uses postfix notation.
The syntax is the following one:
coded function = ce "\0"
ce = ("" | ce | (ce ce) | (ce ce ce) ) operator |
parameter | number
parameter = "V" lower-case letter
number = "D" any real number in double format
operator = "^" | "+" | "*" | "-" | "/" | "M" /*i.e. unary minus */
| function
/*each operand has a characteristic number of operands
(i.e. ce's) */
function = "F" index of a function in the table (one char)
/* Be careful! The index may be represented as \0 */
/* Trust only the result of translate when finding */
/* out the length of the coded function. */
/* Since there can be more than 128 functions, */
/* please declare function[] as an array of unsigned */
/* char */
No blanks exist.
The standard functions are exp(), ln(x), sin(), cos(), tan(),
asin(), acos(), atan(), abs(), pi() (without parameters inside the
brackets) and sqrt(). One can add new functions by using fnew(..);
the name of each function obeys C regulations but can be as long as
needed. If a new function is used, fnew(..) must be called in the
same run as translate(..); one must not call fnew, translate a
function, store the coded function and call a program that uses
fnew(..) and loads the coded function. Moreover, no random-number
generator should be added with fnew.
double fval(unsigned char *function, char *args, ...);
Examples:
translate(f,"x^2+sin(cos(x))","x");
result=fval(f,"x",3.0); /* 3.0, not 3 */
/* returns 3^2+sin(cos(3)) */
translate(g,"n*m","nm");
for(p=0; p<100; p++)
for(q=0; q<1000; q++)
a[p][q]=fval(g,"nm",(double) p,(double) q);
/* the arguments must always be double */
fval(...) calculates the value of a coded mathematical function
in string function[] when the arguments, whose names are in string
args[], are given. If there are not enough parameters or if the
parameters don't belong to the function, the result is undefined.
If there are any mathematical errors such as trying to obtain the
square root of -5, errno is EDOM (domain error) or ERANGE (range
error), the results are Infinity and Not-A-Number, or the program
stops, depending on the compiler and how you use it.
double f_x_val(unsigned char *function, double x);
Examples:
result=f_x_val(f,3); /* calculates f(3) if f is a function
of x */
A shorthand version of fval(..) for functions of x. It is
about as rapid as fval(..) .
int fnew(char *name, void *f, int n_pars);
Examples:
fnew("sinh",(void *) sinh,1); /* sinh has been declared as
double sinh(double); */
/* The (void *) cast is necessary
only if you use C++ */
fnew("logb",(void *)logb,2); /* logb has been declared as
double logb(double, double); */
fnew(...) adds a user-defined C function with double parameters
to the library of FORMULA. The C function can have from 0 to 3
parameters. fnew(...) returns 0 if the library is full (255
functions) or if other error occurs. Otherwise, it returns 1.
Please, do not call any function 'E' !
int read_table(int i, char *name, int *n_of_pars);
Example:
i=0;
while(read_table(i++, name, &n_pars)
printf("%s %d",name,n_pars);
read_table copies the name and the number of parameters of
function #i onto name[] and *n_of_pars. If function #i does not
exist, read_table returns 0. Otherwise, it returns a positive
number.
int where_table(char *name);
Example:
if(where_table("sinh") == -1)
printf("Hyperbolic sine not defined.");
If there is a mathematical function called name[],
where_table(..) returns its index in the table of functions.
Otherwise, where_table(..) returns -1. Use fnew(..) to define
mathematical functions which are not in FORMULA's standard
library.
int fdel(char *name);
Example:
if(where_table("sinh" != -1)
fdel("sinh");
If there is a mathematical function called name[], fdel deletes
it. If fdel is succesful, it returns a non-negative number;
otherwise, it returns -1.