diff --git a/src/libCom/calc/calcPerform.c b/src/libCom/calc/calcPerform.c index e074bbcbc..b09df265e 100644 --- a/src/libCom/calc/calcPerform.c +++ b/src/libCom/calc/calcPerform.c @@ -1,5 +1,5 @@ /*************************************************************************\ -* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. @@ -43,21 +43,26 @@ epicsShareFunc long double stack[CALCPERFORM_STACK+1]; /* zero'th entry not used */ double *ptop; /* stack pointer */ double top; /* value from top of stack */ - long itop; /* integer from top of stack */ + int itop; /* integer from top of stack */ + int op; int nargs; /* initialize */ ptop = stack; /* RPN evaluation loop */ - while (*pinst != END_EXPRESSION){ - switch (*pinst){ + while ((op = *pinst++) != END_EXPRESSION){ + switch (op){ - case LITERAL: - ++ptop; - ++pinst; - memcpy((void *)ptop, pinst, sizeof(double)); - pinst += sizeof(double) - 1; + case LITERAL_DOUBLE: + memcpy((void *)++ptop, pinst, sizeof(double)); + pinst += sizeof(double); + break; + + case LITERAL_INT: + memcpy(&itop, pinst, sizeof(int)); + *++ptop = itop; + pinst += sizeof(int); break; case FETCH_VAL: @@ -76,7 +81,7 @@ epicsShareFunc long case FETCH_J: case FETCH_K: case FETCH_L: - *++ptop = parg[*pinst - FETCH_A]; + *++ptop = parg[op - FETCH_A]; break; case STORE_A: @@ -91,7 +96,7 @@ epicsShareFunc long case STORE_J: case STORE_K: case STORE_L: - parg[*pinst - STORE_A] = *ptop--; + parg[op - STORE_A] = *ptop--; break; case CONST_PI: @@ -160,7 +165,7 @@ epicsShareFunc long break; case MAX: - nargs = *++pinst; + nargs = *pinst++; while (--nargs) { top = *ptop--; if (*ptop < top || isnan(top)) @@ -169,7 +174,7 @@ epicsShareFunc long break; case MIN: - nargs = *++pinst; + nargs = *pinst++; while (--nargs) { top = *ptop--; if (*ptop > top || isnan(top)) @@ -231,7 +236,7 @@ epicsShareFunc long break; case FINITE: - nargs = *++pinst; + nargs = *pinst++; top = finite(*ptop); while (--nargs) { --ptop; @@ -245,7 +250,7 @@ epicsShareFunc long break; case ISNAN: - nargs = *++pinst; + nargs = *pinst++; top = isnan(*ptop); while (--nargs) { --ptop; @@ -350,12 +355,9 @@ epicsShareFunc long break; default: - errlogPrintf("calcPerform: Bad Opcode %d at %p\n",*pinst, pinst); + errlogPrintf("calcPerform: Bad Opcode %d at %p\n", op, pinst-1); return -1; } - - /* Advance to next opcode */ - ++pinst; } /* The stack should now have one item on it, the expression value */ @@ -372,12 +374,21 @@ 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) { + while ((op = *pinst++) != END_EXPRESSION) { switch (op) { - case LITERAL: + case LITERAL_DOUBLE: pinst += sizeof(double); break; + case LITERAL_INT: + pinst += sizeof(int); + break; + case MIN: + case MAX: + case FINITE: + case ISNAN: + pinst++; + break; case FETCH_A: case FETCH_B: @@ -413,7 +424,6 @@ calcArgUsage(const char *pinst, unsigned long *pinputs, unsigned long *pstores) default: break; } - pinst++; } if (pinputs) *pinputs = inputs; if (pstores) *pstores = stores; @@ -439,24 +449,37 @@ static double calcRandom(void) } /* Search the instruction stream for a matching operator, skipping any - * other conditional instructions found + * other conditional instructions found, and leave *ppinst pointing to + * the next instruction to be executed. */ static int cond_search(const char **ppinst, int match) { - const char *pinst = *ppinst + 1; + const char *pinst = *ppinst; int count = 1; int op; - while ((op = *pinst) != END_EXPRESSION) { + while ((op = *pinst++) != END_EXPRESSION) { if (op == match && --count == 0) { *ppinst = pinst; return 0; - } else if (op == COND_IF) - count++; - else if (op == LITERAL) + } + switch (op) { + case LITERAL_DOUBLE: pinst += sizeof(double); - pinst++; + break; + case LITERAL_INT: + pinst += sizeof(int); + break; + case MIN: + case MAX: + case FINITE: + case ISNAN: + pinst++; + break; + case COND_IF: + count++; + break; + } } return 1; } - diff --git a/src/libCom/calc/postfix.c b/src/libCom/calc/postfix.c index da3335e74..50953a11c 100644 --- a/src/libCom/calc/postfix.c +++ b/src/libCom/calc/postfix.c @@ -1,5 +1,5 @@ /*************************************************************************\ -* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne +* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. @@ -10,7 +10,7 @@ * * Subroutines used to convert an infix expression to a postfix expression * - * Author: Bob Dalesio + * Original Author: Bob Dalesio * Date: 12-12-86 */ @@ -69,17 +69,17 @@ static const ELEMENT operands[] = { {"!", 7, 8, 0, UNARY_OPERATOR, REL_NOT}, {"(", 0, 8, 0, UNARY_OPERATOR, NOT_GENERATED}, {"-", 7, 8, 0, UNARY_OPERATOR, UNARY_NEG}, -{".", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"0", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"1", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"2", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"3", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"4", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"5", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"6", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"7", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"8", 0, 0, 1, LITERAL_OPERAND,LITERAL}, -{"9", 0, 0, 1, LITERAL_OPERAND,LITERAL}, +{".", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"0", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"1", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"2", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"3", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"4", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"5", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"6", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"7", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"8", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, +{"9", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, {"A", 0, 0, 1, OPERAND, FETCH_A}, {"ABS", 7, 8, 0, UNARY_OPERATOR, ABS_VAL}, {"ACOS", 7, 8, 0, UNARY_OPERATOR, ACOS}, @@ -101,7 +101,7 @@ static const ELEMENT operands[] = { {"G", 0, 0, 1, OPERAND, FETCH_G}, {"H", 0, 0, 1, OPERAND, FETCH_H}, {"I", 0, 0, 1, OPERAND, FETCH_I}, -{"INF", 0, 0, 1, LITERAL_OPERAND,LITERAL}, +{"INF", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, {"ISINF", 7, 8, 0, UNARY_OPERATOR, ISINF}, {"ISNAN", 7, 8, 0, VARARG_OPERATOR,ISNAN}, {"J", 0, 0, 1, OPERAND, FETCH_J}, @@ -113,7 +113,7 @@ static const ELEMENT operands[] = { {"MAX", 7, 8, 0, VARARG_OPERATOR,MAX}, {"MIN", 7, 8, 0, VARARG_OPERATOR,MIN}, {"NINT", 7, 8, 0, UNARY_OPERATOR, NINT}, -{"NAN", 0, 0, 1, LITERAL_OPERAND,LITERAL}, +{"NAN", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE}, {"NOT", 7, 8, 0, UNARY_OPERATOR, BIT_NOT}, {"PI", 0, 0, 1, OPERAND, CONST_PI}, {"R2D", 0, 0, 1, OPERAND, CONST_R2D}, @@ -214,7 +214,8 @@ epicsShareFunc long int cond_count = 0; char *pout = ppostfix; char *pnext; - double constant; + double lit_d; + int lit_i; if (psrc == NULL || *psrc == '\0' || pout == NULL || perror == NULL) { @@ -237,18 +238,25 @@ epicsShareFunc long break; case LITERAL_OPERAND: - *pout++ = pel->code; runtime_depth += pel->runtime_effect; psrc -= strlen(pel->name); - constant = epicsStrtod(psrc, &pnext); + lit_d = epicsStrtod(psrc, &pnext); if (pnext == psrc) { *perror = CALC_ERR_BAD_LITERAL; goto bad; } psrc = pnext; - memcpy(pout, (void *)&constant, sizeof(double)); - pout += sizeof(double); + lit_i = lit_d; + if (lit_d != (double) lit_i) { + *pout++ = pel->code; + memcpy(pout, (void *)&lit_d, sizeof(double)); + pout += sizeof(double); + } else { + *pout++ = LITERAL_INT; + memcpy(pout, (void *)&lit_i, sizeof(int)); + pout += sizeof(int); + } operand_needed = FALSE; break; @@ -500,7 +508,7 @@ epicsShareFunc void static const char *opcodes[] = { "End Expression", /* Operands */ - "LITERAL", "VAL", + "LITERAL_DOUBLE", "LITERAL_INT", "VAL", "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 */ @@ -571,15 +579,21 @@ epicsShareFunc void "NOT_GENERATED" }; char op; - double lit; + double lit_d; + int lit_i; while ((op = *pinst) != END_EXPRESSION) { switch (op) { - case LITERAL: - memcpy((void *)&lit, ++pinst, sizeof(double)); - printf("\tLiteral: %g\n", lit); + case LITERAL_DOUBLE: + memcpy((void *)&lit_d, ++pinst, sizeof(double)); + printf("\tDouble %g\n", lit_d); pinst += sizeof(double); break; + case LITERAL_INT: + memcpy((void *)&lit_i, ++pinst, sizeof(int)); + printf("\tInteger %d\n", lit_i); + pinst += sizeof(int); + break; case MIN: case MAX: case FINITE: diff --git a/src/libCom/calc/postfix.h b/src/libCom/calc/postfix.h index 7ba676c22..235ccadf3 100644 --- a/src/libCom/calc/postfix.h +++ b/src/libCom/calc/postfix.h @@ -1,14 +1,13 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found +* EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* postfix.h - * Author: Bob Dalesio + * Original Author: Bob Dalesio * Date: 9-21-88 */ @@ -20,14 +19,11 @@ #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 INFIX_TO_POSTFIX_SIZE(n) (n*21/6) +/* The above expression is an estimate of the maximum postfix buffer + * size needed for a given infix expression buffer. The actual size + * needed is never larger than this value, although it is actually a + * few bytes smaller for some sizes. */ /* These are not hard limits, just default sizes for the database */ diff --git a/src/libCom/calc/postfixPvt.h b/src/libCom/calc/postfixPvt.h index ace9b3f4b..53efb32e0 100644 --- a/src/libCom/calc/postfixPvt.h +++ b/src/libCom/calc/postfixPvt.h @@ -1,23 +1,25 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found +* EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* postfixPvt.h - * Author: Bob Dalesio + * Original Author: Bob Dalesio * 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. + * 2. The LITERAL opcodes are followed by a binary representation of their + * values, but these are not aligned properly. + * 3. The var-arg functions MIN, MAX, FINITE and ISNAN are followed by + * a byte giving the number of arguments to process. + * 4. You can't use strlen() on an RPN buffer since the literal values + * can contain zero bytes. */ #ifndef INCpostfixPvth @@ -28,7 +30,7 @@ typedef enum { END_EXPRESSION = 0, /* Operands */ - LITERAL, FETCH_VAL, + LITERAL_DOUBLE, LITERAL_INT, FETCH_VAL, 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 */