Tcl Source Code

Artifact [48e525fa7d]
Login

Artifact 48e525fa7d5e182dd2bf90063ca3feac9d98ecf1:

Attachment "tcl_expon.patch" to ticket [655176ffff] added by dkf 2003-09-13 07:06:30.
Index: doc/expr.n
===================================================================
RCS file: /cvsroot/tcl/tcl/doc/expr.n,v
retrieving revision 1.11
diff -u -r1.11 expr.n
--- doc/expr.n	4 Jul 2003 22:22:07 -0000	1.11
+++ doc/expr.n	12 Sep 2003 23:41:06 -0000
@@ -8,7 +8,7 @@
 '\" RCS: @(#) $Id: expr.n,v 1.11 2003/07/04 22:22:07 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 @@
 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 @@
 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 @@
 \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 @@
 .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 @@
 \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 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 @@
 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 @@
 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
Index: generic/tclCompExpr.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompExpr.c,v
retrieving revision 1.14
diff -u -r1.14 tclCompExpr.c
--- generic/tclCompExpr.c	13 Mar 2003 02:48:52 -0000	1.14
+++ generic/tclCompExpr.c	12 Sep 2003 23:41:06 -0000
@@ -92,6 +92,7 @@
 #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 @@
     {"~",   1,  INST_BITNOT},
     {"eq",  2,  INST_STR_EQ},
     {"ne",  2,  INST_STR_NEQ},
+    {"**",  2,	INST_EXPON},
     {NULL}
 };
 
Index: generic/tclCompile.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.c,v
retrieving revision 1.49
diff -u -r1.49 tclCompile.c
--- generic/tclCompile.c	9 May 2003 13:53:42 -0000	1.49
+++ generic/tclCompile.c	12 Sep 2003 23:41:06 -0000
@@ -271,6 +271,8 @@
 	 */
     {"return",		  1,   -1,          0,   {OPERAND_NONE}},
 	/* return TCL_RETURN code. */
+    {"expon",		  1,   -1,	    0,	 {OPERAND_NONE}},
+	/* Binary exponentiation operator: push (stknext ** stktop) */
     {0}
 };
 
Index: generic/tclCompile.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.h,v
retrieving revision 1.36
diff -u -r1.36 tclCompile.h
--- generic/tclCompile.h	19 Mar 2003 16:51:42 -0000	1.36
+++ generic/tclCompile.h	12 Sep 2003 23:41:07 -0000
@@ -524,6 +524,8 @@
 
 #define INST_RETURN			98
 
+#define INST_EXPON			99 /* TIP#123 - exponentiation */
+
 /* The last opcode */
 #define LAST_INST_OPCODE        	98
 
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.105
diff -u -r1.105 tclExecute.c
--- generic/tclExecute.c	5 Aug 2003 15:59:15 -0000	1.105
+++ generic/tclExecute.c	12 Sep 2003 23:41:07 -0000
@@ -87,13 +87,16 @@
  * 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 @@
 #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 @@
     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 @@
 		    }
 		    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 @@
 		    }
 		    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 @@
 		    }
 		    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 @@
             (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 @@
 				 * 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 @@
 	}
       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 @@
     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;
+}
Index: generic/tclParseExpr.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclParseExpr.c,v
retrieving revision 1.17
diff -u -r1.17 tclParseExpr.c
--- generic/tclParseExpr.c	16 Feb 2003 01:36:32 -0000	1.17
+++ generic/tclParseExpr.c	12 Sep 2003 23:41:07 -0000
@@ -130,6 +130,12 @@
 #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 @@
     "*", "/", "%", "+", "-",
     "<<", ">>", "<", ">", "<=", ">=", "==", "!=",
     "&", "^", "|", "&&", "||", "?", ":",
-    "!", "~", "eq", "ne",
+    "!", "~", "eq", "ne", "**"
 };
 
 /*
@@ -164,6 +170,7 @@
 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 @@
  * 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 @@
     srcStart = infoPtr->start;
     firstIndex = parsePtr->numTokens;
     
-    code = ParseUnaryExpr(infoPtr);
+    code = ParseExponentialExpr(infoPtr);
     if (code != TCL_OK) {
 	return code;
     }
@@ -1016,7 +1023,7 @@
 	if (code != TCL_OK) {
 	    return code;
 	}
-	code = ParseUnaryExpr(infoPtr);
+	code = ParseExponentialExpr(infoPtr);
 	if (code != TCL_OK) {
 	    return code;
 	}
@@ -1035,6 +1042,69 @@
 /*
  *----------------------------------------------------------------------
  *
+ * 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 @@
     int firstIndex, lexeme, code;
     CONST char *srcStart, *operator;
 
-    HERE("unaryExpr", 12);
+    HERE("unaryExpr", 13);
     srcStart = infoPtr->start;
     firstIndex = parsePtr->numTokens;
     
@@ -1132,7 +1202,7 @@
      * 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 @@
 
 	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 '/':
Index: tests/compExpr-old.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/compExpr-old.test,v
retrieving revision 1.7
diff -u -r1.7 compExpr-old.test
--- tests/compExpr-old.test	6 Dec 2001 10:59:17 -0000	1.7
+++ tests/compExpr-old.test	12 Sep 2003 23:41:07 -0000
@@ -133,9 +133,9 @@
     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 @@
 } {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.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.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.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.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.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.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.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.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
Index: tests/expr.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/expr.test,v
retrieving revision 1.18
diff -u -r1.18 expr.test
--- tests/expr.test	27 Mar 2003 13:48:59 -0000	1.18
+++ tests/expr.test	12 Sep 2003 23:41:07 -0000
@@ -132,9 +132,9 @@
     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 @@
 } {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.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.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.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.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.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.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.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.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
@@ -805,6 +805,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]} {