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