summaryrefslogtreecommitdiffstats
path: root/generic/tclCompExpr.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclCompExpr.c')
-rw-r--r--generic/tclCompExpr.c79
1 files changed, 44 insertions, 35 deletions
diff --git a/generic/tclCompExpr.c b/generic/tclCompExpr.c
index d44a528..c3b4952 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.17 2003/12/24 04:18:19 davygrvy Exp $
+ * RCS: @(#) $Id: tclCompExpr.c,v 1.18 2004/01/12 03:23:31 msofer Exp $
*/
#include "tclInt.h"
@@ -595,8 +595,9 @@ CompileLandOrLorExpr(exprTokenPtr, opIndex, infoPtr, envPtr, endPtrPtr)
{
JumpFixup shortCircuitFixup; /* Used to fix up the short circuit jump
* after the first subexpression. */
- JumpFixup lhsTrueFixup, lhsEndFixup;
- /* Used to fix up jumps used to convert the
+ JumpFixup shortCircuitFixup2;/* Used to fix up the second jump to the
+ * short-circuit target. */
+ JumpFixup endFixup; /* Used to fix up jumps used to convert the
* first operand to 0 or 1. */
Tcl_Token *tokenPtr;
int dist, code;
@@ -614,32 +615,9 @@ CompileLandOrLorExpr(exprTokenPtr, opIndex, infoPtr, envPtr, endPtrPtr)
tokenPtr += (tokenPtr->numComponents + 1);
/*
- * Convert the first operand to the result that Tcl requires:
- * "0" or "1". Eventually we'll use a new instruction for this.
- */
-
- TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &lhsTrueFixup);
- TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
- TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &lhsEndFixup);
- dist = (envPtr->codeNext - envPtr->codeStart) - lhsTrueFixup.codeOffset;
- if (TclFixupForwardJump(envPtr, &lhsTrueFixup, dist, 127)) {
- badDist:
- Tcl_Panic("CompileLandOrLorExpr: bad jump distance %d\n", dist);
- }
- envPtr->currStackDepth = savedStackDepth;
- TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
- dist = (envPtr->codeNext - envPtr->codeStart) - lhsEndFixup.codeOffset;
- if (TclFixupForwardJump(envPtr, &lhsEndFixup, dist, 127)) {
- goto badDist;
- }
-
- /*
- * Emit the "short circuit" jump around the rest of the expression.
- * Duplicate the "0" or "1" on top of the stack first to keep the
- * jump from consuming it.
+ * Emit the short-circuit jump.
*/
- TclEmitOpcode(INST_DUP, envPtr);
TclEmitForwardJump(envPtr,
((opIndex==OP_LAND)? TCL_FALSE_JUMP : TCL_TRUE_JUMP),
&shortCircuitFixup);
@@ -653,23 +631,54 @@ CompileLandOrLorExpr(exprTokenPtr, opIndex, infoPtr, envPtr, endPtrPtr)
goto done;
}
tokenPtr += (tokenPtr->numComponents + 1);
-
+
/*
- * Emit a "logical and" or "logical or" instruction. This does not try
- * to "short- circuit" the evaluation of both operands, but instead
- * ensures that we either have a "1" or a "0" result.
+ * Second operand has the same boolean value as the first:
+ * emit a new jump to the short-circuit target.
*/
- TclEmitOpcode(((opIndex==OP_LAND)? INST_LAND : INST_LOR), envPtr);
+ TclEmitForwardJump(envPtr,
+ ((opIndex==OP_LAND)? TCL_FALSE_JUMP : TCL_TRUE_JUMP),
+ &shortCircuitFixup2);
/*
- * Now that we know the target of the forward jump, update it with the
- * correct distance.
+ * Push the boolean value of the second operand, jump to the end.
*/
+ if (opIndex == OP_LAND) {
+ TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
+ } else {
+ TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
+ }
+ TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &endFixup);
+
+ /*
+ * Fixup the short-circuit jumps and push the correct boolean.
+ * NOTE: fixup the jumps in the order they were made
+ */
dist = (envPtr->codeNext - envPtr->codeStart)
- shortCircuitFixup.codeOffset;
- TclFixupForwardJump(envPtr, &shortCircuitFixup, dist, 127);
+ if (TclFixupForwardJump(envPtr, &shortCircuitFixup, dist, 127)) {
+ /*
+ * The short-circuit jump was grown by 3 bytes: update the
+ * fixups for the other two jumps.
+ */
+
+ shortCircuitFixup2.codeOffset += 3;
+ endFixup.codeOffset += 3;
+ }
+ dist = (envPtr->codeNext - envPtr->codeStart)
+ - shortCircuitFixup2.codeOffset;
+ TclFixupForwardJump(envPtr, &shortCircuitFixup2, dist, 127);
+
+ if (opIndex == OP_LAND) {
+ TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
+ } else {
+ TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
+ }
+
+ dist = (envPtr->codeNext - envPtr->codeStart) - endFixup.codeOffset;
+ TclFixupForwardJump(envPtr, &endFixup, dist, 127);
*endPtrPtr = tokenPtr;
done: