diff --git a/src/libCom/calc/calcPerform.c b/src/libCom/calc/calcPerform.c index 9744d5ea1..117ed7c9a 100644 --- a/src/libCom/calc/calcPerform.c +++ b/src/libCom/calc/calcPerform.c @@ -1,10 +1,9 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2008 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. \*************************************************************************/ /* $Id$ */ @@ -44,6 +43,7 @@ epicsShareFunc long double *ptop; /* stack pointer */ double top; /* value from top of stack */ int itop; /* integer from top of stack */ + char nargs; /* initialize */ ptop = stack; @@ -158,15 +158,21 @@ epicsShareFunc long break; case MAX: - top = *ptop--; - if (*ptop < top || isnan(top)) - *ptop = top; + nargs = *++pinst; + while (--nargs) { + top = *ptop--; + if (*ptop < top || isnan(top)) + *ptop = top; + } break; case MIN: - top = *ptop--; - if (*ptop > top || isnan(top)) - *ptop = top; + nargs = *++pinst; + while (--nargs) { + top = *ptop--; + if (*ptop > top || isnan(top)) + *ptop = top; + } break; case SQU_RT: @@ -223,7 +229,13 @@ epicsShareFunc long break; case FINITE: - *ptop = finite(*ptop); + nargs = *++pinst; + top = finite(*ptop); + while (--nargs) { + --ptop; + top = top && finite(*ptop); + } + *ptop = top; break; case ISINF: @@ -231,7 +243,13 @@ epicsShareFunc long break; case ISNAN: - *ptop = isnan(*ptop); + nargs = *++pinst; + top = isnan(*ptop); + while (--nargs) { + --ptop; + top = top || isnan(*ptop); + } + *ptop = top; break; case NINT: diff --git a/src/libCom/calc/postfix.c b/src/libCom/calc/postfix.c index 1d6f2bfb5..231d9eca1 100644 --- a/src/libCom/calc/postfix.c +++ b/src/libCom/calc/postfix.c @@ -1,10 +1,9 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2008 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. \*************************************************************************/ /* $Id$ @@ -36,6 +35,7 @@ typedef enum { LITERAL_OPERAND, STORE_OPERATOR, UNARY_OPERATOR, + VARARG_OPERATOR, BINARY_OPERATOR, SEPERATOR, CLOSE_PAREN, @@ -61,6 +61,8 @@ typedef struct expression_element{ * NOTE: Keep these lists sorted. Elements are searched in reverse order, * and where two names start with the same substring we must pick out the * longest name first (hence the sort requirement). + * NOTE: All VARARG_OPERATORs have to be made known to the calcExprDump() + * routine at the end of this file. */ static const ELEMENT operands[] = { /* name prio's stack element type opcode */ @@ -94,22 +96,22 @@ static const ELEMENT operands[] = { {"E", 0, 0, 1, OPERAND, FETCH_E}, {"EXP", 7, 8, 0, UNARY_OPERATOR, EXP}, {"F", 0, 0, 1, OPERAND, FETCH_F}, -{"FINITE", 7, 8, 0, UNARY_OPERATOR, FINITE}, +{"FINITE", 7, 8, 0, VARARG_OPERATOR,FINITE}, {"FLOOR", 7, 8, 0, UNARY_OPERATOR, FLOOR}, {"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}, {"ISINF", 7, 8, 0, UNARY_OPERATOR, ISINF}, -{"ISNAN", 7, 8, 0, UNARY_OPERATOR, ISNAN}, +{"ISNAN", 7, 8, 0, VARARG_OPERATOR,ISNAN}, {"J", 0, 0, 1, OPERAND, FETCH_J}, {"K", 0, 0, 1, OPERAND, FETCH_K}, {"L", 0, 0, 1, OPERAND, FETCH_L}, {"LN", 7, 8, 0, UNARY_OPERATOR, LOG_E}, {"LOG", 7, 8, 0, UNARY_OPERATOR, LOG_10}, {"LOGE", 7, 8, 0, UNARY_OPERATOR, LOG_E}, -{"MAX", 7, 8, -1, UNARY_OPERATOR, MAX}, -{"MIN", 7, 8, -1, UNARY_OPERATOR, MIN}, +{"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}, {"NOT", 7, 8, 0, UNARY_OPERATOR, BIT_NOT}, @@ -264,10 +266,14 @@ epicsShareFunc long break; case UNARY_OPERATOR: + case VARARG_OPERATOR: /* Move operators of >= priority to the output */ while ((pstacktop > stack) && (pstacktop->in_stack_pri >= pel->in_coming_pri)) { *pout++ = pstacktop->code; + if (pstacktop->type == VARARG_OPERATOR) { + *pout++ = 1 - pstacktop->runtime_effect; + } runtime_depth += pstacktop->runtime_effect; pstacktop--; } @@ -282,6 +288,9 @@ epicsShareFunc long while ((pstacktop > stack) && (pstacktop->in_stack_pri >= pel->in_coming_pri)) { *pout++ = pstacktop->code; + if (pstacktop->type == VARARG_OPERATOR) { + *pout++ = 1 - pstacktop->runtime_effect; + } runtime_depth += pstacktop->runtime_effect; pstacktop--; } @@ -301,10 +310,14 @@ epicsShareFunc long goto bad; } *pout++ = pstacktop->code; + if (pstacktop->type == VARARG_OPERATOR) { + *pout++ = 1 - pstacktop->runtime_effect; + } runtime_depth += pstacktop->runtime_effect; pstacktop--; } operand_needed = TRUE; + pstacktop->runtime_effect -= 1; break; case CLOSE_PAREN: @@ -315,10 +328,23 @@ epicsShareFunc long goto bad; } *pout++ = pstacktop->code; + if (pstacktop->type == VARARG_OPERATOR) { + *pout++ = 1 - pstacktop->runtime_effect; + } runtime_depth += pstacktop->runtime_effect; pstacktop--; } pstacktop--; /* remove ( from stack */ + /* if there is a vararg operator before the opening paren, + it inherits the (opening) paren's stack effect */ + if (pstacktop->type == VARARG_OPERATOR) { + pstacktop->runtime_effect = (pstacktop+1)->runtime_effect; + /* check for no arguments */ + if (pstacktop->runtime_effect > 0) { + *perror = CALC_ERR_INCOMPLETE; + goto bad; + } + } break; case CONDITIONAL: @@ -326,6 +352,9 @@ epicsShareFunc long while ((pstacktop > stack) && (pstacktop->in_stack_pri > pel->in_coming_pri)) { *pout++ = pstacktop->code; + if (pstacktop->type == VARARG_OPERATOR) { + *pout++ = 1 - pstacktop->runtime_effect; + } runtime_depth += pstacktop->runtime_effect; pstacktop--; } @@ -359,6 +388,9 @@ epicsShareFunc long goto bad; } *pout++ = pstacktop->code; + if (pstacktop->type == VARARG_OPERATOR) { + *pout++ = 1 - pstacktop->runtime_effect; + } runtime_depth += pstacktop->runtime_effect; pstacktop--; } @@ -402,6 +434,9 @@ epicsShareFunc long goto bad; } *pout++ = pstacktop->code; + if (pstacktop->type == VARARG_OPERATOR) { + *pout++ = 1 - pstacktop->runtime_effect; + } runtime_depth += pstacktop->runtime_effect; pstacktop--; } @@ -463,7 +498,7 @@ epicsShareFunc void static const char *opcodes[] = { "End Expression", /* Operands */ - "LITERAL", + "LITERAL", "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 */ @@ -534,13 +569,23 @@ epicsShareFunc void "NOT_GENERATED" }; char op; + double lit; + while ((op = *pinst) != END_EXPRESSION) { - if (op == LITERAL) { - double lit; + switch (op) { + case LITERAL: memcpy((void *)&lit, ++pinst, sizeof(double)); printf("\tLiteral: %g\n", lit); pinst += sizeof(double); - } else { + break; + case MIN: + case MAX: + case FINITE: + case ISNAN: + printf("\t%s, %d arg(s)\n", opcodes[(int) op], *++pinst); + pinst++; + break; + default: printf("\t%s\n", opcodes[(int) op]); pinst++; } diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index 872bfefd2..9cc2b28ce 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -1,5 +1,5 @@ /*************************************************************************\ -* Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne +* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. @@ -66,6 +66,20 @@ void testCalc(const char *expr, double expected) { return; } +void testBadExpr(const char *expr, short expected_err) { + /* Parse an invalid expression, test against expected error code */ + char rpn[MAX_POSTFIX_SIZE]; + short err = 0; + + postfix(expr, rpn, &err); + if (!testOk(err == expected_err, "%s (bad expression)", expr)) { + testDiag("Expected '%s', actually got '%s'", + calcErrorStr(expected_err), calcErrorStr(err)); + calcExprDump(rpn); + } + return; +} + /* Test an expression that is also valid C code */ #define testExpr(expr) testCalc(#expr, expr); @@ -83,13 +97,98 @@ void testCalc(const char *expr, double expected) { #define LN(x) log(x) #define LOG(x) log10(x) #define LOGE(x) log(x) -#define MAX(a,b) epicsMax(a,b) -#define MIN(a,b) epicsMin(a,b) #define NINT(x) (double)(long)((x) >= 0 ? (x)+0.5 : (x)-0.5) #define OR | #define SQR(x) sqrt(x) #define XOR ^ +static inline double MAX(double a) { + return a; +} +static inline double MAX(double a, double b) { + return epicsMax(a,b); +} +static inline double MAX(double a, double b, double c) { + return MAX(MAX(a,b),c); +} +static inline double MAX(double a, double b, double c, double d) { + return MAX(MAX(a,b,c),d); +} +static inline double MAX(double a, double b, double c, double d, double e) { + return MAX(MAX(a,b,c,d),e); +} +static inline double MAX(double a, double b, double c, double d, double e, + double f) { + return MAX(MAX(a,b,c,d,e),f); +} +static inline double MAX(double a, double b, double c, double d, double e, + double f, double g) { + return MAX(MAX(a,b,c,d,e,f),g); +} +static inline double MAX(double a, double b, double c, double d, double e, + double f, double g, double h) { + return MAX(MAX(a,b,c,d,e,f,g),h); +} +static inline double MAX(double a, double b, double c, double d, double e, + double f, double g, double h, double i) { + return MAX(MAX(a,b,c,d,e,f,g,h),i); +} +static inline double MAX(double a, double b, double c, double d, double e, + double f, double g, double h, double i, double j) { + return MAX(MAX(a,b,c,d,e,f,g,h,i),j); +} +static inline double MAX(double a, double b, double c, double d, double e, + double f, double g, double h, double i, double j, double k) { + return MAX(MAX(a,b,c,d,e,f,g,h,i,j),k); +} +static inline double MAX(double a, double b, double c, double d, double e, + double f, double g, double h, double i, double j, double k, double l) { + return MAX(MAX(a,b,c,d,e,f,g,h,i,j,k),l); +} + +static inline double MIN(double a) { + return a; +} +static inline double MIN(double a, double b) { + return epicsMin(a,b); +} +static inline double MIN(double a, double b, double c) { + return MIN(MIN(a,b),c); +} +static inline double MIN(double a, double b, double c, double d) { + return MIN(MIN(a,b,c),d); +} +static inline double MIN(double a, double b, double c, double d, double e) { + return MIN(MIN(a,b,c,d),e); +} +static inline double MIN(double a, double b, double c, double d, double e, + double f) { + return MIN(MIN(a,b,c,d,e),f); +} +static inline double MIN(double a, double b, double c, double d, double e, + double f, double g) { + return MIN(MIN(a,b,c,d,e,f),g); +} +static inline double MIN(double a, double b, double c, double d, double e, + double f, double g, double h) { + return MIN(MIN(a,b,c,d,e,f,g),h); +} +static inline double MIN(double a, double b, double c, double d, double e, + double f, double g, double h, double i) { + return MIN(MIN(a,b,c,d,e,f,g,h),i); +} +static inline double MIN(double a, double b, double c, double d, double e, + double f, double g, double h, double i, double j) { + return MIN(MIN(a,b,c,d,e,f,g,h,i),j); +} +static inline double MIN(double a, double b, double c, double d, double e, + double f, double g, double h, double i, double j, double k) { + return MIN(MIN(a,b,c,d,e,f,g,h,i,j),k); +} +static inline double MIN(double a, double b, double c, double d, double e, + double f, double g, double h, double i, double j, double k, double l) { + return MIN(MIN(a,b,c,d,e,f,g,h,i,j,k),l); +} MAIN(epicsCalcTest) { @@ -101,7 +200,7 @@ MAIN(epicsCalcTest) Inf /= NaN; NaN /= NaN; - testPlan(392); + testPlan(532); /* LITERAL_OPERAND elements */ testExpr(0); @@ -167,10 +266,21 @@ MAIN(epicsCalcTest) testExpr(cosh(0.5)); testExpr(exp(1.)); testExpr(floor(1.5)); + testExpr(finite(0)); testExpr(finite(Inf)); testExpr(finite(-Inf)); testExpr(finite(NaN)); + testCalc("finite(0,1,2)", 1); + testCalc("finite(0,1,NaN)", 0); + testCalc("finite(0,NaN,2)", 0); + testCalc("finite(NaN,1,2)", 0); + testCalc("finite(0,1,Inf)", 0); + testCalc("finite(0,Inf,2)", 0); + testCalc("finite(Inf,1,2)", 0); + testCalc("finite(0,1,-Inf)", 0); + testCalc("finite(0,-Inf,2)", 0); + testCalc("finite(-Inf,1,2)", 0); testExpr(isinf(0)); testExpr(isinf(Inf)); testExpr(isinf(-Inf)); @@ -178,20 +288,146 @@ MAIN(epicsCalcTest) testExpr(isnan(0)); testExpr(isnan(Inf)); testExpr(isnan(NaN)); + testCalc("isnan(0,1,2)", 0); + testCalc("isnan(0,1,NaN)", 1); + testCalc("isnan(0,NaN,2)", 1); + testCalc("isnan(NaN,1,2)", 1); + testCalc("isnan(0,1,-Inf)", 0); + testCalc("isnan(0,-Inf,2)", 0); + testCalc("isnan(-Inf,1,2)", 0); + testExpr(LN(5.)); testExpr(LOG(5.)); testExpr(LOGE(2.)); - testExpr(MAX(1,2)); - testExpr(MAX(1.,Inf)); - testExpr(MAX(1.,-Inf)); - testExpr(MAX(1.,NaN)); - testExpr(MAX(NaN,1.)); - testExpr(MIN(1,2)); + + testExpr(MAX(-99)); + testExpr(MAX( 1., 2.)); + testExpr(MAX( 1., Inf)); + testExpr(MAX( 1.,-Inf)); + testExpr(MAX( 1., NaN)); + testExpr(MAX( Inf, 1.)); + testExpr(MAX(-Inf, 1.)); + testExpr(MAX( NaN, 1.)); + testExpr(MAX( 1., 2.,3.)); + testExpr(MAX( 1., 3.,2.)); + testExpr(MAX( 2., 1.,3.)); + testExpr(MAX( 2., 3.,1.)); + testExpr(MAX( 3., 1.,2.)); + testExpr(MAX( 3., 2.,1.)); + testExpr(MAX( 1., 2., Inf)); + testExpr(MAX( 1., 2.,-Inf)); + testExpr(MAX( 1., 2., NaN)); + testExpr(MAX( 1., Inf,2.)); + testExpr(MAX( 1.,-Inf,2.)); + testExpr(MAX( 1., NaN,2.)); + testExpr(MAX( Inf, 1.,2.)); + testExpr(MAX(-Inf, 1.,2.)); + testExpr(MAX( NaN, 1.,2.)); + testExpr(MAX( 1., 2., 3., 4.)); + testExpr(MAX( 1., 2., 4., 3.)); + testExpr(MAX( 1., 4., 3., 2.)); + testExpr(MAX( 4., 2., 3., 1.)); + testExpr(MAX( 1., 2., 3.,NaN)); + testExpr(MAX( 1., 2.,NaN, 3.)); + testExpr(MAX( 1.,NaN, 3., 2.)); + testExpr(MAX(NaN, 2., 3., 1.)); + testExpr(MAX( 1., 2., 3., 4., 5.)); + testExpr(MAX( 1., 2., 3., 5., 4.)); + testExpr(MAX( 1., 2., 5., 4., 3.)); + testExpr(MAX( 1., 5., 3., 4., 2.)); + testExpr(MAX( 5., 2., 3., 4., 1.)); + testExpr(MAX( 1., 2., 3., 4.,NaN)); + testExpr(MAX( 1., 2., 3.,NaN, 4.)); + testExpr(MAX( 1., 2.,NaN, 4., 3.)); + testExpr(MAX( 1.,NaN, 3., 4., 2.)); + testExpr(MAX(NaN, 2., 3., 4., 1.)); + testExpr(MAX( 1., 2., 3., 4., 5., 6.)); + testExpr(MAX( 1., 2., 3., 4., 6., 5.)); + testExpr(MAX( 1., 2., 3., 6., 5., 4.)); + testExpr(MAX( 1., 2., 6., 4., 5., 3.)); + testExpr(MAX( 1., 6., 3., 4., 5., 2.)); + testExpr(MAX( 6., 2., 3., 4., 5., 1.)); + testExpr(MAX( 1., 2., 3., 4., 5.,NaN)); + testExpr(MAX( 1., 2., 3., 4.,NaN, 5.)); + testExpr(MAX( 1., 2., 3.,NaN, 5., 4.)); + testExpr(MAX( 1., 2.,NaN, 4., 5., 3.)); + testExpr(MAX( 1.,NaN, 3., 4., 5., 2.)); + testExpr(MAX(NaN, 2., 3., 4., 5., 1.)); + testExpr(MAX( 1., 2., 3., 4., 5.,Inf)); + testExpr(MAX( 1., 2., 3., 4.,Inf, 5.)); + testExpr(MAX( 1., 2., 3.,Inf, 5., 4.)); + testExpr(MAX( 1., 2.,Inf, 4., 5., 3.)); + testExpr(MAX( 1.,Inf, 3., 4., 5., 2.)); + testExpr(MAX(Inf, 2., 3., 4., 5., 1.)); + testExpr(MAX(1,2,3,4,5,6,7,8,9,10)); + testExpr(MAX(5,4,3,2,1,0,-1,-2,-3,-4)); + testExpr(MAX(-1,1,0)); + + testExpr(MIN(99)); + testExpr(MIN(1.,2.)); testExpr(MIN(1.,Inf)); testExpr(MIN(1.,-Inf)); testExpr(MIN(1.,NaN)); testExpr(MIN(NaN,1.)); + testExpr(MIN( 1., 2.,3.)); + testExpr(MIN( 1., 3.,2.)); + testExpr(MIN( 2., 1.,3.)); + testExpr(MIN( 2., 3.,1.)); + testExpr(MIN( 3., 1.,2.)); + testExpr(MIN( 3., 2.,1.)); + testExpr(MIN( 1., 2., Inf)); + testExpr(MIN( 1., 2.,-Inf)); + testExpr(MIN( 1., 2., NaN)); + testExpr(MIN( 1., Inf,2.)); + testExpr(MIN( 1.,-Inf,2.)); + testExpr(MIN( 1., NaN,2.)); + testExpr(MIN( Inf, 1.,2.)); + testExpr(MIN(-Inf, 1.,2.)); + testExpr(MIN( NaN, 1.,2.)); + testExpr(MIN( 1., 2., 3., 4.)); + testExpr(MIN( 1., 2., 4., 3.)); + testExpr(MIN( 1., 4., 3., 2.)); + testExpr(MIN( 4., 2., 3., 1.)); + testExpr(MIN( 1., 2., 3.,NaN)); + testExpr(MIN( 1., 2.,NaN, 3.)); + testExpr(MIN( 1.,NaN, 3., 2.)); + testExpr(MIN(NaN, 2., 3., 1.)); + testExpr(MIN( 1., 2., 3., 4., 5.)); + testExpr(MIN( 1., 2., 3., 5., 4.)); + testExpr(MIN( 1., 2., 5., 4., 3.)); + testExpr(MIN( 1., 5., 3., 4., 2.)); + testExpr(MIN( 5., 2., 3., 4., 1.)); + testExpr(MIN( 1., 2., 3., 4.,NaN)); + testExpr(MIN( 1., 2., 3.,NaN, 4.)); + testExpr(MIN( 1., 2.,NaN, 4., 3.)); + testExpr(MIN( 1.,NaN, 3., 4., 2.)); + testExpr(MIN(NaN, 2., 3., 4., 1.)); + testExpr(MIN( 1., 2., 3., 4., 5., 6.)); + testExpr(MIN( 2., 1., 3., 4., 5., 6.)); + testExpr(MIN( 3., 2., 1., 4., 5., 6.)); + testExpr(MIN( 4., 2., 3., 1., 5., 6.)); + testExpr(MIN( 5., 2., 3., 4., 1., 6.)); + testExpr(MIN( 6., 2., 3., 4., 5., 1.)); + testExpr(MIN( 1., 2., 3., 4., 5.,NaN)); + testExpr(MIN( 1., 2., 3., 4.,NaN, 5.)); + testExpr(MIN( 1., 2., 3.,NaN, 5., 4.)); + testExpr(MIN( 1., 2.,NaN, 4., 5., 3.)); + testExpr(MIN( 1.,NaN, 3., 4., 5., 2.)); + testExpr(MIN(NaN, 2., 3., 4., 5., 1.)); + testExpr(MIN( 1., 2., 3., 4., 5.,-Inf)); + testExpr(MIN( 1., 2., 3., 4.,-Inf, 5.)); + testExpr(MIN( 1., 2., 3.,-Inf, 5., 4.)); + testExpr(MIN( 1., 2.,-Inf, 4., 5., 3.)); + testExpr(MIN( 1.,-Inf, 3., 4., 5., 2.)); + testExpr(MIN(-Inf, 2., 3., 4., 5., 1.)); + testExpr(MIN(1,2,3,4,5,6,7,8,9,10)); + testExpr(MIN(5,4,3,2,1,0,-1,-2,-3,-4)); + testExpr(MIN(1,-1,0)); + testExpr(MAX(MIN(0,2),MAX(0),MIN(3,2,1))); + + testExpr(NINT(0.4)); testExpr(NINT(0.6)); + testExpr(NINT(-0.4)); testExpr(NINT(-0.6)); testExpr(sin(0.5)); testExpr(sinh(0.5)); @@ -545,6 +781,16 @@ MAIN(epicsCalcTest) testCalc("1+(1|2)**3", 1+pow((double) (1 | 2), 3.));// 8 6 testExpr(1+(1?(1<2):(1>2))*2); + // Malformed expressions + testBadExpr("MIN", CALC_ERR_INCOMPLETE); + testBadExpr("MIN()", CALC_ERR_SYNTAX); + testBadExpr("MIN(A,)", CALC_ERR_SYNTAX); + testBadExpr("MIN(A,B,)", CALC_ERR_SYNTAX); + testBadExpr("MAX", CALC_ERR_INCOMPLETE); + testBadExpr("MAX()", CALC_ERR_SYNTAX); + testBadExpr("MAX(A,)", CALC_ERR_SYNTAX); + testBadExpr("MAX(A,B,)", CALC_ERR_SYNTAX); + return testDone(); }