# include # include # include # include # include # include "../decomp/globs.h" # include # include SCCSID(@(#)interp.c 8.4 2/8/85) /* ** ** INTERPRET ** ** Processes the retrieved tuple from the De.ov_source relation ** according to the symbols in the list. Recognition ** of characteristic delimiters and separators initiates ** action appropriate to a target list or qualification list ** as the case may be. ** ** Between delimiters, the symbol list is expected to be in ** Polish postfix form. A qualification list is further ** expected to be in conjunctive normal form, with Boolean ** operators infixed. ** */ double pow(); double sqrt(); double log(); double exp(); double sin(); double cos(); double atan(); # define SPUSH(v) (++((struct stacksym *) v)) # define SPOP(v) (((struct stacksym *) v)--) SYMBOL * interpret(istlist,list) int istlist; /* signals a target list: used for string substitution */ SYMBOL **list; /* ptr to list of sym pointers */ { register SYMBOL *tos; SYMBOL *op1,*op2; /*operands popped off stack*/ register ANYTYPE *val1,*val2; /*ptrs to values of operands*/ int opval, optype, l1; char *s1; int byflag; long hitid; extern char *Usercode; extern ov_err(); int cb_mark; extern char *ov_ovqpbuf; extern char *locv(); int i; # ifdef xOTR1 if (tTf(72, 0)) { printf("INTERP: list=%x\n",list); printf(" istlist = %d\n", istlist); } # endif byflag = (list == De.ov_bylist); /* set byflag if aggregate function */ tos = (SYMBOL *)(De.ov_stack-1); /* reset the concat and ascii operator buffer */ seterr(De.ov_ovqpbuf, CBUFULL, ov_err); cb_mark = markbuf(De.ov_ovqpbuf); loop: # ifdef xOTR1 if (tTf(72, 1) && tos >= (SYMBOL *) De.ov_stack) { printf("\ttops of stack="); prstack(tos); /* print top of stack element */ } # endif /* check for stack overflow */ l1 = getsymbol(SPUSH(tos), &list); /* getsymbol changes the value of list */ if (l1) { freebuf(De.ov_ovqpbuf, cb_mark); return (tos); } optype = tos->type; opval = tos->value.sym_data.i2type; op1 = tos; SPOP(tos); /* assume that stack will be popped */ switch(optype) { case CHAR: /* do any chars have to be inserted? */ if (istlist && (Patnum || Globnum)) { insert_chars(op1); } case INT: case FLOAT: SPUSH(tos); /* just leave symbol on stack */ goto loop; case COP: SPUSH(tos); /* new symbol goes on stack */ tos->type = CHAR; switch (opval) { case opDBA: tos->value.sym_data.cptype = Admin.adhdr.adowner; tos->len = 2; goto loop; case opUSERCODE: tos->value.sym_data.cptype = Usercode; tos->len = 2; goto loop; } case AND: /* if top value false return immediately */ if (!tos->value.sym_data.i2type) { freebuf(De.ov_ovqpbuf, cb_mark); return(tos); } else SPOP(tos); freebuf(De.ov_ovqpbuf, cb_mark); goto loop; case OR: /* if top value is true then skip to ** end of disjunction. */ if (tos->value.sym_data.i2type) { SPUSH(tos); do { getsymbol(tos, &list); /* getsymbol changes the value of list */ } while (tos->type != AND); optype = AND; SPOP(tos); } SPOP(tos); goto loop; case RESDOM: freebuf(De.ov_ovqpbuf, cb_mark); /* init the concat and ascii buffer */ if (De.ov_result) { if (opval) /* if gt zero then opval represents a real domain */ { if (byflag) opval++; /* skip over count field for ag functs */ rcvt(tos, De.ov_result->relfrmt[opval], De.ov_result->relfrml[opval]); tout(tos, De.ov_outtup+De.ov_result->reloff[opval], De.ov_result->relfrml[opval]); } else /* opval refers to the tid and this is an update */ { De.ov_uptid = tos->value.sym_data.i4type; /* copy tid */ if (De.de_qmode == mdREPL || (De.ov_diffrel && De.de_qmode == mdDEL && De.ov_result->reldum.relindxd > 0 )) { /* De.ov_origtup must be left with the orig ** unaltered tuple, and De.ov_outtup must ** be initialized with the orig tuple. ** ** De.ov_outtup only matters with REPL. ** Scan() sets up De.ov_origtup so when ** De.ov_source == De.ov_result, origtup is already ** correct. */ if (De.ov_diffrel) { if (l1 = get(De.ov_result, &De.ov_uptid, &hitid, De.ov_origtup, CURTUP)) syserr("interp:get on resdom %s, %d", locv(De.ov_uptid), l1); bmove(De.ov_origtup, De.ov_outtup, De.ov_result->reldum.relwid); } else { bmove(De.ov_intup, De.ov_outtup, De.ov_result->reldum.relwid); } } } } else { /* ** This is really here for the 68k machines, ** this works on the VAX, but nowhere else... */ if ( tos->type == INT && tos->len == 1) tos->value.sym_data.i1type = tos->value.sym_data.i2type; if (Equel) equelatt(tos); /* send attribute to equel */ else { if (tos->type == CHAR) s1 = tos->value.sym_data.cptype; else s1 = tos->value.sym_data.c0type; printatt(tos->type, tos->len & I1MASK, s1); /* print attribute */ } } SPOP(tos); goto loop; case BOP: op2 = (SYMBOL *)SPOP(tos); op1 = (SYMBOL *)tos; typecheck(op1, op2, opval); val1 = &op1->value.sym_data; val2 = &op2->value.sym_data; switch (tos->type) { case INT: switch (tos->len) { case 1: case 2: switch (opval) { case opADD: val1->i2type += val2->i2type; goto loop; case opSUB: val1->i2type -= val2->i2type; goto loop; case opMUL: val1->i2type *= val2->i2type; goto loop; case opDIV: val1->i2type /= val2->i2type; goto loop; case opMOD: val1->i2type %= val2->i2type; goto loop; case opPOW: itof(op1); itof(op2); val1->f8type = pow(val1->f8type, val2->f8type); goto loop; /* relational operator */ default: l1 = val1->i2type - val2->i2type; val1->i2type = relop_interp(opval, l1); goto loop; } case 4: switch(opval) { case opADD: val1->i4type += val2->i4type; goto loop; case opSUB: val1->i4type -= val2->i4type; goto loop; case opMUL: val1->i4type *= val2->i4type; goto loop; case opDIV: val1->i4type /= val2->i4type; goto loop; case opMOD: val1->i4type %= val2->i4type; goto loop; case opPOW: itof(op1); itof(op2); val1->f8type = pow(val1->f8type, val2->f8type); goto loop; /* relational operator */ default: tos->len = 2; if (val1->i4type > val2->i4type) l1 = 1; else if (val1->i4type == val2->i4type) l1 = 0; else l1 = -1; val1->i2type = relop_interp(opval, l1); goto loop; } } case FLOAT: switch (opval) { case opADD: val1->f8type += val2->f8type; goto loop; case opSUB: val1->f8type -= val2->f8type; goto loop; case opMUL: val1->f8type *= val2->f8type; goto loop; case opDIV: val1->f8type /= val2->f8type; goto loop; case opPOW: val1->f8type = pow(val1->f8type, val2->f8type); goto loop; default: tos->type = INT; tos->len = 2; if (val1->f8type > val2->f8type) l1 = 1; else if (val1->f8type == val2->f8type) l1 = 0; else l1 = -1; val1->i2type = relop_interp(opval, l1); goto loop; } case CHAR: switch (opval) { case opSUB: newstring(op1, op2); goto loop; case opADD: case opCONCAT: concatsym(op1, op2); /* concatenate the two symbols */ goto loop; default: l1 = lexcomp(val1->cptype, size(op1), val2->cptype, op2->len & I1MASK,0); tos->type = INT; tos->len = 2; val1->i2type = relop_interp(opval, l1); goto loop; } } /* end of BOP */ case UOP: val1 = &tos->value.sym_data; switch (opval) { case opMINUS: case opABS: if (tos->type == CHAR) ov_err(BADUOPC); l1 = opval == opMINUS; switch (tos->type) { case INT: switch (tos->len) { case 1: case 2: if (l1 || val1->i2type < 0) val1->i2type = -val1->i2type; goto loop; case 4: if (l1 || val1->i4type < 0) val1->i4type = -val1->i4type; goto loop; } case FLOAT: if (l1 || val1->f8type < 0.0) val1->f8type = -val1->f8type; goto loop; } case opNOT: val1->i2type = !val1->i2type; case opPLUS: if (tos->type == CHAR) ov_err(BADUOPC); goto loop; case opASCII: ascii(tos); goto loop; case opINT1: typecoerce(tos, INT, 1); goto loop; case opINT2: typecoerce(tos, INT, 2); goto loop; case opINT4: typecoerce(tos, INT, 4); goto loop; case opFLOAT4: typecoerce(tos, FLOAT, 4); goto loop; case opFLOAT8: typecoerce(tos, FLOAT, 8); goto loop; default: if (tos->type == CHAR) ov_err(BADUOPC); if (tos->type == INT) itof(tos); switch (opval) { case opATAN: val1->f8type = atan(val1->f8type); goto loop; case opLOG: val1->f8type = log(val1->f8type); goto loop; case opSIN: val1->f8type = sin(val1->f8type); goto loop; case opCOS: val1->f8type = cos(val1->f8type); goto loop; case opSQRT: val1->f8type = sqrt(val1->f8type); goto loop; case opEXP: val1->f8type = exp(val1->f8type); goto loop; default: syserr("interp:bad uop %d",opval); } } case AOP: aop_interp(opval, tos); SPOP(tos); /* pop this symbol */ goto loop; } syserr("interp: fell out"); /*NOTREACHED*/ } /* ** relop_interp interprets the relational operators ** (ie. EQ, NE etc.) and returns true or false ** by evaluating l1. ** ** l1 should be greater than, equal or less than zero. */ relop_interp(opval, l1) int opval; int l1; { register int i; i = l1; switch (opval) { case opEQ: return (i == 0); case opNE: return (i != 0); case opLT: return (i < 0); case opLE: return (i <= 0); case opGT: return (i > 0); case opGE: return (i >= 0); default: syserr("relop:bad relop or bop %d", opval); } /*NOTREACHED*/ } /* ** Aggregate values are stored in De.ov_outtup. De.ov_tend points ** to the spot for the next aggregate. Aop_interp() ** computes the value for the aggregate and leaves ** the result in the position pointed to by De.ov_tend. */ aop_interp(opval, tos) int opval; register SYMBOL *tos; { register int i; int l1; ANYTYPE numb; /* used for type conversion */ bmove(De.ov_tend, (char *) &numb, 8); /* note: this assumes that there are always 8 bytes which can be moved. ** if it moves beyond De.ov_tend, it's ok */ switch (opval) { case opSUMU: case opSUM: if (*De.ov_counter <= 1) goto puta; switch (tos->type) { case INT: switch(tos->len) { case 1: tos->value.sym_data.i2type += numb.i1type; goto puta; case 2: tos->value.sym_data.i2type += numb.i2type; goto puta; case 4: tos->value.sym_data.i4type += numb.i4type; goto puta; } case FLOAT: if (tos->len == 4) numb.f8type = numb.f4type; tos->value.sym_data.f8type += numb.f8type; goto puta; default: ov_err(BADSUMC); /* cant sum char fields */ } case opCOUNTU: case opCOUNT: tos->type = CNTTYPE; tos->len = CNTLEN; tos->value.sym_data.i4type = *De.ov_counter; goto puta; case opANY: tos->type = OANYTYPE; tos->len = OANYLEN; if (*De.ov_counter) { tos->value.sym_data.i2type = 1; if (!De.ov_bylist && (De.ov_agcount == 1)) De.ov_targvc = 0; /* if simple agg. stop scan */ } else tos->value.sym_data.i2type = 0; goto puta; case opMIN: case opMAX: if (*De.ov_counter<=1) goto puta; switch (tos->type) { case INT: switch (tos->len) { case 1: i = (tos->value.sym_data.i1type < numb.i1type); break; case 2: i = (tos->value.sym_data.i2type < numb.i2type); break; case 4: i = (tos->value.sym_data.i4type < numb.i4type); break; } break; case FLOAT: if (tos->len == 4) numb.f8type = numb.f4type; i = (tos->value.sym_data.f8type < numb.f8type); break; case CHAR: l1 = size(tos); i = (lexcomp(tos->value.sym_data.cptype, l1, De.ov_tend, l1,0) < 0); break; default: syserr("interp:bad op type for opMIN/MAX %d", tos->type); } /* check result of comparison */ if (opval == opMAX) i = !i; /* complement test for opMAX */ if (i) goto puta; /* condition true. new value */ /* condition false. Keep old value */ goto done; case opAVGU: case opAVG: if (tos->type == INT) itof(tos); else if (tos->type == CHAR) ov_err(BADAVG); if (*De.ov_counter > 1) { tos->value.sym_data.f8type = numb.f8type + (tos->value.sym_data.f8type - numb.f8type) / *De.ov_counter; } tos->len = 8; goto puta; default: syserr("interp:bad agg op %d", tos->type); } puta: tout(tos, De.ov_tend, tos->len); done: De.ov_tend += tos->len & I1MASK; }