Added variable argument functions, mostly by Benjamin Fransken.

MIN, MAX, FINITE and ISINF can now take any number of arguments.
This commit is contained in:
Andrew Johnson
2008-04-10 18:06:47 +00:00
parent df59c12f75
commit b281b453bb
3 changed files with 341 additions and 32 deletions

View File

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

View File

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

View File

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