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