home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Encyclopedia of Graphics File Formats Companion
/
GFF_CD.ISO
/
formats
/
ttddd
/
spec
/
t3d_doc
/
igensurf.zoo
/
src
/
caldefn.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-28
|
15KB
|
627 lines
/* :ts=8 */
/* Copyright (c) 1991 Regents of the University of California */
#include <stdio.h>
#include <ctype.h>
#include "calcomp.h"
#include "calc.h"
#ifndef NHASH
#define NHASH 521 /* hash size (a prime!) */
#endif
#define New_Node() (Expression_T *)Ecalloc(1, sizeof(Expression_T))
extern char *Ecalloc(), *savestr();
static double Var_Value1();
long eclock = -1; /* value storage timer */
int (*Command_Func)();
static Variable_T *Hash_Table[NHASH]; /* definition list */
static int Hash_Index;
static Variable_T *Hash_Pos;
Expression_T *Current_Function;
#define Expr_Name(Expr) ((Expr)->Value.Kid->Node_Type == ET_Symbol ? \
(Expr)->Value.Kid->Value.Name : \
(Expr)->Value.Kid->Value.Kid->Value.Name)
void File_Compile(File_Name, N_Command_Func)
char *File_Name;
int (*N_Command_Func)();
/************************************************************************/
/* */
/* get definitions from a file */
/* */
/* Command_Func is the function which should be called when a line */
/* starting with '#' is found. The function will be called with the */
/* following arguments : */
/* */
/* Command_Func(char *Line, int Line_Number) */
/* */
/* Where 'Line' is the contents of the line, and 'Line_Number' is the */
/* current line number. */
/* */
/* Command_Func may be NULL. */
/* */
/************************************************************************/
{
FILE *fp;
Command_Func = N_Command_Func;
if (File_Name == NULL) {
fp = stdin;
} else if ((fp = fopen(File_Name, "r")) == NULL) {
fprintf(stderr, "%s : cannot open\n", File_Name);
exit(1);
}
Init_File(fp, File_Name, 0);
while (Next_Char != EOF) Expr_Compile();
if (File_Name != NULL) fclose(fp);
Command_Func = NULL;
} /* File_Compile */
void String_Compile(str, fn, ln, N_Command_Func)
char *str;
char *fn;
int ln;
int (*N_Command_Func)();
/************************************************************************/
/* */
/* get definitions from a string */
/* */
/* Command_Func is the function which should be called when a line */
/* starting with '#' is found. The function will be called with the */
/* following arguments : */
/* */
/* Command_Func(char *Line, int Line_Number) */
/* */
/* Where 'Line' is the contents of the line, and 'Line_Number' is the */
/* current line number. */
/* */
/* Command_Func may be NULL. */
/* */
/************************************************************************/
{
Command_Func = N_Command_Func;
Init_Str(str, fn, ln);
while (Next_Char != EOF) Expr_Compile();
Command_Func = NULL;
} /* String_Compile */
double Var_Value(Name)
char *Name;
/************************************************************************/
/* */
/* return a variable's value */
/* */
/************************************************************************/
{
return(Var_Value1(Name, Expr_Lookup(Name)));
} /* Var_Value */
double EFunc_Variable(Expr)
Expression_T *Expr;
/************************************************************************/
/* */
/* evaluate a variable */
/* */
/************************************************************************/
{
register Variable_T *dp = Expr->Value.Variable;
return(Var_Value1(dp->Name, dp->Expression));
} /* EFunc_Variable */
void Var_Set(Name, Assignment_Type, Value)
char *Name;
int Assignment_Type;
double Value;
/************************************************************************/
/* */
/* set a variable's value*/
/* */
/************************************************************************/
{
register Expression_T *Expr1, *Expr2;
/* check for quick set */
if ((Expr1 = Expr_Lookup(Name)) != NULL &&
Expr1->Value.Kid->Node_Type == ET_Symbol) {
Expr2 = Expr1->Value.Kid->Sibling;
if (Expr2->Node_Type == ET_Number) {
Expr2->Value.Number = Value;
Expr1->Node_Type = Assignment_Type;
return;
} /* if */
} /* if */
/* hand build definition */
Expr1 = New_Node();
Expr1->Node_Type = Assignment_Type;
Expr2 = New_Node();
Expr2->Node_Type = ET_Symbol;
Expr2->Value.Name = savestr(Name);
Add_Kid(Expr1, Expr2);
Expr2 = New_Node();
Expr2->Node_Type = ET_Number;
Expr2->Value.Number = Value;
Add_Kid(Expr1, Expr2);
Expr_Remove(Name);
Expr_Push(Expr1);
} /* Var_Set */
void Expr_Clear(Name)
char *Name;
/************************************************************************/
/* */
/* delete variable definitions of name */
/* */
/************************************************************************/
{
register Expression_T *Expr;
while ((Expr = Expr_Pop(Name)) != NULL) {
if (Expr->Node_Type == ':') {
Expr_Push(Expr); /* don't clear constants */
return;
} /* if */
Expr_Free(Expr);
} /* while */
} /* Expr_Clear */
void Expr_Remove(Name)
char *Name;
/************************************************************************/
/* */
/* delete all definitions of name */
/* */
/************************************************************************/
{
register Expression_T *Expr;
while ((Expr = Expr_Pop(Name)) != NULL) Expr_Free(Expr);
} /* Expr_Remove */
int Var_Defined(Name)
char *Name;
/************************************************************************/
/* */
/* return non-zero if variable defined */
/* */
/************************************************************************/
{
register Expression_T *dp;
return((dp = Expr_Lookup(Name)) != NULL &&
dp->Value.Kid->Node_Type == ET_Symbol);
} /* Var_Defined */
void Expr_Cleanup(Level)
int Level;
/************************************************************************/
/* */
/* clear definitions (0->vars,1->consts) */
/* */
/************************************************************************/
{
register int i;
register Variable_T *vp;
for (i = 0; i < NHASH; i++) {
for (vp = Hash_Table[i]; vp != NULL; vp = vp->Next) {
if (Level >= 1) Expr_Remove(vp->Name);
else Expr_Clear(vp->Name);
} /* for */
} /* for */
} /* Expr_Cleanup */
Expression_T *Expr_Lookup(Name)
char *Name;
/************************************************************************/
/* */
/* look up a definition */
/* */
/************************************************************************/
{
register Variable_T *vp;
if ((vp = Var_Lookup(Name)) == NULL) return(NULL);
return(vp->Expression);
} /* Expr_Lookup */
Variable_T *Var_Lookup(Name)
char *Name;
/************************************************************************/
/* */
/* look up a variable */
/* */
/************************************************************************/
{
register Variable_T *vp;
for (vp = Hash_Table[Hash_Value(Name)]; vp != NULL; vp = vp->Next) {
if (!strcmp(vp->Name, Name)) return(vp);
} /* for */
return(NULL);
} /* Var_Lookup */
Variable_T *Var_Insert(Name)
char *Name;
/************************************************************************/
/* */
/* get a link to a variable */
/* */
/************************************************************************/
{
register Variable_T *vp;
int hv;
hv = Hash_Value(Name);
for (vp = Hash_Table[hv]; vp != NULL; vp = vp->Next) {
if (!strcmp(vp->Name, Name)) {
vp->Number_Links++;
return(vp);
} /* if */
} /* for */
vp = (Variable_T *)Emalloc(sizeof(Variable_T));
vp->Name = savestr(Name);
vp->Number_Links = 1;
vp->Expression = NULL;
vp->Function = NULL;
vp->Next = Hash_Table[hv];
Hash_Table[hv] = vp;
return(vp);
} /* Var_Insert */
Var_Free(Variable)
register Variable_T *Variable;
/************************************************************************/
/* */
/* release link to variable */
/* */
/************************************************************************/
{
register Variable_T *vp;
int hv;
if (--Variable->Number_Links > 0) return; /* still active */
hv = Hash_Value(Variable->Name);
vp = Hash_Table[hv];
if (vp == Variable) Hash_Table[hv] = vp->Next;
else {
while (vp->Next != Variable) vp = vp->Next; /* must be in list */
vp->Next = Variable->Next;
}
freestr(Variable->Name);
Efree((char *)Variable);
} /* Var_Free */
Expression_T *Expr_First()
/************************************************************************/
/* */
/* return pointer to first definition */
/* */
/************************************************************************/
{
Hash_Index = 0;
Hash_Pos = NULL;
return(Expr_Next());
} /* Expr_First */
Expression_T *Expr_Next()
/************************************************************************/
/* */
/* return pointer to next definition */
/* */
/************************************************************************/
{
register Expression_T *Expr;
while (Hash_Index < NHASH) {
if (Hash_Pos == NULL) Hash_Pos = Hash_Table[Hash_Index++];
while (Hash_Pos != NULL) {
Expr = Hash_Pos->Expression;
Hash_Pos = Hash_Pos->Next;
if (Expr != NULL) return(Expr);
} /* while */
} /* while */
return(NULL);
} /* Expr_Next */
Expression_T *Expr_Pop(Name)
char *Name;
/************************************************************************/
/* */
/* pop a definition */
/* */
/************************************************************************/
{
register Variable_T *vp;
register Expression_T *dp;
if ((vp = Var_Lookup(Name)) == NULL ||
vp->Expression == NULL) return(NULL);
dp = vp->Expression;
vp->Expression = dp->Sibling;
Var_Free(vp);
return(dp);
} /* Expr_Pop */
Expr_Push(Expr)
register Expression_T *Expr;
/************************************************************************/
/* */
/* push on a definition */
/* */
/************************************************************************/
{
register Variable_T *vp;
vp = Var_Insert(Expr_Name(Expr));
Expr->Sibling = vp->Expression;
vp->Expression = Expr;
} /* Expr_Push */
Expr_Compile()
/************************************************************************/
/* */
/* load next definition */
/* */
/************************************************************************/
{
register Expression_T *Expr;
if (Next_Char == ';') { /* empty statement */
Get_Next_Char();
return;
} /* if */
/* ordinary definition */
Expr = Expr_Get();
if (Expr->Node_Type == ':') Expr_Remove(Expr_Name(Expr));
else Expr_Clear(Expr_Name(Expr));
Expr_Push(Expr);
if (Next_Char != EOF) {
if (Next_Char != ';') Syntax_Error("';' expected");
Get_Next_Char();
} /* if */
} /* Expr_Compile */
Expression_T *Expr_Get()
/************************************************************************/
/* */
/* Expr -> ET_Symbol = E1 */
/* ET_Symbol : E1 */
/* ET_Function(ET_Symbol,..) = E1 */
/* ET_Function(ET_Symbol,..) : E1 */
/* */
/************************************************************************/
{
register Expression_T *Expr1, *Expr2;
if (!isalpha(Next_Char)) Syntax_Error("illegal variable name");
Expr1 = New_Node(); /* Get the name */
Expr1->Node_Type = ET_Symbol;
Expr1->Value.Name = savestr(Get_Name());
if (Next_Char == '(') { /* Function definition */
Expr2 = New_Node();
Expr2->Node_Type = ET_Function;
Add_Kid(Expr2, Expr1);
Expr1 = Expr2;
do { /* Get arguments */
Get_Next_Char();
if (!isalpha(Next_Char)) Syntax_Error("illegal variable name");
Expr2 = New_Node();
Expr2->Node_Type = ET_Symbol;
Expr2->Value.Name = savestr(Get_Name());
Add_Kid(Expr1, Expr2);
} while (Next_Char == ',');
if (Next_Char != ')') Syntax_Error("')' expected");
Get_Next_Char();
Current_Function = Expr1;
} else Current_Function = NULL;
if (Next_Char != '=' &&
Next_Char != ':') Syntax_Error("'=' or ':' expected");
Expr2 = New_Node();
Expr2->Node_Type = Next_Char; /* = or : */
Get_Next_Char();
Add_Kid(Expr2, Expr1);
Add_Kid(Expr2, Get_E1()); /* Get definition (E1) */
if (Expr1->Node_Type == ET_Symbol &&
Expr1->Sibling->Node_Type != ET_Number) {
Expr1 = New_Node();
Expr1->Node_Type = ET_Timestamp;
Expr1->Value.Timestamp = -1;
Add_Kid(Expr2, Expr1);
Expr1 = New_Node();
Expr1->Node_Type = ET_Number;
Add_Kid(Expr2, Expr1);
} /* if */
return(Expr2);
} /* Expr_Get */
static double Var_Value1(Name, Expr)
char *Name;
Expression_T *Expr;
/************************************************************************/
/* */
/* evaluate a variable */
/* */
/************************************************************************/
{
register Expression_T *Expr1, *Expr2;
if (Expr == NULL || Expr->Value.Kid->Node_Type != ET_Symbol) {
fprintf(stderr, "%s : undefined variable\n", Name);
exit(1);
} /* if */
Expr1 = Expr->Value.Kid->Sibling; /* get expression */
if (Expr1->Node_Type == ET_Number) return(Expr1->Value.Number);
Expr2 = Expr1->Sibling; /* check time */
if (Expr2->Value.Timestamp < 0 || Expr2->Value.Timestamp < eclock) {
Expr2->Value.Timestamp = Expr->Node_Type == ':' ? 1L<<30 : eclock;
Expr2 = Expr2->Sibling;
Expr2->Value.Number = Expr_Value(Expr1);/* needs new value */
} else Expr2 = Expr2->Sibling; /* else reuse old value */
return(Expr2->Value.Number);
} /* Var_Value1 */
static int Hash_Value(String)
register char *String;
/************************************************************************/
/* */
/* hash a string */
/* */
/************************************************************************/
{
register int rval = 0;
while (*String) rval += *String++;
return(rval % NHASH);
} /* Hash_Value */