1
0
Files
irix-657m-src/irix/cmd/netman/lib/ex_operate.c
2022-09-29 17:59:04 +03:00

366 lines
8.7 KiB
C

/*
* Copyright 1990 Silicon Graphics, Inc. All rights reserved.
*
* Compute the result of an expr operation.
*/
#include <string.h>
#include <values.h>
#include "expr.h"
#include "macros.h"
#define addrlo(ex) ((ex)->ex_addr.a_low)
#define addrhi(ex) ((ex)->ex_addr.a_high)
#define BITSPERADDRHALF (sizeof(unsigned long) * BITSPERBYTE)
static long
cmp(enum exop op, Expr *ex1, Expr *ex2)
{
if (ex1->ex_op == EXOP_ADDRESS) {
long diff;
diff = addrhi(ex1) - addrhi(ex2);
return diff ? diff : addrlo(ex1) - addrlo(ex2);
}
if (ex1->ex_op == EXOP_STRING) {
int len1, len2;
len1 = ex1->ex_str.s_len, len2 = ex2->ex_str.s_len;
if ((op == EXOP_EQ || op == EXOP_NE) && len1 != len2)
return 1;
return memcmp(ex1->ex_str.s_ptr, ex2->ex_str.s_ptr,
MIN(len1, len2));
}
return -1;
}
/*
* Perform op on operands lex and rex and store the result in ex.
* NB: ex may be the same pointer as lex or rex.
*/
ExprType
ex_operate(Expr *ex, enum exop op, Expr *lex, Expr *rex, ExprError *err)
{
switch (op) {
case EXOP_OR:
ex->ex_op = EXOP_NUMBER;
ex->ex_val = ex_test(lex) && ex_test(rex);
break;
case EXOP_AND:
ex->ex_op = EXOP_NUMBER;
ex->ex_val = ex_test(lex) || ex_test(rex);
break;
case EXOP_EQ:
if (lex->ex_op != rex->ex_op) {
ex_badop(lex, err);
return ET_ERROR;
}
ex->ex_op = EXOP_NUMBER;
ex->ex_val = (lex->ex_op == EXOP_NUMBER) ?
lex->ex_val == rex->ex_val :
!cmp(op, lex, rex);
break;
case EXOP_NE:
if (lex->ex_op != rex->ex_op) {
ex_badop(lex, err);
return ET_ERROR;
}
ex->ex_op = EXOP_NUMBER;
ex->ex_val = (lex->ex_op == EXOP_NUMBER) ?
lex->ex_val != rex->ex_val :
cmp(op, lex, rex);
break;
case EXOP_LE:
if (lex->ex_op != rex->ex_op) {
ex_badop(lex, err);
return ET_ERROR;
}
ex->ex_op = EXOP_NUMBER;
ex->ex_val = (lex->ex_op == EXOP_NUMBER) ?
lex->ex_val <= rex->ex_val :
cmp(op, lex, rex) <= 0;
break;
case EXOP_LT:
if (lex->ex_op != rex->ex_op) {
ex_badop(lex, err);
return ET_ERROR;
}
ex->ex_op = EXOP_NUMBER;
ex->ex_val = (lex->ex_op == EXOP_NUMBER) ?
lex->ex_val < rex->ex_val :
cmp(op, lex, rex) < 0;
break;
case EXOP_GE:
if (lex->ex_op != rex->ex_op) {
ex_badop(lex, err);
return ET_ERROR;
}
ex->ex_op = EXOP_NUMBER;
ex->ex_val = (lex->ex_op == EXOP_NUMBER) ?
lex->ex_val >= rex->ex_val :
cmp(op, lex, rex) >= 0;
break;
case EXOP_GT:
if (lex->ex_op != rex->ex_op) {
ex_badop(lex, err);
return ET_ERROR;
}
ex->ex_op = EXOP_NUMBER;
ex->ex_val = (lex->ex_op == EXOP_NUMBER) ?
lex->ex_val > rex->ex_val :
cmp(op, lex, rex) > 0;
break;
case EXOP_BITOR:
if (lex->ex_op != rex->ex_op || lex->ex_op == EXOP_STRING) {
ex_badop(lex, err);
return ET_ERROR;
}
ex->ex_op = lex->ex_op;
if (ex->ex_op == EXOP_NUMBER)
ex->ex_val = lex->ex_val | rex->ex_val;
else {
addrlo(ex) = addrlo(lex) | addrlo(rex);
addrhi(ex) = addrhi(lex) | addrhi(rex);
}
break;
case EXOP_BITAND:
if (lex->ex_op != rex->ex_op || lex->ex_op == EXOP_STRING) {
ex_badop(lex, err);
return ET_ERROR;
}
ex->ex_op = lex->ex_op;
if (ex->ex_op == EXOP_NUMBER)
ex->ex_val = lex->ex_val & rex->ex_val;
else {
addrlo(ex) = addrlo(lex) & addrlo(rex);
addrhi(ex) = addrhi(lex) & addrhi(rex);
}
break;
case EXOP_BITXOR:
if (lex->ex_op != rex->ex_op || lex->ex_op == EXOP_STRING) {
ex_badop(lex, err);
return ET_ERROR;
}
ex->ex_op = lex->ex_op;
if (ex->ex_op == EXOP_NUMBER)
ex->ex_val = lex->ex_val ^ rex->ex_val;
else {
addrlo(ex) = addrlo(lex) ^ addrlo(rex);
addrhi(ex) = addrhi(lex) ^ addrhi(rex);
}
break;
case EXOP_LSH: {
unsigned long shift;
if (lex->ex_op == EXOP_STRING || rex->ex_op != EXOP_NUMBER) {
ex_badop(lex->ex_op == EXOP_STRING ? lex : rex, err);
return ET_ERROR;
}
shift = rex->ex_val;
ex->ex_op = lex->ex_op;
if (ex->ex_op == EXOP_NUMBER) {
ex->ex_val = lex->ex_val << shift % BITSPERADDRHALF;
} else if (shift >= BITSPERADDRHALF) {
addrhi(ex) = addrlo(lex)
<< (shift - BITSPERADDRHALF) % BITSPERADDRHALF;
addrlo(ex) = 0;
} else {
addrhi(ex) = addrhi(lex) << shift;
addrhi(ex) |= addrlo(lex) >> BITSPERADDRHALF - shift;
addrlo(ex) = addrlo(lex) << shift;
}
break;
}
case EXOP_RSH: {
unsigned long shift;
if (lex->ex_op == EXOP_STRING || rex->ex_op != EXOP_NUMBER) {
ex_badop(lex->ex_op == EXOP_STRING ? lex : rex, err);
return ET_ERROR;
}
shift = rex->ex_val;
ex->ex_op = lex->ex_op;
if (ex->ex_op == EXOP_NUMBER) {
ex->ex_val = lex->ex_val >> shift % BITSPERADDRHALF;
} else if (shift >= BITSPERADDRHALF) {
addrlo(ex) = addrhi(lex)
>> (shift - BITSPERADDRHALF) % BITSPERADDRHALF;
addrhi(ex) = 0;
} else {
addrlo(ex) = addrlo(lex) >> shift;
addrlo(ex) |= addrhi(lex) << BITSPERADDRHALF - shift;
addrhi(ex) = addrhi(lex) >> shift;
}
break;
}
case EXOP_ADD:
if (lex->ex_op == EXOP_STRING || rex->ex_op == EXOP_STRING) {
ex_badop(lex->ex_op == EXOP_STRING ? lex : rex, err);
return ET_ERROR;
}
if (lex->ex_op == EXOP_NUMBER && rex->ex_op == EXOP_NUMBER) {
ex->ex_op = EXOP_NUMBER;
ex->ex_val = lex->ex_val + rex->ex_val;
} else {
unsigned long lhigh, llow, rhigh, rlow, lowsum;
if (lex->ex_op == EXOP_ADDRESS)
lhigh = addrhi(lex), llow = addrlo(lex);
else
lhigh = 0, llow = lex->ex_val;
if (rex->ex_op == EXOP_ADDRESS)
rhigh = addrhi(rex), rlow = addrlo(rex);
else
rhigh = 0, rlow = rex->ex_val;
lowsum = llow + rlow;
ex->ex_op = EXOP_ADDRESS;
addrhi(ex) = lhigh + rhigh + (lowsum < MAX(rlow, llow));
addrlo(ex) = lowsum;
}
break;
case EXOP_SUB:
if (lex->ex_op == EXOP_STRING || rex->ex_op == EXOP_STRING) {
ex_badop(lex->ex_op == EXOP_STRING ? lex : rex, err);
return ET_ERROR;
}
if (lex->ex_op == EXOP_NUMBER && rex->ex_op == EXOP_NUMBER) {
ex->ex_op = EXOP_NUMBER;
ex->ex_val = lex->ex_val - rex->ex_val;
} else {
unsigned long lhigh, llow, rhigh, rlow, lowdiff;
if (lex->ex_op == EXOP_ADDRESS)
lhigh = addrhi(lex), llow = addrlo(lex);
else
lhigh = 0, llow = lex->ex_val;
if (rex->ex_op == EXOP_ADDRESS)
rhigh = addrhi(rex), rlow = addrlo(rex);
else
rhigh = 0, rlow = rex->ex_val;
lowdiff = llow - rlow;
ex->ex_op = EXOP_ADDRESS;
addrhi(ex) = lhigh - rhigh - (lowdiff > llow);
addrlo(ex) = lowdiff;
}
break;
case EXOP_MUL:
if (lex->ex_op == EXOP_STRING || rex->ex_op == EXOP_STRING) {
ex_badop(lex->ex_op == EXOP_STRING ? lex : rex, err);
return ET_ERROR;
}
if (lex->ex_op == EXOP_NUMBER && rex->ex_op == EXOP_NUMBER) {
ex->ex_op = EXOP_NUMBER;
ex->ex_val = lex->ex_val * rex->ex_val;
} else {
unsigned long lhigh, llow, rhigh, rlow;
if (lex->ex_op == EXOP_ADDRESS)
lhigh = addrhi(lex), llow = addrlo(lex);
else
lhigh = 0, llow = lex->ex_val;
if (rex->ex_op == EXOP_ADDRESS)
rhigh = addrhi(rex), rlow = addrlo(rex);
else
rhigh = 0, rlow = rex->ex_val;
ex->ex_op = EXOP_ADDRESS;
addrlo(ex) = llow * rlow;
addrhi(ex) = lhigh * rlow + llow * rhigh
+ (addrlo(ex) <= MAX(llow, rlow)
&& MIN(llow, rlow) != 1);
}
break;
case EXOP_DIV:
if (lex->ex_op == EXOP_STRING || rex->ex_op != EXOP_NUMBER) {
ex_badop(lex->ex_op == EXOP_STRING ? lex : rex, err);
return ET_ERROR;
}
if (rex->ex_val == 0) {
ex_error(rex, "division by zero", err);
return ET_ERROR;
}
if (lex->ex_op == EXOP_NUMBER) {
ex->ex_op = EXOP_NUMBER;
ex->ex_val = lex->ex_val / rex->ex_val;
} else {
/* XXX use algorithm D */
ex_badop(lex, err);
return ET_ERROR;
}
break;
case EXOP_MOD:
if (lex->ex_op == EXOP_STRING || rex->ex_op != EXOP_NUMBER) {
ex_badop(lex->ex_op == EXOP_STRING ? lex : rex, err);
return ET_ERROR;
}
if (rex->ex_val == 0) {
ex_error(rex, "modulus with zero", err);
return ET_ERROR;
}
if (lex->ex_op == EXOP_NUMBER) {
ex->ex_op = EXOP_NUMBER;
ex->ex_val = lex->ex_val % rex->ex_val;
} else {
ex->ex_op = EXOP_ADDRESS;
addrhi(ex) = 0;
addrlo(ex) = addrlo(lex) % rex->ex_val;
}
break;
case EXOP_NOT:
ex->ex_op = EXOP_NUMBER;
ex->ex_val = !ex_test(rex);
break;
case EXOP_BITNOT:
if (rex->ex_op == EXOP_STRING) {
ex_badop(rex, err);
return ET_ERROR;
}
ex->ex_op = rex->ex_op;
if (ex->ex_op == EXOP_NUMBER)
ex->ex_val = ~rex->ex_val;
else {
addrhi(ex) = ~addrhi(rex);
addrlo(ex) = ~addrlo(rex);
}
break;
case EXOP_NEG:
if (rex->ex_op == EXOP_STRING) {
ex_badop(rex, err);
return ET_ERROR;
}
ex->ex_op = rex->ex_op;
if (ex->ex_op == EXOP_NUMBER)
ex->ex_val = -rex->ex_val;
else {
ex->ex_op = EXOP_ADDRESS;
addrlo(ex) = ~addrlo(rex) + 1;
addrhi(ex) = ~addrhi(rex) + (addrlo(ex) == 0);
}
break;
default:
return ET_COMPLEX;
}
ex->ex_arity = EX_NULLARY;
return ET_SIMPLE;
}