Attachment "1724437.patch" to
ticket [1724437fff]
added by
dgp
2007-09-09 23:47:44.
Index: generic/tclCompCmds.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompCmds.c,v
retrieving revision 1.117
diff -u -r1.117 tclCompCmds.c
--- generic/tclCompCmds.c 9 Sep 2007 14:34:08 -0000 1.117
+++ generic/tclCompCmds.c 9 Sep 2007 16:45:20 -0000
@@ -4799,21 +4799,20 @@
DefineLineInformation; /* TIP #280 */
int words;
- if (parsePtr->numWords == 1) {
+ for (words=1 ; words<parsePtr->numWords ; words++) {
+ tokenPtr = TokenAfter(tokenPtr);
+ CompileWord(envPtr, tokenPtr, interp, words);
+ }
+ if (parsePtr->numWords <= 2) {
PushLiteral(envPtr, identity, -1);
- return TCL_OK;
+ words++;
}
- if (parsePtr->numWords == 2) {
+ if (words > 3) {
/*
- * TODO: Fixup the single argument case to require numeric argument.
- * Fallback on direct eval until fixed.
+ * Reverse order of arguments to get precise agreement with
+ * [expr] in calcuations, including roundoff errors.
*/
-
- return TCL_ERROR;
- }
- for (words=1 ; words<parsePtr->numWords ; words++) {
- tokenPtr = TokenAfter(tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, words);
+ TclEmitInstInt4(INST_REVERSE, words-1, envPtr);
}
while (--words > 1) {
TclEmitOpcode(instruction, envPtr);
@@ -5042,6 +5041,10 @@
Tcl_Parse *parsePtr,
CompileEnv *envPtr)
{
+ /*
+ * This one has its own implementation because the ** operator is
+ * the only one with right associativity.
+ */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
DefineLineInformation; /* TIP #280 */
int words;
@@ -5178,29 +5181,6 @@
return CompileComparisonOpCmd(interp, parsePtr, INST_STR_EQ, envPtr);
}
-/*
- * This is either clever or stupid.
- *
- * Note the rule: (a-b) = - (b-a)
- * And apply repeatedly to:
- *
- * (((a-b)-c)-d)
- * = - (d - ((a-b)-c))
- * = - (d - - (c - (a-b)))
- * = - (d - - (c - - (b - a)))
- * = - (d + (c + (b - a)))
- * = - ((d + c + b) - a)
- * = (a - (d + c + b))
- *
- * So after word compilation puts the substituted arguments on the stack in
- * reverse order, we don't have to turn them around again and apply repeated
- * INST_SUB instructions. Instead we keep them in reverse order and apply a
- * different sequence of instructions. For N arguments, we apply N-2
- * INST_ADDs, then one INST_SUB. Note that this does the right thing for N=2,
- * a single INST_SUB. When N=1, we can add a phony leading "0" argument and
- * get the right result from the same algorithm as well.
- */
-
int
TclCompileMinusOpCmd(
Tcl_Interp *interp,
@@ -5212,22 +5192,30 @@
int words;
if (parsePtr->numWords == 1) {
+ /* Fallback to direct eval to report syntax error */
return TCL_ERROR;
}
- if (parsePtr->numWords == 2) {
- PushLiteral(envPtr, "0", -1);
- }
for (words=1 ; words<parsePtr->numWords ; words++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
}
- if (parsePtr->numWords == 2) {
- words++;
+ if (words == 2) {
+ TclEmitOpcode(INST_UMINUS, envPtr);
+ return TCL_OK;
}
- while (--words > 2) {
- TclEmitOpcode(INST_ADD, envPtr);
+ if (words == 3) {
+ TclEmitOpcode(INST_SUB, envPtr);
+ return TCL_OK;
+ }
+ /*
+ * Reverse order of arguments to get precise agreement with
+ * [expr] in calcuations, including roundoff errors.
+ */
+ TclEmitInstInt4(INST_REVERSE, words-1, envPtr);
+ while (--words > 1) {
+ TclEmitInstInt4(INST_REVERSE, 2, envPtr);
+ TclEmitOpcode(INST_SUB, envPtr);
}
- TclEmitOpcode(INST_SUB, envPtr);
return TCL_OK;
}
@@ -5237,31 +5225,32 @@
Tcl_Parse *parsePtr,
CompileEnv *envPtr)
{
- Tcl_Token *tokenPtr;
+ Tcl_Token *tokenPtr = parsePtr->tokenPtr;
DefineLineInformation; /* TIP #280 */
int words;
if (parsePtr->numWords == 1) {
+ /* Fallback to direct eval to report syntax error */
return TCL_ERROR;
- } else if (parsePtr->numWords == 2) {
+ }
+ if (parsePtr->numWords == 2) {
PushLiteral(envPtr, "1.0", 3);
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 1);
- TclEmitOpcode(INST_DIV, envPtr);
- return TCL_OK;
- } else {
- /*
- * TODO: get compiled version that passes mathop-6.18. For now,
- * fallback to direct evaluation.
- */
-
- return TCL_ERROR;
}
- tokenPtr = TokenAfter(parsePtr->tokenPtr);
- CompileWord(envPtr, tokenPtr, interp, 1);
- for (words=2 ; words<parsePtr->numWords ; words++) {
+ for (words=1 ; words<parsePtr->numWords ; words++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
+ }
+ if (words <= 3) {
+ TclEmitOpcode(INST_DIV, envPtr);
+ return TCL_OK;
+ }
+ /*
+ * Reverse order of arguments to get precise agreement with
+ * [expr] in calcuations, including roundoff errors.
+ */
+ TclEmitInstInt4(INST_REVERSE, words-1, envPtr);
+ while (--words > 1) {
+ TclEmitInstInt4(INST_REVERSE, 2, envPtr);
TclEmitOpcode(INST_DIV, envPtr);
}
return TCL_OK;
Index: generic/tclCompile.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.c,v
retrieving revision 1.129
diff -u -r1.129 tclCompile.c
--- generic/tclCompile.c 30 Aug 2007 19:24:32 -0000 1.129
+++ generic/tclCompile.c 9 Sep 2007 16:45:20 -0000
@@ -383,6 +383,8 @@
* index op1. Leaves the namespace on stack. */
{"syntax", 9, -1, 2, {OPERAND_INT4, OPERAND_UINT4}},
/* Compiled bytecodes to signal syntax error. */
+ {"reverse", 5, +1, 1, {OPERAND_UINT4}},
+ /* Reverse the order of the arg elements at the top of stack */
{0}
};
Index: generic/tclCompile.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.h,v
retrieving revision 1.77
diff -u -r1.77 tclCompile.h
--- generic/tclCompile.h 28 Aug 2007 16:24:31 -0000 1.77
+++ generic/tclCompile.h 9 Sep 2007 16:45:21 -0000
@@ -630,8 +630,12 @@
#define INST_SYNTAX 125
+/* Instruction to reverse N items on top of stack */
+
+#define INST_REVERSE 126
+
/* The last opcode */
-#define LAST_INST_OPCODE 125
+#define LAST_INST_OPCODE 126
/*
* Table describing the Tcl bytecode instructions: their name (for displaying
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.330
diff -u -r1.330 tclExecute.c
--- generic/tclExecute.c 8 Sep 2007 22:36:59 -0000 1.330
+++ generic/tclExecute.c 9 Sep 2007 16:45:21 -0000
@@ -1883,6 +1883,22 @@
NEXT_INST_F(5, 0, 1);
}
+ case INST_REVERSE: {
+ int opnd;
+ Tcl_Obj **a, **b;
+
+ opnd = TclGetUInt4AtPtr(pc+1);
+ a = tosPtr-(opnd-1);
+ b = tosPtr;
+ while (a<b) {
+ Tcl_Obj *temp = *a;
+ *a = *b;
+ *b = temp;
+ a++; b--;
+ }
+ NEXT_INST_F(5, 0, 0);
+ }
+
case INST_CONCAT1: {
int opnd, length, appendLen = 0;
char *bytes, *p;
Index: tests/mathop.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/mathop.test,v
retrieving revision 1.8
diff -u -r1.8 mathop.test
--- tests/mathop.test 18 May 2007 18:39:31 -0000 1.8
+++ tests/mathop.test 9 Sep 2007 16:45:22 -0000
@@ -793,13 +793,14 @@
} [list 3 -1 2 0 12 -6 60 0 10 -2 24 0]
test mathop-20.8 { multi arg, double } {
set res {}
- foreach vals {{1.0 2} {3.0 4 5} {4 3.0 2 1}} {
+ foreach vals {{1.0 2} {3.0 4 5} {4 3.0 2 1}
+ {1.0 -1.0 1e-18} {1.0 1.0 1e-18}} {
foreach op {+ - * /} {
lappend res [TestOp $op {*}$vals]
}
}
set res
-} [list 3.0 -1.0 2.0 0.5 12.0 -6.0 60.0 0.15 10.0 -2.0 24.0 [expr {2.0/3}]]
+} [list 3.0 -1.0 2.0 0.5 12.0 -6.0 60.0 0.15 10.0 -2.0 24.0 [expr {2.0/3}] 1e-18 2.0 -1e-18 [expr {-1.0/1e-18}] 2.0 -1e-18 1e-18 [expr {1.0/1e-18}]]
test mathop-21.1 { unary ops, bitnot } {
set res {}