home *** CD-ROM | disk | FTP | other *** search
- /* :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 */
-