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