diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2003-09-12 23:55:32 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2003-09-12 23:55:32 (GMT) |
commit | da60f636030ff5e28efdfe34eb534c9dd46e2fb3 (patch) | |
tree | 2f2c7e65505a410bb72e9cc37de0a6baab73939f | |
parent | 15cd6e14858186b0fc6748418f0c92ee5c1495ab (diff) | |
download | tcl-da60f636030ff5e28efdfe34eb534c9dd46e2fb3.zip tcl-da60f636030ff5e28efdfe34eb534c9dd46e2fb3.tar.gz tcl-da60f636030ff5e28efdfe34eb534c9dd46e2fb3.tar.bz2 |
TIP#123 Implementation based on work by Arjen Markus. [Patch 655176]
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | doc/expr.n | 30 | ||||
-rw-r--r-- | generic/tclCompExpr.c | 4 | ||||
-rw-r--r-- | generic/tclCompile.c | 4 | ||||
-rw-r--r-- | generic/tclCompile.h | 4 | ||||
-rw-r--r-- | generic/tclExecute.c | 211 | ||||
-rw-r--r-- | generic/tclParseExpr.c | 90 | ||||
-rw-r--r-- | tests/compExpr-old.test | 54 | ||||
-rw-r--r-- | tests/expr.test | 108 |
9 files changed, 428 insertions, 91 deletions
@@ -1,3 +1,17 @@ +2003-09-13 Donal K. Fellows <fellowsd@cs.man.ac.uk> + + TIP#123 IMPLEMENTATION BASED ON WORK BY ARJEN MARKUS + + * generic/tclCompile.h (INST_EXPON): Implementation of + * generic/tclCompile.c (tclInstructionTable): exponential operator. + * generic/tclCompExpr.c (operatorTable): + * generic/tclParseExpr.c (ParseExponentialExpr, GetLexeme): + * generic/tclExecute.c (TclExecuteByteCode, ExponWide, ExponLong): + (IllegalExprOperandType): + * tests/expr.test: + * tests/compExpr-old.test: + * doc/expr.n: + 2003-09-10 Don Porter <dgp@users.sourceforge.net> * library/opt/optparse.tcl: Latest revisions caused [OptGuessType] @@ -5,10 +5,10 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: expr.n,v 1.11 2003/07/04 22:22:07 dkf Exp $ +'\" RCS: @(#) $Id: expr.n,v 1.12 2003/09/12 23:55:32 dkf Exp $ '\" .so man.macros -.TH expr n 8.4 Tcl "Tcl Built-In Commands" +.TH expr n 8.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME @@ -55,12 +55,10 @@ If no numeric interpretation is possible, then an operand is left as a string (and only a limited set of operators may be applied to it). .PP -.VS 8.4 On 32-bit systems, integer values MAX_INT (0x7FFFFFFF) and MIN_INT (-0x80000000) will be represented as 32-bit values, and integer values outside that range will be represented as 64-bit values (if that is possible at all.) -.VE 8.4 .PP Operands may be specified in any of the following ways: .IP [1] @@ -117,6 +115,12 @@ Unary minus, unary plus, bit-wise NOT, logical NOT. None of these operands may be applied to string operands, and bit-wise NOT may be applied only to integers. .TP 20 +\fB**\fR +.VS 8.5 +Exponentiation. None of these operands may be applied to string +operands. +.VE 8.5 +.TP 20 \fB*\0\0/\0\0%\fR Multiply, divide, remainder. None of these operands may be applied to string operands, and remainder may be applied only @@ -140,12 +144,10 @@ in which case string comparison is used. \fB==\0\0!=\fR Boolean equal and not equal. Each operator produces a zero/one result. Valid for all operand types. -.VS 8.4 .TP 20 \fBeq\0\0ne\fR Boolean string equal and string not equal. Each operator produces a zero/one result. The operand types are interpreted only as strings. -.VE 8.4 .TP 20 \fB&\fR Bit-wise AND. Valid for integer operands only. @@ -173,6 +175,11 @@ The \fIx\fR operand must have a numeric value. .LP See the C manual for more details on the results produced by each operator. +.VS 8.5 +The exponentiation operator promotes types like the multiply and +divide operators, and produces a result that is the same as the output +of the \fBpow\fR function (after any type conversions.) +.VE 8.5 All of the binary operators group left-to-right within the same precedence level. For example, the command .CS @@ -261,13 +268,11 @@ Computes the length of the hypotenuse of a right-angled triangle \fBsqrt(\fIx\fR*\fIx\fR+\fIy\fR*\fIy\fB)\fR. .TP \fBint(\fIarg\fB)\fR -.VS 8.4 If \fIarg\fR is an integer value of the same width as the machine word, returns \fIarg\fR, otherwise converts \fIarg\fR to an integer (of the same size as a machine word, i.e. 32-bits on 32-bit systems, and 64-bits on 64-bit systems) by truncation and returns the converted value. -.VE 8.4 .TP \fBlog(\fIarg\fB)\fR Returns the natural logarithm of \fIarg\fR. \fIArg\fR must be a @@ -316,10 +321,8 @@ Returns the tangent of \fIarg\fR, measured in radians. Returns the hyperbolic tangent of \fIarg\fR. .TP \fBwide(\fIarg\fB)\fR -.VS 8.4 Converts \fIarg\fR to an integer value at least 64-bits wide (by sign-extension if \fIarg\fR is a 32-bit number) if it is not one already. -.VE 8.4 .PP In addition to these predefined functions, applications may define additional functions using \fBTcl_CreateMathFunc\fR(). @@ -365,9 +368,7 @@ returns \fB4.0\fR, not \fB4\fR. String values may be used as operands of the comparison operators, although the expression evaluator tries to do comparisons as integer or floating-point when it can, -.VS 8.4 except in the case of the \fBeq\fR and \fBne\fR operators. -.VE 8.4 If one of the operands of a comparison is a string and the other has a numeric value, the numeric operand is converted back to a string using the C \fIsprintf\fR format specifier @@ -384,10 +385,7 @@ Because of Tcl's tendency to treat values as numbers whenever possible, it isn't generally a good idea to use operators like \fB==\fR when you really want string comparison and the values of the operands could be arbitrary; it's better in these cases to use -.VS 8.4 -the \fBeq\fR or \fBne\fR operators, or -.VE 8.4 -the \fBstring\fR command instead. +the \fBeq\fR or \fBne\fR operators, or the \fBstring\fR command instead. .SH "PERFORMANCE CONSIDERATIONS" .PP diff --git a/generic/tclCompExpr.c b/generic/tclCompExpr.c index 480acfe..d4fecc0 100644 --- a/generic/tclCompExpr.c +++ b/generic/tclCompExpr.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompExpr.c,v 1.14 2003/03/13 02:48:52 dgp Exp $ + * RCS: @(#) $Id: tclCompExpr.c,v 1.15 2003/09/12 23:55:32 dkf Exp $ */ #include "tclInt.h" @@ -92,6 +92,7 @@ typedef struct ExprInfo { #define OP_BITNOT 20 #define OP_STREQ 21 #define OP_STRNEQ 22 +#define OP_EXPON 23 /* * Table describing the expression operators. Entries in this table must @@ -134,6 +135,7 @@ static OperatorDesc operatorTable[] = { {"~", 1, INST_BITNOT}, {"eq", 2, INST_STR_EQ}, {"ne", 2, INST_STR_NEQ}, + {"**", 2, INST_EXPON}, {NULL} }; diff --git a/generic/tclCompile.c b/generic/tclCompile.c index e76048b..10845d3 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompile.c,v 1.49 2003/05/09 13:53:42 msofer Exp $ + * RCS: @(#) $Id: tclCompile.c,v 1.50 2003/09/12 23:55:32 dkf Exp $ */ #include "tclInt.h" @@ -271,6 +271,8 @@ InstructionDesc tclInstructionTable[] = { */ {"return", 1, -1, 0, {OPERAND_NONE}}, /* return TCL_RETURN code. */ + {"expon", 1, -1, 0, {OPERAND_NONE}}, + /* Binary exponentiation operator: push (stknext ** stktop) */ {0} }; diff --git a/generic/tclCompile.h b/generic/tclCompile.h index 993bfd4..3233fd3 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompile.h,v 1.36 2003/03/19 16:51:42 dgp Exp $ + * RCS: @(#) $Id: tclCompile.h,v 1.37 2003/09/12 23:55:32 dkf Exp $ */ #ifndef _TCLCOMPILATION @@ -524,6 +524,8 @@ typedef struct ByteCode { #define INST_RETURN 98 +#define INST_EXPON 99 /* TIP#123 - exponentiation */ + /* The last opcode */ #define LAST_INST_OPCODE 98 diff --git a/generic/tclExecute.c b/generic/tclExecute.c index fcf2dae..316d831 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclExecute.c,v 1.105 2003/08/05 15:59:15 msofer Exp $ + * RCS: @(#) $Id: tclExecute.c,v 1.106 2003/09/12 23:55:32 dkf Exp $ */ #include "tclInt.h" @@ -87,13 +87,16 @@ int tclTraceExec = 0; * Mapping from expression instruction opcodes to strings; used for error * messages. Note that these entries must match the order and number of the * expression opcodes (e.g., INST_LOR) in tclCompile.h. + * + * Does not include the string for INST_EXPON (and beyond), as that is + * disjoint for backward-compatability reasons */ -static char *operatorStrings[] = { +static CONST char *operatorStrings[] = { "||", "&&", "|", "^", "&", "==", "!=", "<", ">", "<=", ">=", "<<", ">>", "+", "-", "*", "/", "%", "+", "-", "~", "!", "BUILTIN FUNCTION", "FUNCTION", - "", "", "", "", "", "", "", "", "eq", "ne", + "", "", "", "", "", "", "", "", "eq", "ne" }; /* @@ -378,6 +381,10 @@ static void ValidatePcAndStackTop _ANSI_ARGS_(( #endif /* TCL_COMPILE_DEBUG */ static int VerifyExprObjType _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); +static Tcl_WideInt ExponWide _ANSI_ARGS_((Tcl_WideInt w, Tcl_WideInt w2, + int *errExpon)); +static long ExponLong _ANSI_ARGS_((long i, long i2, + int *errExpon)); /* * Table describing the built-in math functions. Entries in this table are @@ -3159,6 +3166,7 @@ TclExecuteByteCode(interp, codePtr) case INST_SUB: case INST_MULT: case INST_DIV: + case INST_EXPON: { /* * Operands must be numeric and ints get converted to floats @@ -3275,6 +3283,13 @@ TclExecuteByteCode(interp, codePtr) } dResult = d1 / d2; break; + case INST_EXPON: + if (d1==0.0 && d2<0.0) { + TRACE(("%.6g %.6g => EXPONENT OF ZERO\n", d1, d2)); + goto exponOfZero; + } + dResult = pow(d1, d2); + break; } /* @@ -3331,11 +3346,21 @@ TclExecuteByteCode(interp, codePtr) } wResult = wquot; break; + case INST_EXPON: { + int errExpon; + + wResult = ExponWide(w, w2, &errExpon); + if (errExpon) { + TRACE((LLD" "LLD" => EXPONENT OF ZERO\n", w, w2)); + goto exponOfZero; + } + break; + } } } else { /* - * Do integer arithmetic. - */ + * Do integer arithmetic. + */ switch (*pc) { case INST_ADD: iResult = i + i2; @@ -3368,6 +3393,16 @@ TclExecuteByteCode(interp, codePtr) } iResult = quot; break; + case INST_EXPON: { + int errExpon; + + iResult = ExponLong(i, i2, &errExpon); + if (errExpon) { + TRACE(("%ld %ld => EXPONENT OF ZERO\n", i, i2)); + goto exponOfZero; + } + break; + } } } @@ -4044,7 +4079,21 @@ TclExecuteByteCode(interp, codePtr) (char *) NULL); result = TCL_ERROR; goto checkForCatch; - + + /* + * Exponentiation of zero by negative number in an expression. + * Control only reaches this point by "goto exponOfZero". + */ + + exponOfZero: + Tcl_ResetResult(interp); + Tcl_AppendToObj(Tcl_GetObjResult(interp), + "exponentiation of zero by negative power", -1); + Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", + "exponentiation of zero by negative power", (char *) NULL); + result = TCL_ERROR; + goto checkForCatch; + /* * An external evaluation (INST_INVOKE or INST_EVAL) returned * something different from TCL_OK, or else INST_BREAK or @@ -4381,12 +4430,16 @@ IllegalExprOperandType(interp, pc, opndPtr) * with the illegal type. */ { unsigned char opCode = *pc; - + CONST char *operator = operatorStrings[opCode - INST_LOR]; + if (opCode == INST_EXPON) { + operator = "**"; + } + Tcl_ResetResult(interp); if ((opndPtr->bytes == NULL) || (opndPtr->length == 0)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), - "can't use empty string as operand of \"", - operatorStrings[opCode - INST_LOR], "\"", (char *) NULL); + "can't use empty string as operand of \"", operator, "\"", + (char *) NULL); } else { char *msg = "non-numeric string"; char *s, *p; @@ -4485,8 +4538,7 @@ IllegalExprOperandType(interp, pc, opndPtr) } makeErrorMessage: Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't use ", - msg, " as operand of \"", operatorStrings[opCode - INST_LOR], - "\"", (char *) NULL); + msg, " as operand of \"", operator, "\"", (char *) NULL); } } @@ -6180,3 +6232,140 @@ StringForResultCode(result) return buf; } #endif /* TCL_COMPILE_DEBUG */ + +/* + *---------------------------------------------------------------------- + * + * ExponWide -- + * + * Procedure to return w**w2 as wide integer + * + * Results: + * Return value is w to the power w2, unless the computation + * makes no sense mathematically. In that case *errExpon is + * set to 1. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_WideInt +ExponWide(w, w2, errExpon) + Tcl_WideInt w; /* The value that must be exponentiated */ + Tcl_WideInt w2; /* The exponent */ + int *errExpon; /* Error code */ +{ + Tcl_WideInt result; + + *errExpon = 0; + + /* + * Check for possible errors and simple/edge cases + */ + + if (w == 0) { + if (w2 < 0) { + *errExpon = 1; + return W0; + } else if (w2 > 0) { + return W0; + } + return Tcl_LongAsWide(1); /* By definition and analysis */ + } else if (w < -1) { + if (w2 < 0) { + return W0; + } else if (w2 == 0) { + return Tcl_LongAsWide(1); + } + } else if (w == -1) { + return (w2 & 1) ? Tcl_LongAsWide(-1) : Tcl_LongAsWide(1); + } else if (w == 1) { + return Tcl_LongAsWide(1); + } else if (w>1 && w2<0) { + return W0; + } + + /* + * The general case. + */ + + result = Tcl_LongAsWide(1); + for (; w2>Tcl_LongAsWide(1) ; w*=w,w2/=2) { + if (w2 & 1) { + result *= w; + } + } + return result * w; +} + +/* + *---------------------------------------------------------------------- + * + * ExponLong -- + * + * Procedure to return i**i2 as long integer + * + * Results: + * Return value is i to the power i2, unless the computation + * makes no sense mathematically. In that case *errExpon is + * set to 1. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static long +ExponLong(i, i2, errExpon) + long i; /* The value that must be exponentiated */ + long i2; /* The exponent */ + int *errExpon; /* Error code */ +{ + long result; + + *errExpon = 0; + + /* + * Check for possible errors and simple cases + */ + + if (i == 0) { + if (i2 < 0) { + *errExpon = 1; + return 0L; + } else if (i2 > 0) { + return 0L; + } + /* + * By definition and analysis, 0**0 is 1. + */ + return 1L; + } else if (i < -1) { + if (i2 < 0) { + return 0L; + } else if (i2 == 0) { + return 1L; + } + } else if (i == -1) { + return (i2&1) ? -1L : 1L; + } else if (i == 1) { + return 1L; + } else if (i > 1 && i2 < 0) { + return 0L; + } + + /* + * The general case + */ + + result = 1; + for (; i2>1 ; i*=i,i2/=2) { + if (i2 & 1) { + result *= i; + } + } + return result * i; +} diff --git a/generic/tclParseExpr.c b/generic/tclParseExpr.c index bb88159..a0c0316 100644 --- a/generic/tclParseExpr.c +++ b/generic/tclParseExpr.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclParseExpr.c,v 1.17 2003/02/16 01:36:32 msofer Exp $ + * RCS: @(#) $Id: tclParseExpr.c,v 1.18 2003/09/12 23:55:34 dkf Exp $ */ #include "tclInt.h" @@ -130,6 +130,12 @@ typedef struct ParseInfo { #define STRNEQ 35 /* + * Exponentiation operator: + */ + +#define EXPON 36 + +/* * Mapping from lexemes to strings; used for debugging messages. These * entries must match the order and number of the lexeme definitions above. */ @@ -140,7 +146,7 @@ static char *lexemeStrings[] = { "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=", ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", ":", - "!", "~", "eq", "ne", + "!", "~", "eq", "ne", "**" }; /* @@ -164,6 +170,7 @@ static int ParseMultiplyExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParsePrimaryExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseRelationalExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseShiftExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseExponentialExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseUnaryExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static void PrependSubExprTokens _ANSI_ARGS_((CONST char *op, int opBytes, CONST char *src, int srcBytes, @@ -976,7 +983,7 @@ ParseAddExpr(infoPtr) * ParseMultiplyExpr -- * * This procedure parses a Tcl multiply expression: - * multiplyExpr ::= unaryExpr {('*' | '/' | '%') unaryExpr} + * multiplyExpr ::= exponentialExpr {('*' | '/' | '%') exponentialExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR @@ -1004,7 +1011,7 @@ ParseMultiplyExpr(infoPtr) srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; - code = ParseUnaryExpr(infoPtr); + code = ParseExponentialExpr(infoPtr); if (code != TCL_OK) { return code; } @@ -1016,7 +1023,7 @@ ParseMultiplyExpr(infoPtr) if (code != TCL_OK) { return code; } - code = ParseUnaryExpr(infoPtr); + code = ParseExponentialExpr(infoPtr); if (code != TCL_OK) { return code; } @@ -1035,6 +1042,69 @@ ParseMultiplyExpr(infoPtr) /* *---------------------------------------------------------------------- * + * ParseExponentialExpr -- + * + * This procedure parses a Tcl exponential expression: + * exponentialExpr ::= unaryExpr {'**' unaryExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseExponentialExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, lexeme, code; + CONST char *srcStart, *operator; + + HERE("exponentiateExpr", 12); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseUnaryExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + lexeme = infoPtr->lexeme; + while (lexeme == EXPON) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over ** */ + if (code != TCL_OK) { + return code; + } + code = ParseUnaryExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the subexpression and ** operator. + */ + + PrependSubExprTokens(operator, 2, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + lexeme = infoPtr->lexeme; + } + return TCL_OK; +} + + +/* + *---------------------------------------------------------------------- + * * ParseUnaryExpr -- * * This procedure parses a Tcl unary expression: @@ -1062,7 +1132,7 @@ ParseUnaryExpr(infoPtr) int firstIndex, lexeme, code; CONST char *srcStart, *operator; - HERE("unaryExpr", 12); + HERE("unaryExpr", 13); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; @@ -1132,7 +1202,7 @@ ParsePrimaryExpr(infoPtr) * We simply recurse on parenthesized subexpressions. */ - HERE("primaryExpr", 13); + HERE("primaryExpr", 14); lexeme = infoPtr->lexeme; if (lexeme == OPEN_PAREN) { code = GetLexeme(infoPtr); /* skip over the '(' */ @@ -1681,6 +1751,12 @@ GetLexeme(infoPtr) case '*': infoPtr->lexeme = MULT; + if ((infoPtr->lastChar - src)>1 && src[1]=='*') { + infoPtr->lexeme = EXPON; + infoPtr->size = 2; + infoPtr->next = src+2; + parsePtr->term = infoPtr->next; + } return TCL_OK; case '/': diff --git a/tests/compExpr-old.test b/tests/compExpr-old.test index b7df34c..2c9b778 100644 --- a/tests/compExpr-old.test +++ b/tests/compExpr-old.test @@ -12,7 +12,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: compExpr-old.test,v 1.7 2001/12/06 10:59:17 dkf Exp $ +# RCS: @(#) $Id: compExpr-old.test,v 1.8 2003/09/12 23:55:34 dkf Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest @@ -133,9 +133,9 @@ test compExpr-old-2.1 {TclCompileExpr: are builtin functions registered?} { expr double(5*[llength "6 2"]) } 10.0 test compExpr-old-2.2 {TclCompileExpr: error in expr} { - catch {expr 2**3} msg + catch {expr 2***3} msg set msg -} {syntax error in expression "2**3": unexpected operator *} +} {syntax error in expression "2***3": unexpected operator *} test compExpr-old-2.3 {TclCompileExpr: junk after legal expr} { catch {expr 7*[llength "a b"]foo} msg set msg @@ -151,14 +151,14 @@ test compExpr-old-3.2 {CompileCondExpr: error in lor expr} { } {syntax error in expression "x||3": variable references require preceding $} test compExpr-old-3.3 {CompileCondExpr: test true arm} {expr 3>2?44:66} 44 test compExpr-old-3.4 {CompileCondExpr: error compiling true arm} { - catch {expr 3>2?2**3:66} msg + catch {expr 3>2?2***3:66} msg set msg -} {syntax error in expression "3>2?2**3:66": unexpected operator *} +} {syntax error in expression "3>2?2***3:66": unexpected operator *} test compExpr-old-3.5 {CompileCondExpr: test false arm} {expr 2>3?44:66} 66 test compExpr-old-3.6 {CompileCondExpr: error compiling false arm} { - catch {expr 2>3?44:2**3} msg + catch {expr 2>3?44:2***3} msg set msg -} {syntax error in expression "2>3?44:2**3": unexpected operator *} +} {syntax error in expression "2>3?44:2***3": unexpected operator *} test compExpr-old-3.7 {CompileCondExpr: long arms & nested cond exprs} {nonPortable} { puts "Note: doing test compExpr-old-3.7 which can take several minutes to run" hello_world @@ -179,13 +179,13 @@ test compExpr-old-4.3 {CompileLorExpr: simple lor exprs} {expr 0||1.0} 1 test compExpr-old-4.4 {CompileLorExpr: simple lor exprs} {expr 3.0||0.0} 1 test compExpr-old-4.5 {CompileLorExpr: simple lor exprs} {expr 0||0||1} 1 test compExpr-old-4.6 {CompileLorExpr: error compiling lor arm} { - catch {expr 2**3||4.0} msg + catch {expr 2***3||4.0} msg set msg -} {syntax error in expression "2**3||4.0": unexpected operator *} +} {syntax error in expression "2***3||4.0": unexpected operator *} test compExpr-old-4.7 {CompileLorExpr: error compiling lor arm} { - catch {expr 1.3||2**3} msg + catch {expr 1.3||2***3} msg set msg -} {syntax error in expression "1.3||2**3": unexpected operator *} +} {syntax error in expression "1.3||2***3": unexpected operator *} test compExpr-old-4.8 {CompileLorExpr: error compiling lor arms} { list [catch {expr {"a"||"b"}} msg] $msg } {1 {expected boolean value but got "a"}} @@ -205,13 +205,13 @@ test compExpr-old-5.4 {CompileLandExpr: simple land exprs} {expr 0&&0} 0 test compExpr-old-5.5 {CompileLandExpr: simple land exprs} {expr 3.0&&1.2} 1 test compExpr-old-5.6 {CompileLandExpr: simple land exprs} {expr 1&&1&&2} 1 test compExpr-old-5.7 {CompileLandExpr: error compiling land arm} { - catch {expr 2**3&&4.0} msg + catch {expr 2***3&&4.0} msg set msg -} {syntax error in expression "2**3&&4.0": unexpected operator *} +} {syntax error in expression "2***3&&4.0": unexpected operator *} test compExpr-old-5.8 {CompileLandExpr: error compiling land arm} { - catch {expr 1.3&&2**3} msg + catch {expr 1.3&&2***3} msg set msg -} {syntax error in expression "1.3&&2**3": unexpected operator *} +} {syntax error in expression "1.3&&2***3": unexpected operator *} test compExpr-old-5.9 {CompileLandExpr: error compiling land arm} { list [catch {expr {"a"&&"b"}} msg] $msg } {1 {expected boolean value but got "a"}} @@ -231,9 +231,9 @@ test compExpr-old-6.4 {CompileBitXorExpr: simple bitxor exprs} {expr 3^0x10} 19 test compExpr-old-6.5 {CompileBitXorExpr: simple bitxor exprs} {expr 0^7} 7 test compExpr-old-6.6 {CompileBitXorExpr: simple bitxor exprs} {expr -1^7} -8 test compExpr-old-6.7 {CompileBitXorExpr: error compiling bitxor arm} { - catch {expr 2**3|6} msg + catch {expr 2***3|6} msg set msg -} {syntax error in expression "2**3|6": unexpected operator *} +} {syntax error in expression "2***3|6": unexpected operator *} test compExpr-old-6.8 {CompileBitXorExpr: error compiling bitxor arm} { catch {expr 2^x} msg set msg @@ -258,9 +258,9 @@ test compExpr-old-7.7 {CompileBitAndExpr: simple bitand exprs} {expr 0xf2&0x53} test compExpr-old-7.8 {CompileBitAndExpr: simple bitand exprs} {expr 3&6} 2 test compExpr-old-7.9 {CompileBitAndExpr: simple bitand exprs} {expr -1&-7} -7 test compExpr-old-7.10 {CompileBitAndExpr: error compiling bitand arm} { - catch {expr 2**3&6} msg + catch {expr 2***3&6} msg set msg -} {syntax error in expression "2**3&6": unexpected operator *} +} {syntax error in expression "2***3&6": unexpected operator *} test compExpr-old-7.11 {CompileBitAndExpr: error compiling bitand arm} { catch {expr 2&x} msg set msg @@ -285,9 +285,9 @@ test compExpr-old-8.7 {CompileEqualityExpr: simple equality exprs} {expr -0xf2!= test compExpr-old-8.8 {CompileEqualityExpr: simple equality exprs} {expr {"12398712938788234-1298379" != ""}} 1 test compExpr-old-8.9 {CompileEqualityExpr: simple equality exprs} {expr -1!="abc"} 1 test compExpr-old-8.10 {CompileEqualityExpr: error compiling equality arm} { - catch {expr 2**3==6} msg + catch {expr 2***3==6} msg set msg -} {syntax error in expression "2**3==6": unexpected operator *} +} {syntax error in expression "2***3==6": unexpected operator *} test compExpr-old-8.11 {CompileEqualityExpr: error compiling equality arm} { catch {expr 2!=x} msg set msg @@ -318,9 +318,9 @@ test compExpr-old-9.6 {CompileRelationalExpr: error in shift expr} { test compExpr-old-9.7 {CompileRelationalExpr: simple relational exprs} {expr 0xff>=+0x3} 1 test compExpr-old-9.8 {CompileRelationalExpr: simple relational exprs} {expr -0xf2<0x3} 1 test compExpr-old-9.9 {CompileRelationalExpr: error compiling relational arm} { - catch {expr 2**3>6} msg + catch {expr 2***3>6} msg set msg -} {syntax error in expression "2**3>6": unexpected operator *} +} {syntax error in expression "2***3>6": unexpected operator *} test compExpr-old-9.10 {CompileRelationalExpr: error compiling relational arm} { catch {expr 2<x} msg set msg @@ -337,9 +337,9 @@ test compExpr-old-10.5 {CompileShiftExpr: error in add expr} { test compExpr-old-10.6 {CompileShiftExpr: simple shift exprs} {expr 0xff>>0x3} 31 test compExpr-old-10.7 {CompileShiftExpr: simple shift exprs} {expr -0xf2<<0x3} -1936 test compExpr-old-10.8 {CompileShiftExpr: error compiling shift arm} { - catch {expr 2**3>>6} msg + catch {expr 2***3>>6} msg set msg -} {syntax error in expression "2**3>>6": unexpected operator *} +} {syntax error in expression "2***3>>6": unexpected operator *} test compExpr-old-10.9 {CompileShiftExpr: error compiling shift arm} { catch {expr 2<<x} msg set msg @@ -362,9 +362,9 @@ test compExpr-old-11.5 {CompileAddExpr: error in multiply expr} { test compExpr-old-11.6 {CompileAddExpr: simple add exprs} {expr 0xff++0x3} 258 test compExpr-old-11.7 {CompileAddExpr: simple add exprs} {expr -0xf2--0x3} -239 test compExpr-old-11.8 {CompileAddExpr: error compiling add arm} { - catch {expr 2**3+6} msg + catch {expr 2***3+6} msg set msg -} {syntax error in expression "2**3+6": unexpected operator *} +} {syntax error in expression "2***3+6": unexpected operator *} test compExpr-old-11.9 {CompileAddExpr: error compiling add arm} { catch {expr 2-x} msg set msg diff --git a/tests/expr.test b/tests/expr.test index b11dc15..e1bb6cc 100644 --- a/tests/expr.test +++ b/tests/expr.test @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: expr.test,v 1.18 2003/03/27 13:48:59 dkf Exp $ +# RCS: @(#) $Id: expr.test,v 1.19 2003/09/12 23:55:34 dkf Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest @@ -132,9 +132,9 @@ test expr-2.1 {TclCompileExpr: are builtin functions registered?} { expr double(5*[llength "6 2"]) } 10.0 test expr-2.2 {TclCompileExpr: error in expr} { - catch {expr 2**3} msg + catch {expr 2***3} msg set msg -} {syntax error in expression "2**3": unexpected operator *} +} {syntax error in expression "2***3": unexpected operator *} test expr-2.3 {TclCompileExpr: junk after legal expr} { catch {expr 7*[llength "a b"]foo} msg set msg @@ -150,14 +150,14 @@ test expr-3.2 {CompileCondExpr: error in lor expr} { } {syntax error in expression "x||3": variable references require preceding $} test expr-3.3 {CompileCondExpr: test true arm} {expr 3>2?44:66} 44 test expr-3.4 {CompileCondExpr: error compiling true arm} { - catch {expr 3>2?2**3:66} msg + catch {expr 3>2?2***3:66} msg set msg -} {syntax error in expression "3>2?2**3:66": unexpected operator *} +} {syntax error in expression "3>2?2***3:66": unexpected operator *} test expr-3.5 {CompileCondExpr: test false arm} {expr 2>3?44:66} 66 test expr-3.6 {CompileCondExpr: error compiling false arm} { - catch {expr 2>3?44:2**3} msg + catch {expr 2>3?44:2***3} msg set msg -} {syntax error in expression "2>3?44:2**3": unexpected operator *} +} {syntax error in expression "2>3?44:2***3": unexpected operator *} test expr-3.7 {CompileCondExpr: long arms & nested cond exprs} {unixOnly nonPortable} { puts "Note: doing test expr-3.7 which can take several minutes to run" hello_world @@ -178,13 +178,13 @@ test expr-4.3 {CompileLorExpr: simple lor exprs} {expr 0||1.0} 1 test expr-4.4 {CompileLorExpr: simple lor exprs} {expr 3.0||0.0} 1 test expr-4.5 {CompileLorExpr: simple lor exprs} {expr 0||0||1} 1 test expr-4.6 {CompileLorExpr: error compiling lor arm} { - catch {expr 2**3||4.0} msg + catch {expr 2***3||4.0} msg set msg -} {syntax error in expression "2**3||4.0": unexpected operator *} +} {syntax error in expression "2***3||4.0": unexpected operator *} test expr-4.7 {CompileLorExpr: error compiling lor arm} { - catch {expr 1.3||2**3} msg + catch {expr 1.3||2***3} msg set msg -} {syntax error in expression "1.3||2**3": unexpected operator *} +} {syntax error in expression "1.3||2***3": unexpected operator *} test expr-4.8 {CompileLorExpr: error compiling lor arms} { list [catch {expr {"a"||"b"}} msg] $msg } {1 {expected boolean value but got "a"}} @@ -204,13 +204,13 @@ test expr-5.4 {CompileLandExpr: simple land exprs} {expr 0&&0} 0 test expr-5.5 {CompileLandExpr: simple land exprs} {expr 3.0&&1.2} 1 test expr-5.6 {CompileLandExpr: simple land exprs} {expr 1&&1&&2} 1 test expr-5.7 {CompileLandExpr: error compiling land arm} { - catch {expr 2**3&&4.0} msg + catch {expr 2***3&&4.0} msg set msg -} {syntax error in expression "2**3&&4.0": unexpected operator *} +} {syntax error in expression "2***3&&4.0": unexpected operator *} test expr-5.8 {CompileLandExpr: error compiling land arm} { - catch {expr 1.3&&2**3} msg + catch {expr 1.3&&2***3} msg set msg -} {syntax error in expression "1.3&&2**3": unexpected operator *} +} {syntax error in expression "1.3&&2***3": unexpected operator *} test expr-5.9 {CompileLandExpr: error compiling land arm} { list [catch {expr {"a"&&"b"}} msg] $msg } {1 {expected boolean value but got "a"}} @@ -230,9 +230,9 @@ test expr-6.4 {CompileBitXorExpr: simple bitxor exprs} {expr 3^0x10} 19 test expr-6.5 {CompileBitXorExpr: simple bitxor exprs} {expr 0^7} 7 test expr-6.6 {CompileBitXorExpr: simple bitxor exprs} {expr -1^7} -8 test expr-6.7 {CompileBitXorExpr: error compiling bitxor arm} { - catch {expr 2**3|6} msg + catch {expr 2***3|6} msg set msg -} {syntax error in expression "2**3|6": unexpected operator *} +} {syntax error in expression "2***3|6": unexpected operator *} test expr-6.8 {CompileBitXorExpr: error compiling bitxor arm} { catch {expr 2^x} msg set msg @@ -257,9 +257,9 @@ test expr-7.7 {CompileBitAndExpr: simple bitand exprs} {expr 0xf2&0x53} 82 test expr-7.8 {CompileBitAndExpr: simple bitand exprs} {expr 3&6} 2 test expr-7.9 {CompileBitAndExpr: simple bitand exprs} {expr -1&-7} -7 test expr-7.10 {CompileBitAndExpr: error compiling bitand arm} { - catch {expr 2**3&6} msg + catch {expr 2***3&6} msg set msg -} {syntax error in expression "2**3&6": unexpected operator *} +} {syntax error in expression "2***3&6": unexpected operator *} test expr-7.11 {CompileBitAndExpr: error compiling bitand arm} { catch {expr 2&x} msg set msg @@ -290,9 +290,9 @@ test expr-8.7 {CompileEqualityExpr: simple equality exprs} {expr -0xf2!=0x53} 1 test expr-8.8 {CompileEqualityExpr: simple equality exprs} {expr {"12398712938788234-1298379" != ""}} 1 test expr-8.9 {CompileEqualityExpr: simple equality exprs} {expr -1!="abc"} 1 test expr-8.10 {CompileEqualityExpr: error compiling equality arm} { - catch {expr 2**3==6} msg + catch {expr 2***3==6} msg set msg -} {syntax error in expression "2**3==6": unexpected operator *} +} {syntax error in expression "2***3==6": unexpected operator *} test expr-8.11 {CompileEqualityExpr: error compiling equality arm} { catch {expr 2!=x} msg set msg @@ -339,9 +339,9 @@ test expr-9.6 {CompileRelationalExpr: error in shift expr} { test expr-9.7 {CompileRelationalExpr: simple relational exprs} {expr 0xff>=+0x3} 1 test expr-9.8 {CompileRelationalExpr: simple relational exprs} {expr -0xf2<0x3} 1 test expr-9.9 {CompileRelationalExpr: error compiling relational arm} { - catch {expr 2**3>6} msg + catch {expr 2***3>6} msg set msg -} {syntax error in expression "2**3>6": unexpected operator *} +} {syntax error in expression "2***3>6": unexpected operator *} test expr-9.10 {CompileRelationalExpr: error compiling relational arm} { catch {expr 2<x} msg set msg @@ -358,9 +358,9 @@ test expr-10.5 {CompileShiftExpr: error in add expr} { test expr-10.6 {CompileShiftExpr: simple shift exprs} {expr 0xff>>0x3} 31 test expr-10.7 {CompileShiftExpr: simple shift exprs} {expr -0xf2<<0x3} -1936 test expr-10.8 {CompileShiftExpr: error compiling shift arm} { - catch {expr 2**3>>6} msg + catch {expr 2***3>>6} msg set msg -} {syntax error in expression "2**3>>6": unexpected operator *} +} {syntax error in expression "2***3>>6": unexpected operator *} test expr-10.9 {CompileShiftExpr: error compiling shift arm} { catch {expr 2<<x} msg set msg @@ -383,9 +383,9 @@ test expr-11.5 {CompileAddExpr: error in multiply expr} { test expr-11.6 {CompileAddExpr: simple add exprs} {expr 0xff++0x3} 258 test expr-11.7 {CompileAddExpr: simple add exprs} {expr -0xf2--0x3} -239 test expr-11.8 {CompileAddExpr: error compiling add arm} { - catch {expr 2**3+6} msg + catch {expr 2***3+6} msg set msg -} {syntax error in expression "2**3+6": unexpected operator *} +} {syntax error in expression "2***3+6": unexpected operator *} test expr-11.9 {CompileAddExpr: error compiling add arm} { catch {expr 2-x} msg set msg @@ -806,6 +806,60 @@ test expr-22.8 {non-numeric floats} nonPortable { list [catch {expr {1 / Inf}} msg] $msg } {1 {can't use infinite floating-point value as operand of "/"}} +# Tests for exponentiation handling +test expr-23.1 {CompileExponentialExpr: just exponential expr} {expr 4**2} 16 +test expr-23.2 {CompileExponentialExpr: just exponential expr} {expr 0xff**2} 65025 +test expr-23.3 {CompileExponentialExpr: just exponential expr} {expr -1**2} 1 +test expr-23.4 {CompileExponentialExpr: just exponential expr} {expr 7891**0123} 75407563 +test expr-23.5 {CompileExponentialExpr: error in exponential expr} { + catch {expr x**3} msg + set msg +} {syntax error in expression "x**3": variable references require preceding $} +test expr-23.6 {CompileExponentialExpr: simple expo exprs} {expr 0xff**0x3} 16581375 +test expr-23.7 {CompileExponentialExpr: error compiling expo arm} { + catch {expr (-3-)**6} msg + set msg +} {syntax error in expression "(-3-)**6": unexpected close parenthesis} +test expr-23.8 {CompileExponentialExpr: error compiling expo arm} { + catch {expr 2**x} msg + set msg +} {syntax error in expression "2**x": variable references require preceding $} +test expr-23.9 {CompileExponentialExpr: runtime error} { + list [catch {expr {24.0**"xx"}} msg] $msg +} {1 {can't use non-numeric string as operand of "**"}} +test expr-23.10 {CompileExponentialExpr: runtime error} { + list [catch {expr {"a"**2}} msg] $msg +} {1 {can't use non-numeric string as operand of "**"}} +test expr-23.11 {CompileExponentialExpr: runtime error} { + list [catch {expr {0**-1}} msg] $msg +} {1 {exponentiation of zero by negative power}} +test expr-23.12 {CompileExponentialExpr: runtime error} { + list [catch {expr {0.0**-1.0}} msg] $msg +} {1 {exponentiation of zero by negative power}} +test expr-23.13 {CompileExponentialExpr: runtime error} { + list [catch {expr {wide(0)**wide(-1)}} msg] $msg +} {1 {exponentiation of zero by negative power}} +test epxr-23.14 {INST_EXPON: special cases} {expr {0**1}} 0 +test epxr-23.15 {INST_EXPON: special cases} {expr {0**0}} 1 +test epxr-23.16 {INST_EXPON: special cases} {expr {-2**-1}} 0 +test epxr-23.17 {INST_EXPON: special cases} {expr {-2**0}} 1 +test epxr-23.18 {INST_EXPON: special cases} {expr {-1**1}} -1 +test epxr-23.19 {INST_EXPON: special cases} {expr {-1**0}} 1 +test epxr-23.20 {INST_EXPON: special cases} {expr {-1**2}} 1 +test epxr-23.21 {INST_EXPON: special cases} {expr {-1**-1}} -1 +test epxr-23.22 {INST_EXPON: special cases} {expr {1**1234567}} 1 +test epxr-23.23 {INST_EXPON: special cases} {expr {2**-2}} 0 +test epxr-23.24 {INST_EXPON: special cases} {expr {wide(0)**wide(1)}} 0 +test epxr-23.25 {INST_EXPON: special cases} {expr {wide(0)**wide(0)}} 1 +test epxr-23.26 {INST_EXPON: special cases} {expr {wide(-2)**wide(-1)}} 0 +test epxr-23.27 {INST_EXPON: special cases} {expr {wide(-2)**wide(0)}} 1 +test epxr-23.28 {INST_EXPON: special cases} {expr {wide(-1)**wide(1)}} -1 +test epxr-23.29 {INST_EXPON: special cases} {expr {wide(-1)**wide(0)}} 1 +test epxr-23.30 {INST_EXPON: special cases} {expr {wide(-1)**wide(2)}} 1 +test epxr-23.31 {INST_EXPON: special cases} {expr {wide(-1)**wide(-1)}} -1 +test epxr-23.32 {INST_EXPON: special cases} {expr {wide(1)**wide(1234567)}} 1 +test epxr-23.33 {INST_EXPON: special cases} {expr {wide(2)**wide(-2)}} 0 + # cleanup if {[info exists a]} { unset a |