This is Unofficial EPICS BASE Doxygen Site
calcPerform.c File Reference
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "osiUnistd.h"
#include "dbDefs.h"
#include "epicsMath.h"
#include "epicsTypes.h"
#include "errlog.h"
#include "postfix.h"
#include "postfixPvt.h"
+ Include dependency graph for calcPerform.c:

Go to the source code of this file.

Macros

#define PI   3.14159265358979323
 
#define d2i(x)   ((x)<0?(epicsInt32)(x):(epicsInt32)(epicsUInt32)(x))
 
#define d2ui(x)   ((x)<0?(epicsUInt32)(epicsInt32)(x):(epicsUInt32)(x))
 

Functions

LIBCOM_API long calcPerform (double *parg, double *presult, const char *pinst)
 Run the calculation engine. More...
 
LIBCOM_API long calcArgUsage (const char *pinst, unsigned long *pinputs, unsigned long *pstores)
 Find the inputs and outputs of an expression. More...
 

Macro Definition Documentation

#define d2i (   x)    ((x)<0?(epicsInt32)(x):(epicsInt32)(epicsUInt32)(x))
#define d2ui (   x)    ((x)<0?(epicsUInt32)(epicsInt32)(x):(epicsUInt32)(x))
#define PI   3.14159265358979323

Definition at line 32 of file calcPerform.c.

Function Documentation

LIBCOM_API long calcArgUsage ( const char *  ppostfix,
unsigned long *  pinputs,
unsigned long *  pstores 
)

Find the inputs and outputs of an expression.

Software using the calc subsystem may need to know what expression arguments are used and/or modified by a particular expression. It can discover this from the postfix string by calling calcArgUsage(), which takes two pointers pinputs and pstores to a pair of unsigned long bitmaps which return that information to the caller. Passing a NULL value for either of these pointers is legal if only the other is needed.

The least signficant bit (bit 0) of the bitmap at *pinputs will be set if the expression depends on the argument A, and so on through bit 11 for the argument L. An argument that is not used until after a value has been assigned to it will not be set in the pinputs bitmap, thus the bits can be used to determine whether a value needs to be supplied for their associated argument or not for the purposes of evaluating the expression.

Bit 0 of the bitmap at *pstores will be set if the expression assigns a value to the argument A, bit 1 for argument B etc.

Parameters
ppostfixA postfix expression created by postfix().
pinputsBitmap pointer.
pstoresBitmap pointer.
Returns
The return value will be non-zero if the ppostfix expression was illegal, otherwise 0.

Definition at line 405 of file calcPerform.c.

406 {
407  unsigned long inputs = 0;
408  unsigned long stores = 0;
409  char op;
410  while ((op = *pinst++) != END_EXPRESSION) {
411  switch (op) {
412 
413  case LITERAL_DOUBLE:
414  pinst += sizeof(double);
415  break;
416  case LITERAL_INT:
417  pinst += sizeof(epicsInt32);
418  break;
419  case MIN:
420  case MAX:
421  case FINITE:
422  case ISNAN:
423  pinst++;
424  break;
425 
426  case FETCH_A:
427  case FETCH_B:
428  case FETCH_C:
429  case FETCH_D:
430  case FETCH_E:
431  case FETCH_F:
432  case FETCH_G:
433  case FETCH_H:
434  case FETCH_I:
435  case FETCH_J:
436  case FETCH_K:
437  case FETCH_L:
438  /* Don't claim to use an arg we already stored to */
439  inputs |= (1 << (op - FETCH_A)) & ~stores;
440  break;
441 
442  case STORE_A:
443  case STORE_B:
444  case STORE_C:
445  case STORE_D:
446  case STORE_E:
447  case STORE_F:
448  case STORE_G:
449  case STORE_H:
450  case STORE_I:
451  case STORE_J:
452  case STORE_K:
453  case STORE_L:
454  stores |= (1 << (op - STORE_A));
455  break;
456 
457  default:
458  break;
459  }
460  }
461  if (pinputs) *pinputs = inputs;
462  if (pstores) *pstores = stores;
463  return 0;
464 }
Definition: postfixPvt.h:56
Definition: postfixPvt.h:57
ChannelPut::shared_pointer op
Definition: pvAccess.cpp:132
int epicsInt32
Definition: epicsTypes.h:42
LIBCOM_API long calcPerform ( double *  parg,
double *  presult,
const char *  ppostfix 
)

Run the calculation engine.

Evaluates the postfix expression against a set ot input values.

Parameters
pargPointer to an array of double values for the arguments A-L that can appear in the expression. Note that the argument values may be modified if the expression uses the assignment operator.
presultWhere to put the calculated result, which may be a NaN or Infinity.
ppostfixThe postfix expression created by postfix().
Returns
Status value 0 for OK, or non-zero if an error is discovered during the evaluation process.

Definition at line 45 of file calcPerform.c.

