4.3BSD/usr/ingres/source/monitor/expr.c
# include <ingres.h>
# include <sccs.h>
SCCSID(@(#)expr.c 8.1 12/31/84)
/*
** EXPR -- evaluate expression
**
** This module evaluates an expression in somewhat standard
** infix notation. Several restrictions apply. There are
** no variables, since this can be simulated with the macro
** processor. No numeric overflow is checked. There may be
** no spaces, tabs, or newlines in the expression.
**
** The text of the expression is read from 'macgetch', so
** that must be initialized before calling this routine.
**
** Operators accepted are + - * / < > >= <= = != % ( )
** & |.
** Operands may be signed integers.
** Standard precedence applies.
**
** An expression can be viewed as a sequence of operands,
** and operators. If the terminator is considered to be
** an operator, then the sequence must be composed
** of n matched pairs of operators and operands. NOT and
** Negation are considered to be part of the operand and
** are treated as such. Thus to evaluate an expression,
** n pairs are read until the terminator is found as the
** last operator.
**
** Parameters:
** none
**
** Returns:
** value of the expression. Undetermined value
** on error.
**
** Side Effects:
** Macro processing can occur.
**
** Trace Flags:
** none
*/
# undef STACKSIZE
# define STACKSIZE 50
# define RIGHTP 21
# define END 22
# define SEPERATOR 0
# define OR 1
# define AND 2
# define EQUALS 3
# define NEQ 4
# define LESS 5
# define LEQ 6
# define GREATER 7
# define GEQ 8
# define ADD 9
# define SUBTRACT 10
# define MULTIPLY 11
# define DIVIDE 12
# define MOD 13
int ExprPrec[] = /* Precedence table */
{
0, /* filler */
1, /* 1 -- OR */
2, /* 2 -- AND */
3, /* 3 -- EQUALS */
3, /* 4 -- NEQ */
4, /* 5 -- LESS */
4, /* 6 -- LEQ */
4, /* 7 -- GREATER */
4, /* 8 -- GEQ */
5, /* 9 -- ADD */
5, /* 10 -- SUBTRACT */
6, /* 11 -- MULTIPLY */
6, /* 12 -- DIVIDE */
6 /* 13 -- MOD */
};
int ExprNstack[STACKSIZE];
int *ExprNptr;
int ExprOstack[STACKSIZE];
int *ExprOptr;
int ExprError;
char ExprPeek;
expr()
{
ExprNptr = ExprNstack;
ExprOptr = ExprOstack;
ExprError = FALSE;
ExprPeek = -1;
return(valof(END));
}
/*
** VALOF -- compute value of expression
**
** This is the real expression processor. It handles sequencing
** and precedence.
**
** Parameters:
** terminator -- the symbol which should terminate
** the expression.
**
** Returns:
** The value of the expression.
**
** Side Effects:
** Gobbles input.
**
** Requires:
** exprfind -- to read operands.
** opfind -- to read operators.
** exp_op -- to perform operations.
**
** Called By:
** expr
**
** Diagnostics:
** Extra Parenthesis found: assumed typo
** An unmatched right parenthesis was read.
** It was thrown away.
** Insufficient parenthesis found: assumed zero.
** An unmatched left parenthesis was left
** in the operator stack at the end of the
** expression. The value zero was taken
** for the expression.
**
** Syserrs:
** none
*/
valof(terminator)
int terminator;
{
register int number;
register int operator;
pushop(SEPERATOR); /* initialize the stack */
for(;;)
{
number = exprfind();
if (ExprError)
return(0);
operator = opfind();
if (ExprError)
return(0);
if (operator == RIGHTP || operator == END)
break;
/* Do all previous operations with a higher precedence */
while (ExprPrec[operator] <= ExprPrec[ExprOptr[-1]])
number = exp_op(popop(), popnum(), number);
pushop(operator);
pushnum(number);
}
if (operator != terminator) /* ExprError in operators */
if (operator == RIGHTP)
printf("Extra parenthesis found: assumed typo.\n");
else
{
ExprError = TRUE;
printf("Insufficient parenthesis found: Assumed zero.\n");
return(0);
}
/* Empty stack for this call of valof */
while ((operator = popop()) != SEPERATOR)
number = exp_op(operator, popnum(), number);
return(number);
}
/*
** EXPRFIND -- find and chomp operand
**
** This routine reads the next operand. It generally just
** reads numbers, except it also knows about unary operators
** ! and - (where it calls itself recursively), and paren-
** theses (where it calls valof recursively).
**
** Parameters:
** none
**
** Returns:
** value of operand.
**
** Side Effects:
** Gobbles input.
**
** Requires:
** numberget -- to read numbers.
** exprgch.
**
** Called By:
** valof
** exprfind (recursively)
**
** Trace Flags:
** none
**
** Diagnostics:
** Expression expected: end of expression found.
** Nothing was found. Zero is returned.
** Expression expected: %c found; assumed zero.
** A syntax error -- nothing was found
** which was acceptable.
*/
exprfind()
{
register int result;
register int c;
c = exprgch();
switch(c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return(numberget(c));
case '!':
result = exprfind();
return(ExprError ? 0 : (result <= 0));
case '-':
result = exprfind();
return(ExprError ? 0 : -result);
case '(':
return(valof(RIGHTP));
case ' ':
case '\n':
case '/t':
case '\0':
printf("Expression expected: end of expression found.\n");
ExprError = TRUE;
return(0);
default:
printf("Expression expected; '%c' found: Assumed zero.\n", c);
ExprError = TRUE;
return(0);
}
}
/*
** OPFIND -- find and translate operator
**
** This reads the next operator from the input stream and
** returns the internal code for it.
**
** Parameters:
** none
**
** Returns:
** The code for the next operator.
** Zero on error.
**
** Side Effects:
** Gobbles input.
**
** Requires:
** exprgch.
**
** Called By:
** valof
**
** Trace Flags:
** none
**
** Diagnostics:
** Operator expected: '%c' found.
** Gibberish in input.
*/
opfind()
{
register int c;
c = exprgch();
switch(c)
{
case '/':
return(DIVIDE);
case '=':
return(EQUALS);
case '&':
return(AND);
case '|':
return(OR);
case '+':
return(ADD);
case '-':
return(SUBTRACT);
case '*':
return(MULTIPLY);
case '<':
c = exprgch();
if (c == '=')
{
return(LEQ);
}
ExprPeek = c;
return(LESS);
case '>':
c = exprgch();
if (c == '=')
{
return(GEQ);
}
ExprPeek = c;
return(GREATER);
case '%':
return(MOD);
case '!':
c = exprgch();
if (c == '=')
{
return(NEQ);
}
else
{
printf("Operator expected: '!%c' found.\n", c);
ExprError = TRUE;
return(0);
}
case ')':
return(RIGHTP);
case ' ':
case '\t':
case '\n':
case '\0':
return(END);
default:
printf("Operator expected: '%c' found.\n", c);
ExprError = TRUE;
return(0);
}
}
/*
** EXP_OP -- perform operation
**
** Performs an operation between two values.
**
** Parameters:
** op -- the operation to perform.
** lv -- the left operand.
** rv -- the right operand.
**
** Returns:
** The value of the operation.
**
** Side Effects:
** none
**
** Requires:
** none
**
** Called By:
** valof.
**
** Trace Flags:
** none
**
** Diagnostics:
** none
*/
exp_op(op, lv, rv)
int op;
int lv;
int rv;
{
switch(op)
{
case OR:
return((lv > 0) || (rv > 0));
case AND:
return((lv > 0) && (rv > 0));
case EQUALS:
return(lv == rv);
case NEQ:
return(lv != rv);
case LESS:
return(lv < rv);
case LEQ:
return(lv <= rv);
case GREATER:
return(lv > rv);
case GEQ:
return(lv >= rv);
case ADD:
return(lv + rv);
case SUBTRACT:
return(lv - rv);
case MULTIPLY:
return(lv * rv);
case DIVIDE:
if (rv == 0)
{
printf("Divide by zero: zero assumed.\n");
return(0);
}
else
return(lv / rv);
case MOD:
return(lv % rv);
default:
syserr("exp_op: bad op %d", op);
}
}
/*
** NUMBERGET -- read and convert a number
**
** Reads and converts a signed integer.
**
** Parameters:
** none
**
** Returns:
** The next number in the input stream.
**
** Side Effects:
** Gobbles input.
**
** Requires:
** exprgch.
**
** Called By:
** exprfind.
*/
numberget(cx)
char cx;
{
register int result;
register int c;
c = cx;
result = 0;
do
{
result = result * 10 + c - '0';
c = exprgch();
} while (c >= '0' && c <= '9');
ExprPeek = c;
return(result);
}
/*
** EXPRGCH -- expression character get
**
** Gets the next character from the expression input. Takes
** a character out of ExprPeek first. Also maps spaces, tabs,
** and newlines into zero bytes.
**
** Parameters:
** none
**
** Returns:
** Next character.
**
** Side Effects:
** Gobbles input.
** Clears ExprPeek if set.
**
** Requires:
** ExprPeek -- the peek character.
** macgetch -- to get the next character if ExprPeek
** is not set.
*/
exprgch()
{
register int c;
c = ExprPeek;
if (c < 0)
c = macgetch();
ExprPeek = -1;
if (c == ' ' || c == '\n' || c == '\t')
c = 0;
return (c);
}
/*
** Stack operations.
*/
/* Popop returns the top of the operator stack and decrements this stack. */
popop()
{
if (ExprOptr <= ExprOstack)
syserr("popop: underflow");
return(*--ExprOptr);
}
/* Pushop increments the stack pointer and pushes op on the stack. */
pushop(op)
int op;
{
*ExprOptr++ = op;
}
/* Popnum returns the top of the number stack and decrements the stack pointer. */
popnum()
{
if (ExprNptr <= ExprNstack)
syserr("popnum: underflow");
return(*--ExprNptr);
}
/* Pushnum increments the stack pointer and pushes num onto the stack */
pushnum(num)
int num;
{
*ExprNptr++ = num;
}