os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclCompile.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* 
     2  * tclCompile.c --
     3  *
     4  *	This file contains procedures that compile Tcl commands or parts
     5  *	of commands (like quoted strings or nested sub-commands) into a
     6  *	sequence of instructions ("bytecodes"). 
     7  *
     8  * Copyright (c) 1996-1998 Sun Microsystems, Inc.
     9  * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
    10  * Portions Copyright (c) 2007 Nokia Corporation and/or its subsidiaries. All rights reserved.
    11  *
    12  * See the file "license.terms" for information on usage and redistribution
    13  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    14  *
    15  * RCS: @(#) $Id: tclCompile.c,v 1.43.2.7 2006/11/28 22:20:00 andreas_kupries Exp $
    16  */
    17 
    18 #include "tclInt.h"
    19 #include "tclCompile.h"
    20 #if defined(__SYMBIAN32__) && defined(__WINSCW__)
    21 #include "tclSymbianGlobals.h"
    22 #define dataKey getdataKey(0)
    23 #endif 
    24 
    25 #if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
    26 /*
    27  * Table of all AuxData types.
    28  */
    29  
    30 static Tcl_HashTable auxDataTypeTable;
    31 static int auxDataTypeTableInitialized; /* 0 means not yet initialized. */
    32 #endif
    33 TCL_DECLARE_MUTEX(tableMutex)
    34 
    35 /*
    36  * Variable that controls whether compilation tracing is enabled and, if so,
    37  * what level of tracing is desired:
    38  *    0: no compilation tracing
    39  *    1: summarize compilation of top level cmds and proc bodies
    40  *    2: display all instructions of each ByteCode compiled
    41  * This variable is linked to the Tcl variable "tcl_traceCompile".
    42  */
    43 
    44 #ifdef TCL_COMPILE_DEBUG
    45 int tclTraceCompile = 0;
    46 static int traceInitialized = 0;
    47 #endif
    48 
    49 /*
    50  * A table describing the Tcl bytecode instructions. Entries in this table
    51  * must correspond to the instruction opcode definitions in tclCompile.h.
    52  * The names "op1" and "op4" refer to an instruction's one or four byte
    53  * first operand. Similarly, "stktop" and "stknext" refer to the topmost
    54  * and next to topmost stack elements.
    55  *
    56  * Note that the load, store, and incr instructions do not distinguish local
    57  * from global variables; the bytecode interpreter at runtime uses the
    58  * existence of a procedure call frame to distinguish these.
    59  */
    60 
    61 InstructionDesc tclInstructionTable[] = {
    62    /* Name	      Bytes stackEffect #Opnds Operand types	Stack top, next	  */
    63     {"done",		  1,   -1,        0,   {OPERAND_NONE}},
    64 	/* Finish ByteCode execution and return stktop (top stack item) */
    65     {"push1",		  2,   +1,         1,   {OPERAND_UINT1}},
    66 	/* Push object at ByteCode objArray[op1] */
    67     {"push4",		  5,   +1,         1,   {OPERAND_UINT4}},
    68 	/* Push object at ByteCode objArray[op4] */
    69     {"pop",		  1,   -1,        0,   {OPERAND_NONE}},
    70 	/* Pop the topmost stack object */
    71     {"dup",		  1,   +1,         0,   {OPERAND_NONE}},
    72 	/* Duplicate the topmost stack object and push the result */
    73     {"concat1",		  2,   INT_MIN,    1,   {OPERAND_UINT1}},
    74 	/* Concatenate the top op1 items and push result */
    75     {"invokeStk1",	  2,   INT_MIN,    1,   {OPERAND_UINT1}},
    76 	/* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */
    77     {"invokeStk4",	  5,   INT_MIN,    1,   {OPERAND_UINT4}},
    78 	/* Invoke command named objv[0]; <objc,objv> = <op4,top op4> */
    79     {"evalStk",		  1,   0,          0,   {OPERAND_NONE}},
    80 	/* Evaluate command in stktop using Tcl_EvalObj. */
    81     {"exprStk",		  1,   0,          0,   {OPERAND_NONE}},
    82 	/* Execute expression in stktop using Tcl_ExprStringObj. */
    83     
    84     {"loadScalar1",	  2,   1,          1,   {OPERAND_UINT1}},
    85 	/* Load scalar variable at index op1 <= 255 in call frame */
    86     {"loadScalar4",	  5,   1,          1,   {OPERAND_UINT4}},
    87 	/* Load scalar variable at index op1 >= 256 in call frame */
    88     {"loadScalarStk",	  1,   0,          0,   {OPERAND_NONE}},
    89 	/* Load scalar variable; scalar's name is stktop */
    90     {"loadArray1",	  2,   0,          1,   {OPERAND_UINT1}},
    91 	/* Load array element; array at slot op1<=255, element is stktop */
    92     {"loadArray4",	  5,   0,          1,   {OPERAND_UINT4}},
    93 	/* Load array element; array at slot op1 > 255, element is stktop */
    94     {"loadArrayStk",	  1,   -1,         0,   {OPERAND_NONE}},
    95 	/* Load array element; element is stktop, array name is stknext */
    96     {"loadStk",		  1,   0,          0,   {OPERAND_NONE}},
    97 	/* Load general variable; unparsed variable name is stktop */
    98     {"storeScalar1",	  2,   0,          1,   {OPERAND_UINT1}},
    99 	/* Store scalar variable at op1<=255 in frame; value is stktop */
   100     {"storeScalar4",	  5,   0,          1,   {OPERAND_UINT4}},
   101 	/* Store scalar variable at op1 > 255 in frame; value is stktop */
   102     {"storeScalarStk",	  1,   -1,         0,   {OPERAND_NONE}},
   103 	/* Store scalar; value is stktop, scalar name is stknext */
   104     {"storeArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
   105 	/* Store array element; array at op1<=255, value is top then elem */
   106     {"storeArray4",	  5,   -1,          1,   {OPERAND_UINT4}},
   107 	/* Store array element; array at op1>=256, value is top then elem */
   108     {"storeArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
   109 	/* Store array element; value is stktop, then elem, array names */
   110     {"storeStk",	  1,   -1,         0,   {OPERAND_NONE}},
   111 	/* Store general variable; value is stktop, then unparsed name */
   112     
   113     {"incrScalar1",	  2,   0,          1,   {OPERAND_UINT1}},
   114 	/* Incr scalar at index op1<=255 in frame; incr amount is stktop */
   115     {"incrScalarStk",	  1,   -1,         0,   {OPERAND_NONE}},
   116 	/* Incr scalar; incr amount is stktop, scalar's name is stknext */
   117     {"incrArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
   118 	/* Incr array elem; arr at slot op1<=255, amount is top then elem */
   119     {"incrArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
   120 	/* Incr array element; amount is top then elem then array names */
   121     {"incrStk",		  1,   -1,         0,   {OPERAND_NONE}},
   122 	/* Incr general variable; amount is stktop then unparsed var name */
   123     {"incrScalar1Imm",	  3,   +1,         2,   {OPERAND_UINT1, OPERAND_INT1}},
   124 	/* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */
   125     {"incrScalarStkImm",  2,   0,          1,   {OPERAND_INT1}},
   126 	/* Incr scalar; scalar name is stktop; incr amount is op1 */
   127     {"incrArray1Imm",	  3,   0,         2,   {OPERAND_UINT1, OPERAND_INT1}},
   128 	/* Incr array elem; array at slot op1 <= 255, elem is stktop,
   129 	 * amount is 2nd operand byte */
   130     {"incrArrayStkImm",	  2,   -1,         1,   {OPERAND_INT1}},
   131 	/* Incr array element; elem is top then array name, amount is op1 */
   132     {"incrStkImm",	  2,   0,         1,   {OPERAND_INT1}},
   133 	/* Incr general variable; unparsed name is top, amount is op1 */
   134     
   135     {"jump1",		  2,   0,          1,   {OPERAND_INT1}},
   136 	/* Jump relative to (pc + op1) */
   137     {"jump4",		  5,   0,          1,   {OPERAND_INT4}},
   138 	/* Jump relative to (pc + op4) */
   139     {"jumpTrue1",	  2,   -1,         1,   {OPERAND_INT1}},
   140 	/* Jump relative to (pc + op1) if stktop expr object is true */
   141     {"jumpTrue4",	  5,   -1,         1,   {OPERAND_INT4}},
   142 	/* Jump relative to (pc + op4) if stktop expr object is true */
   143     {"jumpFalse1",	  2,   -1,         1,   {OPERAND_INT1}},
   144 	/* Jump relative to (pc + op1) if stktop expr object is false */
   145     {"jumpFalse4",	  5,   -1,         1,   {OPERAND_INT4}},
   146 	/* Jump relative to (pc + op4) if stktop expr object is false */
   147 
   148     {"lor",		  1,   -1,         0,   {OPERAND_NONE}},
   149 	/* Logical or:	push (stknext || stktop) */
   150     {"land",		  1,   -1,         0,   {OPERAND_NONE}},
   151 	/* Logical and:	push (stknext && stktop) */
   152     {"bitor",		  1,   -1,         0,   {OPERAND_NONE}},
   153 	/* Bitwise or:	push (stknext | stktop) */
   154     {"bitxor",		  1,   -1,         0,   {OPERAND_NONE}},
   155 	/* Bitwise xor	push (stknext ^ stktop) */
   156     {"bitand",		  1,   -1,         0,   {OPERAND_NONE}},
   157 	/* Bitwise and:	push (stknext & stktop) */
   158     {"eq",		  1,   -1,         0,   {OPERAND_NONE}},
   159 	/* Equal:	push (stknext == stktop) */
   160     {"neq",		  1,   -1,         0,   {OPERAND_NONE}},
   161 	/* Not equal:	push (stknext != stktop) */
   162     {"lt",		  1,   -1,         0,   {OPERAND_NONE}},
   163 	/* Less:	push (stknext < stktop) */
   164     {"gt",		  1,   -1,         0,   {OPERAND_NONE}},
   165 	/* Greater:	push (stknext || stktop) */
   166     {"le",		  1,   -1,         0,   {OPERAND_NONE}},
   167 	/* Logical or:	push (stknext || stktop) */
   168     {"ge",		  1,   -1,         0,   {OPERAND_NONE}},
   169 	/* Logical or:	push (stknext || stktop) */
   170     {"lshift",		  1,   -1,         0,   {OPERAND_NONE}},
   171 	/* Left shift:	push (stknext << stktop) */
   172     {"rshift",		  1,   -1,         0,   {OPERAND_NONE}},
   173 	/* Right shift:	push (stknext >> stktop) */
   174     {"add",		  1,   -1,         0,   {OPERAND_NONE}},
   175 	/* Add:		push (stknext + stktop) */
   176     {"sub",		  1,   -1,         0,   {OPERAND_NONE}},
   177 	/* Sub:		push (stkext - stktop) */
   178     {"mult",		  1,   -1,         0,   {OPERAND_NONE}},
   179 	/* Multiply:	push (stknext * stktop) */
   180     {"div",		  1,   -1,         0,   {OPERAND_NONE}},
   181 	/* Divide:	push (stknext / stktop) */
   182     {"mod",		  1,   -1,         0,   {OPERAND_NONE}},
   183 	/* Mod:		push (stknext % stktop) */
   184     {"uplus",		  1,   0,          0,   {OPERAND_NONE}},
   185 	/* Unary plus:	push +stktop */
   186     {"uminus",		  1,   0,          0,   {OPERAND_NONE}},
   187 	/* Unary minus:	push -stktop */
   188     {"bitnot",		  1,   0,          0,   {OPERAND_NONE}},
   189 	/* Bitwise not:	push ~stktop */
   190     {"not",		  1,   0,          0,   {OPERAND_NONE}},
   191 	/* Logical not:	push !stktop */
   192     {"callBuiltinFunc1",  2,   1,          1,   {OPERAND_UINT1}},
   193 	/* Call builtin math function with index op1; any args are on stk */
   194     {"callFunc1",	  2,   INT_MIN,    1,   {OPERAND_UINT1}},
   195 	/* Call non-builtin func objv[0]; <objc,objv>=<op1,top op1>  */
   196     {"tryCvtToNumeric",	  1,   0,          0,   {OPERAND_NONE}},
   197 	/* Try converting stktop to first int then double if possible. */
   198 
   199     {"break",		  1,   0,          0,   {OPERAND_NONE}},
   200 	/* Abort closest enclosing loop; if none, return TCL_BREAK code. */
   201     {"continue",	  1,   0,          0,   {OPERAND_NONE}},
   202 	/* Skip to next iteration of closest enclosing loop; if none,
   203 	 * return TCL_CONTINUE code. */
   204 
   205     {"foreach_start4",	  5,   0,          1,   {OPERAND_UINT4}},
   206 	/* Initialize execution of a foreach loop. Operand is aux data index
   207 	 * of the ForeachInfo structure for the foreach command. */
   208     {"foreach_step4",	  5,   +1,         1,   {OPERAND_UINT4}},
   209 	/* "Step" or begin next iteration of foreach loop. Push 0 if to
   210 	 *  terminate loop, else push 1. */
   211 
   212     {"beginCatch4",	  5,   0,          1,   {OPERAND_UINT4}},
   213 	/* Record start of catch with the operand's exception index.
   214 	 * Push the current stack depth onto a special catch stack. */
   215     {"endCatch",	  1,   0,          0,   {OPERAND_NONE}},
   216 	/* End of last catch. Pop the bytecode interpreter's catch stack. */
   217     {"pushResult",	  1,   +1,         0,   {OPERAND_NONE}},
   218 	/* Push the interpreter's object result onto the stack. */
   219     {"pushReturnCode",	  1,   +1,         0,   {OPERAND_NONE}},
   220 	/* Push interpreter's return code (e.g. TCL_OK or TCL_ERROR) as
   221 	 * a new object onto the stack. */
   222     {"streq",		  1,   -1,         0,   {OPERAND_NONE}},
   223 	/* Str Equal:	push (stknext eq stktop) */
   224     {"strneq",		  1,   -1,         0,   {OPERAND_NONE}},
   225 	/* Str !Equal:	push (stknext neq stktop) */
   226     {"strcmp",		  1,   -1,         0,   {OPERAND_NONE}},
   227 	/* Str Compare:	push (stknext cmp stktop) */
   228     {"strlen",		  1,   0,          0,   {OPERAND_NONE}},
   229 	/* Str Length:	push (strlen stktop) */
   230     {"strindex",	  1,   -1,         0,   {OPERAND_NONE}},
   231 	/* Str Index:	push (strindex stknext stktop) */
   232     {"strmatch",	  2,   -1,         1,   {OPERAND_INT1}},
   233 	/* Str Match:	push (strmatch stknext stktop) opnd == nocase */
   234     {"list",		  5,   INT_MIN,    1,   {OPERAND_UINT4}},
   235 	/* List:	push (stk1 stk2 ... stktop) */
   236     {"listindex",	  1,   -1,         0,   {OPERAND_NONE}},
   237 	/* List Index:	push (listindex stknext stktop) */
   238     {"listlength",	  1,   0,          0,   {OPERAND_NONE}},
   239 	/* List Len:	push (listlength stktop) */
   240     {"appendScalar1",	  2,   0,          1,   {OPERAND_UINT1}},
   241 	/* Append scalar variable at op1<=255 in frame; value is stktop */
   242     {"appendScalar4",	  5,   0,          1,   {OPERAND_UINT4}},
   243 	/* Append scalar variable at op1 > 255 in frame; value is stktop */
   244     {"appendArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
   245 	/* Append array element; array at op1<=255, value is top then elem */
   246     {"appendArray4",	  5,   -1,         1,   {OPERAND_UINT4}},
   247 	/* Append array element; array at op1>=256, value is top then elem */
   248     {"appendArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
   249 	/* Append array element; value is stktop, then elem, array names */
   250     {"appendStk",	  1,   -1,         0,   {OPERAND_NONE}},
   251 	/* Append general variable; value is stktop, then unparsed name */
   252     {"lappendScalar1",	  2,   0,          1,   {OPERAND_UINT1}},
   253 	/* Lappend scalar variable at op1<=255 in frame; value is stktop */
   254     {"lappendScalar4",	  5,   0,          1,   {OPERAND_UINT4}},
   255 	/* Lappend scalar variable at op1 > 255 in frame; value is stktop */
   256     {"lappendArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
   257 	/* Lappend array element; array at op1<=255, value is top then elem */
   258     {"lappendArray4",	  5,   -1,         1,   {OPERAND_UINT4}},
   259 	/* Lappend array element; array at op1>=256, value is top then elem */
   260     {"lappendArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
   261 	/* Lappend array element; value is stktop, then elem, array names */
   262     {"lappendStk",	  1,   -1,         0,   {OPERAND_NONE}},
   263 	/* Lappend general variable; value is stktop, then unparsed name */
   264     {"lindexMulti",	  5,   INT_MIN,   1,   {OPERAND_UINT4}},
   265         /* Lindex with generalized args, operand is number of stacked objs 
   266 	 * used: (operand-1) entries from stktop are the indices; then list 
   267 	 * to process. */
   268     {"over",		  5,   +1,         1,   {OPERAND_UINT4}},
   269         /* Duplicate the arg-th element from top of stack (TOS=0) */
   270     {"lsetList",          1,   -2,         0,   {OPERAND_NONE}},
   271         /* Four-arg version of 'lset'. stktop is old value; next is
   272          * new element value, next is the index list; pushes new value */
   273     {"lsetFlat",          5,   INT_MIN,   1,   {OPERAND_UINT4}},
   274         /* Three- or >=5-arg version of 'lset', operand is number of 
   275 	 * stacked objs: stktop is old value, next is new element value, next 
   276 	 * come (operand-2) indices; pushes the new value.
   277 	 */
   278     {0}
   279 };
   280 
   281 /*
   282  * Prototypes for procedures defined later in this file:
   283  */
   284 
   285 static void		DupByteCodeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
   286 			    Tcl_Obj *copyPtr));
   287 static unsigned char *	EncodeCmdLocMap _ANSI_ARGS_((
   288 			    CompileEnv *envPtr, ByteCode *codePtr,
   289 			    unsigned char *startPtr));
   290 static void		EnterCmdExtentData _ANSI_ARGS_((
   291     			    CompileEnv *envPtr, int cmdNumber,
   292 			    int numSrcBytes, int numCodeBytes));
   293 static void		EnterCmdStartData _ANSI_ARGS_((
   294     			    CompileEnv *envPtr, int cmdNumber,
   295 			    int srcOffset, int codeOffset));
   296 static void		FreeByteCodeInternalRep _ANSI_ARGS_((
   297     			    Tcl_Obj *objPtr));
   298 static int		GetCmdLocEncodingSize _ANSI_ARGS_((
   299 			    CompileEnv *envPtr));
   300 static void		LogCompilationInfo _ANSI_ARGS_((Tcl_Interp *interp,
   301         		    CONST char *script, CONST char *command,
   302 			    int length));
   303 #ifdef TCL_COMPILE_STATS
   304 static void		RecordByteCodeStats _ANSI_ARGS_((
   305 			    ByteCode *codePtr));
   306 #endif /* TCL_COMPILE_STATS */
   307 static int		SetByteCodeFromAny _ANSI_ARGS_((Tcl_Interp *interp,
   308 			    Tcl_Obj *objPtr));
   309 
   310 #ifdef TCL_TIP280
   311 /* TIP #280 : Helper for building the per-word line information of all
   312  * compiled commands */
   313 static void		EnterCmdWordData _ANSI_ARGS_((
   314     			    ExtCmdLoc *eclPtr, int srcOffset, Tcl_Token* tokenPtr,
   315 			    CONST char* cmd, int len, int numWords, int line,
   316 			    int** lines));
   317 #endif
   318 
   319 
   320 /*
   321  * The structure below defines the bytecode Tcl object type by
   322  * means of procedures that can be invoked by generic object code.
   323  */
   324 
   325 Tcl_ObjType tclByteCodeType = {
   326     "bytecode",				/* name */
   327     FreeByteCodeInternalRep,		/* freeIntRepProc */
   328     DupByteCodeInternalRep,		/* dupIntRepProc */
   329     (Tcl_UpdateStringProc *) NULL,	/* updateStringProc */
   330     SetByteCodeFromAny			/* setFromAnyProc */
   331 };
   332 
   333 /*
   334  *----------------------------------------------------------------------
   335  *
   336  * TclSetByteCodeFromAny --
   337  *
   338  *	Part of the bytecode Tcl object type implementation. Attempts to
   339  *	generate an byte code internal form for the Tcl object "objPtr" by
   340  *	compiling its string representation.  This function also takes
   341  *	a hook procedure that will be invoked to perform any needed post
   342  *	processing on the compilation results before generating byte
   343  *	codes.
   344  *
   345  * Results:
   346  *	The return value is a standard Tcl object result. If an error occurs
   347  *	during compilation, an error message is left in the interpreter's
   348  *	result unless "interp" is NULL.
   349  *
   350  * Side effects:
   351  *	Frees the old internal representation. If no error occurs, then the
   352  *	compiled code is stored as "objPtr"s bytecode representation.
   353  *	Also, if debugging, initializes the "tcl_traceCompile" Tcl variable
   354  *	used to trace compilations.
   355  *
   356  *----------------------------------------------------------------------
   357  */
   358 
   359 int
   360 TclSetByteCodeFromAny(interp, objPtr, hookProc, clientData)
   361     Tcl_Interp *interp;		/* The interpreter for which the code is
   362 				 * being compiled.  Must not be NULL. */
   363     Tcl_Obj *objPtr;		/* The object to make a ByteCode object. */
   364     CompileHookProc *hookProc;	/* Procedure to invoke after compilation. */
   365     ClientData clientData;	/* Hook procedure private data. */
   366 {
   367     Interp *iPtr = (Interp *) interp;
   368     CompileEnv compEnv;		/* Compilation environment structure
   369 				 * allocated in frame. */
   370     LiteralTable *localTablePtr = &(compEnv.localLitTable);
   371     register AuxData *auxDataPtr;
   372     LiteralEntry *entryPtr;
   373     register int i;
   374     int length, nested, result;
   375     char *string;
   376 
   377 #ifdef TCL_COMPILE_DEBUG
   378     if (!traceInitialized) {
   379         if (Tcl_LinkVar(interp, "tcl_traceCompile",
   380 	            (char *) &tclTraceCompile,  TCL_LINK_INT) != TCL_OK) {
   381             panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");
   382         }
   383         traceInitialized = 1;
   384     }
   385 #endif
   386 
   387     if (iPtr->evalFlags & TCL_BRACKET_TERM) {
   388 	nested = 1;
   389     } else {
   390 	nested = 0;
   391     }
   392     string = Tcl_GetStringFromObj(objPtr, &length);
   393 #ifndef TCL_TIP280
   394     TclInitCompileEnv(interp, &compEnv, string, length);
   395 #else
   396     /*
   397      * TIP #280. Pick up the CmdFrame in which the BC compiler was invoked
   398      * and use to initialize the tracking in the compiler. This information
   399      * was stored by TclCompEvalObj (tclExecute.c), and ProcCompileProc
   400      * (tclProc.c).
   401      */
   402 
   403     TclInitCompileEnv(interp, &compEnv, string, length,
   404 		      iPtr->invokeCmdFramePtr, iPtr->invokeWord);
   405 #endif
   406     result = TclCompileScript(interp, string, length, nested, &compEnv);
   407 
   408     if (result == TCL_OK) {
   409 	/*
   410 	 * Successful compilation. Add a "done" instruction at the end.
   411 	 */
   412 
   413 	compEnv.numSrcBytes = iPtr->termOffset;
   414 	TclEmitOpcode(INST_DONE, &compEnv);
   415 
   416 	/*
   417 	 * Invoke the compilation hook procedure if one exists.
   418 	 */
   419 
   420 	if (hookProc) {
   421 	    result = (*hookProc)(interp, &compEnv, clientData);
   422 	}
   423 
   424 	/*
   425 	 * Change the object into a ByteCode object. Ownership of the literal
   426 	 * objects and aux data items is given to the ByteCode object.
   427 	 */
   428     
   429 #ifdef TCL_COMPILE_DEBUG
   430 	TclVerifyLocalLiteralTable(&compEnv);
   431 #endif /*TCL_COMPILE_DEBUG*/
   432 
   433 	TclInitByteCodeObj(objPtr, &compEnv);
   434 #ifdef TCL_COMPILE_DEBUG
   435 	if (tclTraceCompile >= 2) {
   436 	    TclPrintByteCodeObj(interp, objPtr);
   437 	}
   438 #endif /* TCL_COMPILE_DEBUG */
   439     }
   440 	
   441     if (result != TCL_OK) {
   442 	/*
   443 	 * Compilation errors. 
   444 	 */
   445 
   446 	entryPtr = compEnv.literalArrayPtr;
   447 	for (i = 0;  i < compEnv.literalArrayNext;  i++) {
   448 	    TclReleaseLiteral(interp, entryPtr->objPtr);
   449 	    entryPtr++;
   450 	}
   451 #ifdef TCL_COMPILE_DEBUG
   452 	TclVerifyGlobalLiteralTable(iPtr);
   453 #endif /*TCL_COMPILE_DEBUG*/
   454 
   455 	auxDataPtr = compEnv.auxDataArrayPtr;
   456 	for (i = 0;  i < compEnv.auxDataArrayNext;  i++) {
   457 	    if (auxDataPtr->type->freeProc != NULL) {
   458 		auxDataPtr->type->freeProc(auxDataPtr->clientData);
   459 	    }
   460 	    auxDataPtr++;
   461 	}
   462     }
   463 
   464 
   465     /*
   466      * Free storage allocated during compilation.
   467      */
   468     
   469     if (localTablePtr->buckets != localTablePtr->staticBuckets) {
   470 	ckfree((char *) localTablePtr->buckets);
   471     }
   472     TclFreeCompileEnv(&compEnv);
   473     return result;
   474 }
   475 
   476 /*
   477  *-----------------------------------------------------------------------
   478  *
   479  * SetByteCodeFromAny --
   480  *
   481  *	Part of the bytecode Tcl object type implementation. Attempts to
   482  *	generate an byte code internal form for the Tcl object "objPtr" by
   483  *	compiling its string representation.
   484  *
   485  * Results:
   486  *	The return value is a standard Tcl object result. If an error occurs
   487  *	during compilation, an error message is left in the interpreter's
   488  *	result unless "interp" is NULL.
   489  *
   490  * Side effects:
   491  *	Frees the old internal representation. If no error occurs, then the
   492  *	compiled code is stored as "objPtr"s bytecode representation.
   493  *	Also, if debugging, initializes the "tcl_traceCompile" Tcl variable
   494  *	used to trace compilations.
   495  *
   496  *----------------------------------------------------------------------
   497  */
   498 
   499 static int
   500 SetByteCodeFromAny(interp, objPtr)
   501     Tcl_Interp *interp;		/* The interpreter for which the code is
   502 				 * being compiled.  Must not be NULL. */
   503     Tcl_Obj *objPtr;		/* The object to make a ByteCode object. */
   504 {
   505     return TclSetByteCodeFromAny(interp, objPtr,
   506 	    (CompileHookProc *) NULL, (ClientData) NULL);
   507 }
   508 
   509 /*
   510  *----------------------------------------------------------------------
   511  *
   512  * DupByteCodeInternalRep --
   513  *
   514  *	Part of the bytecode Tcl object type implementation. However, it
   515  *	does not copy the internal representation of a bytecode Tcl_Obj, but
   516  *	instead leaves the new object untyped (with a NULL type pointer).
   517  *	Code will be compiled for the new object only if necessary.
   518  *
   519  * Results:
   520  *	None.
   521  *
   522  * Side effects:
   523  *	None.
   524  *
   525  *----------------------------------------------------------------------
   526  */
   527 
   528 static void
   529 DupByteCodeInternalRep(srcPtr, copyPtr)
   530     Tcl_Obj *srcPtr;		/* Object with internal rep to copy. */
   531     Tcl_Obj *copyPtr;		/* Object with internal rep to set. */
   532 {
   533     return;
   534 }
   535 
   536 /*
   537  *----------------------------------------------------------------------
   538  *
   539  * FreeByteCodeInternalRep --
   540  *
   541  *	Part of the bytecode Tcl object type implementation. Frees the
   542  *	storage associated with a bytecode object's internal representation
   543  *	unless its code is actively being executed.
   544  *
   545  * Results:
   546  *	None.
   547  *
   548  * Side effects:
   549  *	The bytecode object's internal rep is marked invalid and its
   550  *	code gets freed unless the code is actively being executed.
   551  *	In that case the cleanup is delayed until the last execution
   552  *	of the code completes.
   553  *
   554  *----------------------------------------------------------------------
   555  */
   556 
   557 static void
   558 FreeByteCodeInternalRep(objPtr)
   559     register Tcl_Obj *objPtr;	/* Object whose internal rep to free. */
   560 {
   561     register ByteCode *codePtr =
   562 	    (ByteCode *) objPtr->internalRep.otherValuePtr;
   563 
   564     codePtr->refCount--;
   565     if (codePtr->refCount <= 0) {
   566 	TclCleanupByteCode(codePtr);
   567     }
   568     objPtr->typePtr = NULL;
   569     objPtr->internalRep.otherValuePtr = NULL;
   570 }
   571 
   572 /*
   573  *----------------------------------------------------------------------
   574  *
   575  * TclCleanupByteCode --
   576  *
   577  *	This procedure does all the real work of freeing up a bytecode
   578  *	object's ByteCode structure. It's called only when the structure's
   579  *	reference count becomes zero.
   580  *
   581  * Results:
   582  *	None.
   583  *
   584  * Side effects:
   585  *	Frees objPtr's bytecode internal representation and sets its type
   586  *	and objPtr->internalRep.otherValuePtr NULL. Also releases its
   587  *	literals and frees its auxiliary data items.
   588  *
   589  *----------------------------------------------------------------------
   590  */
   591 
   592 void
   593 TclCleanupByteCode(codePtr)
   594     register ByteCode *codePtr;	/* Points to the ByteCode to free. */
   595 {
   596     Tcl_Interp *interp = (Tcl_Interp *) *codePtr->interpHandle;
   597 #ifdef TCL_TIP280
   598     Interp* iPtr = (Interp*) interp;
   599 #endif
   600     int numLitObjects = codePtr->numLitObjects;
   601     int numAuxDataItems = codePtr->numAuxDataItems;
   602     register Tcl_Obj **objArrayPtr;
   603     register AuxData *auxDataPtr;
   604     int i;
   605 #ifdef TCL_COMPILE_STATS
   606 
   607     if (interp != NULL) {
   608 	ByteCodeStats *statsPtr;
   609 	Tcl_Time destroyTime;
   610 	int lifetimeSec, lifetimeMicroSec, log2;
   611 
   612 	statsPtr = &((Interp *) interp)->stats;
   613 
   614 	statsPtr->numByteCodesFreed++;
   615 	statsPtr->currentSrcBytes -= (double) codePtr->numSrcBytes;
   616 	statsPtr->currentByteCodeBytes -= (double) codePtr->structureSize;
   617 
   618 	statsPtr->currentInstBytes   -= (double) codePtr->numCodeBytes;
   619 	statsPtr->currentLitBytes    -=
   620 		(double) (codePtr->numLitObjects * sizeof(Tcl_Obj *)); 
   621 	statsPtr->currentExceptBytes -=
   622 		(double) (codePtr->numExceptRanges * sizeof(ExceptionRange));
   623 	statsPtr->currentAuxBytes    -=
   624 		(double) (codePtr->numAuxDataItems * sizeof(AuxData));
   625 	statsPtr->currentCmdMapBytes -= (double) codePtr->numCmdLocBytes;
   626 
   627 	Tcl_GetTime(&destroyTime);
   628 	lifetimeSec = destroyTime.sec - codePtr->createTime.sec;
   629 	if (lifetimeSec > 2000) {	/* avoid overflow */
   630 	    lifetimeSec = 2000;
   631 	}
   632 	lifetimeMicroSec =
   633 	    1000000*lifetimeSec + (destroyTime.usec - codePtr->createTime.usec);
   634 	
   635 	log2 = TclLog2(lifetimeMicroSec);
   636 	if (log2 > 31) {
   637 	    log2 = 31;
   638 	}
   639 	statsPtr->lifetimeCount[log2]++;
   640     }
   641 #endif /* TCL_COMPILE_STATS */
   642 
   643     /*
   644      * A single heap object holds the ByteCode structure and its code,
   645      * object, command location, and auxiliary data arrays. This means we
   646      * only need to 1) decrement the ref counts of the LiteralEntry's in
   647      * its literal array, 2) call the free procs for the auxiliary data
   648      * items, and 3) free the ByteCode structure's heap object.
   649      *
   650      * The case for TCL_BYTECODE_PRECOMPILED (precompiled ByteCodes,
   651      * like those generated from tbcload) is special, as they doesn't
   652      * make use of the global literal table.  They instead maintain
   653      * private references to their literals which must be decremented.
   654      */
   655 
   656     if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
   657 	register Tcl_Obj *objPtr;
   658  
   659 	objArrayPtr = codePtr->objArrayPtr;
   660 	for (i = 0;  i < numLitObjects;  i++) {
   661 	    objPtr = *objArrayPtr;
   662 	    if (objPtr) {
   663 		Tcl_DecrRefCount(objPtr);
   664 	    }
   665 	    objArrayPtr++;
   666 	}
   667 	codePtr->numLitObjects = 0;
   668     } else if (interp != NULL) {
   669 	/*
   670 	 * If the interp has already been freed, then Tcl will have already 
   671 	 * forcefully released all the literals used by ByteCodes compiled
   672 	 * with respect to that interp.
   673 	 */
   674 	 
   675 	objArrayPtr = codePtr->objArrayPtr;
   676 	for (i = 0;  i < numLitObjects;  i++) {
   677 	    /*
   678 	     * TclReleaseLiteral sets a ByteCode's object array entry NULL to
   679 	     * indicate that it has already freed the literal.
   680 	     */
   681 	    
   682 	    if (*objArrayPtr != NULL) {
   683 		TclReleaseLiteral(interp, *objArrayPtr);
   684 	    }
   685 	    objArrayPtr++;
   686 	}
   687     }
   688     
   689     auxDataPtr = codePtr->auxDataArrayPtr;
   690     for (i = 0;  i < numAuxDataItems;  i++) {
   691 	if (auxDataPtr->type->freeProc != NULL) {
   692 	    (*auxDataPtr->type->freeProc)(auxDataPtr->clientData);
   693 	}
   694 	auxDataPtr++;
   695     }
   696 
   697 #ifdef TCL_TIP280
   698     /*
   699      * TIP #280. Release the location data associated with this byte code
   700      * structure, if any. NOTE: The interp we belong to may be gone already,
   701      * and the data with it.
   702      *
   703      * See also tclBasic.c, DeleteInterpProc
   704      */
   705 
   706     if (iPtr) {
   707 	Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr);
   708 	if (hePtr) {
   709 	    ExtCmdLoc* eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hePtr);
   710 	    int        i;
   711 
   712 	    if (eclPtr->type == TCL_LOCATION_SOURCE) {
   713 		Tcl_DecrRefCount (eclPtr->path);
   714 	    }
   715 	    for (i=0; i< eclPtr->nuloc; i++) {
   716 		ckfree ((char*) eclPtr->loc[i].line);
   717 	    }
   718 
   719 	    if (eclPtr->loc != NULL) {
   720 		ckfree ((char*) eclPtr->loc);
   721 	    }
   722 
   723 	    ckfree ((char*) eclPtr);
   724 	    Tcl_DeleteHashEntry (hePtr);
   725 	}
   726     }
   727 #endif
   728 
   729     TclHandleRelease(codePtr->interpHandle);
   730     ckfree((char *) codePtr);
   731 }
   732 
   733 /*
   734  *----------------------------------------------------------------------
   735  *
   736  * TclInitCompileEnv --
   737  *
   738  *	Initializes a CompileEnv compilation environment structure for the
   739  *	compilation of a string in an interpreter.
   740  *
   741  * Results:
   742  *	None.
   743  *
   744  * Side effects:
   745  *	The CompileEnv structure is initialized.
   746  *
   747  *----------------------------------------------------------------------
   748  */
   749 
   750 void
   751 #ifndef TCL_TIP280
   752 TclInitCompileEnv(interp, envPtr, string, numBytes)
   753 #else
   754 TclInitCompileEnv(interp, envPtr, string, numBytes, invoker, word)
   755 #endif
   756     Tcl_Interp *interp;		 /* The interpreter for which a CompileEnv
   757 				  * structure is initialized. */
   758     register CompileEnv *envPtr; /* Points to the CompileEnv structure to
   759 				  * initialize. */
   760     char *string;		 /* The source string to be compiled. */
   761     int numBytes;		 /* Number of bytes in source string. */
   762 #ifdef TCL_TIP280
   763     CONST CmdFrame* invoker;     /* Location context invoking the bcc */
   764     int word;                    /* Index of the word in that context
   765 				  * getting compiled */
   766 #endif
   767 {
   768     Interp *iPtr = (Interp *) interp;
   769     
   770     envPtr->iPtr = iPtr;
   771     envPtr->source = string;
   772     envPtr->numSrcBytes = numBytes;
   773     envPtr->procPtr = iPtr->compiledProcPtr;
   774     envPtr->numCommands = 0;
   775     envPtr->exceptDepth = 0;
   776     envPtr->maxExceptDepth = 0;
   777     envPtr->maxStackDepth = 0;
   778     envPtr->currStackDepth = 0;
   779     TclInitLiteralTable(&(envPtr->localLitTable));
   780 
   781     envPtr->codeStart = envPtr->staticCodeSpace;
   782     envPtr->codeNext = envPtr->codeStart;
   783     envPtr->codeEnd = (envPtr->codeStart + COMPILEENV_INIT_CODE_BYTES);
   784     envPtr->mallocedCodeArray = 0;
   785 
   786     envPtr->literalArrayPtr = envPtr->staticLiteralSpace;
   787     envPtr->literalArrayNext = 0;
   788     envPtr->literalArrayEnd = COMPILEENV_INIT_NUM_OBJECTS;
   789     envPtr->mallocedLiteralArray = 0;
   790     
   791     envPtr->exceptArrayPtr = envPtr->staticExceptArraySpace;
   792     envPtr->exceptArrayNext = 0;
   793     envPtr->exceptArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES;
   794     envPtr->mallocedExceptArray = 0;
   795     
   796     envPtr->cmdMapPtr = envPtr->staticCmdMapSpace;
   797     envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE;
   798     envPtr->mallocedCmdMap = 0;
   799 
   800 #ifdef TCL_TIP280
   801     /*
   802      * TIP #280: Set up the extended command location information, based on
   803      * the context invoking the byte code compiler. This structure is used to
   804      * keep the per-word line information for all compiled commands.
   805      *
   806      * See also tclBasic.c, TclEvalObjEx, for the equivalent code in the
   807      * non-compiling evaluator
   808      */
   809 
   810     envPtr->extCmdMapPtr        = (ExtCmdLoc*) ckalloc (sizeof (ExtCmdLoc));
   811     envPtr->extCmdMapPtr->loc   = NULL;
   812     envPtr->extCmdMapPtr->nloc  = 0;
   813     envPtr->extCmdMapPtr->nuloc = 0;
   814     envPtr->extCmdMapPtr->path  = NULL;
   815 
   816     if (invoker == NULL) {
   817         /* Initialize the compiler for relative counting */
   818 
   819 	envPtr->line               = 1;
   820 	envPtr->extCmdMapPtr->type = (envPtr->procPtr
   821 				      ? TCL_LOCATION_PROC
   822 				      : TCL_LOCATION_BC);
   823     } else {
   824         /* Initialize the compiler using the context, making counting absolute
   825 	 * to that context. Note that the context can be byte code
   826 	 * execution. In that case we have to fill out the missing pieces
   827 	 * (line, path, ...). Which may make change the type as well.
   828 	 */
   829 
   830 	if ((invoker->nline <= word) || (invoker->line[word] < 0)) {
   831 	    /* Word is not a literal, relative counting */
   832 
   833 	    envPtr->line               = 1;
   834 	    envPtr->extCmdMapPtr->type = (envPtr->procPtr
   835 					  ? TCL_LOCATION_PROC
   836 					  : TCL_LOCATION_BC);
   837 	} else {
   838 	    CmdFrame ctx = *invoker;
   839 	    int      pc  = 0;
   840 
   841 	    if (invoker->type == TCL_LOCATION_BC) {
   842 		/* Note: Type BC => ctx.data.eval.path    is not used.
   843 		 *                  ctx.data.tebc.codePtr is used instead.
   844 		 */
   845 		TclGetSrcInfoForPc (&ctx);
   846 		pc = 1;
   847 	    }
   848 
   849 	    envPtr->line               = ctx.line [word];
   850 	    envPtr->extCmdMapPtr->type = ctx.type;
   851 
   852 	    if (ctx.type == TCL_LOCATION_SOURCE) {
   853 		if (pc) {
   854 		    /* The reference 'TclGetSrcInfoForPc' made is transfered */
   855 		    envPtr->extCmdMapPtr->path = ctx.data.eval.path;
   856 		    ctx.data.eval.path = NULL;
   857 		} else {
   858 		    /* We have a new reference here */
   859 		    envPtr->extCmdMapPtr->path = ctx.data.eval.path;
   860 		    Tcl_IncrRefCount (envPtr->extCmdMapPtr->path);
   861 		}
   862 	    }
   863 	}
   864     }
   865 #endif
   866 
   867     envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace;
   868     envPtr->auxDataArrayNext = 0;
   869     envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE;
   870     envPtr->mallocedAuxDataArray = 0;
   871 }
   872 
   873 /*
   874  *----------------------------------------------------------------------
   875  *
   876  * TclFreeCompileEnv --
   877  *
   878  *	Free the storage allocated in a CompileEnv compilation environment
   879  *	structure.
   880  *
   881  * Results:
   882  *	None.
   883  * 
   884  * Side effects:
   885  *	Allocated storage in the CompileEnv structure is freed. Note that
   886  *	its local literal table is not deleted and its literal objects are
   887  *	not released. In addition, storage referenced by its auxiliary data
   888  *	items is not freed. This is done so that, when compilation is
   889  *	successful, "ownership" of these objects and aux data items is
   890  *	handed over to the corresponding ByteCode structure.
   891  *
   892  *----------------------------------------------------------------------
   893  */
   894 
   895 void
   896 TclFreeCompileEnv(envPtr)
   897     register CompileEnv *envPtr; /* Points to the CompileEnv structure. */
   898 {
   899     if (envPtr->mallocedCodeArray) {
   900 	ckfree((char *) envPtr->codeStart);
   901     }
   902     if (envPtr->mallocedLiteralArray) {
   903 	ckfree((char *) envPtr->literalArrayPtr);
   904     }
   905     if (envPtr->mallocedExceptArray) {
   906 	ckfree((char *) envPtr->exceptArrayPtr);
   907     }
   908     if (envPtr->mallocedCmdMap) {
   909 	ckfree((char *) envPtr->cmdMapPtr);
   910     }
   911     if (envPtr->mallocedAuxDataArray) {
   912 	ckfree((char *) envPtr->auxDataArrayPtr);
   913     }
   914 }
   915 
   916 #ifdef TCL_TIP280
   917 /*
   918  *----------------------------------------------------------------------
   919  *
   920  * TclWordKnownAtCompileTime --
   921  *
   922  *	Test whether the value of a token is completely known at compile time.
   923  *
   924  * Results:
   925  *	Returns true if the tokenPtr argument points to a word value that is
   926  *	completely known at compile time. Generally, values that are known at
   927  *	compile time can be compiled to their values, while values that cannot
   928  *	be known until substitution at runtime must be compiled to bytecode
   929  *	instructions that perform that substitution. For several commands,
   930  *	whether or not arguments are known at compile time determine whether
   931  *	it is worthwhile to compile at all.
   932  *
   933  * Side effects:
   934  *	None.
   935  *
   936  * TIP #280
   937  *----------------------------------------------------------------------
   938  */
   939 
   940 int
   941 TclWordKnownAtCompileTime (tokenPtr)
   942      Tcl_Token* tokenPtr;
   943 {
   944     int        i;
   945     Tcl_Token* sub;
   946 
   947     if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {return 1;};
   948     if (tokenPtr->type != TCL_TOKEN_WORD)        {return 0;};
   949 
   950     /* Check the sub tokens of the word. It is a literal if we find
   951      * only BS and TEXT tokens */
   952 
   953     for (i=0, sub = tokenPtr + 1;
   954 	 i < tokenPtr->numComponents;
   955 	 i++, sub ++) {
   956       if (sub->type == TCL_TOKEN_TEXT) continue;
   957       if (sub->type == TCL_TOKEN_BS)   continue;
   958       return 0;
   959     }
   960     return 1;
   961 }
   962 #endif
   963 
   964 /*
   965  *----------------------------------------------------------------------
   966  *
   967  * TclCompileScript --
   968  *
   969  *	Compile a Tcl script in a string.
   970  *
   971  * Results:
   972  *	The return value is TCL_OK on a successful compilation and TCL_ERROR
   973  *	on failure. If TCL_ERROR is returned, then the interpreter's result
   974  *	contains an error message.
   975  *
   976  *	interp->termOffset is set to the offset of the character in the
   977  *	script just after the last one successfully processed; this will be
   978  *	the offset of the ']' if (flags & TCL_BRACKET_TERM).
   979  *
   980  * Side effects:
   981  *	Adds instructions to envPtr to evaluate the script at runtime.
   982  *
   983  *----------------------------------------------------------------------
   984  */
   985 
   986 int
   987 TclCompileScript(interp, script, numBytes, nested, envPtr)
   988     Tcl_Interp *interp;		/* Used for error and status reporting.
   989 				 * Also serves as context for finding and
   990 				 * compiling commands.  May not be NULL. */
   991     CONST char *script;		/* The source script to compile. */
   992     int numBytes;		/* Number of bytes in script. If < 0, the
   993 				 * script consists of all bytes up to the
   994 				 * first null character. */
   995     int nested;			/* Non-zero means this is a nested command:
   996 				 * close bracket ']' should be considered a
   997 				 * command terminator. If zero, close
   998 				 * bracket has no special meaning. */
   999     CompileEnv *envPtr;		/* Holds resulting instructions. */
  1000 {
  1001     Interp *iPtr = (Interp *) interp;
  1002     Tcl_Parse parse;
  1003     int lastTopLevelCmdIndex = -1;
  1004     				/* Index of most recent toplevel command in
  1005  				 * the command location table. Initialized
  1006 				 * to avoid compiler warning. */
  1007     int startCodeOffset = -1;	/* Offset of first byte of current command's
  1008                                  * code. Init. to avoid compiler warning. */
  1009     unsigned char *entryCodeNext = envPtr->codeNext;
  1010     CONST char *p, *next;
  1011     Namespace *cmdNsPtr;
  1012     Command *cmdPtr;
  1013     Tcl_Token *tokenPtr;
  1014     int bytesLeft, isFirstCmd, gotParse, wordIdx, currCmdIndex;
  1015     int commandLength, objIndex, code;
  1016     Tcl_DString ds;
  1017 
  1018 #ifdef TCL_TIP280
  1019     /* TIP #280 */
  1020     ExtCmdLoc* eclPtr = envPtr->extCmdMapPtr;
  1021     int* wlines;
  1022     int  wlineat, cmdLine;
  1023 #endif
  1024 
  1025     Tcl_DStringInit(&ds);
  1026 
  1027     if (numBytes < 0) {
  1028 	numBytes = strlen(script);
  1029     }
  1030     Tcl_ResetResult(interp);
  1031     isFirstCmd = 1;
  1032 
  1033     /*
  1034      * Each iteration through the following loop compiles the next
  1035      * command from the script.
  1036      */
  1037 
  1038     p = script;
  1039     bytesLeft = numBytes;
  1040     gotParse = 0;
  1041 #ifdef TCL_TIP280
  1042     cmdLine = envPtr->line;
  1043 #endif
  1044 
  1045     do {
  1046 	if (Tcl_ParseCommand(interp, p, bytesLeft, nested, &parse) != TCL_OK) {
  1047 	    code = TCL_ERROR;
  1048 	    goto error;
  1049 	}
  1050 	gotParse = 1;
  1051 	if (nested) {
  1052 	    /*
  1053 	     * This is an unusual situation where the caller has passed us
  1054 	     * a non-zero value for "nested".  How unusual?  Well, this
  1055 	     * procedure, TclCompileScript, is internal to Tcl, so all
  1056 	     * callers should be within Tcl itself.  All but one of those
  1057 	     * callers explicitly pass in (nested = 0).  The exceptional
  1058 	     * caller is TclSetByteCodeFromAny, which will pass in
  1059 	     * (nested = 1) if and only if the flag TCL_BRACKET_TERM
  1060 	     * is set in the evalFlags field of interp.
  1061 	     *
  1062 	     * It appears that the TCL_BRACKET_TERM flag is only ever set
  1063 	     * by Tcl_SubstObj, and it immediately calls Tcl_EvalEx
  1064 	     * which clears the flag before passing the interp along.
  1065 	     * So, I don't think this procedure, TclCompileScript, is
  1066 	     * **ever** called with (nested != 0). 
  1067 	     * (The testsuite indeed doesn't exercise this code. MS)
  1068 	     *
  1069 	     * This means that the branches in this procedure that are
  1070 	     * only active when (nested != 0) are probably never exercised.
  1071 	     * This means that any bugs in them go unnoticed, and any bug
  1072 	     * fixes in them have a semi-theoretical nature.
  1073 	     *
  1074 	     * All that said, the spec for this procedure says it should
  1075 	     * handle the (nested != 0) case, so here's an attempt to fix
  1076 	     * bugs (Tcl Bug 681841) in that case.  Just in case some
  1077 	     * callers eventually come along and expect it to work...
  1078 	     */
  1079 
  1080 	    if (parse.term == (script + numBytes)) {
  1081 		/* 
  1082 		 * The (nested != 0) case is meant to indicate that the
  1083 		 * caller found an open bracket ([) and asked us to
  1084 		 * parse and compile Tcl commands up to the matching
  1085 		 * close bracket (]).  We have to detect and handle
  1086 		 * the case where the close bracket is missing.
  1087 		 */
  1088 
  1089 		Tcl_SetObjResult(interp,
  1090 			Tcl_NewStringObj("missing close-bracket", -1));
  1091 		code = TCL_ERROR;
  1092 		goto error;
  1093 	    }
  1094 	}
  1095 	if (parse.numWords > 0) {
  1096 	    /*
  1097 	     * If not the first command, pop the previous command's result
  1098 	     * and, if we're compiling a top level command, update the last
  1099 	     * command's code size to account for the pop instruction.
  1100 	     */
  1101 
  1102 	    if (!isFirstCmd) {
  1103 		TclEmitOpcode(INST_POP, envPtr);
  1104 		if (!nested) {
  1105 		    envPtr->cmdMapPtr[lastTopLevelCmdIndex].numCodeBytes =
  1106 			   (envPtr->codeNext - envPtr->codeStart)
  1107 			   - startCodeOffset;
  1108 		}
  1109 	    }
  1110 
  1111 	    /*
  1112 	     * Determine the actual length of the command.
  1113 	     */
  1114 
  1115 	    commandLength = parse.commandSize;
  1116 	    if (parse.term == parse.commandStart + commandLength - 1) {
  1117 		/*
  1118 		 * The command terminator character (such as ; or ]) is
  1119 		 * the last character in the parsed command.  Reduce the
  1120 		 * length by one so that the trace message doesn't include
  1121 		 * the terminator character.
  1122 		 */
  1123 		
  1124 		commandLength -= 1;
  1125 	    }
  1126 
  1127 #ifdef TCL_COMPILE_DEBUG
  1128 	    /*
  1129              * If tracing, print a line for each top level command compiled.
  1130              */
  1131 
  1132 	    if ((tclTraceCompile >= 1)
  1133 		    && !nested && (envPtr->procPtr == NULL)) {
  1134 		fprintf(stdout, "  Compiling: ");
  1135 		TclPrintSource(stdout, parse.commandStart,
  1136 			TclMin(commandLength, 55));
  1137 		fprintf(stdout, "\n");
  1138 	    }
  1139 #endif
  1140 	    /*
  1141 	     * Each iteration of the following loop compiles one word
  1142 	     * from the command.
  1143 	     */
  1144 	    
  1145 	    envPtr->numCommands++;
  1146 	    currCmdIndex = (envPtr->numCommands - 1);
  1147 	    if (!nested) {
  1148 		lastTopLevelCmdIndex = currCmdIndex;
  1149 	    }
  1150 	    startCodeOffset = (envPtr->codeNext - envPtr->codeStart);
  1151 	    EnterCmdStartData(envPtr, currCmdIndex,
  1152 	            (parse.commandStart - envPtr->source), startCodeOffset);
  1153 
  1154 #ifdef TCL_TIP280
  1155 	    /* TIP #280. Scan the words and compute the extended location
  1156 	     * information. The map first contain full per-word line
  1157 	     * information for use by the compiler. This is later replaced by
  1158 	     * a reduced form which signals non-literal words, stored in
  1159 	     * 'wlines'.
  1160 	     */
  1161 
  1162 	    TclAdvanceLines (&cmdLine, p, parse.commandStart);
  1163 	    EnterCmdWordData (eclPtr, (parse.commandStart - envPtr->source),
  1164 			      parse.tokenPtr, parse.commandStart, parse.commandSize,
  1165 			      parse.numWords, cmdLine, &wlines);
  1166 	    wlineat = eclPtr->nuloc - 1;
  1167 #endif
  1168 
  1169 	    for (wordIdx = 0, tokenPtr = parse.tokenPtr;
  1170 		    wordIdx < parse.numWords;
  1171 		    wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) {
  1172 #ifdef TCL_TIP280
  1173 	        envPtr->line = eclPtr->loc [wlineat].line [wordIdx];
  1174 #endif
  1175 		if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
  1176 		    /*
  1177 		     * If this is the first word and the command has a
  1178 		     * compile procedure, let it compile the command.
  1179 		     */
  1180 
  1181 		    if (wordIdx == 0) {
  1182 			if (envPtr->procPtr != NULL) {
  1183 			    cmdNsPtr = envPtr->procPtr->cmdPtr->nsPtr;
  1184 			} else {
  1185 			    cmdNsPtr = NULL; /* use current NS */
  1186 			}
  1187 
  1188 			/*
  1189 			 * We copy the string before trying to find the command
  1190 			 * by name.  We used to modify the string in place, but
  1191 			 * this is not safe because the name resolution
  1192 			 * handlers could have side effects that rely on the
  1193 			 * unmodified string.
  1194 			 */
  1195 
  1196 			Tcl_DStringSetLength(&ds, 0);
  1197 			Tcl_DStringAppend(&ds, tokenPtr[1].start,
  1198 				tokenPtr[1].size);
  1199 
  1200 			cmdPtr = (Command *) Tcl_FindCommand(interp,
  1201 				Tcl_DStringValue(&ds),
  1202 			        (Tcl_Namespace *) cmdNsPtr, /*flags*/ 0);
  1203 
  1204 			if ((cmdPtr != NULL)
  1205 			        && (cmdPtr->compileProc != NULL)
  1206 			        && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES)
  1207 			        && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) {
  1208 			    int savedNumCmds = envPtr->numCommands;
  1209 			    unsigned int savedCodeNext =
  1210 				    envPtr->codeNext - envPtr->codeStart;
  1211 
  1212 			    code = (*(cmdPtr->compileProc))(interp, &parse,
  1213 			            envPtr);
  1214 			    if (code == TCL_OK) {
  1215 				goto finishCommand;
  1216 			    } else if (code == TCL_OUT_LINE_COMPILE) {
  1217 				/*
  1218 				 * Restore numCommands and codeNext to their correct 
  1219 				 * values, removing any commands compiled before 
  1220 				 * TCL_OUT_LINE_COMPILE [Bugs 705406 and 735055]
  1221 				 */
  1222 				envPtr->numCommands = savedNumCmds;
  1223 				envPtr->codeNext = envPtr->codeStart + savedCodeNext;
  1224 			    } else { /* an error */
  1225 				/*
  1226 				 * There was a compilation error, the last
  1227 				 * command did not get compiled into (*envPtr).
  1228 				 * Decrement the number of commands
  1229 				 * claimed to be in (*envPtr).
  1230 				 */
  1231 				envPtr->numCommands--;
  1232 				goto log;
  1233 			    }
  1234 			}
  1235 
  1236 			/*
  1237 			 * No compile procedure so push the word. If the
  1238 			 * command was found, push a CmdName object to
  1239 			 * reduce runtime lookups.
  1240 			 */
  1241 
  1242 			objIndex = TclRegisterNewLiteral(envPtr,
  1243 				tokenPtr[1].start, tokenPtr[1].size);
  1244 			if (cmdPtr != NULL) {
  1245 			    TclSetCmdNameObj(interp,
  1246 			           envPtr->literalArrayPtr[objIndex].objPtr,
  1247 				   cmdPtr);
  1248 			}
  1249 		    } else {
  1250 			objIndex = TclRegisterNewLiteral(envPtr,
  1251 				tokenPtr[1].start, tokenPtr[1].size);
  1252 		    }
  1253 		    TclEmitPush(objIndex, envPtr);
  1254 		} else {
  1255 		    /*
  1256 		     * The word is not a simple string of characters.
  1257 		     */
  1258 		    code = TclCompileTokens(interp, tokenPtr+1,
  1259 			    tokenPtr->numComponents, envPtr);
  1260 		    if (code != TCL_OK) {
  1261 			goto log;
  1262 		    }
  1263 		}
  1264 	    }
  1265 
  1266 	    /*
  1267 	     * Emit an invoke instruction for the command. We skip this
  1268 	     * if a compile procedure was found for the command.
  1269 	     */
  1270 	    
  1271 	    if (wordIdx > 0) {
  1272 		if (wordIdx <= 255) {
  1273 		    TclEmitInstInt1(INST_INVOKE_STK1, wordIdx, envPtr);
  1274 		} else {
  1275 		    TclEmitInstInt4(INST_INVOKE_STK4, wordIdx, envPtr);
  1276 		}
  1277 	    }
  1278 
  1279 	    /*
  1280 	     * Update the compilation environment structure and record the
  1281 	     * offsets of the source and code for the command.
  1282 	     */
  1283 
  1284 	    finishCommand:
  1285 	    EnterCmdExtentData(envPtr, currCmdIndex, commandLength,
  1286 		    (envPtr->codeNext-envPtr->codeStart) - startCodeOffset);
  1287 	    isFirstCmd = 0;
  1288 
  1289 #ifdef TCL_TIP280
  1290 	    /* TIP #280: Free full form of per-word line data and insert
  1291 	     * the reduced form now
  1292 	     */
  1293 	    ckfree ((char*) eclPtr->loc [wlineat].line);
  1294 	    eclPtr->loc [wlineat].line = wlines;
  1295 #endif
  1296 	} /* end if parse.numWords > 0 */
  1297 
  1298 	/*
  1299 	 * Advance to the next command in the script.
  1300 	 */
  1301 
  1302 	next = parse.commandStart + parse.commandSize;
  1303 	bytesLeft -= (next - p);
  1304 	p = next;
  1305 #ifdef TCL_TIP280
  1306 	/* TIP #280 : Track lines in the just compiled command */
  1307 	TclAdvanceLines (&cmdLine, parse.commandStart, p);
  1308 #endif
  1309 	Tcl_FreeParse(&parse);
  1310 	gotParse = 0;
  1311 	if (nested && (*parse.term == ']')) {
  1312 	    /*
  1313 	     * We get here in the special case where TCL_BRACKET_TERM was
  1314 	     * set in the interpreter and the latest parsed command was
  1315 	     * terminated by the matching close-bracket we were looking for.
  1316 	     * Stop compilation.
  1317 	     */
  1318 	    
  1319 	    break;
  1320 	}
  1321     } while (bytesLeft > 0);
  1322 
  1323     /*
  1324      * If the source script yielded no instructions (e.g., if it was empty),
  1325      * push an empty string as the command's result.
  1326      */
  1327     
  1328     if (envPtr->codeNext == entryCodeNext) {
  1329 	TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0),
  1330 	        envPtr);
  1331     }
  1332     
  1333     if (nested) {
  1334 	/*
  1335 	 * When (nested != 0) back up 1 character to have 
  1336 	 * iPtr->termOffset indicate the offset to the matching
  1337 	 * close-bracket.
  1338 	 */
  1339 
  1340 	iPtr->termOffset = (p - 1) - script;
  1341     } else {
  1342 	iPtr->termOffset = (p - script);
  1343     }
  1344     Tcl_DStringFree(&ds);
  1345     return TCL_OK;
  1346 	
  1347     error:
  1348     /*
  1349      * Generate various pieces of error information, such as the line
  1350      * number where the error occurred and information to add to the
  1351      * errorInfo variable. Then free resources that had been allocated
  1352      * to the command.
  1353      */
  1354 
  1355     commandLength = parse.commandSize;
  1356     if (parse.term == parse.commandStart + commandLength - 1) {
  1357 	/*
  1358 	 * The terminator character (such as ; or ]) of the command where
  1359 	 * the error occurred is the last character in the parsed command.
  1360 	 * Reduce the length by one so that the error message doesn't
  1361 	 * include the terminator character.
  1362 	 */
  1363 
  1364 	commandLength -= 1;
  1365     }
  1366 
  1367     log:
  1368     LogCompilationInfo(interp, script, parse.commandStart, commandLength);
  1369     if (gotParse) {
  1370 	Tcl_FreeParse(&parse);
  1371     }
  1372     iPtr->termOffset = (p - script);
  1373     Tcl_DStringFree(&ds);
  1374     return code;
  1375 }
  1376 
  1377 /*
  1378  *----------------------------------------------------------------------
  1379  *
  1380  * TclCompileTokens --
  1381  *
  1382  *	Given an array of tokens parsed from a Tcl command (e.g., the tokens
  1383  *	that make up a word) this procedure emits instructions to evaluate
  1384  *	the tokens and concatenate their values to form a single result
  1385  *	value on the interpreter's runtime evaluation stack.
  1386  *
  1387  * Results:
  1388  *	The return value is a standard Tcl result. If an error occurs, an
  1389  *	error message is left in the interpreter's result.
  1390  *	
  1391  * Side effects:
  1392  *	Instructions are added to envPtr to push and evaluate the tokens
  1393  *	at runtime.
  1394  *
  1395  *----------------------------------------------------------------------
  1396  */
  1397 
  1398 int
  1399 TclCompileTokens(interp, tokenPtr, count, envPtr)
  1400     Tcl_Interp *interp;		/* Used for error and status reporting. */
  1401     Tcl_Token *tokenPtr;	/* Pointer to first in an array of tokens
  1402 				 * to compile. */
  1403     int count;			/* Number of tokens to consider at tokenPtr.
  1404 				 * Must be at least 1. */
  1405     CompileEnv *envPtr;		/* Holds the resulting instructions. */
  1406 {
  1407     Tcl_DString textBuffer;	/* Holds concatenated chars from adjacent
  1408 				 * TCL_TOKEN_TEXT, TCL_TOKEN_BS tokens. */
  1409     char buffer[TCL_UTF_MAX];
  1410     CONST char *name, *p;
  1411     int numObjsToConcat, nameBytes, localVarName, localVar;
  1412     int length, i, code;
  1413     unsigned char *entryCodeNext = envPtr->codeNext;
  1414 
  1415     Tcl_DStringInit(&textBuffer);
  1416     numObjsToConcat = 0;
  1417     for ( ;  count > 0;  count--, tokenPtr++) {
  1418 	switch (tokenPtr->type) {
  1419 	    case TCL_TOKEN_TEXT:
  1420 		Tcl_DStringAppend(&textBuffer, tokenPtr->start,
  1421 			tokenPtr->size);
  1422 		break;
  1423 
  1424 	    case TCL_TOKEN_BS:
  1425 		length = Tcl_UtfBackslash(tokenPtr->start, (int *) NULL,
  1426 			buffer);
  1427 		Tcl_DStringAppend(&textBuffer, buffer, length);
  1428 		break;
  1429 
  1430 	    case TCL_TOKEN_COMMAND:
  1431 		/*
  1432 		 * Push any accumulated chars appearing before the command.
  1433 		 */
  1434 		
  1435 		if (Tcl_DStringLength(&textBuffer) > 0) {
  1436 		    int literal;
  1437 		    
  1438 		    literal = TclRegisterLiteral(envPtr,
  1439 			    Tcl_DStringValue(&textBuffer),
  1440 			    Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);
  1441 		    TclEmitPush(literal, envPtr);
  1442 		    numObjsToConcat++;
  1443 		    Tcl_DStringFree(&textBuffer);
  1444 		}
  1445 		
  1446 		code = TclCompileScript(interp, tokenPtr->start+1,
  1447 			tokenPtr->size-2, /*nested*/ 0,	envPtr);
  1448 		if (code != TCL_OK) {
  1449 		    goto error;
  1450 		}
  1451 		numObjsToConcat++;
  1452 		break;
  1453 
  1454 	    case TCL_TOKEN_VARIABLE:
  1455 		/*
  1456 		 * Push any accumulated chars appearing before the $<var>.
  1457 		 */
  1458 		
  1459 		if (Tcl_DStringLength(&textBuffer) > 0) {
  1460 		    int literal;
  1461 		    
  1462 		    literal = TclRegisterLiteral(envPtr,
  1463 			    Tcl_DStringValue(&textBuffer),
  1464 			    Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);
  1465 		    TclEmitPush(literal, envPtr);
  1466 		    numObjsToConcat++;
  1467 		    Tcl_DStringFree(&textBuffer);
  1468 		}
  1469 		
  1470 		/*
  1471 		 * Determine how the variable name should be handled: if it contains 
  1472 		 * any namespace qualifiers it is not a local variable (localVarName=-1);
  1473 		 * if it looks like an array element and the token has a single component, 
  1474 		 * it should not be created here [Bug 569438] (localVarName=0); otherwise, 
  1475 		 * the local variable can safely be created (localVarName=1).
  1476 		 */
  1477 		
  1478 		name = tokenPtr[1].start;
  1479 		nameBytes = tokenPtr[1].size;
  1480 		localVarName = -1;
  1481 		if (envPtr->procPtr != NULL) {
  1482 		    localVarName = 1;
  1483 		    for (i = 0, p = name;  i < nameBytes;  i++, p++) {
  1484 			if ((*p == ':') && (i < (nameBytes-1))
  1485 			        && (*(p+1) == ':')) {
  1486 			    localVarName = -1;
  1487 			    break;
  1488 			} else if ((*p == '(')
  1489 			        && (tokenPtr->numComponents == 1) 
  1490 				&& (*(name + nameBytes - 1) == ')')) {
  1491 			    localVarName = 0;
  1492 			    break;
  1493 			}
  1494 		    }
  1495 		}
  1496 
  1497 		/*
  1498 		 * Either push the variable's name, or find its index in
  1499 		 * the array of local variables in a procedure frame. 
  1500 		 */
  1501 
  1502 		localVar = -1;
  1503 		if (localVarName != -1) {
  1504 		    localVar = TclFindCompiledLocal(name, nameBytes, 
  1505 			        localVarName, /*flags*/ 0, envPtr->procPtr);
  1506 		}
  1507 		if (localVar < 0) {
  1508 		    TclEmitPush(TclRegisterNewLiteral(envPtr, name, nameBytes),
  1509 			    envPtr); 
  1510 		}
  1511 
  1512 		/*
  1513 		 * Emit instructions to load the variable.
  1514 		 */
  1515 		
  1516 		if (tokenPtr->numComponents == 1) {
  1517 		    if (localVar < 0) {
  1518 			TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);
  1519 		    } else if (localVar <= 255) {
  1520 			TclEmitInstInt1(INST_LOAD_SCALAR1, localVar,
  1521 			        envPtr);
  1522 		    } else {
  1523 			TclEmitInstInt4(INST_LOAD_SCALAR4, localVar,
  1524 				envPtr);
  1525 		    }
  1526 		} else {
  1527 		    code = TclCompileTokens(interp, tokenPtr+2,
  1528 			    tokenPtr->numComponents-1, envPtr);
  1529 		    if (code != TCL_OK) {
  1530 			char errorBuffer[150];
  1531 			sprintf(errorBuffer,
  1532 			        "\n    (parsing index for array \"%.*s\")",
  1533 				((nameBytes > 100)? 100 : nameBytes), name);
  1534 			Tcl_AddObjErrorInfo(interp, errorBuffer, -1);
  1535 			goto error;
  1536 		    }
  1537 		    if (localVar < 0) {
  1538 			TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr);
  1539 		    } else if (localVar <= 255) {
  1540 			TclEmitInstInt1(INST_LOAD_ARRAY1, localVar,
  1541 			        envPtr);
  1542 		    } else {
  1543 			TclEmitInstInt4(INST_LOAD_ARRAY4, localVar,
  1544 			        envPtr);
  1545 		    }
  1546 		}
  1547 		numObjsToConcat++;
  1548 		count -= tokenPtr->numComponents;
  1549 		tokenPtr += tokenPtr->numComponents;
  1550 		break;
  1551 
  1552 	    default:
  1553 		panic("Unexpected token type in TclCompileTokens");
  1554 	}
  1555     }
  1556 
  1557     /*
  1558      * Push any accumulated characters appearing at the end.
  1559      */
  1560 
  1561     if (Tcl_DStringLength(&textBuffer) > 0) {
  1562 	int literal;
  1563 
  1564 	literal = TclRegisterLiteral(envPtr, Tcl_DStringValue(&textBuffer),
  1565 	        Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);
  1566 	TclEmitPush(literal, envPtr);
  1567 	numObjsToConcat++;
  1568     }
  1569 
  1570     /*
  1571      * If necessary, concatenate the parts of the word.
  1572      */
  1573 
  1574     while (numObjsToConcat > 255) {
  1575 	TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
  1576 	numObjsToConcat -= 254;	/* concat pushes 1 obj, the result */
  1577     }
  1578     if (numObjsToConcat > 1) {
  1579 	TclEmitInstInt1(INST_CONCAT1, numObjsToConcat, envPtr);
  1580     }
  1581 
  1582     /*
  1583      * If the tokens yielded no instructions, push an empty string.
  1584      */
  1585     
  1586     if (envPtr->codeNext == entryCodeNext) {
  1587 	TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0),
  1588 	        envPtr);
  1589     }
  1590     Tcl_DStringFree(&textBuffer);
  1591     return TCL_OK;
  1592 
  1593     error:
  1594     Tcl_DStringFree(&textBuffer);
  1595     return code;
  1596 }
  1597 
  1598 /*
  1599  *----------------------------------------------------------------------
  1600  *
  1601  * TclCompileCmdWord --
  1602  *
  1603  *	Given an array of parse tokens for a word containing one or more Tcl
  1604  *	commands, emit inline instructions to execute them. This procedure
  1605  *	differs from TclCompileTokens in that a simple word such as a loop
  1606  *	body enclosed in braces is not just pushed as a string, but is
  1607  *	itself parsed into tokens and compiled.
  1608  *
  1609  * Results:
  1610  *	The return value is a standard Tcl result. If an error occurs, an
  1611  *	error message is left in the interpreter's result.
  1612  *	
  1613  * Side effects:
  1614  *	Instructions are added to envPtr to execute the tokens at runtime.
  1615  *
  1616  *----------------------------------------------------------------------
  1617  */
  1618 
  1619 int
  1620 TclCompileCmdWord(interp, tokenPtr, count, envPtr)
  1621     Tcl_Interp *interp;		/* Used for error and status reporting. */
  1622     Tcl_Token *tokenPtr;	/* Pointer to first in an array of tokens
  1623 				 * for a command word to compile inline. */
  1624     int count;			/* Number of tokens to consider at tokenPtr.
  1625 				 * Must be at least 1. */
  1626     CompileEnv *envPtr;		/* Holds the resulting instructions. */
  1627 {
  1628     int code;
  1629 
  1630     /*
  1631      * Handle the common case: if there is a single text token, compile it
  1632      * into an inline sequence of instructions.
  1633      */
  1634     
  1635     if ((count == 1) && (tokenPtr->type == TCL_TOKEN_TEXT)) {
  1636 	code = TclCompileScript(interp, tokenPtr->start, tokenPtr->size,
  1637 	        /*nested*/ 0, envPtr);
  1638 	return code;
  1639     }
  1640 
  1641     /*
  1642      * Multiple tokens or the single token involves substitutions. Emit
  1643      * instructions to invoke the eval command procedure at runtime on the
  1644      * result of evaluating the tokens.
  1645      */
  1646 
  1647     code = TclCompileTokens(interp, tokenPtr, count, envPtr);
  1648     if (code != TCL_OK) {
  1649 	return code;
  1650     }
  1651     TclEmitOpcode(INST_EVAL_STK, envPtr);
  1652     return TCL_OK;
  1653 }
  1654 
  1655 /*
  1656  *----------------------------------------------------------------------
  1657  *
  1658  * TclCompileExprWords --
  1659  *
  1660  *	Given an array of parse tokens representing one or more words that
  1661  *	contain a Tcl expression, emit inline instructions to execute the
  1662  *	expression. This procedure differs from TclCompileExpr in that it
  1663  *	supports Tcl's two-level substitution semantics for expressions that
  1664  *	appear as command words.
  1665  *
  1666  * Results:
  1667  *	The return value is a standard Tcl result. If an error occurs, an
  1668  *	error message is left in the interpreter's result.
  1669  *	
  1670  * Side effects:
  1671  *	Instructions are added to envPtr to execute the expression.
  1672  *
  1673  *----------------------------------------------------------------------
  1674  */
  1675 
  1676 int
  1677 TclCompileExprWords(interp, tokenPtr, numWords, envPtr)
  1678     Tcl_Interp *interp;		/* Used for error and status reporting. */
  1679     Tcl_Token *tokenPtr;	/* Points to first in an array of word
  1680 				 * tokens tokens for the expression to
  1681 				 * compile inline. */
  1682     int numWords;		/* Number of word tokens starting at
  1683 				 * tokenPtr. Must be at least 1. Each word
  1684 				 * token contains one or more subtokens. */
  1685     CompileEnv *envPtr;		/* Holds the resulting instructions. */
  1686 {
  1687     Tcl_Token *wordPtr;
  1688     int numBytes, i, code;
  1689     CONST char *script;
  1690 
  1691     code = TCL_OK;
  1692 
  1693     /*
  1694      * If the expression is a single word that doesn't require
  1695      * substitutions, just compile its string into inline instructions.
  1696      */
  1697 
  1698     if ((numWords == 1) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
  1699 	script = tokenPtr[1].start;
  1700 	numBytes = tokenPtr[1].size;
  1701 	code = TclCompileExpr(interp, script, numBytes, envPtr);
  1702 	return code;
  1703     }
  1704    
  1705     /*
  1706      * Emit code to call the expr command proc at runtime. Concatenate the
  1707      * (already substituted once) expr tokens with a space between each.
  1708      */
  1709 
  1710     wordPtr = tokenPtr;
  1711     for (i = 0;  i < numWords;  i++) {
  1712 	code = TclCompileTokens(interp, wordPtr+1, wordPtr->numComponents,
  1713                 envPtr);
  1714 	if (code != TCL_OK) {
  1715 	    break;
  1716 	}
  1717 	if (i < (numWords - 1)) {
  1718 	    TclEmitPush(TclRegisterLiteral(envPtr, " ", 1, /*onHeap*/ 0),
  1719 	            envPtr);
  1720 	}
  1721 	wordPtr += (wordPtr->numComponents + 1);
  1722     }
  1723     if (code == TCL_OK) {
  1724 	int concatItems = 2*numWords - 1;
  1725 	while (concatItems > 255) {
  1726 	    TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
  1727 	    concatItems -= 254;
  1728 	}
  1729 	if (concatItems > 1) {
  1730 	    TclEmitInstInt1(INST_CONCAT1, concatItems, envPtr);
  1731 	}
  1732 	TclEmitOpcode(INST_EXPR_STK, envPtr);
  1733     }
  1734 
  1735     return code;
  1736 }
  1737 
  1738 /*
  1739  *----------------------------------------------------------------------
  1740  *
  1741  * TclInitByteCodeObj --
  1742  *
  1743  *	Create a ByteCode structure and initialize it from a CompileEnv
  1744  *	compilation environment structure. The ByteCode structure is
  1745  *	smaller and contains just that information needed to execute
  1746  *	the bytecode instructions resulting from compiling a Tcl script.
  1747  *	The resulting structure is placed in the specified object.
  1748  *
  1749  * Results:
  1750  *	A newly constructed ByteCode object is stored in the internal
  1751  *	representation of the objPtr.
  1752  *
  1753  * Side effects:
  1754  *	A single heap object is allocated to hold the new ByteCode structure
  1755  *	and its code, object, command location, and aux data arrays. Note
  1756  *	that "ownership" (i.e., the pointers to) the Tcl objects and aux
  1757  *	data items will be handed over to the new ByteCode structure from
  1758  *	the CompileEnv structure.
  1759  *
  1760  *----------------------------------------------------------------------
  1761  */
  1762 
  1763 void
  1764 TclInitByteCodeObj(objPtr, envPtr)
  1765     Tcl_Obj *objPtr;		 /* Points object that should be
  1766 				  * initialized, and whose string rep
  1767 				  * contains the source code. */
  1768     register CompileEnv *envPtr; /* Points to the CompileEnv structure from
  1769 				  * which to create a ByteCode structure. */
  1770 {
  1771     register ByteCode *codePtr;
  1772     size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes;
  1773     size_t auxDataArrayBytes, structureSize;
  1774     register unsigned char *p;
  1775 #ifdef TCL_COMPILE_DEBUG
  1776     unsigned char *nextPtr;
  1777 #endif
  1778     int numLitObjects = envPtr->literalArrayNext;
  1779     Namespace *namespacePtr;
  1780     int i;
  1781 #ifdef TCL_TIP280
  1782     int new;
  1783 #endif
  1784     Interp *iPtr;
  1785 
  1786     iPtr = envPtr->iPtr;
  1787 
  1788     codeBytes = (envPtr->codeNext - envPtr->codeStart);
  1789     objArrayBytes = (envPtr->literalArrayNext * sizeof(Tcl_Obj *));
  1790     exceptArrayBytes = (envPtr->exceptArrayNext * sizeof(ExceptionRange));
  1791     auxDataArrayBytes = (envPtr->auxDataArrayNext * sizeof(AuxData));
  1792     cmdLocBytes = GetCmdLocEncodingSize(envPtr);
  1793     
  1794     /*
  1795      * Compute the total number of bytes needed for this bytecode.
  1796      */
  1797 
  1798     structureSize = sizeof(ByteCode);
  1799     structureSize += TCL_ALIGN(codeBytes);        /* align object array */
  1800     structureSize += TCL_ALIGN(objArrayBytes);    /* align exc range arr */
  1801     structureSize += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */
  1802     structureSize += auxDataArrayBytes;
  1803     structureSize += cmdLocBytes;
  1804 
  1805     if (envPtr->iPtr->varFramePtr != NULL) {
  1806         namespacePtr = envPtr->iPtr->varFramePtr->nsPtr;
  1807     } else {
  1808         namespacePtr = envPtr->iPtr->globalNsPtr;
  1809     }
  1810     
  1811     p = (unsigned char *) ckalloc((size_t) structureSize);
  1812     codePtr = (ByteCode *) p;
  1813     codePtr->interpHandle = TclHandlePreserve(iPtr->handle);
  1814     codePtr->compileEpoch = iPtr->compileEpoch;
  1815     codePtr->nsPtr = namespacePtr;
  1816     codePtr->nsEpoch = namespacePtr->resolverEpoch;
  1817     codePtr->refCount = 1;
  1818     codePtr->flags = 0;
  1819     codePtr->source = envPtr->source;
  1820     codePtr->procPtr = envPtr->procPtr;
  1821 
  1822     codePtr->numCommands = envPtr->numCommands;
  1823     codePtr->numSrcBytes = envPtr->numSrcBytes;
  1824     codePtr->numCodeBytes = codeBytes;
  1825     codePtr->numLitObjects = numLitObjects;
  1826     codePtr->numExceptRanges = envPtr->exceptArrayNext;
  1827     codePtr->numAuxDataItems = envPtr->auxDataArrayNext;
  1828     codePtr->numCmdLocBytes = cmdLocBytes;
  1829     codePtr->maxExceptDepth = envPtr->maxExceptDepth;
  1830     codePtr->maxStackDepth = envPtr->maxStackDepth;
  1831 
  1832     p += sizeof(ByteCode);
  1833     codePtr->codeStart = p;
  1834     memcpy((VOID *) p, (VOID *) envPtr->codeStart, (size_t) codeBytes);
  1835     
  1836     p += TCL_ALIGN(codeBytes);	      /* align object array */
  1837     codePtr->objArrayPtr = (Tcl_Obj **) p;
  1838     for (i = 0;  i < numLitObjects;  i++) {
  1839 	codePtr->objArrayPtr[i] = envPtr->literalArrayPtr[i].objPtr;
  1840     }
  1841 
  1842     p += TCL_ALIGN(objArrayBytes);    /* align exception range array */
  1843     if (exceptArrayBytes > 0) {
  1844 	codePtr->exceptArrayPtr = (ExceptionRange *) p;
  1845 	memcpy((VOID *) p, (VOID *) envPtr->exceptArrayPtr,
  1846 	        (size_t) exceptArrayBytes);
  1847     } else {
  1848 	codePtr->exceptArrayPtr = NULL;
  1849     }
  1850     
  1851     p += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */
  1852     if (auxDataArrayBytes > 0) {
  1853 	codePtr->auxDataArrayPtr = (AuxData *) p;
  1854 	memcpy((VOID *) p, (VOID *) envPtr->auxDataArrayPtr,
  1855 	        (size_t) auxDataArrayBytes);
  1856     } else {
  1857 	codePtr->auxDataArrayPtr = NULL;
  1858     }
  1859 
  1860     p += auxDataArrayBytes;
  1861 #ifndef TCL_COMPILE_DEBUG
  1862     EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
  1863 #else
  1864     nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
  1865     if (((size_t)(nextPtr - p)) != cmdLocBytes) {	
  1866 	panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d\n", (nextPtr - p), cmdLocBytes);
  1867     }
  1868 #endif
  1869     
  1870     /*
  1871      * Record various compilation-related statistics about the new ByteCode
  1872      * structure. Don't include overhead for statistics-related fields.
  1873      */
  1874 
  1875 #ifdef TCL_COMPILE_STATS
  1876     codePtr->structureSize = structureSize
  1877 	    - (sizeof(size_t) + sizeof(Tcl_Time));
  1878     Tcl_GetTime(&(codePtr->createTime));
  1879     
  1880     RecordByteCodeStats(codePtr);
  1881 #endif /* TCL_COMPILE_STATS */
  1882     
  1883     /*
  1884      * Free the old internal rep then convert the object to a
  1885      * bytecode object by making its internal rep point to the just
  1886      * compiled ByteCode.
  1887      */
  1888 	    
  1889     if ((objPtr->typePtr != NULL) &&
  1890 	    (objPtr->typePtr->freeIntRepProc != NULL)) {
  1891 	(*objPtr->typePtr->freeIntRepProc)(objPtr);
  1892     }
  1893     objPtr->internalRep.otherValuePtr = (VOID *) codePtr;
  1894     objPtr->typePtr = &tclByteCodeType;
  1895 
  1896 #ifdef TCL_TIP280
  1897     /* TIP #280. Associate the extended per-word line information with the
  1898      * byte code object (internal rep), for use with the bc compiler.
  1899      */
  1900 
  1901     Tcl_SetHashValue (Tcl_CreateHashEntry (iPtr->lineBCPtr, (char*) codePtr, &new),
  1902 		      envPtr->extCmdMapPtr);
  1903     envPtr->extCmdMapPtr = NULL;
  1904 #endif
  1905 }
  1906 
  1907 /*
  1908  *----------------------------------------------------------------------
  1909  *
  1910  * LogCompilationInfo --
  1911  *
  1912  *	This procedure is invoked after an error occurs during compilation.
  1913  *	It adds information to the "errorInfo" variable to describe the
  1914  *	command that was being compiled when the error occurred.
  1915  *
  1916  * Results:
  1917  *	None.
  1918  *
  1919  * Side effects:
  1920  *	Information about the command is added to errorInfo and the
  1921  *	line number stored internally in the interpreter is set.  If this
  1922  *	is the first call to this procedure or Tcl_AddObjErrorInfo since
  1923  *	an error occurred, then old information in errorInfo is
  1924  *	deleted.
  1925  *
  1926  *----------------------------------------------------------------------
  1927  */
  1928 
  1929 static void
  1930 LogCompilationInfo(interp, script, command, length)
  1931     Tcl_Interp *interp;		/* Interpreter in which to log the
  1932 				 * information. */
  1933     CONST char *script;		/* First character in script containing
  1934 				 * command (must be <= command). */
  1935     CONST char *command;	/* First character in command that
  1936 				 * generated the error. */
  1937     int length;			/* Number of bytes in command (-1 means
  1938 				 * use all bytes up to first null byte). */
  1939 {
  1940     char buffer[200];
  1941     register CONST char *p;
  1942     char *ellipsis = "";
  1943     Interp *iPtr = (Interp *) interp;
  1944 
  1945     if (iPtr->flags & ERR_ALREADY_LOGGED) {
  1946 	/*
  1947 	 * Someone else has already logged error information for this
  1948 	 * command; we shouldn't add anything more.
  1949 	 */
  1950 
  1951 	return;
  1952     }
  1953 
  1954     /*
  1955      * Compute the line number where the error occurred.
  1956      */
  1957 
  1958     iPtr->errorLine = 1;
  1959     for (p = script; p != command; p++) {
  1960 	if (*p == '\n') {
  1961 	    iPtr->errorLine++;
  1962 	}
  1963     }
  1964 
  1965     /*
  1966      * Create an error message to add to errorInfo, including up to a
  1967      * maximum number of characters of the command.
  1968      */
  1969 
  1970     if (length < 0) {
  1971 	length = strlen(command);
  1972     }
  1973     if (length > 150) {
  1974 	length = 150;
  1975 	ellipsis = "...";
  1976     }
  1977     while ( (command[length] & 0xC0) == 0x80 ) {
  1978         /*
  1979 	 * Back up truncation point so that we don't truncate in the
  1980 	 * middle of a multi-byte character (in UTF-8)
  1981 	 */
  1982 	 length--;
  1983 	 ellipsis = "...";
  1984     }
  1985     sprintf(buffer, "\n    while compiling\n\"%.*s%s\"",
  1986 	    length, command, ellipsis);
  1987     Tcl_AddObjErrorInfo(interp, buffer, -1);
  1988 }
  1989 
  1990 /*
  1991  *----------------------------------------------------------------------
  1992  *
  1993  * TclFindCompiledLocal --
  1994  *
  1995  *	This procedure is called at compile time to look up and optionally
  1996  *	allocate an entry ("slot") for a variable in a procedure's array of
  1997  *	local variables. If the variable's name is NULL, a new temporary
  1998  *	variable is always created. (Such temporary variables can only be
  1999  *	referenced using their slot index.)
  2000  *
  2001  * Results:
  2002  *	If create is 0 and the name is non-NULL, then if the variable is
  2003  *	found, the index of its entry in the procedure's array of local
  2004  *	variables is returned; otherwise -1 is returned. If name is NULL,
  2005  *	the index of a new temporary variable is returned. Finally, if
  2006  *	create is 1 and name is non-NULL, the index of a new entry is
  2007  *	returned.
  2008  *
  2009  * Side effects:
  2010  *	Creates and registers a new local variable if create is 1 and
  2011  *	the variable is unknown, or if the name is NULL.
  2012  *
  2013  *----------------------------------------------------------------------
  2014  */
  2015 
  2016 int
  2017 TclFindCompiledLocal(name, nameBytes, create, flags, procPtr)
  2018     register CONST char *name;	/* Points to first character of the name of
  2019 				 * a scalar or array variable. If NULL, a
  2020 				 * temporary var should be created. */
  2021     int nameBytes;		/* Number of bytes in the name. */
  2022     int create;			/* If 1, allocate a local frame entry for
  2023 				 * the variable if it is new. */
  2024     int flags;			/* Flag bits for the compiled local if
  2025 				 * created. Only VAR_SCALAR, VAR_ARRAY, and
  2026 				 * VAR_LINK make sense. */
  2027     register Proc *procPtr;	/* Points to structure describing procedure
  2028 				 * containing the variable reference. */
  2029 {
  2030     register CompiledLocal *localPtr;
  2031     int localVar = -1;
  2032     register int i;
  2033 
  2034     /*
  2035      * If not creating a temporary, does a local variable of the specified
  2036      * name already exist?
  2037      */
  2038 
  2039     if (name != NULL) {	
  2040 	int localCt = procPtr->numCompiledLocals;
  2041 	localPtr = procPtr->firstLocalPtr;
  2042 	for (i = 0;  i < localCt;  i++) {
  2043 	    if (!TclIsVarTemporary(localPtr)) {
  2044 		char *localName = localPtr->name;
  2045 		if ((nameBytes == localPtr->nameLength)
  2046 	                && (strncmp(name, localName, (unsigned) nameBytes) == 0)) {
  2047 		    return i;
  2048 		}
  2049 	    }
  2050 	    localPtr = localPtr->nextPtr;
  2051 	}
  2052     }
  2053 
  2054     /*
  2055      * Create a new variable if appropriate.
  2056      */
  2057     
  2058     if (create || (name == NULL)) {
  2059 	localVar = procPtr->numCompiledLocals;
  2060 	localPtr = (CompiledLocal *) ckalloc((unsigned) 
  2061 	        (sizeof(CompiledLocal) - sizeof(localPtr->name)
  2062 		+ nameBytes+1));
  2063 	if (procPtr->firstLocalPtr == NULL) {
  2064 	    procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
  2065 	} else {
  2066 	    procPtr->lastLocalPtr->nextPtr = localPtr;
  2067 	    procPtr->lastLocalPtr = localPtr;
  2068 	}
  2069 	localPtr->nextPtr = NULL;
  2070 	localPtr->nameLength = nameBytes;
  2071 	localPtr->frameIndex = localVar;
  2072 	localPtr->flags = flags | VAR_UNDEFINED;
  2073 	if (name == NULL) {
  2074 	    localPtr->flags |= VAR_TEMPORARY;
  2075 	}
  2076 	localPtr->defValuePtr = NULL;
  2077 	localPtr->resolveInfo = NULL;
  2078 
  2079 	if (name != NULL) {
  2080 	    memcpy((VOID *) localPtr->name, (VOID *) name,
  2081 	            (size_t) nameBytes);
  2082 	}
  2083 	localPtr->name[nameBytes] = '\0';
  2084 	procPtr->numCompiledLocals++;
  2085     }
  2086     return localVar;
  2087 }
  2088 
  2089 /*
  2090  *----------------------------------------------------------------------
  2091  *
  2092  * TclInitCompiledLocals --
  2093  *
  2094  *	This routine is invoked in order to initialize the compiled
  2095  *	locals table for a new call frame.
  2096  *
  2097  * Results:
  2098  *	None.
  2099  *
  2100  * Side effects:
  2101  *	May invoke various name resolvers in order to determine which
  2102  *	variables are being referenced at runtime.
  2103  *
  2104  *----------------------------------------------------------------------
  2105  */
  2106 
  2107 void
  2108 TclInitCompiledLocals(interp, framePtr, nsPtr)
  2109     Tcl_Interp *interp;		/* Current interpreter. */
  2110     CallFrame *framePtr;	/* Call frame to initialize. */
  2111     Namespace *nsPtr;		/* Pointer to current namespace. */
  2112 {
  2113     register CompiledLocal *localPtr;
  2114     Interp *iPtr = (Interp*) interp;
  2115     Tcl_ResolvedVarInfo *vinfo, *resVarInfo;
  2116     Var *varPtr = framePtr->compiledLocals;
  2117     Var *resolvedVarPtr;
  2118     ResolverScheme *resPtr;
  2119     int result;
  2120 
  2121     /*
  2122      * Initialize the array of local variables stored in the call frame.
  2123      * Some variables may have special resolution rules.  In that case,
  2124      * we call their "resolver" procs to get our hands on the variable,
  2125      * and we make the compiled local a link to the real variable.
  2126      */
  2127 
  2128     for (localPtr = framePtr->procPtr->firstLocalPtr;
  2129 	 localPtr != NULL;
  2130 	 localPtr = localPtr->nextPtr) {
  2131 
  2132 	/*
  2133 	 * Check to see if this local is affected by namespace or
  2134 	 * interp resolvers.  The resolver to use is cached for the
  2135 	 * next invocation of the procedure.
  2136 	 */
  2137 
  2138 	if (!(localPtr->flags & (VAR_ARGUMENT|VAR_TEMPORARY|VAR_RESOLVED))
  2139 		&& (nsPtr->compiledVarResProc || iPtr->resolverPtr)) {
  2140 	    resPtr = iPtr->resolverPtr;
  2141 
  2142 	    if (nsPtr->compiledVarResProc) {
  2143 		result = (*nsPtr->compiledVarResProc)(nsPtr->interp,
  2144 			localPtr->name, localPtr->nameLength,
  2145 			(Tcl_Namespace *) nsPtr, &vinfo);
  2146 	    } else {
  2147 		result = TCL_CONTINUE;
  2148 	    }
  2149 
  2150 	    while ((result == TCL_CONTINUE) && resPtr) {
  2151 		if (resPtr->compiledVarResProc) {
  2152 		    result = (*resPtr->compiledVarResProc)(nsPtr->interp,
  2153 			    localPtr->name, localPtr->nameLength,
  2154 			    (Tcl_Namespace *) nsPtr, &vinfo);
  2155 		}
  2156 		resPtr = resPtr->nextPtr;
  2157 	    }
  2158 	    if (result == TCL_OK) {
  2159 		localPtr->resolveInfo = vinfo;
  2160 		localPtr->flags |= VAR_RESOLVED;
  2161 	    }
  2162 	}
  2163 
  2164 	/*
  2165 	 * Now invoke the resolvers to determine the exact variables that
  2166 	 * should be used.
  2167 	 */
  2168 
  2169         resVarInfo = localPtr->resolveInfo;
  2170         resolvedVarPtr = NULL;
  2171 
  2172         if (resVarInfo && resVarInfo->fetchProc) {
  2173             resolvedVarPtr = (Var*) (*resVarInfo->fetchProc)(interp,
  2174 		    resVarInfo);
  2175         }
  2176 
  2177         if (resolvedVarPtr) {
  2178 	    varPtr->name = localPtr->name; /* will be just '\0' if temp var */
  2179 	    varPtr->nsPtr = NULL;
  2180 	    varPtr->hPtr = NULL;
  2181 	    varPtr->refCount = 0;
  2182 	    varPtr->tracePtr = NULL;
  2183 	    varPtr->searchPtr = NULL;
  2184 	    varPtr->flags = 0;
  2185             TclSetVarLink(varPtr);
  2186             varPtr->value.linkPtr = resolvedVarPtr;
  2187             resolvedVarPtr->refCount++;
  2188         } else {
  2189 	    varPtr->value.objPtr = NULL;
  2190 	    varPtr->name = localPtr->name; /* will be just '\0' if temp var */
  2191 	    varPtr->nsPtr = NULL;
  2192 	    varPtr->hPtr = NULL;
  2193 	    varPtr->refCount = 0;
  2194 	    varPtr->tracePtr = NULL;
  2195 	    varPtr->searchPtr = NULL;
  2196 	    varPtr->flags = localPtr->flags;
  2197         }
  2198 	varPtr++;
  2199     }
  2200 }
  2201 
  2202 /*
  2203  *----------------------------------------------------------------------
  2204  *
  2205  * TclExpandCodeArray --
  2206  *
  2207  *	Procedure that uses malloc to allocate more storage for a
  2208  *	CompileEnv's code array.
  2209  *
  2210  * Results:
  2211  *	None. 
  2212  *
  2213  * Side effects:
  2214  *	The byte code array in *envPtr is reallocated to a new array of
  2215  *	double the size, and if envPtr->mallocedCodeArray is non-zero the
  2216  *	old array is freed. Byte codes are copied from the old array to the
  2217  *	new one.
  2218  *
  2219  *----------------------------------------------------------------------
  2220  */
  2221 
  2222 void
  2223 TclExpandCodeArray(envArgPtr)
  2224     void *envArgPtr;		/* Points to the CompileEnv whose code array
  2225 				 * must be enlarged. */
  2226 {
  2227     CompileEnv *envPtr = (CompileEnv*) envArgPtr;	/* Points to the CompileEnv whose code array
  2228 							 * must be enlarged. */
  2229 
  2230     /*
  2231      * envPtr->codeNext is equal to envPtr->codeEnd. The currently defined
  2232      * code bytes are stored between envPtr->codeStart and
  2233      * (envPtr->codeNext - 1) [inclusive].
  2234      */
  2235     
  2236     size_t currBytes = (envPtr->codeNext - envPtr->codeStart);
  2237     size_t newBytes  = 2*(envPtr->codeEnd  - envPtr->codeStart);
  2238     unsigned char *newPtr = (unsigned char *) ckalloc((unsigned) newBytes);
  2239 
  2240     /*
  2241      * Copy from old code array to new, free old code array if needed, and
  2242      * mark new code array as malloced.
  2243      */
  2244  
  2245     memcpy((VOID *) newPtr, (VOID *) envPtr->codeStart, currBytes);
  2246     if (envPtr->mallocedCodeArray) {
  2247         ckfree((char *) envPtr->codeStart);
  2248     }
  2249     envPtr->codeStart = newPtr;
  2250     envPtr->codeNext = (newPtr + currBytes);
  2251     envPtr->codeEnd  = (newPtr + newBytes);
  2252     envPtr->mallocedCodeArray = 1;
  2253 }
  2254 
  2255 /*
  2256  *----------------------------------------------------------------------
  2257  *
  2258  * EnterCmdStartData --
  2259  *
  2260  *	Registers the starting source and bytecode location of a
  2261  *	command. This information is used at runtime to map between
  2262  *	instruction pc and source locations.
  2263  *
  2264  * Results:
  2265  *	None.
  2266  *
  2267  * Side effects:
  2268  *	Inserts source and code location information into the compilation
  2269  *	environment envPtr for the command at index cmdIndex. The
  2270  *	compilation environment's CmdLocation array is grown if necessary.
  2271  *
  2272  *----------------------------------------------------------------------
  2273  */
  2274 
  2275 static void
  2276 EnterCmdStartData(envPtr, cmdIndex, srcOffset, codeOffset)
  2277     CompileEnv *envPtr;		/* Points to the compilation environment
  2278 				 * structure in which to enter command
  2279 				 * location information. */
  2280     int cmdIndex;		/* Index of the command whose start data
  2281 				 * is being set. */
  2282     int srcOffset;		/* Offset of first char of the command. */
  2283     int codeOffset;		/* Offset of first byte of command code. */
  2284 {
  2285     CmdLocation *cmdLocPtr;
  2286     
  2287     if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
  2288 	panic("EnterCmdStartData: bad command index %d\n", cmdIndex);
  2289     }
  2290     
  2291     if (cmdIndex >= envPtr->cmdMapEnd) {
  2292 	/*
  2293 	 * Expand the command location array by allocating more storage from
  2294 	 * the heap. The currently allocated CmdLocation entries are stored
  2295 	 * from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive).
  2296 	 */
  2297 
  2298 	size_t currElems = envPtr->cmdMapEnd;
  2299 	size_t newElems  = 2*currElems;
  2300 	size_t currBytes = currElems * sizeof(CmdLocation);
  2301 	size_t newBytes  = newElems  * sizeof(CmdLocation);
  2302 	CmdLocation *newPtr = (CmdLocation *) ckalloc((unsigned) newBytes);
  2303 	
  2304 	/*
  2305 	 * Copy from old command location array to new, free old command
  2306 	 * location array if needed, and mark new array as malloced.
  2307 	 */
  2308 	
  2309 	memcpy((VOID *) newPtr, (VOID *) envPtr->cmdMapPtr, currBytes);
  2310 	if (envPtr->mallocedCmdMap) {
  2311 	    ckfree((char *) envPtr->cmdMapPtr);
  2312 	}
  2313 	envPtr->cmdMapPtr = (CmdLocation *) newPtr;
  2314 	envPtr->cmdMapEnd = newElems;
  2315 	envPtr->mallocedCmdMap = 1;
  2316     }
  2317 
  2318     if (cmdIndex > 0) {
  2319 	if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) {
  2320 	    panic("EnterCmdStartData: cmd map not sorted by code offset");
  2321 	}
  2322     }
  2323 
  2324     cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
  2325     cmdLocPtr->codeOffset = codeOffset;
  2326     cmdLocPtr->srcOffset = srcOffset;
  2327     cmdLocPtr->numSrcBytes = -1;
  2328     cmdLocPtr->numCodeBytes = -1;
  2329 }
  2330 
  2331 /*
  2332  *----------------------------------------------------------------------
  2333  *
  2334  * EnterCmdExtentData --
  2335  *
  2336  *	Registers the source and bytecode length for a command. This
  2337  *	information is used at runtime to map between instruction pc and
  2338  *	source locations.
  2339  *
  2340  * Results:
  2341  *	None.
  2342  *
  2343  * Side effects:
  2344  *	Inserts source and code length information into the compilation
  2345  *	environment envPtr for the command at index cmdIndex. Starting
  2346  *	source and bytecode information for the command must already
  2347  *	have been registered.
  2348  *
  2349  *----------------------------------------------------------------------
  2350  */
  2351 
  2352 static void
  2353 EnterCmdExtentData(envPtr, cmdIndex, numSrcBytes, numCodeBytes)
  2354     CompileEnv *envPtr;		/* Points to the compilation environment
  2355 				 * structure in which to enter command
  2356 				 * location information. */
  2357     int cmdIndex;		/* Index of the command whose source and
  2358 				 * code length data is being set. */
  2359     int numSrcBytes;		/* Number of command source chars. */
  2360     int numCodeBytes;		/* Offset of last byte of command code. */
  2361 {
  2362     CmdLocation *cmdLocPtr;
  2363 
  2364     if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
  2365 	panic("EnterCmdExtentData: bad command index %d\n", cmdIndex);
  2366     }
  2367     
  2368     if (cmdIndex > envPtr->cmdMapEnd) {
  2369 	panic("EnterCmdExtentData: missing start data for command %d\n",
  2370 	        cmdIndex);
  2371     }
  2372 
  2373     cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
  2374     cmdLocPtr->numSrcBytes = numSrcBytes;
  2375     cmdLocPtr->numCodeBytes = numCodeBytes;
  2376 }
  2377 
  2378 #ifdef TCL_TIP280
  2379 /*
  2380  *----------------------------------------------------------------------
  2381  * TIP #280
  2382  *
  2383  * EnterCmdWordData --
  2384  *
  2385  *	Registers the lines for the words of a command. This information
  2386  *	is used at runtime by 'info frame'.
  2387  *
  2388  * Results:
  2389  *	None.
  2390  *
  2391  * Side effects:
  2392  *	Inserts word location information into the compilation
  2393  *	environment envPtr for the command at index cmdIndex. The
  2394  *	compilation environment's ExtCmdLoc.ECL array is grown if necessary.
  2395  *
  2396  *----------------------------------------------------------------------
  2397  */
  2398 
  2399 static void
  2400 EnterCmdWordData(eclPtr, srcOffset, tokenPtr, cmd, len, numWords, line, wlines)
  2401     ExtCmdLoc *eclPtr;		/* Points to the map environment
  2402 				 * structure in which to enter command
  2403 				 * location information. */
  2404     int srcOffset;		/* Offset of first char of the command. */
  2405     Tcl_Token* tokenPtr;
  2406     CONST char* cmd;
  2407     int         len;
  2408     int numWords;
  2409     int line;
  2410     int** wlines;
  2411 {    
  2412     ECL*        ePtr;
  2413     int         wordIdx;
  2414     CONST char* last;
  2415     int         wordLine;
  2416     int*        wwlines;
  2417 
  2418     if (eclPtr->nuloc >= eclPtr->nloc) {
  2419 	/*
  2420 	 * Expand the ECL array by allocating more storage from the
  2421 	 * heap. The currently allocated ECL entries are stored from
  2422 	 * eclPtr->loc[0] up to eclPtr->loc[eclPtr->nuloc-1] (inclusive).
  2423 	 */
  2424 
  2425 	size_t currElems = eclPtr->nloc;
  2426 	size_t newElems  = (currElems ? 2*currElems : 1);
  2427 	size_t currBytes = currElems * sizeof(ECL);
  2428 	size_t newBytes  = newElems  * sizeof(ECL);
  2429 	ECL *  newPtr    = (ECL *) ckalloc((unsigned) newBytes);
  2430 	
  2431 	/*
  2432 	 * Copy from old ECL array to new, free old ECL array if
  2433 	 * needed.
  2434 	 */
  2435 	
  2436 	if (currBytes) {
  2437 	    memcpy((VOID *) newPtr, (VOID *) eclPtr->loc, currBytes);
  2438 	}
  2439 	if (eclPtr->loc != NULL) {
  2440 	    ckfree((char *) eclPtr->loc);
  2441 	}
  2442 	eclPtr->loc  = (ECL *) newPtr;
  2443 	eclPtr->nloc = newElems;
  2444     }
  2445 
  2446     ePtr            = &eclPtr->loc [eclPtr->nuloc];
  2447     ePtr->srcOffset = srcOffset;
  2448     ePtr->line      = (int*) ckalloc (numWords * sizeof (int));
  2449     ePtr->nline     = numWords;
  2450     wwlines         = (int*) ckalloc (numWords * sizeof (int));
  2451 
  2452     last     = cmd;
  2453     wordLine = line;
  2454     for (wordIdx = 0;
  2455 	 wordIdx < numWords;
  2456 	 wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) {
  2457         TclAdvanceLines (&wordLine, last, tokenPtr->start);
  2458 	wwlines    [wordIdx] = (TclWordKnownAtCompileTime (tokenPtr)
  2459 				? wordLine
  2460 				: -1);
  2461 	ePtr->line [wordIdx] = wordLine;
  2462 	last = tokenPtr->start;
  2463     }
  2464 
  2465     *wlines = wwlines;
  2466     eclPtr->nuloc ++;
  2467 }
  2468 #endif
  2469 
  2470 /*
  2471  *----------------------------------------------------------------------
  2472  *
  2473  * TclCreateExceptRange --
  2474  *
  2475  *	Procedure that allocates and initializes a new ExceptionRange
  2476  *	structure of the specified kind in a CompileEnv.
  2477  *
  2478  * Results:
  2479  *	Returns the index for the newly created ExceptionRange.
  2480  *
  2481  * Side effects:
  2482  *	If there is not enough room in the CompileEnv's ExceptionRange
  2483  *	array, the array in expanded: a new array of double the size is
  2484  *	allocated, if envPtr->mallocedExceptArray is non-zero the old
  2485  *	array is freed, and ExceptionRange entries are copied from the old
  2486  *	array to the new one.
  2487  *
  2488  *----------------------------------------------------------------------
  2489  */
  2490 
  2491 int
  2492 TclCreateExceptRange(type, envPtr)
  2493     ExceptionRangeType type;	/* The kind of ExceptionRange desired. */
  2494     register CompileEnv *envPtr;/* Points to CompileEnv for which to
  2495 				 * create a new ExceptionRange structure. */
  2496 {
  2497     register ExceptionRange *rangePtr;
  2498     int index = envPtr->exceptArrayNext;
  2499     
  2500     if (index >= envPtr->exceptArrayEnd) {
  2501         /*
  2502 	 * Expand the ExceptionRange array. The currently allocated entries
  2503 	 * are stored between elements 0 and (envPtr->exceptArrayNext - 1)
  2504 	 * [inclusive].
  2505 	 */
  2506 	
  2507 	size_t currBytes =
  2508 	        envPtr->exceptArrayNext * sizeof(ExceptionRange);
  2509 	int newElems = 2*envPtr->exceptArrayEnd;
  2510 	size_t newBytes = newElems * sizeof(ExceptionRange);
  2511 	ExceptionRange *newPtr = (ExceptionRange *)
  2512 	        ckalloc((unsigned) newBytes);
  2513 	
  2514 	/*
  2515 	 * Copy from old ExceptionRange array to new, free old
  2516 	 * ExceptionRange array if needed, and mark the new ExceptionRange
  2517 	 * array as malloced.
  2518 	 */
  2519 	
  2520 	memcpy((VOID *) newPtr, (VOID *) envPtr->exceptArrayPtr,
  2521 	        currBytes);
  2522 	if (envPtr->mallocedExceptArray) {
  2523 	    ckfree((char *) envPtr->exceptArrayPtr);
  2524 	}
  2525 	envPtr->exceptArrayPtr = (ExceptionRange *) newPtr;
  2526 	envPtr->exceptArrayEnd = newElems;
  2527 	envPtr->mallocedExceptArray = 1;
  2528     }
  2529     envPtr->exceptArrayNext++;
  2530     
  2531     rangePtr = &(envPtr->exceptArrayPtr[index]);
  2532     rangePtr->type = type;
  2533     rangePtr->nestingLevel = envPtr->exceptDepth;
  2534     rangePtr->codeOffset = -1;
  2535     rangePtr->numCodeBytes = -1;
  2536     rangePtr->breakOffset = -1;
  2537     rangePtr->continueOffset = -1;
  2538     rangePtr->catchOffset = -1;
  2539     return index;
  2540 }
  2541 
  2542 /*
  2543  *----------------------------------------------------------------------
  2544  *
  2545  * TclCreateAuxData --
  2546  *
  2547  *	Procedure that allocates and initializes a new AuxData structure in
  2548  *	a CompileEnv's array of compilation auxiliary data records. These
  2549  *	AuxData records hold information created during compilation by
  2550  *	CompileProcs and used by instructions during execution.
  2551  *
  2552  * Results:
  2553  *	Returns the index for the newly created AuxData structure.
  2554  *
  2555  * Side effects:
  2556  *	If there is not enough room in the CompileEnv's AuxData array,
  2557  *	the AuxData array in expanded: a new array of double the size
  2558  *	is allocated, if envPtr->mallocedAuxDataArray is non-zero
  2559  *	the old array is freed, and AuxData entries are copied from
  2560  *	the old array to the new one.
  2561  *
  2562  *----------------------------------------------------------------------
  2563  */
  2564 
  2565 int
  2566 TclCreateAuxData(clientData, typePtr, envPtr)
  2567     ClientData clientData;	/* The compilation auxiliary data to store
  2568 				 * in the new aux data record. */
  2569     AuxDataType *typePtr;	/* Pointer to the type to attach to this AuxData */
  2570     register CompileEnv *envPtr;/* Points to the CompileEnv for which a new
  2571 				 * aux data structure is to be allocated. */
  2572 {
  2573     int index;			/* Index for the new AuxData structure. */
  2574     register AuxData *auxDataPtr;
  2575     				/* Points to the new AuxData structure */
  2576     
  2577     index = envPtr->auxDataArrayNext;
  2578     if (index >= envPtr->auxDataArrayEnd) {
  2579         /*
  2580 	 * Expand the AuxData array. The currently allocated entries are
  2581 	 * stored between elements 0 and (envPtr->auxDataArrayNext - 1)
  2582 	 * [inclusive].
  2583 	 */
  2584 	
  2585 	size_t currBytes = envPtr->auxDataArrayNext * sizeof(AuxData);
  2586 	int newElems = 2*envPtr->auxDataArrayEnd;
  2587 	size_t newBytes = newElems * sizeof(AuxData);
  2588 	AuxData *newPtr = (AuxData *) ckalloc((unsigned) newBytes);
  2589 	
  2590 	/*
  2591 	 * Copy from old AuxData array to new, free old AuxData array if
  2592 	 * needed, and mark the new AuxData array as malloced.
  2593 	 */
  2594 	
  2595 	memcpy((VOID *) newPtr, (VOID *) envPtr->auxDataArrayPtr,
  2596 	        currBytes);
  2597 	if (envPtr->mallocedAuxDataArray) {
  2598 	    ckfree((char *) envPtr->auxDataArrayPtr);
  2599 	}
  2600 	envPtr->auxDataArrayPtr = newPtr;
  2601 	envPtr->auxDataArrayEnd = newElems;
  2602 	envPtr->mallocedAuxDataArray = 1;
  2603     }
  2604     envPtr->auxDataArrayNext++;
  2605     
  2606     auxDataPtr = &(envPtr->auxDataArrayPtr[index]);
  2607     auxDataPtr->clientData = clientData;
  2608     auxDataPtr->type = typePtr;
  2609     return index;
  2610 }
  2611 
  2612 /*
  2613  *----------------------------------------------------------------------
  2614  *
  2615  * TclInitJumpFixupArray --
  2616  *
  2617  *	Initializes a JumpFixupArray structure to hold some number of
  2618  *	jump fixup entries.
  2619  *
  2620  * Results:
  2621  *	None.
  2622  *
  2623  * Side effects:
  2624  *	The JumpFixupArray structure is initialized.
  2625  *
  2626  *----------------------------------------------------------------------
  2627  */
  2628 
  2629 void
  2630 TclInitJumpFixupArray(fixupArrayPtr)
  2631     register JumpFixupArray *fixupArrayPtr;
  2632 				 /* Points to the JumpFixupArray structure
  2633 				  * to initialize. */
  2634 {
  2635     fixupArrayPtr->fixup = fixupArrayPtr->staticFixupSpace;
  2636     fixupArrayPtr->next = 0;
  2637     fixupArrayPtr->end = (JUMPFIXUP_INIT_ENTRIES - 1);
  2638     fixupArrayPtr->mallocedArray = 0;
  2639 }
  2640 
  2641 /*
  2642  *----------------------------------------------------------------------
  2643  *
  2644  * TclExpandJumpFixupArray --
  2645  *
  2646  *	Procedure that uses malloc to allocate more storage for a
  2647  *      jump fixup array.
  2648  *
  2649  * Results:
  2650  *	None.
  2651  *
  2652  * Side effects:
  2653  *	The jump fixup array in *fixupArrayPtr is reallocated to a new array
  2654  *	of double the size, and if fixupArrayPtr->mallocedArray is non-zero
  2655  *	the old array is freed. Jump fixup structures are copied from the
  2656  *	old array to the new one.
  2657  *
  2658  *----------------------------------------------------------------------
  2659  */
  2660 
  2661 void
  2662 TclExpandJumpFixupArray(fixupArrayPtr)
  2663     register JumpFixupArray *fixupArrayPtr;
  2664 				 /* Points to the JumpFixupArray structure
  2665 				  * to enlarge. */
  2666 {
  2667     /*
  2668      * The currently allocated jump fixup entries are stored from fixup[0]
  2669      * up to fixup[fixupArrayPtr->fixupNext] (*not* inclusive). We assume
  2670      * fixupArrayPtr->fixupNext is equal to fixupArrayPtr->fixupEnd.
  2671      */
  2672 
  2673     size_t currBytes = fixupArrayPtr->next * sizeof(JumpFixup);
  2674     int newElems = 2*(fixupArrayPtr->end + 1);
  2675     size_t newBytes = newElems * sizeof(JumpFixup);
  2676     JumpFixup *newPtr = (JumpFixup *) ckalloc((unsigned) newBytes);
  2677 
  2678     /*
  2679      * Copy from the old array to new, free the old array if needed,
  2680      * and mark the new array as malloced.
  2681      */
  2682  
  2683     memcpy((VOID *) newPtr, (VOID *) fixupArrayPtr->fixup, currBytes);
  2684     if (fixupArrayPtr->mallocedArray) {
  2685 	ckfree((char *) fixupArrayPtr->fixup);
  2686     }
  2687     fixupArrayPtr->fixup = (JumpFixup *) newPtr;
  2688     fixupArrayPtr->end = newElems;
  2689     fixupArrayPtr->mallocedArray = 1;
  2690 }
  2691 
  2692 /*
  2693  *----------------------------------------------------------------------
  2694  *
  2695  * TclFreeJumpFixupArray --
  2696  *
  2697  *	Free any storage allocated in a jump fixup array structure.
  2698  *
  2699  * Results:
  2700  *	None.
  2701  *
  2702  * Side effects:
  2703  *	Allocated storage in the JumpFixupArray structure is freed.
  2704  *
  2705  *----------------------------------------------------------------------
  2706  */
  2707 
  2708 void
  2709 TclFreeJumpFixupArray(fixupArrayPtr)
  2710     register JumpFixupArray *fixupArrayPtr;
  2711 				 /* Points to the JumpFixupArray structure
  2712 				  * to free. */
  2713 {
  2714     if (fixupArrayPtr->mallocedArray) {
  2715 	ckfree((char *) fixupArrayPtr->fixup);
  2716     }
  2717 }
  2718 
  2719 /*
  2720  *----------------------------------------------------------------------
  2721  *
  2722  * TclEmitForwardJump --
  2723  *
  2724  *	Procedure to emit a two-byte forward jump of kind "jumpType". Since
  2725  *	the jump may later have to be grown to five bytes if the jump target
  2726  *	is more than, say, 127 bytes away, this procedure also initializes a
  2727  *	JumpFixup record with information about the jump. 
  2728  *
  2729  * Results:
  2730  *	None.
  2731  *
  2732  * Side effects:
  2733  *	The JumpFixup record pointed to by "jumpFixupPtr" is initialized
  2734  *	with information needed later if the jump is to be grown. Also,
  2735  *	a two byte jump of the designated type is emitted at the current
  2736  *	point in the bytecode stream.
  2737  *
  2738  *----------------------------------------------------------------------
  2739  */
  2740 
  2741 void
  2742 TclEmitForwardJump(envPtr, jumpType, jumpFixupPtr)
  2743     CompileEnv *envPtr;		/* Points to the CompileEnv structure that
  2744 				 * holds the resulting instruction. */
  2745     TclJumpType jumpType;	/* Indicates the kind of jump: if true or
  2746 				 * false or unconditional. */
  2747     JumpFixup *jumpFixupPtr;	/* Points to the JumpFixup structure to
  2748 				 * initialize with information about this
  2749 				 * forward jump. */
  2750 {
  2751     /*
  2752      * Initialize the JumpFixup structure:
  2753      *    - codeOffset is offset of first byte of jump below
  2754      *    - cmdIndex is index of the command after the current one
  2755      *    - exceptIndex is the index of the first ExceptionRange after
  2756      *      the current one.
  2757      */
  2758     
  2759     jumpFixupPtr->jumpType = jumpType;
  2760     jumpFixupPtr->codeOffset = (envPtr->codeNext - envPtr->codeStart);
  2761     jumpFixupPtr->cmdIndex = envPtr->numCommands;
  2762     jumpFixupPtr->exceptIndex = envPtr->exceptArrayNext;
  2763     
  2764     switch (jumpType) {
  2765     case TCL_UNCONDITIONAL_JUMP:
  2766 	TclEmitInstInt1(INST_JUMP1, 0, envPtr);
  2767 	break;
  2768     case TCL_TRUE_JUMP:
  2769 	TclEmitInstInt1(INST_JUMP_TRUE1, 0, envPtr);
  2770 	break;
  2771     default:
  2772 	TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
  2773 	break;
  2774     }
  2775 }
  2776 
  2777 /*
  2778  *----------------------------------------------------------------------
  2779  *
  2780  * TclFixupForwardJump --
  2781  *
  2782  *	Procedure that updates a previously-emitted forward jump to jump
  2783  *	a specified number of bytes, "jumpDist". If necessary, the jump is
  2784  *      grown from two to five bytes; this is done if the jump distance is
  2785  *	greater than "distThreshold" (normally 127 bytes). The jump is
  2786  *	described by a JumpFixup record previously initialized by
  2787  *	TclEmitForwardJump.
  2788  *
  2789  * Results:
  2790  *	1 if the jump was grown and subsequent instructions had to be moved;
  2791  *	otherwise 0. This result is returned to allow callers to update
  2792  *	any additional code offsets they may hold.
  2793  *
  2794  * Side effects:
  2795  *	The jump may be grown and subsequent instructions moved. If this
  2796  *	happens, the code offsets for any commands and any ExceptionRange
  2797  *	records	between the jump and the current code address will be
  2798  *	updated to reflect the moved code. Also, the bytecode instruction
  2799  *	array in the CompileEnv structure may be grown and reallocated.
  2800  *
  2801  *----------------------------------------------------------------------
  2802  */
  2803 
  2804 int
  2805 TclFixupForwardJump(envPtr, jumpFixupPtr, jumpDist, distThreshold)
  2806     CompileEnv *envPtr;		/* Points to the CompileEnv structure that
  2807 				 * holds the resulting instruction. */
  2808     JumpFixup *jumpFixupPtr;    /* Points to the JumpFixup structure that
  2809 				 * describes the forward jump. */
  2810     int jumpDist;		/* Jump distance to set in jump
  2811 				 * instruction. */
  2812     int distThreshold;		/* Maximum distance before the two byte
  2813 				 * jump is grown to five bytes. */
  2814 {
  2815     unsigned char *jumpPc, *p;
  2816     int firstCmd, lastCmd, firstRange, lastRange, k;
  2817     unsigned int numBytes;
  2818     
  2819     if (jumpDist <= distThreshold) {
  2820 	jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
  2821 	switch (jumpFixupPtr->jumpType) {
  2822 	case TCL_UNCONDITIONAL_JUMP:
  2823 	    TclUpdateInstInt1AtPc(INST_JUMP1, jumpDist, jumpPc);
  2824 	    break;
  2825 	case TCL_TRUE_JUMP:
  2826 	    TclUpdateInstInt1AtPc(INST_JUMP_TRUE1, jumpDist, jumpPc);
  2827 	    break;
  2828 	default:
  2829 	    TclUpdateInstInt1AtPc(INST_JUMP_FALSE1, jumpDist, jumpPc);
  2830 	    break;
  2831 	}
  2832 	return 0;
  2833     }
  2834 
  2835     /*
  2836      * We must grow the jump then move subsequent instructions down.
  2837      * Note that if we expand the space for generated instructions,
  2838      * code addresses might change; be careful about updating any of
  2839      * these addresses held in variables.
  2840      */
  2841     
  2842     if ((envPtr->codeNext + 3) > envPtr->codeEnd) {
  2843         TclExpandCodeArray(envPtr);
  2844     }
  2845     jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
  2846     for (numBytes = envPtr->codeNext-jumpPc-2, p = jumpPc+2+numBytes-1;
  2847 	    numBytes > 0;  numBytes--, p--) {
  2848 	p[3] = p[0];
  2849     }
  2850     envPtr->codeNext += 3;
  2851     jumpDist += 3;
  2852     switch (jumpFixupPtr->jumpType) {
  2853     case TCL_UNCONDITIONAL_JUMP:
  2854 	TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc);
  2855 	break;
  2856     case TCL_TRUE_JUMP:
  2857 	TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc);
  2858 	break;
  2859     default:
  2860 	TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc);
  2861 	break;
  2862     }
  2863     
  2864     /*
  2865      * Adjust the code offsets for any commands and any ExceptionRange
  2866      * records between the jump and the current code address.
  2867      */
  2868     
  2869     firstCmd = jumpFixupPtr->cmdIndex;
  2870     lastCmd  = (envPtr->numCommands - 1);
  2871     if (firstCmd < lastCmd) {
  2872 	for (k = firstCmd;  k <= lastCmd;  k++) {
  2873 	    (envPtr->cmdMapPtr[k]).codeOffset += 3;
  2874 	}
  2875     }
  2876     
  2877     firstRange = jumpFixupPtr->exceptIndex;
  2878     lastRange  = (envPtr->exceptArrayNext - 1);
  2879     for (k = firstRange;  k <= lastRange;  k++) {
  2880 	ExceptionRange *rangePtr = &(envPtr->exceptArrayPtr[k]);
  2881 	rangePtr->codeOffset += 3;
  2882 	
  2883 	switch (rangePtr->type) {
  2884 	case LOOP_EXCEPTION_RANGE:
  2885 	    rangePtr->breakOffset += 3;
  2886 	    if (rangePtr->continueOffset != -1) {
  2887 		rangePtr->continueOffset += 3;
  2888 	    }
  2889 	    break;
  2890 	case CATCH_EXCEPTION_RANGE:
  2891 	    rangePtr->catchOffset += 3;
  2892 	    break;
  2893 	default:
  2894 	    panic("TclFixupForwardJump: bad ExceptionRange type %d\n",
  2895 	            rangePtr->type);
  2896 	}
  2897     }
  2898     return 1;			/* the jump was grown */
  2899 }
  2900 
  2901 /*
  2902  *----------------------------------------------------------------------
  2903  *
  2904  * TclGetInstructionTable --
  2905  *
  2906  *  Returns a pointer to the table describing Tcl bytecode instructions.
  2907  *  This procedure is defined so that clients can access the pointer from
  2908  *  outside the TCL DLLs.
  2909  *
  2910  * Results:
  2911  *	Returns a pointer to the global instruction table, same as the
  2912  *	expression (&tclInstructionTable[0]).
  2913  *
  2914  * Side effects:
  2915  *	None.
  2916  *
  2917  *----------------------------------------------------------------------
  2918  */
  2919 
  2920 void * /* == InstructionDesc* == */
  2921 TclGetInstructionTable()
  2922 {
  2923     return &tclInstructionTable[0];
  2924 }
  2925 
  2926 /*
  2927  *--------------------------------------------------------------
  2928  *
  2929  * TclRegisterAuxDataType --
  2930  *
  2931  *	This procedure is called to register a new AuxData type
  2932  *	in the table of all AuxData types supported by Tcl.
  2933  *
  2934  * Results:
  2935  *	None.
  2936  *
  2937  * Side effects:
  2938  *	The type is registered in the AuxData type table. If there was already
  2939  *	a type with the same name as in typePtr, it is replaced with the
  2940  *	new type.
  2941  *
  2942  *--------------------------------------------------------------
  2943  */
  2944 
  2945 void
  2946 TclRegisterAuxDataType(typePtr)
  2947     AuxDataType *typePtr;	/* Information about object type;
  2948                              * storage must be statically
  2949                              * allocated (must live forever). */
  2950 {
  2951     register Tcl_HashEntry *hPtr;
  2952     int new;
  2953 
  2954     Tcl_MutexLock(&tableMutex);
  2955     if (!auxDataTypeTableInitialized) {
  2956         TclInitAuxDataTypeTable();
  2957     }
  2958 
  2959     /*
  2960      * If there's already a type with the given name, remove it.
  2961      */
  2962 
  2963     hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typePtr->name);
  2964     if (hPtr != (Tcl_HashEntry *) NULL) {
  2965         Tcl_DeleteHashEntry(hPtr);
  2966     }
  2967 
  2968     /*
  2969      * Now insert the new object type.
  2970      */
  2971 
  2972     hPtr = Tcl_CreateHashEntry(&auxDataTypeTable, typePtr->name, &new);
  2973     if (new) {
  2974         Tcl_SetHashValue(hPtr, typePtr);
  2975     }
  2976     Tcl_MutexUnlock(&tableMutex);
  2977 }
  2978 
  2979 /*
  2980  *----------------------------------------------------------------------
  2981  *
  2982  * TclGetAuxDataType --
  2983  *
  2984  *	This procedure looks up an Auxdata type by name.
  2985  *
  2986  * Results:
  2987  *	If an AuxData type with name matching "typeName" is found, a pointer
  2988  *	to its AuxDataType structure is returned; otherwise, NULL is returned.
  2989  *
  2990  * Side effects:
  2991  *	None.
  2992  *
  2993  *----------------------------------------------------------------------
  2994  */
  2995 
  2996 AuxDataType *
  2997 TclGetAuxDataType(typeName)
  2998     char *typeName;		/* Name of AuxData type to look up. */
  2999 {
  3000     register Tcl_HashEntry *hPtr;
  3001     AuxDataType *typePtr = NULL;
  3002 
  3003     Tcl_MutexLock(&tableMutex);
  3004     if (!auxDataTypeTableInitialized) {
  3005         TclInitAuxDataTypeTable();
  3006     }
  3007 
  3008     hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typeName);
  3009     if (hPtr != (Tcl_HashEntry *) NULL) {
  3010         typePtr = (AuxDataType *) Tcl_GetHashValue(hPtr);
  3011     }
  3012     Tcl_MutexUnlock(&tableMutex);
  3013 
  3014     return typePtr;
  3015 }
  3016 
  3017 /*
  3018  *--------------------------------------------------------------
  3019  *
  3020  * TclInitAuxDataTypeTable --
  3021  *
  3022  *	This procedure is invoked to perform once-only initialization of
  3023  *	the AuxData type table. It also registers the AuxData types defined in 
  3024  *	this file.
  3025  *
  3026  * Results:
  3027  *	None.
  3028  *
  3029  * Side effects:
  3030  *	Initializes the table of defined AuxData types "auxDataTypeTable" with
  3031  *	builtin AuxData types defined in this file.
  3032  *
  3033  *--------------------------------------------------------------
  3034  */
  3035 
  3036 void
  3037 TclInitAuxDataTypeTable()
  3038 {
  3039     /*
  3040      * The table mutex must already be held before this routine is invoked.
  3041      */
  3042 
  3043     auxDataTypeTableInitialized = 1;
  3044     Tcl_InitHashTable(&auxDataTypeTable, TCL_STRING_KEYS);
  3045 
  3046     /*
  3047      * There is only one AuxData type at this time, so register it here.
  3048      */
  3049 
  3050     TclRegisterAuxDataType(&tclForeachInfoType);
  3051 }
  3052 
  3053 /*
  3054  *----------------------------------------------------------------------
  3055  *
  3056  * TclFinalizeAuxDataTypeTable --
  3057  *
  3058  *	This procedure is called by Tcl_Finalize after all exit handlers
  3059  *	have been run to free up storage associated with the table of AuxData
  3060  *	types.  This procedure is called by TclFinalizeExecution() which
  3061  *	is called by Tcl_Finalize().
  3062  *
  3063  * Results:
  3064  *	None.
  3065  *
  3066  * Side effects:
  3067  *	Deletes all entries in the hash table of AuxData types.
  3068  *
  3069  *----------------------------------------------------------------------
  3070  */
  3071 
  3072 void
  3073 TclFinalizeAuxDataTypeTable()
  3074 {
  3075     Tcl_MutexLock(&tableMutex);
  3076     if (auxDataTypeTableInitialized) {
  3077         Tcl_DeleteHashTable(&auxDataTypeTable);
  3078         auxDataTypeTableInitialized = 0;
  3079     }
  3080     Tcl_MutexUnlock(&tableMutex);
  3081 }
  3082 
  3083 /*
  3084  *----------------------------------------------------------------------
  3085  *
  3086  * GetCmdLocEncodingSize --
  3087  *
  3088  *	Computes the total number of bytes needed to encode the command
  3089  *	location information for some compiled code.
  3090  *
  3091  * Results:
  3092  *	The byte count needed to encode the compiled location information.
  3093  *
  3094  * Side effects:
  3095  *	None.
  3096  *
  3097  *----------------------------------------------------------------------
  3098  */
  3099 
  3100 static int
  3101 GetCmdLocEncodingSize(envPtr)
  3102      CompileEnv *envPtr;	/* Points to compilation environment
  3103 				 * structure containing the CmdLocation
  3104 				 * structure to encode. */
  3105 {
  3106     register CmdLocation *mapPtr = envPtr->cmdMapPtr;
  3107     int numCmds = envPtr->numCommands;
  3108     int codeDelta, codeLen, srcDelta, srcLen;
  3109     int codeDeltaNext, codeLengthNext, srcDeltaNext, srcLengthNext;
  3110 				/* The offsets in their respective byte
  3111 				 * sequences where the next encoded offset
  3112 				 * or length should go. */
  3113     int prevCodeOffset, prevSrcOffset, i;
  3114 
  3115     codeDeltaNext = codeLengthNext = srcDeltaNext = srcLengthNext = 0;
  3116     prevCodeOffset = prevSrcOffset = 0;
  3117     for (i = 0;  i < numCmds;  i++) {
  3118 	codeDelta = (mapPtr[i].codeOffset - prevCodeOffset);
  3119 	if (codeDelta < 0) {
  3120 	    panic("GetCmdLocEncodingSize: bad code offset");
  3121 	} else if (codeDelta <= 127) {
  3122 	    codeDeltaNext++;
  3123 	} else {
  3124 	    codeDeltaNext += 5;	 /* 1 byte for 0xFF, 4 for positive delta */
  3125 	}
  3126 	prevCodeOffset = mapPtr[i].codeOffset;
  3127 
  3128 	codeLen = mapPtr[i].numCodeBytes;
  3129 	if (codeLen < 0) {
  3130 	    panic("GetCmdLocEncodingSize: bad code length");
  3131 	} else if (codeLen <= 127) {
  3132 	    codeLengthNext++;
  3133 	} else {
  3134 	    codeLengthNext += 5; /* 1 byte for 0xFF, 4 for length */
  3135 	}
  3136 
  3137 	srcDelta = (mapPtr[i].srcOffset - prevSrcOffset);
  3138 	if ((-127 <= srcDelta) && (srcDelta <= 127)) {
  3139 	    srcDeltaNext++;
  3140 	} else {
  3141 	    srcDeltaNext += 5;	 /* 1 byte for 0xFF, 4 for delta */
  3142 	}
  3143 	prevSrcOffset = mapPtr[i].srcOffset;
  3144 
  3145 	srcLen = mapPtr[i].numSrcBytes;
  3146 	if (srcLen < 0) {
  3147 	    panic("GetCmdLocEncodingSize: bad source length");
  3148 	} else if (srcLen <= 127) {
  3149 	    srcLengthNext++;
  3150 	} else {
  3151 	    srcLengthNext += 5;	 /* 1 byte for 0xFF, 4 for length */
  3152 	}
  3153     }
  3154 
  3155     return (codeDeltaNext + codeLengthNext + srcDeltaNext + srcLengthNext);
  3156 }
  3157 
  3158 /*
  3159  *----------------------------------------------------------------------
  3160  *
  3161  * EncodeCmdLocMap --
  3162  *
  3163  *	Encode the command location information for some compiled code into
  3164  *	a ByteCode structure. The encoded command location map is stored as
  3165  *	three adjacent byte sequences.
  3166  *
  3167  * Results:
  3168  *	Pointer to the first byte after the encoded command location
  3169  *	information.
  3170  *
  3171  * Side effects:
  3172  *	The encoded information is stored into the block of memory headed
  3173  *	by codePtr. Also records pointers to the start of the four byte
  3174  *	sequences in fields in codePtr's ByteCode header structure.
  3175  *
  3176  *----------------------------------------------------------------------
  3177  */
  3178 
  3179 static unsigned char *
  3180 EncodeCmdLocMap(envPtr, codePtr, startPtr)
  3181      CompileEnv *envPtr;	/* Points to compilation environment
  3182 				 * structure containing the CmdLocation
  3183 				 * structure to encode. */
  3184      ByteCode *codePtr;		/* ByteCode in which to encode envPtr's
  3185 				 * command location information. */
  3186      unsigned char *startPtr;	/* Points to the first byte in codePtr's
  3187 				 * memory block where the location
  3188 				 * information is to be stored. */
  3189 {
  3190     register CmdLocation *mapPtr = envPtr->cmdMapPtr;
  3191     int numCmds = envPtr->numCommands;
  3192     register unsigned char *p = startPtr;
  3193     int codeDelta, codeLen, srcDelta, srcLen, prevOffset;
  3194     register int i;
  3195     
  3196     /*
  3197      * Encode the code offset for each command as a sequence of deltas.
  3198      */
  3199 
  3200     codePtr->codeDeltaStart = p;
  3201     prevOffset = 0;
  3202     for (i = 0;  i < numCmds;  i++) {
  3203 	codeDelta = (mapPtr[i].codeOffset - prevOffset);
  3204 	if (codeDelta < 0) {
  3205 	    panic("EncodeCmdLocMap: bad code offset");
  3206 	} else if (codeDelta <= 127) {
  3207 	    TclStoreInt1AtPtr(codeDelta, p);
  3208 	    p++;
  3209 	} else {
  3210 	    TclStoreInt1AtPtr(0xFF, p);
  3211 	    p++;
  3212 	    TclStoreInt4AtPtr(codeDelta, p);
  3213 	    p += 4;
  3214 	}
  3215 	prevOffset = mapPtr[i].codeOffset;
  3216     }
  3217 
  3218     /*
  3219      * Encode the code length for each command.
  3220      */
  3221 
  3222     codePtr->codeLengthStart = p;
  3223     for (i = 0;  i < numCmds;  i++) {
  3224 	codeLen = mapPtr[i].numCodeBytes;
  3225 	if (codeLen < 0) {
  3226 	    panic("EncodeCmdLocMap: bad code length");
  3227 	} else if (codeLen <= 127) {
  3228 	    TclStoreInt1AtPtr(codeLen, p);
  3229 	    p++;
  3230 	} else {
  3231 	    TclStoreInt1AtPtr(0xFF, p);
  3232 	    p++;
  3233 	    TclStoreInt4AtPtr(codeLen, p);
  3234 	    p += 4;
  3235 	}
  3236     }
  3237 
  3238     /*
  3239      * Encode the source offset for each command as a sequence of deltas.
  3240      */
  3241 
  3242     codePtr->srcDeltaStart = p;
  3243     prevOffset = 0;
  3244     for (i = 0;  i < numCmds;  i++) {
  3245 	srcDelta = (mapPtr[i].srcOffset - prevOffset);
  3246 	if ((-127 <= srcDelta) && (srcDelta <= 127)) {
  3247 	    TclStoreInt1AtPtr(srcDelta, p);
  3248 	    p++;
  3249 	} else {
  3250 	    TclStoreInt1AtPtr(0xFF, p);
  3251 	    p++;
  3252 	    TclStoreInt4AtPtr(srcDelta, p);
  3253 	    p += 4;
  3254 	}
  3255 	prevOffset = mapPtr[i].srcOffset;
  3256     }
  3257 
  3258     /*
  3259      * Encode the source length for each command.
  3260      */
  3261 
  3262     codePtr->srcLengthStart = p;
  3263     for (i = 0;  i < numCmds;  i++) {
  3264 	srcLen = mapPtr[i].numSrcBytes;
  3265 	if (srcLen < 0) {
  3266 	    panic("EncodeCmdLocMap: bad source length");
  3267 	} else if (srcLen <= 127) {
  3268 	    TclStoreInt1AtPtr(srcLen, p);
  3269 	    p++;
  3270 	} else {
  3271 	    TclStoreInt1AtPtr(0xFF, p);
  3272 	    p++;
  3273 	    TclStoreInt4AtPtr(srcLen, p);
  3274 	    p += 4;
  3275 	}
  3276     }
  3277     
  3278     return p;
  3279 }
  3280 
  3281 #ifdef TCL_COMPILE_DEBUG
  3282 /*
  3283  *----------------------------------------------------------------------
  3284  *
  3285  * TclPrintByteCodeObj --
  3286  *
  3287  *	This procedure prints ("disassembles") the instructions of a
  3288  *	bytecode object to stdout.
  3289  *
  3290  * Results:
  3291  *	None.
  3292  *
  3293  * Side effects:
  3294  *	None.
  3295  *
  3296  *----------------------------------------------------------------------
  3297  */
  3298 
  3299 void
  3300 TclPrintByteCodeObj(interp, objPtr)
  3301     Tcl_Interp *interp;		/* Used only for Tcl_GetStringFromObj. */
  3302     Tcl_Obj *objPtr;		/* The bytecode object to disassemble. */
  3303 {
  3304     ByteCode* codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
  3305     unsigned char *codeStart, *codeLimit, *pc;
  3306     unsigned char *codeDeltaNext, *codeLengthNext;
  3307     unsigned char *srcDeltaNext, *srcLengthNext;
  3308     int codeOffset, codeLen, srcOffset, srcLen, numCmds, delta, i;
  3309     Interp *iPtr = (Interp *) *codePtr->interpHandle;
  3310 
  3311     if (codePtr->refCount <= 0) {
  3312 	return;			/* already freed */
  3313     }
  3314 
  3315     codeStart = codePtr->codeStart;
  3316     codeLimit = (codeStart + codePtr->numCodeBytes);
  3317     numCmds = codePtr->numCommands;
  3318 
  3319     /*
  3320      * Print header lines describing the ByteCode.
  3321      */
  3322 
  3323     fprintf(stdout, "\nByteCode 0x%x, refCt %u, epoch %u, interp 0x%x (epoch %u)\n",
  3324 	    (unsigned int) codePtr, codePtr->refCount,
  3325 	    codePtr->compileEpoch, (unsigned int) iPtr,
  3326 	    iPtr->compileEpoch);
  3327     fprintf(stdout, "  Source ");
  3328     TclPrintSource(stdout, codePtr->source,
  3329 	    TclMin(codePtr->numSrcBytes, 55));
  3330     fprintf(stdout, "\n  Cmds %d, src %d, inst %d, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n",
  3331 	    numCmds, codePtr->numSrcBytes, codePtr->numCodeBytes,
  3332 	    codePtr->numLitObjects, codePtr->numAuxDataItems,
  3333 	    codePtr->maxStackDepth,
  3334 #ifdef TCL_COMPILE_STATS
  3335 	    (codePtr->numSrcBytes?
  3336 	            ((float)codePtr->structureSize)/((float)codePtr->numSrcBytes) : 0.0));
  3337 #else
  3338 	    0.0);
  3339 #endif
  3340 #ifdef TCL_COMPILE_STATS
  3341     fprintf(stdout,
  3342 	    "  Code %d = header %d+inst %d+litObj %d+exc %d+aux %d+cmdMap %d\n",
  3343 	    codePtr->structureSize,
  3344 	    (sizeof(ByteCode) - (sizeof(size_t) + sizeof(Tcl_Time))),
  3345 	    codePtr->numCodeBytes,
  3346 	    (codePtr->numLitObjects * sizeof(Tcl_Obj *)),
  3347 	    (codePtr->numExceptRanges * sizeof(ExceptionRange)),
  3348 	    (codePtr->numAuxDataItems * sizeof(AuxData)),
  3349 	    codePtr->numCmdLocBytes);
  3350 #endif /* TCL_COMPILE_STATS */
  3351     
  3352     /*
  3353      * If the ByteCode is the compiled body of a Tcl procedure, print
  3354      * information about that procedure. Note that we don't know the
  3355      * procedure's name since ByteCode's can be shared among procedures.
  3356      */
  3357     
  3358     if (codePtr->procPtr != NULL) {
  3359 	Proc *procPtr = codePtr->procPtr;
  3360 	int numCompiledLocals = procPtr->numCompiledLocals;
  3361 	fprintf(stdout,
  3362 	        "  Proc 0x%x, refCt %d, args %d, compiled locals %d\n",
  3363 		(unsigned int) procPtr, procPtr->refCount, procPtr->numArgs,
  3364 		numCompiledLocals);
  3365 	if (numCompiledLocals > 0) {
  3366 	    CompiledLocal *localPtr = procPtr->firstLocalPtr;
  3367 	    for (i = 0;  i < numCompiledLocals;  i++) {
  3368 		fprintf(stdout, "      slot %d%s%s%s%s%s%s", i, 
  3369 			((localPtr->flags & VAR_SCALAR)?  ", scalar"  : ""),
  3370 			((localPtr->flags & VAR_ARRAY)?  ", array"  : ""),
  3371 			((localPtr->flags & VAR_LINK)?  ", link"  : ""),
  3372 			((localPtr->flags & VAR_ARGUMENT)?  ", arg"  : ""),
  3373 			((localPtr->flags & VAR_TEMPORARY)? ", temp" : ""),
  3374 			((localPtr->flags & VAR_RESOLVED)? ", resolved" : ""));
  3375 		if (TclIsVarTemporary(localPtr)) {
  3376 		    fprintf(stdout,	"\n");
  3377 		} else {
  3378 		    fprintf(stdout,	", \"%s\"\n", localPtr->name);
  3379 		}
  3380 		localPtr = localPtr->nextPtr;
  3381 	    }
  3382 	}
  3383     }
  3384 
  3385     /*
  3386      * Print the ExceptionRange array.
  3387      */
  3388 
  3389     if (codePtr->numExceptRanges > 0) {
  3390 	fprintf(stdout, "  Exception ranges %d, depth %d:\n",
  3391 	        codePtr->numExceptRanges, codePtr->maxExceptDepth);
  3392 	for (i = 0;  i < codePtr->numExceptRanges;  i++) {
  3393 	    ExceptionRange *rangePtr = &(codePtr->exceptArrayPtr[i]);
  3394 	    fprintf(stdout, "      %d: level %d, %s, pc %d-%d, ",
  3395 		    i, rangePtr->nestingLevel,
  3396 		    ((rangePtr->type == LOOP_EXCEPTION_RANGE)
  3397 			    ? "loop" : "catch"),
  3398 		    rangePtr->codeOffset,
  3399 		    (rangePtr->codeOffset + rangePtr->numCodeBytes - 1));
  3400 	    switch (rangePtr->type) {
  3401 	    case LOOP_EXCEPTION_RANGE:
  3402 		fprintf(stdout,	"continue %d, break %d\n",
  3403 		        rangePtr->continueOffset, rangePtr->breakOffset);
  3404 		break;
  3405 	    case CATCH_EXCEPTION_RANGE:
  3406 		fprintf(stdout,	"catch %d\n", rangePtr->catchOffset);
  3407 		break;
  3408 	    default:
  3409 		panic("TclPrintByteCodeObj: bad ExceptionRange type %d\n",
  3410 		        rangePtr->type);
  3411 	    }
  3412 	}
  3413     }
  3414     
  3415     /*
  3416      * If there were no commands (e.g., an expression or an empty string
  3417      * was compiled), just print all instructions and return.
  3418      */
  3419 
  3420     if (numCmds == 0) {
  3421 	pc = codeStart;
  3422 	while (pc < codeLimit) {
  3423 	    fprintf(stdout, "    ");
  3424 	    pc += TclPrintInstruction(codePtr, pc);
  3425 	}
  3426 	return;
  3427     }
  3428     
  3429     /*
  3430      * Print table showing the code offset, source offset, and source
  3431      * length for each command. These are encoded as a sequence of bytes.
  3432      */
  3433 
  3434     fprintf(stdout, "  Commands %d:", numCmds);
  3435     codeDeltaNext = codePtr->codeDeltaStart;
  3436     codeLengthNext = codePtr->codeLengthStart;
  3437     srcDeltaNext  = codePtr->srcDeltaStart;
  3438     srcLengthNext = codePtr->srcLengthStart;
  3439     codeOffset = srcOffset = 0;
  3440     for (i = 0;  i < numCmds;  i++) {
  3441 	if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) {
  3442 	    codeDeltaNext++;
  3443 	    delta = TclGetInt4AtPtr(codeDeltaNext);
  3444 	    codeDeltaNext += 4;
  3445 	} else {
  3446 	    delta = TclGetInt1AtPtr(codeDeltaNext);
  3447 	    codeDeltaNext++;
  3448 	}
  3449 	codeOffset += delta;
  3450 
  3451 	if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) {
  3452 	    codeLengthNext++;
  3453 	    codeLen = TclGetInt4AtPtr(codeLengthNext);
  3454 	    codeLengthNext += 4;
  3455 	} else {
  3456 	    codeLen = TclGetInt1AtPtr(codeLengthNext);
  3457 	    codeLengthNext++;
  3458 	}
  3459 	
  3460 	if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) {
  3461 	    srcDeltaNext++;
  3462 	    delta = TclGetInt4AtPtr(srcDeltaNext);
  3463 	    srcDeltaNext += 4;
  3464 	} else {
  3465 	    delta = TclGetInt1AtPtr(srcDeltaNext);
  3466 	    srcDeltaNext++;
  3467 	}
  3468 	srcOffset += delta;
  3469 
  3470 	if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) {
  3471 	    srcLengthNext++;
  3472 	    srcLen = TclGetInt4AtPtr(srcLengthNext);
  3473 	    srcLengthNext += 4;
  3474 	} else {
  3475 	    srcLen = TclGetInt1AtPtr(srcLengthNext);
  3476 	    srcLengthNext++;
  3477 	}
  3478 	
  3479 	fprintf(stdout,	"%s%4d: pc %d-%d, src %d-%d",
  3480 		((i % 2)? "   	" : "\n   "),
  3481 		(i+1), codeOffset, (codeOffset + codeLen - 1),
  3482 		srcOffset, (srcOffset + srcLen - 1));
  3483     }
  3484     if (numCmds > 0) {
  3485 	fprintf(stdout,	"\n");
  3486     }
  3487     
  3488     /*
  3489      * Print each instruction. If the instruction corresponds to the start
  3490      * of a command, print the command's source. Note that we don't need
  3491      * the code length here.
  3492      */
  3493 
  3494     codeDeltaNext = codePtr->codeDeltaStart;
  3495     srcDeltaNext  = codePtr->srcDeltaStart;
  3496     srcLengthNext = codePtr->srcLengthStart;
  3497     codeOffset = srcOffset = 0;
  3498     pc = codeStart;
  3499     for (i = 0;  i < numCmds;  i++) {
  3500 	if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) {
  3501 	    codeDeltaNext++;
  3502 	    delta = TclGetInt4AtPtr(codeDeltaNext);
  3503 	    codeDeltaNext += 4;
  3504 	} else {
  3505 	    delta = TclGetInt1AtPtr(codeDeltaNext);
  3506 	    codeDeltaNext++;
  3507 	}
  3508 	codeOffset += delta;
  3509 
  3510 	if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) {
  3511 	    srcDeltaNext++;
  3512 	    delta = TclGetInt4AtPtr(srcDeltaNext);
  3513 	    srcDeltaNext += 4;
  3514 	} else {
  3515 	    delta = TclGetInt1AtPtr(srcDeltaNext);
  3516 	    srcDeltaNext++;
  3517 	}
  3518 	srcOffset += delta;
  3519 
  3520 	if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) {
  3521 	    srcLengthNext++;
  3522 	    srcLen = TclGetInt4AtPtr(srcLengthNext);
  3523 	    srcLengthNext += 4;
  3524 	} else {
  3525 	    srcLen = TclGetInt1AtPtr(srcLengthNext);
  3526 	    srcLengthNext++;
  3527 	}
  3528 
  3529 	/*
  3530 	 * Print instructions before command i.
  3531 	 */
  3532 	
  3533 	while ((pc-codeStart) < codeOffset) {
  3534 	    fprintf(stdout, "    ");
  3535 	    pc += TclPrintInstruction(codePtr, pc);
  3536 	}
  3537 
  3538 	fprintf(stdout, "  Command %d: ", (i+1));
  3539 	TclPrintSource(stdout, (codePtr->source + srcOffset),
  3540 	        TclMin(srcLen, 55));
  3541 	fprintf(stdout, "\n");
  3542     }
  3543     if (pc < codeLimit) {
  3544 	/*
  3545 	 * Print instructions after the last command.
  3546 	 */
  3547 
  3548 	while (pc < codeLimit) {
  3549 	    fprintf(stdout, "    ");
  3550 	    pc += TclPrintInstruction(codePtr, pc);
  3551 	}
  3552     }
  3553 }
  3554 #endif /* TCL_COMPILE_DEBUG */
  3555 
  3556 /*
  3557  *----------------------------------------------------------------------
  3558  *
  3559  * TclPrintInstruction --
  3560  *
  3561  *	This procedure prints ("disassembles") one instruction from a
  3562  *	bytecode object to stdout.
  3563  *
  3564  * Results:
  3565  *	Returns the length in bytes of the current instruiction.
  3566  *
  3567  * Side effects:
  3568  *	None.
  3569  *
  3570  *----------------------------------------------------------------------
  3571  */
  3572 
  3573 int
  3574 TclPrintInstruction(codePtr, pc)
  3575     ByteCode* codePtr;		/* Bytecode containing the instruction. */
  3576     unsigned char *pc;		/* Points to first byte of instruction. */
  3577 {
  3578     Proc *procPtr = codePtr->procPtr;
  3579     unsigned char opCode = *pc;
  3580     register InstructionDesc *instDesc = &tclInstructionTable[opCode];
  3581     unsigned char *codeStart = codePtr->codeStart;
  3582     unsigned int pcOffset = (pc - codeStart);
  3583     int opnd, i, j;
  3584     
  3585     fprintf(stdout, "(%u) %s ", pcOffset, instDesc->name);
  3586     for (i = 0;  i < instDesc->numOperands;  i++) {
  3587 	switch (instDesc->opTypes[i]) {
  3588 	case OPERAND_INT1:
  3589 	    opnd = TclGetInt1AtPtr(pc+1+i);
  3590 	    if ((i == 0) && ((opCode == INST_JUMP1)
  3591 			     || (opCode == INST_JUMP_TRUE1)
  3592 		             || (opCode == INST_JUMP_FALSE1))) {
  3593 		fprintf(stdout, "%d  	# pc %u", opnd, (pcOffset + opnd));
  3594 	    } else {
  3595 		fprintf(stdout, "%d", opnd);
  3596 	    }
  3597 	    break;
  3598 	case OPERAND_INT4:
  3599 	    opnd = TclGetInt4AtPtr(pc+1+i);
  3600 	    if ((i == 0) && ((opCode == INST_JUMP4)
  3601 			     || (opCode == INST_JUMP_TRUE4)
  3602 		             || (opCode == INST_JUMP_FALSE4))) {
  3603 		fprintf(stdout, "%d  	# pc %u", opnd, (pcOffset + opnd));
  3604 	    } else {
  3605 		fprintf(stdout, "%d", opnd);
  3606 	    }
  3607 	    break;
  3608 	case OPERAND_UINT1:
  3609 	    opnd = TclGetUInt1AtPtr(pc+1+i);
  3610 	    if ((i == 0) && (opCode == INST_PUSH1)) {
  3611 		fprintf(stdout, "%u  	# ", (unsigned int) opnd);
  3612 		TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40);
  3613 	    } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR1)
  3614 				    || (opCode == INST_LOAD_ARRAY1)
  3615 				    || (opCode == INST_STORE_SCALAR1)
  3616 				    || (opCode == INST_STORE_ARRAY1))) {
  3617 		int localCt = procPtr->numCompiledLocals;
  3618 		CompiledLocal *localPtr = procPtr->firstLocalPtr;
  3619 		if (opnd >= localCt) {
  3620 		    panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
  3621 			     (unsigned int) opnd, localCt);
  3622 		    return instDesc->numBytes;
  3623 		}
  3624 		for (j = 0;  j < opnd;  j++) {
  3625 		    localPtr = localPtr->nextPtr;
  3626 		}
  3627 		if (TclIsVarTemporary(localPtr)) {
  3628 		    fprintf(stdout, "%u	# temp var %u",
  3629 			    (unsigned int) opnd, (unsigned int) opnd);
  3630 		} else {
  3631 		    fprintf(stdout, "%u	# var ", (unsigned int) opnd);
  3632 		    TclPrintSource(stdout, localPtr->name, 40);
  3633 		}
  3634 	    } else {
  3635 		fprintf(stdout, "%u ", (unsigned int) opnd);
  3636 	    }
  3637 	    break;
  3638 	case OPERAND_UINT4:
  3639 	    opnd = TclGetUInt4AtPtr(pc+1+i);
  3640 	    if (opCode == INST_PUSH4) {
  3641 		fprintf(stdout, "%u  	# ", opnd);
  3642 		TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40);
  3643 	    } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR4)
  3644 				    || (opCode == INST_LOAD_ARRAY4)
  3645 				    || (opCode == INST_STORE_SCALAR4)
  3646 				    || (opCode == INST_STORE_ARRAY4))) {
  3647 		int localCt = procPtr->numCompiledLocals;
  3648 		CompiledLocal *localPtr = procPtr->firstLocalPtr;
  3649 		if (opnd >= localCt) {
  3650 		    panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
  3651 			     (unsigned int) opnd, localCt);
  3652 		    return instDesc->numBytes;
  3653 		}
  3654 		for (j = 0;  j < opnd;  j++) {
  3655 		    localPtr = localPtr->nextPtr;
  3656 		}
  3657 		if (TclIsVarTemporary(localPtr)) {
  3658 		    fprintf(stdout, "%u	# temp var %u",
  3659 			    (unsigned int) opnd, (unsigned int) opnd);
  3660 		} else {
  3661 		    fprintf(stdout, "%u	# var ", (unsigned int) opnd);
  3662 		    TclPrintSource(stdout, localPtr->name, 40);
  3663 		}
  3664 	    } else {
  3665 		fprintf(stdout, "%u ", (unsigned int) opnd);
  3666 	    }
  3667 	    break;
  3668 	case OPERAND_NONE:
  3669 	default:
  3670 	    break;
  3671 	}
  3672     }
  3673     fprintf(stdout, "\n");
  3674     return instDesc->numBytes;
  3675 }
  3676 
  3677 /*
  3678  *----------------------------------------------------------------------
  3679  *
  3680  * TclPrintObject --
  3681  *
  3682  *	This procedure prints up to a specified number of characters from
  3683  *	the argument Tcl object's string representation to a specified file.
  3684  *
  3685  * Results:
  3686  *	None.
  3687  *
  3688  * Side effects:
  3689  *	Outputs characters to the specified file.
  3690  *
  3691  *----------------------------------------------------------------------
  3692  */
  3693 
  3694 void
  3695 TclPrintObject(outFile, objPtr, maxChars)
  3696     FILE *outFile;		/* The file to print the source to. */
  3697     Tcl_Obj *objPtr;		/* Points to the Tcl object whose string
  3698 				 * representation should be printed. */
  3699     int maxChars;		/* Maximum number of chars to print. */
  3700 {
  3701     char *bytes;
  3702     int length;
  3703     
  3704     bytes = Tcl_GetStringFromObj(objPtr, &length);
  3705     TclPrintSource(outFile, bytes, TclMin(length, maxChars));
  3706 }
  3707 
  3708 /*
  3709  *----------------------------------------------------------------------
  3710  *
  3711  * TclPrintSource --
  3712  *
  3713  *	This procedure prints up to a specified number of characters from
  3714  *	the argument string to a specified file. It tries to produce legible
  3715  *	output by adding backslashes as necessary.
  3716  *
  3717  * Results:
  3718  *	None.
  3719  *
  3720  * Side effects:
  3721  *	Outputs characters to the specified file.
  3722  *
  3723  *----------------------------------------------------------------------
  3724  */
  3725 
  3726 void
  3727 TclPrintSource(outFile, string, maxChars)
  3728     FILE *outFile;		/* The file to print the source to. */
  3729     CONST char *string;		/* The string to print. */
  3730     int maxChars;		/* Maximum number of chars to print. */
  3731 {
  3732     register CONST char *p;
  3733     register int i = 0;
  3734 
  3735     if (string == NULL) {
  3736 	fprintf(outFile, "\"\"");
  3737 	return;
  3738     }
  3739 
  3740     fprintf(outFile, "\"");
  3741     p = string;
  3742     for (;  (*p != '\0') && (i < maxChars);  p++, i++) {
  3743 	switch (*p) {
  3744 	    case '"':
  3745 		fprintf(outFile, "\\\"");
  3746 		continue;
  3747 	    case '\f':
  3748 		fprintf(outFile, "\\f");
  3749 		continue;
  3750 	    case '\n':
  3751 		fprintf(outFile, "\\n");
  3752 		continue;
  3753             case '\r':
  3754 		fprintf(outFile, "\\r");
  3755 		continue;
  3756 	    case '\t':
  3757 		fprintf(outFile, "\\t");
  3758 		continue;
  3759             case '\v':
  3760 		fprintf(outFile, "\\v");
  3761 		continue;
  3762 	    default:
  3763 		fprintf(outFile, "%c", *p);
  3764 		continue;
  3765 	}
  3766     }
  3767     fprintf(outFile, "\"");
  3768 }
  3769 
  3770 #ifdef TCL_COMPILE_STATS
  3771 /*
  3772  *----------------------------------------------------------------------
  3773  *
  3774  * RecordByteCodeStats --
  3775  *
  3776  *	Accumulates various compilation-related statistics for each newly
  3777  *	compiled ByteCode. Called by the TclInitByteCodeObj when Tcl is
  3778  *	compiled with the -DTCL_COMPILE_STATS flag
  3779  *
  3780  * Results:
  3781  *	None.
  3782  *
  3783  * Side effects:
  3784  *	Accumulates aggregate code-related statistics in the interpreter's
  3785  *	ByteCodeStats structure. Records statistics specific to a ByteCode
  3786  *	in its ByteCode structure.
  3787  *
  3788  *----------------------------------------------------------------------
  3789  */
  3790 
  3791 void
  3792 RecordByteCodeStats(codePtr)
  3793     ByteCode *codePtr;		/* Points to ByteCode structure with info
  3794 				 * to add to accumulated statistics. */
  3795 {
  3796     Interp *iPtr = (Interp *) *codePtr->interpHandle;
  3797     register ByteCodeStats *statsPtr = &(iPtr->stats);
  3798 
  3799     statsPtr->numCompilations++;
  3800     statsPtr->totalSrcBytes        += (double) codePtr->numSrcBytes;
  3801     statsPtr->totalByteCodeBytes   += (double) codePtr->structureSize;
  3802     statsPtr->currentSrcBytes      += (double) codePtr->numSrcBytes;
  3803     statsPtr->currentByteCodeBytes += (double) codePtr->structureSize;
  3804     
  3805     statsPtr->srcCount[TclLog2(codePtr->numSrcBytes)]++;
  3806     statsPtr->byteCodeCount[TclLog2((int)(codePtr->structureSize))]++;
  3807 
  3808     statsPtr->currentInstBytes   += (double) codePtr->numCodeBytes;
  3809     statsPtr->currentLitBytes    +=
  3810 	    (double) (codePtr->numLitObjects * sizeof(Tcl_Obj *)); 
  3811     statsPtr->currentExceptBytes +=
  3812 	    (double) (codePtr->numExceptRanges * sizeof(ExceptionRange));
  3813     statsPtr->currentAuxBytes    +=
  3814             (double) (codePtr->numAuxDataItems * sizeof(AuxData));
  3815     statsPtr->currentCmdMapBytes += (double) codePtr->numCmdLocBytes;
  3816 }
  3817 #endif /* TCL_COMPILE_STATS */
  3818 
  3819 /*
  3820  * Local Variables:
  3821  * mode: c
  3822  * c-basic-offset: 4
  3823  * fill-column: 78
  3824  * End:
  3825  */
  3826