46 {
47  double stack[CALCPERFORM_STACK+1]; /* zero'th entry not used */
48  double *ptop; /* stack pointer */
49  double top; /* value from top of stack */
50  epicsInt32 itop; /* integer from top of stack */
51  int op;
52  int nargs;
53 
54  /* initialize */
55  ptop = stack;
56 
57  /* RPN evaluation loop */
58  while ((op = *pinst++) != END_EXPRESSION){
59  switch (op){
60 
61  case LITERAL_DOUBLE:
62  memcpy(++ptop, pinst, sizeof(double));
63  pinst += sizeof(double);
64  break;
65 
66  case LITERAL_INT:
67  memcpy(&itop, pinst, sizeof(epicsInt32));
68  *++ptop = itop;
69  pinst += sizeof(epicsInt32);
70  break;
71 
72  case FETCH_VAL:
73  *++ptop = *presult;
74  break;
75 
76  case FETCH_A:
77  case FETCH_B:
78  case FETCH_C:
79  case FETCH_D:
80  case FETCH_E:
81  case FETCH_F:
82  case FETCH_G:
83  case FETCH_H:
84  case FETCH_I:
85  case FETCH_J:
86  case FETCH_K:
87  case FETCH_L:
88  *++ptop = parg[op - FETCH_A];
89  break;
90 
91  case STORE_A:
92  case STORE_B:
93  case STORE_C:
94  case STORE_D:
95  case STORE_E:
96  case STORE_F:
97  case STORE_G:
98  case STORE_H:
99  case STORE_I:
100  case STORE_J:
101  case STORE_K:
102  case STORE_L:
103  parg[op - STORE_A] = *ptop--;
104  break;
105 
106  case CONST_PI:
107  *++ptop = PI;
108  break;
109 
110  case CONST_D2R:
111  *++ptop = PI/180.;
112  break;
113 
114  case CONST_R2D:
115  *++ptop = 180./PI;
116  break;
117 
118  case UNARY_NEG:
119  *ptop = - *ptop;
120  break;
121 
122  case ADD:
123  top = *ptop--;
124  *ptop += top;
125  break;
126 
127  case SUB:
128  top = *ptop--;
129  *ptop -= top;
130  break;
131 
132  case MULT:
133  top = *ptop--;
134  *ptop *= top;
135  break;
136 
137  case DIV:
138  top = *ptop--;
139  *ptop /= top;
140  break;
141 
142  case MODULO:
143  itop = (epicsInt32) *ptop--;
144  if (itop)
145  *ptop = (epicsInt32) *ptop % itop;
146  else
147  *ptop = epicsNAN;
148  break;
149 
150  case POWER:
151  top = *ptop--;
152  *ptop = pow(*ptop, top);
153  break;
154 
155  case ABS_VAL:
156  *ptop = fabs(*ptop);
157  break;
158 
159  case EXP:
160  *ptop = exp(*ptop);
161  break;
162 
163  case LOG_10:
164  *ptop = log10(*ptop);
165  break;
166 
167  case LOG_E:
168  *ptop = log(*ptop);
169  break;
170 
171  case MAX:
172  nargs = *pinst++;
173  while (--nargs) {
174  top = *ptop--;
175  if (*ptop < top || isnan(top))
176  *ptop = top;
177  }
178  break;
179 
180  case MIN:
181  nargs = *pinst++;
182  while (--nargs) {
183  top = *ptop--;
184  if (*ptop > top || isnan(top))
185  *ptop = top;
186  }
187  break;
188 
189  case SQU_RT:
190  *ptop = sqrt(*ptop);
191  break;
192 
193  case ACOS:
194  *ptop = acos(*ptop);
195  break;
196 
197  case ASIN:
198  *ptop = asin(*ptop);
199  break;
200 
201  case ATAN:
202  *ptop = atan(*ptop);
203  break;
204 
205  case ATAN2:
206  top = *ptop--;
207  *ptop = atan2(top, *ptop); /* Ouch!: Args backwards! */
208  break;
209 
210  case COS:
211  *ptop = cos(*ptop);
212  break;
213 
214  case SIN:
215  *ptop = sin(*ptop);
216  break;
217 
218  case TAN:
219  *ptop = tan(*ptop);
220  break;
221 
222  case COSH:
223  *ptop = cosh(*ptop);
224  break;
225 
226  case SINH:
227  *ptop = sinh(*ptop);
228  break;
229 
230  case TANH:
231  *ptop = tanh(*ptop);
232  break;
233 
234  case CEIL:
235  *ptop = ceil(*ptop);
236  break;
237 
238  case FLOOR:
239  *ptop = floor(*ptop);
240  break;
241 
242  case FINITE:
243  nargs = *pinst++;
244  top = finite(*ptop);
245  while (--nargs) {
246  --ptop;
247  top = top && finite(*ptop);
248  }
249  *ptop = top;
250  break;
251 
252  case ISINF:
253  *ptop = isinf(*ptop);
254  break;
255 
256  case ISNAN:
257  nargs = *pinst++;
258  top = isnan(*ptop);
259  while (--nargs) {
260  --ptop;
261  top = top || isnan(*ptop);
262  }
263  *ptop = top;
264  break;
265 
266  case NINT:
267  top = *ptop;
268  *ptop = (epicsInt32) (top >= 0 ? top + 0.5 : top - 0.5);
269  break;
270 
271  case RANDOM:
272  *++ptop = calcRandom();
273  break;
274 
275  case REL_OR:
276  top = *ptop--;
277  *ptop = *ptop || top;
278  break;
279 
280  case REL_AND:
281  top = *ptop--;
282  *ptop = *ptop && top;
283  break;
284 
285  case REL_NOT:
286  *ptop = ! *ptop;
287  break;
288 
289  /* Be VERY careful converting double to int in case bit 31 is set!
290  * Out-of-range errors give very different results on different sytems.
291  * Convert negative doubles to signed and positive doubles to unsigned
292  * first to avoid overflows if bit 32 is set.
293  * The result is always signed, values with bit 31 set are negative
294  * to avoid problems when writing the value to signed integer fields
295  * like longout.VAL or ao.RVAL. However unsigned fields may give
296  * problems on some architectures. (Fewer than giving problems with
297  * signed integer. Maybe the conversion functions should handle
298  * overflows better.)
299  */
300  #define d2i(x) ((x)<0?(epicsInt32)(x):(epicsInt32)(epicsUInt32)(x))
301  #define d2ui(x) ((x)<0?(epicsUInt32)(epicsInt32)(x):(epicsUInt32)(x))
302 
303  case BIT_OR:
304  top = *ptop--;
305  *ptop = (double)(d2i(*ptop) | d2i(top));
306  break;
307 
308  case BIT_AND:
309  top = *ptop--;
310  *ptop = (double)(d2i(*ptop) & d2i(top));
311  break;
312 
313  case BIT_EXCL_OR:
314  top = *ptop--;
315  *ptop = (double)(d2i(*ptop) ^ d2i(top));
316  break;
317 
318  case BIT_NOT:
319  *ptop = (double)~d2i(*ptop);
320  break;
321 
322  /* In C the shift operators decide on an arithmetic or logical shift
323  * based on whether the integer is signed or unsigned.
324  * With signed integers, a right-shift is arithmetic and will
325  * extend the sign bit into the left-hand end of the value. When used
326  * with unsigned values a logical shift is performed. The
327  * double-casting through signed/unsigned here is important, see above.
328  */
329 
330  case RIGHT_SHIFT_ARITH:
331  top = *ptop--;
332  *ptop = (double)(d2i(*ptop) >> (d2i(top) & 31));
333  break;
334 
335  case LEFT_SHIFT_ARITH:
336  top = *ptop--;
337  *ptop = (double)(d2i(*ptop) << (d2i(top) & 31));
338  break;
339 
340  case RIGHT_SHIFT_LOGIC:
341  top = *ptop--;
342  *ptop = (double)(d2ui(*ptop) >> (d2ui(top) & 31u));
343  break;
344 
345  case NOT_EQ:
346  top = *ptop--;
347  *ptop = *ptop != top;
348  break;
349 
350  case LESS_THAN:
351  top = *ptop--;
352  *ptop = *ptop < top;
353  break;
354 
355  case LESS_OR_EQ:
356  top = *ptop--;
357  *ptop = *ptop <= top;
358  break;
359 
360  case EQUAL:
361  top = *ptop--;
362  *ptop = *ptop == top;
363  break;
364 
365  case GR_OR_EQ:
366  top = *ptop--;
367  *ptop = *ptop >= top;
368  break;
369 
370  case GR_THAN:
371  top = *ptop--;
372  *ptop = *ptop > top;
373  break;
374 
375  case COND_IF:
376  if (*ptop-- == 0.0 &&
377  cond_search(&pinst, COND_ELSE)) return -1;
378  break;
379 
380  case COND_ELSE:
381  if (cond_search(&pinst, COND_END)) return -1;
382  break;
383 
384  case COND_END:
385  break;
386 
387  default:
388  errlogPrintf("calcPerform: Bad Opcode %d at %p\n", op, pinst-1);
389  return -1;
390  }
391  }
392 
393  /* The stack should now have one item on it, the expression value */
394  if (ptop != stack + 1)
395  return -1;
396  *presult = *ptop;
397  return 0;
398 }
Definition: postfixPvt.h:56
#define isinf(x)
Definition: epicsMath.h:16
Definition: postfixPvt.h:45
Definition: postfixPvt.h:57
#define PI
Definition: calcPerform.c:32
#define isnan(x)
Definition: epicsMath.h:21
#define d2ui(x)
Definition: postfixPvt.h:46
Definition: postfixPvt.h:64
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
float epicsNAN
Definition: epicsMath.cpp:35
Definition: postfixPvt.h:68
Definition: postfixPvt.h:48
Definition: postfixPvt.h:53
#define CALCPERFORM_STACK
Size of the internal partial result stack.
Definition: postfix.h:27
Definition: postfixPvt.h:66
ChannelPut::shared_pointer op
Definition: pvAccess.cpp:132
#define d2i(x)
#define finite(x)
Definition: epicsMath.h:16
int epicsInt32
Definition: epicsTypes.h:42