diff options
Diffstat (limited to 'generic/tclCompExpr.c')
-rw-r--r-- | generic/tclCompExpr.c | 79 |
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: |