Major update, code reorganization and enhancement.
This commit is contained in:
+393
-432
@@ -12,450 +12,391 @@
|
||||
* Author: Julie Sander and Bob Dalesio
|
||||
* Date: 07-27-87
|
||||
*/
|
||||
|
||||
/* This module contains the code for processing the arithmetic
|
||||
* expressions defined in calculation records. postfix must be called
|
||||
* to convert a valid infix expression to postfix. CalcPerform
|
||||
* calculates the postfix expression.
|
||||
*
|
||||
* Subroutines
|
||||
*
|
||||
* Public
|
||||
*
|
||||
* calcPerform perform the calculation
|
||||
* args
|
||||
* double *pargs address of arguments (12)
|
||||
* double *presult address of result
|
||||
* char *rpcl address of reverse polish buffer
|
||||
* returns
|
||||
* 0 fetched successfully
|
||||
* -1 fetch failed
|
||||
*
|
||||
* Private routine for calcPerform
|
||||
* local_random random number generator
|
||||
* returns
|
||||
* double value between 0.00 and 1.00
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "osiUnistd.h"
|
||||
#include "dbDefs.h"
|
||||
#include "epicsMath.h"
|
||||
#define epicsExportSharedSymbols
|
||||
#include "postfix.h"
|
||||
#include "postfixPvt.h"
|
||||
#include "osiUnistd.h"
|
||||
|
||||
static double local_random(void);
|
||||
|
||||
#define NOT_SET 0
|
||||
#define TRUE_COND 1
|
||||
#define FALSE_COND 2
|
||||
static double calcRandom(void);
|
||||
static int cond_search(const char **ppinst, int match);
|
||||
|
||||
#ifndef PI
|
||||
#define PI 3.141592654
|
||||
#define PI 3.14159265358979323
|
||||
#endif
|
||||
|
||||
epicsShareFunc long epicsShareAPI
|
||||
calcPerform(double *parg, double *presult, char *post)
|
||||
|
||||
/* calcPerform
|
||||
*
|
||||
* Evalutate the postfix expression
|
||||
*/
|
||||
epicsShareFunc long
|
||||
calcPerform(double *parg, double *presult, const char *pinst)
|
||||
{
|
||||
double *pstacktop; /* stack of values */
|
||||
double stack[80];
|
||||
short temp1;
|
||||
double *top;
|
||||
int itop; /* integer top value */
|
||||
int inexttop; /* ineteger next to top value */
|
||||
short cond_flag; /* conditional else flag */
|
||||
short got_if;
|
||||
|
||||
/* initialize flag */
|
||||
cond_flag = NOT_SET;
|
||||
pstacktop = &stack[0];
|
||||
|
||||
/* DEBUG print statements
|
||||
for (short i=0;i<184;i++){
|
||||
printf ("%d_",post[i]);
|
||||
if ( post[i] == END_STACK ) break;
|
||||
if ( post[i] == 71 ) i=i+8;
|
||||
}
|
||||
printf ("*FINISHED*\n");
|
||||
*/
|
||||
if(*post == BAD_EXPRESSION) return(-1);
|
||||
|
||||
/* set post to postfix expression in calc structure */
|
||||
top = pstacktop;
|
||||
|
||||
/* polish calculator loop */
|
||||
while (*post != END_STACK){
|
||||
|
||||
switch (*post){
|
||||
case FETCH_A:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[0];
|
||||
break;
|
||||
|
||||
case FETCH_B:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[1];
|
||||
break;
|
||||
|
||||
case FETCH_C:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[2];
|
||||
break;
|
||||
|
||||
case FETCH_D:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[3];
|
||||
break;
|
||||
|
||||
case FETCH_E:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[4];
|
||||
break;
|
||||
|
||||
case FETCH_F:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[5];
|
||||
break;
|
||||
|
||||
case FETCH_G:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[6];
|
||||
break;
|
||||
|
||||
case FETCH_H:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[7];
|
||||
break;
|
||||
|
||||
case FETCH_I:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[8];
|
||||
break;
|
||||
|
||||
case FETCH_J:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[9];
|
||||
break;
|
||||
|
||||
case FETCH_K:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[10];
|
||||
break;
|
||||
|
||||
case FETCH_L:
|
||||
++pstacktop;
|
||||
*pstacktop = parg[11];
|
||||
break;
|
||||
|
||||
case CONST_PI:
|
||||
++pstacktop;
|
||||
*pstacktop = PI;
|
||||
break;
|
||||
|
||||
case CONST_D2R:
|
||||
++pstacktop;
|
||||
*pstacktop = PI/180.;
|
||||
break;
|
||||
|
||||
case CONST_R2D:
|
||||
++pstacktop;
|
||||
*pstacktop = 180./PI;
|
||||
break;
|
||||
|
||||
case ADD:
|
||||
--pstacktop;
|
||||
*pstacktop = *pstacktop + *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case SUB:
|
||||
--pstacktop;
|
||||
*pstacktop = *pstacktop - *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case MULT:
|
||||
--pstacktop;
|
||||
*pstacktop = *pstacktop * *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case DIV:
|
||||
--pstacktop;
|
||||
if (*(pstacktop+1) == 0) /* can't divide by zero */
|
||||
return(-1);
|
||||
*pstacktop = *pstacktop / *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case COND_IF:
|
||||
/* if false condition then skip true expression */
|
||||
if (*pstacktop == 0.0) {
|
||||
/* skip to matching COND_ELSE */
|
||||
for (got_if=1; got_if>0 && *(post+1) != END_STACK; ++post) {
|
||||
if (*(post+1) == CONSTANT ) post+=8;
|
||||
else if (*(post+1) == COND_IF ) got_if++;
|
||||
else if (*(post+1) == COND_ELSE) got_if--;
|
||||
}
|
||||
}
|
||||
/* remove condition from stack top */
|
||||
--pstacktop;
|
||||
break;
|
||||
|
||||
case COND_ELSE:
|
||||
/* result, true condition is on stack so skip false condition */
|
||||
/* skip to matching COND_END */
|
||||
for (got_if=1; got_if>0 && *(post+1) != END_STACK; ++post) {
|
||||
if (*(post+1) == CONSTANT ) post+=8;
|
||||
else if (*(post+1) == COND_IF ) got_if++;
|
||||
else if (*(post+1) == COND_END) got_if--;
|
||||
}
|
||||
break;
|
||||
|
||||
case COND_END:
|
||||
break;
|
||||
|
||||
case ABS_VAL:
|
||||
if (*pstacktop < 0) *pstacktop = -*pstacktop;
|
||||
break;
|
||||
|
||||
case UNARY_NEG:
|
||||
*pstacktop = -1* (*pstacktop);
|
||||
break;
|
||||
|
||||
case SQU_RT:
|
||||
if (*pstacktop < 0) return(-1); /* undefined */
|
||||
*pstacktop = sqrt(*pstacktop);
|
||||
break;
|
||||
|
||||
case EXP:
|
||||
*pstacktop = exp(*pstacktop);
|
||||
break;
|
||||
|
||||
case LOG_10:
|
||||
*pstacktop = log10(*pstacktop);
|
||||
break;
|
||||
|
||||
case LOG_E:
|
||||
*pstacktop = log(*pstacktop);
|
||||
break;
|
||||
|
||||
case RANDOM:
|
||||
++pstacktop;
|
||||
*pstacktop = local_random();
|
||||
break;
|
||||
|
||||
case EXPON:
|
||||
--pstacktop;
|
||||
if (*pstacktop == 0) break;
|
||||
if (*pstacktop < 0){
|
||||
temp1 = (int) *(pstacktop+1);
|
||||
/* is exponent an integer */
|
||||
if ((*(pstacktop+1) - (double)temp1) != 0) return (-1);
|
||||
*pstacktop = exp(*(pstacktop+1) * log(-*pstacktop));
|
||||
/* is value negative */
|
||||
if ((temp1 % 2) > 0) *pstacktop = -*pstacktop;
|
||||
}else{
|
||||
*pstacktop = exp(*(pstacktop+1) * log(*pstacktop));
|
||||
}
|
||||
break;
|
||||
|
||||
case MODULO:
|
||||
--pstacktop;
|
||||
itop = (int)*pstacktop;
|
||||
inexttop = (int)*(pstacktop+1);
|
||||
if (inexttop == 0)
|
||||
return(-1);
|
||||
*pstacktop = itop % inexttop;
|
||||
break;
|
||||
|
||||
case REL_OR:
|
||||
--pstacktop;
|
||||
*pstacktop = (*pstacktop || *(pstacktop+1));
|
||||
break;
|
||||
|
||||
case REL_AND:
|
||||
--pstacktop;
|
||||
*pstacktop = (*pstacktop && *(pstacktop+1));
|
||||
break;
|
||||
|
||||
case BIT_OR:
|
||||
/* force double values into integers and or them */
|
||||
itop = (int)*pstacktop;
|
||||
inexttop = (int)*(pstacktop-1);
|
||||
--pstacktop;
|
||||
*pstacktop = (inexttop | itop);
|
||||
break;
|
||||
|
||||
case BIT_AND:
|
||||
/* force double values into integers and and them */
|
||||
itop = (int)*pstacktop;
|
||||
inexttop = (int)*(pstacktop-1);
|
||||
--pstacktop;
|
||||
*pstacktop = (inexttop & itop);
|
||||
break;
|
||||
|
||||
case BIT_EXCL_OR:
|
||||
/*force double values to integers to exclusive or them*/
|
||||
itop = (int)*pstacktop;
|
||||
inexttop = (int)*(pstacktop-1);
|
||||
--pstacktop;
|
||||
*pstacktop = (inexttop ^ itop);
|
||||
break;
|
||||
|
||||
case GR_OR_EQ:
|
||||
--pstacktop;
|
||||
*pstacktop = *pstacktop >= *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case GR_THAN:
|
||||
--pstacktop;
|
||||
*pstacktop = *pstacktop > *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case LESS_OR_EQ:
|
||||
--pstacktop;
|
||||
*pstacktop = *pstacktop <= *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case LESS_THAN:
|
||||
--pstacktop;
|
||||
*pstacktop = *pstacktop < *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case NOT_EQ:
|
||||
--pstacktop;
|
||||
*pstacktop = *pstacktop != *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case EQUAL:
|
||||
--pstacktop;
|
||||
*pstacktop = (*pstacktop == *(pstacktop+1));
|
||||
break;
|
||||
|
||||
case RIGHT_SHIFT:
|
||||
itop = (int)*pstacktop;
|
||||
inexttop = (int)*(pstacktop-1);
|
||||
--pstacktop;
|
||||
*pstacktop = (inexttop >> itop);
|
||||
break;
|
||||
|
||||
case LEFT_SHIFT:
|
||||
itop = (int)*pstacktop;
|
||||
inexttop = (int)*(pstacktop-1);
|
||||
--pstacktop;
|
||||
*pstacktop = (inexttop << itop);
|
||||
break;
|
||||
|
||||
case MAX:
|
||||
--pstacktop;
|
||||
if (*pstacktop < *(pstacktop+1))
|
||||
*pstacktop = *(pstacktop+1);
|
||||
break;
|
||||
|
||||
case MIN:
|
||||
--pstacktop;
|
||||
if (*pstacktop > *(pstacktop+1))
|
||||
*pstacktop = *(pstacktop+1);
|
||||
break;
|
||||
|
||||
|
||||
case ACOS:
|
||||
*pstacktop = acos(*pstacktop);
|
||||
break;
|
||||
|
||||
case ASIN:
|
||||
*pstacktop = asin(*pstacktop);
|
||||
break;
|
||||
|
||||
case ATAN:
|
||||
*pstacktop = atan(*pstacktop);
|
||||
break;
|
||||
|
||||
case ATAN2:
|
||||
--pstacktop;
|
||||
*pstacktop = atan2(*(pstacktop+1), *pstacktop);
|
||||
break;
|
||||
|
||||
case COS:
|
||||
*pstacktop = cos(*pstacktop);
|
||||
break;
|
||||
|
||||
case SIN:
|
||||
*pstacktop = sin(*pstacktop);
|
||||
break;
|
||||
|
||||
case TAN:
|
||||
*pstacktop = tan(*pstacktop);
|
||||
break;
|
||||
|
||||
case COSH:
|
||||
*pstacktop = cosh(*pstacktop);
|
||||
break;
|
||||
|
||||
case SINH:
|
||||
*pstacktop = sinh(*pstacktop);
|
||||
break;
|
||||
|
||||
case TANH:
|
||||
*pstacktop = tanh(*pstacktop);
|
||||
break;
|
||||
|
||||
case CEIL:
|
||||
*pstacktop = ceil(*pstacktop);
|
||||
break;
|
||||
|
||||
case FLOOR:
|
||||
*pstacktop = floor(*pstacktop);
|
||||
break;
|
||||
|
||||
case NINT:
|
||||
*pstacktop = (double)(long)((*pstacktop) >= 0 ? (*pstacktop)+0.5 : (*pstacktop)-0.5);
|
||||
break;
|
||||
|
||||
case REL_NOT:
|
||||
*pstacktop = ((*pstacktop)?0:1);
|
||||
break;
|
||||
|
||||
case BIT_NOT:
|
||||
itop = (int)*pstacktop;
|
||||
*pstacktop = ~itop;
|
||||
break;
|
||||
|
||||
case CONSTANT:
|
||||
++pstacktop;
|
||||
++post;
|
||||
if ( post == NULL ) {
|
||||
++post;
|
||||
printf("%.7s bad constant in expression\n",post);
|
||||
break;
|
||||
}
|
||||
memcpy((void *)pstacktop,post,8);
|
||||
post+=7;
|
||||
break;
|
||||
default:
|
||||
printf("%d bad expression element\n",*post);
|
||||
break;
|
||||
}
|
||||
|
||||
/* move ahead in postfix expression */
|
||||
++post;
|
||||
double stack[CALCPERFORM_STACK]; /* zero'th entry not used */
|
||||
double *ptop; /* stack pointer */
|
||||
double top; /* value from top of stack */
|
||||
int itop; /* integer from top of stack */
|
||||
|
||||
/* initialize */
|
||||
ptop = stack;
|
||||
|
||||
if(*pinst == END_EXPRESSION) return -1;
|
||||
|
||||
/* RPN evaluation loop */
|
||||
while (*pinst != END_EXPRESSION){
|
||||
switch (*pinst){
|
||||
|
||||
case LITERAL:
|
||||
++ptop;
|
||||
++pinst;
|
||||
memcpy((void *)ptop, pinst, sizeof(double));
|
||||
pinst += sizeof(double) - 1;
|
||||
break;
|
||||
|
||||
case FETCH_A:
|
||||
case FETCH_B:
|
||||
case FETCH_C:
|
||||
case FETCH_D:
|
||||
case FETCH_E:
|
||||
case FETCH_F:
|
||||
case FETCH_G:
|
||||
case FETCH_H:
|
||||
case FETCH_I:
|
||||
case FETCH_J:
|
||||
case FETCH_K:
|
||||
case FETCH_L:
|
||||
*++ptop = parg[*pinst - FETCH_A];
|
||||
break;
|
||||
|
||||
case STORE_A:
|
||||
case STORE_B:
|
||||
case STORE_C:
|
||||
case STORE_D:
|
||||
case STORE_E:
|
||||
case STORE_F:
|
||||
case STORE_G:
|
||||
case STORE_H:
|
||||
case STORE_I:
|
||||
case STORE_J:
|
||||
case STORE_K:
|
||||
case STORE_L:
|
||||
parg[*pinst - STORE_A] = *ptop--;
|
||||
break;
|
||||
|
||||
case CONST_PI:
|
||||
*++ptop = PI;
|
||||
break;
|
||||
|
||||
case CONST_D2R:
|
||||
*++ptop = PI/180.;
|
||||
break;
|
||||
|
||||
case CONST_R2D:
|
||||
*++ptop = 180./PI;
|
||||
break;
|
||||
|
||||
case UNARY_NEG:
|
||||
*ptop = - *ptop;
|
||||
break;
|
||||
|
||||
case ADD:
|
||||
top = *ptop--;
|
||||
*ptop += top;
|
||||
break;
|
||||
|
||||
case SUB:
|
||||
top = *ptop--;
|
||||
*ptop -= top;
|
||||
break;
|
||||
|
||||
case MULT:
|
||||
top = *ptop--;
|
||||
*ptop *= top;
|
||||
break;
|
||||
|
||||
case DIV:
|
||||
top = *ptop--;
|
||||
*ptop /= top;
|
||||
break;
|
||||
|
||||
case MODULO:
|
||||
top = *ptop--;
|
||||
*ptop = fmod(*ptop, top);
|
||||
break;
|
||||
|
||||
case POWER:
|
||||
top = *ptop--;
|
||||
*ptop = pow(*ptop, top);
|
||||
break;
|
||||
|
||||
case ABS_VAL:
|
||||
if (*ptop < 0.0) *ptop = - *ptop;
|
||||
break;
|
||||
|
||||
case EXP:
|
||||
*ptop = exp(*ptop);
|
||||
break;
|
||||
|
||||
case LOG_10:
|
||||
*ptop = log10(*ptop);
|
||||
break;
|
||||
|
||||
case LOG_E:
|
||||
*ptop = log(*ptop);
|
||||
break;
|
||||
|
||||
case MAX:
|
||||
top = *ptop--;
|
||||
if (*ptop < top || isnan(top))
|
||||
*ptop = top;
|
||||
break;
|
||||
|
||||
case MIN:
|
||||
top = *ptop--;
|
||||
if (*ptop > top || isnan(top))
|
||||
*ptop = top;
|
||||
break;
|
||||
|
||||
case SQU_RT:
|
||||
*ptop = sqrt(*ptop);
|
||||
break;
|
||||
|
||||
case ACOS:
|
||||
*ptop = acos(*ptop);
|
||||
break;
|
||||
|
||||
case ASIN:
|
||||
*ptop = asin(*ptop);
|
||||
break;
|
||||
|
||||
case ATAN:
|
||||
*ptop = atan(*ptop);
|
||||
break;
|
||||
|
||||
case ATAN2:
|
||||
top = *ptop--;
|
||||
*ptop = atan2(top, *ptop); /* Ouch!: Args backwards! */
|
||||
break;
|
||||
|
||||
case COS:
|
||||
*ptop = cos(*ptop);
|
||||
break;
|
||||
|
||||
case SIN:
|
||||
*ptop = sin(*ptop);
|
||||
break;
|
||||
|
||||
case TAN:
|
||||
*ptop = tan(*ptop);
|
||||
break;
|
||||
|
||||
case COSH:
|
||||
*ptop = cosh(*ptop);
|
||||
break;
|
||||
|
||||
case SINH:
|
||||
*ptop = sinh(*ptop);
|
||||
break;
|
||||
|
||||
case TANH:
|
||||
*ptop = tanh(*ptop);
|
||||
break;
|
||||
|
||||
case CEIL:
|
||||
*ptop = ceil(*ptop);
|
||||
break;
|
||||
|
||||
case FLOOR:
|
||||
*ptop = floor(*ptop);
|
||||
break;
|
||||
|
||||
case FINITE:
|
||||
*ptop = finite(*ptop);
|
||||
break;
|
||||
|
||||
case ISINF:
|
||||
*ptop = isinf(*ptop);
|
||||
break;
|
||||
|
||||
case ISNAN:
|
||||
*ptop = isnan(*ptop);
|
||||
break;
|
||||
|
||||
case NINT:
|
||||
top = *ptop;
|
||||
*ptop = (double)(long)(top >= 0 ? top + 0.5 : top - 0.5);
|
||||
break;
|
||||
|
||||
case RANDOM:
|
||||
*++ptop = calcRandom();
|
||||
break;
|
||||
|
||||
case REL_OR:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop || top;
|
||||
break;
|
||||
|
||||
case REL_AND:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop && top;
|
||||
break;
|
||||
|
||||
case REL_NOT:
|
||||
*ptop = ! *ptop;
|
||||
break;
|
||||
|
||||
case BIT_OR:
|
||||
itop = (int) *ptop--;
|
||||
*ptop = (int) *ptop | itop;
|
||||
break;
|
||||
|
||||
case BIT_AND:
|
||||
itop = (int) *ptop--;
|
||||
*ptop = (int) *ptop & itop;
|
||||
break;
|
||||
|
||||
case BIT_EXCL_OR:
|
||||
itop = (int) *ptop--;
|
||||
*ptop = (int) *ptop ^ itop;
|
||||
break;
|
||||
|
||||
case BIT_NOT:
|
||||
itop = (int) *ptop;
|
||||
*ptop = ~itop;
|
||||
break;
|
||||
|
||||
case RIGHT_SHIFT:
|
||||
itop = (int) *ptop--;
|
||||
*ptop = (int) *ptop >> itop;
|
||||
break;
|
||||
|
||||
case LEFT_SHIFT:
|
||||
itop = (int) *ptop--;
|
||||
*ptop = (int) *ptop << itop;
|
||||
break;
|
||||
|
||||
case NOT_EQ:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop != top;
|
||||
break;
|
||||
|
||||
case LESS_THAN:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop < top;
|
||||
break;
|
||||
|
||||
case LESS_OR_EQ:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop <= top;
|
||||
break;
|
||||
|
||||
case EQUAL:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop == top;
|
||||
break;
|
||||
|
||||
case GR_OR_EQ:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop >= top;
|
||||
break;
|
||||
|
||||
case GR_THAN:
|
||||
top = *ptop--;
|
||||
*ptop = *ptop > top;
|
||||
break;
|
||||
|
||||
case COND_IF:
|
||||
if (*ptop-- == 0.0 &&
|
||||
cond_search(&pinst, COND_ELSE)) return -1;
|
||||
break;
|
||||
|
||||
case COND_ELSE:
|
||||
if (cond_search(&pinst, COND_END)) return -1;
|
||||
break;
|
||||
|
||||
case COND_END:
|
||||
break;
|
||||
|
||||
default:
|
||||
errlogPrintf("calcPerform: Bad Opcode %d at %p\n",*pinst, pinst);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if everything is peachy,the stack should end at its first position */
|
||||
if (++top == pstacktop)
|
||||
*presult = *pstacktop;
|
||||
else
|
||||
return(-1);
|
||||
return(((isnan(*presult)||isinf(*presult)) ? -1 : 0));
|
||||
/* Advance to next opcode */
|
||||
++pinst;
|
||||
}
|
||||
|
||||
/* The stack should now have one item on it, the expression value */
|
||||
if (ptop != stack + 1)
|
||||
return -1;
|
||||
*presult = *ptop;
|
||||
return (isnan(*presult) || isinf(*presult)) ? -1 : 0; /* FIXME */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RAND
|
||||
*
|
||||
* generates a random number between 0 and 1 using the
|
||||
epicsShareFunc long
|
||||
calcArgUsage(const char *pinst, unsigned long *pinputs, unsigned long *pstores)
|
||||
{
|
||||
unsigned long inputs = 0;
|
||||
unsigned long stores = 0;
|
||||
char op;
|
||||
while ((op = *pinst) != END_EXPRESSION) {
|
||||
switch (op) {
|
||||
|
||||
case LITERAL:
|
||||
pinst += sizeof(double);
|
||||
break;
|
||||
|
||||
case FETCH_A:
|
||||
case FETCH_B:
|
||||
case FETCH_C:
|
||||
case FETCH_D:
|
||||
case FETCH_E:
|
||||
case FETCH_F:
|
||||
case FETCH_G:
|
||||
case FETCH_H:
|
||||
case FETCH_I:
|
||||
case FETCH_J:
|
||||
case FETCH_K:
|
||||
case FETCH_L:
|
||||
/* Don't claim to use an arg we already stored to */
|
||||
inputs |= (1 << (op - FETCH_A)) & ~stores;
|
||||
break;
|
||||
|
||||
case STORE_A:
|
||||
case STORE_B:
|
||||
case STORE_C:
|
||||
case STORE_D:
|
||||
case STORE_E:
|
||||
case STORE_F:
|
||||
case STORE_G:
|
||||
case STORE_H:
|
||||
case STORE_I:
|
||||
case STORE_J:
|
||||
case STORE_K:
|
||||
case STORE_L:
|
||||
stores |= (1 << (op - STORE_A));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pinst++;
|
||||
}
|
||||
if (pinputs) *pinputs = inputs;
|
||||
if (pstores) *pstores = stores;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate a random number between 0 and 1 using the algorithm
|
||||
* seed = (multy * seed) + addy Random Number Generator by Knuth
|
||||
* SemiNumerical Algorithms
|
||||
* Chapter 1
|
||||
@@ -464,14 +405,34 @@ printf ("*FINISHED*\n");
|
||||
static unsigned short seed = 0xa3bf;
|
||||
static unsigned short multy = 191 * 8 + 5; /* 191 % 8 == 5 */
|
||||
static unsigned short addy = 0x3141;
|
||||
static double local_random()
|
||||
|
||||
static double calcRandom()
|
||||
{
|
||||
double randy;
|
||||
seed = (seed * multy) + addy;
|
||||
|
||||
/* random number */
|
||||
seed = (seed * multy) + addy;
|
||||
randy = (float) seed / 65535.0;
|
||||
|
||||
/* between 0 - 1 */
|
||||
return(randy);
|
||||
/* between 0 - 1 */
|
||||
return (double) seed / 65535.0;
|
||||
}
|
||||
|
||||
/* Search the instruction stream for a matching operator, skipping any
|
||||
* other conditional instructions found
|
||||
*/
|
||||
static int cond_search(const char **ppinst, int match)
|
||||
{
|
||||
const char *pinst = *ppinst + 1;
|
||||
int count = 1;
|
||||
int op;
|
||||
|
||||
while ((op = *pinst) != END_EXPRESSION) {
|
||||
if (op == match && --count == 0) {
|
||||
*ppinst = pinst;
|
||||
return 0;
|
||||
} else if (op == COND_IF)
|
||||
count++;
|
||||
else if (op == LITERAL)
|
||||
pinst += sizeof(double);
|
||||
pinst++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+497
-482
File diff suppressed because it is too large
Load Diff
@@ -16,15 +16,61 @@
|
||||
#define INCpostfixh
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#define CALCPERFORM_NARGS 12
|
||||
#define CALCPERFORM_STACK 80
|
||||
|
||||
#define INFIX_TO_POSTFIX_SIZE(n) (((n-2)>>2)*21 + ((n-2)&2)*5 + 10)
|
||||
/* The above is calculated from the following expression fragments:
|
||||
* 1?1: 4 chars expand to 21 chars
|
||||
* 1+ 2 chars expand to 10 chars
|
||||
* 1 1 char expands to 9 chars
|
||||
* All other infix operators convert by a factor of 1:1 or less.
|
||||
* Allow 1 char each for the infix and postfix terminators,
|
||||
* and the infix must be a complete expression
|
||||
*/
|
||||
|
||||
#define MAX_INFIX_SIZE 100
|
||||
#define MAX_POSTFIX_SIZE INFIX_TO_POSTFIX_SIZE(MAX_INFIX_SIZE)
|
||||
|
||||
|
||||
/* Error numbers from postfix */
|
||||
|
||||
#define CALC_ERR_NONE 0 /* No error */
|
||||
#define CALC_ERR_TOOMANY 1 /* Too many results returned */
|
||||
#define CALC_ERR_BAD_LITERAL 2 /* Bad numeric literal */
|
||||
#define CALC_ERR_BAD_ASSIGNMENT 3 /* Bad assignment target */
|
||||
#define CALC_ERR_BAD_SEPERATOR 4 /* Comma without parentheses */
|
||||
#define CALC_ERR_PAREN_NOT_OPEN 5 /* Close parenthesis without open */
|
||||
#define CALC_ERR_PAREN_OPEN 6 /* Open parenthesis at end of expression */
|
||||
#define CALC_ERR_CONDITIONAL 7 /* Unbalanced conditional ?: operators */
|
||||
#define CALC_ERR_INCOMPLETE 8 /* Incomplete expression, operand missing */
|
||||
#define CALC_ERR_UNDERFLOW 9 /* Runtime stack would underflow */
|
||||
#define CALC_ERR_OVERFLOW 10 /* Runtime stack would overflow */
|
||||
#define CALC_ERR_SYNTAX 11 /* Syntax error */
|
||||
#define CALC_ERR_NULL_ARG 12 /* NULL or empty input argument */
|
||||
#define CALC_ERR_INTERNAL 13 /* Internal error, bad element type */
|
||||
/* Changes in the above errors must also be made in calcErrorStr() */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareFunc long epicsShareAPI
|
||||
postfix (const char *pinfix, char *ppostfix, short *perror);
|
||||
epicsShareFunc long
|
||||
postfix(const char *pinfix, char *ppostfix, short *perror);
|
||||
|
||||
epicsShareFunc long epicsShareAPI
|
||||
calcPerform(double *parg, double *presult, char *post);
|
||||
epicsShareFunc long
|
||||
calcPerform(double *parg, double *presult, const char *ppostfix);
|
||||
|
||||
epicsShareFunc long
|
||||
calcArgUsage(const char *ppostfix, unsigned long *pinputs, unsigned long *pstores);
|
||||
|
||||
epicsShareFunc const char *
|
||||
calcErrorStr(short error);
|
||||
|
||||
epicsShareFunc void
|
||||
calcExprDump(const char *pinst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -12,90 +12,91 @@
|
||||
* Date: 9-21-88
|
||||
*/
|
||||
|
||||
/* Notes:
|
||||
* 1. The FETCH_A through FETCH_L and STORE_A through STORE_L opcodes must
|
||||
* be contiguous.
|
||||
* 2. The LITERAL opcode is followed by its double value.
|
||||
* 3. You can't quite use strlen() on an RPN buffer, since the literal
|
||||
* double value can contain nil bytes.
|
||||
*/
|
||||
|
||||
#ifndef INCpostfixPvth
|
||||
#define INCpostfixPvth
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
/* defines for element table */
|
||||
#define BAD_EXPRESSION 0
|
||||
#define FETCH_A 1
|
||||
#define FETCH_B 2
|
||||
#define FETCH_C 3
|
||||
#define FETCH_D 4
|
||||
#define FETCH_E 5
|
||||
#define FETCH_F 6
|
||||
#define FETCH_G 7
|
||||
#define FETCH_H 8
|
||||
#define FETCH_I 9
|
||||
#define FETCH_J 10
|
||||
#define FETCH_K 11
|
||||
#define FETCH_L 12
|
||||
#define ACOS 13
|
||||
#define ASIN 14
|
||||
#define ATAN 15
|
||||
#define COS 16
|
||||
#define COSH 17
|
||||
#define SIN 18
|
||||
#define STORE_A 19
|
||||
#define STORE_B 20
|
||||
#define STORE_C 21
|
||||
#define STORE_D 22
|
||||
#define STORE_E 23
|
||||
#define STORE_F 24
|
||||
#define STORE_G 25
|
||||
#define STORE_H 26
|
||||
#define STORE_I 27
|
||||
#define STORE_J 28
|
||||
#define STORE_K 29
|
||||
#define STORE_L 30
|
||||
#define RIGHT_SHIFT 31
|
||||
#define LEFT_SHIFT 32
|
||||
#define SINH 33
|
||||
#define TAN 34
|
||||
#define TANH 35
|
||||
#define LOG_2 36
|
||||
#define COND_ELSE 37
|
||||
#define ABS_VAL 38
|
||||
#define UNARY_NEG 39
|
||||
#define SQU_RT 40
|
||||
#define EXP 41
|
||||
#define CEIL 42
|
||||
#define FLOOR 43
|
||||
#define LOG_10 44
|
||||
#define LOG_E 45
|
||||
#define RANDOM 46
|
||||
#define ADD 47
|
||||
#define SUB 48
|
||||
#define MULT 49
|
||||
#define DIV 50
|
||||
#define EXPON 51
|
||||
#define MODULO 52
|
||||
#define BIT_OR 53
|
||||
#define BIT_AND 54
|
||||
#define BIT_EXCL_OR 55
|
||||
#define GR_OR_EQ 56
|
||||
#define GR_THAN 57
|
||||
#define LESS_OR_EQ 58
|
||||
#define LESS_THAN 59
|
||||
#define NOT_EQ 60
|
||||
#define EQUAL 61
|
||||
#define REL_OR 62
|
||||
#define REL_AND 63
|
||||
#define REL_NOT 64
|
||||
#define BIT_NOT 65
|
||||
#define PAREN 66
|
||||
#define MAX 67
|
||||
#define MIN 68
|
||||
#define COMMA 69
|
||||
#define COND_IF 70
|
||||
#define COND_END 71
|
||||
#define CONSTANT 72
|
||||
#define CONST_PI 73
|
||||
#define CONST_D2R 74
|
||||
#define CONST_R2D 75
|
||||
#define NINT 76
|
||||
#define ATAN2 77
|
||||
#define END_STACK 127
|
||||
/* RPN opcodes */
|
||||
typedef enum {
|
||||
END_EXPRESSION = 0,
|
||||
/* Operands */
|
||||
LITERAL,
|
||||
FETCH_A, FETCH_B, FETCH_C, FETCH_D, FETCH_E, FETCH_F,
|
||||
FETCH_G, FETCH_H, FETCH_I, FETCH_J, FETCH_K, FETCH_L,
|
||||
/* Assignment */
|
||||
STORE_A, STORE_B, STORE_C, STORE_D, STORE_E, STORE_F,
|
||||
STORE_G, STORE_H, STORE_I, STORE_J, STORE_K, STORE_L,
|
||||
/* Trigonometry Constants */
|
||||
CONST_PI,
|
||||
CONST_D2R,
|
||||
CONST_R2D,
|
||||
/* Arithmetic */
|
||||
UNARY_NEG,
|
||||
ADD,
|
||||
SUB,
|
||||
MULT,
|
||||
DIV,
|
||||
MODULO,
|
||||
POWER,
|
||||
/* Algebraic */
|
||||
ABS_VAL,
|
||||
EXP,
|
||||
LOG_10,
|
||||
LOG_E,
|
||||
MAX,
|
||||
MIN,
|
||||
SQU_RT,
|
||||
/* Trigonometric */
|
||||
ACOS,
|
||||
ASIN,
|
||||
ATAN,
|
||||
ATAN2,
|
||||
COS,
|
||||
COSH,
|
||||
SIN,
|
||||
SINH,
|
||||
TAN,
|
||||
TANH,
|
||||
/* Numeric */
|
||||
CEIL,
|
||||
FLOOR,
|
||||
FINITE,
|
||||
ISINF,
|
||||
ISNAN,
|
||||
NINT,
|
||||
RANDOM,
|
||||
/* Boolean */
|
||||
REL_OR,
|
||||
REL_AND,
|
||||
REL_NOT,
|
||||
/* Bitwise */
|
||||
BIT_OR,
|
||||
BIT_AND,
|
||||
BIT_EXCL_OR,
|
||||
BIT_NOT,
|
||||
RIGHT_SHIFT,
|
||||
LEFT_SHIFT,
|
||||
/* Relationals */
|
||||
NOT_EQ,
|
||||
LESS_THAN,
|
||||
LESS_OR_EQ,
|
||||
EQUAL,
|
||||
GR_OR_EQ,
|
||||
GR_THAN,
|
||||
/* Conditional */
|
||||
COND_IF,
|
||||
COND_ELSE,
|
||||
COND_END,
|
||||
/* Misc */
|
||||
NOT_GENERATED
|
||||
} rpn_opcode;
|
||||
|
||||
#endif /* INCpostfixPvth */
|
||||
|
||||
Reference in New Issue
Block a user