Diff
Not logged in

Differences From Artifact [ea61e99336]:

To Artifact [27c7245b5b]:


1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19











-
+







/* 
 * tclCompExpr.c --
 *
 *	This file contains the code to compile Tcl expressions.
 *
 * Copyright (c) 1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 *
 * 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.2.2 2003/10/16 02:28:01 dgp Exp $
 * RCS: @(#) $Id: tclCompExpr.c,v 1.14.2.3 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * The stuff below is a bit of a hack so that this file can be used in
347
348
349
350
351
352
353
354

355
356
357
358
359
360
361
347
348
349
350
351
352
353

354
355
356
357
358
359
360
361







-
+







    Tcl_HashEntry *hPtr;
    CONST char *operator;
    Tcl_DString opBuf;
    int objIndex, opIndex, length, code;
    char buffer[TCL_UTF_MAX];

    if (exprTokenPtr->type != TCL_TOKEN_SUB_EXPR) {
	panic("CompileSubExpr: token type %d not TCL_TOKEN_SUB_EXPR\n",
	Tcl_Panic("CompileSubExpr: token type %d not TCL_TOKEN_SUB_EXPR\n",
	        exprTokenPtr->type);
    }
    code = TCL_OK;

    /*
     * Switch on the type of the first token after the subexpression token.
     * After processing it, advance tokenPtr to point just after the
545
546
547
548
549
550
551
552

553
554
555
556
557
558
559

560
561
562
563
564
565
566
545
546
547
548
549
550
551

552
553
554
555
556
557
558

559
560
561
562
563
564
565
566







-
+






-
+







		    if (code != TCL_OK) {
			goto done;
		    }
		    tokenPtr = endPtr;
		    break;
		    
		default:
		    panic("CompileSubExpr: unexpected operator %d requiring special treatment\n",
		    Tcl_Panic("CompileSubExpr: unexpected operator %d requiring special treatment\n",
		        opIndex);
	    } /* end switch on operator requiring special treatment */
	    infoPtr->hasOperators = 1;
	    break;

        default:
	    panic("CompileSubExpr: unexpected token type %d\n",
	    Tcl_Panic("CompileSubExpr: unexpected token type %d\n",
	            tokenPtr->type);
    }

    /*
     * Verify that the subexpression token had the required number of
     * subtokens: that we've advanced tokenPtr just beyond the
     * subexpression's last token. For example, a "*" subexpression must
608
609
610
611
612
613
614
615
616



617
618
619

620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637

638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673

674
675
676
677



678
679

680


681







682



683

684
685
686
687
688
689
















690
691
692
693
694
695
696
608
609
610
611
612
613
614


615
616
617

618

619
620
621
622
623
624
625
626
627
628
629
630
631
632
633




634



















635
636

637
638
639
640
641
642
643
644
645
646
647
648
649

650
651



652
653
654
655
656
657

658
659
660
661
662
663
664
665
666
667
668
669
670
671

672






673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695







-
-
+
+
+
-

-
+














-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-


-













-
+

-
-
-
+
+
+


+
-
+
+

+
+
+
+
+
+
+

+
+
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    CompileEnv *envPtr;		 /* Holds resulting instructions. */
    Tcl_Token **endPtrPtr;	 /* If successful, a pointer to the token
				  * just after the last token in the
				  * subexpression is stored here. */
{
    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 jump to the end. */
				  * first operand to 0 or 1. */
    Tcl_Token *tokenPtr;
    int dist, code;
    int code;
    int savedStackDepth = envPtr->currStackDepth;

    /*
     * Emit code for the first operand.
     */

    tokenPtr = exprTokenPtr+2;
    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
    if (code != TCL_OK) {
	goto done;
    }
    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.
     */
    
     * Emit the short-circuit jump.
    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:
	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.
     */

    TclEmitOpcode(INST_DUP, envPtr);
    TclEmitForwardJump(envPtr,
	    ((opIndex==OP_LAND)? TCL_FALSE_JUMP : TCL_TRUE_JUMP),
	    &shortCircuitFixup);

    /*
     * Emit code for the second operand.
     */

    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
    if (code != TCL_OK) {
	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.
     * The result is the boolean value of the second operand. We 
     * code this in a somewhat contorted manner to be able to reuse
     * the shortCircuit value and save one INST_JUMP.
     */

    TclEmitForwardJump(envPtr,
    TclEmitOpcode(((opIndex==OP_LAND)? INST_LAND : INST_LOR), envPtr);
	    ((opIndex==OP_LAND)? TCL_FALSE_JUMP : TCL_TRUE_JUMP),
	    &shortCircuitFixup2);

    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 shortCircuit value.
     * Note that shortCircuitFixup2 is always a short jump.
     */
     * Now that we know the target of the forward jump, update it with the

     * correct distance.
     */

    dist = (envPtr->codeNext - envPtr->codeStart)
	    - shortCircuitFixup.codeOffset;
    TclFixupForwardJump(envPtr, &shortCircuitFixup, dist, 127);
    TclFixupForwardJumpToHere(envPtr, &shortCircuitFixup2, 127);
    if (TclFixupForwardJumpToHere(envPtr, &shortCircuitFixup, 127)) {
	/*
	 * shortCircuit jump grown by 3 bytes: update endFixup.
	 */
	    
	 endFixup.codeOffset += 3;
    }

    if (opIndex == OP_LAND) {
	TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
    } else {
	TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
    }

    TclFixupForwardJumpToHere(envPtr, &endFixup, 127);
    *endPtrPtr = tokenPtr;

    done:
    envPtr->currStackDepth = savedStackDepth + 1;
    return code;
}