home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Encyclopedia of Graphics File Formats Companion
/
GFF_CD.ISO
/
formats
/
ttddd
/
spec
/
t3d_doc
/
igensurf.zoo
/
src
/
calexpr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-28
|
20KB
|
895 lines
/* :ts=8 */
/* Copyright (c) 1986 Regents of the University of California */
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "calcomp.h"
#include "calc.h"
#define ABS(x) (((x) > 0.0) ? (x) : (-(x)))
#define Max_Line_Length 256 /* maximum line length */
#define Max_Word_Length 64 /* maximum word length */
#define New_Node() (Expression_T *)Ecalloc(1, sizeof(Expression_T))
#define isid(c) (isalnum(c) || (c) == '_' || (c) == '.')
#define isdecimal(c) (isdigit(c) || (c) == '.')
extern double atof(), pow();
extern char *fgets(), *savestr();
extern char *Emalloc(), *Ecalloc();
extern Expression_T *Current_Function;
extern double EFunc_Function(), EFunc_Variable();
static double EFunc_UMinus(), EFunc_Argument(), EFunc_Number();
static double EFunc_Add(), EFunc_Subtract(), EFunc_Mult();
static double EFunc_Division(), EFunc_Power();
static double EFunc_Error();
extern int errno;
int Next_Char; /* lookahead character */
double (*Expr_Funcs[])() = { /* expression operations */
EFunc_Error,
EFunc_Variable,
EFunc_Number,
EFunc_UMinus,
EFunc_Error,
EFunc_Function,
EFunc_Argument,
EFunc_Error,
EFunc_Error,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
EFunc_Mult,
EFunc_Add,
0,
EFunc_Subtract,
0,
EFunc_Division,
0,0,0,0,0,0,0,0,0,0,
EFunc_Error,
0,0,
EFunc_Error,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
EFunc_Power,
};
static FILE *In_Stream; /* input file pointer */
static char *In_Buffer; /* line buffer */
static char *In_File; /* input file name */
static int In_Line_No; /* input line number */
static int In_Buffer_Pos; /* position in buffer */
Expression_T *Expr_Parse(expr)
char *expr;
/************************************************************************/
/* */
/* parse an expression string */
/* */
/************************************************************************/
{
Expression_T *Expr;
Init_Str(expr, NULL, 0);
Current_Function = NULL;
Expr = Get_E1();
if (Next_Char != EOF) Syntax_Error("unexpected character");
return(Expr);
} /* Expr_Parse */
double String_Eval(expr)
char *expr;
/************************************************************************/
/* */
/* evaluate an expression string */
/* */
/************************************************************************/
{
register Expression_T *Expr;
double rval;
Expr = Expr_Parse(expr);
rval = Expr_Value(Expr);
Expr_Free(Expr);
return(rval);
} /* String_Eval */
void Expr_Free(epar)
register Expression_T *epar;
/************************************************************************/
/* */
/* free a parse tree */
/* */
/************************************************************************/
{
register Expression_T *Expr;
switch (epar->Node_Type) {
case ET_Variable:
Var_Free(epar->Value.Variable);
break;
case ET_Symbol:
freestr(epar->Value.Name);
break;
case ET_Number:
case ET_Chan:
case ET_Argument:
case ET_Timestamp:
break;
default:
for (Expr = epar->Value.Kid; Expr != NULL; Expr = Expr->Sibling)
Expr_Free(Expr);
break;
}
Efree((char *)epar);
} /* Expr_Free */
static double EFunc_Argument(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* */
/************************************************************************/
{
return(Get_Argument(Expr->Value.Channel));
}
static double EFunc_Number(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* */
/************************************************************************/
{
return(Expr->Value.Number);
}
static double EFunc_UMinus(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* */
/************************************************************************/
{
register Expression_T *Expr1 = Expr->Value.Kid;
return(-Expr_Value(Expr1));
}
static double EFunc_Add(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* */
/************************************************************************/
{
register Expression_T *Expr1 = Expr->Value.Kid;
return(Expr_Value(Expr1) + Expr_Value(Expr1->Sibling));
}
static double EFunc_Subtract(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* */
/************************************************************************/
{
register Expression_T *Expr1 = Expr->Value.Kid;
return(Expr_Value(Expr1) - Expr_Value(Expr1->Sibling));
}
static double EFunc_Mult(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* */
/************************************************************************/
{
register Expression_T *Expr1 = Expr->Value.Kid;
return(Expr_Value(Expr1) * Expr_Value(Expr1->Sibling));
}
static double EFunc_Division(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* */
/************************************************************************/
{
register Expression_T *Expr1 = Expr->Value.Kid;
double d;
d = Expr_Value(Expr1->Sibling);
if (d == 0.0) {
fprintf(stderr, "Division by zero\n");
errno = ERANGE;
return(0.0);
}
return(Expr_Value(Expr1) / d);
}
static double EFunc_Power(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* */
/************************************************************************/
{
register Expression_T *Expr1 = Expr->Value.Kid;
double d, dtmp;
int lasterrno;
lasterrno = errno;
errno = 0;
dtmp = Expr_Value(Expr1);
if (ABS(dtmp) < 1e-5) d = 0.0;
else d = pow(dtmp, Expr_Value(Expr1->Sibling));
/* d = pow(Expr_Value(Expr1), Expr_Value(Expr1->Sibling)); */
#ifdef IEEE
if (!finite(d)) errno = EDOM;
#endif
if (errno) {
fprintf(stderr, "Illegal power\n");
return(0.0);
} /* if */
errno = lasterrno;
return(d);
} /* EFunc_Power */
static double EFunc_Error(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* */
/************************************************************************/
{
fprintf(stderr, "Bad expression!\n");
exit(1);
return(0.0); /* Dummy return to remove warning msg at compile */
}
Expression_T *Expr_Kid(Expr, n)
register Expression_T *Expr;
register int n;
/************************************************************************/
/* */
/* return pointer to a node's nth kid */
/* */
/************************************************************************/
{
for (Expr = Expr->Value.Kid; Expr != NULL; Expr = Expr->Sibling)
if (--n < 0)
break;
return(Expr);
} /* Expr_Kid */
int Nbr_Kids(Expr)
register Expression_T *Expr;
/************************************************************************/
/* */
/* return # of kids for node Expr */
/* */
/************************************************************************/
{
register int n = 0;
for (Expr = Expr->Value.Kid; Expr != NULL; Expr = Expr->Sibling)
n++;
return(n);
} /* Nbr_Kids */
void Init_File(fp, fn, ln)
FILE *fp;
char *fn;
int ln;
/************************************************************************/
/* */
/* prepare input file */
/* */
/************************************************************************/
{
static char inpbuf[Max_Line_Length+1];
In_Stream = fp;
In_Buffer = inpbuf;
In_File = fn;
In_Line_No = ln;
In_Buffer_Pos = 0;
inpbuf[0] = '\0';
Get_Next_Char();
} /* Init_File */
void Init_Str(s, fn, ln)
char *s;
char *fn;
int ln;
/************************************************************************/
/* */
/* prepare input string */
/* */
/************************************************************************/
{
In_Stream = NULL;
In_File = fn;
In_Line_No = ln;
In_Buffer = s;
In_Buffer_Pos = 0;
Get_Next_Char();
} /* Init_Str */
void Get_Next_Char()
/************************************************************************/
/* */
/* scan next character */
/* */
/************************************************************************/
{
extern int (*Command_Func)();
int Status;
do {
if (In_Buffer[In_Buffer_Pos] == '\0') {
if (In_Stream == NULL ||
fgets(In_Buffer, Max_Line_Length, In_Stream) == NULL) {
Next_Char = EOF;
} else {
In_Line_No++;
if (In_Buffer[0] == '#') {
if (Command_Func != NULL) {
Status = Command_Func(In_Buffer, In_Line_No);
if (Status != 0) Next_Char = EOF;
}
In_Buffer[0] = '\n'; In_Buffer[1] = '\0';
} /* if */
Next_Char = In_Buffer[0];
In_Buffer_Pos = 1;
}
} else Next_Char = In_Buffer[In_Buffer_Pos++];
if (Next_Char == '{') { /* A comment */
Get_Next_Char();
while (Next_Char != '}') {
if (Next_Char == EOF) Syntax_Error("'}' expected");
else Get_Next_Char();
} /* while */
Get_Next_Char();
} /* if */
} while (isspace(Next_Char));
} /* Get_Next_Char */
void Syntax_Error(Msg)
char *Msg;
/************************************************************************/
/* */
/* report syntax error and quit */
/* */
/************************************************************************/
{
register int i;
if (In_File != NULL || In_Line_No != 0) {
if (In_File != NULL) fprintf(stderr, In_File);
if (In_Line_No != 0) {
fprintf(stderr, In_File != NULL ? ", line " : "line ");
fprintf(stderr, "%ld", (long)In_Line_No);
}
fprintf(stderr, ": syntax error:\n");
}
fprintf(stderr, In_Buffer);
if (In_Buffer[strlen(In_Buffer)-1] != '\n') fprintf(stderr, "\n");
for (i = 0; i < In_Buffer_Pos-1; i++)
fprintf(stderr, In_Buffer[i] == '\t' ? "\t" : " ");
fprintf(stderr, "^ ");
fprintf(stderr, Msg);
fprintf(stderr, "\n");
exit(1);
} /* Syntax_Error */
void Add_Kid(Expr, Kid)
register Expression_T *Expr;
Expression_T *Kid;
/************************************************************************/
/* */
/* add a child to Expr */
/* */
/************************************************************************/
{
if (Expr->Value.Kid == NULL) Expr->Value.Kid = Kid;
else {
for (Expr = Expr->Value.Kid;
Expr->Sibling != NULL; Expr = Expr->Sibling) ;
Expr->Sibling = Kid;
}
Kid->Sibling = NULL;
} /* Add_Kid */
char *Get_Name()
/************************************************************************/
/* */
/* scan an identifier */
/* */
/************************************************************************/
{
static char str[Max_Word_Length+1];
register int i;
for (i = 0; i < Max_Word_Length &&
isid(Next_Char); i++, Get_Next_Char()) str[i] = Next_Char;
str[i] = '\0';
return(str);
} /* Get_Name */
int GetInteger()
/************************************************************************/
/* */
/* scan a positive integer */
/* */
/************************************************************************/
{
register int n;
n = 0;
while (isdigit(Next_Char)) {
n = n * 10 + Next_Char - '0';
Get_Next_Char();
}
return(n);
} /* GetInteger */
double GetFloat()
/************************************************************************/
/* */
/* scan a positive float */
/* */
/************************************************************************/
{
register int i;
char str[Max_Word_Length+1];
i = 0;
while (isdigit(Next_Char) && i < Max_Word_Length) {
str[i++] = Next_Char;
Get_Next_Char();
} /* while */
if (Next_Char == '.' && i < Max_Word_Length) {
str[i++] = Next_Char;
Get_Next_Char();
while (isdigit(Next_Char) && i < Max_Word_Length) {
str[i++] = Next_Char;
Get_Next_Char();
} /* while */
} /* if */
if ((Next_Char == 'e' || Next_Char == 'E') && i < Max_Word_Length) {
str[i++] = Next_Char;
Get_Next_Char();
if ((Next_Char == '-' || Next_Char == '+') && i < Max_Word_Length) {
str[i++] = Next_Char;
Get_Next_Char();
} /* if */
while (isdigit(Next_Char) && i < Max_Word_Length) {
str[i++] = Next_Char;
Get_Next_Char();
} /* while */
} /* if */
str[i] = '\0';
return(atof(str));
} /* GetFloat */
Expression_T *Get_E1()
/************************************************************************/
/* */
/* E1 -> E1 ADDOP E2 */
/* E2 */
/* */
/************************************************************************/
{
register Expression_T *Expr1, *Expr2;
Expr1 = Get_E2();
while (Next_Char == '+' || Next_Char == '-') {
Expr2 = New_Node();
Expr2->Node_Type = Next_Char;
Get_Next_Char();
Add_Kid(Expr2, Expr1);
Add_Kid(Expr2, Get_E2());
if (Expr1->Node_Type == ET_Number &&
Expr1->Sibling->Node_Type == ET_Number)
Expr2 = Const_Reduce(Expr2);
Expr1 = Expr2;
}
return(Expr1);
} /* Get_E1 */
Expression_T *Get_E2()
/************************************************************************/
/* */
/* E2 -> E2 MULOP E3 */
/* E3 */
/* */
/************************************************************************/
{
register Expression_T *Expr1, *Expr2;
Expr1 = Get_E3();
while (Next_Char == '*' || Next_Char == '/') {
Expr2 = New_Node();
Expr2->Node_Type = Next_Char;
Get_Next_Char();
Add_Kid(Expr2, Expr1);
Add_Kid(Expr2, Get_E3());
if (Expr1->Node_Type == ET_Number &&
Expr1->Sibling->Node_Type == ET_Number)
Expr2 = Const_Reduce(Expr2);
Expr1 = Expr2;
} /* while */
return(Expr1);
} /* Get_E2 */
Expression_T *Get_E3()
/************************************************************************/
/* */
/* E3 -> E4 ^ E3 */
/* E4 */
/* */
/************************************************************************/
{
register Expression_T *Expr1, *Expr2;
Expr1 = Get_E4();
if (Next_Char == '^') {
Expr2 = New_Node();
Expr2->Node_Type = Next_Char;
Get_Next_Char();
Add_Kid(Expr2, Expr1);
Add_Kid(Expr2, Get_E3());
if (Expr1->Node_Type == ET_Number &&
Expr1->Sibling->Node_Type == ET_Number)
Expr2 = Const_Reduce(Expr2);
return(Expr2);
} /* if */
return(Expr1);
} /* Get_E3 */
Expression_T * Get_E4()
/************************************************************************/
/* */
/* E4 -> ADDOP E5 */
/* E5 */
/* */
/************************************************************************/
{
register Expression_T *Expr1, *Expr2;
if (Next_Char == '-') {
Get_Next_Char();
Expr2 = Get_E5();
if (Expr2->Node_Type == ET_Number) {
Expr2->Value.Number = -Expr2->Value.Number;
return(Expr2);
} /* if */
Expr1 = New_Node();
Expr1->Node_Type = ET_UMinus;
Add_Kid(Expr1, Expr2);
return(Expr1);
} /* if */
if (Next_Char == '+') Get_Next_Char();
return(Get_E5());
} /* Get_E4 */
Expression_T *Get_E5()
/************************************************************************/
/* */
/* E5 -> (E1) */
/* ET_Variable */
/* ET_Number */
/* $N */
/* ET_Function(E1,..) */
/* ET_Argument */
/* */
/************************************************************************/
{
int i;
register Expression_T *Expr1, *Expr2;
if (Next_Char == '(') {
Get_Next_Char();
Expr1 = Get_E1();
if (Next_Char != ')') Syntax_Error("')' expected");
Get_Next_Char();
return(Expr1);
} /* if */
if (isalpha(Next_Char)) {
Expr1 = New_Node();
Expr1->Node_Type = ET_Variable;
Expr1->Value.Variable = Var_Insert(Get_Name());
if (Current_Function != NULL) {
for (i = 1, Expr2 = Current_Function->Value.Kid->Sibling;
Expr2 != NULL; i++, Expr2 = Expr2->Sibling) {
if (!strcmp(Expr2->Value.Name,Expr1->Value.Variable->Name)) {
Expr_Free(Expr1);
Expr1 = New_Node();
Expr1->Node_Type = ET_Argument;
Expr1->Value.Channel = i;
break;
} /* if */
} /* while */
} /* if */
if (Next_Char == '(') {
Expr2 = New_Node();
Expr2->Node_Type = ET_Function;
Add_Kid(Expr2, Expr1);
Expr1 = Expr2;
do {
Get_Next_Char();
Add_Kid(Expr1, Get_E1());
} while (Next_Char == ',');
if (Next_Char != ')') Syntax_Error("')' expected");
Get_Next_Char();
} /* if */
if (Is_Const_Var(Expr1)) Expr1 = Const_Reduce(Expr1);
return(Expr1);
} /* if */
if (isdecimal(Next_Char)) {
Expr1 = New_Node();
Expr1->Node_Type = ET_Number;
Expr1->Value.Number = GetFloat();
return(Expr1);
} /* if */
Syntax_Error("unexpected character");
} /* Get_E5 */
Expression_T *Const_Reduce(epar)
register Expression_T *epar;
/************************************************************************/
/* */
/* reduce a constant expression */
/* */
/************************************************************************/
{
register Expression_T *Expr;
Expr = New_Node();
Expr->Node_Type = ET_Number;
errno = 0;
Expr->Value.Number = Expr_Value(epar);
if (errno) Syntax_Error("bad constant expression");
Expr_Free(epar);
return(Expr);
} /* Const_Reduce */
int Is_Const_Var(Expr)
register Expression_T *Expr;
/************************************************************************/
/* */
/* is Expr linked to a constant expression? */
/* */
/************************************************************************/
{
register Expression_T *Expr1;
if (Expr->Node_Type == ET_Function) {
if (!Is_Const_Fun(Expr->Value.Kid)) return(0);
for (Expr1 = Expr->Value.Kid->Sibling;
Expr1 != NULL; Expr1 = Expr1->Sibling) {
if (Expr1->Node_Type != ET_Number && !Is_Const_Fun(Expr1))
return(0);
} /* for */
return(1);
} /* if */
if (Expr->Node_Type != ET_Variable) return(0);
Expr1 = Expr->Value.Variable->Expression;
if (Expr1 == NULL || Expr1->Node_Type != ':') return(0);
if (Expr1->Value.Kid->Node_Type != ET_Symbol) return(0);
return(1);
} /* Is_Const_Var */
int Is_Const_Fun(Expr)
register Expression_T *Expr;
/************************************************************************/
/* */
/* is Expr linked to a constant function? */
/* */
/************************************************************************/
{
register Expression_T *dp;
register Function_T *lp;
if (Expr->Node_Type != ET_Variable) return(0);
dp = Expr->Value.Variable->Expression;
if (dp != NULL && dp->Node_Type != ':') return(0);
if ((dp == NULL || dp->Value.Kid->Node_Type != ET_Function)
&& ((lp = LibFunc_Lookup(Expr->Value.Variable->Name)) == NULL
|| lp->Assignment_Type != ':')) return(0);
return(1);
} /* Is_Const_Fun */