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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclCompCmds.c --
  3.  *
  4.  * This file contains compilation procedures that compile various
  5.  * Tcl commands into a sequence of instructions ("bytecodes"). 
  6.  *
  7.  * Copyright (c) 1997-1998 Sun Microsystems, Inc.
  8.  * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
  9.  * Copyright (c) 2002 ActiveState Corporation.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tclCompCmds.c,v 1.39.2.6 2007/03/01 16:06:19 dkf Exp $
  15.  */
  16. #include "tclInt.h"
  17. #include "tclCompile.h"
  18. /*
  19.  * Prototypes for procedures defined later in this file:
  20.  */
  21. static ClientData DupForeachInfo _ANSI_ARGS_((ClientData clientData));
  22. static void FreeForeachInfo _ANSI_ARGS_((ClientData clientData));
  23. #ifndef TCL_TIP280
  24. static int TclPushVarName _ANSI_ARGS_((Tcl_Interp *interp,
  25. Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags,
  26. int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr));
  27. #else
  28. static int TclPushVarName _ANSI_ARGS_((Tcl_Interp *interp,
  29. Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags,
  30. int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr,
  31. int line));
  32. #endif
  33. /*
  34.  * Flags bits used by TclPushVarName.
  35.  */
  36. #define TCL_CREATE_VAR     1 /* Create a compiled local if none is found */
  37. #define TCL_NO_LARGE_INDEX 2 /* Do not return localIndex value > 255 */
  38. /*
  39.  * The structures below define the AuxData types defined in this file.
  40.  */
  41. AuxDataType tclForeachInfoType = {
  42.     "ForeachInfo", /* name */
  43.     DupForeachInfo, /* dupProc */
  44.     FreeForeachInfo /* freeProc */
  45. };
  46. /*
  47.  *----------------------------------------------------------------------
  48.  *
  49.  * TclCompileAppendCmd --
  50.  *
  51.  * Procedure called to compile the "append" command.
  52.  *
  53.  * Results:
  54.  * The return value is a standard Tcl result, which is normally TCL_OK
  55.  * unless there was an error while parsing string. If an error occurs
  56.  * then the interpreter's result contains a standard error message. If
  57.  * complation fails because the command requires a second level of
  58.  * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the
  59.  * command should be compiled "out of line" by emitting code to
  60.  * invoke its command procedure (Tcl_AppendObjCmd) at runtime.
  61.  *
  62.  * Side effects:
  63.  * Instructions are added to envPtr to execute the "append" command
  64.  * at runtime.
  65.  *
  66.  *----------------------------------------------------------------------
  67.  */
  68. int
  69. TclCompileAppendCmd(interp, parsePtr, envPtr)
  70.     Tcl_Interp *interp; /* Used for error reporting. */
  71.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  72.  * command created by Tcl_ParseCommand. */
  73.     CompileEnv *envPtr; /* Holds resulting instructions. */
  74. {
  75.     Tcl_Token *varTokenPtr, *valueTokenPtr;
  76.     int simpleVarName, isScalar, localIndex, numWords;
  77.     int code = TCL_OK;
  78. #ifdef TCL_TIP280
  79.     /* TIP #280 : Remember the per-word line information of the current
  80.      * command. An index is used instead of a pointer as recursive compilation
  81.      * may reallocate, i.e. move, the array. This is also the reason to save
  82.      * the nuloc now, it may change during the course of the function.
  83.      */
  84.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  85.     int        eclIndex = mapPtr->nuloc - 1;
  86. #endif
  87.     numWords = parsePtr->numWords;
  88.     if (numWords == 1) {
  89. Tcl_ResetResult(interp);
  90. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  91. "wrong # args: should be "append varName ?value value ...?"",
  92. -1);
  93. return TCL_ERROR;
  94.     } else if (numWords == 2) {
  95. /*
  96.  * append varName === set varName
  97.  */
  98.         return TclCompileSetCmd(interp, parsePtr, envPtr);
  99.     } else if (numWords > 3) {
  100. /*
  101.  * APPEND instructions currently only handle one value
  102.  */
  103.         return TCL_OUT_LINE_COMPILE;
  104.     }
  105.     /*
  106.      * Decide if we can use a frame slot for the var/array name or if we
  107.      * need to emit code to compute and push the name at runtime. We use a
  108.      * frame slot (entry in the array of local vars) if we are compiling a
  109.      * procedure body and if the name is simple text that does not include
  110.      * namespace qualifiers. 
  111.      */
  112.     varTokenPtr = parsePtr->tokenPtr
  113.     + (parsePtr->tokenPtr->numComponents + 1);
  114.     code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR,
  115. #ifndef TCL_TIP280
  116.     &localIndex, &simpleVarName, &isScalar);
  117. #else
  118.     &localIndex, &simpleVarName, &isScalar,
  119.     mapPtr->loc [eclIndex].line [1]);
  120. #endif
  121.     if (code != TCL_OK) {
  122. goto done;
  123.     }
  124.     /*
  125.      * We are doing an assignment, otherwise TclCompileSetCmd was called,
  126.      * so push the new value.  This will need to be extended to push a
  127.      * value for each argument.
  128.      */
  129.     if (numWords > 2) {
  130. valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  131. if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  132.     TclEmitPush(TclRegisterNewLiteral(envPtr, 
  133.     valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr);
  134. } else {
  135. #ifdef TCL_TIP280
  136.     envPtr->line = mapPtr->loc [eclIndex].line [2];
  137. #endif
  138.     code = TclCompileTokens(interp, valueTokenPtr+1,
  139.             valueTokenPtr->numComponents, envPtr);
  140.     if (code != TCL_OK) {
  141. goto done;
  142.     }
  143. }
  144.     }
  145.     /*
  146.      * Emit instructions to set/get the variable.
  147.      */
  148.     if (simpleVarName) {
  149. if (isScalar) {
  150.     if (localIndex >= 0) {
  151. if (localIndex <= 255) {
  152.     TclEmitInstInt1(INST_APPEND_SCALAR1, localIndex, envPtr);
  153. } else {
  154.     TclEmitInstInt4(INST_APPEND_SCALAR4, localIndex, envPtr);
  155. }
  156.     } else {
  157. TclEmitOpcode(INST_APPEND_STK, envPtr);
  158.     }
  159. } else {
  160.     if (localIndex >= 0) {
  161. if (localIndex <= 255) {
  162.     TclEmitInstInt1(INST_APPEND_ARRAY1, localIndex, envPtr);
  163. } else {
  164.     TclEmitInstInt4(INST_APPEND_ARRAY4, localIndex, envPtr);
  165. }
  166.     } else {
  167. TclEmitOpcode(INST_APPEND_ARRAY_STK, envPtr);
  168.     }
  169. }
  170.     } else {
  171. TclEmitOpcode(INST_APPEND_STK, envPtr);
  172.     }
  173.     done:
  174.     return code;
  175. }
  176. /*
  177.  *----------------------------------------------------------------------
  178.  *
  179.  * TclCompileBreakCmd --
  180.  *
  181.  * Procedure called to compile the "break" command.
  182.  *
  183.  * Results:
  184.  * The return value is a standard Tcl result, which is TCL_OK unless
  185.  * there was an error during compilation. If an error occurs then
  186.  * the interpreter's result contains a standard error message.
  187.  *
  188.  * Side effects:
  189.  * Instructions are added to envPtr to execute the "break" command
  190.  * at runtime.
  191.  *
  192.  *----------------------------------------------------------------------
  193.  */
  194. int
  195. TclCompileBreakCmd(interp, parsePtr, envPtr)
  196.     Tcl_Interp *interp; /* Used for error reporting. */
  197.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  198.  * command created by Tcl_ParseCommand. */
  199.     CompileEnv *envPtr; /* Holds resulting instructions. */
  200. {
  201.     if (parsePtr->numWords != 1) {
  202. Tcl_ResetResult(interp);
  203. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  204.         "wrong # args: should be "break"", -1);
  205. return TCL_ERROR;
  206.     }
  207.     /*
  208.      * Emit a break instruction.
  209.      */
  210.     TclEmitOpcode(INST_BREAK, envPtr);
  211.     return TCL_OK;
  212. }
  213. /*
  214.  *----------------------------------------------------------------------
  215.  *
  216.  * TclCompileCatchCmd --
  217.  *
  218.  * Procedure called to compile the "catch" command.
  219.  *
  220.  * Results:
  221.  * The return value is a standard Tcl result, which is TCL_OK if
  222.  * compilation was successful. If an error occurs then the
  223.  * interpreter's result contains a standard error message and TCL_ERROR
  224.  * is returned. If the command is too complex for TclCompileCatchCmd,
  225.  * TCL_OUT_LINE_COMPILE is returned indicating that the catch command
  226.  * should be compiled "out of line" by emitting code to invoke its
  227.  * command procedure at runtime.
  228.  *
  229.  * Side effects:
  230.  * Instructions are added to envPtr to execute the "catch" command
  231.  * at runtime.
  232.  *
  233.  *----------------------------------------------------------------------
  234.  */
  235. int
  236. TclCompileCatchCmd(interp, parsePtr, envPtr)
  237.     Tcl_Interp *interp; /* Used for error reporting. */
  238.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  239.  * command created by Tcl_ParseCommand. */
  240.     CompileEnv *envPtr; /* Holds resulting instructions. */
  241. {
  242.     JumpFixup jumpFixup;
  243.     Tcl_Token *cmdTokenPtr, *nameTokenPtr;
  244.     CONST char *name;
  245.     int localIndex, nameChars, range, startOffset, jumpDist;
  246.     int code;
  247.     int savedStackDepth = envPtr->currStackDepth;
  248. #ifdef TCL_TIP280
  249.     /* TIP #280 : Remember the per-word line information of the current
  250.      * command. An index is used instead of a pointer as recursive compilation
  251.      * may reallocate, i.e. move, the array. This is also the reason to save
  252.      * the nuloc now, it may change during the course of the function.
  253.      */
  254.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  255.     int        eclIndex = mapPtr->nuloc - 1;
  256. #endif
  257.     if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) {
  258. Tcl_ResetResult(interp);
  259. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  260.         "wrong # args: should be "catch command ?varName?"", -1);
  261. return TCL_ERROR;
  262.     }
  263.     /*
  264.      * If a variable was specified and the catch command is at global level
  265.      * (not in a procedure), don't compile it inline: the payoff is
  266.      * too small.
  267.      */
  268.     if ((parsePtr->numWords == 3) && (envPtr->procPtr == NULL)) {
  269. return TCL_OUT_LINE_COMPILE;
  270.     }
  271.     /*
  272.      * Make sure the variable name, if any, has no substitutions and just
  273.      * refers to a local scaler.
  274.      */
  275.     localIndex = -1;
  276.     cmdTokenPtr = parsePtr->tokenPtr
  277.     + (parsePtr->tokenPtr->numComponents + 1);
  278.     if (parsePtr->numWords == 3) {
  279. nameTokenPtr = cmdTokenPtr + (cmdTokenPtr->numComponents + 1);
  280. if (nameTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  281.     name = nameTokenPtr[1].start;
  282.     nameChars = nameTokenPtr[1].size;
  283.     if (!TclIsLocalScalar(name, nameChars)) {
  284. return TCL_OUT_LINE_COMPILE;
  285.     }
  286.     localIndex = TclFindCompiledLocal(nameTokenPtr[1].start,
  287.     nameTokenPtr[1].size, /*create*/ 1, 
  288.     /*flags*/ VAR_SCALAR, envPtr->procPtr);
  289. } else {
  290.    return TCL_OUT_LINE_COMPILE;
  291. }
  292.     }
  293.     /*
  294.      * We will compile the catch command. Emit a beginCatch instruction at
  295.      * the start of the catch body: the subcommand it controls.
  296.      */
  297.     
  298.     envPtr->exceptDepth++;
  299.     envPtr->maxExceptDepth =
  300. TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
  301.     range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
  302.     TclEmitInstInt4(INST_BEGIN_CATCH4, range, envPtr);
  303.     /*
  304.      * If the body is a simple word, compile the instructions to
  305.      * eval it. Otherwise, compile instructions to substitute its
  306.      * text without catching, a catch instruction that resets the 
  307.      * stack to what it was before substituting the body, and then 
  308.      * an instruction to eval the body. Care has to be taken to 
  309.      * register the correct startOffset for the catch range so that
  310.      * errors in the substitution are not catched [Bug 219184]
  311.      */
  312. #ifdef TCL_TIP280
  313.     envPtr->line = mapPtr->loc [eclIndex].line [1];
  314. #endif
  315.     if (cmdTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  316. startOffset = (envPtr->codeNext - envPtr->codeStart);
  317. code = TclCompileCmdWord(interp, cmdTokenPtr+1, 1, envPtr);
  318.     } else {
  319. code = TclCompileTokens(interp, cmdTokenPtr+1,
  320.         cmdTokenPtr->numComponents, envPtr);
  321. startOffset = (envPtr->codeNext - envPtr->codeStart);
  322. TclEmitOpcode(INST_EVAL_STK, envPtr);
  323.     }
  324.     envPtr->exceptArrayPtr[range].codeOffset = startOffset;
  325.     if (code != TCL_OK) {
  326. code = TCL_OUT_LINE_COMPILE;
  327. goto done;
  328.     }
  329.     envPtr->exceptArrayPtr[range].numCodeBytes =
  330.     (envPtr->codeNext - envPtr->codeStart) - startOffset;
  331.     
  332.     /*
  333.      * The "no errors" epilogue code: store the body's result into the
  334.      * variable (if any), push "0" (TCL_OK) as the catch's "no error"
  335.      * result, and jump around the "error case" code.
  336.      */
  337.     if (localIndex != -1) {
  338. if (localIndex <= 255) {
  339.     TclEmitInstInt1(INST_STORE_SCALAR1, localIndex, envPtr);
  340. } else {
  341.     TclEmitInstInt4(INST_STORE_SCALAR4, localIndex, envPtr);
  342. }
  343.     }
  344.     TclEmitOpcode(INST_POP, envPtr);
  345.     TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
  346.     TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
  347.     /*
  348.      * The "error case" code: store the body's result into the variable (if
  349.      * any), then push the error result code. The initial PC offset here is
  350.      * the catch's error target.
  351.      */
  352.     envPtr->currStackDepth = savedStackDepth;
  353.     envPtr->exceptArrayPtr[range].catchOffset =
  354.     (envPtr->codeNext - envPtr->codeStart);
  355.     if (localIndex != -1) {
  356. TclEmitOpcode(INST_PUSH_RESULT, envPtr);
  357. if (localIndex <= 255) {
  358.     TclEmitInstInt1(INST_STORE_SCALAR1, localIndex, envPtr);
  359. } else {
  360.     TclEmitInstInt4(INST_STORE_SCALAR4, localIndex, envPtr);
  361. }
  362. TclEmitOpcode(INST_POP, envPtr);
  363.     }
  364.     TclEmitOpcode(INST_PUSH_RETURN_CODE, envPtr);
  365.     /*
  366.      * Update the target of the jump after the "no errors" code, then emit
  367.      * an endCatch instruction at the end of the catch command.
  368.      */
  369.     jumpDist = (envPtr->codeNext - envPtr->codeStart)
  370.     - jumpFixup.codeOffset;
  371.     if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) {
  372. panic("TclCompileCatchCmd: bad jump distance %dn", jumpDist);
  373.     }
  374.     TclEmitOpcode(INST_END_CATCH, envPtr);
  375.     done:
  376.     envPtr->currStackDepth = savedStackDepth + 1;
  377.     envPtr->exceptDepth--;
  378.     return code;
  379. }
  380. /*
  381.  *----------------------------------------------------------------------
  382.  *
  383.  * TclCompileContinueCmd --
  384.  *
  385.  * Procedure called to compile the "continue" command.
  386.  *
  387.  * Results:
  388.  * The return value is a standard Tcl result, which is TCL_OK unless
  389.  * there was an error while parsing string. If an error occurs then
  390.  * the interpreter's result contains a standard error message.
  391.  *
  392.  * Side effects:
  393.  * Instructions are added to envPtr to execute the "continue" command
  394.  * at runtime.
  395.  *
  396.  *----------------------------------------------------------------------
  397.  */
  398. int
  399. TclCompileContinueCmd(interp, parsePtr, envPtr)
  400.     Tcl_Interp *interp; /* Used for error reporting. */
  401.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  402.  * command created by Tcl_ParseCommand. */
  403.     CompileEnv *envPtr; /* Holds resulting instructions. */
  404. {
  405.     /*
  406.      * There should be no argument after the "continue".
  407.      */
  408.     if (parsePtr->numWords != 1) {
  409. Tcl_ResetResult(interp);
  410. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  411.         "wrong # args: should be "continue"", -1);
  412. return TCL_ERROR;
  413.     }
  414.     /*
  415.      * Emit a continue instruction.
  416.      */
  417.     TclEmitOpcode(INST_CONTINUE, envPtr);
  418.     return TCL_OK;
  419. }
  420. /*
  421.  *----------------------------------------------------------------------
  422.  *
  423.  * TclCompileExprCmd --
  424.  *
  425.  * Procedure called to compile the "expr" command.
  426.  *
  427.  * Results:
  428.  * The return value is a standard Tcl result, which is TCL_OK
  429.  * unless there was an error while parsing string. If an error occurs
  430.  * then the interpreter's result contains a standard error message.
  431.  *
  432.  * Side effects:
  433.  * Instructions are added to envPtr to execute the "expr" command
  434.  * at runtime.
  435.  *
  436.  *----------------------------------------------------------------------
  437.  */
  438. int
  439. TclCompileExprCmd(interp, parsePtr, envPtr)
  440.     Tcl_Interp *interp; /* Used for error reporting. */
  441.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  442.  * command created by Tcl_ParseCommand. */
  443.     CompileEnv *envPtr; /* Holds resulting instructions. */
  444. {
  445.     Tcl_Token *firstWordPtr;
  446.     if (parsePtr->numWords == 1) {
  447. Tcl_ResetResult(interp);
  448. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  449.         "wrong # args: should be "expr arg ?arg ...?"", -1);
  450.         return TCL_ERROR;
  451.     }
  452. #ifdef TCL_TIP280
  453.     /* TIP #280 : Use the per-word line information of the current command.
  454.      */
  455.     envPtr->line = envPtr->extCmdMapPtr->loc [envPtr->extCmdMapPtr->nuloc - 1].line [1];
  456. #endif
  457.     firstWordPtr = parsePtr->tokenPtr
  458.     + (parsePtr->tokenPtr->numComponents + 1);
  459.     return TclCompileExprWords(interp, firstWordPtr, (parsePtr->numWords-1),
  460.     envPtr);
  461. }
  462. /*
  463.  *----------------------------------------------------------------------
  464.  *
  465.  * TclCompileForCmd --
  466.  *
  467.  * Procedure called to compile the "for" command.
  468.  *
  469.  * Results:
  470.  * The return value is a standard Tcl result, which is TCL_OK unless
  471.  * there was an error while parsing string. If an error occurs then
  472.  * the interpreter's result contains a standard error message.
  473.  *
  474.  * Side effects:
  475.  * Instructions are added to envPtr to execute the "for" command
  476.  * at runtime.
  477.  *
  478.  *----------------------------------------------------------------------
  479.  */
  480. int
  481. TclCompileForCmd(interp, parsePtr, envPtr)
  482.     Tcl_Interp *interp; /* Used for error reporting. */
  483.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  484.  * command created by Tcl_ParseCommand. */
  485.     CompileEnv *envPtr; /* Holds resulting instructions. */
  486. {
  487.     Tcl_Token *startTokenPtr, *testTokenPtr, *nextTokenPtr, *bodyTokenPtr;
  488.     JumpFixup jumpEvalCondFixup;
  489.     int testCodeOffset, bodyCodeOffset, nextCodeOffset, jumpDist;
  490.     int bodyRange, nextRange, code;
  491.     char buffer[32 + TCL_INTEGER_SPACE];
  492.     int savedStackDepth = envPtr->currStackDepth;
  493. #ifdef TCL_TIP280
  494.     /* TIP #280 : Remember the per-word line information of the current
  495.      * command. An index is used instead of a pointer as recursive compilation
  496.      * may reallocate, i.e. move, the array. This is also the reason to save
  497.      * the nuloc now, it may change during the course of the function.
  498.      */
  499.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  500.     int        eclIndex = mapPtr->nuloc - 1;
  501. #endif
  502.     if (parsePtr->numWords != 5) {
  503. Tcl_ResetResult(interp);
  504. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  505.         "wrong # args: should be "for start test next command"", -1);
  506. return TCL_ERROR;
  507.     }
  508.     /*
  509.      * If the test expression requires substitutions, don't compile the for
  510.      * command inline. E.g., the expression might cause the loop to never
  511.      * execute or execute forever, as in "for {} "$x > 5" {incr x} {}".
  512.      */
  513.     startTokenPtr = parsePtr->tokenPtr
  514.     + (parsePtr->tokenPtr->numComponents + 1);
  515.     testTokenPtr = startTokenPtr + (startTokenPtr->numComponents + 1);
  516.     if (testTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
  517. return TCL_OUT_LINE_COMPILE;
  518.     }
  519.     /*
  520.      * Bail out also if the body or the next expression require substitutions
  521.      * in order to insure correct behaviour [Bug 219166]
  522.      */
  523.     nextTokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1);
  524.     bodyTokenPtr = nextTokenPtr + (nextTokenPtr->numComponents + 1);
  525.     if ((nextTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) 
  526.     || (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)) {
  527. return TCL_OUT_LINE_COMPILE;
  528.     }
  529.     /*
  530.      * Create ExceptionRange records for the body and the "next" command.
  531.      * The "next" command's ExceptionRange supports break but not continue
  532.      * (and has a -1 continueOffset).
  533.      */
  534.     envPtr->exceptDepth++;
  535.     envPtr->maxExceptDepth =
  536.     TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
  537.     bodyRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
  538.     nextRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
  539.     /*
  540.      * Inline compile the initial command.
  541.      */
  542. #ifdef TCL_TIP280
  543.     envPtr->line = mapPtr->loc [eclIndex].line [1];
  544. #endif
  545.     code = TclCompileCmdWord(interp, startTokenPtr+1,
  546.     startTokenPtr->numComponents, envPtr);
  547.     if (code != TCL_OK) {
  548. if (code == TCL_ERROR) {
  549.             Tcl_AddObjErrorInfo(interp,
  550.             "n    ("for" initial command)", -1);
  551.         }
  552. goto done;
  553.     }
  554.     TclEmitOpcode(INST_POP, envPtr);
  555.    
  556.     /*
  557.      * Jump to the evaluation of the condition. This code uses the "loop
  558.      * rotation" optimisation (which eliminates one branch from the loop).
  559.      * "for start cond next body" produces then:
  560.      *       start
  561.      *       goto A
  562.      *    B: body                : bodyCodeOffset
  563.      *       next                : nextCodeOffset, continueOffset
  564.      *    A: cond -> result      : testCodeOffset
  565.      *       if (result) goto B
  566.      */
  567.     TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup);
  568.     /*
  569.      * Compile the loop body.
  570.      */
  571.     bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart);
  572. #ifdef TCL_TIP280
  573.     envPtr->line = mapPtr->loc [eclIndex].line [4];
  574. #endif
  575.     code = TclCompileCmdWord(interp, bodyTokenPtr+1,
  576.     bodyTokenPtr->numComponents, envPtr);
  577.     envPtr->currStackDepth = savedStackDepth + 1;
  578.     if (code != TCL_OK) {
  579. if (code == TCL_ERROR) {
  580.     sprintf(buffer, "n    ("for" body line %d)",
  581.     interp->errorLine);
  582.             Tcl_AddObjErrorInfo(interp, buffer, -1);
  583.         }
  584. goto done;
  585.     }
  586.     envPtr->exceptArrayPtr[bodyRange].numCodeBytes =
  587.     (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
  588.     TclEmitOpcode(INST_POP, envPtr);
  589.     /*
  590.      * Compile the "next" subcommand.
  591.      */
  592.     nextCodeOffset = (envPtr->codeNext - envPtr->codeStart);
  593. #ifdef TCL_TIP280
  594.     envPtr->line = mapPtr->loc [eclIndex].line [3];
  595. #endif
  596.     envPtr->currStackDepth = savedStackDepth;
  597.     code = TclCompileCmdWord(interp, nextTokenPtr+1,
  598.     nextTokenPtr->numComponents, envPtr);
  599.     envPtr->currStackDepth = savedStackDepth + 1;
  600.     if (code != TCL_OK) {
  601. if (code == TCL_ERROR) {
  602.     Tcl_AddObjErrorInfo(interp,
  603.             "n    ("for" loop-end command)", -1);
  604. }
  605. goto done;
  606.     }
  607.     envPtr->exceptArrayPtr[nextRange].numCodeBytes =
  608.     (envPtr->codeNext - envPtr->codeStart)
  609.     - nextCodeOffset;
  610.     TclEmitOpcode(INST_POP, envPtr);
  611.     envPtr->currStackDepth = savedStackDepth;
  612.     /*
  613.      * Compile the test expression then emit the conditional jump that
  614.      * terminates the for.
  615.      */
  616.     testCodeOffset = (envPtr->codeNext - envPtr->codeStart);
  617.     jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset;
  618.     if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) {
  619. bodyCodeOffset += 3;
  620. nextCodeOffset += 3;
  621. testCodeOffset += 3;
  622.     }
  623. #ifdef TCL_TIP280
  624.     envPtr->line = mapPtr->loc [eclIndex].line [2];
  625. #endif
  626.     envPtr->currStackDepth = savedStackDepth;
  627.     code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
  628.     if (code != TCL_OK) {
  629. if (code == TCL_ERROR) {
  630.     Tcl_AddObjErrorInfo(interp,
  631. "n    ("for" test expression)", -1);
  632. }
  633. goto done;
  634.     }
  635.     envPtr->currStackDepth = savedStackDepth + 1;
  636.     
  637.     jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
  638.     if (jumpDist > 127) {
  639. TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
  640.     } else {
  641. TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
  642.     }
  643.     
  644.     /*
  645.      * Set the loop's offsets and break target.
  646.      */
  647.     envPtr->exceptArrayPtr[bodyRange].codeOffset = bodyCodeOffset;
  648.     envPtr->exceptArrayPtr[bodyRange].continueOffset = nextCodeOffset;
  649.     envPtr->exceptArrayPtr[nextRange].codeOffset = nextCodeOffset;
  650.     envPtr->exceptArrayPtr[bodyRange].breakOffset =
  651.             envPtr->exceptArrayPtr[nextRange].breakOffset =
  652.     (envPtr->codeNext - envPtr->codeStart);
  653.     
  654.     /*
  655.      * The for command's result is an empty string.
  656.      */
  657.     envPtr->currStackDepth = savedStackDepth;
  658.     TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
  659.     code = TCL_OK;
  660.     done:
  661.     envPtr->exceptDepth--;
  662.     return code;
  663. }
  664. /*
  665.  *----------------------------------------------------------------------
  666.  *
  667.  * TclCompileForeachCmd --
  668.  *
  669.  * Procedure called to compile the "foreach" command.
  670.  *
  671.  * Results:
  672.  * The return value is a standard Tcl result, which is TCL_OK if
  673.  * compilation was successful. If an error occurs then the
  674.  * interpreter's result contains a standard error message and TCL_ERROR
  675.  * is returned. If the command is too complex for TclCompileForeachCmd,
  676.  * TCL_OUT_LINE_COMPILE is returned indicating that the foreach command
  677.  * should be compiled "out of line" by emitting code to invoke its
  678.  * command procedure at runtime.
  679.  *
  680.  * Side effects:
  681.  * Instructions are added to envPtr to execute the "foreach" command
  682.  * at runtime.
  683.  *
  684. n*----------------------------------------------------------------------
  685.  */
  686. int
  687. TclCompileForeachCmd(interp, parsePtr, envPtr)
  688.     Tcl_Interp *interp; /* Used for error reporting. */
  689.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  690.  * command created by Tcl_ParseCommand. */
  691.     CompileEnv *envPtr; /* Holds resulting instructions. */
  692. {
  693.     Proc *procPtr = envPtr->procPtr;
  694.     ForeachInfo *infoPtr; /* Points to the structure describing this
  695.  * foreach command. Stored in a AuxData
  696.  * record in the ByteCode. */
  697.     int firstValueTemp; /* Index of the first temp var in the frame
  698.  * used to point to a value list. */
  699.     int loopCtTemp; /* Index of temp var holding the loop's
  700.  * iteration count. */
  701.     Tcl_Token *tokenPtr, *bodyTokenPtr;
  702.     unsigned char *jumpPc;
  703.     JumpFixup jumpFalseFixup;
  704.     int jumpDist, jumpBackDist, jumpBackOffset, infoIndex, range;
  705.     int numWords, numLists, numVars, loopIndex, tempVar, i, j, code;
  706.     char buffer[32 + TCL_INTEGER_SPACE];
  707.     int savedStackDepth = envPtr->currStackDepth;
  708. #ifdef TCL_TIP280
  709.     /* TIP #280 : Remember the per-word line information of the current
  710.      * command. An index is used instead of a pointer as recursive compilation
  711.      * may reallocate, i.e. move, the array. This is also the reason to save
  712.      * the nuloc now, it may change during the course of the function.
  713.      */
  714.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  715.     int        eclIndex = mapPtr->nuloc - 1;
  716.     int        bodyIndex;
  717. #endif
  718.     /*
  719.      * We parse the variable list argument words and create two arrays:
  720.      *    varcList[i] is number of variables in i-th var list
  721.      *    varvList[i] points to array of var names in i-th var list
  722.      */
  723. #define STATIC_VAR_LIST_SIZE 5
  724.     int varcListStaticSpace[STATIC_VAR_LIST_SIZE];
  725.     CONST char **varvListStaticSpace[STATIC_VAR_LIST_SIZE];
  726.     int *varcList = varcListStaticSpace;
  727.     CONST char ***varvList = varvListStaticSpace;
  728.     /*
  729.      * If the foreach command isn't in a procedure, don't compile it inline:
  730.      * the payoff is too small.
  731.      */
  732.     if (procPtr == NULL) {
  733. return TCL_OUT_LINE_COMPILE;
  734.     }
  735.     numWords = parsePtr->numWords;
  736.     if ((numWords < 4) || (numWords%2 != 0)) {
  737. Tcl_ResetResult(interp);
  738. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  739.         "wrong # args: should be "foreach varList list ?varList list ...? command"", -1);
  740.         return TCL_ERROR;
  741.     }
  742.     /*
  743.      * Bail out if the body requires substitutions
  744.      * in order to insure correct behaviour [Bug 219166]
  745.      */
  746.     for (i = 0, tokenPtr = parsePtr->tokenPtr;
  747.     i < numWords-1;
  748.     i++, tokenPtr += (tokenPtr->numComponents + 1)) {
  749.     }
  750.     bodyTokenPtr = tokenPtr;
  751.     if (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
  752. return TCL_OUT_LINE_COMPILE;
  753.     }
  754. #ifdef TCL_TIP280
  755.     bodyIndex = i-1;
  756. #endif
  757.     /*
  758.      * Allocate storage for the varcList and varvList arrays if necessary.
  759.      */
  760.     numLists = (numWords - 2)/2;
  761.     if (numLists > STATIC_VAR_LIST_SIZE) {
  762.         varcList = (int *) ckalloc(numLists * sizeof(int));
  763.         varvList = (CONST char ***) ckalloc(numLists * sizeof(CONST char **));
  764.     }
  765.     for (loopIndex = 0;  loopIndex < numLists;  loopIndex++) {
  766.         varcList[loopIndex] = 0;
  767.         varvList[loopIndex] = NULL;
  768.     }
  769.     
  770.     /*
  771.      * Set the exception stack depth.
  772.      */ 
  773.     envPtr->exceptDepth++;
  774.     envPtr->maxExceptDepth =
  775. TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
  776.     /*
  777.      * Break up each var list and set the varcList and varvList arrays.
  778.      * Don't compile the foreach inline if any var name needs substitutions
  779.      * or isn't a scalar, or if any var list needs substitutions.
  780.      */
  781.     loopIndex = 0;
  782.     for (i = 0, tokenPtr = parsePtr->tokenPtr;
  783.     i < numWords-1;
  784.     i++, tokenPtr += (tokenPtr->numComponents + 1)) {
  785. if (i%2 == 1) {
  786.     if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
  787. code = TCL_OUT_LINE_COMPILE;
  788. goto done;
  789.     } else {
  790. /* Lots of copying going on here.  Need a ListObj wizard
  791.  * to show a better way. */
  792. Tcl_DString varList;
  793. Tcl_DStringInit(&varList);
  794. Tcl_DStringAppend(&varList, tokenPtr[1].start,
  795. tokenPtr[1].size);
  796. code = Tcl_SplitList(interp, Tcl_DStringValue(&varList),
  797. &varcList[loopIndex], &varvList[loopIndex]);
  798. Tcl_DStringFree(&varList);
  799. if (code != TCL_OK) {
  800.     goto done;
  801. }
  802. numVars = varcList[loopIndex];
  803. /*
  804.  * If the variable list is empty, we can enter an infinite
  805.  * loop when the interpreted version would not. Take care to
  806.  * ensure this does not happen. [Bug 1671138]
  807.  */
  808. if (numVars == 0) {
  809.     code = TCL_OUT_LINE_COMPILE;
  810.     goto done;
  811. }
  812. for (j = 0;  j < numVars;  j++) {
  813.     CONST char *varName = varvList[loopIndex][j];
  814.     if (!TclIsLocalScalar(varName, (int) strlen(varName))) {
  815. code = TCL_OUT_LINE_COMPILE;
  816. goto done;
  817.     }
  818. }
  819.     }
  820.     loopIndex++;
  821. }
  822.     }
  823.     /*
  824.      * We will compile the foreach command.
  825.      * Reserve (numLists + 1) temporary variables:
  826.      *    - numLists temps to hold each value list
  827.      *    - 1 temp for the loop counter (index of next element in each list)
  828.      * At this time we don't try to reuse temporaries; if there are two
  829.      * nonoverlapping foreach loops, they don't share any temps.
  830.      */
  831.     firstValueTemp = -1;
  832.     for (loopIndex = 0;  loopIndex < numLists;  loopIndex++) {
  833. tempVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
  834. /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
  835. if (loopIndex == 0) {
  836.     firstValueTemp = tempVar;
  837. }
  838.     }
  839.     loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
  840.     /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
  841.     
  842.     /*
  843.      * Create and initialize the ForeachInfo and ForeachVarList data
  844.      * structures describing this command. Then create a AuxData record
  845.      * pointing to the ForeachInfo structure.
  846.      */
  847.     infoPtr = (ForeachInfo *) ckalloc((unsigned)
  848.     (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *))));
  849.     infoPtr->numLists = numLists;
  850.     infoPtr->firstValueTemp = firstValueTemp;
  851.     infoPtr->loopCtTemp = loopCtTemp;
  852.     for (loopIndex = 0;  loopIndex < numLists;  loopIndex++) {
  853. ForeachVarList *varListPtr;
  854. numVars = varcList[loopIndex];
  855. varListPtr = (ForeachVarList *) ckalloc((unsigned)
  856.         sizeof(ForeachVarList) + (numVars * sizeof(int)));
  857. varListPtr->numVars = numVars;
  858. for (j = 0;  j < numVars;  j++) {
  859.     CONST char *varName = varvList[loopIndex][j];
  860.     int nameChars = strlen(varName);
  861.     varListPtr->varIndexes[j] = TclFindCompiledLocal(varName,
  862.     nameChars, /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
  863. }
  864. infoPtr->varLists[loopIndex] = varListPtr;
  865.     }
  866.     infoIndex = TclCreateAuxData((ClientData) infoPtr, &tclForeachInfoType, envPtr);
  867.     /*
  868.      * Evaluate then store each value list in the associated temporary.
  869.      */
  870.     range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
  871.     
  872.     loopIndex = 0;
  873.     for (i = 0, tokenPtr = parsePtr->tokenPtr;
  874.     i < numWords-1;
  875.     i++, tokenPtr += (tokenPtr->numComponents + 1)) {
  876. if ((i%2 == 0) && (i > 0)) {
  877. #ifdef TCL_TIP280
  878.     envPtr->line = mapPtr->loc [eclIndex].line [i];
  879. #endif
  880.     code = TclCompileTokens(interp, tokenPtr+1,
  881.     tokenPtr->numComponents, envPtr);
  882.     if (code != TCL_OK) {
  883. goto done;
  884.     }
  885.     tempVar = (firstValueTemp + loopIndex);
  886.     if (tempVar <= 255) {
  887. TclEmitInstInt1(INST_STORE_SCALAR1, tempVar, envPtr);
  888.     } else {
  889. TclEmitInstInt4(INST_STORE_SCALAR4, tempVar, envPtr);
  890.     }
  891.     TclEmitOpcode(INST_POP, envPtr);
  892.     loopIndex++;
  893. }
  894.     }
  895.     /*
  896.      * Initialize the temporary var that holds the count of loop iterations.
  897.      */
  898.     TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr);
  899.     
  900.     /*
  901.      * Top of loop code: assign each loop variable and check whether
  902.      * to terminate the loop.
  903.      */
  904.     envPtr->exceptArrayPtr[range].continueOffset =
  905.     (envPtr->codeNext - envPtr->codeStart);
  906.     TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr);
  907.     TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFalseFixup);
  908.     
  909.     /*
  910.      * Inline compile the loop body.
  911.      */
  912. #ifdef TCL_TIP280
  913.     envPtr->line = mapPtr->loc [eclIndex].line [bodyIndex];
  914. #endif
  915.     envPtr->exceptArrayPtr[range].codeOffset =
  916.     (envPtr->codeNext - envPtr->codeStart);
  917.     code = TclCompileCmdWord(interp, bodyTokenPtr+1,
  918.     bodyTokenPtr->numComponents, envPtr);
  919.     envPtr->currStackDepth = savedStackDepth + 1;
  920.     if (code != TCL_OK) {
  921. if (code == TCL_ERROR) {
  922.     sprintf(buffer, "n    ("foreach" body line %d)",
  923.     interp->errorLine);
  924.             Tcl_AddObjErrorInfo(interp, buffer, -1);
  925.         }
  926. goto done;
  927.     }
  928.     envPtr->exceptArrayPtr[range].numCodeBytes =
  929.     (envPtr->codeNext - envPtr->codeStart)
  930.     - envPtr->exceptArrayPtr[range].codeOffset;
  931.     TclEmitOpcode(INST_POP, envPtr);
  932.     /*
  933.      * Jump back to the test at the top of the loop. Generate a 4 byte jump
  934.      * if the distance to the test is > 120 bytes. This is conservative and
  935.      * ensures that we won't have to replace this jump if we later need to
  936.      * replace the ifFalse jump with a 4 byte jump.
  937.      */
  938.     jumpBackOffset = (envPtr->codeNext - envPtr->codeStart);
  939.     jumpBackDist =
  940. (jumpBackOffset - envPtr->exceptArrayPtr[range].continueOffset);
  941.     if (jumpBackDist > 120) {
  942. TclEmitInstInt4(INST_JUMP4, -jumpBackDist, envPtr);
  943.     } else {
  944. TclEmitInstInt1(INST_JUMP1, -jumpBackDist, envPtr);
  945.     }
  946.     /*
  947.      * Fix the target of the jump after the foreach_step test.
  948.      */
  949.     jumpDist = (envPtr->codeNext - envPtr->codeStart)
  950.     - jumpFalseFixup.codeOffset;
  951.     if (TclFixupForwardJump(envPtr, &jumpFalseFixup, jumpDist, 127)) {
  952. /*
  953.  * Update the loop body's starting PC offset since it moved down.
  954.  */
  955. envPtr->exceptArrayPtr[range].codeOffset += 3;
  956. /*
  957.  * Update the jump back to the test at the top of the loop since it
  958.  * also moved down 3 bytes.
  959.  */
  960. jumpBackOffset += 3;
  961. jumpPc = (envPtr->codeStart + jumpBackOffset);
  962. jumpBackDist += 3;
  963. if (jumpBackDist > 120) {
  964.     TclUpdateInstInt4AtPc(INST_JUMP4, -jumpBackDist, jumpPc);
  965. } else {
  966.     TclUpdateInstInt1AtPc(INST_JUMP1, -jumpBackDist, jumpPc);
  967. }
  968.     }
  969.     /*
  970.      * Set the loop's break target.
  971.      */
  972.     envPtr->exceptArrayPtr[range].breakOffset =
  973.     (envPtr->codeNext - envPtr->codeStart);
  974.     
  975.     /*
  976.      * The foreach command's result is an empty string.
  977.      */
  978.     envPtr->currStackDepth = savedStackDepth;
  979.     TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
  980.     envPtr->currStackDepth = savedStackDepth + 1;
  981.     done:
  982.     for (loopIndex = 0;  loopIndex < numLists;  loopIndex++) {
  983. if (varvList[loopIndex] != (CONST char **) NULL) {
  984.     ckfree((char *) varvList[loopIndex]);
  985. }
  986.     }
  987.     if (varcList != varcListStaticSpace) {
  988. ckfree((char *) varcList);
  989.         ckfree((char *) varvList);
  990.     }
  991.     envPtr->exceptDepth--;
  992.     return code;
  993. }
  994. /*
  995.  *----------------------------------------------------------------------
  996.  *
  997.  * DupForeachInfo --
  998.  *
  999.  * This procedure duplicates a ForeachInfo structure created as
  1000.  * auxiliary data during the compilation of a foreach command.
  1001.  *
  1002.  * Results:
  1003.  * A pointer to a newly allocated copy of the existing ForeachInfo
  1004.  * structure is returned.
  1005.  *
  1006.  * Side effects:
  1007.  * Storage for the copied ForeachInfo record is allocated. If the
  1008.  * original ForeachInfo structure pointed to any ForeachVarList
  1009.  * records, these structures are also copied and pointers to them
  1010.  * are stored in the new ForeachInfo record.
  1011.  *
  1012.  *----------------------------------------------------------------------
  1013.  */
  1014. static ClientData
  1015. DupForeachInfo(clientData)
  1016.     ClientData clientData; /* The foreach command's compilation
  1017.  * auxiliary data to duplicate. */
  1018. {
  1019.     register ForeachInfo *srcPtr = (ForeachInfo *) clientData;
  1020.     ForeachInfo *dupPtr;
  1021.     register ForeachVarList *srcListPtr, *dupListPtr;
  1022.     int numLists = srcPtr->numLists;
  1023.     int numVars, i, j;
  1024.     
  1025.     dupPtr = (ForeachInfo *) ckalloc((unsigned)
  1026.     (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *))));
  1027.     dupPtr->numLists = numLists;
  1028.     dupPtr->firstValueTemp = srcPtr->firstValueTemp;
  1029.     dupPtr->loopCtTemp = srcPtr->loopCtTemp;
  1030.     
  1031.     for (i = 0;  i < numLists;  i++) {
  1032. srcListPtr = srcPtr->varLists[i];
  1033. numVars = srcListPtr->numVars;
  1034. dupListPtr = (ForeachVarList *) ckalloc((unsigned)
  1035.         sizeof(ForeachVarList) + numVars*sizeof(int));
  1036. dupListPtr->numVars = numVars;
  1037. for (j = 0;  j < numVars;  j++) {
  1038.     dupListPtr->varIndexes[j] = srcListPtr->varIndexes[j];
  1039. }
  1040. dupPtr->varLists[i] = dupListPtr;
  1041.     }
  1042.     return (ClientData) dupPtr;
  1043. }
  1044. /*
  1045.  *----------------------------------------------------------------------
  1046.  *
  1047.  * FreeForeachInfo --
  1048.  *
  1049.  * Procedure to free a ForeachInfo structure created as auxiliary data
  1050.  * during the compilation of a foreach command.
  1051.  *
  1052.  * Results:
  1053.  * None.
  1054.  *
  1055.  * Side effects:
  1056.  * Storage for the ForeachInfo structure pointed to by the ClientData
  1057.  * argument is freed as is any ForeachVarList record pointed to by the
  1058.  * ForeachInfo structure.
  1059.  *
  1060.  *----------------------------------------------------------------------
  1061.  */
  1062. static void
  1063. FreeForeachInfo(clientData)
  1064.     ClientData clientData; /* The foreach command's compilation
  1065.  * auxiliary data to free. */
  1066. {
  1067.     register ForeachInfo *infoPtr = (ForeachInfo *) clientData;
  1068.     register ForeachVarList *listPtr;
  1069.     int numLists = infoPtr->numLists;
  1070.     register int i;
  1071.     for (i = 0;  i < numLists;  i++) {
  1072. listPtr = infoPtr->varLists[i];
  1073. ckfree((char *) listPtr);
  1074.     }
  1075.     ckfree((char *) infoPtr);
  1076. }
  1077. /*
  1078.  *----------------------------------------------------------------------
  1079.  *
  1080.  * TclCompileIfCmd --
  1081.  *
  1082.  * Procedure called to compile the "if" command.
  1083.  *
  1084.  * Results:
  1085.  * The return value is a standard Tcl result, which is TCL_OK if
  1086.  * compilation was successful. If an error occurs then the
  1087.  * interpreter's result contains a standard error message and TCL_ERROR
  1088.  * is returned. If the command is too complex for TclCompileIfCmd,
  1089.  * TCL_OUT_LINE_COMPILE is returned indicating that the if command
  1090.  * should be compiled "out of line" by emitting code to invoke its
  1091.  * command procedure at runtime.
  1092.  *
  1093.  * Side effects:
  1094.  * Instructions are added to envPtr to execute the "if" command
  1095.  * at runtime.
  1096.  *
  1097.  *----------------------------------------------------------------------
  1098.  */
  1099. int
  1100. TclCompileIfCmd(interp, parsePtr, envPtr)
  1101.     Tcl_Interp *interp; /* Used for error reporting. */
  1102.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  1103.  * command created by Tcl_ParseCommand. */
  1104.     CompileEnv *envPtr; /* Holds resulting instructions. */
  1105. {
  1106.     JumpFixupArray jumpFalseFixupArray;
  1107.      /* Used to fix the ifFalse jump after each
  1108.  * test when its target PC is determined. */
  1109.     JumpFixupArray jumpEndFixupArray;
  1110. /* Used to fix the jump after each "then"
  1111.  * body to the end of the "if" when that PC
  1112.  * is determined. */
  1113.     Tcl_Token *tokenPtr, *testTokenPtr;
  1114.     int jumpDist, jumpFalseDist;
  1115.     int jumpIndex = 0;          /* avoid compiler warning. */
  1116.     int numWords, wordIdx, numBytes, j, code;
  1117.     CONST char *word;
  1118.     char buffer[100];
  1119.     int savedStackDepth = envPtr->currStackDepth;
  1120.                                 /* Saved stack depth at the start of the first
  1121.  * test; the envPtr current depth is restored
  1122.  * to this value at the start of each test. */
  1123.     int realCond = 1;           /* set to 0 for static conditions: "if 0 {..}" */
  1124.     int boolVal;                /* value of static condition */
  1125.     int compileScripts = 1;            
  1126. #ifdef TCL_TIP280
  1127.     /* TIP #280 : Remember the per-word line information of the current
  1128.      * command. An index is used instead of a pointer as recursive compilation
  1129.      * may reallocate, i.e. move, the array. This is also the reason to save
  1130.      * the nuloc now, it may change during the course of the function.
  1131.      */
  1132.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  1133.     int        eclIndex = mapPtr->nuloc - 1;
  1134. #endif
  1135.     /*
  1136.      * Only compile the "if" command if all arguments are simple
  1137.      * words, in order to insure correct substitution [Bug 219166]
  1138.      */
  1139.     tokenPtr = parsePtr->tokenPtr;
  1140.     wordIdx = 0;
  1141.     numWords = parsePtr->numWords;
  1142.     for (wordIdx = 0; wordIdx < numWords; wordIdx++) {
  1143. if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
  1144.     return TCL_OUT_LINE_COMPILE;
  1145. }
  1146. tokenPtr += 2;
  1147.     }
  1148.     TclInitJumpFixupArray(&jumpFalseFixupArray);
  1149.     TclInitJumpFixupArray(&jumpEndFixupArray);
  1150.     code = TCL_OK;
  1151.     /*
  1152.      * Each iteration of this loop compiles one "if expr ?then? body"
  1153.      * or "elseif expr ?then? body" clause. 
  1154.      */
  1155.     tokenPtr = parsePtr->tokenPtr;
  1156.     wordIdx = 0;
  1157.     while (wordIdx < numWords) {
  1158. /*
  1159.  * Stop looping if the token isn't "if" or "elseif".
  1160.  */
  1161. word = tokenPtr[1].start;
  1162. numBytes = tokenPtr[1].size;
  1163. if ((tokenPtr == parsePtr->tokenPtr)
  1164.         || ((numBytes == 6) && (strncmp(word, "elseif", 6) == 0))) {
  1165.     tokenPtr += (tokenPtr->numComponents + 1);
  1166.     wordIdx++;
  1167. } else {
  1168.     break;
  1169. }
  1170. if (wordIdx >= numWords) {
  1171.     sprintf(buffer,
  1172.             "wrong # args: no expression after "%.*s" argument",
  1173.     (numBytes > 50 ? 50 : numBytes), word);
  1174.     Tcl_ResetResult(interp);
  1175.     Tcl_AppendToObj(Tcl_GetObjResult(interp), buffer, -1);
  1176.     code = TCL_ERROR;
  1177.     goto done;
  1178. }
  1179. /*
  1180.  * Compile the test expression then emit the conditional jump
  1181.  * around the "then" part. 
  1182.  */
  1183. envPtr->currStackDepth = savedStackDepth;
  1184. testTokenPtr = tokenPtr;
  1185. if (realCond) {
  1186.     /*
  1187.      * Find out if the condition is a constant. 
  1188.      */
  1189.     Tcl_Obj *boolObj = Tcl_NewStringObj(testTokenPtr[1].start,
  1190.     testTokenPtr[1].size);
  1191.     Tcl_IncrRefCount(boolObj);
  1192.     code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
  1193.     Tcl_DecrRefCount(boolObj);
  1194.     if (code == TCL_OK) {
  1195. /*
  1196.  * A static condition
  1197.  */
  1198. realCond = 0;
  1199. if (!boolVal) {
  1200.     compileScripts = 0;
  1201. }
  1202.     } else {
  1203. Tcl_ResetResult(interp);
  1204. #ifdef TCL_TIP280
  1205. envPtr->line = mapPtr->loc [eclIndex].line [wordIdx];
  1206. #endif
  1207. code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
  1208. if (code != TCL_OK) {
  1209.     if (code == TCL_ERROR) {
  1210. Tcl_AddObjErrorInfo(interp,
  1211.         "n    ("if" test expression)", -1);
  1212.     }
  1213.     goto done;
  1214. }
  1215. if (jumpFalseFixupArray.next >= jumpFalseFixupArray.end) {
  1216.     TclExpandJumpFixupArray(&jumpFalseFixupArray);
  1217. }
  1218. jumpIndex = jumpFalseFixupArray.next;
  1219. jumpFalseFixupArray.next++;
  1220. TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
  1221.        &(jumpFalseFixupArray.fixup[jumpIndex]));     
  1222.     }
  1223. }
  1224. /*
  1225.  * Skip over the optional "then" before the then clause.
  1226.  */
  1227. tokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1);
  1228. wordIdx++;
  1229. if (wordIdx >= numWords) {
  1230.     sprintf(buffer,
  1231.     "wrong # args: no script following "%.*s" argument",
  1232.     (testTokenPtr->size > 50 ? 50 : testTokenPtr->size),
  1233.     testTokenPtr->start);
  1234.     Tcl_ResetResult(interp);
  1235.     Tcl_AppendToObj(Tcl_GetObjResult(interp), buffer, -1);
  1236.     code = TCL_ERROR;
  1237.     goto done;
  1238. }
  1239. if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  1240.     word = tokenPtr[1].start;
  1241.     numBytes = tokenPtr[1].size;
  1242.     if ((numBytes == 4) && (strncmp(word, "then", 4) == 0)) {
  1243. tokenPtr += (tokenPtr->numComponents + 1);
  1244. wordIdx++;
  1245. if (wordIdx >= numWords) {
  1246.     Tcl_ResetResult(interp);
  1247.     Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1248.             "wrong # args: no script following "then" argument", -1);
  1249.     code = TCL_ERROR;
  1250.     goto done;
  1251. }
  1252.     }
  1253. }
  1254. /*
  1255.  * Compile the "then" command body.
  1256.  */
  1257. if (compileScripts) {
  1258. #ifdef TCL_TIP280
  1259.     envPtr->line = mapPtr->loc [eclIndex].line [wordIdx];
  1260. #endif
  1261.     envPtr->currStackDepth = savedStackDepth;
  1262.     code = TclCompileCmdWord(interp, tokenPtr+1,
  1263.             tokenPtr->numComponents, envPtr);
  1264.     if (code != TCL_OK) {
  1265. if (code == TCL_ERROR) {
  1266.     sprintf(buffer, "n    ("if" then script line %d)",
  1267.             interp->errorLine);
  1268.     Tcl_AddObjErrorInfo(interp, buffer, -1);
  1269. }
  1270. goto done;
  1271.     }
  1272. }
  1273. if (realCond) {
  1274.     /*
  1275.      * Jump to the end of the "if" command. Both jumpFalseFixupArray and
  1276.      * jumpEndFixupArray are indexed by "jumpIndex".
  1277.      */
  1278.     
  1279.     if (jumpEndFixupArray.next >= jumpEndFixupArray.end) {
  1280. TclExpandJumpFixupArray(&jumpEndFixupArray);
  1281.     }
  1282.     jumpEndFixupArray.next++;
  1283.     TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
  1284.             &(jumpEndFixupArray.fixup[jumpIndex]));
  1285.     
  1286.     /*
  1287.      * Fix the target of the jumpFalse after the test. Generate a 4 byte
  1288.      * jump if the distance is > 120 bytes. This is conservative, and
  1289.      * ensures that we won't have to replace this jump if we later also
  1290.      * need to replace the proceeding jump to the end of the "if" with a
  1291.      * 4 byte jump.
  1292.      */
  1293.     jumpDist = (envPtr->codeNext - envPtr->codeStart)
  1294.             - jumpFalseFixupArray.fixup[jumpIndex].codeOffset;
  1295.     if (TclFixupForwardJump(envPtr,
  1296.             &(jumpFalseFixupArray.fixup[jumpIndex]), jumpDist, 120)) {
  1297. /*
  1298.  * Adjust the code offset for the proceeding jump to the end
  1299.  * of the "if" command.
  1300.  */
  1301. jumpEndFixupArray.fixup[jumpIndex].codeOffset += 3;
  1302.     }
  1303. } else if (boolVal) {
  1304.     /* 
  1305.      *We were processing an "if 1 {...}"; stop compiling
  1306.      * scripts
  1307.      */
  1308.     compileScripts = 0;
  1309. } else {
  1310.     /* 
  1311.      *We were processing an "if 0 {...}"; reset so that
  1312.      * the rest (elseif, else) is compiled correctly
  1313.      */
  1314.     realCond = 1;
  1315.     compileScripts = 1;
  1316. tokenPtr += (tokenPtr->numComponents + 1);
  1317. wordIdx++;
  1318.     }
  1319.     /*
  1320.      * Restore the current stack depth in the environment; the 
  1321.      * "else" clause (or its default) will add 1 to this.
  1322.      */
  1323.     envPtr->currStackDepth = savedStackDepth;
  1324.     /*
  1325.      * Check for the optional else clause. Do not compile
  1326.      * anything if this was an "if 1 {...}" case.
  1327.      */
  1328.     if ((wordIdx < numWords)
  1329.     && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
  1330. /*
  1331.  * There is an else clause. Skip over the optional "else" word.
  1332.  */
  1333. word = tokenPtr[1].start;
  1334. numBytes = tokenPtr[1].size;
  1335. if ((numBytes == 4) && (strncmp(word, "else", 4) == 0)) {
  1336.     tokenPtr += (tokenPtr->numComponents + 1);
  1337.     wordIdx++;
  1338.     if (wordIdx >= numWords) {
  1339. Tcl_ResetResult(interp);
  1340. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1341.         "wrong # args: no script following "else" argument", -1);
  1342. code = TCL_ERROR;
  1343. goto done;
  1344.     }
  1345. }
  1346. if (compileScripts) {
  1347.     /*
  1348.      * Compile the else command body.
  1349.      */
  1350. #ifdef TCL_TIP280
  1351.     envPtr->line = mapPtr->loc [eclIndex].line [wordIdx];
  1352. #endif
  1353.     code = TclCompileCmdWord(interp, tokenPtr+1,
  1354.     tokenPtr->numComponents, envPtr);
  1355.     if (code != TCL_OK) {
  1356. if (code == TCL_ERROR) {
  1357.     sprintf(buffer, "n    ("if" else script line %d)",
  1358.     interp->errorLine);
  1359.     Tcl_AddObjErrorInfo(interp, buffer, -1);
  1360. }
  1361. goto done;
  1362.     }
  1363. }
  1364. /*
  1365.  * Make sure there are no words after the else clause.
  1366.  */
  1367. wordIdx++;
  1368. if (wordIdx < numWords) {
  1369.     Tcl_ResetResult(interp);
  1370.     Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1371.     "wrong # args: extra words after "else" clause in "if" command", -1);
  1372.     code = TCL_ERROR;
  1373.     goto done;
  1374. }
  1375.     } else {
  1376. /*
  1377.  * No else clause: the "if" command's result is an empty string.
  1378.  */
  1379. if (compileScripts) {
  1380.     TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
  1381. }
  1382.     }
  1383.     /*
  1384.      * Fix the unconditional jumps to the end of the "if" command.
  1385.      */
  1386.     
  1387.     for (j = jumpEndFixupArray.next;  j > 0;  j--) {
  1388. jumpIndex = (j - 1); /* i.e. process the closest jump first */
  1389. jumpDist = (envPtr->codeNext - envPtr->codeStart)
  1390.         - jumpEndFixupArray.fixup[jumpIndex].codeOffset;
  1391. if (TclFixupForwardJump(envPtr,
  1392.         &(jumpEndFixupArray.fixup[jumpIndex]), jumpDist, 127)) {
  1393.     /*
  1394.      * Adjust the immediately preceeding "ifFalse" jump. We moved
  1395.      * it's target (just after this jump) down three bytes.
  1396.      */
  1397.     unsigned char *ifFalsePc = envPtr->codeStart
  1398.             + jumpFalseFixupArray.fixup[jumpIndex].codeOffset;
  1399.     unsigned char opCode = *ifFalsePc;
  1400.     if (opCode == INST_JUMP_FALSE1) {
  1401. jumpFalseDist = TclGetInt1AtPtr(ifFalsePc + 1);
  1402. jumpFalseDist += 3;
  1403. TclStoreInt1AtPtr(jumpFalseDist, (ifFalsePc + 1));
  1404.     } else if (opCode == INST_JUMP_FALSE4) {
  1405. jumpFalseDist = TclGetInt4AtPtr(ifFalsePc + 1);
  1406. jumpFalseDist += 3;
  1407. TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1));
  1408.     } else {
  1409. panic("TclCompileIfCmd: unexpected opcode updating ifFalse jump");
  1410.     }
  1411. }
  1412.     }
  1413.     /*
  1414.      * Free the jumpFixupArray array if malloc'ed storage was used.
  1415.      */
  1416.     done:
  1417.     envPtr->currStackDepth = savedStackDepth + 1;
  1418.     TclFreeJumpFixupArray(&jumpFalseFixupArray);
  1419.     TclFreeJumpFixupArray(&jumpEndFixupArray);
  1420.     return code;
  1421. }
  1422. /*
  1423.  *----------------------------------------------------------------------
  1424.  *
  1425.  * TclCompileIncrCmd --
  1426.  *
  1427.  * Procedure called to compile the "incr" command.
  1428.  *
  1429.  * Results:
  1430.  * The return value is a standard Tcl result, which is TCL_OK if
  1431.  * compilation was successful. If an error occurs then the
  1432.  * interpreter's result contains a standard error message and TCL_ERROR
  1433.  * is returned. If the command is too complex for TclCompileIncrCmd,
  1434.  * TCL_OUT_LINE_COMPILE is returned indicating that the incr command
  1435.  * should be compiled "out of line" by emitting code to invoke its
  1436.  * command procedure at runtime.
  1437.  *
  1438.  * Side effects:
  1439.  * Instructions are added to envPtr to execute the "incr" command
  1440.  * at runtime.
  1441.  *
  1442.  *----------------------------------------------------------------------
  1443.  */
  1444. int
  1445. TclCompileIncrCmd(interp, parsePtr, envPtr)
  1446.     Tcl_Interp *interp; /* Used for error reporting. */
  1447.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  1448.  * command created by Tcl_ParseCommand. */
  1449.     CompileEnv *envPtr; /* Holds resulting instructions. */
  1450. {
  1451.     Tcl_Token *varTokenPtr, *incrTokenPtr;
  1452.     int simpleVarName, isScalar, localIndex, haveImmValue, immValue;
  1453.     int code = TCL_OK;
  1454. #ifdef TCL_TIP280
  1455.     /* TIP #280 : Remember the per-word line information of the current
  1456.      * command. An index is used instead of a pointer as recursive compilation
  1457.      * may reallocate, i.e. move, the array. This is also the reason to save
  1458.      * the nuloc now, it may change during the course of the function.
  1459.      */
  1460.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  1461.     int        eclIndex = mapPtr->nuloc - 1;
  1462. #endif
  1463.     if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) {
  1464. Tcl_ResetResult(interp);
  1465. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1466.         "wrong # args: should be "incr varName ?increment?"", -1);
  1467. return TCL_ERROR;
  1468.     }
  1469.     varTokenPtr = parsePtr->tokenPtr
  1470.     + (parsePtr->tokenPtr->numComponents + 1);
  1471.     code = TclPushVarName(interp, varTokenPtr, envPtr, 
  1472.     (TCL_NO_LARGE_INDEX | TCL_CREATE_VAR),
  1473. #ifndef TCL_TIP280
  1474.     &localIndex, &simpleVarName, &isScalar);
  1475. #else
  1476.     &localIndex, &simpleVarName, &isScalar,
  1477.     mapPtr->loc [eclIndex].line [1]);
  1478. #endif
  1479.     if (code != TCL_OK) {
  1480. goto done;
  1481.     }
  1482.     /*
  1483.      * If an increment is given, push it, but see first if it's a small
  1484.      * integer.
  1485.      */
  1486.     haveImmValue = 0;
  1487.     immValue = 1;
  1488.     if (parsePtr->numWords == 3) {
  1489. incrTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  1490. if (incrTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  1491.     CONST char *word = incrTokenPtr[1].start;
  1492.     int numBytes = incrTokenPtr[1].size;
  1493.     /*
  1494.      * Note there is a danger that modifying the string could have
  1495.      * undesirable side effects.  In this case, TclLooksLikeInt has
  1496.      * no dependencies on shared strings so we should be safe.
  1497.      */
  1498.     if (TclLooksLikeInt(word, numBytes)) {
  1499. int code;
  1500. Tcl_Obj *intObj = Tcl_NewStringObj(word, numBytes);
  1501. Tcl_IncrRefCount(intObj);
  1502. code = Tcl_GetIntFromObj(NULL, intObj, &immValue);
  1503. Tcl_DecrRefCount(intObj);
  1504. if ((code == TCL_OK)
  1505. && (-127 <= immValue) && (immValue <= 127)) {
  1506.     haveImmValue = 1;
  1507. }
  1508.     }
  1509.     if (!haveImmValue) {
  1510. TclEmitPush(
  1511. TclRegisterNewLiteral(envPtr, word, numBytes), envPtr);
  1512.     }
  1513. } else {
  1514. #ifdef TCL_TIP280
  1515.     envPtr->line = mapPtr->loc [eclIndex].line [2];
  1516. #endif
  1517.     code = TclCompileTokens(interp, incrTokenPtr+1, 
  1518.             incrTokenPtr->numComponents, envPtr);
  1519.     if (code != TCL_OK) {
  1520. goto done;
  1521.     }
  1522. }
  1523.     } else { /* no incr amount given so use 1 */
  1524. haveImmValue = 1;
  1525.     }
  1526.     
  1527.     /*
  1528.      * Emit the instruction to increment the variable.
  1529.      */
  1530.     if (simpleVarName) {
  1531. if (isScalar) {
  1532.     if (localIndex >= 0) {
  1533. if (haveImmValue) {
  1534.     TclEmitInstInt1(INST_INCR_SCALAR1_IMM, localIndex, envPtr);
  1535.     TclEmitInt1(immValue, envPtr);
  1536. } else {
  1537.     TclEmitInstInt1(INST_INCR_SCALAR1, localIndex, envPtr);
  1538. }
  1539.     } else {
  1540. if (haveImmValue) {
  1541.     TclEmitInstInt1(INST_INCR_SCALAR_STK_IMM, immValue, envPtr);
  1542. } else {
  1543.     TclEmitOpcode(INST_INCR_SCALAR_STK, envPtr);
  1544. }
  1545.     }
  1546. } else {
  1547.     if (localIndex >= 0) {
  1548. if (haveImmValue) {
  1549.     TclEmitInstInt1(INST_INCR_ARRAY1_IMM, localIndex, envPtr);
  1550.     TclEmitInt1(immValue, envPtr);
  1551. } else {
  1552.     TclEmitInstInt1(INST_INCR_ARRAY1, localIndex, envPtr);
  1553. }
  1554.     } else {
  1555. if (haveImmValue) {
  1556.     TclEmitInstInt1(INST_INCR_ARRAY_STK_IMM, immValue, envPtr);
  1557. } else {
  1558.     TclEmitOpcode(INST_INCR_ARRAY_STK, envPtr);
  1559. }
  1560.     }
  1561. }
  1562.     } else { /* non-simple variable name */
  1563. if (haveImmValue) {
  1564.     TclEmitInstInt1(INST_INCR_STK_IMM, immValue, envPtr);
  1565. } else {
  1566.     TclEmitOpcode(INST_INCR_STK, envPtr);
  1567. }
  1568.     }
  1569.     done:
  1570.     return code;
  1571. }
  1572. /*
  1573.  *----------------------------------------------------------------------
  1574.  *
  1575.  * TclCompileLappendCmd --
  1576.  *
  1577.  * Procedure called to compile the "lappend" command.
  1578.  *
  1579.  * Results:
  1580.  * The return value is a standard Tcl result, which is normally TCL_OK
  1581.  * unless there was an error while parsing string. If an error occurs
  1582.  * then the interpreter's result contains a standard error message. If
  1583.  * complation fails because the command requires a second level of
  1584.  * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the
  1585.  * command should be compiled "out of line" by emitting code to
  1586.  * invoke its command procedure (Tcl_LappendObjCmd) at runtime.
  1587.  *
  1588.  * Side effects:
  1589.  * Instructions are added to envPtr to execute the "lappend" command
  1590.  * at runtime.
  1591.  *
  1592.  *----------------------------------------------------------------------
  1593.  */
  1594. int
  1595. TclCompileLappendCmd(interp, parsePtr, envPtr)
  1596.     Tcl_Interp *interp; /* Used for error reporting. */
  1597.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  1598.  * command created by Tcl_ParseCommand. */
  1599.     CompileEnv *envPtr; /* Holds resulting instructions. */
  1600. {
  1601.     Tcl_Token *varTokenPtr, *valueTokenPtr;
  1602.     int simpleVarName, isScalar, localIndex, numWords;
  1603.     int code = TCL_OK;
  1604. #ifdef TCL_TIP280
  1605.     /* TIP #280 : Remember the per-word line information of the current
  1606.      * command. An index is used instead of a pointer as recursive compilation
  1607.      * may reallocate, i.e. move, the array. This is also the reason to save
  1608.      * the nuloc now, it may change during the course of the function.
  1609.      */
  1610.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  1611.     int        eclIndex = mapPtr->nuloc - 1;
  1612. #endif
  1613.     /*
  1614.      * If we're not in a procedure, don't compile.
  1615.      */
  1616.     if (envPtr->procPtr == NULL) {
  1617. return TCL_OUT_LINE_COMPILE;
  1618.     }
  1619.     numWords = parsePtr->numWords;
  1620.     if (numWords == 1) {
  1621. Tcl_ResetResult(interp);
  1622. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1623. "wrong # args: should be "lappend varName ?value value ...?"", -1);
  1624. return TCL_ERROR;
  1625.     }
  1626.     if (numWords != 3) {
  1627. /*
  1628.  * LAPPEND instructions currently only handle one value appends
  1629.  */
  1630.         return TCL_OUT_LINE_COMPILE;
  1631.     }
  1632.     /*
  1633.      * Decide if we can use a frame slot for the var/array name or if we
  1634.      * need to emit code to compute and push the name at runtime. We use a
  1635.      * frame slot (entry in the array of local vars) if we are compiling a
  1636.      * procedure body and if the name is simple text that does not include
  1637.      * namespace qualifiers. 
  1638.      */
  1639.     varTokenPtr = parsePtr->tokenPtr
  1640.     + (parsePtr->tokenPtr->numComponents + 1);
  1641.     code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR,
  1642. #ifndef TCL_TIP280
  1643.     &localIndex, &simpleVarName, &isScalar);
  1644. #else
  1645.     &localIndex, &simpleVarName, &isScalar,
  1646.     mapPtr->loc [eclIndex].line [1]);
  1647. #endif
  1648.     if (code != TCL_OK) {
  1649. goto done;
  1650.     }
  1651.     /*
  1652.      * If we are doing an assignment, push the new value.
  1653.      * In the no values case, create an empty object.
  1654.      */
  1655.     if (numWords > 2) {
  1656. valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  1657. if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  1658.     TclEmitPush(TclRegisterNewLiteral(envPtr, 
  1659.     valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr);
  1660. } else {
  1661. #ifdef TCL_TIP280
  1662.     envPtr->line = mapPtr->loc [eclIndex].line [2];
  1663. #endif
  1664.     code = TclCompileTokens(interp, valueTokenPtr+1,
  1665.             valueTokenPtr->numComponents, envPtr);
  1666.     if (code != TCL_OK) {
  1667. goto done;
  1668.     }
  1669. }
  1670.     }
  1671.     /*
  1672.      * Emit instructions to set/get the variable.
  1673.      */
  1674.     /*
  1675.      * The *_STK opcodes should be refactored to make better use of existing
  1676.      * LOAD/STORE instructions.
  1677.      */
  1678.     if (simpleVarName) {
  1679. if (isScalar) {
  1680.     if (localIndex >= 0) {
  1681. if (localIndex <= 255) {
  1682.     TclEmitInstInt1(INST_LAPPEND_SCALAR1, localIndex, envPtr);
  1683. } else {
  1684.     TclEmitInstInt4(INST_LAPPEND_SCALAR4, localIndex, envPtr);
  1685. }
  1686.     } else {
  1687. TclEmitOpcode(INST_LAPPEND_STK, envPtr);
  1688.     }
  1689. } else {
  1690.     if (localIndex >= 0) {
  1691. if (localIndex <= 255) {
  1692.     TclEmitInstInt1(INST_LAPPEND_ARRAY1, localIndex, envPtr);
  1693. } else {
  1694.     TclEmitInstInt4(INST_LAPPEND_ARRAY4, localIndex, envPtr);
  1695. }
  1696.     } else {
  1697. TclEmitOpcode(INST_LAPPEND_ARRAY_STK, envPtr);
  1698.     }
  1699. }
  1700.     } else {
  1701. TclEmitOpcode(INST_LAPPEND_STK, envPtr);
  1702.     }
  1703.     done:
  1704.     return code;
  1705. }
  1706. /*
  1707.  *----------------------------------------------------------------------
  1708.  *
  1709.  * TclCompileLindexCmd --
  1710.  *
  1711.  * Procedure called to compile the "lindex" command.
  1712.  *
  1713.  * Results:
  1714.  * The return value is a standard Tcl result, which is TCL_OK if the
  1715.  * compilation was successful.  If the command cannot be byte-compiled,
  1716.  * TCL_OUT_LINE_COMPILE is returned.  If an error occurs then the
  1717.  * interpreter's result contains an error message, and TCL_ERROR is
  1718.  * returned.
  1719.  *
  1720.  * Side effects:
  1721.  * Instructions are added to envPtr to execute the "lindex" command
  1722.  * at runtime.
  1723.  *
  1724.  *----------------------------------------------------------------------
  1725.  */
  1726. int
  1727. TclCompileLindexCmd(interp, parsePtr, envPtr)
  1728.     Tcl_Interp *interp; /* Used for error reporting. */
  1729.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  1730.  * command created by Tcl_ParseCommand. */
  1731.     CompileEnv *envPtr; /* Holds resulting instructions. */
  1732. {
  1733.     Tcl_Token *varTokenPtr;
  1734.     int code, i;
  1735. #ifdef TCL_TIP280
  1736.     /* TIP #280 : Remember the per-word line information of the current
  1737.      * command. An index is used instead of a pointer as recursive compilation
  1738.      * may reallocate, i.e. move, the array. This is also the reason to save
  1739.      * the nuloc now, it may change during the course of the function.
  1740.      */
  1741.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  1742.     int        eclIndex = mapPtr->nuloc - 1;
  1743. #endif
  1744.     int numWords;
  1745.     numWords = parsePtr->numWords;
  1746.     /*
  1747.      * Quit if too few args
  1748.      */
  1749.     if ( numWords <= 1 ) {
  1750. return TCL_OUT_LINE_COMPILE;
  1751.     }
  1752.     varTokenPtr = parsePtr->tokenPtr
  1753. + (parsePtr->tokenPtr->numComponents + 1);
  1754.     
  1755.     /*
  1756.      * Push the operands onto the stack.
  1757.      */
  1758.     for ( i = 1 ; i < numWords ; i++ ) {
  1759. if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  1760.     TclEmitPush(
  1761.     TclRegisterNewLiteral( envPtr, varTokenPtr[1].start,
  1762.     varTokenPtr[1].size), envPtr);
  1763. } else {
  1764. #ifdef TCL_TIP280
  1765.     envPtr->line = mapPtr->loc [eclIndex].line [i];
  1766. #endif
  1767.     code = TclCompileTokens(interp, varTokenPtr+1,
  1768.     varTokenPtr->numComponents, envPtr);
  1769.     if (code != TCL_OK) {
  1770. return code;
  1771.     }
  1772. }
  1773. varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  1774.     }
  1775.     /*
  1776.      * Emit INST_LIST_INDEX if objc==3, or INST_LIST_INDEX_MULTI
  1777.      * if there are multiple index args.
  1778.      */
  1779.     if ( numWords == 3 ) {
  1780. TclEmitOpcode( INST_LIST_INDEX, envPtr );
  1781.     } else {
  1782.   TclEmitInstInt4( INST_LIST_INDEX_MULTI, numWords-1, envPtr );
  1783.     }
  1784.     return TCL_OK;
  1785. }
  1786. /*
  1787.  *----------------------------------------------------------------------
  1788.  *
  1789.  * TclCompileListCmd --
  1790.  *
  1791.  * Procedure called to compile the "list" command.
  1792.  *
  1793.  * Results:
  1794.  * The return value is a standard Tcl result, which is normally TCL_OK
  1795.  * unless there was an error while parsing string. If an error occurs
  1796.  * then the interpreter's result contains a standard error message. If
  1797.  * complation fails because the command requires a second level of
  1798.  * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the
  1799.  * command should be compiled "out of line" by emitting code to
  1800.  * invoke its command procedure (Tcl_ListObjCmd) at runtime.
  1801.  *
  1802.  * Side effects:
  1803.  * Instructions are added to envPtr to execute the "list" command
  1804.  * at runtime.
  1805.  *
  1806.  *----------------------------------------------------------------------
  1807.  */
  1808. int
  1809. TclCompileListCmd(interp, parsePtr, envPtr)
  1810.     Tcl_Interp *interp; /* Used for error reporting. */
  1811.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  1812.  * command created by Tcl_ParseCommand. */
  1813.     CompileEnv *envPtr; /* Holds resulting instructions. */
  1814. {
  1815. #ifdef TCL_TIP280
  1816.     /* TIP #280 : Remember the per-word line information of the current
  1817.      * command. An index is used instead of a pointer as recursive compilation
  1818.      * may reallocate, i.e. move, the array. This is also the reason to save
  1819.      * the nuloc now, it may change during the course of the function.
  1820.      */
  1821.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  1822.     int        eclIndex = mapPtr->nuloc - 1;
  1823. #endif
  1824.     /*
  1825.      * If we're not in a procedure, don't compile.
  1826.      */
  1827.     if (envPtr->procPtr == NULL) {
  1828. return TCL_OUT_LINE_COMPILE;
  1829.     }
  1830.     if (parsePtr->numWords == 1) {
  1831. /*
  1832.  * Empty args case
  1833.  */
  1834. TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
  1835.     } else {
  1836. /*
  1837.  * Push the all values onto the stack.
  1838.  */
  1839. Tcl_Token *valueTokenPtr;
  1840. int i, code, numWords;
  1841. numWords = parsePtr->numWords;
  1842. valueTokenPtr = parsePtr->tokenPtr
  1843.     + (parsePtr->tokenPtr->numComponents + 1);
  1844. for (i = 1; i < numWords; i++) {
  1845.     if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  1846. TclEmitPush(TclRegisterNewLiteral(envPtr,
  1847. valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr);
  1848.     } else {
  1849. #ifdef TCL_TIP280
  1850.         envPtr->line = mapPtr->loc [eclIndex].line [i];
  1851. #endif
  1852. code = TclCompileTokens(interp, valueTokenPtr+1,
  1853. valueTokenPtr->numComponents, envPtr);
  1854. if (code != TCL_OK) {
  1855.     return code;
  1856. }
  1857.     }
  1858.     valueTokenPtr = valueTokenPtr + (valueTokenPtr->numComponents + 1);
  1859. }
  1860. TclEmitInstInt4(INST_LIST, numWords - 1, envPtr);
  1861.     }
  1862.     return TCL_OK;
  1863. }
  1864. /*
  1865.  *----------------------------------------------------------------------
  1866.  *
  1867.  * TclCompileLlengthCmd --
  1868.  *
  1869.  * Procedure called to compile the "llength" command.
  1870.  *
  1871.  * Results:
  1872.  * The return value is a standard Tcl result, which is TCL_OK if the
  1873.  * compilation was successful.  If the command cannot be byte-compiled,
  1874.  * TCL_OUT_LINE_COMPILE is returned.  If an error occurs then the
  1875.  * interpreter's result contains an error message, and TCL_ERROR is
  1876.  * returned.
  1877.  *
  1878.  * Side effects:
  1879.  * Instructions are added to envPtr to execute the "llength" command
  1880.  * at runtime.
  1881.  *
  1882.  *----------------------------------------------------------------------
  1883.  */
  1884. int
  1885. TclCompileLlengthCmd(interp, parsePtr, envPtr)
  1886.     Tcl_Interp *interp; /* Used for error reporting. */
  1887.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  1888.  * command created by Tcl_ParseCommand. */
  1889.     CompileEnv *envPtr; /* Holds resulting instructions. */
  1890. {
  1891.     Tcl_Token *varTokenPtr;
  1892.     int code;
  1893. #ifdef TCL_TIP280
  1894.     /* TIP #280 : Remember the per-word line information of the current
  1895.      * command. An index is used instead of a pointer as recursive compilation
  1896.      * may reallocate, i.e. move, the array. This is also the reason to save
  1897.      * the nuloc now, it may change during the course of the function.
  1898.      */
  1899.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  1900.     int        eclIndex = mapPtr->nuloc - 1;
  1901. #endif
  1902.     if (parsePtr->numWords != 2) {
  1903. Tcl_SetResult(interp, "wrong # args: should be "llength list"",
  1904. TCL_STATIC);
  1905. return TCL_ERROR;
  1906.     }
  1907.     varTokenPtr = parsePtr->tokenPtr
  1908. + (parsePtr->tokenPtr->numComponents + 1);
  1909.     if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  1910. /*
  1911.  * We could simply count the number of elements here and push
  1912.  * that value, but that is too rare a case to waste the code space.
  1913.  */
  1914. TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start,
  1915. varTokenPtr[1].size), envPtr);
  1916.     } else {
  1917. #ifdef TCL_TIP280
  1918.         envPtr->line = mapPtr->loc [eclIndex].line [1];
  1919. #endif
  1920. code = TclCompileTokens(interp, varTokenPtr+1,
  1921. varTokenPtr->numComponents, envPtr);
  1922. if (code != TCL_OK) {
  1923.     return code;
  1924. }
  1925.     }
  1926.     TclEmitOpcode(INST_LIST_LENGTH, envPtr);
  1927.     return TCL_OK;
  1928. }
  1929. /*
  1930.  *----------------------------------------------------------------------
  1931.  *
  1932.  * TclCompileLsetCmd --
  1933.  *
  1934.  * Procedure called to compile the "lset" command.
  1935.  *
  1936.  * Results:
  1937.  * The return value is a standard Tcl result, which is TCL_OK if
  1938.  * the compilation was successful.  If the "lset" command is too
  1939.  * complex for this function, then TCL_OUT_LINE_COMPILE is returned,
  1940.  * indicating that the command should be compiled "out of line"
  1941.  * (that is, not byte-compiled).  If an error occurs, TCL_ERROR is
  1942.  * returned, and the interpreter result contains an error message.
  1943.  *
  1944.  * Side effects:
  1945.  * Instructions are added to envPtr to execute the "lset" command
  1946.  * at runtime.
  1947.  *
  1948.  * The general template for execution of the "lset" command is:
  1949.  * (1) Instructions to push the variable name, unless the
  1950.  *     variable is local to the stack frame.
  1951.  * (2) If the variable is an array element, instructions
  1952.  *     to push the array element name.
  1953.  * (3) Instructions to push each of zero or more "index" arguments
  1954.  *     to the stack, followed with the "newValue" element.
  1955.  * (4) Instructions to duplicate the variable name and/or array
  1956.  *     element name onto the top of the stack, if either was
  1957.  *     pushed at steps (1) and (2).
  1958.  * (5) The appropriate INST_LOAD_* instruction to place the
  1959.  *     original value of the list variable at top of stack.
  1960.  * (6) At this point, the stack contains:
  1961.  *      varName? arrayElementName? index1 index2 ... newValue oldList
  1962.  *     The compiler emits one of INST_LSET_FLAT or INST_LSET_LIST
  1963.  *     according as whether there is exactly one index element (LIST)
  1964.  *     or either zero or else two or more (FLAT).  This instruction
  1965.  *     removes everything from the stack except for the two names
  1966.  *     and pushes the new value of the variable.
  1967.  * (7) Finally, INST_STORE_* stores the new value in the variable
  1968.  *     and cleans up the stack.
  1969.  *
  1970.  *----------------------------------------------------------------------
  1971.  */
  1972. int
  1973. TclCompileLsetCmd( interp, parsePtr, envPtr )
  1974.     Tcl_Interp* interp; /* Tcl interpreter for error reporting */
  1975.     Tcl_Parse* parsePtr; /* Points to a parse structure for
  1976.  * the command */
  1977.     CompileEnv* envPtr; /* Holds the resulting instructions */
  1978. {
  1979.     int tempDepth; /* Depth used for emitting one part
  1980.  * of the code burst. */
  1981.     Tcl_Token* varTokenPtr; /* Pointer to the Tcl_Token representing
  1982.  * the parse of the variable name */
  1983.     int result; /* Status return from library calls */
  1984.     int localIndex; /* Index of var in local var table */
  1985.     int simpleVarName; /* Flag == 1 if var name is simple */
  1986.     int isScalar; /* Flag == 1 if scalar, 0 if array */
  1987.     int i;
  1988. #ifdef TCL_TIP280
  1989.     /* TIP #280 : Remember the per-word line information of the current
  1990.      * command. An index is used instead of a pointer as recursive compilation
  1991.      * may reallocate, i.e. move, the array. This is also the reason to save
  1992.      * the nuloc now, it may change during the course of the function.
  1993.      */
  1994.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  1995.     int        eclIndex = mapPtr->nuloc - 1;
  1996. #endif
  1997.     /* Check argument count */
  1998.     if ( parsePtr->numWords < 3 ) {
  1999. /* Fail at run time, not in compilation */
  2000. return TCL_OUT_LINE_COMPILE;
  2001.     }
  2002.     /*
  2003.      * Decide if we can use a frame slot for the var/array name or if we
  2004.      * need to emit code to compute and push the name at runtime. We use a
  2005.      * frame slot (entry in the array of local vars) if we are compiling a
  2006.      * procedure body and if the name is simple text that does not include
  2007.      * namespace qualifiers. 
  2008.      */
  2009.     varTokenPtr = parsePtr->tokenPtr
  2010.     + (parsePtr->tokenPtr->numComponents + 1);
  2011.     result = TclPushVarName( interp, varTokenPtr, envPtr, 
  2012. #ifndef TCL_TIP280
  2013.             TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar );
  2014. #else
  2015.             TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar,
  2016.     mapPtr->loc [eclIndex].line [1]);
  2017. #endif
  2018.     if (result != TCL_OK) {
  2019. return result;
  2020.     }
  2021.     /* Push the "index" args and the new element value. */
  2022.     for ( i = 2; i < parsePtr->numWords; ++i ) {
  2023. /* Advance to next arg */
  2024. varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2025. /* Push an arg */
  2026. if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  2027.     TclEmitPush(TclRegisterNewLiteral( envPtr, varTokenPtr[1].start,
  2028.     varTokenPtr[1].size), envPtr);
  2029. } else {
  2030. #ifdef TCL_TIP280
  2031.     envPtr->line = mapPtr->loc [eclIndex].line [i];
  2032. #endif
  2033.     result = TclCompileTokens(interp, varTokenPtr+1,
  2034.       varTokenPtr->numComponents, envPtr);
  2035.     if ( result != TCL_OK ) {
  2036. return result;
  2037.     }
  2038. }
  2039.     }
  2040.     /*
  2041.      * Duplicate the variable name if it's been pushed.  
  2042.      */
  2043.     if ( !simpleVarName || localIndex < 0 ) {
  2044. if ( !simpleVarName || isScalar ) {
  2045.     tempDepth = parsePtr->numWords - 2;
  2046. } else {
  2047.     tempDepth = parsePtr->numWords - 1;
  2048. }
  2049. TclEmitInstInt4( INST_OVER, tempDepth, envPtr );
  2050.     }
  2051.     /*
  2052.      * Duplicate an array index if one's been pushed
  2053.      */
  2054.     if ( simpleVarName && !isScalar ) {
  2055. if ( localIndex < 0 ) {
  2056.     tempDepth = parsePtr->numWords - 1;
  2057. } else {
  2058.     tempDepth = parsePtr->numWords - 2;
  2059. }
  2060. TclEmitInstInt4( INST_OVER, tempDepth, envPtr );
  2061.     }
  2062.     /*
  2063.      * Emit code to load the variable's value.
  2064.      */
  2065.     if ( !simpleVarName ) {
  2066. TclEmitOpcode( INST_LOAD_STK, envPtr );
  2067.     } else if ( isScalar ) {
  2068. if ( localIndex < 0 ) {
  2069.     TclEmitOpcode( INST_LOAD_SCALAR_STK, envPtr );
  2070. } else if ( localIndex < 0x100 ) {
  2071.     TclEmitInstInt1( INST_LOAD_SCALAR1, localIndex, envPtr );
  2072. } else {
  2073.     TclEmitInstInt4( INST_LOAD_SCALAR4, localIndex, envPtr );
  2074. }
  2075.     } else {
  2076. if ( localIndex < 0 ) {
  2077.     TclEmitOpcode( INST_LOAD_ARRAY_STK, envPtr );
  2078. } else if ( localIndex < 0x100 ) {
  2079.     TclEmitInstInt1( INST_LOAD_ARRAY1, localIndex, envPtr );
  2080. } else {
  2081.     TclEmitInstInt4( INST_LOAD_ARRAY4, localIndex, envPtr );
  2082. }
  2083.     }
  2084.     /*
  2085.      * Emit the correct variety of 'lset' instruction
  2086.      */
  2087.     if ( parsePtr->numWords == 4 ) {
  2088. TclEmitOpcode( INST_LSET_LIST, envPtr );
  2089.     } else {
  2090. TclEmitInstInt4( INST_LSET_FLAT, (parsePtr->numWords - 1), envPtr );
  2091.     }
  2092.     /*
  2093.      * Emit code to put the value back in the variable
  2094.      */
  2095.     if ( !simpleVarName ) {
  2096. TclEmitOpcode( INST_STORE_STK, envPtr );
  2097.     } else if ( isScalar ) {
  2098. if ( localIndex < 0 ) {
  2099.     TclEmitOpcode( INST_STORE_SCALAR_STK, envPtr );
  2100. } else if ( localIndex < 0x100 ) {
  2101.     TclEmitInstInt1( INST_STORE_SCALAR1, localIndex, envPtr );
  2102. } else {
  2103.     TclEmitInstInt4( INST_STORE_SCALAR4, localIndex, envPtr );
  2104. }
  2105.     } else {
  2106. if ( localIndex < 0 ) {
  2107.     TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr );
  2108. } else if ( localIndex < 0x100 ) {
  2109.     TclEmitInstInt1( INST_STORE_ARRAY1, localIndex, envPtr );
  2110. } else {
  2111.     TclEmitInstInt4( INST_STORE_ARRAY4, localIndex, envPtr );
  2112. }
  2113.     }
  2114.     
  2115.     return TCL_OK;
  2116. }
  2117. /*
  2118.  *----------------------------------------------------------------------
  2119.  *
  2120.  * TclCompileRegexpCmd --
  2121.  *
  2122.  * Procedure called to compile the "regexp" command.
  2123.  *
  2124.  * Results:
  2125.  * The return value is a standard Tcl result, which is TCL_OK if
  2126.  * the compilation was successful.  If the "regexp" command is too
  2127.  * complex for this function, then TCL_OUT_LINE_COMPILE is returned,
  2128.  * indicating that the command should be compiled "out of line"
  2129.  * (that is, not byte-compiled).  If an error occurs, TCL_ERROR is
  2130.  * returned, and the interpreter result contains an error message.
  2131.  *
  2132.  * Side effects:
  2133.  * Instructions are added to envPtr to execute the "regexp" command
  2134.  * at runtime.
  2135.  *
  2136.  *----------------------------------------------------------------------
  2137.  */
  2138. int
  2139. TclCompileRegexpCmd(interp, parsePtr, envPtr)
  2140.     Tcl_Interp* interp; /* Tcl interpreter for error reporting */
  2141.     Tcl_Parse* parsePtr; /* Points to a parse structure for
  2142.  * the command */
  2143.     CompileEnv* envPtr; /* Holds the resulting instructions */
  2144. {
  2145.     Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing
  2146.  * the parse of the RE or string */
  2147.     int i, len, code, nocase, anchorLeft, anchorRight, start;
  2148.     char *str;
  2149. #ifdef TCL_TIP280
  2150.     /* TIP #280 : Remember the per-word line information of the current
  2151.      * command. An index is used instead of a pointer as recursive compilation
  2152.      * may reallocate, i.e. move, the array. This is also the reason to save
  2153.      * the nuloc now, it may change during the course of the function.
  2154.      */
  2155.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  2156.     int        eclIndex = mapPtr->nuloc - 1;
  2157. #endif
  2158.     /*
  2159.      * We are only interested in compiling simple regexp cases.
  2160.      * Currently supported compile cases are:
  2161.      *   regexp ?-nocase? ?--? staticString $var
  2162.      *   regexp ?-nocase? ?--? {^staticString$} $var
  2163.      */
  2164.     if (parsePtr->numWords < 3) {
  2165. return TCL_OUT_LINE_COMPILE;
  2166.     }
  2167.     nocase = 0;
  2168.     varTokenPtr = parsePtr->tokenPtr;
  2169.     /*
  2170.      * We only look for -nocase and -- as options.  Everything else
  2171.      * gets pushed to runtime execution.  This is different than regexp's
  2172.      * runtime option handling, but satisfies our stricter needs.
  2173.      */
  2174.     for (i = 1; i < parsePtr->numWords - 2; i++) {
  2175. varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2176. if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
  2177.     /* Not a simple string - punt to runtime. */
  2178.     return TCL_OUT_LINE_COMPILE;
  2179. }
  2180. str = (char *) varTokenPtr[1].start;
  2181. len = varTokenPtr[1].size;
  2182. if ((len == 2) && (str[0] == '-') && (str[1] == '-')) {
  2183.     i++;
  2184.     break;
  2185. } else if ((len > 1)
  2186. && (strncmp(str, "-nocase", (unsigned) len) == 0)) {
  2187.     nocase = 1;
  2188. } else {
  2189.     /* Not an option we recognize. */
  2190.     return TCL_OUT_LINE_COMPILE;
  2191. }
  2192.     }
  2193.     if ((parsePtr->numWords - i) != 2) {
  2194. /* We don't support capturing to variables */
  2195. return TCL_OUT_LINE_COMPILE;
  2196.     }
  2197.     /*
  2198.      * Get the regexp string.  If it is not a simple string, punt to runtime.
  2199.      * If it has a '-', it could be an incorrectly formed regexp command.
  2200.      */
  2201.     varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2202.     str = (char *) varTokenPtr[1].start;
  2203.     len = varTokenPtr[1].size;
  2204.     if ((varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) || (*str == '-')) {
  2205. return TCL_OUT_LINE_COMPILE;
  2206.     }
  2207.     if (len == 0) {
  2208. /*
  2209.  * The semantics of regexp are always match on re == "".
  2210.  */
  2211. TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
  2212. return TCL_OK;
  2213.     }
  2214.     /*
  2215.      * Make a copy of the string that is null-terminated for checks which
  2216.      * require such.
  2217.      */
  2218.     str = (char *) ckalloc((unsigned) len + 1);
  2219.     strncpy(str, varTokenPtr[1].start, (size_t) len);
  2220.     str[len] = '';
  2221.     start = 0;
  2222.     /*
  2223.      * Check for anchored REs (ie ^foo$), so we can use string equal if
  2224.      * possible. Do not alter the start of str so we can free it correctly.
  2225.      */
  2226.     if (str[0] == '^') {
  2227. start++;
  2228. anchorLeft = 1;
  2229.     } else {
  2230. anchorLeft = 0;
  2231.     }
  2232.     if ((str[len-1] == '$') && ((len == 1) || (str[len-2] != '\'))) {
  2233. anchorRight = 1;
  2234. str[--len] = '';
  2235.     } else {
  2236. anchorRight = 0;
  2237.     }
  2238.     /*
  2239.      * On the first (pattern) arg, check to see if any RE special characters
  2240.      * are in the word.  If not, this is the same as 'string equal'.
  2241.      */
  2242.     if ((len > (1+start)) && (str[start] == '.') && (str[start+1] == '*')) {
  2243. start += 2;
  2244. anchorLeft = 0;
  2245.     }
  2246.     if ((len > (2+start)) && (str[len-3] != '\')
  2247.     && (str[len-2] == '.') && (str[len-1] == '*')) {
  2248. len -= 2;
  2249. str[len] = '';
  2250. anchorRight = 0;
  2251.     }
  2252.     /*
  2253.      * Don't do anything with REs with other special chars.  Also check if
  2254.      * this is a bad RE (do this at the end because it can be expensive).
  2255.      * If so, let it complain at runtime.
  2256.      */
  2257.     if ((strpbrk(str + start, "*+?{}()[].\|^$") != NULL)
  2258.     || (Tcl_RegExpCompile(NULL, str) == NULL)) {
  2259. ckfree((char *) str);
  2260. return TCL_OUT_LINE_COMPILE;
  2261.     }
  2262.     if (anchorLeft && anchorRight) {
  2263. TclEmitPush(TclRegisterNewLiteral(envPtr, str+start, len-start),
  2264. envPtr);
  2265.     } else {
  2266. /*
  2267.  * This needs to find the substring anywhere in the string, so
  2268.  * use string match and *foo*, with appropriate anchoring.
  2269.  */
  2270. char *newStr  = ckalloc((unsigned) len + 3);
  2271. len -= start;
  2272. if (anchorLeft) {
  2273.     strncpy(newStr, str + start, (size_t) len);
  2274. } else {
  2275.     newStr[0] = '*';
  2276.     strncpy(newStr + 1, str + start, (size_t) len++);
  2277. }
  2278. if (!anchorRight) {
  2279.     newStr[len++] = '*';
  2280. }
  2281. newStr[len] = '';
  2282. TclEmitPush(TclRegisterNewLiteral(envPtr, newStr, len), envPtr);
  2283. ckfree((char *) newStr);
  2284.     }
  2285.     ckfree((char *) str);
  2286.     /*
  2287.      * Push the string arg
  2288.      */
  2289.     varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2290.     if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  2291. TclEmitPush(TclRegisterNewLiteral(envPtr,
  2292. varTokenPtr[1].start, varTokenPtr[1].size), envPtr);
  2293.     } else {
  2294. #ifdef TCL_TIP280
  2295.         envPtr->line = mapPtr->loc [eclIndex].line [parsePtr->numWords-1];
  2296. #endif
  2297. code = TclCompileTokens(interp, varTokenPtr+1,
  2298. varTokenPtr->numComponents, envPtr);
  2299. if (code != TCL_OK) {
  2300.     return code;
  2301. }
  2302.     }
  2303.     if (anchorLeft && anchorRight && !nocase) {
  2304. TclEmitOpcode(INST_STR_EQ, envPtr);
  2305.     } else {
  2306. TclEmitInstInt1(INST_STR_MATCH, nocase, envPtr);
  2307.     }
  2308.     return TCL_OK;
  2309. }
  2310. /*
  2311.  *----------------------------------------------------------------------
  2312.  *
  2313.  * TclCompileReturnCmd --
  2314.  *
  2315.  * Procedure called to compile the "return" command.
  2316.  *
  2317.  * Results:
  2318.  * The return value is a standard Tcl result, which is TCL_OK if the
  2319.  * compilation was successful.  If the particular return command is
  2320.  * too complex for this function (ie, return with any flags like "-code"
  2321.  * or "-errorinfo"), TCL_OUT_LINE_COMPILE is returned, indicating that
  2322.  * the command should be compiled "out of line" (eg, not byte compiled).
  2323.  * If an error occurs then the interpreter's result contains a standard
  2324.  * error message.
  2325.  *
  2326.  * Side effects:
  2327.  * Instructions are added to envPtr to execute the "return" command
  2328.  * at runtime.
  2329.  *
  2330.  *----------------------------------------------------------------------
  2331.  */
  2332. int
  2333. TclCompileReturnCmd(interp, parsePtr, envPtr)
  2334.     Tcl_Interp *interp; /* Used for error reporting. */
  2335.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  2336.  * command created by Tcl_ParseCommand. */
  2337.     CompileEnv *envPtr; /* Holds resulting instructions. */
  2338. {
  2339.     Tcl_Token *varTokenPtr;
  2340.     int code;
  2341.     int index = envPtr->exceptArrayNext - 1;
  2342. #ifdef TCL_TIP280
  2343.     /* TIP #280 : Remember the per-word line information of the current
  2344.      * command. An index is used instead of a pointer as recursive compilation
  2345.      * may reallocate, i.e. move, the array. This is also the reason to save
  2346.      * the nuloc now, it may change during the course of the function.
  2347.      */
  2348.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  2349.     int        eclIndex = mapPtr->nuloc - 1;
  2350. #endif
  2351.     /*
  2352.      * If we're not in a procedure, don't compile.
  2353.      */
  2354.     if (envPtr->procPtr == NULL) {
  2355. return TCL_OUT_LINE_COMPILE;
  2356.     }
  2357.     /*
  2358.      * Look back through the ExceptionRanges of the current CompileEnv,
  2359.      * from exceptArrayPtr[(exceptArrayNext - 1)] down to 
  2360.      * exceptArrayPtr[0] to see if any of them is an enclosing [catch].
  2361.      * If there's an enclosing [catch], don't compile.
  2362.      */
  2363.     while (index >= 0) {
  2364. ExceptionRange range = envPtr->exceptArrayPtr[index];
  2365. if ((range.type == CATCH_EXCEPTION_RANGE) 
  2366. && (range.catchOffset == -1)) {
  2367.     return TCL_OUT_LINE_COMPILE;
  2368. }
  2369. index--;
  2370.     }
  2371.     switch (parsePtr->numWords) {
  2372. case 1: {
  2373.     /*
  2374.      * Simple case:  [return]
  2375.      * Just push the literal string "".
  2376.      */
  2377.     TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
  2378.     break;
  2379. }
  2380. case 2: {
  2381.     /*
  2382.      * More complex cases:
  2383.      * [return "foo"]
  2384.      * [return $value]
  2385.      * [return [otherCmd]]
  2386.      */
  2387.     varTokenPtr = parsePtr->tokenPtr
  2388. + (parsePtr->tokenPtr->numComponents + 1);
  2389.     if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  2390. /*
  2391.  * [return "foo"] case:  the parse token is a simple word,
  2392.  * so just push it.
  2393.  */
  2394. TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start,
  2395. varTokenPtr[1].size), envPtr);
  2396.     } else {
  2397. /*
  2398.  * Parse token is more complex, so compile it; this handles the
  2399.  * variable reference and nested command cases.  If the
  2400.  * parse token can be byte-compiled, then this instance of
  2401.  * "return" will be byte-compiled; otherwise it will be
  2402.  * out line compiled.
  2403.  */
  2404. #ifdef TCL_TIP280
  2405.         envPtr->line = mapPtr->loc [eclIndex].line [1];
  2406. #endif
  2407. code = TclCompileTokens(interp, varTokenPtr+1,
  2408. varTokenPtr->numComponents, envPtr);
  2409. if (code != TCL_OK) {
  2410.     return code;
  2411. }
  2412.     }
  2413.     break;
  2414. }
  2415. default: {
  2416.     /*
  2417.      * Most complex return cases: everything else, including
  2418.      * [return -code error], etc.
  2419.      */
  2420.     return TCL_OUT_LINE_COMPILE;
  2421. }
  2422.     }
  2423.     /*
  2424.      * The INST_DONE opcode actually causes the branching out of the
  2425.      * subroutine, and takes the top stack item as the return result
  2426.      * (which is why we pushed the value above).
  2427.      */
  2428.     TclEmitOpcode(INST_DONE, envPtr);
  2429.     return TCL_OK;
  2430. }
  2431. /*
  2432.  *----------------------------------------------------------------------
  2433.  *
  2434.  * TclCompileSetCmd --
  2435.  *
  2436.  * Procedure called to compile the "set" command.
  2437.  *
  2438.  * Results:
  2439.  * The return value is a standard Tcl result, which is normally TCL_OK
  2440.  * unless there was an error while parsing string. If an error occurs
  2441.  * then the interpreter's result contains a standard error message. If
  2442.  * complation fails because the set command requires a second level of
  2443.  * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the
  2444.  * set command should be compiled "out of line" by emitting code to
  2445.  * invoke its command procedure (Tcl_SetCmd) at runtime.
  2446.  *
  2447.  * Side effects:
  2448.  * Instructions are added to envPtr to execute the "set" command
  2449.  * at runtime.
  2450.  *
  2451.  *----------------------------------------------------------------------
  2452.  */
  2453. int
  2454. TclCompileSetCmd(interp, parsePtr, envPtr)
  2455.     Tcl_Interp *interp; /* Used for error reporting. */
  2456.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  2457.  * command created by Tcl_ParseCommand. */
  2458.     CompileEnv *envPtr; /* Holds resulting instructions. */
  2459. {
  2460.     Tcl_Token *varTokenPtr, *valueTokenPtr;
  2461.     int isAssignment, isScalar, simpleVarName, localIndex, numWords;
  2462.     int code = TCL_OK;
  2463. #ifdef TCL_TIP280
  2464.     /* TIP #280 : Remember the per-word line information of the current
  2465.      * command. An index is used instead of a pointer as recursive compilation
  2466.      * may reallocate, i.e. move, the array. This is also the reason to save
  2467.      * the nuloc now, it may change during the course of the function.
  2468.      */
  2469.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  2470.     int        eclIndex = mapPtr->nuloc - 1;
  2471. #endif
  2472.     numWords = parsePtr->numWords;
  2473.     if ((numWords != 2) && (numWords != 3)) {
  2474. Tcl_ResetResult(interp);
  2475. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  2476.         "wrong # args: should be "set varName ?newValue?"", -1);
  2477.         return TCL_ERROR;
  2478.     }
  2479.     isAssignment = (numWords == 3);
  2480.     /*
  2481.      * Decide if we can use a frame slot for the var/array name or if we
  2482.      * need to emit code to compute and push the name at runtime. We use a
  2483.      * frame slot (entry in the array of local vars) if we are compiling a
  2484.      * procedure body and if the name is simple text that does not include
  2485.      * namespace qualifiers. 
  2486.      */
  2487.     varTokenPtr = parsePtr->tokenPtr
  2488.     + (parsePtr->tokenPtr->numComponents + 1);
  2489.     code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR,
  2490. #ifndef TCL_TIP280
  2491.     &localIndex, &simpleVarName, &isScalar);
  2492. #else
  2493.     &localIndex, &simpleVarName, &isScalar,
  2494.     mapPtr->loc [eclIndex].line [1]);
  2495. #endif
  2496.     if (code != TCL_OK) {
  2497. goto done;
  2498.     }
  2499.     /*
  2500.      * If we are doing an assignment, push the new value.
  2501.      */
  2502.     if (isAssignment) {
  2503. valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2504. if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  2505.     TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start,
  2506.     valueTokenPtr[1].size), envPtr);
  2507. } else {
  2508. #ifdef TCL_TIP280
  2509.     envPtr->line = mapPtr->loc [eclIndex].line [2];
  2510. #endif
  2511.     code = TclCompileTokens(interp, valueTokenPtr+1,
  2512.             valueTokenPtr->numComponents, envPtr);
  2513.     if (code != TCL_OK) {
  2514. goto done;
  2515.     }
  2516. }
  2517.     }
  2518.     /*
  2519.      * Emit instructions to set/get the variable.
  2520.      */
  2521.     if (simpleVarName) {
  2522. if (isScalar) {
  2523.     if (localIndex >= 0) {
  2524. if (localIndex <= 255) {
  2525.     TclEmitInstInt1((isAssignment?
  2526.             INST_STORE_SCALAR1 : INST_LOAD_SCALAR1),
  2527.     localIndex, envPtr);
  2528. } else {
  2529.     TclEmitInstInt4((isAssignment?
  2530.     INST_STORE_SCALAR4 : INST_LOAD_SCALAR4),
  2531.     localIndex, envPtr);
  2532. }
  2533.     } else {
  2534. TclEmitOpcode((isAssignment?
  2535.         INST_STORE_SCALAR_STK : INST_LOAD_SCALAR_STK), envPtr);
  2536.     }
  2537. } else {
  2538.     if (localIndex >= 0) {
  2539. if (localIndex <= 255) {
  2540.     TclEmitInstInt1((isAssignment?
  2541.             INST_STORE_ARRAY1 : INST_LOAD_ARRAY1),
  2542.     localIndex, envPtr);
  2543. } else {
  2544.     TclEmitInstInt4((isAssignment?
  2545.     INST_STORE_ARRAY4 : INST_LOAD_ARRAY4),
  2546.     localIndex, envPtr);
  2547. }
  2548.     } else {
  2549. TclEmitOpcode((isAssignment?
  2550.         INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK), envPtr);
  2551.     }
  2552. }
  2553.     } else {
  2554. TclEmitOpcode((isAssignment? INST_STORE_STK : INST_LOAD_STK), envPtr);
  2555.     }
  2556.     done:
  2557.     return code;
  2558. }
  2559. /*
  2560.  *----------------------------------------------------------------------
  2561.  *
  2562.  * TclCompileStringCmd --
  2563.  *
  2564.  * Procedure called to compile the "string" command.
  2565.  *
  2566.  * Results:
  2567.  * The return value is a standard Tcl result, which is TCL_OK if the
  2568.  * compilation was successful.  If the command cannot be byte-compiled,
  2569.  * TCL_OUT_LINE_COMPILE is returned.  If an error occurs then the
  2570.  * interpreter's result contains an error message, and TCL_ERROR is
  2571.  * returned.
  2572.  *
  2573.  * Side effects:
  2574.  * Instructions are added to envPtr to execute the "string" command
  2575.  * at runtime.
  2576.  *
  2577.  *----------------------------------------------------------------------
  2578.  */
  2579. int
  2580. TclCompileStringCmd(interp, parsePtr, envPtr)
  2581.     Tcl_Interp *interp; /* Used for error reporting. */
  2582.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  2583.  * command created by Tcl_ParseCommand. */
  2584.     CompileEnv *envPtr; /* Holds resulting instructions. */
  2585. {
  2586.     Tcl_Token *opTokenPtr, *varTokenPtr;
  2587.     Tcl_Obj *opObj;
  2588.     int index;
  2589.     int code;
  2590.     
  2591.     static CONST char *options[] = {
  2592. "bytelength", "compare", "equal", "first",
  2593. "index", "is", "last", "length",
  2594. "map", "match", "range", "repeat",
  2595. "replace", "tolower", "toupper", "totitle",
  2596. "trim", "trimleft", "trimright",
  2597. "wordend", "wordstart", (char *) NULL
  2598.     };
  2599.     enum options {
  2600. STR_BYTELENGTH, STR_COMPARE, STR_EQUAL, STR_FIRST,
  2601. STR_INDEX, STR_IS, STR_LAST, STR_LENGTH,
  2602. STR_MAP, STR_MATCH, STR_RANGE, STR_REPEAT,
  2603. STR_REPLACE, STR_TOLOWER, STR_TOUPPER, STR_TOTITLE,
  2604. STR_TRIM, STR_TRIMLEFT, STR_TRIMRIGHT,
  2605. STR_WORDEND, STR_WORDSTART
  2606.     };   
  2607. #ifdef TCL_TIP280
  2608.     /* TIP #280 : Remember the per-word line information of the current
  2609.      * command. An index is used instead of a pointer as recursive compilation
  2610.      * may reallocate, i.e. move, the array. This is also the reason to save
  2611.      * the nuloc now, it may change during the course of the function.
  2612.      */
  2613.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  2614.     int        eclIndex = mapPtr->nuloc - 1;
  2615. #endif
  2616.     if (parsePtr->numWords < 2) {
  2617. /* Fail at run time, not in compilation */
  2618. return TCL_OUT_LINE_COMPILE;
  2619.     }
  2620.     opTokenPtr = parsePtr->tokenPtr
  2621. + (parsePtr->tokenPtr->numComponents + 1);
  2622.     opObj = Tcl_NewStringObj(opTokenPtr->start, opTokenPtr->size);
  2623.     if (Tcl_GetIndexFromObj(interp, opObj, options, "option", 0,
  2624.     &index) != TCL_OK) {
  2625. Tcl_DecrRefCount(opObj);
  2626. Tcl_ResetResult(interp);
  2627. return TCL_OUT_LINE_COMPILE;
  2628.     }
  2629.     Tcl_DecrRefCount(opObj);
  2630.     varTokenPtr = opTokenPtr + (opTokenPtr->numComponents + 1);
  2631.     switch ((enum options) index) {
  2632. case STR_BYTELENGTH:
  2633. case STR_FIRST:
  2634. case STR_IS:
  2635. case STR_LAST:
  2636. case STR_MAP:
  2637. case STR_RANGE:
  2638. case STR_REPEAT:
  2639. case STR_REPLACE:
  2640. case STR_TOLOWER:
  2641. case STR_TOUPPER:
  2642. case STR_TOTITLE:
  2643. case STR_TRIM:
  2644. case STR_TRIMLEFT:
  2645. case STR_TRIMRIGHT:
  2646. case STR_WORDEND:
  2647. case STR_WORDSTART:
  2648.     /*
  2649.      * All other cases: compile out of line.
  2650.      */
  2651.     return TCL_OUT_LINE_COMPILE;
  2652. case STR_COMPARE: 
  2653. case STR_EQUAL: {
  2654.     int i;
  2655.     /*
  2656.      * If there are any flags to the command, we can't byte compile it
  2657.      * because the INST_STR_EQ bytecode doesn't support flags.
  2658.      */
  2659.     if (parsePtr->numWords != 4) {
  2660. return TCL_OUT_LINE_COMPILE;
  2661.     }
  2662.     /*
  2663.      * Push the two operands onto the stack.
  2664.      */
  2665.     for (i = 0; i < 2; i++) {
  2666. if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  2667.     TclEmitPush(TclRegisterNewLiteral(envPtr,
  2668.     varTokenPtr[1].start, varTokenPtr[1].size), envPtr);
  2669. } else {
  2670. #ifdef TCL_TIP280
  2671.     envPtr->line = mapPtr->loc [eclIndex].line [i];
  2672. #endif
  2673.     code = TclCompileTokens(interp, varTokenPtr+1,
  2674.     varTokenPtr->numComponents, envPtr);
  2675.     if (code != TCL_OK) {
  2676. return code;
  2677.     }
  2678. }
  2679. varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2680.     }
  2681.     TclEmitOpcode(((((enum options) index) == STR_COMPARE) ?
  2682.     INST_STR_CMP : INST_STR_EQ), envPtr);
  2683.     return TCL_OK;
  2684. }
  2685. case STR_INDEX: {
  2686.     int i;
  2687.     if (parsePtr->numWords != 4) {
  2688. /* Fail at run time, not in compilation */
  2689. return TCL_OUT_LINE_COMPILE;
  2690.     }
  2691.     /*
  2692.      * Push the two operands onto the stack.
  2693.      */
  2694.     for (i = 0; i < 2; i++) {
  2695. if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  2696.     TclEmitPush(TclRegisterNewLiteral(envPtr,
  2697.     varTokenPtr[1].start, varTokenPtr[1].size), envPtr);
  2698. } else {
  2699. #ifdef TCL_TIP280
  2700.     envPtr->line = mapPtr->loc [eclIndex].line [i];
  2701. #endif
  2702.     code = TclCompileTokens(interp, varTokenPtr+1,
  2703.     varTokenPtr->numComponents, envPtr);
  2704.     if (code != TCL_OK) {
  2705. return code;
  2706.     }
  2707. }
  2708. varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2709.     }
  2710.     TclEmitOpcode(INST_STR_INDEX, envPtr);
  2711.     return TCL_OK;
  2712. }
  2713. case STR_LENGTH: {
  2714.     if (parsePtr->numWords != 3) {
  2715. /* Fail at run time, not in compilation */
  2716. return TCL_OUT_LINE_COMPILE;
  2717.     }
  2718.     if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  2719. /*
  2720.  * Here someone is asking for the length of a static string.
  2721.  * Just push the actual character (not byte) length.
  2722.  */
  2723. char buf[TCL_INTEGER_SPACE];
  2724. int len = Tcl_NumUtfChars(varTokenPtr[1].start,
  2725. varTokenPtr[1].size);
  2726. len = sprintf(buf, "%d", len);
  2727. TclEmitPush(TclRegisterNewLiteral(envPtr, buf, len), envPtr);
  2728. return TCL_OK;
  2729.     } else {
  2730. #ifdef TCL_TIP280
  2731.         envPtr->line = mapPtr->loc [eclIndex].line [2];
  2732. #endif
  2733. code = TclCompileTokens(interp, varTokenPtr+1,
  2734. varTokenPtr->numComponents, envPtr);
  2735. if (code != TCL_OK) {
  2736.     return code;
  2737. }
  2738.     }
  2739.     TclEmitOpcode(INST_STR_LEN, envPtr);
  2740.     return TCL_OK;
  2741. }
  2742. case STR_MATCH: {
  2743.     int i, length, exactMatch = 0, nocase = 0;
  2744.     CONST char *str;
  2745.     if (parsePtr->numWords < 4 || parsePtr->numWords > 5) {
  2746. /* Fail at run time, not in compilation */
  2747. return TCL_OUT_LINE_COMPILE;
  2748.     }
  2749.     if (parsePtr->numWords == 5) {
  2750. if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
  2751.     return TCL_OUT_LINE_COMPILE;
  2752. }
  2753. str    = varTokenPtr[1].start;
  2754. length = varTokenPtr[1].size;
  2755. if ((length > 1) &&
  2756. strncmp(str, "-nocase", (size_t) length) == 0) {
  2757.     nocase = 1;
  2758. } else {
  2759.     /* Fail at run time, not in compilation */
  2760.     return TCL_OUT_LINE_COMPILE;
  2761. }
  2762. varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2763.     }
  2764.     for (i = 0; i < 2; i++) {
  2765. if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  2766.     str = varTokenPtr[1].start;
  2767.     length = varTokenPtr[1].size;
  2768.     if (!nocase && (i == 0)) {
  2769. /*
  2770.  * On the first (pattern) arg, check to see if any
  2771.  * glob special characters are in the word '*[]?\'.
  2772.  * If not, this is the same as 'string equal'.  We
  2773.  * can use strpbrk here because the glob chars are all
  2774.  * in the ascii-7 range.  If -nocase was specified,
  2775.  * we can't do this because INST_STR_EQ has no support
  2776.  * for nocase.
  2777.  */
  2778. Tcl_Obj *copy = Tcl_NewStringObj(str, length);
  2779. Tcl_IncrRefCount(copy);
  2780. exactMatch = (strpbrk(Tcl_GetString(copy),
  2781. "*[]?\") == NULL);
  2782. Tcl_DecrRefCount(copy);
  2783.     }
  2784.     TclEmitPush(
  2785.     TclRegisterNewLiteral(envPtr, str, length), envPtr);
  2786. } else {
  2787. #ifdef TCL_TIP280
  2788.     envPtr->line = mapPtr->loc [eclIndex].line [i];
  2789. #endif
  2790.     code = TclCompileTokens(interp, varTokenPtr+1,
  2791.     varTokenPtr->numComponents, envPtr);
  2792.     if (code != TCL_OK) {
  2793. return code;
  2794.     }
  2795. }
  2796. varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2797.     }
  2798.     if (exactMatch) {
  2799. TclEmitOpcode(INST_STR_EQ, envPtr);
  2800.     } else {
  2801. TclEmitInstInt1(INST_STR_MATCH, nocase, envPtr);
  2802.     }
  2803.     return TCL_OK;
  2804. }
  2805.     }
  2806.     return TCL_OK;
  2807. }
  2808. /*
  2809.  *----------------------------------------------------------------------
  2810.  *
  2811.  * TclCompileVariableCmd --
  2812.  *
  2813.  * Procedure called to reserve the local variables for the 
  2814.  *      "variable" command. The command itself is *not* compiled.
  2815.  *
  2816.  * Results:
  2817.  *      Always returns TCL_OUT_LINE_COMPILE.
  2818.  *
  2819.  * Side effects:
  2820.  *      Indexed local variables are added to the environment.
  2821.  *
  2822.  *----------------------------------------------------------------------
  2823.  */
  2824. int
  2825. TclCompileVariableCmd(interp, parsePtr, envPtr)
  2826.     Tcl_Interp *interp; /* Used for error reporting. */
  2827.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  2828.  * command created by Tcl_ParseCommand. */
  2829.     CompileEnv *envPtr; /* Holds resulting instructions. */
  2830. {
  2831.     Tcl_Token *varTokenPtr;
  2832.     int i, numWords;
  2833.     CONST char *varName, *tail;
  2834.     
  2835.     if (envPtr->procPtr == NULL) {
  2836. return TCL_OUT_LINE_COMPILE;
  2837.     }
  2838.     numWords = parsePtr->numWords;
  2839.     
  2840.     varTokenPtr = parsePtr->tokenPtr
  2841. + (parsePtr->tokenPtr->numComponents + 1);
  2842.     for (i = 1; i < numWords; i += 2) {
  2843. if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  2844.     varName = varTokenPtr[1].start;
  2845.     tail = varName + varTokenPtr[1].size - 1;
  2846.     if ((*tail == ')') || (tail < varName)) continue;
  2847.     while ((tail > varName) && ((*tail != ':') || (*(tail-1) != ':'))) {
  2848. tail--;
  2849.     }
  2850.     if ((*tail == ':') && (tail > varName)) {
  2851. tail++;
  2852.     }
  2853.     (void) TclFindCompiledLocal(tail, (tail-varName+1),
  2854.     /*create*/ 1, /*flags*/ 0, envPtr->procPtr);
  2855.     varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
  2856. }
  2857.     }
  2858.     return TCL_OUT_LINE_COMPILE;
  2859. }
  2860. /*
  2861.  *----------------------------------------------------------------------
  2862.  *
  2863.  * TclCompileWhileCmd --
  2864.  *
  2865.  * Procedure called to compile the "while" command.
  2866.  *
  2867.  * Results:
  2868.  * The return value is a standard Tcl result, which is TCL_OK if
  2869.  * compilation was successful. If an error occurs then the
  2870.  * interpreter's result contains a standard error message and TCL_ERROR
  2871.  * is returned. If compilation failed because the command is too
  2872.  * complex for TclCompileWhileCmd, TCL_OUT_LINE_COMPILE is returned
  2873.  * indicating that the while command should be compiled "out of line"
  2874.  * by emitting code to invoke its command procedure at runtime.
  2875.  *
  2876.  * Side effects:
  2877.  * Instructions are added to envPtr to execute the "while" command
  2878.  * at runtime.
  2879.  *
  2880.  *----------------------------------------------------------------------
  2881.  */
  2882. int
  2883. TclCompileWhileCmd(interp, parsePtr, envPtr)
  2884.     Tcl_Interp *interp; /* Used for error reporting. */
  2885.     Tcl_Parse *parsePtr; /* Points to a parse structure for the
  2886.  * command created by Tcl_ParseCommand. */
  2887.     CompileEnv *envPtr; /* Holds resulting instructions. */
  2888. {
  2889.     Tcl_Token *testTokenPtr, *bodyTokenPtr;
  2890.     JumpFixup jumpEvalCondFixup;
  2891.     int testCodeOffset, bodyCodeOffset, jumpDist;
  2892.     int range, code;
  2893.     char buffer[32 + TCL_INTEGER_SPACE];
  2894.     int savedStackDepth = envPtr->currStackDepth;
  2895.     int loopMayEnd = 1;         /* This is set to 0 if it is recognized as
  2896.  * an infinite loop. */
  2897.     Tcl_Obj *boolObj;
  2898.     int boolVal;
  2899. #ifdef TCL_TIP280
  2900.     /* TIP #280 : Remember the per-word line information of the current
  2901.      * command. An index is used instead of a pointer as recursive compilation
  2902.      * may reallocate, i.e. move, the array. This is also the reason to save
  2903.      * the nuloc now, it may change during the course of the function.
  2904.      */
  2905.     ExtCmdLoc* mapPtr   = envPtr->extCmdMapPtr;
  2906.     int        eclIndex = mapPtr->nuloc - 1;
  2907. #endif
  2908.     if (parsePtr->numWords != 3) {
  2909. Tcl_ResetResult(interp);
  2910. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  2911.         "wrong # args: should be "while test command"", -1);
  2912. return TCL_ERROR;
  2913.     }
  2914.     /*
  2915.      * If the test expression requires substitutions, don't compile the
  2916.      * while command inline. E.g., the expression might cause the loop to
  2917.      * never execute or execute forever, as in "while "$x < 5" {}".
  2918.      *
  2919.      * Bail out also if the body expression requires substitutions
  2920.      * in order to insure correct behaviour [Bug 219166]
  2921.      */
  2922.     testTokenPtr = parsePtr->tokenPtr
  2923.     + (parsePtr->tokenPtr->numComponents + 1);
  2924.     bodyTokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1);
  2925.     if ((testTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)
  2926.     || (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)) {
  2927. return TCL_OUT_LINE_COMPILE;
  2928.     }
  2929.     /*
  2930.      * Find out if the condition is a constant. 
  2931.      */
  2932.     boolObj = Tcl_NewStringObj(testTokenPtr[1].start, testTokenPtr[1].size);
  2933.     Tcl_IncrRefCount(boolObj);
  2934.     code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
  2935.     Tcl_DecrRefCount(boolObj);
  2936.     if (code == TCL_OK) {
  2937. if (boolVal) {
  2938.     /*
  2939.      * it is an infinite loop 
  2940.      */
  2941.     loopMayEnd = 0;  
  2942. } else {
  2943.     /*
  2944.      * This is an empty loop: "while 0 {...}" or such.
  2945.      * Compile no bytecodes.
  2946.      */
  2947.     goto pushResult;
  2948. }
  2949.     }
  2950.     /* 
  2951.      * Create a ExceptionRange record for the loop body. This is used to
  2952.      * implement break and continue.
  2953.      */
  2954.     envPtr->exceptDepth++;
  2955.     envPtr->maxExceptDepth =
  2956. TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
  2957.     range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
  2958.     /*
  2959.      * Jump to the evaluation of the condition. This code uses the "loop
  2960.      * rotation" optimisation (which eliminates one branch from the loop).
  2961.      * "while cond body" produces then:
  2962.      *       goto A
  2963.      *    B: body                : bodyCodeOffset
  2964.      *    A: cond -> result      : testCodeOffset, continueOffset
  2965.      *       if (result) goto B
  2966.      *
  2967.      * The infinite loop "while 1 body" produces:
  2968.      *    B: body                : all three offsets here
  2969.      *       goto B
  2970.      */
  2971.     if (loopMayEnd) {
  2972. TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup);
  2973. testCodeOffset = 0; /* avoid compiler warning */
  2974.     } else {
  2975. testCodeOffset = (envPtr->codeNext - envPtr->codeStart);
  2976.     }
  2977.     
  2978.     /*
  2979.      * Compile the loop body.
  2980.      */
  2981. #ifdef TCL_TIP280
  2982.     envPtr->line = mapPtr->loc [eclIndex].line [2];
  2983. #endif
  2984.     bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart);
  2985.     code = TclCompileCmdWord(interp, bodyTokenPtr+1,
  2986.     bodyTokenPtr->numComponents, envPtr);
  2987.     envPtr->currStackDepth = savedStackDepth + 1;
  2988.     if (code != TCL_OK) {
  2989. if (code == TCL_ERROR) {
  2990.     sprintf(buffer, "n    ("while" body line %d)",
  2991.     interp->errorLine);
  2992.             Tcl_AddObjErrorInfo(interp, buffer, -1);
  2993.         }
  2994. goto error;
  2995.     }
  2996.     envPtr->exceptArrayPtr[range].numCodeBytes =
  2997.     (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
  2998.     TclEmitOpcode(INST_POP, envPtr);
  2999.     /*
  3000.      * Compile the test expression then emit the conditional jump that
  3001.      * terminates the while. We already know it's a simple word.
  3002.      */
  3003.     if (loopMayEnd) {
  3004. testCodeOffset = (envPtr->codeNext - envPtr->codeStart);
  3005. jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset;
  3006. if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) {
  3007.     bodyCodeOffset += 3;
  3008.     testCodeOffset += 3;
  3009. }
  3010. envPtr->currStackDepth = savedStackDepth;
  3011. #ifdef TCL_TIP280
  3012. envPtr->line = mapPtr->loc [eclIndex].line [1];
  3013. #endif
  3014. code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
  3015. if (code != TCL_OK) {
  3016.     if (code == TCL_ERROR) {
  3017. Tcl_AddObjErrorInfo(interp,
  3018.     "n    ("while" test expression)", -1);
  3019.     }
  3020.     goto error;
  3021. }
  3022. envPtr->currStackDepth = savedStackDepth + 1;
  3023.     
  3024. jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
  3025. if (jumpDist > 127) {
  3026.     TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
  3027. } else {
  3028.     TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
  3029. }
  3030.     } else {
  3031. jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
  3032. if (jumpDist > 127) {
  3033.     TclEmitInstInt4(INST_JUMP4, -jumpDist, envPtr);
  3034. } else {
  3035.     TclEmitInstInt1(INST_JUMP1, -jumpDist, envPtr);
  3036. }
  3037.     }
  3038.     /*
  3039.      * Set the loop's body, continue and break offsets.
  3040.      */
  3041.     envPtr->exceptArrayPtr[range].continueOffset = testCodeOffset;
  3042.     envPtr->exceptArrayPtr[range].codeOffset = bodyCodeOffset;
  3043.     envPtr->exceptArrayPtr[range].breakOffset =
  3044.     (envPtr->codeNext - envPtr->codeStart);
  3045.     
  3046.     /*
  3047.      * The while command's result is an empty string.
  3048.      */
  3049.     pushResult:
  3050.     envPtr->currStackDepth = savedStackDepth;
  3051.     TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
  3052.     envPtr->exceptDepth--;
  3053.     return TCL_OK;
  3054.     error:
  3055.     envPtr->exceptDepth--;
  3056.     return code;
  3057. }
  3058. /*
  3059.  *----------------------------------------------------------------------
  3060.  *
  3061.  * TclPushVarName --
  3062.  *
  3063.  * Procedure used in the compiling where pushing a variable name
  3064.  * is necessary (append, lappend, set).
  3065.  *
  3066.  * Results:
  3067.  * The return value is a standard Tcl result, which is normally TCL_OK
  3068.  * unless there was an error while parsing string. If an error occurs
  3069.  * then the interpreter's result contains a standard error message.
  3070.  *
  3071.  * Side effects:
  3072.  * Instructions are added to envPtr to execute the "set" command
  3073.  * at runtime.
  3074.  *
  3075.  *----------------------------------------------------------------------
  3076.  */
  3077. static int
  3078. TclPushVarName(interp, varTokenPtr, envPtr, flags, localIndexPtr,
  3079. #ifndef TCL_TIP280
  3080. simpleVarNamePtr, isScalarPtr)
  3081. #else
  3082. simpleVarNamePtr, isScalarPtr, line)
  3083. #endif
  3084.     Tcl_Interp *interp; /* Used for error reporting. */
  3085.     Tcl_Token *varTokenPtr; /* Points to a variable token. */
  3086.     CompileEnv *envPtr; /* Holds resulting instructions. */
  3087.     int flags; /* takes TCL_CREATE_VAR or
  3088.  * TCL_NO_LARGE_INDEX */
  3089.     int *localIndexPtr; /* must not be NULL */
  3090.     int *simpleVarNamePtr; /* must not be NULL */
  3091.     int *isScalarPtr; /* must not be NULL */
  3092. #ifdef TCL_TIP280
  3093.     int line;                   /* line the token starts on */
  3094. #endif
  3095. {
  3096.     register CONST char *p;
  3097.     CONST char *name, *elName;
  3098.     register int i, n;
  3099.     int nameChars, elNameChars, simpleVarName, localIndex;
  3100.     int code = TCL_OK;
  3101.     Tcl_Token *elemTokenPtr = NULL;
  3102.     int elemTokenCount = 0;
  3103.     int allocedTokens = 0;
  3104.     int removedParen = 0;
  3105.     /*
  3106.      * Decide if we can use a frame slot for the var/array name or if we
  3107.      * need to emit code to compute and push the name at runtime. We use a
  3108.      * frame slot (entry in the array of local vars) if we are compiling a
  3109.      * procedure body and if the name is simple text that does not include
  3110.      * namespace qualifiers. 
  3111.      */
  3112.     simpleVarName = 0;
  3113.     name = elName = NULL;
  3114.     nameChars = elNameChars = 0;
  3115.     localIndex = -1;
  3116.     /*
  3117.      * Check not only that the type is TCL_TOKEN_SIMPLE_WORD, but whether
  3118.      * curly braces surround the variable name.
  3119.      * This really matters for array elements to handle things like
  3120.      *    set {x($foo)} 5
  3121.      * which raises an undefined var error if we are not careful here.
  3122.      */
  3123.     if ((varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) &&
  3124.     (varTokenPtr->start[0] != '{')) {
  3125. /*
  3126.  * A simple variable name. Divide it up into "name" and "elName"
  3127.  * strings. If it is not a local variable, look it up at runtime.
  3128.  */
  3129. simpleVarName = 1;
  3130. name = varTokenPtr[1].start;
  3131. nameChars = varTokenPtr[1].size;
  3132. if ( *(name + nameChars - 1) == ')') {
  3133.     /* 
  3134.      * last char is ')' => potential array reference.
  3135.      */
  3136.     for (i = 0, p = name;  i < nameChars;  i++, p++) {
  3137. if (*p == '(') {
  3138.     elName = p + 1;
  3139.     elNameChars = nameChars - i - 2;
  3140.     nameChars = i ;
  3141.     break;
  3142. }
  3143.     }
  3144.     if ((elName != NULL) && elNameChars) {
  3145. /*
  3146.  * An array element, the element name is a simple
  3147.  * string: assemble the corresponding token.
  3148.  */
  3149. elemTokenPtr = (Tcl_Token *) ckalloc(sizeof(Tcl_Token));
  3150. allocedTokens = 1;
  3151. elemTokenPtr->type = TCL_TOKEN_TEXT;
  3152. elemTokenPtr->start = elName;
  3153. elemTokenPtr->size = elNameChars;
  3154. elemTokenPtr->numComponents = 0;
  3155. elemTokenCount = 1;
  3156.     }
  3157. }
  3158.     } else if (((n = varTokenPtr->numComponents) > 1)
  3159.     && (varTokenPtr[1].type == TCL_TOKEN_TEXT)
  3160.             && (varTokenPtr[n].type == TCL_TOKEN_TEXT)
  3161.             && (varTokenPtr[n].start[varTokenPtr[n].size - 1] == ')')) {
  3162.         /*
  3163.  * Check for parentheses inside first token
  3164.  */
  3165.         simpleVarName = 0;
  3166.         for (i = 0, p = varTokenPtr[1].start; 
  3167.      i < varTokenPtr[1].size; i++, p++) {
  3168.             if (*p == '(') {
  3169.                 simpleVarName = 1;
  3170.                 break;
  3171.             }
  3172.         }
  3173.         if (simpleVarName) {
  3174.     int remainingChars;
  3175.     /*
  3176.      * Check the last token: if it is just ')', do not count
  3177.      * it. Otherwise, remove the ')' and flag so that it is
  3178.      * restored at the end.
  3179.      */
  3180.     if (varTokenPtr[n].size == 1) {
  3181. --n;
  3182.     } else {
  3183. --varTokenPtr[n].size;
  3184. removedParen = n;
  3185.     }
  3186.             name = varTokenPtr[1].start;
  3187.             nameChars = p - varTokenPtr[1].start;
  3188.             elName = p + 1;
  3189.             remainingChars = (varTokenPtr[2].start - p) - 1;
  3190.             elNameChars = (varTokenPtr[n].start - p) + varTokenPtr[n].size - 2;
  3191.     if (remainingChars) {
  3192. /*
  3193.  * Make a first token with the extra characters in the first 
  3194.  * token.
  3195.  */
  3196. elemTokenPtr = (Tcl_Token *) ckalloc(n * sizeof(Tcl_Token));
  3197. allocedTokens = 1;
  3198. elemTokenPtr->type = TCL_TOKEN_TEXT;
  3199. elemTokenPtr->start = elName;
  3200. elemTokenPtr->size = remainingChars;
  3201. elemTokenPtr->numComponents = 0;
  3202. elemTokenCount = n;
  3203. /*
  3204.  * Copy the remaining tokens.
  3205.  */
  3206. memcpy((void *) (elemTokenPtr+1), (void *) (&varTokenPtr[2]),
  3207.        ((n-1) * sizeof(Tcl_Token)));
  3208.     } else {
  3209. /*
  3210.  * Use the already available tokens.
  3211.  */
  3212. elemTokenPtr = &varTokenPtr[2];
  3213. elemTokenCount = n - 1;     
  3214.     }
  3215. }
  3216.     }
  3217.     if (simpleVarName) {
  3218. /*
  3219.  * See whether name has any namespace separators (::'s).
  3220.  */
  3221. int hasNsQualifiers = 0;
  3222. for (i = 0, p = name;  i < nameChars;  i++, p++) {
  3223.     if ((*p == ':') && ((i+1) < nameChars) && (*(p+1) == ':')) {
  3224. hasNsQualifiers = 1;
  3225. break;
  3226.     }
  3227. }
  3228. /*
  3229.  * Look up the var name's index in the array of local vars in the
  3230.  * proc frame. If retrieving the var's value and it doesn't already
  3231.  * exist, push its name and look it up at runtime.
  3232.  */
  3233. if ((envPtr->procPtr != NULL) && !hasNsQualifiers) {
  3234.     localIndex = TclFindCompiledLocal(name, nameChars,
  3235.     /*create*/ (flags & TCL_CREATE_VAR),
  3236.                     /*flags*/ ((elName==NULL)? VAR_SCALAR : VAR_ARRAY),
  3237.     envPtr->procPtr);
  3238.     if ((flags & TCL_NO_LARGE_INDEX) && (localIndex > 255)) {
  3239. /* we'll push the name */
  3240. localIndex = -1;
  3241.     }
  3242. }
  3243. if (localIndex < 0) {
  3244.     TclEmitPush(TclRegisterNewLiteral(envPtr, name, nameChars), envPtr);
  3245. }
  3246. /*
  3247.  * Compile the element script, if any.
  3248.  */
  3249. if (elName != NULL) {
  3250.     if (elNameChars) {
  3251. #ifdef TCL_TIP280
  3252.         envPtr->line = line;
  3253. #endif
  3254. code = TclCompileTokens(interp, elemTokenPtr,
  3255.                         elemTokenCount, envPtr);
  3256. if (code != TCL_OK) {
  3257.     goto done;
  3258. }
  3259.     } else {
  3260. TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
  3261.     }
  3262. }
  3263.     } else {
  3264. /*
  3265.  * The var name isn't simple: compile and push it.
  3266.  */
  3267. #ifdef TCL_TIP280
  3268.         envPtr->line = line;
  3269. #endif
  3270. code = TclCompileTokens(interp, varTokenPtr+1,
  3271. varTokenPtr->numComponents, envPtr);
  3272. if (code != TCL_OK) {
  3273.     goto done;
  3274. }
  3275.     }
  3276.     done:
  3277.     if (removedParen) {
  3278. ++varTokenPtr[removedParen].size;
  3279.     }
  3280.     if (allocedTokens) {
  3281.         ckfree((char *) elemTokenPtr);
  3282.     }
  3283.     *localIndexPtr = localIndex;
  3284.     *simpleVarNamePtr = simpleVarName;
  3285.     *isScalarPtr = (elName == NULL);
  3286.     return code;
  3287. }
  3288. /*
  3289.  * Local Variables:
  3290.  * mode: c
  3291.  * c-basic-offset: 4
  3292.  * fill-column: 78
  3293.  * End:
  3294.  */