tclExecute.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:182k
源码类别:

通讯编程

开发平台:

Visual C++

  1.     /*
  2.      * Shifts are never usefully 64-bits wide!
  3.      */
  4.     FORCE_LONG(value2Ptr, i2, w2);
  5.     if (valuePtr->typePtr == &tclWideIntType) {
  6. #ifdef TCL_COMPILE_DEBUG
  7. w2 = Tcl_LongAsWide(i2);
  8. #endif /* TCL_COMPILE_DEBUG */
  9. if (w < 0) {
  10.     wResult = ~w;
  11. } else {
  12.     wResult = w;
  13. }
  14. /*
  15.  * Shift in steps when the shift gets large to prevent
  16.  * annoying compiler/processor bugs. [Bug 868467]
  17.  */
  18. if (i2 >= 64) {
  19.     wResult = Tcl_LongAsWide(0);
  20. } else if (i2 > 60) {
  21.     wResult >>= 30;
  22.     wResult >>= 30;
  23.     wResult >>= i2-60;
  24. } else if (i2 > 30) {
  25.     wResult >>= 30;
  26.     wResult >>= i2-30;
  27. } else {
  28.     wResult >>= i2;
  29. }
  30. if (w < 0) {
  31.     wResult = ~wResult;
  32. }
  33. doWide = 1;
  34. break;
  35.     }
  36.     if (i < 0) {
  37. iResult = ~i;
  38.     } else {
  39. iResult = i;
  40.     }
  41.     /*
  42.      * Shift in steps when the shift gets large to prevent
  43.      * annoying compiler/processor bugs. [Bug 868467]
  44.      */
  45.     if (i2 >= 64) {
  46. iResult = 0;
  47.     } else if (i2 > 60) {
  48. iResult >>= 30;
  49. iResult >>= 30;
  50. iResult >>= i2-60;
  51.     } else if (i2 > 30) {
  52. iResult >>= 30;
  53. iResult >>= i2-30;
  54.     } else {
  55. iResult >>= i2;
  56.     }
  57.     if (i < 0) {
  58. iResult = ~iResult;
  59.     }
  60.     break;
  61. case INST_BITOR:
  62.     if (valuePtr->typePtr == &tclWideIntType
  63. || value2Ptr->typePtr == &tclWideIntType) {
  64. /*
  65.  * Promote to wide
  66.  */
  67. if (valuePtr->typePtr == &tclIntType) {
  68.     w = Tcl_LongAsWide(i);
  69. } else if (value2Ptr->typePtr == &tclIntType) {
  70.     w2 = Tcl_LongAsWide(i2);
  71. }
  72. wResult = w | w2;
  73. doWide = 1;
  74. break;
  75.     }
  76.     iResult = i | i2;
  77.     break;
  78. case INST_BITXOR:
  79.     if (valuePtr->typePtr == &tclWideIntType
  80. || value2Ptr->typePtr == &tclWideIntType) {
  81. /*
  82.  * Promote to wide
  83.  */
  84. if (valuePtr->typePtr == &tclIntType) {
  85.     w = Tcl_LongAsWide(i);
  86. } else if (value2Ptr->typePtr == &tclIntType) {
  87.     w2 = Tcl_LongAsWide(i2);
  88. }
  89. wResult = w ^ w2;
  90. doWide = 1;
  91. break;
  92.     }
  93.     iResult = i ^ i2;
  94.     break;
  95. case INST_BITAND:
  96.     if (valuePtr->typePtr == &tclWideIntType
  97. || value2Ptr->typePtr == &tclWideIntType) {
  98. /*
  99.  * Promote to wide
  100.  */
  101. if (valuePtr->typePtr == &tclIntType) {
  102.     w = Tcl_LongAsWide(i);
  103. } else if (value2Ptr->typePtr == &tclIntType) {
  104.     w2 = Tcl_LongAsWide(i2);
  105. }
  106. wResult = w & w2;
  107. doWide = 1;
  108. break;
  109.     }
  110.     iResult = i & i2;
  111.     break;
  112. }
  113. /*
  114.  * Reuse the valuePtr object already on stack if possible.
  115.  */
  116. if (Tcl_IsShared(valuePtr)) {
  117.     if (doWide) {
  118. objResultPtr = Tcl_NewWideIntObj(wResult);
  119. TRACE((LLD" "LLD" => "LLD"n", w, w2, wResult));
  120.     } else {
  121. objResultPtr = Tcl_NewLongObj(iResult);
  122. TRACE(("%ld %ld => %ldn", i, i2, iResult));
  123.     }
  124.     NEXT_INST_F(1, 2, 1);
  125. } else { /* reuse the valuePtr object */
  126.     if (doWide) {
  127. TRACE((LLD" "LLD" => "LLD"n", w, w2, wResult));
  128. Tcl_SetWideIntObj(valuePtr, wResult);
  129.     } else {
  130. TRACE(("%ld %ld => %ldn", i, i2, iResult));
  131. Tcl_SetLongObj(valuePtr, iResult);
  132.     }
  133.     NEXT_INST_F(1, 1, 0);
  134. }
  135.     }
  136.     case INST_ADD:
  137.     case INST_SUB:
  138.     case INST_MULT:
  139.     case INST_DIV:
  140.     {
  141. /*
  142.  * Operands must be numeric and ints get converted to floats
  143.  * if necessary. We compute value op value2.
  144.  */
  145. Tcl_ObjType *t1Ptr, *t2Ptr;
  146. long i2 = 0, quot, rem; /* Init. avoids compiler warning. */
  147. double d1, d2;
  148. long iResult = 0; /* Init. avoids compiler warning. */
  149. double dResult = 0.0; /* Init. avoids compiler warning. */
  150. int doDouble = 0; /* 1 if doing floating arithmetic */
  151. Tcl_WideInt w2, wquot, wrem;
  152. Tcl_WideInt wResult = W0; /* Init. avoids compiler warning. */
  153. int doWide = 0; /* 1 if doing wide arithmetic. */
  154. value2Ptr = stackPtr[stackTop];
  155. valuePtr  = stackPtr[stackTop - 1];
  156. t1Ptr = valuePtr->typePtr;
  157. t2Ptr = value2Ptr->typePtr;
  158. if (t1Ptr == &tclIntType) {
  159.     i = valuePtr->internalRep.longValue;
  160. } else if (t1Ptr == &tclWideIntType) {
  161.     TclGetWide(w,valuePtr);
  162. } else if ((t1Ptr == &tclDoubleType)
  163.    && (valuePtr->bytes == NULL)) {
  164.     /*
  165.      * We can only use the internal rep directly if there is
  166.      * no string rep.  Otherwise the string rep might actually
  167.      * look like an integer, which is preferred.
  168.      */
  169.     d1 = valuePtr->internalRep.doubleValue;
  170. } else {
  171.     char *s = Tcl_GetStringFromObj(valuePtr, &length);
  172.     if (TclLooksLikeInt(s, length)) {
  173. GET_WIDE_OR_INT(result, valuePtr, i, w);
  174.     } else {
  175. result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  176.       valuePtr, &d1);
  177.     }
  178.     if (result != TCL_OK) {
  179. TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %sn",
  180.         s, O2S(valuePtr),
  181.         (valuePtr->typePtr?
  182.     valuePtr->typePtr->name : "null")));
  183. DECACHE_STACK_INFO();
  184. IllegalExprOperandType(interp, pc, valuePtr);
  185. CACHE_STACK_INFO();
  186. goto checkForCatch;
  187.     }
  188.     t1Ptr = valuePtr->typePtr;
  189. }
  190. if (t2Ptr == &tclIntType) {
  191.     i2 = value2Ptr->internalRep.longValue;
  192. } else if (t2Ptr == &tclWideIntType) {
  193.     TclGetWide(w2,value2Ptr);
  194. } else if ((t2Ptr == &tclDoubleType)
  195.    && (value2Ptr->bytes == NULL)) {
  196.     /*
  197.      * We can only use the internal rep directly if there is
  198.      * no string rep.  Otherwise the string rep might actually
  199.      * look like an integer, which is preferred.
  200.      */
  201.     d2 = value2Ptr->internalRep.doubleValue;
  202. } else {
  203.     char *s = Tcl_GetStringFromObj(value2Ptr, &length);
  204.     if (TclLooksLikeInt(s, length)) {
  205. GET_WIDE_OR_INT(result, value2Ptr, i2, w2);
  206.     } else {
  207. result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  208.         value2Ptr, &d2);
  209.     }
  210.     if (result != TCL_OK) {
  211. TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %sn",
  212.         O2S(value2Ptr), s,
  213.         (value2Ptr->typePtr?
  214.     value2Ptr->typePtr->name : "null")));
  215. DECACHE_STACK_INFO();
  216. IllegalExprOperandType(interp, pc, value2Ptr);
  217. CACHE_STACK_INFO();
  218. goto checkForCatch;
  219.     }
  220.     t2Ptr = value2Ptr->typePtr;
  221. }
  222. if ((t1Ptr == &tclDoubleType) || (t2Ptr == &tclDoubleType)) {
  223.     /*
  224.      * Do double arithmetic.
  225.      */
  226.     doDouble = 1;
  227.     if (t1Ptr == &tclIntType) {
  228. d1 = i;       /* promote value 1 to double */
  229.     } else if (t2Ptr == &tclIntType) {
  230. d2 = i2;      /* promote value 2 to double */
  231.     } else if (t1Ptr == &tclWideIntType) {
  232. d1 = Tcl_WideAsDouble(w);
  233.     } else if (t2Ptr == &tclWideIntType) {
  234. d2 = Tcl_WideAsDouble(w2);
  235.     }
  236.     switch (*pc) {
  237.         case INST_ADD:
  238.     dResult = d1 + d2;
  239.     break;
  240.         case INST_SUB:
  241.     dResult = d1 - d2;
  242.     break;
  243.         case INST_MULT:
  244.     dResult = d1 * d2;
  245.     break;
  246.         case INST_DIV:
  247.     if (d2 == 0.0) {
  248. TRACE(("%.6g %.6g => DIVIDE BY ZEROn", d1, d2));
  249. goto divideByZero;
  250.     }
  251.     dResult = d1 / d2;
  252.     break;
  253.     }
  254.     
  255.     /*
  256.      * Check now for IEEE floating-point error.
  257.      */
  258.     
  259.     if (IS_NAN(dResult) || IS_INF(dResult)) {
  260. TRACE(("%.20s %.20s => IEEE FLOATING PT ERRORn",
  261.         O2S(valuePtr), O2S(value2Ptr)));
  262. DECACHE_STACK_INFO();
  263. TclExprFloatError(interp, dResult);
  264. CACHE_STACK_INFO();
  265. result = TCL_ERROR;
  266. goto checkForCatch;
  267.     }
  268. } else if ((t1Ptr == &tclWideIntType) 
  269.    || (t2Ptr == &tclWideIntType)) {
  270.     /*
  271.      * Do wide integer arithmetic.
  272.      */
  273.     doWide = 1;
  274.     if (t1Ptr == &tclIntType) {
  275. w = Tcl_LongAsWide(i);
  276.     } else if (t2Ptr == &tclIntType) {
  277. w2 = Tcl_LongAsWide(i2);
  278.     }
  279.     switch (*pc) {
  280.         case INST_ADD:
  281.     wResult = w + w2;
  282.     break;
  283.         case INST_SUB:
  284.     wResult = w - w2;
  285.     break;
  286.         case INST_MULT:
  287.     wResult = w * w2;
  288.     break;
  289.         case INST_DIV:
  290.     /*
  291.      * This code is tricky: C doesn't guarantee much
  292.      * about the quotient or remainder, but Tcl does.
  293.      * The remainder always has the same sign as the
  294.      * divisor and a smaller absolute value.
  295.      */
  296.     if (w2 == W0) {
  297. TRACE((LLD" "LLD" => DIVIDE BY ZEROn", w, w2));
  298. goto divideByZero;
  299.     }
  300.     if (w2 < 0) {
  301. w2 = -w2;
  302. w = -w;
  303.     }
  304.     wquot = w / w2;
  305.     wrem  = w % w2;
  306.     if (wrem < W0) {
  307. wquot -= 1;
  308.     }
  309.     wResult = wquot;
  310.     break;
  311.     }
  312. } else {
  313.     /*
  314.      * Do integer arithmetic.
  315.      */
  316.     switch (*pc) {
  317.         case INST_ADD:
  318.     iResult = i + i2;
  319.     break;
  320.         case INST_SUB:
  321.     iResult = i - i2;
  322.     break;
  323.         case INST_MULT:
  324.     iResult = i * i2;
  325.     break;
  326.         case INST_DIV:
  327.     /*
  328.      * This code is tricky: C doesn't guarantee much
  329.      * about the quotient or remainder, but Tcl does.
  330.      * The remainder always has the same sign as the
  331.      * divisor and a smaller absolute value.
  332.      */
  333.     if (i2 == 0) {
  334. TRACE(("%ld %ld => DIVIDE BY ZEROn", i, i2));
  335. goto divideByZero;
  336.     }
  337.     if (i2 < 0) {
  338. i2 = -i2;
  339. i = -i;
  340.     }
  341.     quot = i / i2;
  342.     rem  = i % i2;
  343.     if (rem < 0) {
  344. quot -= 1;
  345.     }
  346.     iResult = quot;
  347.     break;
  348.     }
  349. }
  350. /*
  351.  * Reuse the valuePtr object already on stack if possible.
  352.  */
  353. if (Tcl_IsShared(valuePtr)) {
  354.     if (doDouble) {
  355. objResultPtr = Tcl_NewDoubleObj(dResult);
  356. TRACE(("%.6g %.6g => %.6gn", d1, d2, dResult));
  357.     } else if (doWide) {
  358. objResultPtr = Tcl_NewWideIntObj(wResult);
  359. TRACE((LLD" "LLD" => "LLD"n", w, w2, wResult));
  360.     } else {
  361. objResultPtr = Tcl_NewLongObj(iResult);
  362. TRACE(("%ld %ld => %ldn", i, i2, iResult));
  363.     } 
  364.     NEXT_INST_F(1, 2, 1);
  365. } else {     /* reuse the valuePtr object */
  366.     if (doDouble) { /* NB: stack top is off by 1 */
  367. TRACE(("%.6g %.6g => %.6gn", d1, d2, dResult));
  368. Tcl_SetDoubleObj(valuePtr, dResult);
  369.     } else if (doWide) {
  370. TRACE((LLD" "LLD" => "LLD"n", w, w2, wResult));
  371. Tcl_SetWideIntObj(valuePtr, wResult);
  372.     } else {
  373. TRACE(("%ld %ld => %ldn", i, i2, iResult));
  374. Tcl_SetLongObj(valuePtr, iResult);
  375.     }
  376.     NEXT_INST_F(1, 1, 0);
  377. }
  378.     }
  379.     case INST_UPLUS:
  380.     {
  381. /*
  382.  * Operand must be numeric.
  383.  */
  384. double d;
  385. Tcl_ObjType *tPtr;
  386. valuePtr = stackPtr[stackTop];
  387. tPtr = valuePtr->typePtr;
  388. if (!IS_INTEGER_TYPE(tPtr) && ((tPtr != &tclDoubleType) 
  389.                 || (valuePtr->bytes != NULL))) {
  390.     char *s = Tcl_GetStringFromObj(valuePtr, &length);
  391.     if (TclLooksLikeInt(s, length)) {
  392. GET_WIDE_OR_INT(result, valuePtr, i, w);
  393.     } else {
  394. result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d);
  395.     }
  396.     if (result != TCL_OK) { 
  397. TRACE((""%.20s" => ILLEGAL TYPE %s n",
  398.         s, (tPtr? tPtr->name : "null")));
  399. DECACHE_STACK_INFO();
  400. IllegalExprOperandType(interp, pc, valuePtr);
  401. CACHE_STACK_INFO();
  402. goto checkForCatch;
  403.     }
  404.     tPtr = valuePtr->typePtr;
  405. }
  406. /*
  407.  * Ensure that the operand's string rep is the same as the
  408.  * formatted version of its internal rep. This makes sure
  409.  * that "expr +000123" yields "83", not "000123". We
  410.  * implement this by _discarding_ the string rep since we
  411.  * know it will be regenerated, if needed later, by
  412.  * formatting the internal rep's value.
  413.  */
  414. if (Tcl_IsShared(valuePtr)) {
  415.     if (tPtr == &tclIntType) {
  416. i = valuePtr->internalRep.longValue;
  417. objResultPtr = Tcl_NewLongObj(i);
  418.     } else if (tPtr == &tclWideIntType) {
  419. TclGetWide(w,valuePtr);
  420. objResultPtr = Tcl_NewWideIntObj(w);
  421.     } else {
  422. d = valuePtr->internalRep.doubleValue;
  423. objResultPtr = Tcl_NewDoubleObj(d);
  424.     }
  425.     TRACE_WITH_OBJ(("%s => ", O2S(objResultPtr)), objResultPtr);
  426.     NEXT_INST_F(1, 1, 1);
  427. } else {
  428.     Tcl_InvalidateStringRep(valuePtr);
  429.     TRACE_WITH_OBJ(("%s => ", O2S(valuePtr)), valuePtr);
  430.     NEXT_INST_F(1, 0, 0);
  431. }
  432.     }
  433.     
  434.     case INST_UMINUS:
  435.     case INST_LNOT:
  436.     {
  437. /*
  438.  * The operand must be numeric or a boolean string as
  439.  * accepted by Tcl_GetBooleanFromObj(). If the operand
  440.  * object is unshared modify it directly, otherwise
  441.  * create a copy to modify: this is "copy on write".
  442.  * Free any old string representation since it is now
  443.  * invalid.
  444.  */
  445. double d;
  446. int boolvar;
  447. Tcl_ObjType *tPtr;
  448. valuePtr = stackPtr[stackTop];
  449. tPtr = valuePtr->typePtr;
  450. if (!IS_INTEGER_TYPE(tPtr) && ((tPtr != &tclDoubleType)
  451.         || (valuePtr->bytes != NULL))) {
  452.     if ((tPtr == &tclBooleanType) && (valuePtr->bytes == NULL)) {
  453. valuePtr->typePtr = &tclIntType;
  454.     } else {
  455. char *s = Tcl_GetStringFromObj(valuePtr, &length);
  456. if (TclLooksLikeInt(s, length)) {
  457.     GET_WIDE_OR_INT(result, valuePtr, i, w);
  458. } else {
  459.     result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  460.             valuePtr, &d);
  461. }
  462. if (result == TCL_ERROR && *pc == INST_LNOT) {
  463.     result = Tcl_GetBooleanFromObj((Tcl_Interp *)NULL,
  464.             valuePtr, &boolvar);
  465.     i = (long)boolvar; /* i is long, not int! */
  466. }
  467. if (result != TCL_OK) {
  468.     TRACE((""%.20s" => ILLEGAL TYPE %sn",
  469.             s, (tPtr? tPtr->name : "null")));
  470.     DECACHE_STACK_INFO();
  471.     IllegalExprOperandType(interp, pc, valuePtr);
  472.     CACHE_STACK_INFO();
  473.     goto checkForCatch;
  474. }
  475.     }
  476.     tPtr = valuePtr->typePtr;
  477. }
  478. if (Tcl_IsShared(valuePtr)) {
  479.     /*
  480.      * Create a new object.
  481.      */
  482.     if ((tPtr == &tclIntType) || (tPtr == &tclBooleanType)) {
  483. i = valuePtr->internalRep.longValue;
  484. objResultPtr = Tcl_NewLongObj(
  485.     (*pc == INST_UMINUS)? -i : !i);
  486. TRACE_WITH_OBJ(("%ld => ", i), objResultPtr);
  487.     } else if (tPtr == &tclWideIntType) {
  488. TclGetWide(w,valuePtr);
  489. if (*pc == INST_UMINUS) {
  490.     objResultPtr = Tcl_NewWideIntObj(-w);
  491. } else {
  492.     objResultPtr = Tcl_NewLongObj(w == W0);
  493. }
  494. TRACE_WITH_OBJ((LLD" => ", w), objResultPtr);
  495.     } else {
  496. d = valuePtr->internalRep.doubleValue;
  497. if (*pc == INST_UMINUS) {
  498.     objResultPtr = Tcl_NewDoubleObj(-d);
  499. } else {
  500.     /*
  501.      * Should be able to use "!d", but apparently
  502.      * some compilers can't handle it.
  503.      */
  504.     objResultPtr = Tcl_NewLongObj((d==0.0)? 1 : 0);
  505. }
  506. TRACE_WITH_OBJ(("%.6g => ", d), objResultPtr);
  507.     }
  508.     NEXT_INST_F(1, 1, 1);
  509. } else {
  510.     /*
  511.      * valuePtr is unshared. Modify it directly.
  512.      */
  513.     if ((tPtr == &tclIntType) || (tPtr == &tclBooleanType)) {
  514. i = valuePtr->internalRep.longValue;
  515. Tcl_SetLongObj(valuePtr,
  516.                 (*pc == INST_UMINUS)? -i : !i);
  517. TRACE_WITH_OBJ(("%ld => ", i), valuePtr);
  518.     } else if (tPtr == &tclWideIntType) {
  519. TclGetWide(w,valuePtr);
  520. if (*pc == INST_UMINUS) {
  521.     Tcl_SetWideIntObj(valuePtr, -w);
  522. } else {
  523.     Tcl_SetLongObj(valuePtr, w == W0);
  524. }
  525. TRACE_WITH_OBJ((LLD" => ", w), valuePtr);
  526.     } else {
  527. d = valuePtr->internalRep.doubleValue;
  528. if (*pc == INST_UMINUS) {
  529.     Tcl_SetDoubleObj(valuePtr, -d);
  530. } else {
  531.     /*
  532.      * Should be able to use "!d", but apparently
  533.      * some compilers can't handle it.
  534.      */
  535.     Tcl_SetLongObj(valuePtr, (d==0.0)? 1 : 0);
  536. }
  537. TRACE_WITH_OBJ(("%.6g => ", d), valuePtr);
  538.     }
  539.     NEXT_INST_F(1, 0, 0);
  540. }
  541.     }
  542.     case INST_BITNOT:
  543.     {
  544. /*
  545.  * The operand must be an integer. If the operand object is
  546.  * unshared modify it directly, otherwise modify a copy. 
  547.  * Free any old string representation since it is now
  548.  * invalid.
  549.  */
  550. Tcl_ObjType *tPtr;
  551. valuePtr = stackPtr[stackTop];
  552. tPtr = valuePtr->typePtr;
  553. if (!IS_INTEGER_TYPE(tPtr)) {
  554.     REQUIRE_WIDE_OR_INT(result, valuePtr, i, w);
  555.     if (result != TCL_OK) {   /* try to convert to double */
  556. TRACE((""%.20s" => ILLEGAL TYPE %sn",
  557.         O2S(valuePtr), (tPtr? tPtr->name : "null")));
  558. DECACHE_STACK_INFO();
  559. IllegalExprOperandType(interp, pc, valuePtr);
  560. CACHE_STACK_INFO();
  561. goto checkForCatch;
  562.     }
  563. }
  564. if (valuePtr->typePtr == &tclWideIntType) {
  565.     TclGetWide(w,valuePtr);
  566.     if (Tcl_IsShared(valuePtr)) {
  567. objResultPtr = Tcl_NewWideIntObj(~w);
  568. TRACE(("0x%llx => (%llu)n", w, ~w));
  569. NEXT_INST_F(1, 1, 1);
  570.     } else {
  571. /*
  572.  * valuePtr is unshared. Modify it directly.
  573.  */
  574. Tcl_SetWideIntObj(valuePtr, ~w);
  575. TRACE(("0x%llx => (%llu)n", w, ~w));
  576. NEXT_INST_F(1, 0, 0);
  577.     }
  578. } else {
  579.     i = valuePtr->internalRep.longValue;
  580.     if (Tcl_IsShared(valuePtr)) {
  581. objResultPtr = Tcl_NewLongObj(~i);
  582. TRACE(("0x%lx => (%lu)n", i, ~i));
  583. NEXT_INST_F(1, 1, 1);
  584.     } else {
  585. /*
  586.  * valuePtr is unshared. Modify it directly.
  587.  */
  588. Tcl_SetLongObj(valuePtr, ~i);
  589. TRACE(("0x%lx => (%lu)n", i, ~i));
  590. NEXT_INST_F(1, 0, 0);
  591.     }
  592. }
  593.     }
  594.     case INST_CALL_BUILTIN_FUNC1:
  595. opnd = TclGetUInt1AtPtr(pc+1);
  596. {
  597.     /*
  598.      * Call one of the built-in Tcl math functions.
  599.      */
  600.     BuiltinFunc *mathFuncPtr;
  601.     if ((opnd < 0) || (opnd > LAST_BUILTIN_FUNC)) {
  602. TRACE(("UNRECOGNIZED BUILTIN FUNC CODE %dn", opnd));
  603. panic("TclExecuteByteCode: unrecognized builtin function code %d", opnd);
  604.     }
  605.     mathFuncPtr = &(tclBuiltinFuncTable[opnd]);
  606.     DECACHE_STACK_INFO();
  607.     result = (*mathFuncPtr->proc)(interp, eePtr,
  608.             mathFuncPtr->clientData);
  609.     CACHE_STACK_INFO();
  610.     if (result != TCL_OK) {
  611. goto checkForCatch;
  612.     }
  613.     TRACE_WITH_OBJ(("%d => ", opnd), stackPtr[stackTop]);
  614. }
  615. NEXT_INST_F(2, 0, 0);
  616.     
  617.     case INST_CALL_FUNC1:
  618. opnd = TclGetUInt1AtPtr(pc+1);
  619. {
  620.     /*
  621.      * Call a non-builtin Tcl math function previously
  622.      * registered by a call to Tcl_CreateMathFunc.
  623.      */
  624.     int objc = opnd;   /* Number of arguments. The function name
  625. * is the 0-th argument. */
  626.     Tcl_Obj **objv;    /* The array of arguments. The function
  627. * name is objv[0]. */
  628.     objv = &(stackPtr[stackTop - (objc-1)]); /* "objv[0]" */
  629.     DECACHE_STACK_INFO();
  630.     result = ExprCallMathFunc(interp, eePtr, objc, objv);
  631.     CACHE_STACK_INFO();
  632.     if (result != TCL_OK) {
  633. goto checkForCatch;
  634.     }
  635.     TRACE_WITH_OBJ(("%d => ", objc), stackPtr[stackTop]);
  636. }
  637. NEXT_INST_F(2, 0, 0);
  638.     case INST_TRY_CVT_TO_NUMERIC:
  639.     {
  640. /*
  641.  * Try to convert the topmost stack object to an int or
  642.  * double object. This is done in order to support Tcl's
  643.  * policy of interpreting operands if at all possible as
  644.  * first integers, else floating-point numbers.
  645.  */
  646. double d;
  647. char *s;
  648. Tcl_ObjType *tPtr;
  649. int converted, needNew;
  650. valuePtr = stackPtr[stackTop];
  651. tPtr = valuePtr->typePtr;
  652. converted = 0;
  653. if (!IS_INTEGER_TYPE(tPtr) && ((tPtr != &tclDoubleType)
  654.         || (valuePtr->bytes != NULL))) {
  655.     if ((tPtr == &tclBooleanType) && (valuePtr->bytes == NULL)) {
  656. valuePtr->typePtr = &tclIntType;
  657. converted = 1;
  658.     } else {
  659. s = Tcl_GetStringFromObj(valuePtr, &length);
  660. if (TclLooksLikeInt(s, length)) {
  661.     GET_WIDE_OR_INT(result, valuePtr, i, w);
  662. } else {
  663.     result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  664.             valuePtr, &d);
  665. }
  666. if (result == TCL_OK) {
  667.     converted = 1;
  668. }
  669. result = TCL_OK; /* reset the result variable */
  670.     }
  671.     tPtr = valuePtr->typePtr;
  672. }
  673. /*
  674.  * Ensure that the topmost stack object, if numeric, has a
  675.  * string rep the same as the formatted version of its
  676.  * internal rep. This is used, e.g., to make sure that "expr
  677.  * {0001}" yields "1", not "0001". We implement this by
  678.  * _discarding_ the string rep since we know it will be
  679.  * regenerated, if needed later, by formatting the internal
  680.  * rep's value. Also check if there has been an IEEE
  681.  * floating point error.
  682.  */
  683. objResultPtr = valuePtr;
  684. needNew = 0;
  685. if (IS_NUMERIC_TYPE(tPtr)) {
  686.     if (Tcl_IsShared(valuePtr)) {
  687. if (valuePtr->bytes != NULL) {
  688.     /*
  689.      * We only need to make a copy of the object
  690.      * when it already had a string rep
  691.      */
  692.     needNew = 1;
  693.     if (tPtr == &tclIntType) {
  694. i = valuePtr->internalRep.longValue;
  695. objResultPtr = Tcl_NewLongObj(i);
  696.     } else if (tPtr == &tclWideIntType) {
  697. TclGetWide(w,valuePtr);
  698. objResultPtr = Tcl_NewWideIntObj(w);
  699.     } else {
  700. d = valuePtr->internalRep.doubleValue;
  701. objResultPtr = Tcl_NewDoubleObj(d);
  702.     }
  703.     tPtr = objResultPtr->typePtr;
  704. }
  705.     } else {
  706. Tcl_InvalidateStringRep(valuePtr);
  707.     }
  708.     if (tPtr == &tclDoubleType) {
  709. d = objResultPtr->internalRep.doubleValue;
  710. if (IS_NAN(d) || IS_INF(d)) {
  711.     TRACE((""%.20s" => IEEE FLOATING PT ERRORn",
  712.             O2S(objResultPtr)));
  713.     DECACHE_STACK_INFO();
  714.     TclExprFloatError(interp, d);
  715.     CACHE_STACK_INFO();
  716.     result = TCL_ERROR;
  717.     goto checkForCatch;
  718. }
  719.     }
  720.     converted = converted;  /* lint, converted not used. */
  721.     TRACE((""%.20s" => numeric, %s, %sn", O2S(valuePtr),
  722.             (converted? "converted" : "not converted"),
  723.     (needNew? "new Tcl_Obj" : "same Tcl_Obj")));
  724. } else {
  725.     TRACE((""%.20s" => not numericn", O2S(valuePtr)));
  726. }
  727. if (needNew) {
  728.     NEXT_INST_F(1, 1, 1);
  729. } else {
  730.     NEXT_INST_F(1, 0, 0);
  731. }
  732.     }
  733.     case INST_BREAK:
  734. DECACHE_STACK_INFO();
  735. Tcl_ResetResult(interp);
  736. CACHE_STACK_INFO();
  737. result = TCL_BREAK;
  738. cleanup = 0;
  739. goto processExceptionReturn;
  740.     case INST_CONTINUE:
  741. DECACHE_STACK_INFO();
  742. Tcl_ResetResult(interp);
  743. CACHE_STACK_INFO();
  744. result = TCL_CONTINUE;
  745. cleanup = 0;
  746. goto processExceptionReturn;
  747.     case INST_FOREACH_START4:
  748. opnd = TclGetUInt4AtPtr(pc+1);
  749. {
  750.     /*
  751.      * Initialize the temporary local var that holds the count
  752.      * of the number of iterations of the loop body to -1.
  753.      */
  754.     ForeachInfo *infoPtr = (ForeachInfo *)
  755.             codePtr->auxDataArrayPtr[opnd].clientData;
  756.     int iterTmpIndex = infoPtr->loopCtTemp;
  757.     Var *compiledLocals = iPtr->varFramePtr->compiledLocals;
  758.     Var *iterVarPtr = &(compiledLocals[iterTmpIndex]);
  759.     Tcl_Obj *oldValuePtr = iterVarPtr->value.objPtr;
  760.     if (oldValuePtr == NULL) {
  761. iterVarPtr->value.objPtr = Tcl_NewLongObj(-1);
  762. Tcl_IncrRefCount(iterVarPtr->value.objPtr);
  763.     } else {
  764. Tcl_SetLongObj(oldValuePtr, -1);
  765.     }
  766.     TclSetVarScalar(iterVarPtr);
  767.     TclClearVarUndefined(iterVarPtr);
  768.     TRACE(("%u => loop iter count temp %dn", 
  769.    opnd, iterTmpIndex));
  770. }
  771.     
  772. #ifndef TCL_COMPILE_DEBUG
  773. /* 
  774.  * Remark that the compiler ALWAYS sets INST_FOREACH_STEP4
  775.  * immediately after INST_FOREACH_START4 - let us just fall
  776.  * through instead of jumping back to the top.
  777.  */
  778. pc += 5;
  779. TCL_DTRACE_INST_NEXT();
  780. #else
  781. NEXT_INST_F(5, 0, 0);
  782. #endif
  783.     case INST_FOREACH_STEP4:
  784. opnd = TclGetUInt4AtPtr(pc+1);
  785. {
  786.     /*
  787.      * "Step" a foreach loop (i.e., begin its next iteration) by
  788.      * assigning the next value list element to each loop var.
  789.      */
  790.     ForeachInfo *infoPtr = (ForeachInfo *)
  791.             codePtr->auxDataArrayPtr[opnd].clientData;
  792.     ForeachVarList *varListPtr;
  793.     int numLists = infoPtr->numLists;
  794.     Var *compiledLocals = iPtr->varFramePtr->compiledLocals;
  795.     Tcl_Obj *listPtr;
  796.     Var *iterVarPtr, *listVarPtr;
  797.     int iterNum, listTmpIndex, listLen, numVars;
  798.     int varIndex, valIndex, continueLoop, j;
  799.     /*
  800.      * Increment the temp holding the loop iteration number.
  801.      */
  802.     iterVarPtr = &(compiledLocals[infoPtr->loopCtTemp]);
  803.     valuePtr = iterVarPtr->value.objPtr;
  804.     iterNum = (valuePtr->internalRep.longValue + 1);
  805.     Tcl_SetLongObj(valuePtr, iterNum);
  806.     /*
  807.      * Check whether all value lists are exhausted and we should
  808.      * stop the loop.
  809.      */
  810.     continueLoop = 0;
  811.     listTmpIndex = infoPtr->firstValueTemp;
  812.     for (i = 0;  i < numLists;  i++) {
  813. varListPtr = infoPtr->varLists[i];
  814. numVars = varListPtr->numVars;
  815.     
  816. listVarPtr = &(compiledLocals[listTmpIndex]);
  817. listPtr = listVarPtr->value.objPtr;
  818. result = Tcl_ListObjLength(interp, listPtr, &listLen);
  819. if (result != TCL_OK) {
  820.     TRACE_WITH_OBJ(("%u => ERROR converting list %ld, "%s": ",
  821.             opnd, i, O2S(listPtr)), Tcl_GetObjResult(interp));
  822.     goto checkForCatch;
  823. }
  824. if (listLen > (iterNum * numVars)) {
  825.     continueLoop = 1;
  826. }
  827. listTmpIndex++;
  828.     }
  829.     /*
  830.      * If some var in some var list still has a remaining list
  831.      * element iterate one more time. Assign to var the next
  832.      * element from its value list. We already checked above
  833.      * that each list temp holds a valid list object.
  834.      */
  835.     if (continueLoop) {
  836. listTmpIndex = infoPtr->firstValueTemp;
  837. for (i = 0;  i < numLists;  i++) {
  838.     varListPtr = infoPtr->varLists[i];
  839.     numVars = varListPtr->numVars;
  840.     listVarPtr = &(compiledLocals[listTmpIndex]);
  841.     listPtr = listVarPtr->value.objPtr;
  842.     valIndex = (iterNum * numVars);
  843.     for (j = 0;  j < numVars;  j++) {
  844. Tcl_Obj **elements;
  845. /*
  846.  * The call to TclPtrSetVar might shimmer listPtr,
  847.  * so re-fetch pointers every iteration for safety.
  848.  * See test foreach-10.1.
  849.  */
  850. Tcl_ListObjGetElements(NULL, listPtr,
  851. &listLen, &elements);
  852. if (valIndex >= listLen) {
  853.     TclNewObj(valuePtr);
  854. } else {
  855.     valuePtr = elements[valIndex];
  856. }
  857.     
  858. varIndex = varListPtr->varIndexes[j];
  859. varPtr = &(varFramePtr->compiledLocals[varIndex]);
  860. part1 = varPtr->name;
  861. while (TclIsVarLink(varPtr)) {
  862.     varPtr = varPtr->value.linkPtr;
  863. }
  864. if (!((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL))
  865.         && (varPtr->tracePtr == NULL)
  866.         && (TclIsVarScalar(varPtr) || TclIsVarUndefined(varPtr))) {
  867.     value2Ptr = varPtr->value.objPtr;
  868.     if (valuePtr != value2Ptr) {
  869. if (value2Ptr != NULL) {
  870.     TclDecrRefCount(value2Ptr);
  871. } else {
  872.     TclSetVarScalar(varPtr);
  873.     TclClearVarUndefined(varPtr);
  874. }
  875. varPtr->value.objPtr = valuePtr;
  876. Tcl_IncrRefCount(valuePtr);
  877.     }
  878. } else {
  879.     DECACHE_STACK_INFO();
  880.     Tcl_IncrRefCount(valuePtr);
  881.     value2Ptr = TclPtrSetVar(interp, varPtr, NULL, part1, 
  882.      NULL, valuePtr, TCL_LEAVE_ERR_MSG);
  883.     TclDecrRefCount(valuePtr);
  884.     CACHE_STACK_INFO();
  885.     if (value2Ptr == NULL) {
  886. TRACE_WITH_OBJ(("%u => ERROR init. index temp %d: ",
  887. opnd, varIndex),
  888.        Tcl_GetObjResult(interp));
  889. result = TCL_ERROR;
  890. goto checkForCatch;
  891.     }
  892. }
  893. valIndex++;
  894.     }
  895.     listTmpIndex++;
  896. }
  897.     }
  898.     TRACE(("%u => %d lists, iter %d, %s loopn", opnd, numLists, 
  899.             iterNum, (continueLoop? "continue" : "exit")));
  900.     /* 
  901.      * Run-time peep-hole optimisation: the compiler ALWAYS follows
  902.      * INST_FOREACH_STEP4 with an INST_JUMP_FALSE. We just skip that
  903.      * instruction and jump direct from here.
  904.      */
  905.     pc += 5;
  906.     if (*pc == INST_JUMP_FALSE1) {
  907. NEXT_INST_F((continueLoop? 2 : TclGetInt1AtPtr(pc+1)), 0, 0);
  908.     } else {
  909. NEXT_INST_F((continueLoop? 5 : TclGetInt4AtPtr(pc+1)), 0, 0);
  910.     }
  911. }
  912.     case INST_BEGIN_CATCH4:
  913. /*
  914.  * Record start of the catch command with exception range index
  915.  * equal to the operand. Push the current stack depth onto the
  916.  * special catch stack.
  917.  */
  918. catchStackPtr[++catchTop] = stackTop;
  919. TRACE(("%u => catchTop=%d, stackTop=%dn",
  920.        TclGetUInt4AtPtr(pc+1), catchTop, stackTop));
  921. NEXT_INST_F(5, 0, 0);
  922.     case INST_END_CATCH:
  923. catchTop--;
  924. result = TCL_OK;
  925. TRACE(("=> catchTop=%dn", catchTop));
  926. NEXT_INST_F(1, 0, 0);
  927.     
  928.     case INST_PUSH_RESULT:
  929. objResultPtr = Tcl_GetObjResult(interp);
  930. TRACE_WITH_OBJ(("=> "), Tcl_GetObjResult(interp));
  931. /*
  932.  * See the comments at INST_INVOKE_STK
  933.  */
  934. {
  935.     Tcl_Obj *newObjResultPtr;
  936.     TclNewObj(newObjResultPtr);
  937.     Tcl_IncrRefCount(newObjResultPtr);
  938.     iPtr->objResultPtr = newObjResultPtr;
  939. }
  940. NEXT_INST_F(1, 0, -1);
  941.     case INST_PUSH_RETURN_CODE:
  942. objResultPtr = Tcl_NewLongObj(result);
  943. TRACE(("=> %un", result));
  944. NEXT_INST_F(1, 0, 1);
  945.     default:
  946. panic("TclExecuteByteCode: unrecognized opCode %u", *pc);
  947.     } /* end of switch on opCode */
  948.     /*
  949.      * Division by zero in an expression. Control only reaches this
  950.      * point by "goto divideByZero".
  951.      */
  952.  divideByZero:
  953.     DECACHE_STACK_INFO();
  954.     Tcl_ResetResult(interp);
  955.     Tcl_AppendToObj(Tcl_GetObjResult(interp), "divide by zero", -1);
  956.     Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero",
  957.             (char *) NULL);
  958.     CACHE_STACK_INFO();
  959.     result = TCL_ERROR;
  960.     goto checkForCatch;
  961.     /*
  962.      * An external evaluation (INST_INVOKE or INST_EVAL) returned 
  963.      * something different from TCL_OK, or else INST_BREAK or 
  964.      * INST_CONTINUE were called.
  965.      */
  966.  processExceptionReturn:
  967. #if TCL_COMPILE_DEBUG    
  968.     switch (*pc) {
  969.         case INST_INVOKE_STK1:
  970.         case INST_INVOKE_STK4:
  971.     TRACE(("%u => ... after "%.20s": ", opnd, cmdNameBuf));
  972.     break;
  973.         case INST_EVAL_STK:
  974.     /*
  975.      * Note that the object at stacktop has to be used
  976.      * before doing the cleanup.
  977.      */
  978.     TRACE((""%.30s" => ", O2S(stackPtr[stackTop])));
  979.     break;
  980.         default:
  981.     TRACE(("=> "));
  982.     }     
  983. #endif    
  984.     if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) {
  985. rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 0, codePtr);
  986. if (rangePtr == NULL) {
  987.     TRACE_APPEND(("no encl. loop or catch, returning %sn",
  988.             StringForResultCode(result)));
  989.     goto abnormalReturn;
  990. if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
  991.     TRACE_APPEND(("%s ...n", StringForResultCode(result)));
  992.     goto processCatch;
  993. }
  994. while (cleanup--) {
  995.     valuePtr = POP_OBJECT();
  996.     TclDecrRefCount(valuePtr);
  997. }
  998. if (result == TCL_BREAK) {
  999.     result = TCL_OK;
  1000.     pc = (codePtr->codeStart + rangePtr->breakOffset);
  1001.     TRACE_APPEND(("%s, range at %d, new pc %dn",
  1002.    StringForResultCode(result),
  1003.    rangePtr->codeOffset, rangePtr->breakOffset));
  1004.     NEXT_INST_F(0, 0, 0);
  1005. } else {
  1006.     if (rangePtr->continueOffset == -1) {
  1007. TRACE_APPEND(("%s, loop w/o continue, checking for catchn",
  1008.         StringForResultCode(result)));
  1009. goto checkForCatch;
  1010.     } 
  1011.     result = TCL_OK;
  1012.     pc = (codePtr->codeStart + rangePtr->continueOffset);
  1013.     TRACE_APPEND(("%s, range at %d, new pc %dn",
  1014.    StringForResultCode(result),
  1015.    rangePtr->codeOffset, rangePtr->continueOffset));
  1016.     NEXT_INST_F(0, 0, 0);
  1017. }
  1018. #if TCL_COMPILE_DEBUG    
  1019.     } else if (traceInstructions) {
  1020. if ((result != TCL_ERROR) && (result != TCL_RETURN))  {
  1021.     objPtr = Tcl_GetObjResult(interp);
  1022.     TRACE_APPEND(("OTHER RETURN CODE %d, result= "%s"n ", 
  1023.     result, O2S(objPtr)));
  1024. } else {
  1025.     objPtr = Tcl_GetObjResult(interp);
  1026.     TRACE_APPEND(("%s, result= "%s"n", 
  1027.             StringForResultCode(result), O2S(objPtr)));
  1028. }
  1029. #endif
  1030.     }
  1031.     
  1032.     /*
  1033.      * Execution has generated an "exception" such as TCL_ERROR. If the
  1034.      * exception is an error, record information about what was being
  1035.      * executed when the error occurred. Find the closest enclosing
  1036.      * catch range, if any. If no enclosing catch range is found, stop
  1037.      * execution and return the "exception" code.
  1038.      */
  1039.  checkForCatch:
  1040.     if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
  1041. bytes = GetSrcInfoForPc(pc, codePtr, &length);
  1042. if (bytes != NULL) {
  1043.     DECACHE_STACK_INFO();
  1044.     Tcl_LogCommandInfo(interp, codePtr->source, bytes, length);
  1045.             CACHE_STACK_INFO();
  1046.     iPtr->flags |= ERR_ALREADY_LOGGED;
  1047. }
  1048.     }
  1049.     if (catchTop == -1) {
  1050. #ifdef TCL_COMPILE_DEBUG
  1051. if (traceInstructions) {
  1052.     fprintf(stdout, "   ... no enclosing catch, returning %sn",
  1053.             StringForResultCode(result));
  1054. }
  1055. #endif
  1056. goto abnormalReturn;
  1057.     }
  1058.     rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 1, codePtr);
  1059.     if (rangePtr == NULL) {
  1060. /*
  1061.  * This is only possible when compiling a [catch] that sends its
  1062.  * script to INST_EVAL. Cannot correct the compiler without 
  1063.  * breakingcompat with previous .tbc compiled scripts.
  1064.  */
  1065. #ifdef TCL_COMPILE_DEBUG
  1066. if (traceInstructions) {
  1067.     fprintf(stdout, "   ... no enclosing catch, returning %sn",
  1068.             StringForResultCode(result));
  1069. }
  1070. #endif
  1071. goto abnormalReturn;
  1072.     }
  1073.     /*
  1074.      * A catch exception range (rangePtr) was found to handle an
  1075.      * "exception". It was found either by checkForCatch just above or
  1076.      * by an instruction during break, continue, or error processing.
  1077.      * Jump to its catchOffset after unwinding the operand stack to
  1078.      * the depth it had when starting to execute the range's catch
  1079.      * command.
  1080.      */
  1081.  processCatch:
  1082.     while (stackTop > catchStackPtr[catchTop]) {
  1083. valuePtr = POP_OBJECT();
  1084. TclDecrRefCount(valuePtr);
  1085.     }
  1086. #ifdef TCL_COMPILE_DEBUG
  1087.     if (traceInstructions) {
  1088. fprintf(stdout, "  ... found catch at %d, catchTop=%d, unwound to %d, new pc %un",
  1089.         rangePtr->codeOffset, catchTop, catchStackPtr[catchTop],
  1090.         (unsigned int)(rangePtr->catchOffset));
  1091.     }
  1092. #endif
  1093.     pc = (codePtr->codeStart + rangePtr->catchOffset);
  1094.     NEXT_INST_F(0, 0, 0); /* restart the execution loop at pc */
  1095.     /* 
  1096.      * end of infinite loop dispatching on instructions.
  1097.      */
  1098.     /*
  1099.      * Abnormal return code. Restore the stack to state it had when starting
  1100.      * to execute the ByteCode. Panic if the stack is below the initial level.
  1101.      */
  1102.  abnormalReturn:
  1103.     TCL_DTRACE_INST_LAST();
  1104.     while (stackTop > initStackTop) {
  1105. valuePtr = POP_OBJECT();
  1106. TclDecrRefCount(valuePtr);
  1107.     }
  1108.     if (stackTop < initStackTop) {
  1109. fprintf(stderr, "nTclExecuteByteCode: abnormal return at pc %u: stack top %d < entry stack top %dn",
  1110.         (unsigned int)(pc - codePtr->codeStart),
  1111. (unsigned int) stackTop,
  1112. (unsigned int) initStackTop);
  1113. panic("TclExecuteByteCode execution failure: end stack top < start stack top");
  1114.     }
  1115.     /*
  1116.      * Free the catch stack array if malloc'ed storage was used.
  1117.      */
  1118.     if (catchStackPtr != catchStackStorage) {
  1119. ckfree((char *) catchStackPtr);
  1120.     }
  1121.     eePtr->stackTop = initStackTop;
  1122.     return result;
  1123. #undef STATIC_CATCH_STACK_SIZE
  1124. }
  1125. #ifdef TCL_COMPILE_DEBUG
  1126. /*
  1127.  *----------------------------------------------------------------------
  1128.  *
  1129.  * PrintByteCodeInfo --
  1130.  *
  1131.  * This procedure prints a summary about a bytecode object to stdout.
  1132.  * It is called by TclExecuteByteCode when starting to execute the
  1133.  * bytecode object if tclTraceExec has the value 2 or more.
  1134.  *
  1135.  * Results:
  1136.  * None.
  1137.  *
  1138.  * Side effects:
  1139.  * None.
  1140.  *
  1141.  *----------------------------------------------------------------------
  1142.  */
  1143. static void
  1144. PrintByteCodeInfo(codePtr)
  1145.     register ByteCode *codePtr; /* The bytecode whose summary is printed
  1146.  * to stdout. */
  1147. {
  1148.     Proc *procPtr = codePtr->procPtr;
  1149.     Interp *iPtr = (Interp *) *codePtr->interpHandle;
  1150.     fprintf(stdout, "nExecuting ByteCode 0x%x, refCt %u, epoch %u, interp 0x%x (epoch %u)n",
  1151.     (unsigned int) codePtr, codePtr->refCount,
  1152.     codePtr->compileEpoch, (unsigned int) iPtr,
  1153.     iPtr->compileEpoch);
  1154.     
  1155.     fprintf(stdout, "  Source: ");
  1156.     TclPrintSource(stdout, codePtr->source, 60);
  1157.     fprintf(stdout, "n  Cmds %d, src %d, inst %u, litObjs %u, aux %d, stkDepth %u, code/src %.2fn",
  1158.             codePtr->numCommands, codePtr->numSrcBytes,
  1159.     codePtr->numCodeBytes, codePtr->numLitObjects,
  1160.     codePtr->numAuxDataItems, codePtr->maxStackDepth,
  1161. #ifdef TCL_COMPILE_STATS
  1162.     (codePtr->numSrcBytes?
  1163.             ((float)codePtr->structureSize)/((float)codePtr->numSrcBytes) : 0.0));
  1164. #else
  1165.     0.0);
  1166. #endif
  1167. #ifdef TCL_COMPILE_STATS
  1168.     fprintf(stdout, "  Code %d = header %d+inst %d+litObj %d+exc %d+aux %d+cmdMap %dn",
  1169.     codePtr->structureSize,
  1170.     (sizeof(ByteCode) - (sizeof(size_t) + sizeof(Tcl_Time))),
  1171.     codePtr->numCodeBytes,
  1172.     (codePtr->numLitObjects * sizeof(Tcl_Obj *)),
  1173.     (codePtr->numExceptRanges * sizeof(ExceptionRange)),
  1174.     (codePtr->numAuxDataItems * sizeof(AuxData)),
  1175.     codePtr->numCmdLocBytes);
  1176. #endif /* TCL_COMPILE_STATS */
  1177.     if (procPtr != NULL) {
  1178. fprintf(stdout,
  1179. "  Proc 0x%x, refCt %d, args %d, compiled locals %dn",
  1180. (unsigned int) procPtr, procPtr->refCount,
  1181. procPtr->numArgs, procPtr->numCompiledLocals);
  1182.     }
  1183. }
  1184. #endif /* TCL_COMPILE_DEBUG */
  1185. /*
  1186.  *----------------------------------------------------------------------
  1187.  *
  1188.  * ValidatePcAndStackTop --
  1189.  *
  1190.  * This procedure is called by TclExecuteByteCode when debugging to
  1191.  * verify that the program counter and stack top are valid during
  1192.  * execution.
  1193.  *
  1194.  * Results:
  1195.  * None.
  1196.  *
  1197.  * Side effects:
  1198.  * Prints a message to stderr and panics if either the pc or stack
  1199.  * top are invalid.
  1200.  *
  1201.  *----------------------------------------------------------------------
  1202.  */
  1203. #ifdef TCL_COMPILE_DEBUG
  1204. static void
  1205. ValidatePcAndStackTop(codePtr, pc, stackTop, stackLowerBound)
  1206.     register ByteCode *codePtr; /* The bytecode whose summary is printed
  1207.  * to stdout. */
  1208.     unsigned char *pc; /* Points to first byte of a bytecode
  1209.  * instruction. The program counter. */
  1210.     int stackTop; /* Current stack top. Must be between
  1211.  * stackLowerBound and stackUpperBound
  1212.  * (inclusive). */
  1213.     int stackLowerBound; /* Smallest legal value for stackTop. */
  1214. {
  1215.     int stackUpperBound = stackLowerBound +  codePtr->maxStackDepth;
  1216.                                 /* Greatest legal value for stackTop. */
  1217.     unsigned int relativePc = (unsigned int) (pc - codePtr->codeStart);
  1218.     unsigned int codeStart = (unsigned int) codePtr->codeStart;
  1219.     unsigned int codeEnd = (unsigned int)
  1220.     (codePtr->codeStart + codePtr->numCodeBytes);
  1221.     unsigned char opCode = *pc;
  1222.     if (((unsigned int) pc < codeStart) || ((unsigned int) pc > codeEnd)) {
  1223. fprintf(stderr, "nBad instruction pc 0x%x in TclExecuteByteCoden",
  1224. (unsigned int) pc);
  1225. panic("TclExecuteByteCode execution failure: bad pc");
  1226.     }
  1227.     if ((unsigned int) opCode > LAST_INST_OPCODE) {
  1228. fprintf(stderr, "nBad opcode %d at pc %u in TclExecuteByteCoden",
  1229. (unsigned int) opCode, relativePc);
  1230.         panic("TclExecuteByteCode execution failure: bad opcode");
  1231.     }
  1232.     if ((stackTop < stackLowerBound) || (stackTop > stackUpperBound)) {
  1233. int numChars;
  1234. char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars);
  1235. char *ellipsis = "";
  1236. fprintf(stderr, "nBad stack top %d at pc %u in TclExecuteByteCode (min %i, max %i)",
  1237. stackTop, relativePc, stackLowerBound, stackUpperBound);
  1238. if (cmd != NULL) {
  1239.     if (numChars > 100) {
  1240. numChars = 100;
  1241. ellipsis = "...";
  1242.     }
  1243.     fprintf(stderr, "n executing %.*s%sn", numChars, cmd,
  1244.     ellipsis);
  1245. } else {
  1246.     fprintf(stderr, "n");
  1247. }
  1248. panic("TclExecuteByteCode execution failure: bad stack top");
  1249.     }
  1250. }
  1251. #endif /* TCL_COMPILE_DEBUG */
  1252. /*
  1253.  *----------------------------------------------------------------------
  1254.  *
  1255.  * IllegalExprOperandType --
  1256.  *
  1257.  * Used by TclExecuteByteCode to add an error message to errorInfo
  1258.  * when an illegal operand type is detected by an expression
  1259.  * instruction. The argument opndPtr holds the operand object in error.
  1260.  *
  1261.  * Results:
  1262.  * None.
  1263.  *
  1264.  * Side effects:
  1265.  * An error message is appended to errorInfo.
  1266.  *
  1267.  *----------------------------------------------------------------------
  1268.  */
  1269. static void
  1270. IllegalExprOperandType(interp, pc, opndPtr)
  1271.     Tcl_Interp *interp; /* Interpreter to which error information
  1272.  * pertains. */
  1273.     unsigned char *pc; /* Points to the instruction being executed
  1274.  * when the illegal type was found. */
  1275.     Tcl_Obj *opndPtr; /* Points to the operand holding the value
  1276.  * with the illegal type. */
  1277. {
  1278.     unsigned char opCode = *pc;
  1279.     
  1280.     Tcl_ResetResult(interp);
  1281.     if ((opndPtr->bytes == NULL) || (opndPtr->length == 0)) {
  1282. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1283. "can't use empty string as operand of "",
  1284. operatorStrings[opCode - INST_LOR], """, (char *) NULL);
  1285.     } else {
  1286. char *msg = "non-numeric string";
  1287. char *s, *p;
  1288. int length;
  1289. int looksLikeInt = 0;
  1290. s = Tcl_GetStringFromObj(opndPtr, &length);
  1291. p = s;
  1292. /*
  1293.  * strtod() isn't at all consistent about detecting Inf and
  1294.  * NaN between platforms.
  1295.  */
  1296. if (length == 3) {
  1297.     if ((s[0]=='n' || s[0]=='N') && (s[1]=='a' || s[1]=='A') &&
  1298.     (s[2]=='n' || s[2]=='N')) {
  1299. msg = "non-numeric floating-point value";
  1300. goto makeErrorMessage;
  1301.     }
  1302.     if ((s[0]=='i' || s[0]=='I') && (s[1]=='n' || s[1]=='N') &&
  1303.     (s[2]=='f' || s[2]=='F')) {
  1304. msg = "infinite floating-point value";
  1305. goto makeErrorMessage;
  1306.     }
  1307. }
  1308. /*
  1309.  * We cannot use TclLooksLikeInt here because it passes strings
  1310.  * like "10;" [Bug 587140]. We'll accept as "looking like ints"
  1311.  * for the present purposes any string that looks formally like
  1312.  * a (decimal|octal|hex) integer.
  1313.  */
  1314. while (length && isspace(UCHAR(*p))) {
  1315.     length--;
  1316.     p++;
  1317. }
  1318. if (length && ((*p == '+') || (*p == '-'))) {
  1319.     length--;
  1320.     p++;
  1321. }
  1322. if (length) {
  1323.     if ((*p == '0') && ((*(p+1) == 'x') || (*(p+1) == 'X'))) {
  1324. p += 2;
  1325. length -= 2;
  1326. looksLikeInt = ((length > 0) && isxdigit(UCHAR(*p)));
  1327. if (looksLikeInt) {
  1328.     length--;
  1329.     p++;
  1330.     while (length && isxdigit(UCHAR(*p))) {
  1331. length--;
  1332. p++;
  1333.     }
  1334. }
  1335.     } else {
  1336. looksLikeInt = (length && isdigit(UCHAR(*p)));
  1337. if (looksLikeInt) {
  1338.     length--;
  1339.     p++;
  1340.     while (length && isdigit(UCHAR(*p))) {
  1341. length--;
  1342. p++;
  1343.     }
  1344. }
  1345.     }
  1346.     while (length && isspace(UCHAR(*p))) {
  1347. length--;
  1348. p++;
  1349.     }
  1350.     looksLikeInt = !length;
  1351. }
  1352. if (looksLikeInt) {
  1353.     /*
  1354.      * If something that looks like an integer could not be
  1355.      * converted, then it *must* be a bad octal or too large
  1356.      * to represent [Bug 542588].
  1357.      */
  1358.     if (TclCheckBadOctal(NULL, s)) {
  1359. msg = "invalid octal number";
  1360.     } else {
  1361. msg = "integer value too large to represent";
  1362. Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  1363.     "integer value too large to represent", (char *) NULL);
  1364.     }
  1365. } else {
  1366.     /*
  1367.      * See if the operand can be interpreted as a double in
  1368.      * order to improve the error message.
  1369.      */
  1370.     double d;
  1371.     if (Tcl_GetDouble((Tcl_Interp *) NULL, s, &d) == TCL_OK) {
  1372. msg = "floating-point value";
  1373.     }
  1374. }
  1375.       makeErrorMessage:
  1376. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't use ",
  1377. msg, " as operand of "", operatorStrings[opCode - INST_LOR],
  1378. """, (char *) NULL);
  1379.     }
  1380. }
  1381. /*
  1382.  *----------------------------------------------------------------------
  1383.  *
  1384.  * TclGetSrcInfoForPc, GetSrcInfoForPc --
  1385.  *
  1386.  * Given a program counter value, finds the closest command in the
  1387.  * bytecode code unit's CmdLocation array and returns information about
  1388.  * that command's source: a pointer to its first byte and the number of
  1389.  * characters.
  1390.  *
  1391.  * Results:
  1392.  * If a command is found that encloses the program counter value, a
  1393.  * pointer to the command's source is returned and the length of the
  1394.  * source is stored at *lengthPtr. If multiple commands resulted in
  1395.  * code at pc, information about the closest enclosing command is
  1396.  * returned. If no matching command is found, NULL is returned and
  1397.  * *lengthPtr is unchanged.
  1398.  *
  1399.  * Side effects:
  1400.  * None.
  1401.  *
  1402.  *----------------------------------------------------------------------
  1403.  */
  1404. #ifdef TCL_TIP280
  1405. void
  1406. TclGetSrcInfoForPc (cfPtr)
  1407.      CmdFrame* cfPtr;
  1408. {
  1409.     ByteCode* codePtr = (ByteCode*) cfPtr->data.tebc.codePtr;
  1410.     if (cfPtr->cmd.str.cmd == NULL) {
  1411.         cfPtr->cmd.str.cmd = GetSrcInfoForPc((char*) cfPtr->data.tebc.pc,
  1412.      codePtr,
  1413.      &cfPtr->cmd.str.len);
  1414.     }
  1415.     if (cfPtr->cmd.str.cmd != NULL) {
  1416.         /* We now have the command. We can get the srcOffset back and
  1417.  * from there find the list of word locations for this command
  1418.  */
  1419. ExtCmdLoc*     eclPtr;
  1420. ECL*           locPtr = NULL;
  1421. int            srcOffset;
  1422.         Interp*        iPtr  = (Interp*) *codePtr->interpHandle;
  1423. Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr);
  1424. if (!hePtr) return;
  1425. srcOffset = cfPtr->cmd.str.cmd - codePtr->source;
  1426. eclPtr    = (ExtCmdLoc*) Tcl_GetHashValue (hePtr);
  1427. {
  1428.     int i;
  1429.     for (i=0; i < eclPtr->nuloc; i++) {
  1430. if (eclPtr->loc [i].srcOffset == srcOffset) {
  1431.     locPtr = &(eclPtr->loc [i]);
  1432.     break;
  1433. }
  1434.     }
  1435. }
  1436. if (locPtr == NULL) {Tcl_Panic ("LocSearch failure");}
  1437. cfPtr->line           = locPtr->line;
  1438. cfPtr->nline          = locPtr->nline;
  1439. cfPtr->type           = eclPtr->type;
  1440. if (eclPtr->type == TCL_LOCATION_SOURCE) {
  1441.     cfPtr->data.eval.path = eclPtr->path;
  1442.     Tcl_IncrRefCount (cfPtr->data.eval.path);
  1443. }
  1444. /* Do not set cfPtr->data.eval.path NULL for non-SOURCE
  1445.  * Needed for cfPtr->data.tebc.codePtr.
  1446.  */
  1447.     }
  1448. }
  1449. #endif
  1450. static char *
  1451. GetSrcInfoForPc(pc, codePtr, lengthPtr)
  1452.     unsigned char *pc; /* The program counter value for which to
  1453.  * return the closest command's source info.
  1454.  * This points to a bytecode instruction
  1455.  * in codePtr's code. */
  1456.     ByteCode *codePtr; /* The bytecode sequence in which to look
  1457.  * up the command source for the pc. */
  1458.     int *lengthPtr; /* If non-NULL, the location where the
  1459.  * length of the command's source should be
  1460.  * stored. If NULL, no length is stored. */
  1461. {
  1462.     register int pcOffset = (pc - codePtr->codeStart);
  1463.     int numCmds = codePtr->numCommands;
  1464.     unsigned char *codeDeltaNext, *codeLengthNext;
  1465.     unsigned char *srcDeltaNext, *srcLengthNext;
  1466.     int codeOffset, codeLen, codeEnd, srcOffset, srcLen, delta, i;
  1467.     int bestDist = INT_MAX; /* Distance of pc to best cmd's start pc. */
  1468.     int bestSrcOffset = -1; /* Initialized to avoid compiler warning. */
  1469.     int bestSrcLength = -1; /* Initialized to avoid compiler warning. */
  1470.     if ((pcOffset < 0) || (pcOffset >= codePtr->numCodeBytes)) {
  1471. return NULL;
  1472.     }
  1473.     /*
  1474.      * Decode the code and source offset and length for each command. The
  1475.      * closest enclosing command is the last one whose code started before
  1476.      * pcOffset.
  1477.      */
  1478.     codeDeltaNext = codePtr->codeDeltaStart;
  1479.     codeLengthNext = codePtr->codeLengthStart;
  1480.     srcDeltaNext  = codePtr->srcDeltaStart;
  1481.     srcLengthNext = codePtr->srcLengthStart;
  1482.     codeOffset = srcOffset = 0;
  1483.     for (i = 0;  i < numCmds;  i++) {
  1484. if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) {
  1485.     codeDeltaNext++;
  1486.     delta = TclGetInt4AtPtr(codeDeltaNext);
  1487.     codeDeltaNext += 4;
  1488. } else {
  1489.     delta = TclGetInt1AtPtr(codeDeltaNext);
  1490.     codeDeltaNext++;
  1491. }
  1492. codeOffset += delta;
  1493. if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) {
  1494.     codeLengthNext++;
  1495.     codeLen = TclGetInt4AtPtr(codeLengthNext);
  1496.     codeLengthNext += 4;
  1497. } else {
  1498.     codeLen = TclGetInt1AtPtr(codeLengthNext);
  1499.     codeLengthNext++;
  1500. }
  1501. codeEnd = (codeOffset + codeLen - 1);
  1502. if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) {
  1503.     srcDeltaNext++;
  1504.     delta = TclGetInt4AtPtr(srcDeltaNext);
  1505.     srcDeltaNext += 4;
  1506. } else {
  1507.     delta = TclGetInt1AtPtr(srcDeltaNext);
  1508.     srcDeltaNext++;
  1509. }
  1510. srcOffset += delta;
  1511. if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) {
  1512.     srcLengthNext++;
  1513.     srcLen = TclGetInt4AtPtr(srcLengthNext);
  1514.     srcLengthNext += 4;
  1515. } else {
  1516.     srcLen = TclGetInt1AtPtr(srcLengthNext);
  1517.     srcLengthNext++;
  1518. }
  1519. if (codeOffset > pcOffset) {      /* best cmd already found */
  1520.     break;
  1521. } else if (pcOffset <= codeEnd) { /* this cmd's code encloses pc */
  1522.     int dist = (pcOffset - codeOffset);
  1523.     if (dist <= bestDist) {
  1524. bestDist = dist;
  1525. bestSrcOffset = srcOffset;
  1526. bestSrcLength = srcLen;
  1527.     }
  1528. }
  1529.     }
  1530.     if (bestDist == INT_MAX) {
  1531. return NULL;
  1532.     }
  1533.     
  1534.     if (lengthPtr != NULL) {
  1535. *lengthPtr = bestSrcLength;
  1536.     }
  1537.     return (codePtr->source + bestSrcOffset);
  1538. }
  1539. /*
  1540.  *----------------------------------------------------------------------
  1541.  *
  1542.  * GetExceptRangeForPc --
  1543.  *
  1544.  * Given a program counter value, return the closest enclosing
  1545.  * ExceptionRange.
  1546.  *
  1547.  * Results:
  1548.  * In the normal case, catchOnly is 0 (false) and this procedure
  1549.  * returns a pointer to the most closely enclosing ExceptionRange
  1550.  * structure regardless of whether it is a loop or catch exception
  1551.  * range. This is appropriate when processing a TCL_BREAK or
  1552.  * TCL_CONTINUE, which will be "handled" either by a loop exception
  1553.  * range or a closer catch range. If catchOnly is nonzero, this
  1554.  * procedure ignores loop exception ranges and returns a pointer to the
  1555.  * closest catch range. If no matching ExceptionRange is found that
  1556.  * encloses pc, a NULL is returned.
  1557.  *
  1558.  * Side effects:
  1559.  * None.
  1560.  *
  1561.  *----------------------------------------------------------------------
  1562.  */
  1563. static ExceptionRange *
  1564. GetExceptRangeForPc(pc, catchOnly, codePtr)
  1565.     unsigned char *pc; /* The program counter value for which to
  1566.  * search for a closest enclosing exception
  1567.  * range. This points to a bytecode
  1568.  * instruction in codePtr's code. */
  1569.     int catchOnly; /* If 0, consider either loop or catch
  1570.  * ExceptionRanges in search. If nonzero
  1571.  * consider only catch ranges (and ignore
  1572.  * any closer loop ranges). */
  1573.     ByteCode* codePtr; /* Points to the ByteCode in which to search
  1574.  * for the enclosing ExceptionRange. */
  1575. {
  1576.     ExceptionRange *rangeArrayPtr;
  1577.     int numRanges = codePtr->numExceptRanges;
  1578.     register ExceptionRange *rangePtr;
  1579.     int pcOffset = (pc - codePtr->codeStart);
  1580.     register int start;
  1581.     if (numRanges == 0) {
  1582. return NULL;
  1583.     }
  1584.     /* 
  1585.      * This exploits peculiarities of our compiler: nested ranges
  1586.      * are always *after* their containing ranges, so that by scanning
  1587.      * backwards we are sure that the first matching range is indeed
  1588.      * the deepest.
  1589.      */
  1590.     rangeArrayPtr = codePtr->exceptArrayPtr;
  1591.     rangePtr = rangeArrayPtr + numRanges;
  1592.     while (--rangePtr >= rangeArrayPtr) {
  1593. start = rangePtr->codeOffset;
  1594. if ((start <= pcOffset) &&
  1595.         (pcOffset < (start + rangePtr->numCodeBytes))) {
  1596.     if ((!catchOnly)
  1597.     || (rangePtr->type == CATCH_EXCEPTION_RANGE)) {
  1598. return rangePtr;
  1599.     }
  1600. }
  1601.     }
  1602.     return NULL;
  1603. }
  1604. /*
  1605.  *----------------------------------------------------------------------
  1606.  *
  1607.  * GetOpcodeName --
  1608.  *
  1609.  * This procedure is called by the TRACE and TRACE_WITH_OBJ macros
  1610.  * used in TclExecuteByteCode when debugging. It returns the name of
  1611.  * the bytecode instruction at a specified instruction pc.
  1612.  *
  1613.  * Results:
  1614.  * A character string for the instruction.
  1615.  *
  1616.  * Side effects:
  1617.  * None.
  1618.  *
  1619.  *----------------------------------------------------------------------
  1620.  */
  1621. #ifdef TCL_COMPILE_DEBUG
  1622. static char *
  1623. GetOpcodeName(pc)
  1624.     unsigned char *pc; /* Points to the instruction whose name
  1625.  * should be returned. */
  1626. {
  1627.     unsigned char opCode = *pc;
  1628.     
  1629.     return tclInstructionTable[opCode].name;
  1630. }
  1631. #endif /* TCL_COMPILE_DEBUG */
  1632. /*
  1633.  *----------------------------------------------------------------------
  1634.  *
  1635.  * VerifyExprObjType --
  1636.  *
  1637.  * This procedure is called by the math functions to verify that
  1638.  * the object is either an int or double, coercing it if necessary.
  1639.  * If an error occurs during conversion, an error message is left
  1640.  * in the interpreter's result unless "interp" is NULL.
  1641.  *
  1642.  * Results:
  1643.  * TCL_OK if it was int or double, TCL_ERROR otherwise
  1644.  *
  1645.  * Side effects:
  1646.  * objPtr is ensured to be of tclIntType, tclWideIntType or
  1647.  * tclDoubleType.
  1648.  *
  1649.  *----------------------------------------------------------------------
  1650.  */
  1651. static int
  1652. VerifyExprObjType(interp, objPtr)
  1653.     Tcl_Interp *interp; /* The interpreter in which to execute the
  1654.  * function. */
  1655.     Tcl_Obj *objPtr; /* Points to the object to type check. */
  1656. {
  1657.     if (IS_NUMERIC_TYPE(objPtr->typePtr)) {
  1658. return TCL_OK;
  1659.     } else {
  1660. int length, result = TCL_OK;
  1661. char *s = Tcl_GetStringFromObj(objPtr, &length);
  1662. if (TclLooksLikeInt(s, length)) {
  1663.     long i;
  1664.     Tcl_WideInt w;
  1665.     GET_WIDE_OR_INT(result, objPtr, i, w);
  1666. } else {
  1667.     double d;
  1668.     result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, objPtr, &d);
  1669. }
  1670. if ((result != TCL_OK) && (interp != NULL)) {
  1671.     Tcl_ResetResult(interp);
  1672.     if (TclCheckBadOctal((Tcl_Interp *) NULL, s)) {
  1673. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1674. "argument to math function was an invalid octal number",
  1675. -1);
  1676.     } else {
  1677. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1678. "argument to math function didn't have numeric value",
  1679. -1);
  1680.     }
  1681. }
  1682. return result;
  1683.     }
  1684. }
  1685. /*
  1686.  *----------------------------------------------------------------------
  1687.  *
  1688.  * Math Functions --
  1689.  *
  1690.  * This page contains the procedures that implement all of the
  1691.  * built-in math functions for expressions.
  1692.  *
  1693.  * Results:
  1694.  * Each procedure returns TCL_OK if it succeeds and pushes an
  1695.  * Tcl object holding the result. If it fails it returns TCL_ERROR
  1696.  * and leaves an error message in the interpreter's result.
  1697.  *
  1698.  * Side effects:
  1699.  * None.
  1700.  *
  1701.  *----------------------------------------------------------------------
  1702.  */
  1703. static int
  1704. ExprUnaryFunc(interp, eePtr, clientData)
  1705.     Tcl_Interp *interp; /* The interpreter in which to execute the
  1706.  * function. */
  1707.     ExecEnv *eePtr; /* Points to the environment for executing
  1708.  * the function. */
  1709.     ClientData clientData; /* Contains the address of a procedure that
  1710.  * takes one double argument and returns a
  1711.  * double result. */
  1712. {
  1713.     Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */
  1714.     register int stackTop; /* Cached top index of evaluation stack. */
  1715.     register Tcl_Obj *valuePtr;
  1716.     double d, dResult;
  1717.     int result;
  1718.     
  1719.     double (*func) _ANSI_ARGS_((double)) =
  1720. (double (*)_ANSI_ARGS_((double))) clientData;
  1721.     /*
  1722.      * Set stackPtr and stackTop from eePtr.
  1723.      */
  1724.     result = TCL_OK;
  1725.     CACHE_STACK_INFO();
  1726.     /*
  1727.      * Pop the function's argument from the evaluation stack. Convert it
  1728.      * to a double if necessary.
  1729.      */
  1730.     valuePtr = POP_OBJECT();
  1731.     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  1732. result = TCL_ERROR;
  1733. goto done;
  1734.     }
  1735.     GET_DOUBLE_VALUE(d, valuePtr, valuePtr->typePtr);
  1736.     errno = 0;
  1737.     dResult = (*func)(d);
  1738.     if ((errno != 0) || IS_NAN(dResult) || IS_INF(dResult)) {
  1739. TclExprFloatError(interp, dResult);
  1740. result = TCL_ERROR;
  1741. goto done;
  1742.     }
  1743.     
  1744.     /*
  1745.      * Push a Tcl object holding the result.
  1746.      */
  1747.     PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  1748.     
  1749.     /*
  1750.      * Reflect the change to stackTop back in eePtr.
  1751.      */
  1752.     done:
  1753.     TclDecrRefCount(valuePtr);
  1754.     DECACHE_STACK_INFO();
  1755.     return result;
  1756. }
  1757. static int
  1758. ExprBinaryFunc(interp, eePtr, clientData)
  1759.     Tcl_Interp *interp; /* The interpreter in which to execute the
  1760.  * function. */
  1761.     ExecEnv *eePtr; /* Points to the environment for executing
  1762.  * the function. */
  1763.     ClientData clientData; /* Contains the address of a procedure that
  1764.  * takes two double arguments and
  1765.  * returns a double result. */
  1766. {
  1767.     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  1768.     register int stackTop; /* Cached top index of evaluation stack. */
  1769.     register Tcl_Obj *valuePtr, *value2Ptr;
  1770.     double d1, d2, dResult;
  1771.     int result;
  1772.     
  1773.     double (*func) _ANSI_ARGS_((double, double))
  1774. = (double (*)_ANSI_ARGS_((double, double))) clientData;
  1775.     /*
  1776.      * Set stackPtr and stackTop from eePtr.
  1777.      */
  1778.     result = TCL_OK;
  1779.     CACHE_STACK_INFO();
  1780.     /*
  1781.      * Pop the function's two arguments from the evaluation stack. Convert
  1782.      * them to doubles if necessary.
  1783.      */
  1784.     value2Ptr = POP_OBJECT();
  1785.     valuePtr  = POP_OBJECT();
  1786.     if ((VerifyExprObjType(interp, valuePtr) != TCL_OK) ||
  1787.     (VerifyExprObjType(interp, value2Ptr) != TCL_OK)) {
  1788. result = TCL_ERROR;
  1789. goto done;
  1790.     }
  1791.     GET_DOUBLE_VALUE(d1, valuePtr, valuePtr->typePtr);
  1792.     GET_DOUBLE_VALUE(d2, value2Ptr, value2Ptr->typePtr);
  1793.     errno = 0;
  1794.     dResult = (*func)(d1, d2);
  1795.     if ((errno != 0) || IS_NAN(dResult) || IS_INF(dResult)) {
  1796. TclExprFloatError(interp, dResult);
  1797. result = TCL_ERROR;
  1798. goto done;
  1799.     }
  1800.     /*
  1801.      * Push a Tcl object holding the result.
  1802.      */
  1803.     PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  1804.     
  1805.     /*
  1806.      * Reflect the change to stackTop back in eePtr.
  1807.      */
  1808.     done:
  1809.     TclDecrRefCount(valuePtr);
  1810.     TclDecrRefCount(value2Ptr);
  1811.     DECACHE_STACK_INFO();
  1812.     return result;
  1813. }
  1814. static int
  1815. ExprAbsFunc(interp, eePtr, clientData)
  1816.     Tcl_Interp *interp; /* The interpreter in which to execute the
  1817.  * function. */
  1818.     ExecEnv *eePtr; /* Points to the environment for executing
  1819.  * the function. */
  1820.     ClientData clientData; /* Ignored. */
  1821. {
  1822.     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  1823.     register int stackTop; /* Cached top index of evaluation stack. */
  1824.     register Tcl_Obj *valuePtr;
  1825.     long i, iResult;
  1826.     double d, dResult;
  1827.     int result;
  1828.     /*
  1829.      * Set stackPtr and stackTop from eePtr.
  1830.      */
  1831.     result = TCL_OK;
  1832.     CACHE_STACK_INFO();
  1833.     /*
  1834.      * Pop the argument from the evaluation stack.
  1835.      */
  1836.     valuePtr = POP_OBJECT();
  1837.     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  1838. result = TCL_ERROR;
  1839. goto done;
  1840.     }
  1841.     /*
  1842.      * Push a Tcl object with the result.
  1843.      */
  1844.     if (valuePtr->typePtr == &tclIntType) {
  1845. i = valuePtr->internalRep.longValue;
  1846. if (i < 0) {
  1847.     if (i == LONG_MIN) {
  1848. #ifdef TCL_WIDE_INT_IS_LONG
  1849. Tcl_SetObjResult(interp, Tcl_NewStringObj(
  1850. "integer value too large to represent", -1));
  1851. Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  1852. "integer value too large to represent", (char *) NULL);
  1853. result = TCL_ERROR;
  1854. goto done;
  1855. #else 
  1856. /*
  1857.  * Special case: abs(MIN_INT) must promote to wide.
  1858.  */
  1859. PUSH_OBJECT( Tcl_NewWideIntObj(-(Tcl_WideInt) i) );
  1860. result = TCL_OK;
  1861. goto done;
  1862. #endif
  1863.     }
  1864.     iResult = -i;
  1865. } else {
  1866.     iResult = i;
  1867. }     
  1868. PUSH_OBJECT(Tcl_NewLongObj(iResult));
  1869.     } else if (valuePtr->typePtr == &tclWideIntType) {
  1870. Tcl_WideInt wResult, w;
  1871. TclGetWide(w,valuePtr);
  1872. if (w < W0) {
  1873.     wResult = -w;
  1874.     if (wResult < 0) {
  1875. Tcl_ResetResult(interp);
  1876. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1877.         "integer value too large to represent", -1);
  1878. Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  1879. "integer value too large to represent", (char *) NULL);
  1880. result = TCL_ERROR;
  1881. goto done;
  1882.     }
  1883. } else {
  1884.     wResult = w;
  1885. }     
  1886. PUSH_OBJECT(Tcl_NewWideIntObj(wResult));
  1887.     } else {
  1888. d = valuePtr->internalRep.doubleValue;
  1889. if (d < 0.0) {
  1890.     dResult = -d;
  1891. } else {
  1892.     dResult = d;
  1893. }
  1894. if (IS_NAN(dResult) || IS_INF(dResult)) {
  1895.     TclExprFloatError(interp, dResult);
  1896.     result = TCL_ERROR;
  1897.     goto done;
  1898. }
  1899. PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  1900.     }
  1901.     /*
  1902.      * Reflect the change to stackTop back in eePtr.
  1903.      */
  1904.     done:
  1905.     TclDecrRefCount(valuePtr);
  1906.     DECACHE_STACK_INFO();
  1907.     return result;
  1908. }
  1909. static int
  1910. ExprDoubleFunc(interp, eePtr, clientData)
  1911.     Tcl_Interp *interp; /* The interpreter in which to execute the
  1912.  * function. */
  1913.     ExecEnv *eePtr; /* Points to the environment for executing
  1914.  * the function. */
  1915.     ClientData clientData; /* Ignored. */
  1916. {
  1917.     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  1918.     register int stackTop; /* Cached top index of evaluation stack. */
  1919.     register Tcl_Obj *valuePtr;
  1920.     double dResult;
  1921.     int result;
  1922.     /*
  1923.      * Set stackPtr and stackTop from eePtr.
  1924.      */
  1925.     result = TCL_OK;
  1926.     CACHE_STACK_INFO();
  1927.     /*
  1928.      * Pop the argument from the evaluation stack.
  1929.      */
  1930.     valuePtr = POP_OBJECT();
  1931.     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  1932. result = TCL_ERROR;
  1933. goto done;
  1934.     }
  1935.     GET_DOUBLE_VALUE(dResult, valuePtr, valuePtr->typePtr);
  1936.     /*
  1937.      * Push a Tcl object with the result.
  1938.      */
  1939.     PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  1940.     /*
  1941.      * Reflect the change to stackTop back in eePtr.
  1942.      */
  1943.     done:
  1944.     TclDecrRefCount(valuePtr);
  1945.     DECACHE_STACK_INFO();
  1946.     return result;
  1947. }
  1948. static int
  1949. ExprIntFunc(interp, eePtr, clientData)
  1950.     Tcl_Interp *interp; /* The interpreter in which to execute the
  1951.  * function. */
  1952.     ExecEnv *eePtr; /* Points to the environment for executing
  1953.  * the function. */
  1954.     ClientData clientData; /* Ignored. */
  1955. {
  1956.     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  1957.     register int stackTop; /* Cached top index of evaluation stack. */
  1958.     register Tcl_Obj *valuePtr;
  1959.     long iResult;
  1960.     double d;
  1961.     int result;
  1962.     /*
  1963.      * Set stackPtr and stackTop from eePtr.
  1964.      */
  1965.     result = TCL_OK;
  1966.     CACHE_STACK_INFO();
  1967.     /*
  1968.      * Pop the argument from the evaluation stack.
  1969.      */
  1970.     valuePtr = POP_OBJECT();
  1971.     
  1972.     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  1973. result = TCL_ERROR;
  1974. goto done;
  1975.     }
  1976.     
  1977.     if (valuePtr->typePtr == &tclIntType) {
  1978. iResult = valuePtr->internalRep.longValue;
  1979.     } else if (valuePtr->typePtr == &tclWideIntType) {
  1980. TclGetLongFromWide(iResult,valuePtr);
  1981.     } else {
  1982. d = valuePtr->internalRep.doubleValue;
  1983. if (d < 0.0) {
  1984.     if (d < (double) (long) LONG_MIN) {
  1985. tooLarge:
  1986. Tcl_ResetResult(interp);
  1987. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1988.         "integer value too large to represent", -1);
  1989. Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  1990. "integer value too large to represent", (char *) NULL);
  1991. result = TCL_ERROR;
  1992. goto done;
  1993.     }
  1994. } else {
  1995.     if (d > (double) LONG_MAX) {
  1996. goto tooLarge;
  1997.     }
  1998. }
  1999. if (IS_NAN(d) || IS_INF(d)) {
  2000.     TclExprFloatError(interp, d);
  2001.     result = TCL_ERROR;
  2002.     goto done;
  2003. }
  2004. iResult = (long) d;
  2005.     }
  2006.     /*
  2007.      * Push a Tcl object with the result.
  2008.      */
  2009.     
  2010.     PUSH_OBJECT(Tcl_NewLongObj(iResult));
  2011.     /*
  2012.      * Reflect the change to stackTop back in eePtr.
  2013.      */
  2014.     done:
  2015.     TclDecrRefCount(valuePtr);
  2016.     DECACHE_STACK_INFO();
  2017.     return result;
  2018. }
  2019. static int
  2020. ExprWideFunc(interp, eePtr, clientData)
  2021.     Tcl_Interp *interp; /* The interpreter in which to execute the
  2022.  * function. */
  2023.     ExecEnv *eePtr; /* Points to the environment for executing
  2024.  * the function. */
  2025.     ClientData clientData; /* Ignored. */
  2026. {
  2027.     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  2028.     register int stackTop; /* Cached top index of evaluation stack. */
  2029.     register Tcl_Obj *valuePtr;
  2030.     Tcl_WideInt wResult;
  2031.     double d;
  2032.     int result;
  2033.     /*
  2034.      * Set stackPtr and stackTop from eePtr.
  2035.      */
  2036.     result = TCL_OK;
  2037.     CACHE_STACK_INFO();
  2038.     /*
  2039.      * Pop the argument from the evaluation stack.
  2040.      */
  2041.     valuePtr = POP_OBJECT();
  2042.     
  2043.     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  2044. result = TCL_ERROR;
  2045. goto done;
  2046.     }
  2047.     
  2048.     if (valuePtr->typePtr == &tclWideIntType) {
  2049. TclGetWide(wResult,valuePtr);
  2050.     } else if (valuePtr->typePtr == &tclIntType) {
  2051. wResult = Tcl_LongAsWide(valuePtr->internalRep.longValue);
  2052.     } else {
  2053. d = valuePtr->internalRep.doubleValue;
  2054. if (d < 0.0) {
  2055.     if (d < Tcl_WideAsDouble(LLONG_MIN)) {
  2056. tooLarge:
  2057. Tcl_ResetResult(interp);
  2058. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  2059.         "integer value too large to represent", -1);
  2060. Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  2061. "integer value too large to represent", (char *) NULL);
  2062. result = TCL_ERROR;
  2063. goto done;
  2064.     }
  2065. } else {
  2066.     if (d > Tcl_WideAsDouble(LLONG_MAX)) {
  2067. goto tooLarge;
  2068.     }
  2069. }
  2070. if (IS_NAN(d) || IS_INF(d)) {
  2071.     TclExprFloatError(interp, d);
  2072.     result = TCL_ERROR;
  2073.     goto done;
  2074. }
  2075. wResult = Tcl_DoubleAsWide(d);
  2076.     }
  2077.     /*
  2078.      * Push a Tcl object with the result.
  2079.      */
  2080.     
  2081.     PUSH_OBJECT(Tcl_NewWideIntObj(wResult));
  2082.     /*
  2083.      * Reflect the change to stackTop back in eePtr.
  2084.      */
  2085.     done:
  2086.     TclDecrRefCount(valuePtr);
  2087.     DECACHE_STACK_INFO();
  2088.     return result;
  2089. }
  2090. static int
  2091. ExprRandFunc(interp, eePtr, clientData)
  2092.     Tcl_Interp *interp; /* The interpreter in which to execute the
  2093.  * function. */
  2094.     ExecEnv *eePtr; /* Points to the environment for executing
  2095.  * the function. */
  2096.     ClientData clientData; /* Ignored. */
  2097. {
  2098.     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  2099.     register int stackTop; /* Cached top index of evaluation stack. */
  2100.     Interp *iPtr = (Interp *) interp;
  2101.     double dResult;
  2102.     long tmp; /* Algorithm assumes at least 32 bits.
  2103.  * Only long guarantees that.  See below. */
  2104.     if (!(iPtr->flags & RAND_SEED_INITIALIZED)) {
  2105. iPtr->flags |= RAND_SEED_INITIALIZED;
  2106.         
  2107.         /* 
  2108.  * Take into consideration the thread this interp is running in order
  2109.  * to insure different seeds in different threads (bug #416643)
  2110.  */
  2111. iPtr->randSeed = TclpGetClicks() + ((long)Tcl_GetCurrentThread()<<12);
  2112. /*
  2113.  * Make sure 1 <= randSeed <= (2^31) - 2.  See below.
  2114.  */
  2115.         iPtr->randSeed &= (unsigned long) 0x7fffffff;
  2116. if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
  2117.     iPtr->randSeed ^= 123459876;
  2118. }
  2119.     }
  2120.     
  2121.     /*
  2122.      * Set stackPtr and stackTop from eePtr.
  2123.      */
  2124.     
  2125.     CACHE_STACK_INFO();
  2126.     /*
  2127.      * Generate the random number using the linear congruential
  2128.      * generator defined by the following recurrence:
  2129.      * seed = ( IA * seed ) mod IM
  2130.      * where IA is 16807 and IM is (2^31) - 1.  The recurrence maps
  2131.      * a seed in the range [1, IM - 1] to a new seed in that same range.
  2132.      * The recurrence maps IM to 0, and maps 0 back to 0, so those two
  2133.      * values must not be allowed as initial values of seed.
  2134.      *
  2135.      * In order to avoid potential problems with integer overflow, the
  2136.      * recurrence is implemented in terms of additional constants
  2137.      * IQ and IR such that
  2138.      * IM = IA*IQ + IR
  2139.      * None of the operations in the implementation overflows a 32-bit
  2140.      * signed integer, and the C type long is guaranteed to be at least
  2141.      * 32 bits wide.
  2142.      *
  2143.      * For more details on how this algorithm works, refer to the following
  2144.      * papers: 
  2145.      *
  2146.      * S.K. Park & K.W. Miller, "Random number generators: good ones
  2147.      * are hard to find," Comm ACM 31(10):1192-1201, Oct 1988
  2148.      *
  2149.      * W.H. Press & S.A. Teukolsky, "Portable random number
  2150.      * generators," Computers in Physics 6(5):522-524, Sep/Oct 1992.
  2151.      */
  2152. #define RAND_IA 16807
  2153. #define RAND_IM 2147483647
  2154. #define RAND_IQ 127773
  2155. #define RAND_IR 2836
  2156. #define RAND_MASK 123459876
  2157.     tmp = iPtr->randSeed/RAND_IQ;
  2158.     iPtr->randSeed = RAND_IA*(iPtr->randSeed - tmp*RAND_IQ) - RAND_IR*tmp;
  2159.     if (iPtr->randSeed < 0) {
  2160. iPtr->randSeed += RAND_IM;
  2161.     }
  2162.     /*
  2163.      * Since the recurrence keeps seed values in the range [1, RAND_IM - 1],
  2164.      * dividing by RAND_IM yields a double in the range (0, 1).
  2165.      */
  2166.     dResult = iPtr->randSeed * (1.0/RAND_IM);
  2167.     /*
  2168.      * Push a Tcl object with the result.
  2169.      */
  2170.     PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  2171.     
  2172.     /*
  2173.      * Reflect the change to stackTop back in eePtr.
  2174.      */
  2175.     DECACHE_STACK_INFO();
  2176.     return TCL_OK;
  2177. }
  2178. static int
  2179. ExprRoundFunc(interp, eePtr, clientData)
  2180.     Tcl_Interp *interp; /* The interpreter in which to execute the
  2181.  * function. */
  2182.     ExecEnv *eePtr; /* Points to the environment for executing
  2183.  * the function. */
  2184.     ClientData clientData; /* Ignored. */
  2185. {
  2186.     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  2187.     register int stackTop; /* Cached top index of evaluation stack. */
  2188.     Tcl_Obj *valuePtr, *resPtr;
  2189.     double d, f, i;
  2190.     int result;
  2191.     /*
  2192.      * Set stackPtr and stackTop from eePtr.
  2193.      */
  2194.     result = TCL_OK;
  2195.     CACHE_STACK_INFO();
  2196.     /*
  2197.      * Pop the argument from the evaluation stack.
  2198.      */
  2199.     valuePtr = POP_OBJECT();
  2200.     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  2201. result = TCL_ERROR;
  2202. goto done;
  2203.     }
  2204.     if ((valuePtr->typePtr == &tclIntType) ||
  2205.     (valuePtr->typePtr == &tclWideIntType)) {
  2206. result = TCL_OK;
  2207. resPtr = valuePtr;
  2208.     } else {
  2209. /* 
  2210.  * Round the number to the nearest integer.  I'd like to use round(),
  2211.  * but it's C99 (or BSD), and not yet universal.
  2212.  */
  2213. d = valuePtr->internalRep.doubleValue;
  2214. f = modf(d, &i);
  2215. if (d < 0.0) {
  2216.     if (f <= -0.5) {
  2217. i += -1.0;
  2218.     }
  2219.     if (i <= Tcl_WideAsDouble(LLONG_MIN)) {
  2220. goto tooLarge;
  2221.     } else if (i <= (double) LONG_MIN) {
  2222. resPtr = Tcl_NewWideIntObj(Tcl_DoubleAsWide(i));
  2223.     } else {
  2224. resPtr = Tcl_NewLongObj((long) i);
  2225.     }     
  2226. } else {
  2227.     if (f >= 0.5) {
  2228. i += 1.0;
  2229.     }
  2230.     if (i >= Tcl_WideAsDouble(LLONG_MAX)) {
  2231. goto tooLarge;
  2232.     } else if (i >= (double) LONG_MAX) {
  2233. resPtr = Tcl_NewWideIntObj(Tcl_DoubleAsWide(i));
  2234.     } else {
  2235. resPtr = Tcl_NewLongObj((long) i);
  2236.     }
  2237. }
  2238.     }
  2239.     /*
  2240.      * Push the result object and free the argument Tcl_Obj.
  2241.      */
  2242.     PUSH_OBJECT(resPtr);
  2243.     
  2244.     done:
  2245.     TclDecrRefCount(valuePtr);
  2246.     DECACHE_STACK_INFO();
  2247.     return result;
  2248.     /*
  2249.      * Error return: result cannot be represented as an integer.
  2250.      */
  2251.     
  2252.     tooLarge:
  2253.     Tcl_ResetResult(interp);
  2254.     Tcl_AppendToObj(Tcl_GetObjResult(interp),
  2255.     "integer value too large to represent", -1);
  2256.     Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  2257.     "integer value too large to represent",
  2258.     (char *) NULL);
  2259.     result = TCL_ERROR;
  2260.     goto done;
  2261. }
  2262. static int
  2263. ExprSrandFunc(interp, eePtr, clientData)
  2264.     Tcl_Interp *interp; /* The interpreter in which to execute the
  2265.  * function. */
  2266.     ExecEnv *eePtr; /* Points to the environment for executing
  2267.  * the function. */
  2268.     ClientData clientData; /* Ignored. */
  2269. {
  2270.     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  2271.     register int stackTop; /* Cached top index of evaluation stack. */
  2272.     Interp *iPtr = (Interp *) interp;
  2273.     Tcl_Obj *valuePtr;
  2274.     long i = 0; /* Initialized to avoid compiler warning. */
  2275.     /*
  2276.      * Set stackPtr and stackTop from eePtr.
  2277.      */
  2278.     
  2279.     CACHE_STACK_INFO();
  2280.     /*
  2281.      * Pop the argument from the evaluation stack.  Use the value
  2282.      * to reset the random number seed.
  2283.      */
  2284.     valuePtr = POP_OBJECT();
  2285.     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  2286. goto badValue;
  2287.     }
  2288.     if (Tcl_GetLongFromObj(NULL, valuePtr, &i) != TCL_OK) {
  2289. Tcl_WideInt w;
  2290. if (Tcl_GetWideIntFromObj(interp, valuePtr, &w) != TCL_OK) {
  2291. badValue:
  2292.     Tcl_AddErrorInfo(interp, "n    (argument to "srand()")");
  2293.     TclDecrRefCount(valuePtr);
  2294.     DECACHE_STACK_INFO();
  2295.     return TCL_ERROR;
  2296. }
  2297. i = Tcl_WideAsLong(w);
  2298.     }
  2299.     
  2300.     /*
  2301.      * Reset the seed.  Make sure 1 <= randSeed <= 2^31 - 2.
  2302.      * See comments in ExprRandFunc() for more details.
  2303.      */
  2304.     iPtr->flags |= RAND_SEED_INITIALIZED;
  2305.     iPtr->randSeed = i;
  2306.     iPtr->randSeed &= (unsigned long) 0x7fffffff;
  2307.     if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
  2308. iPtr->randSeed ^= 123459876;
  2309.     }
  2310.     /*
  2311.      * To avoid duplicating the random number generation code we simply
  2312.      * clean up our state and call the real random number function. That
  2313.      * function will always succeed.
  2314.      */
  2315.     
  2316.     TclDecrRefCount(valuePtr);
  2317.     DECACHE_STACK_INFO();
  2318.     ExprRandFunc(interp, eePtr, clientData);
  2319.     return TCL_OK;
  2320. }
  2321. /*
  2322.  *----------------------------------------------------------------------
  2323.  *
  2324.  * ExprCallMathFunc --
  2325.  *
  2326.  * This procedure is invoked to call a non-builtin math function
  2327.  * during the execution of an expression. 
  2328.  *
  2329.  * Results:
  2330.  * TCL_OK is returned if all went well and the function's value
  2331.  * was computed successfully. If an error occurred, TCL_ERROR
  2332.  * is returned and an error message is left in the interpreter's
  2333.  * result. After a successful return this procedure pushes a Tcl object
  2334.  * holding the result. 
  2335.  *
  2336.  * Side effects:
  2337.  * None, unless the called math function has side effects.
  2338.  *
  2339.  *----------------------------------------------------------------------
  2340.  */
  2341. static int
  2342. ExprCallMathFunc(interp, eePtr, objc, objv)
  2343.     Tcl_Interp *interp; /* The interpreter in which to execute the
  2344.  * function. */
  2345.     ExecEnv *eePtr; /* Points to the environment for executing
  2346.  * the function. */
  2347.     int objc; /* Number of arguments. The function name is
  2348.  * the 0-th argument. */
  2349.     Tcl_Obj **objv; /* The array of arguments. The function name
  2350.  * is objv[0]. */
  2351. {
  2352.     Interp *iPtr = (Interp *) interp;
  2353.     Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */
  2354.     register int stackTop; /* Cached top index of evaluation stack. */
  2355.     char *funcName;
  2356.     Tcl_HashEntry *hPtr;
  2357.     MathFunc *mathFuncPtr; /* Information about math function. */
  2358.     Tcl_Value args[MAX_MATH_ARGS]; /* Arguments for function call. */
  2359.     Tcl_Value funcResult; /* Result of function call as Tcl_Value. */
  2360.     register Tcl_Obj *valuePtr;
  2361.     long i;
  2362.     double d;
  2363.     int j, k, result;
  2364.     Tcl_ResetResult(interp);
  2365.     /*
  2366.      * Set stackPtr and stackTop from eePtr.
  2367.      */
  2368.     
  2369.     CACHE_STACK_INFO();
  2370.     /*
  2371.      * Look up the MathFunc record for the function.
  2372.      */
  2373.     funcName = TclGetString(objv[0]);
  2374.     hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcName);
  2375.     if (hPtr == NULL) {
  2376. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  2377. "unknown math function "", funcName, """, (char *) NULL);
  2378. result = TCL_ERROR;
  2379. goto done;
  2380.     }
  2381.     mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
  2382.     if (mathFuncPtr->numArgs != (objc-1)) {
  2383. panic("ExprCallMathFunc: expected number of args %d != actual number %d",
  2384.         mathFuncPtr->numArgs, objc);
  2385. result = TCL_ERROR;
  2386. goto done;
  2387.     }
  2388.     /*
  2389.      * Collect the arguments for the function, if there are any, into the
  2390.      * array "args". Note that args[0] will have the Tcl_Value that
  2391.      * corresponds to objv[1].
  2392.      */
  2393.     for (j = 1, k = 0;  j < objc;  j++, k++) {
  2394. valuePtr = objv[j];
  2395. if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  2396.     result = TCL_ERROR;
  2397.     goto done;
  2398. }
  2399. /*
  2400.  * Copy the object's numeric value to the argument record,
  2401.  * converting it if necessary. 
  2402.  */
  2403. if (valuePtr->typePtr == &tclIntType) {
  2404.     i = valuePtr->internalRep.longValue;
  2405.     if (mathFuncPtr->argTypes[k] == TCL_DOUBLE) {
  2406. args[k].type = TCL_DOUBLE;
  2407. args[k].doubleValue = i;
  2408.     } else if (mathFuncPtr->argTypes[k] == TCL_WIDE_INT) {
  2409. args[k].type = TCL_WIDE_INT;
  2410. args[k].wideValue = Tcl_LongAsWide(i);
  2411.     } else {
  2412. args[k].type = TCL_INT;
  2413. args[k].intValue = i;
  2414.     }
  2415. } else if (valuePtr->typePtr == &tclWideIntType) {
  2416.     Tcl_WideInt w;
  2417.     TclGetWide(w,valuePtr);
  2418.     if (mathFuncPtr->argTypes[k] == TCL_DOUBLE) {
  2419. args[k].type = TCL_DOUBLE;
  2420. args[k].doubleValue = Tcl_WideAsDouble(w);
  2421.     } else if (mathFuncPtr->argTypes[k] == TCL_INT) {
  2422. args[k].type = TCL_INT;
  2423. args[k].intValue = Tcl_WideAsLong(w);
  2424.     } else {
  2425. args[k].type = TCL_WIDE_INT;
  2426. args[k].wideValue = w;
  2427.     }
  2428. } else {
  2429.     d = valuePtr->internalRep.doubleValue;
  2430.     if (mathFuncPtr->argTypes[k] == TCL_INT) {
  2431. args[k].type = TCL_INT;
  2432. args[k].intValue = (long) d;
  2433.     } else if (mathFuncPtr->argTypes[k] == TCL_WIDE_INT) {
  2434. args[k].type = TCL_WIDE_INT;
  2435. args[k].wideValue = Tcl_DoubleAsWide(d);
  2436.     } else {
  2437. args[k].type = TCL_DOUBLE;
  2438. args[k].doubleValue = d;
  2439.     }
  2440. }
  2441.     }
  2442.     /*
  2443.      * Invoke the function and copy its result back into valuePtr.
  2444.      */
  2445.     result = (*mathFuncPtr->proc)(mathFuncPtr->clientData, interp, args,
  2446.     &funcResult);
  2447.     if (result != TCL_OK) {
  2448. goto done;
  2449.     }
  2450.     /*
  2451.      * Pop the objc top stack elements and decrement their ref counts.
  2452.      */
  2453.     k = (stackTop - (objc-1));
  2454.     while (stackTop >= k) {
  2455. valuePtr = POP_OBJECT();
  2456. TclDecrRefCount(valuePtr);
  2457.     }
  2458.     
  2459.     /*
  2460.      * Push the call's object result.
  2461.      */
  2462.     
  2463.     if (funcResult.type == TCL_INT) {
  2464. PUSH_OBJECT(Tcl_NewLongObj(funcResult.intValue));
  2465.     } else if (funcResult.type == TCL_WIDE_INT) {
  2466. PUSH_OBJECT(Tcl_NewWideIntObj(funcResult.wideValue));
  2467.     } else {
  2468. d = funcResult.doubleValue;
  2469. if (IS_NAN(d) || IS_INF(d)) {
  2470.     TclExprFloatError(interp, d);
  2471.     result = TCL_ERROR;
  2472.     goto done;
  2473. }
  2474. PUSH_OBJECT(Tcl_NewDoubleObj(d));
  2475.     }
  2476.     /*
  2477.      * Reflect the change to stackTop back in eePtr.
  2478.      */
  2479.     done:
  2480.     DECACHE_STACK_INFO();
  2481.     return result;
  2482. }
  2483. /*
  2484.  *----------------------------------------------------------------------
  2485.  *
  2486.  * TclExprFloatError --
  2487.  *
  2488.  * This procedure is called when an error occurs during a
  2489.  * floating-point operation. It reads errno and sets
  2490.  * interp->objResultPtr accordingly.
  2491.  *
  2492.  * Results:
  2493.  * interp->objResultPtr is set to hold an error message.
  2494.  *
  2495.  * Side effects:
  2496.  * None.
  2497.  *
  2498.  *----------------------------------------------------------------------
  2499.  */
  2500. void
  2501. TclExprFloatError(interp, value)
  2502.     Tcl_Interp *interp; /* Where to store error message. */
  2503.     double value; /* Value returned after error;  used to
  2504.  * distinguish underflows from overflows. */
  2505. {
  2506.     char *s;
  2507.     Tcl_ResetResult(interp);
  2508.     if ((errno == EDOM) || IS_NAN(value)) {
  2509. s = "domain error: argument not in valid range";
  2510. Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
  2511. Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", s, (char *) NULL);
  2512.     } else if ((errno == ERANGE) || IS_INF(value)) {
  2513. if (value == 0.0) {
  2514.     s = "floating-point value too small to represent";
  2515.     Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
  2516.     Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", s, (char *) NULL);
  2517. } else {
  2518.     s = "floating-point value too large to represent";
  2519.     Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
  2520.     Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", s, (char *) NULL);
  2521. }
  2522.     } else {
  2523. char msg[64 + TCL_INTEGER_SPACE];
  2524. sprintf(msg, "unknown floating-point error, errno = %d", errno);
  2525. Tcl_AppendToObj(Tcl_GetObjResult(interp), msg, -1);
  2526. Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN", msg, (char *) NULL);
  2527.     }
  2528. }
  2529. #ifdef TCL_COMPILE_STATS
  2530. /*
  2531.  *----------------------------------------------------------------------
  2532.  *
  2533.  * TclLog2 --
  2534.  *
  2535.  * Procedure used while collecting compilation statistics to determine
  2536.  * the log base 2 of an integer.
  2537.  *
  2538.  * Results:
  2539.  * Returns the log base 2 of the operand. If the argument is less
  2540.  * than or equal to zero, a zero is returned.
  2541.  *
  2542.  * Side effects:
  2543.  * None.
  2544.  *
  2545.  *----------------------------------------------------------------------
  2546.  */
  2547. int
  2548. TclLog2(value)
  2549.     register int value; /* The integer for which to compute the
  2550.  * log base 2. */
  2551. {
  2552.     register int n = value;
  2553.     register int result = 0;
  2554.     while (n > 1) {
  2555. n = n >> 1;
  2556. result++;
  2557.     }
  2558.     return result;
  2559. }
  2560. /*
  2561.  *----------------------------------------------------------------------
  2562.  *
  2563.  * EvalStatsCmd --
  2564.  *
  2565.  * Implements the "evalstats" command that prints instruction execution
  2566.  * counts to stdout.
  2567.  *
  2568.  * Results:
  2569.  * Standard Tcl results.
  2570.  *
  2571.  * Side effects:
  2572.  * None.
  2573.  *
  2574.  *----------------------------------------------------------------------
  2575.  */
  2576. static int
  2577. EvalStatsCmd(unused, interp, objc, objv)
  2578.     ClientData unused; /* Unused. */
  2579.     Tcl_Interp *interp; /* The current interpreter. */
  2580.     int objc; /* The number of arguments. */
  2581.     Tcl_Obj *CONST objv[]; /* The argument strings. */
  2582. {
  2583.     Interp *iPtr = (Interp *) interp;
  2584.     LiteralTable *globalTablePtr = &(iPtr->literalTable);
  2585.     ByteCodeStats *statsPtr = &(iPtr->stats);
  2586.     double totalCodeBytes, currentCodeBytes;
  2587.     double totalLiteralBytes, currentLiteralBytes;
  2588.     double objBytesIfUnshared, strBytesIfUnshared, sharingBytesSaved;
  2589.     double strBytesSharedMultX, strBytesSharedOnce;
  2590.     double numInstructions, currentHeaderBytes;
  2591.     long numCurrentByteCodes, numByteCodeLits;
  2592.     long refCountSum, literalMgmtBytes, sum;
  2593.     int numSharedMultX, numSharedOnce;
  2594.     int decadeHigh, minSizeDecade, maxSizeDecade, length, i;
  2595.     char *litTableStats;
  2596.     LiteralEntry *entryPtr;
  2597.     numInstructions = 0.0;
  2598.     for (i = 0;  i < 256;  i++) {
  2599.         if (statsPtr->instructionCount[i] != 0) {
  2600.             numInstructions += statsPtr->instructionCount[i];
  2601.         }
  2602.     }
  2603.     totalLiteralBytes = sizeof(LiteralTable)
  2604.     + iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)
  2605.     + (statsPtr->numLiteralsCreated * sizeof(LiteralEntry))
  2606.     + (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj))
  2607.     + statsPtr->totalLitStringBytes;
  2608.     totalCodeBytes = statsPtr->totalByteCodeBytes + totalLiteralBytes;
  2609.     numCurrentByteCodes =
  2610.     statsPtr->numCompilations - statsPtr->numByteCodesFreed;
  2611.     currentHeaderBytes = numCurrentByteCodes
  2612.     * (sizeof(ByteCode) - (sizeof(size_t) + sizeof(Tcl_Time)));
  2613.     literalMgmtBytes = sizeof(LiteralTable)
  2614.     + (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *))
  2615.     + (iPtr->literalTable.numEntries * sizeof(LiteralEntry));
  2616.     currentLiteralBytes = literalMgmtBytes
  2617.     + iPtr->literalTable.numEntries * sizeof(Tcl_Obj)
  2618.     + statsPtr->currentLitStringBytes;
  2619.     currentCodeBytes = statsPtr->currentByteCodeBytes + currentLiteralBytes;
  2620.     
  2621.     /*
  2622.      * Summary statistics, total and current source and ByteCode sizes.
  2623.      */
  2624.     fprintf(stdout, "n----------------------------------------------------------------n");
  2625.     fprintf(stdout,
  2626.     "Compilation and execution statistics for interpreter 0x%xn",
  2627.     (unsigned int) iPtr);
  2628.     fprintf(stdout, "nNumber ByteCodes executed %ldn",
  2629.     statsPtr->numExecutions);
  2630.     fprintf(stdout, "Number ByteCodes compiled %ldn",
  2631.     statsPtr->numCompilations);
  2632.     fprintf(stdout, "  Mean executions/compile %.1fn",
  2633.     ((float)statsPtr->numExecutions) / ((float)statsPtr->numCompilations));
  2634.     
  2635.     fprintf(stdout, "nInstructions executed %.0fn",
  2636.     numInstructions);
  2637.     fprintf(stdout, "  Mean inst/compile %.0fn",
  2638.     numInstructions / statsPtr->numCompilations);
  2639.     fprintf(stdout, "  Mean inst/execution %.0fn",
  2640.     numInstructions / statsPtr->numExecutions);
  2641.     fprintf(stdout, "nTotal ByteCodes %ldn",
  2642.     statsPtr->numCompilations);
  2643.     fprintf(stdout, "  Source bytes %.6gn",
  2644.     statsPtr->totalSrcBytes);
  2645.     fprintf(stdout, "  Code bytes %.6gn",
  2646.     totalCodeBytes);
  2647.     fprintf(stdout, "    ByteCode bytes %.6gn",
  2648.     statsPtr->totalByteCodeBytes);
  2649.     fprintf(stdout, "    Literal bytes %.6gn",
  2650.     totalLiteralBytes);
  2651.     fprintf(stdout, "      table %d + bkts %d + entries %ld + objects %ld + strings %.6gn",
  2652.     sizeof(LiteralTable),
  2653.     iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
  2654.     statsPtr->numLiteralsCreated * sizeof(LiteralEntry),
  2655.     statsPtr->numLiteralsCreated * sizeof(Tcl_Obj),
  2656.     statsPtr->totalLitStringBytes);
  2657.     fprintf(stdout, "  Mean code/compile %.1fn",
  2658.     totalCodeBytes / statsPtr->numCompilations);
  2659.     fprintf(stdout, "  Mean code/source %.1fn",
  2660.     totalCodeBytes / statsPtr->totalSrcBytes);
  2661.     fprintf(stdout, "nCurrent (active) ByteCodes %ldn",
  2662.     numCurrentByteCodes);
  2663.     fprintf(stdout, "  Source bytes %.6gn",
  2664.     statsPtr->currentSrcBytes);
  2665.     fprintf(stdout, "  Code bytes %.6gn",
  2666.     currentCodeBytes);
  2667.     fprintf(stdout, "    ByteCode bytes %.6gn",
  2668.     statsPtr->currentByteCodeBytes);
  2669.     fprintf(stdout, "    Literal bytes %.6gn",
  2670.     currentLiteralBytes);
  2671.     fprintf(stdout, "      table %d + bkts %d + entries %d + objects %d + strings %.6gn",
  2672.     sizeof(LiteralTable),
  2673.     iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
  2674.     iPtr->literalTable.numEntries * sizeof(LiteralEntry),
  2675.     iPtr->literalTable.numEntries * sizeof(Tcl_Obj),
  2676.     statsPtr->currentLitStringBytes);
  2677.     fprintf(stdout, "  Mean code/source %.1fn",
  2678.     currentCodeBytes / statsPtr->currentSrcBytes);
  2679.     fprintf(stdout, "  Code + source bytes %.6g (%0.1f mean code/src)n",
  2680.     (currentCodeBytes + statsPtr->currentSrcBytes),
  2681.     (currentCodeBytes / statsPtr->currentSrcBytes) + 1.0);
  2682.     /*
  2683.      * Tcl_IsShared statistics check
  2684.      *
  2685.      * This gives the refcount of each obj as Tcl_IsShared was called
  2686.      * for it.  Shared objects must be duplicated before they can be
  2687.      * modified.
  2688.      */
  2689.     numSharedMultX = 0;
  2690.     fprintf(stdout, "nTcl_IsShared object check (all objects):n");
  2691.     fprintf(stdout, "  Object had refcount <=1 (not shared) %ldn",
  2692.     tclObjsShared[1]);
  2693.     for (i = 2;  i < TCL_MAX_SHARED_OBJ_STATS;  i++) {
  2694. fprintf(stdout, "  refcount ==%d %ldn",
  2695. i, tclObjsShared[i]);
  2696. numSharedMultX += tclObjsShared[i];
  2697.     }
  2698.     fprintf(stdout, "  refcount >=%d %ldn",
  2699.     i, tclObjsShared[0]);
  2700.     numSharedMultX += tclObjsShared[0];
  2701.     fprintf(stdout, "  Total shared objects %dn",
  2702.     numSharedMultX);
  2703.     /*
  2704.      * Literal table statistics.
  2705.      */
  2706.     numByteCodeLits = 0;
  2707.     refCountSum = 0;
  2708.     numSharedMultX = 0;
  2709.     numSharedOnce  = 0;
  2710.     objBytesIfUnshared  = 0.0;
  2711.     strBytesIfUnshared  = 0.0;
  2712.     strBytesSharedMultX = 0.0;
  2713.     strBytesSharedOnce  = 0.0;
  2714.     for (i = 0;  i < globalTablePtr->numBuckets;  i++) {
  2715. for (entryPtr = globalTablePtr->buckets[i];  entryPtr != NULL;
  2716.         entryPtr = entryPtr->nextPtr) {
  2717.     if (entryPtr->objPtr->typePtr == &tclByteCodeType) {
  2718. numByteCodeLits++;
  2719.     }
  2720.     (void) Tcl_GetStringFromObj(entryPtr->objPtr, &length);
  2721.     refCountSum += entryPtr->refCount;
  2722.     objBytesIfUnshared += (entryPtr->refCount * sizeof(Tcl_Obj));
  2723.     strBytesIfUnshared += (entryPtr->refCount * (length+1));
  2724.     if (entryPtr->refCount > 1) {
  2725. numSharedMultX++;
  2726. strBytesSharedMultX += (length+1);
  2727.     } else {
  2728. numSharedOnce++;
  2729. strBytesSharedOnce += (length+1);
  2730.     }
  2731. }
  2732.     }
  2733.     sharingBytesSaved = (objBytesIfUnshared + strBytesIfUnshared)
  2734.     - currentLiteralBytes;
  2735.     fprintf(stdout, "nTotal objects (all interps) %ldn",
  2736.     tclObjsAlloced);
  2737.     fprintf(stdout, "Current objects %ldn",
  2738.     (tclObjsAlloced - tclObjsFreed));
  2739.     fprintf(stdout, "Total literal objects %ldn",
  2740.     statsPtr->numLiteralsCreated);
  2741.     fprintf(stdout, "nCurrent literal objects %d (%0.1f%% of current objects)n",
  2742.     globalTablePtr->numEntries,
  2743.     (globalTablePtr->numEntries * 100.0) / (tclObjsAlloced-tclObjsFreed));
  2744.     fprintf(stdout, "  ByteCode literals   %ld (%0.1f%% of current literals)n",
  2745.     numByteCodeLits,
  2746.     (numByteCodeLits * 100.0) / globalTablePtr->numEntries);
  2747.     fprintf(stdout, "  Literals reused > 1x   %dn",
  2748.     numSharedMultX);
  2749.     fprintf(stdout, "  Mean reference count   %.2fn",
  2750.     ((double) refCountSum) / globalTablePtr->numEntries);
  2751.     fprintf(stdout, "  Mean len, str reused >1x  %.2fn",
  2752.     (numSharedMultX? (strBytesSharedMultX/numSharedMultX) : 0.0));
  2753.     fprintf(stdout, "  Mean len, str used 1x   %.2fn",
  2754.     (numSharedOnce? (strBytesSharedOnce/numSharedOnce) : 0.0));
  2755.     fprintf(stdout, "  Total sharing savings   %.6g (%0.1f%% of bytes if no sharing)n",
  2756.     sharingBytesSaved,
  2757.     (sharingBytesSaved * 100.0) / (objBytesIfUnshared + strBytesIfUnshared));
  2758.     fprintf(stdout, "    Bytes with sharing %.6gn",
  2759.     currentLiteralBytes);
  2760.     fprintf(stdout, "      table %d + bkts %d + entries %d + objects %d + strings %.6gn",
  2761.     sizeof(LiteralTable),
  2762.     iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
  2763.     iPtr->literalTable.numEntries * sizeof(LiteralEntry),
  2764.     iPtr->literalTable.numEntries * sizeof(Tcl_Obj),
  2765.     statsPtr->currentLitStringBytes);
  2766.     fprintf(stdout, "    Bytes if no sharing %.6g = objects %.6g + strings %.6gn",
  2767.     (objBytesIfUnshared + strBytesIfUnshared),
  2768.     objBytesIfUnshared, strBytesIfUnshared);
  2769.     fprintf(stdout, "  String sharing savings  %.6g = unshared %.6g - shared %.6gn",
  2770.     (strBytesIfUnshared - statsPtr->currentLitStringBytes),
  2771.     strBytesIfUnshared, statsPtr->currentLitStringBytes);
  2772.     fprintf(stdout, "  Literal mgmt overhead   %ld (%0.1f%% of bytes with sharing)n",
  2773.     literalMgmtBytes,
  2774.     (literalMgmtBytes * 100.0) / currentLiteralBytes);
  2775.     fprintf(stdout, "    table %d + buckets %d + entries %dn",
  2776.     sizeof(LiteralTable),
  2777.     iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
  2778.     iPtr->literalTable.numEntries * sizeof(LiteralEntry));
  2779.     /*
  2780.      * Breakdown of current ByteCode space requirements.
  2781.      */
  2782.     
  2783.     fprintf(stdout, "nBreakdown of current ByteCode requirements:n");
  2784.     fprintf(stdout, "                         Bytes      Pct of    Avg pern");
  2785.     fprintf(stdout, "                                     total    ByteCoden");
  2786.     fprintf(stdout, "Total             %12.6g     100.00%%   %8.1fn",
  2787.     statsPtr->currentByteCodeBytes,
  2788.     statsPtr->currentByteCodeBytes / numCurrentByteCodes);
  2789.     fprintf(stdout, "Header            %12.6g   %8.1f%%   %8.1fn",
  2790.     currentHeaderBytes,
  2791.     ((currentHeaderBytes * 100.0) / statsPtr->currentByteCodeBytes),
  2792.     currentHeaderBytes / numCurrentByteCodes);
  2793.     fprintf(stdout, "Instructions      %12.6g   %8.1f%%   %8.1fn",
  2794.     statsPtr->currentInstBytes,
  2795.     ((statsPtr->currentInstBytes * 100.0) / statsPtr->currentByteCodeBytes),
  2796.     statsPtr->currentInstBytes / numCurrentByteCodes);
  2797.     fprintf(stdout, "Literal ptr array %12.6g   %8.1f%%   %8.1fn",
  2798.     statsPtr->currentLitBytes,
  2799.     ((statsPtr->currentLitBytes * 100.0) / statsPtr->currentByteCodeBytes),
  2800.     statsPtr->currentLitBytes / numCurrentByteCodes);
  2801.     fprintf(stdout, "Exception table   %12.6g   %8.1f%%   %8.1fn",
  2802.     statsPtr->currentExceptBytes,
  2803.     ((statsPtr->currentExceptBytes * 100.0) / statsPtr->currentByteCodeBytes),
  2804.     statsPtr->currentExceptBytes / numCurrentByteCodes);
  2805.     fprintf(stdout, "Auxiliary data    %12.6g   %8.1f%%   %8.1fn",
  2806.     statsPtr->currentAuxBytes,
  2807.     ((statsPtr->currentAuxBytes * 100.0) / statsPtr->currentByteCodeBytes),
  2808.     statsPtr->currentAuxBytes / numCurrentByteCodes);
  2809.     fprintf(stdout, "Command map       %12.6g   %8.1f%%   %8.1fn",
  2810.     statsPtr->currentCmdMapBytes,
  2811.     ((statsPtr->currentCmdMapBytes * 100.0) / statsPtr->currentByteCodeBytes),
  2812.     statsPtr->currentCmdMapBytes / numCurrentByteCodes);
  2813.     /*
  2814.      * Detailed literal statistics.
  2815.      */
  2816.     
  2817.     fprintf(stdout, "nLiteral string sizes:n");
  2818.     fprintf(stdout, "  Up to length Percentagen");
  2819.     maxSizeDecade = 0;
  2820.     for (i = 31;  i >= 0;  i--) {
  2821.         if (statsPtr->literalCount[i] > 0) {
  2822.             maxSizeDecade = i;
  2823.     break;
  2824.         }
  2825.     }
  2826.     sum = 0;
  2827.     for (i = 0;  i <= maxSizeDecade;  i++) {
  2828. decadeHigh = (1 << (i+1)) - 1;
  2829. sum += statsPtr->literalCount[i];
  2830.         fprintf(stdout, " %10d %8.0f%%n",
  2831. decadeHigh, (sum * 100.0) / statsPtr->numLiteralsCreated);
  2832.     }
  2833.     litTableStats = TclLiteralStats(globalTablePtr);
  2834.     fprintf(stdout, "nCurrent literal table statistics:n%sn",
  2835.             litTableStats);
  2836.     ckfree((char *) litTableStats);
  2837.     /*
  2838.      * Source and ByteCode size distributions.
  2839.      */
  2840.     fprintf(stdout, "nSource sizes:n");
  2841.     fprintf(stdout, "  Up to size Percentagen");
  2842.     minSizeDecade = maxSizeDecade = 0;
  2843.     for (i = 0;  i < 31;  i++) {
  2844.         if (statsPtr->srcCount[i] > 0) {
  2845.     minSizeDecade = i;
  2846.     break;
  2847.         }
  2848.     }
  2849.     for (i = 31;  i >= 0;  i--) {
  2850.         if (statsPtr->srcCount[i] > 0) {
  2851.             maxSizeDecade = i;
  2852.     break;
  2853.         }
  2854.     }
  2855.     sum = 0;
  2856.     for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
  2857. decadeHigh = (1 << (i+1)) - 1;
  2858. sum += statsPtr->srcCount[i];
  2859.         fprintf(stdout, " %10d %8.0f%%n",
  2860. decadeHigh, (sum * 100.0) / statsPtr->numCompilations);
  2861.     }
  2862.     fprintf(stdout, "nByteCode sizes:n");
  2863.     fprintf(stdout, "  Up to size Percentagen");
  2864.     minSizeDecade = maxSizeDecade = 0;
  2865.     for (i = 0;  i < 31;  i++) {
  2866.         if (statsPtr->byteCodeCount[i] > 0) {
  2867.     minSizeDecade = i;
  2868.     break;
  2869.         }
  2870.     }
  2871.     for (i = 31;  i >= 0;  i--) {
  2872.         if (statsPtr->byteCodeCount[i] > 0) {
  2873.             maxSizeDecade = i;
  2874.     break;
  2875.         }
  2876.     }
  2877.     sum = 0;
  2878.     for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
  2879. decadeHigh = (1 << (i+1)) - 1;
  2880. sum += statsPtr->byteCodeCount[i];
  2881.         fprintf(stdout, " %10d %8.0f%%n",
  2882. decadeHigh, (sum * 100.0) / statsPtr->numCompilations);
  2883.     }
  2884.     fprintf(stdout, "nByteCode longevity (excludes Current ByteCodes):n");
  2885.     fprintf(stdout, "        Up to ms Percentagen");
  2886.     minSizeDecade = maxSizeDecade = 0;
  2887.     for (i = 0;  i < 31;  i++) {
  2888.         if (statsPtr->lifetimeCount[i] > 0) {
  2889.     minSizeDecade = i;
  2890.     break;
  2891.         }
  2892.     }
  2893.     for (i = 31;  i >= 0;  i--) {
  2894.         if (statsPtr->lifetimeCount[i] > 0) {
  2895.             maxSizeDecade = i;
  2896.     break;
  2897.         }
  2898.     }
  2899.     sum = 0;
  2900.     for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
  2901. decadeHigh = (1 << (i+1)) - 1;
  2902. sum += statsPtr->lifetimeCount[i];
  2903.         fprintf(stdout, " %12.3f %8.0f%%n",
  2904. decadeHigh / 1000.0,
  2905. (sum * 100.0) / statsPtr->numByteCodesFreed);
  2906.     }
  2907.     /*
  2908.      * Instruction counts.
  2909.      */
  2910.     fprintf(stdout, "nInstruction counts:n");
  2911.     for (i = 0;  i <= LAST_INST_OPCODE;  i++) {
  2912.         if (statsPtr->instructionCount[i]) {
  2913.             fprintf(stdout, "%20s %8ld %6.1f%%n",
  2914.     tclInstructionTable[i].name,
  2915.     statsPtr->instructionCount[i],
  2916.     (statsPtr->instructionCount[i]*100.0) / numInstructions);
  2917.         }
  2918.     }
  2919.     fprintf(stdout, "nInstructions NEVER executed:n");
  2920.     for (i = 0;  i <= LAST_INST_OPCODE;  i++) {
  2921.         if (statsPtr->instructionCount[i] == 0) {
  2922.             fprintf(stdout, "%20sn", tclInstructionTable[i].name);
  2923.         }
  2924.     }
  2925. #ifdef TCL_MEM_DEBUG
  2926.     fprintf(stdout, "nHeap Statistics:n");
  2927.     TclDumpMemoryInfo(stdout);
  2928. #endif
  2929.     fprintf(stdout, "n----------------------------------------------------------------n");
  2930.     return TCL_OK;
  2931. }
  2932. #endif /* TCL_COMPILE_STATS */
  2933. #ifdef TCL_COMPILE_DEBUG
  2934. /*
  2935.  *----------------------------------------------------------------------
  2936.  *
  2937.  * StringForResultCode --
  2938.  *
  2939.  * Procedure that returns a human-readable string representing a
  2940.  * Tcl result code such as TCL_ERROR. 
  2941.  *
  2942.  * Results:
  2943.  * If the result code is one of the standard Tcl return codes, the
  2944.  * result is a string representing that code such as "TCL_ERROR".
  2945.  * Otherwise, the result string is that code formatted as a
  2946.  * sequence of decimal digit characters. Note that the resulting
  2947.  * string must not be modified by the caller.
  2948.  *
  2949.  * Side effects:
  2950.  * None.
  2951.  *
  2952.  *----------------------------------------------------------------------
  2953.  */
  2954. static char *
  2955. StringForResultCode(result)
  2956.     int result; /* The Tcl result code for which to
  2957.  * generate a string. */
  2958. {
  2959.     static char buf[TCL_INTEGER_SPACE];
  2960.     
  2961.     if ((result >= TCL_OK) && (result <= TCL_CONTINUE)) {
  2962. return resultStrings[result];
  2963.     }
  2964.     TclFormatInt(buf, result);
  2965.     return buf;
  2966. }
  2967. #endif /* TCL_COMPILE_DEBUG */
  2968. /*
  2969.  * Local Variables:
  2970.  * mode: c
  2971.  * c-basic-offset: 4
  2972.  * fill-column: 78
  2973.  * End:
  2974.  */