libCom/calc: Added integer literals, which use less space in Postfix.

Renamed LITERAL to LITERAL_DOUBLE and added LITERAL_INT.
postfix() only uses LITERAL_INT if the results are identical.
Adjusted INFIX_TO_POSTFIX_SIZE() macro to match.
Cleaned up some other internal issues.
This commit is contained in:
Andrew Johnson
2010-10-04 13:32:34 -05:00
parent 641aa70eb1
commit bb7d8d6435
4 changed files with 110 additions and 75 deletions

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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 */

View File

@@ -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 */