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

通讯编程

开发平台:

Visual C++

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