Tcl Source Code

Artifact [069f40802e]
Login

Artifact 069f40802e1ccd5e7e5fbde6bdf5bd10e8234ee7:

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 {}