summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2003-09-12 23:55:32 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2003-09-12 23:55:32 (GMT)
commitda60f636030ff5e28efdfe34eb534c9dd46e2fb3 (patch)
tree2f2c7e65505a410bb72e9cc37de0a6baab73939f
parent15cd6e14858186b0fc6748418f0c92ee5c1495ab (diff)
downloadtcl-da60f636030ff5e28efdfe34eb534c9dd46e2fb3.zip
tcl-da60f636030ff5e28efdfe34eb534c9dd46e2fb3.tar.gz
tcl-da60f636030ff5e28efdfe34eb534c9dd46e2fb3.tar.bz2
TIP#123 Implementation based on work by Arjen Markus. [Patch 655176]
-rw-r--r--ChangeLog14
-rw-r--r--doc/expr.n30
-rw-r--r--generic/tclCompExpr.c4
-rw-r--r--generic/tclCompile.c4
-rw-r--r--generic/tclCompile.h4
-rw-r--r--generic/tclExecute.c211
-rw-r--r--generic/tclParseExpr.c90
-rw-r--r--tests/compExpr-old.test54
-rw-r--r--tests/expr.test108
9 files changed, 428 insertions, 91 deletions
diff --git a/ChangeLog b/ChangeLog
index b98ca9f..4c0754c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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]
diff --git a/doc/expr.n b/doc/expr.n
index 8508ee2..b7425f1 100644
--- a/doc/expr.n
+++ b/doc/expr.n
@@ -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