OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [generic/] [tclCompile.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
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-1997 Sun Microsystems, Inc.
9
 *
10
 * See the file "license.terms" for information on usage and redistribution
11
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12
 *
13
 * RCS: @(#) $Id: tclCompile.c,v 1.1.1.1 2002-01-16 10:25:26 markom Exp $
14
 */
15
 
16
#include "tclInt.h"
17
#include "tclCompile.h"
18
 
19
/*
20
 * Variable that controls whether compilation tracing is enabled and, if so,
21
 * what level of tracing is desired:
22
 *    0: no compilation tracing
23
 *    1: summarize compilation of top level cmds and proc bodies
24
 *    2: display all instructions of each ByteCode compiled
25
 * This variable is linked to the Tcl variable "tcl_traceCompile".
26
 */
27
 
28
int tclTraceCompile = 0;
29
static int traceInitialized = 0;
30
 
31
/*
32
 * Count of the number of compilations and various other compilation-
33
 * related statistics.
34
 */
35
 
36
#ifdef TCL_COMPILE_STATS
37
long tclNumCompilations = 0;
38
double tclTotalSourceBytes = 0.0;
39
double tclTotalCodeBytes = 0.0;
40
 
41
double tclTotalInstBytes = 0.0;
42
double tclTotalObjBytes = 0.0;
43
double tclTotalExceptBytes = 0.0;
44
double tclTotalAuxBytes = 0.0;
45
double tclTotalCmdMapBytes = 0.0;
46
 
47
double tclCurrentSourceBytes = 0.0;
48
double tclCurrentCodeBytes = 0.0;
49
 
50
int tclSourceCount[32];
51
int tclByteCodeCount[32];
52
#endif /* TCL_COMPILE_STATS */
53
 
54
/*
55
 * A table describing the Tcl bytecode instructions. The entries in this
56
 * table must correspond to the list of instructions in tclInt.h. The names
57
 * "op1" and "op4" refer to an instruction's one or four byte first operand.
58
 * Similarly, "stktop" and "stknext" refer to the topmost and next to
59
 * topmost stack elements.
60
 *
61
 * Note that the load, store, and incr instructions do not distinguish local
62
 * from global variables; the bytecode interpreter at runtime uses the
63
 * existence of a procedure call frame to distinguish these.
64
 */
65
 
66
InstructionDesc instructionTable[] = {
67
   /* Name            Bytes #Opnds Operand types        Stack top, next   */
68
    {"done",              1,   0,   {OPERAND_NONE}},
69
        /* Finish ByteCode execution and return stktop (top stack item) */
70
    {"push1",             2,   1,   {OPERAND_UINT1}},
71
        /* Push object at ByteCode objArray[op1] */
72
    {"push4",             5,   1,   {OPERAND_UINT4}},
73
        /* Push object at ByteCode objArray[op4] */
74
    {"pop",               1,   0,   {OPERAND_NONE}},
75
        /* Pop the topmost stack object */
76
    {"dup",               1,   0,   {OPERAND_NONE}},
77
        /* Duplicate the topmost stack object and push the result */
78
    {"concat1",           2,   1,   {OPERAND_UINT1}},
79
        /* Concatenate the top op1 items and push result */
80
    {"invokeStk1",        2,   1,   {OPERAND_UINT1}},
81
        /* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */
82
    {"invokeStk4",        5,   1,   {OPERAND_UINT4}},
83
        /* Invoke command named objv[0]; <objc,objv> = <op4,top op4> */
84
    {"evalStk",           1,   0,   {OPERAND_NONE}},
85
        /* Evaluate command in stktop using Tcl_EvalObj. */
86
    {"exprStk",           1,   0,   {OPERAND_NONE}},
87
        /* Execute expression in stktop using Tcl_ExprStringObj. */
88
 
89
    {"loadScalar1",       2,   1,   {OPERAND_UINT1}},
90
        /* Load scalar variable at index op1 <= 255 in call frame */
91
    {"loadScalar4",       5,   1,   {OPERAND_UINT4}},
92
        /* Load scalar variable at index op1 >= 256 in call frame */
93
    {"loadScalarStk",     1,   0,   {OPERAND_NONE}},
94
        /* Load scalar variable; scalar's name is stktop */
95
    {"loadArray1",        2,   1,   {OPERAND_UINT1}},
96
        /* Load array element; array at slot op1<=255, element is stktop */
97
    {"loadArray4",        5,   1,   {OPERAND_UINT4}},
98
        /* Load array element; array at slot op1 > 255, element is stktop */
99
    {"loadArrayStk",      1,   0,   {OPERAND_NONE}},
100
        /* Load array element; element is stktop, array name is stknext */
101
    {"loadStk",           1,   0,   {OPERAND_NONE}},
102
        /* Load general variable; unparsed variable name is stktop */
103
    {"storeScalar1",      2,   1,   {OPERAND_UINT1}},
104
        /* Store scalar variable at op1<=255 in frame; value is stktop */
105
    {"storeScalar4",      5,   1,   {OPERAND_UINT4}},
106
        /* Store scalar variable at op1 > 255 in frame; value is stktop */
107
    {"storeScalarStk",    1,   0,   {OPERAND_NONE}},
108
        /* Store scalar; value is stktop, scalar name is stknext */
109
    {"storeArray1",       2,   1,   {OPERAND_UINT1}},
110
        /* Store array element; array at op1<=255, value is top then elem */
111
    {"storeArray4",       5,   1,   {OPERAND_UINT4}},
112
        /* Store array element; array at op1>=256, value is top then elem */
113
    {"storeArrayStk",     1,   0,   {OPERAND_NONE}},
114
        /* Store array element; value is stktop, then elem, array names */
115
    {"storeStk",          1,   0,   {OPERAND_NONE}},
116
        /* Store general variable; value is stktop, then unparsed name */
117
 
118
    {"incrScalar1",       2,   1,   {OPERAND_UINT1}},
119
        /* Incr scalar at index op1<=255 in frame; incr amount is stktop */
120
    {"incrScalarStk",     1,   0,   {OPERAND_NONE}},
121
        /* Incr scalar; incr amount is stktop, scalar's name is stknext */
122
    {"incrArray1",        2,   1,   {OPERAND_UINT1}},
123
        /* Incr array elem; arr at slot op1<=255, amount is top then elem */
124
    {"incrArrayStk",      1,   0,   {OPERAND_NONE}},
125
        /* Incr array element; amount is top then elem then array names */
126
    {"incrStk",           1,   0,   {OPERAND_NONE}},
127
        /* Incr general variable; amount is stktop then unparsed var name */
128
    {"incrScalar1Imm",    3,   2,   {OPERAND_UINT1, OPERAND_INT1}},
129
        /* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */
130
    {"incrScalarStkImm",  2,   1,   {OPERAND_INT1}},
131
        /* Incr scalar; scalar name is stktop; incr amount is op1 */
132
    {"incrArray1Imm",     3,   2,   {OPERAND_UINT1, OPERAND_INT1}},
133
        /* Incr array elem; array at slot op1 <= 255, elem is stktop,
134
         * amount is 2nd operand byte */
135
    {"incrArrayStkImm",   2,   1,   {OPERAND_INT1}},
136
        /* Incr array element; elem is top then array name, amount is op1 */
137
    {"incrStkImm",        2,   1,   {OPERAND_INT1}},
138
        /* Incr general variable; unparsed name is top, amount is op1 */
139
 
140
    {"jump1",             2,   1,   {OPERAND_INT1}},
141
        /* Jump relative to (pc + op1) */
142
    {"jump4",             5,   1,   {OPERAND_INT4}},
143
        /* Jump relative to (pc + op4) */
144
    {"jumpTrue1",         2,   1,   {OPERAND_INT1}},
145
        /* Jump relative to (pc + op1) if stktop expr object is true */
146
    {"jumpTrue4",         5,   1,   {OPERAND_INT4}},
147
        /* Jump relative to (pc + op4) if stktop expr object is true */
148
    {"jumpFalse1",        2,   1,   {OPERAND_INT1}},
149
        /* Jump relative to (pc + op1) if stktop expr object is false */
150
    {"jumpFalse4",        5,   1,   {OPERAND_INT4}},
151
        /* Jump relative to (pc + op4) if stktop expr object is false */
152
 
153
    {"lor",               1,   0,   {OPERAND_NONE}},
154
        /* Logical or:  push (stknext || stktop) */
155
    {"land",              1,   0,   {OPERAND_NONE}},
156
        /* Logical and: push (stknext && stktop) */
157
    {"bitor",             1,   0,   {OPERAND_NONE}},
158
        /* Bitwise or:  push (stknext | stktop) */
159
    {"bitxor",            1,   0,   {OPERAND_NONE}},
160
        /* Bitwise xor  push (stknext ^ stktop) */
161
    {"bitand",            1,   0,   {OPERAND_NONE}},
162
        /* Bitwise and: push (stknext & stktop) */
163
    {"eq",                1,   0,   {OPERAND_NONE}},
164
        /* Equal:       push (stknext == stktop) */
165
    {"neq",               1,   0,   {OPERAND_NONE}},
166
        /* Not equal:   push (stknext != stktop) */
167
    {"lt",                1,   0,   {OPERAND_NONE}},
168
        /* Less:        push (stknext < stktop) */
169
    {"gt",                1,   0,   {OPERAND_NONE}},
170
        /* Greater:     push (stknext || stktop) */
171
    {"le",                1,   0,   {OPERAND_NONE}},
172
        /* Logical or:  push (stknext || stktop) */
173
    {"ge",                1,   0,   {OPERAND_NONE}},
174
        /* Logical or:  push (stknext || stktop) */
175
    {"lshift",            1,   0,   {OPERAND_NONE}},
176
        /* Left shift:  push (stknext << stktop) */
177
    {"rshift",            1,   0,   {OPERAND_NONE}},
178
        /* Right shift: push (stknext >> stktop) */
179
    {"add",               1,   0,   {OPERAND_NONE}},
180
        /* Add:         push (stknext + stktop) */
181
    {"sub",               1,   0,   {OPERAND_NONE}},
182
        /* Sub:         push (stkext - stktop) */
183
    {"mult",              1,   0,   {OPERAND_NONE}},
184
        /* Multiply:    push (stknext * stktop) */
185
    {"div",               1,   0,   {OPERAND_NONE}},
186
        /* Divide:      push (stknext / stktop) */
187
    {"mod",               1,   0,   {OPERAND_NONE}},
188
        /* Mod:         push (stknext % stktop) */
189
    {"uplus",             1,   0,   {OPERAND_NONE}},
190
        /* Unary plus:  push +stktop */
191
    {"uminus",            1,   0,   {OPERAND_NONE}},
192
        /* Unary minus: push -stktop */
193
    {"bitnot",            1,   0,   {OPERAND_NONE}},
194
        /* Bitwise not: push ~stktop */
195
    {"not",               1,   0,   {OPERAND_NONE}},
196
        /* Logical not: push !stktop */
197
    {"callBuiltinFunc1",  2,   1,   {OPERAND_UINT1}},
198
        /* Call builtin math function with index op1; any args are on stk */
199
    {"callFunc1",         2,   1,   {OPERAND_UINT1}},
200
        /* Call non-builtin func objv[0]; <objc,objv>=<op1,top op1>  */
201
    {"tryCvtToNumeric",   1,   0,   {OPERAND_NONE}},
202
        /* Try converting stktop to first int then double if possible. */
203
 
204
    {"break",             1,   0,   {OPERAND_NONE}},
205
        /* Abort closest enclosing loop; if none, return TCL_BREAK code. */
206
    {"continue",          1,   0,   {OPERAND_NONE}},
207
        /* Skip to next iteration of closest enclosing loop; if none,
208
         * return TCL_CONTINUE code. */
209
 
210
    {"foreach_start4",    5,   1,   {OPERAND_UINT4}},
211
        /* Initialize execution of a foreach loop. Operand is aux data index
212
         * of the ForeachInfo structure for the foreach command. */
213
    {"foreach_step4",     5,   1,   {OPERAND_UINT4}},
214
        /* "Step" or begin next iteration of foreach loop. Push 0 if to
215
         *  terminate loop, else push 1. */
216
 
217
    {"beginCatch4",       5,   1,   {OPERAND_UINT4}},
218
        /* Record start of catch with the operand's exception range index.
219
         * Push the current stack depth onto a special catch stack. */
220
    {"endCatch",          1,   0,   {OPERAND_NONE}},
221
        /* End of last catch. Pop the bytecode interpreter's catch stack. */
222
    {"pushResult",        1,   0,   {OPERAND_NONE}},
223
        /* Push the interpreter's object result onto the stack. */
224
    {"pushReturnCode",    1,   0,   {OPERAND_NONE}},
225
        /* Push interpreter's return code (e.g. TCL_OK or TCL_ERROR) as
226
         * a new object onto the stack. */
227
    {0}
228
};
229
 
230
/*
231
 * The following table assigns a type to each character. Only types
232
 * meaningful to Tcl parsing are represented here. The table is
233
 * designed to be referenced with either signed or unsigned characters,
234
 * so it has 384 entries. The first 128 entries correspond to negative
235
 * character values, the next 256 correspond to positive character
236
 * values. The last 128 entries are identical to the first 128. The
237
 * table is always indexed with a 128-byte offset (the 128th entry
238
 * corresponds to a 0 character value).
239
 */
240
 
241
unsigned char tclTypeTable[] = {
242
    /*
243
     * Negative character values, from -128 to -1:
244
     */
245
 
246
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
247
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
248
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
249
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
250
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
251
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
252
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
253
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
254
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
255
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
256
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
257
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
258
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
259
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
260
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
261
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
262
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
263
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
264
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
265
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
266
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
267
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
268
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
269
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
270
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
271
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
272
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
273
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
274
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
275
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
276
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
277
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
278
 
279
    /*
280
     * Positive character values, from 0-127:
281
     */
282
 
283
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
284
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
285
    TCL_NORMAL,        TCL_SPACE,         TCL_COMMAND_END,   TCL_SPACE,
286
    TCL_SPACE,         TCL_SPACE,         TCL_NORMAL,        TCL_NORMAL,
287
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
288
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
289
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
290
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
291
    TCL_SPACE,         TCL_NORMAL,        TCL_QUOTE,         TCL_NORMAL,
292
    TCL_DOLLAR,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
293
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
294
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
295
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
296
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
297
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_COMMAND_END,
298
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
299
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
300
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
301
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
302
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
303
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
304
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
305
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_OPEN_BRACKET,
306
    TCL_BACKSLASH,     TCL_COMMAND_END,   TCL_NORMAL,        TCL_NORMAL,
307
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
308
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
309
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
310
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
311
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
312
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
313
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_OPEN_BRACE,
314
    TCL_NORMAL,        TCL_CLOSE_BRACE,   TCL_NORMAL,        TCL_NORMAL,
315
 
316
    /*
317
     * Large unsigned character values, from 128-255:
318
     */
319
 
320
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
321
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
322
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
323
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
324
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
325
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
326
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
327
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
328
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
329
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
330
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
331
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
332
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
333
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
334
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
335
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
336
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
337
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
338
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
339
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
340
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
341
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
342
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
343
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
344
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
345
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
346
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
347
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
348
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
349
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
350
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
351
    TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,        TCL_NORMAL,
352
};
353
 
354
/*
355
 * Table of all AuxData types.
356
 */
357
 
358
static Tcl_HashTable auxDataTypeTable;
359
static int auxDataTypeTableInitialized = 0;    /* 0 means not yet
360
                                                * initialized. */
361
 
362
/*
363
 * Prototypes for procedures defined later in this file:
364
 */
365
 
366
static void             AdvanceToNextWord _ANSI_ARGS_((char *string,
367
                            CompileEnv *envPtr));
368
static int              CollectArgInfo _ANSI_ARGS_((Tcl_Interp *interp,
369
                            char *string, char *lastChar, int flags,
370
                            ArgInfo *argInfoPtr));
371
static int              CompileBraces _ANSI_ARGS_((Tcl_Interp *interp,
372
                            char *string, char *lastChar, int flags,
373
                            CompileEnv *envPtr));
374
static int              CompileCmdWordInline _ANSI_ARGS_((
375
                            Tcl_Interp *interp, char *string,
376
                            char *lastChar, int flags, CompileEnv *envPtr));
377
static int              CompileExprWord _ANSI_ARGS_((Tcl_Interp *interp,
378
                            char *string, char *lastChar, int flags,
379
                            CompileEnv *envPtr));
380
static int              CompileMultipartWord _ANSI_ARGS_((
381
                            Tcl_Interp *interp, char *string,
382
                            char *lastChar, int flags, CompileEnv *envPtr));
383
static int              CompileWord _ANSI_ARGS_((Tcl_Interp *interp,
384
                            char *string, char *lastChar, int flags,
385
                            CompileEnv *envPtr));
386
static int              CreateExceptionRange _ANSI_ARGS_((
387
                            ExceptionRangeType type, CompileEnv *envPtr));
388
static void             DupByteCodeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
389
                            Tcl_Obj *copyPtr));
390
static ClientData       DupForeachInfo _ANSI_ARGS_((ClientData clientData));
391
static unsigned char *  EncodeCmdLocMap _ANSI_ARGS_((
392
                            CompileEnv *envPtr, ByteCode *codePtr,
393
                            unsigned char *startPtr));
394
static void             EnterCmdExtentData _ANSI_ARGS_((
395
                            CompileEnv *envPtr, int cmdNumber,
396
                            int numSrcChars, int numCodeBytes));
397
static void             EnterCmdStartData _ANSI_ARGS_((
398
                            CompileEnv *envPtr, int cmdNumber,
399
                            int srcOffset, int codeOffset));
400
static void             ExpandObjectArray _ANSI_ARGS_((CompileEnv *envPtr));
401
static void             FreeForeachInfo _ANSI_ARGS_((
402
                            ClientData clientData));
403
static void             FreeByteCodeInternalRep _ANSI_ARGS_((
404
                            Tcl_Obj *objPtr));
405
static void             FreeArgInfo _ANSI_ARGS_((ArgInfo *argInfoPtr));
406
static int              GetCmdLocEncodingSize _ANSI_ARGS_((
407
                            CompileEnv *envPtr));
408
static void             InitArgInfo _ANSI_ARGS_((ArgInfo *argInfoPtr));
409
static int              IsLocalScalar  _ANSI_ARGS_((char *name, int len));
410
static int              LookupCompiledLocal _ANSI_ARGS_((
411
                            char *name, int nameChars, int createIfNew,
412
                            int flagsIfCreated, Proc *procPtr));
413
static int              SetByteCodeFromAny _ANSI_ARGS_((Tcl_Interp *interp,
414
                            Tcl_Obj *objPtr));
415
static void             UpdateStringOfByteCode _ANSI_ARGS_((Tcl_Obj *objPtr));
416
 
417
/*
418
 * The structure below defines the bytecode Tcl object type by
419
 * means of procedures that can be invoked by generic object code.
420
 */
421
 
422
Tcl_ObjType tclByteCodeType = {
423
    "bytecode",                 /* name */
424
    FreeByteCodeInternalRep,    /* freeIntRepProc */
425
    DupByteCodeInternalRep,     /* dupIntRepProc */
426
    UpdateStringOfByteCode,     /* updateStringProc */
427
    SetByteCodeFromAny          /* setFromAnyProc */
428
};
429
 
430
/*
431
 * The structures below define the AuxData types defined in this file.
432
 */
433
 
434
AuxDataType tclForeachInfoType = {
435
    "ForeachInfo",                              /* name */
436
    DupForeachInfo,                             /* dupProc */
437
    FreeForeachInfo                             /* freeProc */
438
};
439
 
440
/*
441
 *----------------------------------------------------------------------
442
 *
443
 * TclPrintByteCodeObj --
444
 *
445
 *      This procedure prints ("disassembles") the instructions of a
446
 *      bytecode object to stdout.
447
 *
448
 * Results:
449
 *      None.
450
 *
451
 * Side effects:
452
 *      None.
453
 *
454
 *----------------------------------------------------------------------
455
 */
456
 
457
void
458
TclPrintByteCodeObj(interp, objPtr)
459
    Tcl_Interp *interp;         /* Used only for Tcl_GetStringFromObj. */
460
    Tcl_Obj *objPtr;            /* The bytecode object to disassemble. */
461
{
462
    ByteCode* codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
463
    unsigned char *codeStart, *codeLimit, *pc;
464
    unsigned char *codeDeltaNext, *codeLengthNext;
465
    unsigned char *srcDeltaNext, *srcLengthNext;
466
    int codeOffset, codeLen, srcOffset, srcLen;
467
    int numCmds, numObjs, delta, objBytes, i;
468
 
469
    if (codePtr->refCount <= 0) {
470
        return;                 /* already freed */
471
    }
472
 
473
    codeStart = codePtr->codeStart;
474
    codeLimit = (codeStart + codePtr->numCodeBytes);
475
    numCmds = codePtr->numCommands;
476
    numObjs = codePtr->numObjects;
477
 
478
    objBytes = (numObjs * sizeof(Tcl_Obj));
479
    for (i = 0;  i < numObjs;  i++) {
480
        Tcl_Obj *litObjPtr = codePtr->objArrayPtr[i];
481
        if (litObjPtr->bytes != NULL) {
482
            objBytes += litObjPtr->length;
483
        }
484
    }
485
 
486
    /*
487
     * Print header lines describing the ByteCode.
488
     */
489
 
490
    fprintf(stdout, "\nByteCode 0x%x, ref ct %u, epoch %u, interp 0x%x(epoch %u)\n",
491
            (unsigned int) codePtr, codePtr->refCount,
492
            codePtr->compileEpoch, (unsigned int) codePtr->iPtr,
493
            codePtr->iPtr->compileEpoch);
494
    fprintf(stdout, "  Source ");
495
    TclPrintSource(stdout, codePtr->source,
496
            TclMin(codePtr->numSrcChars, 70));
497
    fprintf(stdout, "\n  Cmds %d, chars %d, inst %d, objs %u, aux %d, stk depth %u, code/src %.2f\n",
498
            numCmds, codePtr->numSrcChars, codePtr->numCodeBytes, numObjs,
499
            codePtr->numAuxDataItems, codePtr->maxStackDepth,
500
            (codePtr->numSrcChars?
501
                    ((float)codePtr->totalSize)/((float)codePtr->numSrcChars) : 0.0));
502
    fprintf(stdout, "  Code %d = %d(header)+%d(inst)+%d(objs)+%d(exc)+%d(aux)+%d(cmd map)\n",
503
            codePtr->totalSize, sizeof(ByteCode), codePtr->numCodeBytes,
504
            objBytes, (codePtr->numExcRanges * sizeof(ExceptionRange)),
505
            (codePtr->numAuxDataItems * sizeof(AuxData)),
506
            codePtr->numCmdLocBytes);
507
 
508
    /*
509
     * If the ByteCode is the compiled body of a Tcl procedure, print
510
     * information about that procedure. Note that we don't know the
511
     * procedure's name since ByteCode's can be shared among procedures.
512
     */
513
 
514
    if (codePtr->procPtr != NULL) {
515
        Proc *procPtr = codePtr->procPtr;
516
        int numCompiledLocals = procPtr->numCompiledLocals;
517
        fprintf(stdout,
518
                "  Proc 0x%x, ref ct %d, args %d, compiled locals %d\n",
519
                (unsigned int) procPtr, procPtr->refCount, procPtr->numArgs,
520
                numCompiledLocals);
521
        if (numCompiledLocals > 0) {
522
            CompiledLocal *localPtr = procPtr->firstLocalPtr;
523
            for (i = 0;  i < numCompiledLocals;  i++) {
524
                fprintf(stdout, "      %d: slot %d%s%s%s%s%s%s",
525
                        i, localPtr->frameIndex,
526
                        ((localPtr->flags & VAR_SCALAR)?  ", scalar"  : ""),
527
                        ((localPtr->flags & VAR_ARRAY)?  ", array"  : ""),
528
                        ((localPtr->flags & VAR_LINK)?  ", link"  : ""),
529
                        ((localPtr->flags & VAR_ARGUMENT)?  ", arg"  : ""),
530
                        ((localPtr->flags & VAR_TEMPORARY)? ", temp" : ""),
531
                        ((localPtr->flags & VAR_RESOLVED)? ", resolved" : ""));
532
                if (TclIsVarTemporary(localPtr)) {
533
                    fprintf(stdout,     "\n");
534
                } else {
535
                    fprintf(stdout,     ", name=\"%s\"\n", localPtr->name);
536
                }
537
                localPtr = localPtr->nextPtr;
538
            }
539
        }
540
    }
541
 
542
    /*
543
     * Print the ExceptionRange array.
544
     */
545
 
546
    if (codePtr->numExcRanges > 0) {
547
        fprintf(stdout, "  Exception ranges %d, depth %d:\n",
548
                codePtr->numExcRanges, codePtr->maxExcRangeDepth);
549
        for (i = 0;  i < codePtr->numExcRanges;  i++) {
550
            ExceptionRange *rangePtr = &(codePtr->excRangeArrayPtr[i]);
551
            fprintf(stdout, "      %d: level %d, %s, pc %d-%d, ",
552
                    i, rangePtr->nestingLevel,
553
                    ((rangePtr->type == LOOP_EXCEPTION_RANGE)? "loop":"catch"),
554
                    rangePtr->codeOffset,
555
                    (rangePtr->codeOffset + rangePtr->numCodeBytes - 1));
556
            switch (rangePtr->type) {
557
            case LOOP_EXCEPTION_RANGE:
558
                fprintf(stdout, "continue %d, break %d\n",
559
                        rangePtr->continueOffset, rangePtr->breakOffset);
560
                break;
561
            case CATCH_EXCEPTION_RANGE:
562
                fprintf(stdout, "catch %d\n", rangePtr->catchOffset);
563
                break;
564
            default:
565
                panic("TclPrintSource: unrecognized ExceptionRange type %d\n",
566
                        rangePtr->type);
567
            }
568
        }
569
    }
570
 
571
    /*
572
     * If there were no commands (e.g., an expression or an empty string
573
     * was compiled), just print all instructions and return.
574
     */
575
 
576
    if (numCmds == 0) {
577
        pc = codeStart;
578
        while (pc < codeLimit) {
579
            fprintf(stdout, "    ");
580
            pc += TclPrintInstruction(codePtr, pc);
581
        }
582
        return;
583
    }
584
 
585
    /*
586
     * Print table showing the code offset, source offset, and source
587
     * length for each command. These are encoded as a sequence of bytes.
588
     */
589
 
590
    fprintf(stdout, "  Commands %d:", numCmds);
591
    codeDeltaNext = codePtr->codeDeltaStart;
592
    codeLengthNext = codePtr->codeLengthStart;
593
    srcDeltaNext  = codePtr->srcDeltaStart;
594
    srcLengthNext = codePtr->srcLengthStart;
595
    codeOffset = srcOffset = 0;
596
    for (i = 0;  i < numCmds;  i++) {
597
        if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) {
598
            codeDeltaNext++;
599
            delta = TclGetInt4AtPtr(codeDeltaNext);
600
            codeDeltaNext += 4;
601
        } else {
602
            delta = TclGetInt1AtPtr(codeDeltaNext);
603
            codeDeltaNext++;
604
        }
605
        codeOffset += delta;
606
 
607
        if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) {
608
            codeLengthNext++;
609
            codeLen = TclGetInt4AtPtr(codeLengthNext);
610
            codeLengthNext += 4;
611
        } else {
612
            codeLen = TclGetInt1AtPtr(codeLengthNext);
613
            codeLengthNext++;
614
        }
615
 
616
        if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) {
617
            srcDeltaNext++;
618
            delta = TclGetInt4AtPtr(srcDeltaNext);
619
            srcDeltaNext += 4;
620
        } else {
621
            delta = TclGetInt1AtPtr(srcDeltaNext);
622
            srcDeltaNext++;
623
        }
624
        srcOffset += delta;
625
 
626
        if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) {
627
            srcLengthNext++;
628
            srcLen = TclGetInt4AtPtr(srcLengthNext);
629
            srcLengthNext += 4;
630
        } else {
631
            srcLen = TclGetInt1AtPtr(srcLengthNext);
632
            srcLengthNext++;
633
        }
634
 
635
        fprintf(stdout, "%s%4d: pc %d-%d, source %d-%d",
636
                ((i % 2)? "     " : "\n   "),
637
                (i+1), codeOffset, (codeOffset + codeLen - 1),
638
                srcOffset, (srcOffset + srcLen - 1));
639
    }
640
    if ((numCmds > 0) && ((numCmds % 2) != 0)) {
641
        fprintf(stdout, "\n");
642
    }
643
 
644
    /*
645
     * Print each instruction. If the instruction corresponds to the start
646
     * of a command, print the command's source. Note that we don't need
647
     * the code length here.
648
     */
649
 
650
    codeDeltaNext = codePtr->codeDeltaStart;
651
    srcDeltaNext  = codePtr->srcDeltaStart;
652
    srcLengthNext = codePtr->srcLengthStart;
653
    codeOffset = srcOffset = 0;
654
    pc = codeStart;
655
    for (i = 0;  i < numCmds;  i++) {
656
        if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) {
657
            codeDeltaNext++;
658
            delta = TclGetInt4AtPtr(codeDeltaNext);
659
            codeDeltaNext += 4;
660
        } else {
661
            delta = TclGetInt1AtPtr(codeDeltaNext);
662
            codeDeltaNext++;
663
        }
664
        codeOffset += delta;
665
 
666
        if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) {
667
            srcDeltaNext++;
668
            delta = TclGetInt4AtPtr(srcDeltaNext);
669
            srcDeltaNext += 4;
670
        } else {
671
            delta = TclGetInt1AtPtr(srcDeltaNext);
672
            srcDeltaNext++;
673
        }
674
        srcOffset += delta;
675
 
676
        if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) {
677
            srcLengthNext++;
678
            srcLen = TclGetInt4AtPtr(srcLengthNext);
679
            srcLengthNext += 4;
680
        } else {
681
            srcLen = TclGetInt1AtPtr(srcLengthNext);
682
            srcLengthNext++;
683
        }
684
 
685
        /*
686
         * Print instructions before command i.
687
         */
688
 
689
        while ((pc-codeStart) < codeOffset) {
690
            fprintf(stdout, "    ");
691
            pc += TclPrintInstruction(codePtr, pc);
692
        }
693
 
694
        fprintf(stdout, "  Command %d: ", (i+1));
695
        TclPrintSource(stdout, (codePtr->source + srcOffset),
696
                TclMin(srcLen, 70));
697
        fprintf(stdout, "\n");
698
    }
699
    if (pc < codeLimit) {
700
        /*
701
         * Print instructions after the last command.
702
         */
703
 
704
        while (pc < codeLimit) {
705
            fprintf(stdout, "    ");
706
            pc += TclPrintInstruction(codePtr, pc);
707
        }
708
    }
709
}
710
 
711
/*
712
 *----------------------------------------------------------------------
713
 *
714
 * TclPrintInstruction --
715
 *
716
 *      This procedure prints ("disassembles") one instruction from a
717
 *      bytecode object to stdout.
718
 *
719
 * Results:
720
 *      Returns the length in bytes of the current instruiction.
721
 *
722
 * Side effects:
723
 *      None.
724
 *
725
 *----------------------------------------------------------------------
726
 */
727
 
728
int
729
TclPrintInstruction(codePtr, pc)
730
    ByteCode* codePtr;          /* Bytecode containing the instruction. */
731
    unsigned char *pc;          /* Points to first byte of instruction. */
732
{
733
    Proc *procPtr = codePtr->procPtr;
734
    unsigned char opCode = *pc;
735
    register InstructionDesc *instDesc = &instructionTable[opCode];
736
    unsigned char *codeStart = codePtr->codeStart;
737
    unsigned int pcOffset = (pc - codeStart);
738
    int opnd, elemLen, i, j;
739
    Tcl_Obj *elemPtr;
740
    char *string;
741
 
742
    fprintf(stdout, "(%u) %s ", pcOffset, instDesc->name);
743
    for (i = 0;  i < instDesc->numOperands;  i++) {
744
        switch (instDesc->opTypes[i]) {
745
        case OPERAND_INT1:
746
            opnd = TclGetInt1AtPtr(pc+1+i);
747
            if ((i == 0) && ((opCode == INST_JUMP1)
748
                             || (opCode == INST_JUMP_TRUE1)
749
                             || (opCode == INST_JUMP_FALSE1))) {
750
                fprintf(stdout, "%d     # pc %u", opnd, (pcOffset + opnd));
751
            } else {
752
                fprintf(stdout, "%d", opnd);
753
            }
754
            break;
755
        case OPERAND_INT4:
756
            opnd = TclGetInt4AtPtr(pc+1+i);
757
            if ((i == 0) && ((opCode == INST_JUMP4)
758
                             || (opCode == INST_JUMP_TRUE4)
759
                             || (opCode == INST_JUMP_FALSE4))) {
760
                fprintf(stdout, "%d     # pc %u", opnd, (pcOffset + opnd));
761
            } else {
762
                fprintf(stdout, "%d", opnd);
763
            }
764
            break;
765
        case OPERAND_UINT1:
766
            opnd = TclGetUInt1AtPtr(pc+1+i);
767
            if ((i == 0) && (opCode == INST_PUSH1)) {
768
                elemPtr = codePtr->objArrayPtr[opnd];
769
                string = Tcl_GetStringFromObj(elemPtr, &elemLen);
770
                fprintf(stdout, "%u     # ", (unsigned int) opnd);
771
                TclPrintSource(stdout, string, TclMin(elemLen, 40));
772
            } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR1)
773
                                    || (opCode == INST_LOAD_ARRAY1)
774
                                    || (opCode == INST_STORE_SCALAR1)
775
                                    || (opCode == INST_STORE_ARRAY1))) {
776
                int localCt = procPtr->numCompiledLocals;
777
                CompiledLocal *localPtr = procPtr->firstLocalPtr;
778
                if (opnd >= localCt) {
779
                    panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
780
                             (unsigned int) opnd, localCt);
781
                    return instDesc->numBytes;
782
                }
783
                for (j = 0;  j < opnd;  j++) {
784
                    localPtr = localPtr->nextPtr;
785
                }
786
                if (TclIsVarTemporary(localPtr)) {
787
                    fprintf(stdout, "%u # temp var %u",
788
                            (unsigned int) opnd, (unsigned int) opnd);
789
                } else {
790
                    fprintf(stdout, "%u # var ", (unsigned int) opnd);
791
                    TclPrintSource(stdout, localPtr->name, 40);
792
                }
793
            } else {
794
                fprintf(stdout, "%u ", (unsigned int) opnd);
795
            }
796
            break;
797
        case OPERAND_UINT4:
798
            opnd = TclGetUInt4AtPtr(pc+1+i);
799
            if (opCode == INST_PUSH4) {
800
                elemPtr = codePtr->objArrayPtr[opnd];
801
                string = Tcl_GetStringFromObj(elemPtr, &elemLen);
802
                fprintf(stdout, "%u     # ", opnd);
803
                TclPrintSource(stdout, string, TclMin(elemLen, 40));
804
            } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR4)
805
                                    || (opCode == INST_LOAD_ARRAY4)
806
                                    || (opCode == INST_STORE_SCALAR4)
807
                                    || (opCode == INST_STORE_ARRAY4))) {
808
                int localCt = procPtr->numCompiledLocals;
809
                CompiledLocal *localPtr = procPtr->firstLocalPtr;
810
                if (opnd >= localCt) {
811
                    panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
812
                             (unsigned int) opnd, localCt);
813
                    return instDesc->numBytes;
814
                }
815
                for (j = 0;  j < opnd;  j++) {
816
                    localPtr = localPtr->nextPtr;
817
                }
818
                if (TclIsVarTemporary(localPtr)) {
819
                    fprintf(stdout, "%u # temp var %u",
820
                            (unsigned int) opnd, (unsigned int) opnd);
821
                } else {
822
                    fprintf(stdout, "%u # var ", (unsigned int) opnd);
823
                    TclPrintSource(stdout, localPtr->name, 40);
824
                }
825
            } else {
826
                fprintf(stdout, "%u ", (unsigned int) opnd);
827
            }
828
            break;
829
        case OPERAND_NONE:
830
        default:
831
            break;
832
        }
833
    }
834
    fprintf(stdout, "\n");
835
    return instDesc->numBytes;
836
}
837
 
838
/*
839
 *----------------------------------------------------------------------
840
 *
841
 * TclPrintSource --
842
 *
843
 *      This procedure prints up to a specified number of characters from
844
 *      the argument string to a specified file. It tries to produce legible
845
 *      output by adding backslashes as necessary.
846
 *
847
 * Results:
848
 *      None.
849
 *
850
 * Side effects:
851
 *      Outputs characters to the specified file.
852
 *
853
 *----------------------------------------------------------------------
854
 */
855
 
856
void
857
TclPrintSource(outFile, string, maxChars)
858
    FILE *outFile;              /* The file to print the source to. */
859
    char *string;               /* The string to print. */
860
    int maxChars;               /* Maximum number of chars to print. */
861
{
862
    register char *p;
863
    register int i = 0;
864
 
865
    if (string == NULL) {
866
        fprintf(outFile, "\"\"");
867
        return;
868
    }
869
 
870
    fprintf(outFile, "\"");
871
    p = string;
872
    for (;  (*p != '\0') && (i < maxChars);  p++, i++) {
873
        switch (*p) {
874
            case '"':
875
                fprintf(outFile, "\\\"");
876
                continue;
877
            case '\f':
878
                fprintf(outFile, "\\f");
879
                continue;
880
            case '\n':
881
                fprintf(outFile, "\\n");
882
                continue;
883
            case '\r':
884
                fprintf(outFile, "\\r");
885
                continue;
886
            case '\t':
887
                fprintf(outFile, "\\t");
888
                continue;
889
            case '\v':
890
                fprintf(outFile, "\\v");
891
                continue;
892
            default:
893
                fprintf(outFile, "%c", *p);
894
                continue;
895
        }
896
    }
897
    fprintf(outFile, "\"");
898
}
899
 
900
/*
901
 *----------------------------------------------------------------------
902
 *
903
 * FreeByteCodeInternalRep --
904
 *
905
 *      Part of the bytecode Tcl object type implementation. Frees the
906
 *      storage associated with a bytecode object's internal representation
907
 *      unless its code is actively being executed.
908
 *
909
 * Results:
910
 *      None.
911
 *
912
 * Side effects:
913
 *      The bytecode object's internal rep is marked invalid and its
914
 *      code gets freed unless the code is actively being executed.
915
 *      In that case the cleanup is delayed until the last execution
916
 *      of the code completes.
917
 *
918
 *----------------------------------------------------------------------
919
 */
920
 
921
static void
922
FreeByteCodeInternalRep(objPtr)
923
    register Tcl_Obj *objPtr;   /* Object whose internal rep to free. */
924
{
925
    register ByteCode *codePtr =
926
            (ByteCode *) objPtr->internalRep.otherValuePtr;
927
 
928
    codePtr->refCount--;
929
    if (codePtr->refCount <= 0) {
930
        TclCleanupByteCode(codePtr);
931
    }
932
    objPtr->typePtr = NULL;
933
    objPtr->internalRep.otherValuePtr = NULL;
934
}
935
 
936
/*
937
 *----------------------------------------------------------------------
938
 *
939
 * TclCleanupByteCode --
940
 *
941
 *      This procedure does all the real work of freeing up a bytecode
942
 *      object's ByteCode structure. It's called only when the structure's
943
 *      reference count becomes zero.
944
 *
945
 * Results:
946
 *      None.
947
 *
948
 * Side effects:
949
 *      Frees objPtr's bytecode internal representation and sets
950
 *      its type and objPtr->internalRep.otherValuePtr NULL. Also
951
 *      decrements the ref counts on each object in its object array,
952
 *      and frees its auxiliary data items.
953
 *
954
 *----------------------------------------------------------------------
955
 */
956
 
957
void
958
TclCleanupByteCode(codePtr)
959
    ByteCode *codePtr;          /* ByteCode to free. */
960
{
961
    Tcl_Obj **objArrayPtr = codePtr->objArrayPtr;
962
    int numObjects = codePtr->numObjects;
963
    int numAuxDataItems = codePtr->numAuxDataItems;
964
    register AuxData *auxDataPtr;
965
    register Tcl_Obj *elemPtr;
966
    register int i;
967
 
968
#ifdef TCL_COMPILE_STATS    
969
    tclCurrentSourceBytes -= (double) codePtr->numSrcChars;
970
    tclCurrentCodeBytes -= (double) codePtr->totalSize;
971
#endif /* TCL_COMPILE_STATS */
972
 
973
    /*
974
     * A single heap object holds the ByteCode structure and its code,
975
     * object, command location, and auxiliary data arrays. This means we
976
     * only need to 1) decrement the ref counts on the objects in its
977
     * object array, 2) call the free procs for the auxiliary data items,
978
     * and 3) free the ByteCode structure's heap object.
979
     */
980
 
981
    for (i = 0;  i < numObjects;  i++) {
982
        elemPtr = objArrayPtr[i];
983
        TclDecrRefCount(elemPtr);
984
    }
985
 
986
    auxDataPtr = codePtr->auxDataArrayPtr;
987
    for (i = 0;  i < numAuxDataItems;  i++) {
988
        if (auxDataPtr->type->freeProc != NULL) {
989
            auxDataPtr->type->freeProc(auxDataPtr->clientData);
990
        }
991
        auxDataPtr++;
992
    }
993
 
994
    ckfree((char *) codePtr);
995
}
996
 
997
/*
998
 *----------------------------------------------------------------------
999
 *
1000
 * DupByteCodeInternalRep --
1001
 *
1002
 *      Part of the bytecode Tcl object type implementation. However, it
1003
 *      does not copy the internal representation of a bytecode Tcl_Obj, but
1004
 *      instead leaves the new object untyped (with a NULL type pointer).
1005
 *      Code will be compiled for the new object only if necessary.
1006
 *
1007
 * Results:
1008
 *      None.
1009
 *
1010
 * Side effects:
1011
 *      None.
1012
 *
1013
 *----------------------------------------------------------------------
1014
 */
1015
 
1016
static void
1017
DupByteCodeInternalRep(srcPtr, copyPtr)
1018
    Tcl_Obj *srcPtr;            /* Object with internal rep to copy. */
1019
    Tcl_Obj *copyPtr;           /* Object with internal rep to set. */
1020
{
1021
    return;
1022
}
1023
 
1024
/*
1025
 *-----------------------------------------------------------------------
1026
 *
1027
 * SetByteCodeFromAny --
1028
 *
1029
 *      Part of the bytecode Tcl object type implementation. Attempts to
1030
 *      generate an byte code internal form for the Tcl object "objPtr" by
1031
 *      compiling its string representation.
1032
 *
1033
 * Results:
1034
 *      The return value is a standard Tcl object result. If an error occurs
1035
 *      during compilation, an error message is left in the interpreter's
1036
 *      result unless "interp" is NULL.
1037
 *
1038
 * Side effects:
1039
 *      Frees the old internal representation. If no error occurs, then the
1040
 *      compiled code is stored as "objPtr"s bytecode representation.
1041
 *      Also, if debugging, initializes the "tcl_traceCompile" Tcl variable
1042
 *      used to trace compilations.
1043
 *
1044
 *----------------------------------------------------------------------
1045
 */
1046
 
1047
static int
1048
SetByteCodeFromAny(interp, objPtr)
1049
    Tcl_Interp *interp;         /* The interpreter for which the code is
1050
                                 * compiled. */
1051
    Tcl_Obj *objPtr;            /* The object to convert. */
1052
{
1053
    Interp *iPtr = (Interp *) interp;
1054
    char *string;
1055
    CompileEnv compEnv;         /* Compilation environment structure
1056
                                 * allocated in frame. */
1057
    AuxData *auxDataPtr;
1058
    register int i;
1059
    int length, result;
1060
 
1061
    if (!traceInitialized) {
1062
        if (Tcl_LinkVar(interp, "tcl_traceCompile",
1063
                    (char *) &tclTraceCompile,  TCL_LINK_INT) != TCL_OK) {
1064
            panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");
1065
        }
1066
        traceInitialized = 1;
1067
    }
1068
 
1069
    string = Tcl_GetStringFromObj(objPtr, &length);
1070
    TclInitCompileEnv(interp, &compEnv, string);
1071
    result = TclCompileString(interp, string, string+length,
1072
            iPtr->evalFlags, &compEnv);
1073
    if (result == TCL_OK) {
1074
        /*
1075
         * Add a "done" instruction at the end of the instruction sequence.
1076
         */
1077
 
1078
        TclEmitOpcode(INST_DONE, &compEnv);
1079
 
1080
        /*
1081
         * Convert the object to a ByteCode object.
1082
         */
1083
 
1084
        TclInitByteCodeObj(objPtr, &compEnv);
1085
    } else {
1086
        /*
1087
         * Compilation errors. Decrement the ref counts on any objects in
1088
         * the object array and free any aux data items prior to freeing
1089
         * the compilation environment.
1090
         */
1091
 
1092
        for (i = 0;  i < compEnv.objArrayNext;  i++) {
1093
            Tcl_Obj *elemPtr = compEnv.objArrayPtr[i];
1094
            Tcl_DecrRefCount(elemPtr);
1095
        }
1096
 
1097
        auxDataPtr = compEnv.auxDataArrayPtr;
1098
        for (i = 0;  i < compEnv.auxDataArrayNext;  i++) {
1099
            if (auxDataPtr->type->freeProc != NULL) {
1100
            auxDataPtr->type->freeProc(auxDataPtr->clientData);
1101
            }
1102
            auxDataPtr++;
1103
        }
1104
    }
1105
    TclFreeCompileEnv(&compEnv);
1106
 
1107
    if (result == TCL_OK) {
1108
        if (tclTraceCompile == 2) {
1109
            TclPrintByteCodeObj(interp, objPtr);
1110
        }
1111
    }
1112
    return result;
1113
}
1114
 
1115
/*
1116
 *----------------------------------------------------------------------
1117
 *
1118
 * UpdateStringOfByteCode --
1119
 *
1120
 *      Part of the bytecode Tcl object type implementation. Called to
1121
 *      update the string representation for a byte code object.
1122
 *      Note: This procedure does not free an existing old string rep
1123
 *      so storage will be lost if this has not already been done.
1124
 *
1125
 * Results:
1126
 *      None.
1127
 *
1128
 * Side effects:
1129
 *      Generates a panic.
1130
 *
1131
 *----------------------------------------------------------------------
1132
 */
1133
 
1134
static void
1135
UpdateStringOfByteCode(objPtr)
1136
    register Tcl_Obj *objPtr;   /* ByteCode object with string rep that
1137
                                 * needs updating. */
1138
{
1139
    /*
1140
     * This procedure is never invoked since the internal representation of
1141
     * a bytecode object is never modified.
1142
     */
1143
 
1144
    panic("UpdateStringOfByteCode should never be called.");
1145
}
1146
 
1147
/*
1148
 *----------------------------------------------------------------------
1149
 *
1150
 * TclInitCompileEnv --
1151
 *
1152
 *      Initializes a CompileEnv compilation environment structure for the
1153
 *      compilation of a string in an interpreter.
1154
 *
1155
 * Results:
1156
 *      None.
1157
 *
1158
 * Side effects:
1159
 *      The CompileEnv structure is initialized.
1160
 *
1161
 *----------------------------------------------------------------------
1162
 */
1163
 
1164
void
1165
TclInitCompileEnv(interp, envPtr, string)
1166
    Tcl_Interp *interp;          /* The interpreter for which a CompileEnv
1167
                                  * structure is initialized. */
1168
    register CompileEnv *envPtr; /* Points to the CompileEnv structure to
1169
                                  * initialize. */
1170
    char *string;                /* The source string to be compiled. */
1171
{
1172
    Interp *iPtr = (Interp *) interp;
1173
 
1174
    envPtr->iPtr = iPtr;
1175
    envPtr->source = string;
1176
    envPtr->procPtr = iPtr->compiledProcPtr;
1177
    envPtr->numCommands = 0;
1178
    envPtr->excRangeDepth = 0;
1179
    envPtr->maxExcRangeDepth = 0;
1180
    envPtr->maxStackDepth = 0;
1181
    Tcl_InitHashTable(&(envPtr->objTable), TCL_STRING_KEYS);
1182
    envPtr->pushSimpleWords = 1;
1183
    envPtr->wordIsSimple = 0;
1184
    envPtr->numSimpleWordChars = 0;
1185
    envPtr->exprIsJustVarRef = 0;
1186
    envPtr->exprIsComparison = 0;
1187
    envPtr->termOffset = 0;
1188
 
1189
    envPtr->codeStart = envPtr->staticCodeSpace;
1190
    envPtr->codeNext = envPtr->codeStart;
1191
    envPtr->codeEnd = (envPtr->codeStart + COMPILEENV_INIT_CODE_BYTES);
1192
    envPtr->mallocedCodeArray = 0;
1193
 
1194
    envPtr->objArrayPtr = envPtr->staticObjArraySpace;
1195
    envPtr->objArrayNext = 0;
1196
    envPtr->objArrayEnd = COMPILEENV_INIT_NUM_OBJECTS;
1197
    envPtr->mallocedObjArray = 0;
1198
 
1199
    envPtr->excRangeArrayPtr = envPtr->staticExcRangeArraySpace;
1200
    envPtr->excRangeArrayNext = 0;
1201
    envPtr->excRangeArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES;
1202
    envPtr->mallocedExcRangeArray = 0;
1203
 
1204
    envPtr->cmdMapPtr = envPtr->staticCmdMapSpace;
1205
    envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE;
1206
    envPtr->mallocedCmdMap = 0;
1207
 
1208
    envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace;
1209
    envPtr->auxDataArrayNext = 0;
1210
    envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE;
1211
    envPtr->mallocedAuxDataArray = 0;
1212
}
1213
 
1214
/*
1215
 *----------------------------------------------------------------------
1216
 *
1217
 * TclFreeCompileEnv --
1218
 *
1219
 *      Free the storage allocated in a CompileEnv compilation environment
1220
 *      structure.
1221
 *
1222
 * Results:
1223
 *      None.
1224
 *
1225
 * Side effects:
1226
 *      Allocated storage in the CompileEnv structure is freed. Note that
1227
 *      ref counts for Tcl objects in its object table are not decremented.
1228
 *      In addition, any storage referenced by any auxiliary data items
1229
 *      in the CompileEnv structure are not freed either. The expectation
1230
 *      is that when compilation is successful, "ownership" (i.e., the
1231
 *      pointers to) these objects and aux data items will just be handed
1232
 *      over to the corresponding ByteCode structure.
1233
 *
1234
 *----------------------------------------------------------------------
1235
 */
1236
 
1237
void
1238
TclFreeCompileEnv(envPtr)
1239
    register CompileEnv *envPtr; /* Points to the CompileEnv structure. */
1240
{
1241
    Tcl_DeleteHashTable(&(envPtr->objTable));
1242
    if (envPtr->mallocedCodeArray) {
1243
        ckfree((char *) envPtr->codeStart);
1244
    }
1245
    if (envPtr->mallocedObjArray) {
1246
        ckfree((char *) envPtr->objArrayPtr);
1247
    }
1248
    if (envPtr->mallocedExcRangeArray) {
1249
        ckfree((char *) envPtr->excRangeArrayPtr);
1250
    }
1251
    if (envPtr->mallocedCmdMap) {
1252
        ckfree((char *) envPtr->cmdMapPtr);
1253
    }
1254
    if (envPtr->mallocedAuxDataArray) {
1255
        ckfree((char *) envPtr->auxDataArrayPtr);
1256
    }
1257
}
1258
 
1259
/*
1260
 *----------------------------------------------------------------------
1261
 *
1262
 * TclInitByteCodeObj --
1263
 *
1264
 *      Create a ByteCode structure and initialize it from a CompileEnv
1265
 *      compilation environment structure. The ByteCode structure is
1266
 *      smaller and contains just that information needed to execute
1267
 *      the bytecode instructions resulting from compiling a Tcl script.
1268
 *      The resulting structure is placed in the specified object.
1269
 *
1270
 * Results:
1271
 *      A newly constructed ByteCode object is stored in the internal
1272
 *      representation of the objPtr.
1273
 *
1274
 * Side effects:
1275
 *      A single heap object is allocated to hold the new ByteCode structure
1276
 *      and its code, object, command location, and aux data arrays. Note
1277
 *      that "ownership" (i.e., the pointers to) the Tcl objects and aux
1278
 *      data items will be handed over to the new ByteCode structure from
1279
 *      the CompileEnv structure.
1280
 *
1281
 *----------------------------------------------------------------------
1282
 */
1283
 
1284
void
1285
TclInitByteCodeObj(objPtr, envPtr)
1286
    Tcl_Obj *objPtr;             /* Points object that should be
1287
                                  * initialized, and whose string rep
1288
                                  * contains the source code. */
1289
    register CompileEnv *envPtr; /* Points to the CompileEnv structure from
1290
                                  * which to create a ByteCode structure. */
1291
{
1292
    register ByteCode *codePtr;
1293
    size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes;
1294
    size_t auxDataArrayBytes;
1295
    register size_t size, objBytes, totalSize;
1296
    register unsigned char *p;
1297
    unsigned char *nextPtr;
1298
    int srcLen = envPtr->termOffset;
1299
    int numObjects, i;
1300
    Namespace *namespacePtr;
1301
#ifdef TCL_COMPILE_STATS
1302
    int srcLenLog2, sizeLog2;
1303
#endif /*TCL_COMPILE_STATS*/
1304
 
1305
    codeBytes = (envPtr->codeNext - envPtr->codeStart);
1306
    numObjects = envPtr->objArrayNext;
1307
    objArrayBytes = (envPtr->objArrayNext * sizeof(Tcl_Obj *));
1308
    exceptArrayBytes = (envPtr->excRangeArrayNext * sizeof(ExceptionRange));
1309
    auxDataArrayBytes = (envPtr->auxDataArrayNext * sizeof(AuxData));
1310
    cmdLocBytes = GetCmdLocEncodingSize(envPtr);
1311
 
1312
    size = sizeof(ByteCode);
1313
    size += TCL_ALIGN(codeBytes);       /* align object array */
1314
    size += TCL_ALIGN(objArrayBytes);   /* align exception range array */
1315
    size += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */
1316
    size += auxDataArrayBytes;
1317
    size += cmdLocBytes;
1318
 
1319
    /*
1320
     * Compute the total number of bytes needed for this bytecode
1321
     * including the storage for the Tcl objects in its object array.
1322
     */
1323
 
1324
    objBytes = (numObjects * sizeof(Tcl_Obj));
1325
    for (i = 0;  i < numObjects;  i++) {
1326
        Tcl_Obj *litObjPtr = envPtr->objArrayPtr[i];
1327
        if (litObjPtr->bytes != NULL) {
1328
            objBytes += litObjPtr->length;
1329
        }
1330
    }
1331
    totalSize = (size + objBytes);
1332
 
1333
#ifdef TCL_COMPILE_STATS
1334
    tclNumCompilations++;
1335
    tclTotalSourceBytes += (double) srcLen;
1336
    tclTotalCodeBytes += (double) totalSize;
1337
 
1338
    tclTotalInstBytes += (double) codeBytes;
1339
    tclTotalObjBytes += (double) objBytes;
1340
    tclTotalExceptBytes += exceptArrayBytes;
1341
    tclTotalAuxBytes += (double) auxDataArrayBytes;
1342
    tclTotalCmdMapBytes += (double) cmdLocBytes;
1343
 
1344
    tclCurrentSourceBytes += (double) srcLen;
1345
    tclCurrentCodeBytes += (double) totalSize;
1346
 
1347
    srcLenLog2 = TclLog2(srcLen);
1348
    sizeLog2 = TclLog2((int) totalSize);
1349
    if ((srcLenLog2 > 31) || (sizeLog2 > 31)) {
1350
        panic("TclInitByteCodeObj: bad source or code sizes\n");
1351
    }
1352
    tclSourceCount[srcLenLog2]++;
1353
    tclByteCodeCount[sizeLog2]++;
1354
#endif /* TCL_COMPILE_STATS */    
1355
 
1356
    if (envPtr->iPtr->varFramePtr != NULL) {
1357
        namespacePtr = envPtr->iPtr->varFramePtr->nsPtr;
1358
    } else {
1359
        namespacePtr = envPtr->iPtr->globalNsPtr;
1360
    }
1361
 
1362
    p = (unsigned char *) ckalloc(size);
1363
    codePtr = (ByteCode *) p;
1364
    codePtr->iPtr = envPtr->iPtr;
1365
    codePtr->compileEpoch = envPtr->iPtr->compileEpoch;
1366
    codePtr->nsPtr = namespacePtr;
1367
    codePtr->nsEpoch = namespacePtr->resolverEpoch;
1368
    codePtr->refCount = 1;
1369
    codePtr->flags = 0;
1370
    codePtr->source = envPtr->source;
1371
    codePtr->procPtr = envPtr->procPtr;
1372
    codePtr->totalSize = totalSize;
1373
    codePtr->numCommands = envPtr->numCommands;
1374
    codePtr->numSrcChars = srcLen;
1375
    codePtr->numCodeBytes = codeBytes;
1376
    codePtr->numObjects = numObjects;
1377
    codePtr->numExcRanges = envPtr->excRangeArrayNext;
1378
    codePtr->numAuxDataItems = envPtr->auxDataArrayNext;
1379
    codePtr->auxDataArrayPtr = NULL;
1380
    codePtr->numCmdLocBytes = cmdLocBytes;
1381
    codePtr->maxExcRangeDepth = envPtr->maxExcRangeDepth;
1382
    codePtr->maxStackDepth = envPtr->maxStackDepth;
1383
 
1384
    p += sizeof(ByteCode);
1385
    codePtr->codeStart = p;
1386
    memcpy((VOID *) p, (VOID *) envPtr->codeStart, codeBytes);
1387
 
1388
    p += TCL_ALIGN(codeBytes);        /* align object array */
1389
    codePtr->objArrayPtr = (Tcl_Obj **) p;
1390
    memcpy((VOID *) p, (VOID *) envPtr->objArrayPtr, objArrayBytes);
1391
 
1392
    p += TCL_ALIGN(objArrayBytes);    /* align exception range array */
1393
    if (exceptArrayBytes > 0) {
1394
        codePtr->excRangeArrayPtr = (ExceptionRange *) p;
1395
        memcpy((VOID *) p, (VOID *) envPtr->excRangeArrayPtr,
1396
                exceptArrayBytes);
1397
    }
1398
 
1399
    p += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */
1400
    if (auxDataArrayBytes > 0) {
1401
        codePtr->auxDataArrayPtr = (AuxData *) p;
1402
        memcpy((VOID *) p, (VOID *) envPtr->auxDataArrayPtr,
1403
                auxDataArrayBytes);
1404
    }
1405
 
1406
    p += auxDataArrayBytes;
1407
    nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
1408
    if (((size_t)(nextPtr - p)) != cmdLocBytes) {
1409
        panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d\n", (nextPtr - p), cmdLocBytes);
1410
    }
1411
 
1412
    /*
1413
     * Free the old internal rep then convert the object to a
1414
     * bytecode object by making its internal rep point to the just
1415
     * compiled ByteCode.
1416
     */
1417
 
1418
    if ((objPtr->typePtr != NULL) &&
1419
            (objPtr->typePtr->freeIntRepProc != NULL)) {
1420
        objPtr->typePtr->freeIntRepProc(objPtr);
1421
    }
1422
    objPtr->internalRep.otherValuePtr = (VOID *) codePtr;
1423
    objPtr->typePtr = &tclByteCodeType;
1424
}
1425
 
1426
/*
1427
 *----------------------------------------------------------------------
1428
 *
1429
 * GetCmdLocEncodingSize --
1430
 *
1431
 *      Computes the total number of bytes needed to encode the command
1432
 *      location information for some compiled code.
1433
 *
1434
 * Results:
1435
 *      The byte count needed to encode the compiled location information.
1436
 *
1437
 * Side effects:
1438
 *      None.
1439
 *
1440
 *----------------------------------------------------------------------
1441
 */
1442
 
1443
static int
1444
GetCmdLocEncodingSize(envPtr)
1445
     CompileEnv *envPtr;        /* Points to compilation environment
1446
                                 * structure containing the CmdLocation
1447
                                 * structure to encode. */
1448
{
1449
    register CmdLocation *mapPtr = envPtr->cmdMapPtr;
1450
    int numCmds = envPtr->numCommands;
1451
    int codeDelta, codeLen, srcDelta, srcLen;
1452
    int codeDeltaNext, codeLengthNext, srcDeltaNext, srcLengthNext;
1453
                                /* The offsets in their respective byte
1454
                                 * sequences where the next encoded offset
1455
                                 * or length should go. */
1456
    int prevCodeOffset, prevSrcOffset, i;
1457
 
1458
    codeDeltaNext = codeLengthNext = srcDeltaNext = srcLengthNext = 0;
1459
    prevCodeOffset = prevSrcOffset = 0;
1460
    for (i = 0;  i < numCmds;  i++) {
1461
        codeDelta = (mapPtr[i].codeOffset - prevCodeOffset);
1462
        if (codeDelta < 0) {
1463
            panic("GetCmdLocEncodingSize: bad code offset");
1464
        } else if (codeDelta <= 127) {
1465
            codeDeltaNext++;
1466
        } else {
1467
            codeDeltaNext += 5;  /* 1 byte for 0xFF, 4 for positive delta */
1468
        }
1469
        prevCodeOffset = mapPtr[i].codeOffset;
1470
 
1471
        codeLen = mapPtr[i].numCodeBytes;
1472
        if (codeLen < 0) {
1473
            panic("GetCmdLocEncodingSize: bad code length");
1474
        } else if (codeLen <= 127) {
1475
            codeLengthNext++;
1476
        } else {
1477
            codeLengthNext += 5; /* 1 byte for 0xFF, 4 for length */
1478
        }
1479
 
1480
        srcDelta = (mapPtr[i].srcOffset - prevSrcOffset);
1481
        if ((-127 <= srcDelta) && (srcDelta <= 127)) {
1482
            srcDeltaNext++;
1483
        } else {
1484
            srcDeltaNext += 5;   /* 1 byte for 0xFF, 4 for delta */
1485
        }
1486
        prevSrcOffset = mapPtr[i].srcOffset;
1487
 
1488
        srcLen = mapPtr[i].numSrcChars;
1489
        if (srcLen < 0) {
1490
            panic("GetCmdLocEncodingSize: bad source length");
1491
        } else if (srcLen <= 127) {
1492
            srcLengthNext++;
1493
        } else {
1494
            srcLengthNext += 5;  /* 1 byte for 0xFF, 4 for length */
1495
        }
1496
    }
1497
 
1498
    return (codeDeltaNext + codeLengthNext + srcDeltaNext + srcLengthNext);
1499
}
1500
 
1501
/*
1502
 *----------------------------------------------------------------------
1503
 *
1504
 * EncodeCmdLocMap --
1505
 *
1506
 *      Encode the command location information for some compiled code into
1507
 *      a ByteCode structure. The encoded command location map is stored as
1508
 *      three adjacent byte sequences.
1509
 *
1510
 * Results:
1511
 *      Pointer to the first byte after the encoded command location
1512
 *      information.
1513
 *
1514
 * Side effects:
1515
 *      The encoded information is stored into the block of memory headed
1516
 *      by codePtr. Also records pointers to the start of the four byte
1517
 *      sequences in fields in codePtr's ByteCode header structure.
1518
 *
1519
 *----------------------------------------------------------------------
1520
 */
1521
 
1522
static unsigned char *
1523
EncodeCmdLocMap(envPtr, codePtr, startPtr)
1524
     CompileEnv *envPtr;        /* Points to compilation environment
1525
                                 * structure containing the CmdLocation
1526
                                 * structure to encode. */
1527
     ByteCode *codePtr;         /* ByteCode in which to encode envPtr's
1528
                                 * command location information. */
1529
     unsigned char *startPtr;   /* Points to the first byte in codePtr's
1530
                                 * memory block where the location
1531
                                 * information is to be stored. */
1532
{
1533
    register CmdLocation *mapPtr = envPtr->cmdMapPtr;
1534
    int numCmds = envPtr->numCommands;
1535
    register unsigned char *p = startPtr;
1536
    int codeDelta, codeLen, srcDelta, srcLen, prevOffset;
1537
    register int i;
1538
 
1539
    /*
1540
     * Encode the code offset for each command as a sequence of deltas.
1541
     */
1542
 
1543
    codePtr->codeDeltaStart = p;
1544
    prevOffset = 0;
1545
    for (i = 0;  i < numCmds;  i++) {
1546
        codeDelta = (mapPtr[i].codeOffset - prevOffset);
1547
        if (codeDelta < 0) {
1548
            panic("EncodeCmdLocMap: bad code offset");
1549
        } else if (codeDelta <= 127) {
1550
            TclStoreInt1AtPtr(codeDelta, p);
1551
            p++;
1552
        } else {
1553
            TclStoreInt1AtPtr(0xFF, p);
1554
            p++;
1555
            TclStoreInt4AtPtr(codeDelta, p);
1556
            p += 4;
1557
        }
1558
        prevOffset = mapPtr[i].codeOffset;
1559
    }
1560
 
1561
    /*
1562
     * Encode the code length for each command.
1563
     */
1564
 
1565
    codePtr->codeLengthStart = p;
1566
    for (i = 0;  i < numCmds;  i++) {
1567
        codeLen = mapPtr[i].numCodeBytes;
1568
        if (codeLen < 0) {
1569
            panic("EncodeCmdLocMap: bad code length");
1570
        } else if (codeLen <= 127) {
1571
            TclStoreInt1AtPtr(codeLen, p);
1572
            p++;
1573
        } else {
1574
            TclStoreInt1AtPtr(0xFF, p);
1575
            p++;
1576
            TclStoreInt4AtPtr(codeLen, p);
1577
            p += 4;
1578
        }
1579
    }
1580
 
1581
    /*
1582
     * Encode the source offset for each command as a sequence of deltas.
1583
     */
1584
 
1585
    codePtr->srcDeltaStart = p;
1586
    prevOffset = 0;
1587
    for (i = 0;  i < numCmds;  i++) {
1588
        srcDelta = (mapPtr[i].srcOffset - prevOffset);
1589
        if ((-127 <= srcDelta) && (srcDelta <= 127)) {
1590
            TclStoreInt1AtPtr(srcDelta, p);
1591
            p++;
1592
        } else {
1593
            TclStoreInt1AtPtr(0xFF, p);
1594
            p++;
1595
            TclStoreInt4AtPtr(srcDelta, p);
1596
            p += 4;
1597
        }
1598
        prevOffset = mapPtr[i].srcOffset;
1599
    }
1600
 
1601
    /*
1602
     * Encode the source length for each command.
1603
     */
1604
 
1605
    codePtr->srcLengthStart = p;
1606
    for (i = 0;  i < numCmds;  i++) {
1607
        srcLen = mapPtr[i].numSrcChars;
1608
        if (srcLen < 0) {
1609
            panic("EncodeCmdLocMap: bad source length");
1610
        } else if (srcLen <= 127) {
1611
            TclStoreInt1AtPtr(srcLen, p);
1612
            p++;
1613
        } else {
1614
            TclStoreInt1AtPtr(0xFF, p);
1615
            p++;
1616
            TclStoreInt4AtPtr(srcLen, p);
1617
            p += 4;
1618
        }
1619
    }
1620
 
1621
    return p;
1622
}
1623
 
1624
/*
1625
 *----------------------------------------------------------------------
1626
 *
1627
 * TclCompileString --
1628
 *
1629
 *      Compile a Tcl script in a null-terminated binary string.
1630
 *
1631
 * Results:
1632
 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1633
 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1634
 *      contains an error message.
1635
 *
1636
 *      envPtr->termOffset and interp->termOffset are filled in with the
1637
 *      offset of the character in the string just after the last one
1638
 *      successfully processed; this might be the offset of the ']' (if
1639
 *      flags & TCL_BRACKET_TERM), or the offset of the '\0' at the end of
1640
 *      the string. Also updates envPtr->maxStackDepth with the maximum
1641
 *      number of stack elements needed to execute the string's commands.
1642
 *
1643
 * Side effects:
1644
 *      Adds instructions to envPtr to evaluate the string at runtime.
1645
 *
1646
 *----------------------------------------------------------------------
1647
 */
1648
 
1649
int
1650
TclCompileString(interp, string, lastChar, flags, envPtr)
1651
    Tcl_Interp *interp;         /* Used for error reporting. */
1652
    char *string;               /* The source string to compile. */
1653
    char *lastChar;             /* Pointer to terminating character of
1654
                                 * string. */
1655
    int flags;                  /* Flags to control compilation (same as
1656
                                 * passed to Tcl_Eval). */
1657
    CompileEnv *envPtr;         /* Holds resulting instructions. */
1658
{
1659
    Interp *iPtr = (Interp *) interp;
1660
    register char *src = string;/* Points to current source char. */
1661
    register char c = *src;     /* The current char. */
1662
    register int type;          /* Current char's CHAR_TYPE type. */
1663
    char termChar = (char)((flags & TCL_BRACKET_TERM)? ']' : '\0');
1664
                                /* Return when this character is found
1665
                                 * (either ']' or '\0'). Zero means newlines
1666
                                 * terminate cmds. */
1667
    int isFirstCmd = 1;         /* 1 if compiling the first cmd. */
1668
    char *cmdSrcStart = NULL;   /* Points to first non-blank char in each
1669
                                 * command. Initialized to avoid compiler
1670
                                 * warning. */
1671
    int cmdIndex;               /* The index of the current command in the
1672
                                 * compilation environment's command
1673
                                 * location table. */
1674
    int lastTopLevelCmdIndex = -1;
1675
                                /* Index of most recent toplevel command in
1676
                                 * the command location table. Initialized
1677
                                 * to avoid compiler warning. */
1678
    int cmdCodeOffset = -1;     /* Offset of first byte of current command's
1679
                                 * code. Initialized to avoid compiler
1680
                                 * warning. */
1681
    int cmdWords;               /* Number of words in current command. */
1682
    Tcl_Command cmd;            /* Used to search for commands. */
1683
    Command *cmdPtr;            /* Points to command's Command structure if
1684
                                 * first word is simple and command was
1685
                                 * found; else NULL. */
1686
    int maxDepth = 0;            /* Maximum number of stack elements needed
1687
                                 * to execute all cmds. */
1688
    char *termPtr;              /* Points to char that terminated word. */
1689
    char savedChar;             /* Holds the character from string
1690
                                 * termporarily replaced by a null character
1691
                                 * during processing of words. */
1692
    int objIndex = -1;          /* The object array index for a pushed
1693
                                 * object holding a word or word part
1694
                                 * Initialized to avoid compiler warning. */
1695
    unsigned char *entryCodeNext = envPtr->codeNext;
1696
                                /* Value of envPtr's current instruction
1697
                                 * pointer at entry. Used to tell if any
1698
                                 * instructions generated. */
1699
    char *ellipsis = "";        /* Used to set errorInfo variable; "..."
1700
                                 * indicates that not all of offending
1701
                                 * command is included in errorInfo. ""
1702
                                 * means that the command is all there. */
1703
    Tcl_Obj *objPtr;
1704
    int numChars;
1705
    int result = TCL_OK;
1706
    int savePushSimpleWords = envPtr->pushSimpleWords;
1707
 
1708
    /*
1709
     * commands: command {(';' | '\n') command}
1710
     */
1711
 
1712
    while ((src != lastChar) && (c != termChar)) {
1713
        /*
1714
         * Skip white space, semicolons, backslash-newlines (treated as
1715
         * spaces), and comments before command.
1716
         */
1717
 
1718
        type = CHAR_TYPE(src, lastChar);
1719
        while ((type & (TCL_SPACE | TCL_BACKSLASH))
1720
                || (c == '\n') || (c == ';')) {
1721
            if (type == TCL_BACKSLASH) {
1722
                if (src[1] == '\n') {
1723
                    src += 2;
1724
                } else {
1725
                    break;
1726
                }
1727
            } else {
1728
                src++;
1729
            }
1730
            c = *src;
1731
            type = CHAR_TYPE(src, lastChar);
1732
        }
1733
 
1734
        if (c == '#') {
1735
            while (src != lastChar) {
1736
                if (c == '\\') {
1737
                    int numRead;
1738
                    Tcl_Backslash(src, &numRead);
1739
                    src += numRead;
1740
                } else if (c == '\n') {
1741
                    src++;
1742
                    c = *src;
1743
                    envPtr->termOffset = (src - string);
1744
                    break;
1745
                } else {
1746
                    src++;
1747
                }
1748
                c = *src;
1749
            }
1750
            continue;   /* end of comment, restart outer command loop */
1751
        }
1752
 
1753
        /*
1754
         * Compile one command: zero or more words terminated by a '\n',
1755
         * ';', ']' (if command is terminated by close bracket), or
1756
         * the end of string.
1757
         *
1758
         * command: word*
1759
         */
1760
 
1761
        type = CHAR_TYPE(src, lastChar);
1762
        if ((type == TCL_COMMAND_END)
1763
                && ((c != ']') || (flags & TCL_BRACKET_TERM))) {
1764
            continue;  /* empty command; restart outer cmd loop */
1765
        }
1766
 
1767
        /*
1768
         * If not the first command, discard the previous command's result.
1769
         */
1770
 
1771
        if (!isFirstCmd) {
1772
            TclEmitOpcode(INST_POP, envPtr);
1773
            if (!(flags & TCL_BRACKET_TERM)) {
1774
                /*
1775
                 * We are compiling a top level command. Update the number
1776
                 * of code bytes for the last command to account for the pop
1777
                 * instruction.
1778
                 */
1779
 
1780
                (envPtr->cmdMapPtr[lastTopLevelCmdIndex]).numCodeBytes =
1781
                    (envPtr->codeNext-envPtr->codeStart) - cmdCodeOffset;
1782
            }
1783
        }
1784
 
1785
        /*
1786
         * Compile the words of the command. Process the first word
1787
         * specially, since it is the name of a command. If it is a "simple"
1788
         * string (just a sequence of characters), look it up in the table
1789
         * of compilation procedures. If a word other than the first is
1790
         * simple and represents an integer whose formatted representation
1791
         * is the same as the word, just push an integer object. Also record
1792
         * starting source and object information for the command.
1793
         */
1794
 
1795
        envPtr->numCommands++;
1796
        cmdIndex = (envPtr->numCommands - 1);
1797
        if (!(flags & TCL_BRACKET_TERM)) {
1798
            lastTopLevelCmdIndex = cmdIndex;
1799
        }
1800
 
1801
        cmdSrcStart = src;
1802
        cmdCodeOffset = (envPtr->codeNext - envPtr->codeStart);
1803
        cmdWords = 0;
1804
        EnterCmdStartData(envPtr, cmdIndex, src-envPtr->source,
1805
                cmdCodeOffset);
1806
 
1807
        if ((!(flags & TCL_BRACKET_TERM))
1808
                && (tclTraceCompile >= 1) && (envPtr->procPtr == NULL)) {
1809
            /*
1810
             * Display a line summarizing the top level command we are about
1811
             * to compile.
1812
             */
1813
 
1814
            char *p = cmdSrcStart;
1815
            int numChars, complete;
1816
 
1817
            while ((CHAR_TYPE(p, lastChar) != TCL_COMMAND_END)
1818
                   || ((*p == ']') && !(flags & TCL_BRACKET_TERM))) {
1819
                p++;
1820
            }
1821
            numChars = (p - cmdSrcStart);
1822
            complete = 1;
1823
            if (numChars > 60) {
1824
                numChars = 60;
1825
                complete = 0;
1826
            } else if ((numChars >= 2) && (*p == '\n') && (*(p-1) == '{')) {
1827
                complete = 0;
1828
            }
1829
            fprintf(stdout, "Compiling: %.*s%s\n",
1830
                    numChars, cmdSrcStart, (complete? "" : " ..."));
1831
        }
1832
 
1833
        while ((type != TCL_COMMAND_END)
1834
                || ((c == ']') && !(flags & TCL_BRACKET_TERM))) {
1835
            /*
1836
             * Skip any leading white space at the start of a word. Note
1837
             * that a backslash-newline is treated as a space.
1838
             */
1839
 
1840
            while (type & (TCL_SPACE | TCL_BACKSLASH)) {
1841
                if (type == TCL_BACKSLASH) {
1842
                    if (src[1] == '\n') {
1843
                        src += 2;
1844
                    } else {
1845
                        break;
1846
                    }
1847
                } else {
1848
                    src++;
1849
                }
1850
                c = *src;
1851
                type = CHAR_TYPE(src, lastChar);
1852
            }
1853
            if ((type == TCL_COMMAND_END)
1854
                    && ((c != ']') || (flags & TCL_BRACKET_TERM))) {
1855
                break;          /* no words remain for command. */
1856
            }
1857
 
1858
            /*
1859
             * Compile one word. We use an inline version of CompileWord to
1860
             * avoid an extra procedure call.
1861
             */
1862
 
1863
            envPtr->pushSimpleWords = 0;
1864
            if (type & (TCL_QUOTE | TCL_OPEN_BRACE)) {
1865
                src++;
1866
                if (type == TCL_QUOTE) {
1867
                    result = TclCompileQuotes(interp, src, lastChar,
1868
                            '"', flags, envPtr);
1869
                } else {
1870
                    result = CompileBraces(interp, src, lastChar,
1871
                            flags, envPtr);
1872
                }
1873
                termPtr = (src + envPtr->termOffset);
1874
                if (result != TCL_OK) {
1875
                    src = termPtr;
1876
                    goto done;
1877
                }
1878
 
1879
                /*
1880
                 * Make sure terminating character of the quoted or braced
1881
                 * string is the end of word.
1882
                 */
1883
 
1884
                c = *termPtr;
1885
                if ((c == '\\') && (*(termPtr+1) == '\n')) {
1886
                    /*
1887
                     * Line is continued on next line; the backslash-
1888
                     * newline turns into space, which terminates the word.
1889
                     */
1890
                } else {
1891
                    type = CHAR_TYPE(termPtr, lastChar);
1892
                    if ((type != TCL_SPACE) && (type != TCL_COMMAND_END)) {
1893
                        Tcl_ResetResult(interp);
1894
                        if (*(src-1) == '"') {
1895
                            Tcl_AppendToObj(Tcl_GetObjResult(interp),
1896
                                    "extra characters after close-quote", -1);
1897
                        } else {
1898
                            Tcl_AppendToObj(Tcl_GetObjResult(interp),
1899
                                    "extra characters after close-brace", -1);
1900
                        }
1901
                        result = TCL_ERROR;
1902
                    }
1903
                }
1904
            } else {
1905
                result = CompileMultipartWord(interp, src, lastChar,
1906
                        flags, envPtr);
1907
                termPtr = (src + envPtr->termOffset);
1908
            }
1909
            if (result != TCL_OK) {
1910
                ellipsis = "...";
1911
                src = termPtr;
1912
                goto done;
1913
            }
1914
 
1915
            if (envPtr->wordIsSimple) {
1916
                /*
1917
                 * A simple word. Temporarily replace the terminating
1918
                 * character with a null character.
1919
                 */
1920
 
1921
                numChars = envPtr->numSimpleWordChars;
1922
                savedChar = src[numChars];
1923
                src[numChars] = '\0';
1924
 
1925
                if ((cmdWords == 0)
1926
                        && (!(iPtr->flags & DONT_COMPILE_CMDS_INLINE))) {
1927
                    /*
1928
                     * The first word of a command and inline command
1929
                     * compilation has not been disabled (e.g., by command
1930
                     * traces). Look up the first word in the interpreter's
1931
                     * hashtable of commands. If a compilation procedure is
1932
                     * found, let it compile the command after resetting
1933
                     * error logging information. Note that if we are
1934
                     * compiling a procedure, we must look up the command
1935
                     * in the procedure's namespace and not the current
1936
                     * namespace.
1937
                     */
1938
 
1939
                    Namespace *cmdNsPtr;
1940
 
1941
                    if (envPtr->procPtr != NULL) {
1942
                        cmdNsPtr = envPtr->procPtr->cmdPtr->nsPtr;
1943
                    } else {
1944
                        cmdNsPtr = NULL;
1945
                    }
1946
 
1947
                    cmdPtr = NULL;
1948
                    cmd = Tcl_FindCommand(interp, src,
1949
                            (Tcl_Namespace *) cmdNsPtr, /*flags*/ 0);
1950
                    if (cmd != (Tcl_Command) NULL) {
1951
                        cmdPtr = (Command *) cmd;
1952
                    }
1953
                    if ((cmdPtr != NULL) && (cmdPtr->compileProc != NULL)) {
1954
                        char *firstArg = termPtr;
1955
                        src[numChars] = savedChar;
1956
                        iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS
1957
                                         | ERROR_CODE_SET);
1958
                        result = (*(cmdPtr->compileProc))(interp,
1959
                                firstArg, lastChar, flags, envPtr);
1960
                        if (result == TCL_OK) {
1961
                            src = (firstArg + envPtr->termOffset);
1962
                            maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
1963
                            goto finishCommand;
1964
                        } else if (result == TCL_OUT_LINE_COMPILE) {
1965
                            result = TCL_OK;
1966
                            src[numChars] = '\0';
1967
                        } else {
1968
                            src = firstArg;
1969
                            goto done;           /* an error */
1970
                        }
1971
                    }
1972
 
1973
                    /*
1974
                     * No compile procedure was found for the command: push
1975
                     * the word and continue to compile the remaining
1976
                     * words. If a hashtable entry was found for the
1977
                     * command, push a CmdName object instead to avoid
1978
                     * runtime lookups. If necessary, convert the pushed
1979
                     * object to be a CmdName object. If this is the first
1980
                     * CmdName object in this code unit that refers to the
1981
                     * command, increment the reference count in the
1982
                     * Command structure to reflect the new reference from
1983
                     * the CmdName object and, if the command is deleted
1984
                     * later, to keep the Command structure from being freed
1985
                     * until TclExecuteByteCode has a chance to recognize
1986
                     * that the command was deleted.
1987
                     */
1988
 
1989
                    objIndex = TclObjIndexForString(src, numChars,
1990
                            /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
1991
                    if (cmdPtr != NULL) {
1992
                        objPtr = envPtr->objArrayPtr[objIndex];
1993
                        if ((objPtr->typePtr != &tclCmdNameType)
1994
                                && (objPtr->bytes != NULL)) {
1995
                            ResolvedCmdName *resPtr = (ResolvedCmdName *)
1996
                                    ckalloc(sizeof(ResolvedCmdName));
1997
                            Namespace *nsPtr = (Namespace *)
1998
                                    Tcl_GetCurrentNamespace(interp);
1999
 
2000
                            resPtr->cmdPtr = cmdPtr;
2001
                            resPtr->refNsPtr = nsPtr;
2002
                            resPtr->refNsId = nsPtr->nsId;
2003
                            resPtr->refNsCmdEpoch = nsPtr->cmdRefEpoch;
2004
                            resPtr->cmdEpoch = cmdPtr->cmdEpoch;
2005
                            resPtr->refCount = 1;
2006
                            objPtr->internalRep.twoPtrValue.ptr1 =
2007
                                (VOID *) resPtr;
2008
                            objPtr->internalRep.twoPtrValue.ptr2 = NULL;
2009
                            objPtr->typePtr = &tclCmdNameType;
2010
                            cmdPtr->refCount++;
2011
                        }
2012
                    }
2013
                } else {
2014
                    /*
2015
                     * See if the word represents an integer whose formatted
2016
                     * representation is the same as the word (e.g., this is
2017
                     * true for 123 and -1 but not for 00005). If so, just
2018
                     * push an integer object.
2019
                     */
2020
 
2021
                    int isCompilableInt = 0;
2022
                    long n;
2023
                    char buf[40];
2024
 
2025
                    if (TclLooksLikeInt(src)) {
2026
                        int code = TclGetLong(interp, src, &n);
2027
                        if (code == TCL_OK) {
2028
                            TclFormatInt(buf, n);
2029
                            if (strcmp(src, buf) == 0) {
2030
                                isCompilableInt = 1;
2031
                                objIndex = TclObjIndexForString(src,
2032
                                        numChars, /*allocStrRep*/ 0,
2033
                                        /*inHeap*/ 0, envPtr);
2034
                                objPtr = envPtr->objArrayPtr[objIndex];
2035
 
2036
                                Tcl_InvalidateStringRep(objPtr);
2037
                                objPtr->internalRep.longValue = n;
2038
                                objPtr->typePtr = &tclIntType;
2039
                            }
2040
                        } else {
2041
                            Tcl_ResetResult(interp);
2042
                        }
2043
                    }
2044
                    if (!isCompilableInt) {
2045
                        objIndex = TclObjIndexForString(src, numChars,
2046
                                /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
2047
                    }
2048
                }
2049
                src[numChars] = savedChar;
2050
                TclEmitPush(objIndex, envPtr);
2051
                maxDepth = TclMax((cmdWords + 1), maxDepth);
2052
            } else {            /* not a simple word */
2053
                maxDepth = TclMax((cmdWords + envPtr->maxStackDepth),
2054
                               maxDepth);
2055
            }
2056
            src = termPtr;
2057
            c = *src;
2058
            type = CHAR_TYPE(src, lastChar);
2059
            cmdWords++;
2060
        }
2061
 
2062
        /*
2063
         * Emit an invoke instruction for the command. If a compile command
2064
         * was found for the command we called it and skipped this.
2065
         */
2066
 
2067
        if (cmdWords > 0) {
2068
            if (cmdWords <= 255) {
2069
                TclEmitInstUInt1(INST_INVOKE_STK1, cmdWords, envPtr);
2070
            } else {
2071
                TclEmitInstUInt4(INST_INVOKE_STK4, cmdWords, envPtr);
2072
            }
2073
        }
2074
 
2075
        /*
2076
         * Update the compilation environment structure. Record
2077
         * source/object information for the command.
2078
         */
2079
 
2080
        finishCommand:
2081
        EnterCmdExtentData(envPtr, cmdIndex, src-cmdSrcStart,
2082
                (envPtr->codeNext-envPtr->codeStart) - cmdCodeOffset);
2083
 
2084
        isFirstCmd = 0;
2085
        envPtr->termOffset = (src - string);
2086
        c = *src;
2087
    }
2088
 
2089
    done:
2090
    if (result == TCL_OK) {
2091
        /*
2092
         * If the source string yielded no instructions (e.g., if it was
2093
         * empty), push an empty string object as the command's result.
2094
         */
2095
 
2096
        if (entryCodeNext == envPtr->codeNext) {
2097
            int objIndex = TclObjIndexForString("", 0, /*allocStrRep*/ 0,
2098
                                                /*inHeap*/ 0, envPtr);
2099
            TclEmitPush(objIndex, envPtr);
2100
            maxDepth = 1;
2101
        }
2102
    } else {
2103
        /*
2104
         * Add additional error information. First compute the line number
2105
         * where the error occurred.
2106
         */
2107
 
2108
        register char *p;
2109
        int numChars;
2110
        char buf[200];
2111
 
2112
        iPtr->errorLine = 1;
2113
        for (p = string;  p != cmdSrcStart;  p++) {
2114
            if (*p == '\n') {
2115
                iPtr->errorLine++;
2116
            }
2117
        }
2118
        for (  ; isspace(UCHAR(*p)) || (*p == ';');  p++) {
2119
            if (*p == '\n') {
2120
                iPtr->errorLine++;
2121
            }
2122
        }
2123
 
2124
        /*
2125
         * Figure out how much of the command to print (up to a certain
2126
         * number of characters, or up to the end of the command).
2127
         */
2128
 
2129
        p = cmdSrcStart;
2130
        while ((CHAR_TYPE(p, lastChar) != TCL_COMMAND_END)
2131
                || ((*p == ']') && !(flags & TCL_BRACKET_TERM))) {
2132
            p++;
2133
        }
2134
        numChars = (p - cmdSrcStart);
2135
        if (numChars > 150) {
2136
            numChars = 150;
2137
            ellipsis = " ...";
2138
        } else if ((numChars >= 2) && (*p == '\n') && (*(p-1) == '{')) {
2139
            ellipsis = " ...";
2140
        }
2141
 
2142
        sprintf(buf, "\n    while compiling\n\"%.*s%s\"",
2143
                numChars, cmdSrcStart, ellipsis);
2144
        Tcl_AddObjErrorInfo(interp, buf, -1);
2145
    }
2146
 
2147
    envPtr->termOffset = (src - string);
2148
    iPtr->termOffset = envPtr->termOffset;
2149
    envPtr->maxStackDepth = maxDepth;
2150
    envPtr->pushSimpleWords = savePushSimpleWords;
2151
    return result;
2152
}
2153
 
2154
/*
2155
 *----------------------------------------------------------------------
2156
 *
2157
 * CompileWord --
2158
 *
2159
 *      This procedure compiles one word from a command string. It skips
2160
 *      any leading white space.
2161
 *
2162
 *      Ordinarily, callers set envPtr->pushSimpleWords to 1 and this
2163
 *      procedure emits push and other instructions to compute the
2164
 *      word on the Tcl evaluation stack at execution time. If a caller sets
2165
 *      envPtr->pushSimpleWords to 0, CompileWord will _not_ compile
2166
 *      "simple" words: words that are just a sequence of characters without
2167
 *      backslashes. It will leave their compilation up to the caller.
2168
 *
2169
 *      As an important special case, if the word is simple, this procedure
2170
 *      sets envPtr->wordIsSimple to 1 and envPtr->numSimpleWordChars to the
2171
 *      number of characters in the simple word. This allows the caller to
2172
 *      process these words specially.
2173
 *
2174
 * Results:
2175
 *      The return value is a standard Tcl result. If an error occurs, an
2176
 *      error message is left in the interpreter's result.
2177
 *
2178
 *      envPtr->termOffset is filled in with the offset of the character in
2179
 *      "string" just after the last one successfully processed in the last
2180
 *      word. This is normally the character just after the last one in a
2181
 *      word (perhaps the command terminator), or the vicinity of an error
2182
 *      (if the result is not TCL_OK).
2183
 *
2184
 *      envPtr->wordIsSimple is set 1 if the word is simple: just a
2185
 *      sequence of characters without backslashes. If so, the word's
2186
 *      characters are the envPtr->numSimpleWordChars characters starting
2187
 *      at string.
2188
 *
2189
 *      envPtr->maxStackDepth is updated with the maximum number of stack
2190
 *      elements needed to evaluate the word. This is not changed if
2191
 *      the word is simple and envPtr->pushSimpleWords was 0 (false).
2192
 *
2193
 * Side effects:
2194
 *      Instructions are added to envPtr to compute and push the word
2195
 *      at runtime.
2196
 *
2197
 *----------------------------------------------------------------------
2198
 */
2199
 
2200
static int
2201
CompileWord(interp, string, lastChar, flags, envPtr)
2202
    Tcl_Interp *interp;         /* Interpreter to use for nested command
2203
                                 * evaluations and error messages. */
2204
    char *string;               /* First character of word. */
2205
    char *lastChar;              /* Pointer to terminating character of
2206
                                  * string. */
2207
    int flags;                  /* Flags to control compilation (same values
2208
                                 * passed to Tcl_EvalObj). */
2209
    CompileEnv *envPtr;         /* Holds the resulting instructions. */
2210
{
2211
    /*
2212
     * Compile one word: approximately
2213
     *
2214
     * word:             quoted_string | braced_string | multipart_word
2215
     * quoted_string:    '"' char* '"'
2216
     * braced_string:    '{' char* '}'
2217
     * multipart_word    (see CompileMultipartWord below)
2218
     */
2219
 
2220
    register char *src = string; /* Points to current source char. */
2221
    register int type = CHAR_TYPE(src, lastChar);
2222
                                 /* Current char's CHAR_TYPE type. */
2223
    int maxDepth = 0;             /* Maximum number of stack elements needed
2224
                                  * to compute and push the word. */
2225
    char *termPtr = src;         /* Points to the character that terminated
2226
                                  * the word. */
2227
    int result = TCL_OK;
2228
 
2229
    /*
2230
     * Skip any leading white space at the start of a word. Note that a
2231
     * backslash-newline is treated as a space.
2232
     */
2233
 
2234
    while (type & (TCL_SPACE | TCL_BACKSLASH)) {
2235
        if (type == TCL_BACKSLASH) {
2236
            if (src[1] == '\n') {
2237
                src += 2;
2238
            } else {
2239
                break;          /* no longer white space */
2240
            }
2241
        } else {
2242
            src++;
2243
        }
2244
        type = CHAR_TYPE(src, lastChar);
2245
    }
2246
    if (type == TCL_COMMAND_END) {
2247
        goto done;
2248
    }
2249
 
2250
    /*
2251
     * Compile the word. Handle quoted and braced string words here in order
2252
     * to avoid an extra procedure call.
2253
     */
2254
 
2255
    if (type & (TCL_QUOTE | TCL_OPEN_BRACE)) {
2256
        src++;
2257
        if (type == TCL_QUOTE) {
2258
            result = TclCompileQuotes(interp, src, lastChar, '"', flags,
2259
                    envPtr);
2260
        } else {
2261
            result = CompileBraces(interp, src, lastChar, flags, envPtr);
2262
        }
2263
        termPtr = (src + envPtr->termOffset);
2264
        if (result != TCL_OK) {
2265
            goto done;
2266
        }
2267
 
2268
        /*
2269
         * Make sure terminating character of the quoted or braced string is
2270
         * the end of word.
2271
         */
2272
 
2273
        if ((*termPtr == '\\') && (*(termPtr+1) == '\n')) {
2274
            /*
2275
             * Line is continued on next line; the backslash-newline turns
2276
             * into space, which terminates the word.
2277
             */
2278
        } else {
2279
            type = CHAR_TYPE(termPtr, lastChar);
2280
            if (!(type & (TCL_SPACE | TCL_COMMAND_END))) {
2281
                Tcl_ResetResult(interp);
2282
                if (*(src-1) == '"') {
2283
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
2284
                            "extra characters after close-quote", -1);
2285
                } else {
2286
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
2287
                            "extra characters after close-brace", -1);
2288
                }
2289
                result = TCL_ERROR;
2290
                goto done;
2291
            }
2292
        }
2293
        maxDepth = envPtr->maxStackDepth;
2294
    } else {
2295
        result = CompileMultipartWord(interp, src, lastChar, flags, envPtr);
2296
        termPtr = (src + envPtr->termOffset);
2297
        maxDepth = envPtr->maxStackDepth;
2298
    }
2299
 
2300
    /*
2301
     * Done processing the word. The values of envPtr->wordIsSimple and
2302
     * envPtr->numSimpleWordChars are left at the values returned by
2303
     * TclCompileQuotes/Braces/MultipartWord.
2304
     */
2305
 
2306
    done:
2307
    envPtr->termOffset = (termPtr - string);
2308
    envPtr->maxStackDepth = maxDepth;
2309
    return result;
2310
}
2311
 
2312
/*
2313
 *----------------------------------------------------------------------
2314
 *
2315
 * CompileMultipartWord --
2316
 *
2317
 *      This procedure compiles one multipart word: a word comprised of some
2318
 *      number of nested commands, variable references, or arbitrary
2319
 *      characters. This procedure assumes that quoted string and braced
2320
 *      string words and the end of command have already been handled by its
2321
 *      caller. It also assumes that any leading white space has already
2322
 *      been consumed.
2323
 *
2324
 *      Ordinarily, callers set envPtr->pushSimpleWords to 1 and this
2325
 *      procedure emits push and other instructions to compute the word on
2326
 *      the Tcl evaluation stack at execution time. If a caller sets
2327
 *      envPtr->pushSimpleWords to 0, it will _not_ compile "simple" words:
2328
 *      words that are just a sequence of characters without backslashes.
2329
 *      It will leave their compilation up to the caller. This is done, for
2330
 *      example, to provide special support for the first word of commands,
2331
 *      which are almost always the (simple) name of a command.
2332
 *
2333
 *      As an important special case, if the word is simple, this procedure
2334
 *      sets envPtr->wordIsSimple to 1 and envPtr->numSimpleWordChars to the
2335
 *      number of characters in the simple word. This allows the caller to
2336
 *      process these words specially.
2337
 *
2338
 * Results:
2339
 *      The return value is a standard Tcl result. If an error occurs, an
2340
 *      error message is left in the interpreter's result.
2341
 *
2342
 *      envPtr->termOffset is filled in with the offset of the character in
2343
 *      "string" just after the last one successfully processed in the last
2344
 *      word. This is normally the character just after the last one in a
2345
 *      word (perhaps the command terminator), or the vicinity of an error
2346
 *      (if the result is not TCL_OK).
2347
 *
2348
 *      envPtr->wordIsSimple is set 1 if the word is simple: just a
2349
 *      sequence of characters without backslashes. If so, the word's
2350
 *      characters are the envPtr->numSimpleWordChars characters starting
2351
 *      at string.
2352
 *
2353
 *      envPtr->maxStackDepth is updated with the maximum number of stack
2354
 *      elements needed to evaluate the word. This is not changed if
2355
 *      the word is simple and envPtr->pushSimpleWords was 0 (false).
2356
 *
2357
 * Side effects:
2358
 *      Instructions are added to envPtr to compute and push the word
2359
 *      at runtime.
2360
 *
2361
 *----------------------------------------------------------------------
2362
 */
2363
 
2364
static int
2365
CompileMultipartWord(interp, string, lastChar, flags, envPtr)
2366
    Tcl_Interp *interp;         /* Interpreter to use for nested command
2367
                                 * evaluations and error messages. */
2368
    char *string;               /* First character of word. */
2369
    char *lastChar;              /* Pointer to terminating character of
2370
                                  * string. */
2371
    int flags;                  /* Flags to control compilation (same values
2372
                                 * passed to Tcl_EvalObj). */
2373
    CompileEnv *envPtr;         /* Holds the resulting instructions. */
2374
{
2375
    /*
2376
     * Compile one multi_part word:
2377
     *
2378
     * multi_part_word:  word_part+
2379
     * word_part:        nested_cmd | var_reference | char+
2380
     * nested_cmd:       '[' command ']'
2381
     * var_reference:    '$' name | '$' name '(' index_string ')' |
2382
     *                   '$' '{' braced_name '}')
2383
     * name:             (letter | digit | underscore)+
2384
     * braced_name:      (non_close_brace_char)*
2385
     * index_string:     (non_close_paren_char)*
2386
     */
2387
 
2388
    register char *src = string; /* Points to current source char. */
2389
    register char c = *src;     /* The current char. */
2390
    register int type;          /* Current char's CHAR_TYPE type. */
2391
    int bracketNormal = !(flags & TCL_BRACKET_TERM);
2392
    int simpleWord = 0;          /* Set 1 if word is simple. */
2393
    int numParts = 0;            /* Count of word_part objs pushed. */
2394
    int maxDepth = 0;            /* Maximum number of stack elements needed
2395
                                 * to compute and push the word. */
2396
    char *start;                /* Starting position of char+ word_part. */
2397
    int hasBackslash;           /* Nonzero if '\' in char+ word_part. */
2398
    int numChars;               /* Number of chars in char+ word_part. */
2399
    char savedChar;             /* Holds the character from string
2400
                                 * termporarily replaced by a null character
2401
                                 * during word_part processing. */
2402
    int objIndex;               /* The object array index for a pushed
2403
                                 * object holding a word_part. */
2404
    int savePushSimpleWords = envPtr->pushSimpleWords;
2405
    int result = TCL_OK;
2406
    int numRead;
2407
 
2408
    type = CHAR_TYPE(src, lastChar);
2409
    while (1) {
2410
        /*
2411
         * Process a word_part: a sequence of chars, a var reference, or
2412
         * a nested command.
2413
         */
2414
 
2415
        if ((type & (TCL_NORMAL | TCL_CLOSE_BRACE | TCL_BACKSLASH |
2416
                     TCL_QUOTE | TCL_OPEN_BRACE)) ||
2417
            ((c == ']') && bracketNormal)) {
2418
            /*
2419
             * A char+ word part. Scan first looking for any backslashes.
2420
             * Note that a backslash-newline must be treated as a word
2421
             * separator, as if the backslash-newline had been collapsed
2422
             * before command parsing began.
2423
             */
2424
 
2425
            start = src;
2426
            hasBackslash = 0;
2427
            do {
2428
                if (type == TCL_BACKSLASH) {
2429
                    hasBackslash = 1;
2430
                    Tcl_Backslash(src, &numRead);
2431
                    if (src[1] == '\n') {
2432
                        src += numRead;
2433
                        type = TCL_SPACE; /* force word end */
2434
                        break;
2435
                    }
2436
                    src += numRead;
2437
                } else {
2438
                    src++;
2439
                }
2440
                c = *src;
2441
                type = CHAR_TYPE(src, lastChar);
2442
            } while (type & (TCL_NORMAL | TCL_BACKSLASH | TCL_QUOTE |
2443
                            TCL_OPEN_BRACE | TCL_CLOSE_BRACE)
2444
                            || ((c == ']') && bracketNormal));
2445
 
2446
            if ((numParts == 0) && !hasBackslash
2447
                    && (type & (TCL_SPACE | TCL_COMMAND_END))) {
2448
                /*
2449
                 * The word is "simple": just a sequence of characters
2450
                 * without backslashes terminated by a TCL_SPACE or
2451
                 * TCL_COMMAND_END. Just return if we are not to compile
2452
                 * simple words.
2453
                 */
2454
 
2455
                simpleWord = 1;
2456
                if (!envPtr->pushSimpleWords) {
2457
                    envPtr->wordIsSimple = 1;
2458
                    envPtr->numSimpleWordChars = (src - string);
2459
                    envPtr->termOffset = envPtr->numSimpleWordChars;
2460
                    envPtr->pushSimpleWords = savePushSimpleWords;
2461
                    return TCL_OK;
2462
                }
2463
            }
2464
 
2465
            /*
2466
             * Create and push a string object for the char+ word_part,
2467
             * which starts at "start" and ends at the char just before
2468
             * src. If backslashes were found, copy the word_part's
2469
             * characters with substituted backslashes into a heap-allocated
2470
             * buffer and use it to create the string object. Temporarily
2471
             * replace the terminating character with a null character.
2472
             */
2473
 
2474
            numChars = (src - start);
2475
            savedChar = start[numChars];
2476
            start[numChars] = '\0';
2477
            if ((numChars > 0) && (hasBackslash)) {
2478
                char *buffer = ckalloc((unsigned) numChars + 1);
2479
                register char *dst = buffer;
2480
                register char *p = start;
2481
                while (p < src) {
2482
                    if (*p == '\\') {
2483
                        *dst = Tcl_Backslash(p, &numRead);
2484
                        if (p[1] == '\n') {
2485
                            break;
2486
                        }
2487
                        p += numRead;
2488
                        dst++;
2489
                    } else {
2490
                        *dst++ = *p++;
2491
                    }
2492
                }
2493
                *dst = '\0';
2494
                objIndex = TclObjIndexForString(buffer, dst-buffer,
2495
                        /*allocStrRep*/ 1, /*inHeap*/ 1, envPtr);
2496
            } else {
2497
                objIndex = TclObjIndexForString(start, numChars,
2498
                        /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
2499
            }
2500
            start[numChars] = savedChar;
2501
            TclEmitPush(objIndex, envPtr);
2502
            maxDepth = TclMax((numParts + 1), maxDepth);
2503
        } else if (type == TCL_DOLLAR) {
2504
            result = TclCompileDollarVar(interp, src, lastChar,
2505
                    flags, envPtr);
2506
            src += envPtr->termOffset;
2507
            if (result != TCL_OK) {
2508
                goto done;
2509
            }
2510
            maxDepth = TclMax((numParts + envPtr->maxStackDepth), maxDepth);
2511
            c = *src;
2512
            type = CHAR_TYPE(src, lastChar);
2513
        } else if (type == TCL_OPEN_BRACKET) {
2514
            char *termPtr;
2515
            envPtr->pushSimpleWords = 1;
2516
            src++;
2517
            result = TclCompileString(interp, src, lastChar,
2518
                                      (flags | TCL_BRACKET_TERM), envPtr);
2519
            termPtr = (src + envPtr->termOffset);
2520
            if (*termPtr == ']') {
2521
                termPtr++;
2522
            } else if (*termPtr == '\0') {
2523
                /*
2524
                 * Missing ] at end of nested command.
2525
                 */
2526
 
2527
                Tcl_ResetResult(interp);
2528
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
2529
                        "missing close-bracket", -1);
2530
                result = TCL_ERROR;
2531
            }
2532
            src = termPtr;
2533
            if (result != TCL_OK) {
2534
                goto done;
2535
            }
2536
            maxDepth = TclMax((numParts + envPtr->maxStackDepth), maxDepth);
2537
            c = *src;
2538
            type = CHAR_TYPE(src, lastChar);
2539
        } else if (type & (TCL_SPACE | TCL_COMMAND_END)) {
2540
            goto wordEnd;
2541
        }
2542
        numParts++;
2543
    } /* end of infinite loop */
2544
 
2545
    wordEnd:
2546
    /*
2547
     * End of a non-simple word: TCL_SPACE, TCL_COMMAND_END, or
2548
     * backslash-newline. Concatenate the word_parts if necessary.
2549
     */
2550
 
2551
    while (numParts > 255) {
2552
        TclEmitInstUInt1(INST_CONCAT1, 255, envPtr);
2553
        numParts -= 254;  /* concat pushes 1 obj, the result */
2554
    }
2555
    if (numParts > 1) {
2556
        TclEmitInstUInt1(INST_CONCAT1, numParts, envPtr);
2557
    }
2558
 
2559
    done:
2560
    if (simpleWord) {
2561
        envPtr->wordIsSimple = 1;
2562
        envPtr->numSimpleWordChars = (src - string);
2563
    } else {
2564
        envPtr->wordIsSimple = 0;
2565
        envPtr->numSimpleWordChars = 0;
2566
    }
2567
    envPtr->termOffset = (src - string);
2568
    envPtr->maxStackDepth = maxDepth;
2569
    envPtr->pushSimpleWords = savePushSimpleWords;
2570
    return result;
2571
}
2572
 
2573
/*
2574
 *----------------------------------------------------------------------
2575
 *
2576
 * TclCompileQuotes --
2577
 *
2578
 *      This procedure compiles a double-quoted string such as a quoted Tcl
2579
 *      command argument or a quoted value in a Tcl expression. This
2580
 *      procedure is also used to compile array element names within
2581
 *      parentheses (where the termChar will be ')' instead of '"'), or
2582
 *      anything else that needs the substitutions that happen in quotes.
2583
 *
2584
 *      Ordinarily, callers set envPtr->pushSimpleWords to 1 and
2585
 *      TclCompileQuotes always emits push and other instructions to compute
2586
 *      the word on the Tcl evaluation stack at execution time. If a caller
2587
 *      sets envPtr->pushSimpleWords to 0, TclCompileQuotes will not compile
2588
 *      "simple" words: words that are just a sequence of characters without
2589
 *      backslashes. It will leave their compilation up to the caller. This
2590
 *      is done to provide special support for the first word of commands,
2591
 *      which are almost always the (simple) name of a command.
2592
 *
2593
 *      As an important special case, if the word is simple, this procedure
2594
 *      sets envPtr->wordIsSimple to 1 and envPtr->numSimpleWordChars to the
2595
 *      number of characters in the simple word. This allows the caller to
2596
 *      process these words specially.
2597
 *
2598
 * Results:
2599
 *      The return value is a standard Tcl result, which is TCL_OK unless
2600
 *      there was an error while parsing the quoted string. If an error
2601
 *      occurs then the interpreter's result contains a standard error
2602
 *      message.
2603
 *
2604
 *      envPtr->termOffset is filled in with the offset of the character in
2605
 *      "string" just after the last one successfully processed; this is
2606
 *      usually the character just after the matching close-quote.
2607
 *
2608
 *      envPtr->wordIsSimple is set 1 if the word is simple: just a
2609
 *      sequence of characters without backslashes. If so, the word's
2610
 *      characters are the envPtr->numSimpleWordChars characters starting
2611
 *      at string.
2612
 *
2613
 *      envPtr->maxStackDepth is updated with the maximum number of stack
2614
 *      elements needed to evaluate the word. This is not changed if
2615
 *      the word is simple and envPtr->pushSimpleWords was 0 (false).
2616
 *
2617
 * Side effects:
2618
 *      Instructions are added to envPtr to push the quoted-string
2619
 *      at runtime.
2620
 *
2621
 *----------------------------------------------------------------------
2622
 */
2623
 
2624
int
2625
TclCompileQuotes(interp, string, lastChar, termChar, flags, envPtr)
2626
    Tcl_Interp *interp;          /* Interpreter to use for nested command
2627
                                  * evaluations and error messages. */
2628
    char *string;                /* Points to the character just after
2629
                                  * the opening '"' or '('. */
2630
    char *lastChar;              /* Pointer to terminating character of
2631
                                  * string. */
2632
    int termChar;                /* Character that terminates the "quoted"
2633
                                  * string (usually double-quote, but might
2634
                                  * be right-paren or something else). */
2635
    int flags;                   /* Flags to control compilation (same
2636
                                  * values passed to Tcl_Eval). */
2637
    CompileEnv *envPtr;          /* Holds the resulting instructions. */
2638
{
2639
    register char *src = string; /* Points to current source char. */
2640
    register char c = *src;      /* The current char. */
2641
    int simpleWord = 0;           /* Set 1 if a simple quoted string word. */
2642
    char *start;                 /* Start position of char+ string_part. */
2643
    int hasBackslash;            /* 1 if '\' found in char+ string_part. */
2644
    int numRead;                 /* Count of chars read by Tcl_Backslash. */
2645
    int numParts = 0;             /* Count of string_part objs pushed. */
2646
    int maxDepth = 0;             /* Maximum number of stack elements needed
2647
                                  * to compute and push the string. */
2648
    char savedChar;              /* Holds the character from string
2649
                                  * termporarily replaced by a null
2650
                                  * char during string_part processing. */
2651
    int objIndex;                /* The object array index for a pushed
2652
                                  * object holding a string_part. */
2653
    int numChars;                /* Number of chars in string_part. */
2654
    int savePushSimpleWords = envPtr->pushSimpleWords;
2655
    int result = TCL_OK;
2656
 
2657
    /*
2658
     * quoted_string: '"' string_part* '"'   (or termChar instead of ")
2659
     * string_part:   var_reference | nested_cmd | char+
2660
     */
2661
 
2662
 
2663
    while ((src != lastChar) && (c != termChar)) {
2664
        if (c == '$') {
2665
            result = TclCompileDollarVar(interp, src, lastChar, flags,
2666
                    envPtr);
2667
            src += envPtr->termOffset;
2668
            if (result != TCL_OK) {
2669
                goto done;
2670
            }
2671
            maxDepth = TclMax((numParts + envPtr->maxStackDepth), maxDepth);
2672
            c = *src;
2673
        } else if (c == '[') {
2674
            char *termPtr;
2675
            envPtr->pushSimpleWords = 1;
2676
            src++;
2677
            result = TclCompileString(interp, src, lastChar,
2678
                                      (flags | TCL_BRACKET_TERM), envPtr);
2679
            termPtr = (src + envPtr->termOffset);
2680
            if (*termPtr == ']') {
2681
                termPtr++;
2682
            }
2683
            src = termPtr;
2684
            if (result != TCL_OK) {
2685
                goto done;
2686
            }
2687
            if (termPtr == lastChar) {
2688
                /*
2689
                 * Missing ] at end of nested command.
2690
                 */
2691
 
2692
                Tcl_ResetResult(interp);
2693
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
2694
                        "missing close-bracket", -1);
2695
                result = TCL_ERROR;
2696
                goto done;
2697
            }
2698
            maxDepth = TclMax((numParts + envPtr->maxStackDepth), maxDepth);
2699
            c = *src;
2700
        } else {
2701
            /*
2702
             * Start of a char+ string_part. Scan first looking for any
2703
             * backslashes.
2704
             */
2705
 
2706
            start = src;
2707
            hasBackslash = 0;
2708
            do {
2709
                if (c == '\\') {
2710
                    hasBackslash = 1;
2711
                    Tcl_Backslash(src, &numRead);
2712
                    src += numRead;
2713
                } else {
2714
                    src++;
2715
                }
2716
                c = *src;
2717
            } while ((src != lastChar) && (c != '$') && (c != '[')
2718
                    && (c != termChar));
2719
 
2720
            if ((numParts == 0) && !hasBackslash
2721
                    && ((src == lastChar) && (c == termChar))) {
2722
                /*
2723
                 * The quoted string is "simple": just a sequence of
2724
                 * characters without backslashes terminated by termChar or
2725
                 * a null character. Just return if we are not to compile
2726
                 * simple words.
2727
                 */
2728
 
2729
                simpleWord = 1;
2730
                if (!envPtr->pushSimpleWords) {
2731
                    if ((src == lastChar) && (termChar != '\0')) {
2732
                        char buf[40];
2733
                        sprintf(buf, "missing %c", termChar);
2734
                        Tcl_ResetResult(interp);
2735
                        Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);
2736
                        result = TCL_ERROR;
2737
                    } else {
2738
                        src++;
2739
                    }
2740
                    envPtr->wordIsSimple = 1;
2741
                    envPtr->numSimpleWordChars = (src - string - 1);
2742
                    envPtr->termOffset = (src - string);
2743
                    envPtr->pushSimpleWords = savePushSimpleWords;
2744
                    return result;
2745
                }
2746
            }
2747
 
2748
            /*
2749
             * Create and push a string object for the char+ string_part
2750
             * that starts at "start" and ends at the char just before
2751
             * src. If backslashes were found, copy the string_part's
2752
             * characters with substituted backslashes into a heap-allocated
2753
             * buffer and use it to create the string object. Temporarily
2754
             * replace the terminating character with a null character.
2755
             */
2756
 
2757
            numChars = (src - start);
2758
            savedChar = start[numChars];
2759
            start[numChars] = '\0';
2760
            if ((numChars > 0) && (hasBackslash)) {
2761
                char *buffer = ckalloc((unsigned) numChars + 1);
2762
                register char *dst = buffer;
2763
                register char *p = start;
2764
                while (p < src) {
2765
                    if (*p == '\\') {
2766
                        *dst++ = Tcl_Backslash(p, &numRead);
2767
                        p += numRead;
2768
                    } else {
2769
                        *dst++ = *p++;
2770
                    }
2771
                }
2772
                *dst = '\0';
2773
                objIndex = TclObjIndexForString(buffer, (dst - buffer),
2774
                        /*allocStrRep*/ 1, /*inHeap*/ 1, envPtr);
2775
            } else {
2776
                objIndex = TclObjIndexForString(start, numChars,
2777
                        /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
2778
            }
2779
            start[numChars] = savedChar;
2780
            TclEmitPush(objIndex, envPtr);
2781
            maxDepth = TclMax((numParts + 1), maxDepth);
2782
        }
2783
        numParts++;
2784
    }
2785
 
2786
    /*
2787
     * End of the quoted string: src points at termChar or '\0'. If
2788
     * necessary, concatenate the string_part objects on the stack.
2789
     */
2790
 
2791
    if ((src == lastChar) && (termChar != '\0')) {
2792
        char buf[40];
2793
        sprintf(buf, "missing %c", termChar);
2794
        Tcl_ResetResult(interp);
2795
        Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);
2796
        result = TCL_ERROR;
2797
        goto done;
2798
    } else {
2799
        src++;
2800
    }
2801
 
2802
    if (numParts == 0) {
2803
        /*
2804
         * The quoted string was empty. Push an empty string object.
2805
         */
2806
 
2807
        int objIndex = TclObjIndexForString("", 0, /*allocStrRep*/ 0,
2808
                                            /*inHeap*/ 0, envPtr);
2809
        TclEmitPush(objIndex, envPtr);
2810
    } else {
2811
        /*
2812
         * Emit any needed concat instructions.
2813
         */
2814
 
2815
        while (numParts > 255) {
2816
            TclEmitInstUInt1(INST_CONCAT1, 255, envPtr);
2817
            numParts -= 254;  /* concat pushes 1 obj, the result */
2818
        }
2819
        if (numParts > 1) {
2820
            TclEmitInstUInt1(INST_CONCAT1, numParts, envPtr);
2821
        }
2822
    }
2823
 
2824
    done:
2825
    if (simpleWord) {
2826
        envPtr->wordIsSimple = 1;
2827
        envPtr->numSimpleWordChars = (src - string - 1);
2828
    } else {
2829
        envPtr->wordIsSimple = 0;
2830
        envPtr->numSimpleWordChars = 0;
2831
    }
2832
    envPtr->termOffset = (src - string);
2833
    envPtr->maxStackDepth = maxDepth;
2834
    envPtr->pushSimpleWords = savePushSimpleWords;
2835
    return result;
2836
}
2837
 
2838
/*
2839
 *--------------------------------------------------------------
2840
 *
2841
 * CompileBraces --
2842
 *
2843
 *      This procedure compiles characters between matching curly braces.
2844
 *
2845
 *      Ordinarily, callers set envPtr->pushSimpleWords to 1 and
2846
 *      CompileBraces always emits a push instruction to compute the word on
2847
 *      the Tcl evaluation stack at execution time. However, if a caller
2848
 *      sets envPtr->pushSimpleWords to 0, CompileBraces will _not_ compile
2849
 *      "simple" words: words that are just a sequence of characters without
2850
 *      backslash-newlines. It will leave their compilation up to the
2851
 *      caller.
2852
 *
2853
 *      As an important special case, if the word is simple, this procedure
2854
 *      sets envPtr->wordIsSimple to 1 and envPtr->numSimpleWordChars to the
2855
 *      number of characters in the simple word. This allows the caller to
2856
 *      process these words specially.
2857
 *
2858
 * Results:
2859
 *      The return value is a standard Tcl result, which is TCL_OK unless
2860
 *      there was an error while parsing string. If an error occurs then
2861
 *      the interpreter's result contains a standard error message.
2862
 *
2863
 *      envPtr->termOffset is filled in with the offset of the character in
2864
 *      "string" just after the last one successfully processed. This is
2865
 *      usually the character just after the matching close-brace.
2866
 *
2867
 *      envPtr->wordIsSimple is set 1 if the word is simple: just a
2868
 *      sequence of characters without backslash-newlines. If so, the word's
2869
 *      characters are the envPtr->numSimpleWordChars characters starting
2870
 *      at string.
2871
 *
2872
 *      envPtr->maxStackDepth is updated with the maximum number of stack
2873
 *      elements needed to evaluate the word. This is not changed if
2874
 *      the word is simple and envPtr->pushSimpleWords was 0 (false).
2875
 *
2876
 * Side effects:
2877
 *      Instructions are added to envPtr to push the braced string
2878
 *      at runtime.
2879
 *
2880
 *--------------------------------------------------------------
2881
 */
2882
 
2883
static int
2884
CompileBraces(interp, string, lastChar, flags, envPtr)
2885
    Tcl_Interp *interp;          /* Interpreter to use for nested command
2886
                                  * evaluations and error messages. */
2887
    char *string;                /* Character just after opening bracket. */
2888
    char *lastChar;              /* Pointer to terminating character of
2889
                                  * string. */
2890
    int flags;                   /* Flags to control compilation (same
2891
                                  * values passed to Tcl_Eval). */
2892
    CompileEnv *envPtr;          /* Holds the resulting instructions. */
2893
{
2894
    register char *src = string; /* Points to current source char. */
2895
    register char c;             /* The current char. */
2896
    int simpleWord = 0;           /* Set 1 if a simple braced string word. */
2897
    int level = 1;               /* {} nesting level. Initially 1 since {
2898
                                  * was parsed before we were called. */
2899
    int hasBackslashNewline = 0; /* Nonzero if '\' found. */
2900
    char *last;                  /* Points just before terminating '}'. */
2901
    int numChars;                /* Number of chars in braced string. */
2902
    char savedChar;              /* Holds the character from string
2903
                                  * termporarily replaced by a null
2904
                                  * char during braced string processing. */
2905
    int objIndex;                /* The object array index for a pushed
2906
                                  * object holding a braced string. */
2907
    int numRead;
2908
    int result = TCL_OK;
2909
 
2910
    /*
2911
     * Check for any backslash-newlines, since we must treat
2912
     * backslash-newlines specially (they must be replaced by spaces).
2913
     */
2914
 
2915
    while (1) {
2916
        c = *src;
2917
        if (src == lastChar) {
2918
            Tcl_ResetResult(interp);
2919
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
2920
                    "missing close-brace", -1);
2921
            result = TCL_ERROR;
2922
            goto done;
2923
        }
2924
        if (CHAR_TYPE(src, lastChar) != TCL_NORMAL) {
2925
            if (c == '{') {
2926
                level++;
2927
            } else if (c == '}') {
2928
                --level;
2929
                if (level == 0) {
2930
                    src++;
2931
                    last = (src - 2); /* point just before terminating } */
2932
                    break;
2933
                }
2934
            } else if (c == '\\') {
2935
                if (*(src+1) == '\n') {
2936
                    hasBackslashNewline = 1;
2937
                }
2938
                (void) Tcl_Backslash(src, &numRead);
2939
                src += numRead - 1;
2940
            }
2941
        }
2942
        src++;
2943
    }
2944
 
2945
    if (!hasBackslashNewline) {
2946
        /*
2947
         * The braced word is "simple": just a sequence of characters
2948
         * without backslash-newlines. Just return if we are not to compile
2949
         * simple words.
2950
         */
2951
 
2952
        simpleWord = 1;
2953
        if (!envPtr->pushSimpleWords) {
2954
            envPtr->wordIsSimple = 1;
2955
            envPtr->numSimpleWordChars = (src - string - 1);
2956
            envPtr->termOffset = (src - string);
2957
            return TCL_OK;
2958
        }
2959
    }
2960
 
2961
    /*
2962
     * Create and push a string object for the braced string. This starts at
2963
     * "string" and ends just after "last" (which points to the final
2964
     * character before the terminating '}'). If backslash-newlines were
2965
     * found, we copy characters one at a time into a heap-allocated buffer
2966
     * and do backslash-newline substitutions.
2967
     */
2968
 
2969
    numChars = (last - string + 1);
2970
    savedChar = string[numChars];
2971
    string[numChars] = '\0';
2972
    if ((numChars > 0) && (hasBackslashNewline)) {
2973
        char *buffer = ckalloc((unsigned) numChars + 1);
2974
        register char *dst = buffer;
2975
        register char *p = string;
2976
        while (p <= last) {
2977
            c = *dst++ = *p++;
2978
            if (c == '\\') {
2979
                if (*p == '\n') {
2980
                    dst[-1] = Tcl_Backslash(p-1, &numRead);
2981
                    p += numRead - 1;
2982
                } else {
2983
                    (void) Tcl_Backslash(p-1, &numRead);
2984
                    while (numRead > 1) {
2985
                        *dst++ = *p++;
2986
                        numRead--;
2987
                    }
2988
                }
2989
            }
2990
        }
2991
        *dst = '\0';
2992
        objIndex = TclObjIndexForString(buffer, (dst - buffer),
2993
                /*allocStrRep*/ 1, /*inHeap*/ 1, envPtr);
2994
    } else {
2995
        objIndex = TclObjIndexForString(string, numChars, /*allocStrRep*/ 1,
2996
                                        /*inHeap*/ 0, envPtr);
2997
    }
2998
    string[numChars] = savedChar;
2999
    TclEmitPush(objIndex, envPtr);
3000
 
3001
    done:
3002
    if (simpleWord) {
3003
        envPtr->wordIsSimple = 1;
3004
        envPtr->numSimpleWordChars = (src - string - 1);
3005
    } else {
3006
        envPtr->wordIsSimple = 0;
3007
        envPtr->numSimpleWordChars = 0;
3008
    }
3009
    envPtr->termOffset = (src - string);
3010
    envPtr->maxStackDepth = 1;
3011
    return result;
3012
}
3013
 
3014
/*
3015
 *----------------------------------------------------------------------
3016
 *
3017
 * TclCompileDollarVar --
3018
 *
3019
 *      Given a string starting with a $ sign, parse a variable name
3020
 *      and compile instructions to push its value. If the variable
3021
 *      reference is just a '$' (i.e. the '$' isn't followed by anything
3022
 *      that could possibly be a variable name), just push a string object
3023
 *      containing '$'.
3024
 *
3025
 * Results:
3026
 *      The return value is a standard Tcl result. If an error occurs
3027
 *      then an error message is left in the interpreter's result.
3028
 *
3029
 *      envPtr->termOffset is filled in with the offset of the character in
3030
 *      "string" just after the last one in the variable reference.
3031
 *
3032
 *      envPtr->wordIsSimple is set 0 (false) because the word is not
3033
 *      simple: it is not just a sequence of characters without backslashes.
3034
 *      For the same reason, envPtr->numSimpleWordChars is set 0.
3035
 *
3036
 *      envPtr->maxStackDepth is updated with the maximum number of stack
3037
 *      elements needed to execute the string's commands.
3038
 *
3039
 * Side effects:
3040
 *      Instructions are added to envPtr to look up the variable and
3041
 *      push its value at runtime.
3042
 *
3043
 *----------------------------------------------------------------------
3044
 */
3045
 
3046
int
3047
TclCompileDollarVar(interp, string, lastChar, flags, envPtr)
3048
    Tcl_Interp *interp;          /* Interpreter to use for nested command
3049
                                  * evaluations and error messages. */
3050
    char *string;                /* First char (i.e. $) of var reference. */
3051
    char *lastChar;              /* Pointer to terminating character of
3052
                                  * string. */
3053
    int flags;                   /* Flags to control compilation (same
3054
                                  * values passed to Tcl_Eval). */
3055
    CompileEnv *envPtr;          /* Holds the resulting instructions. */
3056
{
3057
    register char *src = string; /* Points to current source char. */
3058
    register char c;             /* The current char. */
3059
    char *name;                  /* Start of 1st part of variable name. */
3060
    int nameChars;               /* Count of chars in name. */
3061
    int nameHasNsSeparators = 0; /* Set 1 if name contains "::"s. */
3062
    char savedChar;              /* Holds the character from string
3063
                                  * termporarily replaced by a null
3064
                                  * char during name processing. */
3065
    int objIndex;                /* The object array index for a pushed
3066
                                  * object holding a name part. */
3067
    int isArrayRef = 0;           /* 1 if reference to array element. */
3068
    int localIndex = -1;         /* Frame index of local if found.  */
3069
    int maxDepth = 0;             /* Maximum number of stack elements needed
3070
                                  * to push the variable. */
3071
    int savePushSimpleWords = envPtr->pushSimpleWords;
3072
    int result = TCL_OK;
3073
 
3074
    /*
3075
     * var_reference: '$' '{' braced_name '}' |
3076
     *                '$' name ['(' index_string ')']
3077
     *
3078
     * There are three cases:
3079
     * 1. The $ sign is followed by an open curly brace. Then the variable
3080
     *    name is everything up to the next close curly brace, and the
3081
     *    variable is a scalar variable.
3082
     * 2. The $ sign is not followed by an open curly brace. Then the
3083
     *    variable name is everything up to the next character that isn't
3084
     *    a letter, digit, underscore, or a "::" namespace separator. If the
3085
     *    following character is an open parenthesis, then the information
3086
     *    between parentheses is the array element name, which can include
3087
     *    any of the substitutions permissible between quotes.
3088
     * 3. The $ sign is followed by something that isn't a letter, digit,
3089
     *    underscore, or a "::" namespace separator: in this case,
3090
     *    there is no variable name, and "$" is pushed.
3091
     */
3092
 
3093
    src++;                      /* advance over the '$'. */
3094
 
3095
    /*
3096
     * Collect the first part of the variable's name into "name" and
3097
     * determine if it is an array reference and if it contains any
3098
     * namespace separator (::'s).
3099
     */
3100
 
3101
    if (*src == '{') {
3102
        /*
3103
         * A scalar name in braces.
3104
         */
3105
 
3106
        char *p;
3107
 
3108
        src++;
3109
        name = src;
3110
        c = *src;
3111
        while (c != '}') {
3112
            if (src == lastChar) {
3113
                Tcl_ResetResult(interp);
3114
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
3115
                        "missing close-brace for variable name", -1);
3116
                result = TCL_ERROR;
3117
                goto done;
3118
            }
3119
            src++;
3120
            c = *src;
3121
        }
3122
        nameChars = (src - name);
3123
        for (p = name;  p < src;  p++) {
3124
            if ((*p == ':') && (*(p+1) == ':')) {
3125
                nameHasNsSeparators = 1;
3126
                break;
3127
            }
3128
        }
3129
        src++;                  /* advance over the '}'. */
3130
    } else {
3131
        /*
3132
         * Scalar name or array reference not in braces.
3133
         */
3134
 
3135
        name = src;
3136
        c = *src;
3137
        while (isalnum(UCHAR(c)) || (c == '_') || (c == ':')) {
3138
            if (c == ':') {
3139
                if (*(src+1) == ':') {
3140
                    nameHasNsSeparators = 1;
3141
                    src += 2;
3142
                    while (*src == ':') {
3143
                        src++;
3144
                    }
3145
                    c = *src;
3146
                } else {
3147
                    break;      /* : by itself */
3148
                }
3149
            } else {
3150
                src++;
3151
                c = *src;
3152
            }
3153
        }
3154
        if (src == name) {
3155
            /*
3156
             * A '$' by itself, not a name reference. Push a "$" string.
3157
             */
3158
 
3159
            objIndex = TclObjIndexForString("$", 1, /*allocStrRep*/ 1,
3160
                                            /*inHeap*/ 0, envPtr);
3161
            TclEmitPush(objIndex, envPtr);
3162
            maxDepth = 1;
3163
            goto done;
3164
        }
3165
        nameChars = (src - name);
3166
        isArrayRef = (c == '(');
3167
    }
3168
 
3169
    /*
3170
     * Now emit instructions to load the variable. First either push the
3171
     * name of the scalar or array, or determine its index in the array of
3172
     * local variables in a procedure frame. Push the name if we are not
3173
     * compiling a procedure body or if the name has namespace
3174
     * qualifiers ("::"s).
3175
     */
3176
 
3177
    if (!isArrayRef) {          /* scalar reference */
3178
        if ((envPtr->procPtr == NULL) || nameHasNsSeparators) {
3179
            savedChar = name[nameChars];
3180
            name[nameChars] = '\0';
3181
            objIndex = TclObjIndexForString(name, nameChars,
3182
                    /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
3183
            name[nameChars] = savedChar;
3184
            TclEmitPush(objIndex, envPtr);
3185
            TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);
3186
            maxDepth = 1;
3187
        } else {
3188
            localIndex = LookupCompiledLocal(name, nameChars,
3189
                    /*createIfNew*/ 0, /*flagsIfCreated*/ 0,
3190
                    envPtr->procPtr);
3191
            if (localIndex >= 0) {
3192
                if (localIndex <= 255) {
3193
                    TclEmitInstUInt1(INST_LOAD_SCALAR1, localIndex, envPtr);
3194
                } else {
3195
                    TclEmitInstUInt4(INST_LOAD_SCALAR4, localIndex, envPtr);
3196
                }
3197
                maxDepth = 0;
3198
            } else {
3199
                savedChar = name[nameChars];
3200
                name[nameChars] = '\0';
3201
                objIndex = TclObjIndexForString(name, nameChars,
3202
                        /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
3203
                name[nameChars] = savedChar;
3204
                TclEmitPush(objIndex, envPtr);
3205
                TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);
3206
                maxDepth = 1;
3207
            }
3208
        }
3209
    } else {                    /* array reference */
3210
        if ((envPtr->procPtr == NULL) || nameHasNsSeparators) {
3211
            savedChar = name[nameChars];
3212
            name[nameChars] = '\0';
3213
            objIndex = TclObjIndexForString(name, nameChars,
3214
                    /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
3215
            name[nameChars] = savedChar;
3216
            TclEmitPush(objIndex, envPtr);
3217
            maxDepth = 1;
3218
        } else {
3219
            localIndex = LookupCompiledLocal(name, nameChars,
3220
                    /*createIfNew*/ 0, /*flagsIfCreated*/ 0,
3221
                    envPtr->procPtr);
3222
            if (localIndex < 0) {
3223
                savedChar = name[nameChars];
3224
                name[nameChars] = '\0';
3225
                objIndex = TclObjIndexForString(name, nameChars,
3226
                        /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
3227
                name[nameChars] = savedChar;
3228
                TclEmitPush(objIndex, envPtr);
3229
                maxDepth = 1;
3230
            }
3231
        }
3232
 
3233
        /*
3234
         * Parse and push the array element. Perform substitutions on it,
3235
         * just as is done for quoted strings.
3236
         */
3237
 
3238
        src++;
3239
        envPtr->pushSimpleWords = 1;
3240
        result = TclCompileQuotes(interp, src, lastChar, ')', flags,
3241
                envPtr);
3242
        src += envPtr->termOffset;
3243
        if (result != TCL_OK) {
3244
            char msg[200];
3245
            sprintf(msg, "\n    (parsing index for array \"%.*s\")",
3246
                    (nameChars > 100? 100 : nameChars), name);
3247
            Tcl_AddObjErrorInfo(interp, msg, -1);
3248
            goto done;
3249
        }
3250
        maxDepth += envPtr->maxStackDepth;
3251
 
3252
        /*
3253
         * Now emit the appropriate load instruction for the array element.
3254
         */
3255
 
3256
        if (localIndex < 0) {    /* a global or an unknown local */
3257
            TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr);
3258
        } else {
3259
            if (localIndex <= 255) {
3260
                TclEmitInstUInt1(INST_LOAD_ARRAY1, localIndex, envPtr);
3261
            } else {
3262
                TclEmitInstUInt4(INST_LOAD_ARRAY4, localIndex, envPtr);
3263
            }
3264
        }
3265
    }
3266
 
3267
    done:
3268
    envPtr->termOffset = (src - string);
3269
    envPtr->wordIsSimple = 0;
3270
    envPtr->numSimpleWordChars = 0;
3271
    envPtr->maxStackDepth = maxDepth;
3272
    envPtr->pushSimpleWords = savePushSimpleWords;
3273
    return result;
3274
}
3275
 
3276
/*
3277
 *----------------------------------------------------------------------
3278
 *
3279
 * IsLocalScalar --
3280
 *
3281
 *      Checks to see if a variable name refers to a local scalar.
3282
 *
3283
 * Results:
3284
 *      Returns 1 if the variable is a local scalar.
3285
 *
3286
 * Side effects:
3287
 *      None.
3288
 *
3289
 *----------------------------------------------------------------------
3290
 */
3291
 
3292
static int
3293
IsLocalScalar(varName, length)
3294
    char *varName;              /* The name to check. */
3295
    int length;         /* The number of characters in the string.  */
3296
{
3297
    char *p;
3298
    char *lastChar = varName + (length - 1);
3299
 
3300
    for (p = varName; p <= lastChar; p++) {
3301
        if ((CHAR_TYPE(p, lastChar) != TCL_NORMAL) &&
3302
            (CHAR_TYPE(p, lastChar) != TCL_COMMAND_END)) {
3303
            /*
3304
             * TCL_COMMAND_END is returned for the last character
3305
             * of the string.  By this point we know it isn't
3306
             * an array or namespace reference.
3307
             */
3308
 
3309
            return 0;
3310
        }
3311
        if  (*p == '(') {
3312
            if (*lastChar == ')') { /* we have an array element */
3313
                return 0;
3314
            }
3315
        } else if (*p == ':') {
3316
            if ((p != lastChar) && *(p+1) == ':') { /* qualified name */
3317
                return 0;
3318
            }
3319
        }
3320
    }
3321
 
3322
    return 1;
3323
}
3324
 
3325
/*
3326
 *----------------------------------------------------------------------
3327
 *
3328
 * TclCompileBreakCmd --
3329
 *
3330
 *      Procedure called to compile the "break" command.
3331
 *
3332
 * Results:
3333
 *      The return value is a standard Tcl result, which is TCL_OK unless
3334
 *      there was an error while parsing string. If an error occurs then
3335
 *      the interpreter's result contains a standard error message.
3336
 *
3337
 *      envPtr->termOffset is filled in with the offset of the character in
3338
 *      "string" just after the last one successfully processed.
3339
 *
3340
 *      envPtr->maxStackDepth is updated with the maximum number of stack
3341
 *      elements needed to execute the command.
3342
 *
3343
 * Side effects:
3344
 *      Instructions are added to envPtr to evaluate the "break" command
3345
 *      at runtime.
3346
 *
3347
 *----------------------------------------------------------------------
3348
 */
3349
 
3350
int
3351
TclCompileBreakCmd(interp, string, lastChar, flags, envPtr)
3352
    Tcl_Interp *interp;         /* Used for error reporting. */
3353
    char *string;               /* The source string to compile. */
3354
    char *lastChar;             /* Pointer to terminating character of
3355
                                 * string. */
3356
    int flags;                  /* Flags to control compilation (same as
3357
                                 * passed to Tcl_Eval). */
3358
    CompileEnv *envPtr;         /* Holds resulting instructions. */
3359
{
3360
    register char *src = string;/* Points to current source char. */
3361
    register int type;          /* Current char's CHAR_TYPE type. */
3362
    int result = TCL_OK;
3363
 
3364
    /*
3365
     * There should be no argument after the "break".
3366
     */
3367
 
3368
    type = CHAR_TYPE(src, lastChar);
3369
    if (type != TCL_COMMAND_END) {
3370
        AdvanceToNextWord(src, envPtr);
3371
        src += envPtr->termOffset;
3372
        type = CHAR_TYPE(src, lastChar);
3373
        if (type != TCL_COMMAND_END) {
3374
            Tcl_ResetResult(interp);
3375
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
3376
                    "wrong # args: should be \"break\"", -1);
3377
            result = TCL_ERROR;
3378
            goto done;
3379
        }
3380
    }
3381
 
3382
    /*
3383
     * Emit a break instruction.
3384
     */
3385
 
3386
    TclEmitOpcode(INST_BREAK, envPtr);
3387
 
3388
    done:
3389
    envPtr->termOffset = (src - string);
3390
    envPtr->maxStackDepth = 0;
3391
    return result;
3392
}
3393
 
3394
/*
3395
 *----------------------------------------------------------------------
3396
 *
3397
 * TclCompileCatchCmd --
3398
 *
3399
 *      Procedure called to compile the "catch" command.
3400
 *
3401
 * Results:
3402
 *      The return value is a standard Tcl result, which is TCL_OK if
3403
 *      compilation was successful. If an error occurs then the
3404
 *      interpreter's result contains a standard error message and TCL_ERROR
3405
 *      is returned. If compilation failed because the command is too
3406
 *      complex for TclCompileCatchCmd, TCL_OUT_LINE_COMPILE is returned
3407
 *      indicating that the catch command should be compiled "out of line"
3408
 *      by emitting code to invoke its command procedure at runtime.
3409
 *
3410
 *      envPtr->termOffset is filled in with the offset of the character in
3411
 *      "string" just after the last one successfully processed.
3412
 *
3413
 *      envPtr->maxStackDepth is updated with the maximum number of stack
3414
 *      elements needed to execute the command.
3415
 *
3416
 * Side effects:
3417
 *      Instructions are added to envPtr to evaluate the "catch" command
3418
 *      at runtime.
3419
 *
3420
 *----------------------------------------------------------------------
3421
 */
3422
 
3423
int
3424
TclCompileCatchCmd(interp, string, lastChar, flags, envPtr)
3425
    Tcl_Interp *interp;         /* Used for error reporting. */
3426
    char *string;               /* The source string to compile. */
3427
    char *lastChar;             /* Pointer to terminating character of
3428
                                 * string. */
3429
    int flags;                  /* Flags to control compilation (same as
3430
                                 * passed to Tcl_Eval). */
3431
    CompileEnv *envPtr;         /* Holds resulting instructions. */
3432
{
3433
    Proc *procPtr = envPtr->procPtr;
3434
                                /* Points to structure describing procedure
3435
                                 * containing the catch cmd, else NULL. */
3436
    int maxDepth = 0;           /* Maximum number of stack elements needed
3437
                                 * to execute cmd. */
3438
    ArgInfo argInfo;            /* Structure holding information about the
3439
                                 * start and end of each argument word. */
3440
    int range = -1;             /* If we compile the catch command, the
3441
                                 * index for its catch range record in the
3442
                                 * ExceptionRange array. -1 if we are not
3443
                                 * compiling the command. */
3444
    char *name;                 /* If a var name appears for a scalar local
3445
                                 * to a procedure, this points to the name's
3446
                                 * 1st char and nameChars is its length. */
3447
    int nameChars;              /* Length of the variable name, if any. */
3448
    int localIndex = -1;        /* Index of the variable in the current
3449
                                 * procedure's array of local variables.
3450
                                 * Otherwise -1 if not in a procedure or
3451
                                 * the variable wasn't found. */
3452
    char savedChar;             /* Holds the character from string
3453
                                 * termporarily replaced by a null character
3454
                                 * during processing of words. */
3455
    JumpFixup jumpFixup;        /* Used to emit the jump after the "no
3456
                                 * errors" epilogue code. */
3457
    int numWords, objIndex, jumpDist, result;
3458
    char *bodyStart, *bodyEnd;
3459
    Tcl_Obj *objPtr;
3460
    int savePushSimpleWords = envPtr->pushSimpleWords;
3461
 
3462
    /*
3463
     * Scan the words of the command and record the start and finish of
3464
     * each argument word.
3465
     */
3466
 
3467
    InitArgInfo(&argInfo);
3468
    result = CollectArgInfo(interp, string, lastChar, flags, &argInfo);
3469
    numWords = argInfo.numArgs;   /* i.e., the # after the command name */
3470
    if (result != TCL_OK) {
3471
        goto done;
3472
    }
3473
    if ((numWords != 1) && (numWords != 2)) {
3474
        Tcl_ResetResult(interp);
3475
        Tcl_AppendToObj(Tcl_GetObjResult(interp),
3476
                "wrong # args: should be \"catch command ?varName?\"", -1);
3477
        result = TCL_ERROR;
3478
        goto done;
3479
    }
3480
 
3481
    /*
3482
     * If a variable was specified and the catch command is at global level
3483
     * (not in a procedure), don't compile it inline: the payoff is
3484
     * too small.
3485
     */
3486
 
3487
    if ((numWords == 2) && (procPtr == NULL)) {
3488
        result = TCL_OUT_LINE_COMPILE;
3489
        goto done;
3490
    }
3491
 
3492
    /*
3493
     * Make sure the variable name, if any, has no substitutions and just
3494
     * refers to a local scaler.
3495
     */
3496
 
3497
    if (numWords == 2) {
3498
        char *firstChar = argInfo.startArray[1];
3499
        char *lastChar  = argInfo.endArray[1];
3500
 
3501
        if (*firstChar == '{') {
3502
            if (*lastChar != '}') {
3503
                Tcl_ResetResult(interp);
3504
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
3505
                        "extra characters after close-brace", -1);
3506
                result = TCL_ERROR;
3507
                goto done;
3508
            }
3509
            firstChar++;
3510
            lastChar--;
3511
        }
3512
 
3513
        nameChars = (lastChar - firstChar + 1);
3514
        if (!IsLocalScalar(firstChar, nameChars)) {
3515
            result = TCL_OUT_LINE_COMPILE;
3516
            goto done;
3517
        }
3518
 
3519
        name = firstChar;
3520
        localIndex = LookupCompiledLocal(name, nameChars,
3521
                    /*createIfNew*/ 1, /*flagsIfCreated*/ VAR_SCALAR,
3522
                    procPtr);
3523
    }
3524
 
3525
    /*
3526
     *==== At this point we believe we can compile the catch command ====
3527
     */
3528
 
3529
    /*
3530
     * Create and initialize a ExceptionRange record to hold information
3531
     * about this catch command.
3532
     */
3533
 
3534
    envPtr->excRangeDepth++;
3535
    envPtr->maxExcRangeDepth =
3536
        TclMax(envPtr->excRangeDepth, envPtr->maxExcRangeDepth);
3537
    range = CreateExceptionRange(CATCH_EXCEPTION_RANGE, envPtr);
3538
 
3539
    /*
3540
     * Emit the instruction to mark the start of the catch command.
3541
     */
3542
 
3543
    TclEmitInstUInt4(INST_BEGIN_CATCH4, range, envPtr);
3544
 
3545
    /*
3546
     * Inline compile the catch's body word: the command it controls. Also
3547
     * register the body's starting PC offset and byte length in the
3548
     * ExceptionRange record.
3549
     */
3550
 
3551
    envPtr->excRangeArrayPtr[range].codeOffset = TclCurrCodeOffset();
3552
 
3553
    bodyStart = argInfo.startArray[0];
3554
    bodyEnd   = argInfo.endArray[0];
3555
    savedChar = *(bodyEnd+1);
3556
    *(bodyEnd+1) = '\0';
3557
    result = CompileCmdWordInline(interp, bodyStart, (bodyEnd+1),
3558
            flags, envPtr);
3559
    *(bodyEnd+1) = savedChar;
3560
 
3561
    if (result != TCL_OK) {
3562
        if (result == TCL_ERROR) {
3563
            char msg[60];
3564
            sprintf(msg, "\n    (\"catch\" body line %d)",
3565
                    interp->errorLine);
3566
            Tcl_AddObjErrorInfo(interp, msg, -1);
3567
        }
3568
        goto done;
3569
    }
3570
    maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
3571
    envPtr->excRangeArrayPtr[range].numCodeBytes =
3572
        TclCurrCodeOffset() - envPtr->excRangeArrayPtr[range].codeOffset;
3573
 
3574
    /*
3575
     * Now emit the "no errors" epilogue code for the catch. First, if a
3576
     * variable was specified, store the body's result into the
3577
     * variable; otherwise, just discard the body's result. Then push
3578
     * a "0" object as the catch command's "no error" TCL_OK result,
3579
     * and jump around the "error case" epilogue code.
3580
     */
3581
 
3582
    if (localIndex != -1) {
3583
        if (localIndex <= 255) {
3584
            TclEmitInstUInt1(INST_STORE_SCALAR1, localIndex, envPtr);
3585
        } else {
3586
            TclEmitInstUInt4(INST_STORE_SCALAR4, localIndex, envPtr);
3587
        }
3588
    }
3589
    TclEmitOpcode(INST_POP, envPtr);
3590
 
3591
    objIndex = TclObjIndexForString("0", 1, /*allocStrRep*/ 0, /*inHeap*/ 0,
3592
            envPtr);
3593
    objPtr = envPtr->objArrayPtr[objIndex];
3594
 
3595
    Tcl_InvalidateStringRep(objPtr);
3596
    objPtr->internalRep.longValue = 0;
3597
    objPtr->typePtr = &tclIntType;
3598
 
3599
    TclEmitPush(objIndex, envPtr);
3600
    if (maxDepth == 0) {
3601
        maxDepth = 1;   /* since we just pushed one object */
3602
    }
3603
 
3604
    TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
3605
 
3606
    /*
3607
     * Now emit the "error case" epilogue code. First, if a variable was
3608
     * specified, emit instructions to push the interpreter's object result
3609
     * and store it into the variable. Then emit an instruction to push the
3610
     * nonzero error result. Note that the initial PC offset here is the
3611
     * catch's error target.
3612
     */
3613
 
3614
    envPtr->excRangeArrayPtr[range].catchOffset = TclCurrCodeOffset();
3615
    if (localIndex != -1) {
3616
        TclEmitOpcode(INST_PUSH_RESULT, envPtr);
3617
        if (localIndex <= 255) {
3618
            TclEmitInstUInt1(INST_STORE_SCALAR1, localIndex, envPtr);
3619
        } else {
3620
            TclEmitInstUInt4(INST_STORE_SCALAR4, localIndex, envPtr);
3621
        }
3622
        TclEmitOpcode(INST_POP, envPtr);
3623
    }
3624
    TclEmitOpcode(INST_PUSH_RETURN_CODE, envPtr);
3625
 
3626
    /*
3627
     * Now that we know the target of the jump after the "no errors"
3628
     * epilogue, update it with the correct distance. This is less
3629
     * than 127 bytes.
3630
     */
3631
 
3632
    jumpDist = (TclCurrCodeOffset() - jumpFixup.codeOffset);
3633
    if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) {
3634
        panic("TclCompileCatchCmd: bad jump distance %d\n", jumpDist);
3635
    }
3636
 
3637
    /*
3638
     * Emit the instruction to mark the end of the catch command.
3639
     */
3640
 
3641
    TclEmitOpcode(INST_END_CATCH, envPtr);
3642
 
3643
    done:
3644
    if (numWords == 0) {
3645
        envPtr->termOffset = 0;
3646
    } else {
3647
        envPtr->termOffset = (argInfo.endArray[numWords-1] + 1 - string);
3648
    }
3649
    if (range != -1) {          /* we compiled the catch command */
3650
        envPtr->excRangeDepth--;
3651
    }
3652
    envPtr->pushSimpleWords = savePushSimpleWords;
3653
    envPtr->maxStackDepth = maxDepth;
3654
    FreeArgInfo(&argInfo);
3655
    return result;
3656
}
3657
 
3658
/*
3659
 *----------------------------------------------------------------------
3660
 *
3661
 * TclCompileContinueCmd --
3662
 *
3663
 *      Procedure called to compile the "continue" command.
3664
 *
3665
 * Results:
3666
 *      The return value is a standard Tcl result, which is TCL_OK unless
3667
 *      there was an error while parsing string. If an error occurs then
3668
 *      the interpreter's result contains a standard error message.
3669
 *
3670
 *      envPtr->termOffset is filled in with the offset of the character in
3671
 *      "string" just after the last one successfully processed.
3672
 *
3673
 *      envPtr->maxStackDepth is updated with the maximum number of stack
3674
 *      elements needed to execute the command.
3675
 *
3676
 * Side effects:
3677
 *      Instructions are added to envPtr to evaluate the "continue" command
3678
 *      at runtime.
3679
 *
3680
 *----------------------------------------------------------------------
3681
 */
3682
 
3683
int
3684
TclCompileContinueCmd(interp, string, lastChar, flags, envPtr)
3685
    Tcl_Interp *interp;         /* Used for error reporting. */
3686
    char *string;               /* The source string to compile. */
3687
    char *lastChar;             /* Pointer to terminating character of
3688
                                 * string. */
3689
    int flags;                  /* Flags to control compilation (same as
3690
                                 * passed to Tcl_Eval). */
3691
    CompileEnv *envPtr;         /* Holds resulting instructions. */
3692
{
3693
    register char *src = string;/* Points to current source char. */
3694
    register int type;          /* Current char's CHAR_TYPE type. */
3695
    int result = TCL_OK;
3696
 
3697
    /*
3698
     * There should be no argument after the "continue".
3699
     */
3700
 
3701
    type = CHAR_TYPE(src, lastChar);
3702
    if (type != TCL_COMMAND_END) {
3703
        AdvanceToNextWord(src, envPtr);
3704
        src += envPtr->termOffset;
3705
        type = CHAR_TYPE(src, lastChar);
3706
        if (type != TCL_COMMAND_END) {
3707
            Tcl_ResetResult(interp);
3708
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
3709
                    "wrong # args: should be \"continue\"", -1);
3710
            result = TCL_ERROR;
3711
            goto done;
3712
        }
3713
    }
3714
 
3715
    /*
3716
     * Emit a continue instruction.
3717
     */
3718
 
3719
    TclEmitOpcode(INST_CONTINUE, envPtr);
3720
 
3721
    done:
3722
    envPtr->termOffset = (src - string);
3723
    envPtr->maxStackDepth = 0;
3724
    return result;
3725
}
3726
 
3727
/*
3728
 *----------------------------------------------------------------------
3729
 *
3730
 * TclCompileExprCmd --
3731
 *
3732
 *      Procedure called to compile the "expr" command.
3733
 *
3734
 * Results:
3735
 *      The return value is a standard Tcl result, which is TCL_OK
3736
 *      unless there was an error while parsing string. If an error occurs
3737
 *      then the interpreter's result contains a standard error message.
3738
 *
3739
 *      envPtr->termOffset is filled in with the offset of the character in
3740
 *      "string" just after the last one successfully processed.
3741
 *
3742
 *      envPtr->maxStackDepth is updated with the maximum number of stack
3743
 *      elements needed to execute the "expr" command.
3744
 *
3745
 * Side effects:
3746
 *      Instructions are added to envPtr to evaluate the "expr" command
3747
 *      at runtime.
3748
 *
3749
 *----------------------------------------------------------------------
3750
 */
3751
 
3752
int
3753
TclCompileExprCmd(interp, string, lastChar, flags, envPtr)
3754
    Tcl_Interp *interp;         /* Used for error reporting. */
3755
    char *string;               /* The source string to compile. */
3756
    char *lastChar;             /* Pointer to terminating character of
3757
                                 * string. */
3758
    int flags;                  /* Flags to control compilation (same as
3759
                                 * passed to Tcl_Eval). */
3760
    CompileEnv *envPtr;         /* Holds resulting instructions. */
3761
{
3762
    int maxDepth = 0;            /* Maximum number of stack elements needed
3763
                                 * to execute cmd. */
3764
    ArgInfo argInfo;            /* Structure holding information about the
3765
                                 * start and end of each argument word. */
3766
    Tcl_DString buffer;         /* Holds the concatenated expr command
3767
                                 * argument words. */
3768
    int firstWord;              /* 1 if processing the first word; 0 if
3769
                                 * processing subsequent words. */
3770
    char *first, *last;         /* Points to the first and last significant
3771
                                 * chars of the concatenated expression. */
3772
    int inlineCode;             /* 1 if inline "optimistic" code is
3773
                                 * emitted for the expression; else 0. */
3774
    int range = -1;             /* If we inline compile the concatenated
3775
                                 * expression, the index for its catch range
3776
                                 * record in the ExceptionRange array.
3777
                                 * Initialized to avoid compile warning. */
3778
    JumpFixup jumpFixup;        /* Used to emit the "success" jump after
3779
                                 * the inline concat. expression's code. */
3780
    char savedChar;             /* Holds the character termporarily replaced
3781
                                 * by a null character during compilation
3782
                                 * of the concatenated expression. */
3783
    int numWords, objIndex, i, result;
3784
    char *wordStart, *wordEnd, *p;
3785
    char c;
3786
    int savePushSimpleWords = envPtr->pushSimpleWords;
3787
    int saveExprIsJustVarRef = envPtr->exprIsJustVarRef;
3788
    int saveExprIsComparison = envPtr->exprIsComparison;
3789
 
3790
    /*
3791
     * Scan the words of the command and record the start and finish of
3792
     * each argument word.
3793
     */
3794
 
3795
    InitArgInfo(&argInfo);
3796
    result = CollectArgInfo(interp, string, lastChar, flags, &argInfo);
3797
    numWords = argInfo.numArgs;   /* i.e., the # after the command name */
3798
    if (result != TCL_OK) {
3799
        goto done;
3800
    }
3801
    if (numWords == 0) {
3802
        Tcl_ResetResult(interp);
3803
        Tcl_AppendToObj(Tcl_GetObjResult(interp),
3804
                "wrong # args: should be \"expr arg ?arg ...?\"", -1);
3805
        result = TCL_ERROR;
3806
        goto done;
3807
    }
3808
 
3809
    /*
3810
     * If there is a single argument word and it is enclosed in {}s, we may
3811
     * strip them off and safely compile the expr command into an inline
3812
     * sequence of instructions using TclCompileExpr. We know these
3813
     * instructions will have the right Tcl7.x expression semantics.
3814
     *
3815
     * Otherwise, if the word is not enclosed in {}s, or there are multiple
3816
     * words, we may need to call the expr command (Tcl_ExprObjCmd) at
3817
     * runtime. This recompiles the expression each time (typically) and so
3818
     * is slow. However, there are some circumstances where we can still
3819
     * compile inline instructions "optimistically" and check, during their
3820
     * execution, for double substitutions (these appear as nonnumeric
3821
     * operands). We check for any backslash or command substitutions. If
3822
     * none appear, and only variable substitutions are found, we generate
3823
     * inline instructions. If there is a compilation error, we must emit
3824
     * instructions that return the error at runtime, since this is when
3825
     * scripts in Tcl7.x would "see" the error.
3826
     *
3827
     * For now, if there are multiple words, or the single argument word is
3828
     * not in {}s, we concatenate the argument words and strip off any
3829
     * enclosing {}s or ""s. We call the expr command at runtime if
3830
     * either command or backslash substitutions appear (but not if
3831
     * only variable substitutions appear).
3832
     */
3833
 
3834
    if (numWords == 1) {
3835
        wordStart = argInfo.startArray[0]; /* start of 1st arg word */
3836
        wordEnd   = argInfo.endArray[0];   /* last char of 1st arg word */
3837
        if ((*wordStart == '{') && (*wordEnd == '}')) {
3838
            /*
3839
             * Simple case: a single argument word in {}'s.
3840
             */
3841
 
3842
            *wordEnd = '\0';
3843
            result = TclCompileExpr(interp, (wordStart + 1), wordEnd,
3844
                    flags, envPtr);
3845
            *wordEnd = '}';
3846
 
3847
            envPtr->termOffset = (wordEnd + 1) - string;
3848
            envPtr->pushSimpleWords = savePushSimpleWords;
3849
            FreeArgInfo(&argInfo);
3850
            return result;
3851
        }
3852
    }
3853
 
3854
    /*
3855
     * There are multiple words or no braces around the single word.
3856
     * Concatenate the expression's argument words while stripping off
3857
     * any enclosing {}s or ""s.
3858
     */
3859
 
3860
    Tcl_DStringInit(&buffer);
3861
    firstWord = 1;
3862
    for (i = 0;  i < numWords;  i++) {
3863
        wordStart = argInfo.startArray[i];
3864
        wordEnd   = argInfo.endArray[i];
3865
        if (((*wordStart == '{') && (*wordEnd == '}'))
3866
                || ((*wordStart == '"') && (*wordEnd == '"'))) {
3867
            wordStart++;
3868
            wordEnd--;
3869
        }
3870
        if (!firstWord) {
3871
            Tcl_DStringAppend(&buffer, " ", 1);
3872
        }
3873
        firstWord = 0;
3874
        if (wordEnd >= wordStart) {
3875
            Tcl_DStringAppend(&buffer, wordStart, (wordEnd-wordStart+1));
3876
        }
3877
    }
3878
 
3879
    /*
3880
     * Scan the concatenated expression's characters looking for any
3881
     * '['s or (for now) '\'s. If any are found, just call the expr cmd
3882
     * at runtime.
3883
     */
3884
 
3885
    inlineCode = 1;
3886
    first = Tcl_DStringValue(&buffer);
3887
    last = first + (Tcl_DStringLength(&buffer) - 1);
3888
    for (p = first;  p <= last;  p++) {
3889
        c = *p;
3890
        if ((c == '[') || (c == '\\')) {
3891
            inlineCode = 0;
3892
            break;
3893
        }
3894
    }
3895
 
3896
    if (inlineCode) {
3897
        /*
3898
         * Inline compile the concatenated expression inside a "catch"
3899
         * so that a runtime error will back off to a (slow) call on expr.
3900
         */
3901
 
3902
        int startCodeOffset = (envPtr->codeNext - envPtr->codeStart);
3903
        int startRangeNext = envPtr->excRangeArrayNext;
3904
 
3905
        /*
3906
         * Create a ExceptionRange record to hold information about the
3907
         * "catch" range for the expression's inline code. Also emit the
3908
         * instruction to mark the start of the range.
3909
         */
3910
 
3911
        envPtr->excRangeDepth++;
3912
        envPtr->maxExcRangeDepth =
3913
                TclMax(envPtr->excRangeDepth, envPtr->maxExcRangeDepth);
3914
        range = CreateExceptionRange(CATCH_EXCEPTION_RANGE, envPtr);
3915
        TclEmitInstUInt4(INST_BEGIN_CATCH4, range, envPtr);
3916
 
3917
        /*
3918
         * Inline compile the concatenated expression.
3919
         */
3920
 
3921
        envPtr->excRangeArrayPtr[range].codeOffset = TclCurrCodeOffset();
3922
        savedChar = *(last + 1);
3923
        *(last + 1) = '\0';
3924
        result = TclCompileExpr(interp, first, last + 1, flags, envPtr);
3925
        *(last + 1) = savedChar;
3926
 
3927
        maxDepth = envPtr->maxStackDepth;
3928
        envPtr->excRangeArrayPtr[range].numCodeBytes =
3929
                TclCurrCodeOffset() - envPtr->excRangeArrayPtr[range].codeOffset;
3930
 
3931
        if ((result != TCL_OK) || (envPtr->exprIsJustVarRef)
3932
                || (envPtr->exprIsComparison)) {
3933
            /*
3934
             * We must call the expr command at runtime. Either there was a
3935
             * compilation error or the inline code might fail to give the
3936
             * correct 2 level substitution semantics.
3937
             *
3938
             * The latter can happen if the expression consisted of just a
3939
             * single variable reference or if the top-level operator in the
3940
             * expr is a comparison (which might operate on strings). In the
3941
             * latter case, the expression's code might execute (apparently)
3942
             * successfully but produce the wrong result. We depend on its
3943
             * execution failing if a second level of substitutions is
3944
             * required. This causes the "catch" code we generate around the
3945
             * inline code to back off to a call on the expr command at
3946
             * runtime, and this always gives the right 2 level substitution
3947
             * semantics.
3948
             *
3949
             * We delete the inline code by backing up the code pc and catch
3950
             * index. Note that if there was a compilation error, we can't
3951
             * report the error yet since the expression might be valid
3952
             * after the second round of substitutions.
3953
             */
3954
 
3955
            envPtr->codeNext = (envPtr->codeStart + startCodeOffset);
3956
            envPtr->excRangeArrayNext = startRangeNext;
3957
            inlineCode = 0;
3958
        } else {
3959
            TclEmitOpcode(INST_END_CATCH, envPtr); /* for ok case */
3960
            TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
3961
            envPtr->excRangeArrayPtr[range].catchOffset = TclCurrCodeOffset();
3962
            TclEmitOpcode(INST_END_CATCH, envPtr); /* for error case */
3963
        }
3964
    }
3965
 
3966
    /*
3967
     * Emit code for the (slow) call on the expr command at runtime.
3968
     * Generate code to concatenate the (already substituted once)
3969
     * expression words with a space between each word.
3970
     */
3971
 
3972
    for (i = 0;  i < numWords;  i++) {
3973
        wordStart = argInfo.startArray[i];
3974
        wordEnd   = argInfo.endArray[i];
3975
        savedChar = *(wordEnd + 1);
3976
        *(wordEnd + 1) = '\0';
3977
        envPtr->pushSimpleWords = 1;
3978
        result = CompileWord(interp, wordStart, wordEnd+1, flags, envPtr);
3979
        *(wordEnd + 1) = savedChar;
3980
        if (result != TCL_OK) {
3981
            break;
3982
        }
3983
        if (i != (numWords - 1)) {
3984
            objIndex = TclObjIndexForString(" ", 1, /*allocStrRep*/ 1,
3985
                                            /*inHeap*/ 0, envPtr);
3986
            TclEmitPush(objIndex, envPtr);
3987
            maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
3988
        } else {
3989
            maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
3990
        }
3991
    }
3992
    if (result == TCL_OK) {
3993
        int concatItems = 2*numWords - 1;
3994
        while (concatItems > 255) {
3995
            TclEmitInstUInt1(INST_CONCAT1, 255, envPtr);
3996
            concatItems -= 254;  /* concat pushes 1 obj, the result */
3997
        }
3998
        if (concatItems > 1) {
3999
            TclEmitInstUInt1(INST_CONCAT1, concatItems, envPtr);
4000
        }
4001
        TclEmitOpcode(INST_EXPR_STK, envPtr);
4002
    }
4003
 
4004
    /*
4005
     * If emitting inline code, update the target of the jump after
4006
     * that inline code.
4007
     */
4008
 
4009
    if (inlineCode) {
4010
        int jumpDist = (TclCurrCodeOffset() - jumpFixup.codeOffset);
4011
        if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) {
4012
            /*
4013
             * Update the inline expression code's catch ExceptionRange
4014
             * target since it, being after the jump, also moved down.
4015
             */
4016
 
4017
            envPtr->excRangeArrayPtr[range].catchOffset += 3;
4018
        }
4019
    }
4020
    Tcl_DStringFree(&buffer);
4021
 
4022
    done:
4023
    if (numWords == 0) {
4024
        envPtr->termOffset = 0;
4025
    } else {
4026
        envPtr->termOffset = (argInfo.endArray[numWords-1] + 1 - string);
4027
    }
4028
    if (range != -1) {          /* we inline compiled the expr */
4029
        envPtr->excRangeDepth--;
4030
    }
4031
    envPtr->pushSimpleWords = savePushSimpleWords;
4032
    envPtr->exprIsJustVarRef = saveExprIsJustVarRef;
4033
    envPtr->exprIsComparison = saveExprIsComparison;
4034
    envPtr->maxStackDepth = maxDepth;
4035
    FreeArgInfo(&argInfo);
4036
    return result;
4037
}
4038
 
4039
/*
4040
 *----------------------------------------------------------------------
4041
 *
4042
 * TclCompileForCmd --
4043
 *
4044
 *      Procedure called to compile the "for" command.
4045
 *
4046
 * Results:
4047
 *      The return value is a standard Tcl result, which is TCL_OK unless
4048
 *      there was an error while parsing string. If an error occurs then
4049
 *      the interpreter's result contains a standard error message.
4050
 *
4051
 *      envPtr->termOffset is filled in with the offset of the character in
4052
 *      "string" just after the last one successfully processed.
4053
 *
4054
 *      envPtr->maxStackDepth is updated with the maximum number of stack
4055
 *      elements needed to execute the command.
4056
 *
4057
 * Side effects:
4058
 *      Instructions are added to envPtr to evaluate the "for" command
4059
 *      at runtime.
4060
 *
4061
 *----------------------------------------------------------------------
4062
 */
4063
 
4064
int
4065
TclCompileForCmd(interp, string, lastChar, flags, envPtr)
4066
    Tcl_Interp *interp;         /* Used for error reporting. */
4067
    char *string;               /* The source string to compile. */
4068
    char *lastChar;             /* Pointer to terminating character of
4069
                                 * string. */
4070
    int flags;                  /* Flags to control compilation (same as
4071
                                 * passed to Tcl_Eval). */
4072
    CompileEnv *envPtr;         /* Holds resulting instructions. */
4073
{
4074
    int maxDepth = 0;            /* Maximum number of stack elements needed
4075
                                 * to execute cmd. */
4076
    ArgInfo argInfo;            /* Structure holding information about the
4077
                                 * start and end of each argument word. */
4078
    int range1 = -1, range2;    /* Indexes in the ExceptionRange array of
4079
                                 * the loop ranges for this loop: one for
4080
                                 * its body and one for its "next" cmd. */
4081
    JumpFixup jumpFalseFixup;   /* Used to update or replace the ifFalse
4082
                                 * jump after the "for" test when its target
4083
                                 * PC is determined. */
4084
    int jumpBackDist, jumpBackOffset, testCodeOffset, jumpDist, objIndex;
4085
    unsigned char *jumpPc;
4086
    int savePushSimpleWords = envPtr->pushSimpleWords;
4087
    int numWords, result;
4088
 
4089
    /*
4090
     * Scan the words of the command and record the start and finish of
4091
     * each argument word.
4092
     */
4093
 
4094
    InitArgInfo(&argInfo);
4095
    result = CollectArgInfo(interp, string, lastChar, flags, &argInfo);
4096
    numWords = argInfo.numArgs;   /* i.e., the # after the command name */
4097
    if (result != TCL_OK) {
4098
        goto done;
4099
    }
4100
    if (numWords != 4) {
4101
        Tcl_ResetResult(interp);
4102
        Tcl_AppendToObj(Tcl_GetObjResult(interp),
4103
                "wrong # args: should be \"for start test next command\"", -1);
4104
        result = TCL_ERROR;
4105
        goto done;
4106
    }
4107
 
4108
    /*
4109
     * If the test expression is not enclosed in braces, don't compile
4110
     * the for inline. As a result of Tcl's two level substitution
4111
     * semantics for expressions, the expression might have a constant
4112
     * value that results in the loop never executing, or executing forever.
4113
     * Consider "set x 0; for {} "$x > 5" {incr x} {}": the loop body
4114
     * should never be executed.
4115
     * NOTE: This is an overly aggressive test, since there are legitimate
4116
     * literals that could be compiled but aren't in braces.  However, until
4117
     * the parser is integrated in 8.1, this is the simplest implementation.
4118
     */
4119
 
4120
    if (*(argInfo.startArray[1]) != '{') {
4121
        result = TCL_OUT_LINE_COMPILE;
4122
        goto done;
4123
    }
4124
 
4125
    /*
4126
     * Create a ExceptionRange record for the for loop's body. This is used
4127
     * to implement break and continue commands inside the body.
4128
     * Then create a second ExceptionRange record for the "next" command in
4129
     * order to implement break (but not continue) inside it. The second,
4130
     * "next" ExceptionRange will always have a -1 continueOffset.
4131
     */
4132
 
4133
    envPtr->excRangeDepth++;
4134
    envPtr->maxExcRangeDepth =
4135
        TclMax(envPtr->excRangeDepth, envPtr->maxExcRangeDepth);
4136
    range1 = CreateExceptionRange(LOOP_EXCEPTION_RANGE, envPtr);
4137
    range2 = CreateExceptionRange(LOOP_EXCEPTION_RANGE, envPtr);
4138
 
4139
    /*
4140
     * Compile inline the next word: the initial command.
4141
     */
4142
 
4143
    result = CompileCmdWordInline(interp, argInfo.startArray[0],
4144
            (argInfo.endArray[0] + 1), flags, envPtr);
4145
    if (result != TCL_OK) {
4146
        if (result == TCL_ERROR) {
4147
            Tcl_AddObjErrorInfo(interp, "\n    (\"for\" initial command)", -1);
4148
        }
4149
        goto done;
4150
    }
4151
    maxDepth = envPtr->maxStackDepth;
4152
 
4153
    /*
4154
     * Discard the start command's result.
4155
     */
4156
 
4157
    TclEmitOpcode(INST_POP, envPtr);
4158
 
4159
    /*
4160
     * Compile the next word: the test expression.
4161
     */
4162
 
4163
    testCodeOffset = TclCurrCodeOffset();
4164
    envPtr->pushSimpleWords = 1;    /* process words normally */
4165
    result = CompileExprWord(interp, argInfo.startArray[1],
4166
            (argInfo.endArray[1] + 1), flags, envPtr);
4167
    if (result != TCL_OK) {
4168
        if (result == TCL_ERROR) {
4169
            Tcl_AddObjErrorInfo(interp, "\n    (\"for\" test expression)", -1);
4170
        }
4171
        goto done;
4172
    }
4173
    maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
4174
 
4175
    /*
4176
     * Emit the jump that terminates the for command if the test was
4177
     * false. We emit a one byte (relative) jump here, and replace it later
4178
     * with a four byte jump if the jump target is > 127 bytes away.
4179
     */
4180
 
4181
    TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFalseFixup);
4182
 
4183
    /*
4184
     * Compile the loop body word inline. Also register the loop body's
4185
     * starting PC offset and byte length in the its ExceptionRange record.
4186
     */
4187
 
4188
    envPtr->excRangeArrayPtr[range1].codeOffset = TclCurrCodeOffset();
4189
    result = CompileCmdWordInline(interp, argInfo.startArray[3],
4190
            (argInfo.endArray[3] + 1), flags, envPtr);
4191
    if (result != TCL_OK) {
4192
        if (result == TCL_ERROR) {
4193
            char msg[60];
4194
            sprintf(msg, "\n    (\"for\" body line %d)", interp->errorLine);
4195
            Tcl_AddObjErrorInfo(interp, msg, -1);
4196
        }
4197
        goto done;
4198
    }
4199
    maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
4200
    envPtr->excRangeArrayPtr[range1].numCodeBytes =
4201
        (TclCurrCodeOffset() - envPtr->excRangeArrayPtr[range1].codeOffset);
4202
 
4203
    /*
4204
     * Discard the loop body's result.
4205
     */
4206
 
4207
    TclEmitOpcode(INST_POP, envPtr);
4208
 
4209
    /*
4210
     * Finally, compile the "next" subcommand word inline.
4211
     */
4212
 
4213
    envPtr->excRangeArrayPtr[range1].continueOffset = TclCurrCodeOffset();
4214
    envPtr->excRangeArrayPtr[range2].codeOffset = TclCurrCodeOffset();
4215
    result = CompileCmdWordInline(interp, argInfo.startArray[2],
4216
            (argInfo.endArray[2] + 1), flags, envPtr);
4217
    if (result != TCL_OK) {
4218
        if (result == TCL_ERROR) {
4219
            Tcl_AddObjErrorInfo(interp, "\n    (\"for\" loop-end command)", -1);
4220
        }
4221
        goto done;
4222
    }
4223
    maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
4224
    envPtr->excRangeArrayPtr[range2].numCodeBytes =
4225
        TclCurrCodeOffset() - envPtr->excRangeArrayPtr[range2].codeOffset;
4226
 
4227
    /*
4228
     * Discard the "next" subcommand's result.
4229
     */
4230
 
4231
    TclEmitOpcode(INST_POP, envPtr);
4232
 
4233
    /*
4234
     * Emit the unconditional jump back to the test at the top of the for
4235
     * loop. We generate a four byte jump if the distance to the test is
4236
     * greater than 120 bytes. This is conservative, and ensures that we
4237
     * won't have to replace this unconditional jump if we later need to
4238
     * replace the ifFalse jump with a four-byte jump.
4239
     */
4240
 
4241
    jumpBackOffset = TclCurrCodeOffset();
4242
    jumpBackDist = (jumpBackOffset - testCodeOffset);
4243
    if (jumpBackDist > 120) {
4244
        TclEmitInstInt4(INST_JUMP4, /*offset*/ -jumpBackDist, envPtr);
4245
    } else {
4246
        TclEmitInstInt1(INST_JUMP1, /*offset*/ -jumpBackDist, envPtr);
4247
    }
4248
 
4249
    /*
4250
     * Now that we know the target of the jumpFalse after the test, update
4251
     * it with the correct distance. If the distance is too great (more
4252
     * than 127 bytes), replace that jump with a four byte instruction and
4253
     * move the instructions after the jump down.
4254
     */
4255
 
4256
    jumpDist = (TclCurrCodeOffset() - jumpFalseFixup.codeOffset);
4257
    if (TclFixupForwardJump(envPtr, &jumpFalseFixup, jumpDist, 127)) {
4258
        /*
4259
         * Update the loop body's ExceptionRange record since it moved down:
4260
         * i.e., increment both its start and continue PC offsets. Also,
4261
         * update the "next" command's start PC offset in its ExceptionRange
4262
         * record since it also moved down.
4263
         */
4264
 
4265
        envPtr->excRangeArrayPtr[range1].codeOffset += 3;
4266
        envPtr->excRangeArrayPtr[range1].continueOffset += 3;
4267
        envPtr->excRangeArrayPtr[range2].codeOffset += 3;
4268
 
4269
        /*
4270
         * Update the distance for the unconditional jump back to the test
4271
         * at the top of the loop since it moved down 3 bytes too.
4272
         */
4273
 
4274
        jumpBackOffset += 3;
4275
        jumpPc = (envPtr->codeStart + jumpBackOffset);
4276
        if (jumpBackDist > 120) {
4277
            jumpBackDist += 3;
4278
            TclUpdateInstInt4AtPc(INST_JUMP4, /*offset*/ -jumpBackDist,
4279
                                   jumpPc);
4280
        } else {
4281
            jumpBackDist += 3;
4282
            TclUpdateInstInt1AtPc(INST_JUMP1, /*offset*/ -jumpBackDist,
4283
                                   jumpPc);
4284
        }
4285
    }
4286
 
4287
    /*
4288
     * The current PC offset (after the loop's body and "next" subcommand)
4289
     * is the loop's break target.
4290
     */
4291
 
4292
    envPtr->excRangeArrayPtr[range1].breakOffset =
4293
        envPtr->excRangeArrayPtr[range2].breakOffset = TclCurrCodeOffset();
4294
 
4295
    /*
4296
     * Push an empty string object as the for command's result.
4297
     */
4298
 
4299
    objIndex = TclObjIndexForString("", 0, /*allocStrRep*/ 0, /*inHeap*/ 0,
4300
                                    envPtr);
4301
    TclEmitPush(objIndex, envPtr);
4302
    if (maxDepth == 0) {
4303
        maxDepth = 1;
4304
    }
4305
 
4306
    done:
4307
    if (numWords == 0) {
4308
        envPtr->termOffset = 0;
4309
    } else {
4310
        envPtr->termOffset = (argInfo.endArray[numWords-1] + 1 - string);
4311
    }
4312
    envPtr->pushSimpleWords = savePushSimpleWords;
4313
    envPtr->maxStackDepth = maxDepth;
4314
    if (range1 != -1) {
4315
        envPtr->excRangeDepth--;
4316
    }
4317
    FreeArgInfo(&argInfo);
4318
    return result;
4319
}
4320
 
4321
/*
4322
 *----------------------------------------------------------------------
4323
 *
4324
 * TclCompileForeachCmd --
4325
 *
4326
 *      Procedure called to compile the "foreach" command.
4327
 *
4328
 * Results:
4329
 *      The return value is a standard Tcl result, which is TCL_OK if
4330
 *      compilation was successful. If an error occurs then the
4331
 *      interpreter's result contains a standard error message and TCL_ERROR
4332
 *      is returned. If complation failed because the command is too complex
4333
 *      for TclCompileForeachCmd, TCL_OUT_LINE_COMPILE is returned
4334
 *      indicating that the foreach command should be compiled "out of line"
4335
 *      by emitting code to invoke its command procedure at runtime.
4336
 *
4337
 *      envPtr->termOffset is filled in with the offset of the character in
4338
 *      "string" just after the last one successfully processed.
4339
 *
4340
 *      envPtr->maxStackDepth is updated with the maximum number of stack
4341
 *      elements needed to execute the "while" command.
4342
 *
4343
 * Side effects:
4344
 *      Instructions are added to envPtr to evaluate the "foreach" command
4345
 *      at runtime.
4346
 *
4347
 *----------------------------------------------------------------------
4348
 */
4349
 
4350
int
4351
TclCompileForeachCmd(interp, string, lastChar, flags, envPtr)
4352
    Tcl_Interp *interp;         /* Used for error reporting. */
4353
    char *string;               /* The source string to compile. */
4354
    char *lastChar;             /* Pointer to terminating character of
4355
                                 * string. */
4356
    int flags;                  /* Flags to control compilation (same as
4357
                                 * passed to Tcl_Eval). */
4358
    CompileEnv *envPtr;         /* Holds resulting instructions. */
4359
{
4360
    Proc *procPtr = envPtr->procPtr;
4361
                                /* Points to structure describing procedure
4362
                                 * containing foreach command, else NULL. */
4363
    int maxDepth = 0;            /* Maximum number of stack elements needed
4364
                                 * to execute cmd. */
4365
    ArgInfo argInfo;            /* Structure holding information about the
4366
                                 * start and end of each argument word. */
4367
    int numLists = 0;            /* Count of variable (and value) lists. */
4368
    int range = -1;             /* Index in the ExceptionRange array of the
4369
                                 * ExceptionRange record for this loop. */
4370
    ForeachInfo *infoPtr;       /* Points to the structure describing this
4371
                                 * foreach command. Stored in a AuxData
4372
                                 * record in the ByteCode. */
4373
    JumpFixup jumpFalseFixup;   /* Used to update or replace the ifFalse
4374
                                 * jump after test when its target PC is
4375
                                 * determined. */
4376
    char savedChar;             /* Holds the char from string termporarily
4377
                                 * replaced by a null character during
4378
                                 * processing of argument words. */
4379
    int firstListTmp = -1;      /* If we decide to compile this foreach
4380
                                 * command, this is the index or "slot
4381
                                 * number" for the first temp var allocated
4382
                                 * in the proc frame that holds a pointer to
4383
                                 * a value list. Initialized to avoid a
4384
                                 * compiler warning. */
4385
    int loopIterNumTmp;         /* If we decide to compile this foreach
4386
                                 * command, the index for the temp var that
4387
                                 * holds the current iteration count.  */
4388
    char *varListStart, *varListEnd, *valueListStart, *bodyStart, *bodyEnd;
4389
    unsigned char *jumpPc;
4390
    int jumpDist, jumpBackDist, jumpBackOffset;
4391
    int numWords, numVars, infoIndex, tmpIndex, objIndex, i, j, result;
4392
    int savePushSimpleWords = envPtr->pushSimpleWords;
4393
 
4394
    /*
4395
     * We parse the variable list argument words and create two arrays:
4396
     *    varcList[i] gives the number of variables in the i-th var list
4397
     *    varvList[i] points to an array of the names in the i-th var list
4398
     * These are initially allocated on the stack, and are allocated on
4399
     * the heap if necessary.
4400
     */
4401
 
4402
#define STATIC_VAR_LIST_SIZE 4
4403
    int varcListStaticSpace[STATIC_VAR_LIST_SIZE];
4404
    char **varvListStaticSpace[STATIC_VAR_LIST_SIZE];
4405
 
4406
    int *varcList = varcListStaticSpace;
4407
    char ***varvList = varvListStaticSpace;
4408
 
4409
    /*
4410
     * If the foreach command is at global level (not in a procedure),
4411
     * don't compile it inline: the payoff is too small.
4412
     */
4413
 
4414
    if (procPtr == NULL) {
4415
        return TCL_OUT_LINE_COMPILE;
4416
    }
4417
 
4418
    /*
4419
     * Scan the words of the command and record the start and finish of
4420
     * each argument word.
4421
     */
4422
 
4423
    InitArgInfo(&argInfo);
4424
    result = CollectArgInfo(interp, string, lastChar, flags, &argInfo);
4425
    numWords = argInfo.numArgs;
4426
    if (result != TCL_OK) {
4427
        goto done;
4428
    }
4429
    if ((numWords < 3) || (numWords%2 != 1)) {
4430
        Tcl_ResetResult(interp);
4431
        Tcl_AppendToObj(Tcl_GetObjResult(interp),
4432
                "wrong # args: should be \"foreach varList list ?varList list ...? command\"", -1);
4433
        result = TCL_ERROR;
4434
        goto done;
4435
    }
4436
 
4437
    /*
4438
     * Initialize the varcList and varvList arrays; allocate heap storage,
4439
     * if necessary, for them. Also make sure the variable names
4440
     * have no substitutions: that they're just "var" or "var(elem)"
4441
     */
4442
 
4443
    numLists = (numWords - 1)/2;
4444
    if (numLists > STATIC_VAR_LIST_SIZE) {
4445
        varcList = (int *) ckalloc(numLists * sizeof(int));
4446
        varvList = (char ***) ckalloc(numLists * sizeof(char **));
4447
    }
4448
    for (i = 0;  i < numLists;  i++) {
4449
        varcList[i] = 0;
4450
        varvList[i] = (char **) NULL;
4451
    }
4452
    for (i = 0;  i < numLists;  i++) {
4453
        /*
4454
         * Break each variable list into its component variables. If the
4455
         * lists is enclosed in {}s or ""s, strip them off first.
4456
         */
4457
 
4458
        varListStart = argInfo.startArray[i*2];
4459
        varListEnd   = argInfo.endArray[i*2];
4460
        if ((*varListStart == '{') || (*varListStart == '"')) {
4461
            if ((*varListEnd != '}') && (*varListEnd != '"')) {
4462
                Tcl_ResetResult(interp);
4463
                if (*varListStart == '"') {
4464
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
4465
                            "extra characters after close-quote", -1);
4466
                } else {
4467
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
4468
                            "extra characters after close-brace", -1);
4469
                }
4470
                result = TCL_ERROR;
4471
                goto done;
4472
            }
4473
            varListStart++;
4474
            varListEnd--;
4475
        }
4476
 
4477
        /*
4478
         * NOTE: THIS NEEDS TO BE CONVERTED TO AN OBJECT LIST.
4479
         */
4480
 
4481
        savedChar = *(varListEnd+1);
4482
        *(varListEnd+1) = '\0';
4483
        result = Tcl_SplitList(interp, varListStart,
4484
                               &varcList[i], &varvList[i]);
4485
        *(varListEnd+1) = savedChar;
4486
        if (result != TCL_OK) {
4487
            goto done;
4488
        }
4489
 
4490
        /*
4491
         * Check that each variable name has no substitutions and that
4492
         * it is a local scalar name.
4493
         */
4494
 
4495
        numVars = varcList[i];
4496
        for (j = 0;  j < numVars;  j++) {
4497
            char *varName = varvList[i][j];
4498
            if (!IsLocalScalar(varName, (int) strlen(varName))) {
4499
                result = TCL_OUT_LINE_COMPILE;
4500
                goto done;
4501
            }
4502
        }
4503
    }
4504
 
4505
    /*
4506
     *==== At this point we believe we can compile the foreach command ====
4507
     */
4508
 
4509
    /*
4510
     * Create and initialize a ExceptionRange record to hold information
4511
     * about this loop. This is used to implement break and continue.
4512
     */
4513
 
4514
    envPtr->excRangeDepth++;
4515
    envPtr->maxExcRangeDepth =
4516
        TclMax(envPtr->excRangeDepth, envPtr->maxExcRangeDepth);
4517
    range = CreateExceptionRange(LOOP_EXCEPTION_RANGE, envPtr);
4518
 
4519
    /*
4520
     * Reserve (numLists + 1) temporary variables:
4521
     *    - numLists temps for each value list
4522
     *    - a temp for the "next value" index into each value list
4523
     * At this time we don't try to reuse temporaries; if there are two
4524
     * nonoverlapping foreach loops, they don't share any temps.
4525
     */
4526
 
4527
    for (i = 0;  i < numLists;  i++) {
4528
        tmpIndex = LookupCompiledLocal(NULL, /*nameChars*/ 0,
4529
                /*createIfNew*/ 1, /*flagsIfCreated*/ VAR_SCALAR, procPtr);
4530
        if (i == 0) {
4531
            firstListTmp = tmpIndex;
4532
        }
4533
    }
4534
    loopIterNumTmp = LookupCompiledLocal(NULL, /*nameChars*/ 0,
4535
            /*createIfNew*/ 1, /*flagsIfCreated*/ VAR_SCALAR, procPtr);
4536
 
4537
    /*
4538
     * Create and initialize the ForeachInfo and ForeachVarList data
4539
     * structures describing this command. Then create a AuxData record
4540
     * pointing to the ForeachInfo structure in the compilation environment.
4541
     */
4542
 
4543
    infoPtr = (ForeachInfo *) ckalloc((unsigned)
4544
            (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *))));
4545
    infoPtr->numLists = numLists;
4546
    infoPtr->firstListTmp = firstListTmp;
4547
    infoPtr->loopIterNumTmp = loopIterNumTmp;
4548
    for (i = 0;  i < numLists;  i++) {
4549
        ForeachVarList *varListPtr;
4550
        numVars = varcList[i];
4551
        varListPtr = (ForeachVarList *) ckalloc((unsigned)
4552
                sizeof(ForeachVarList) + numVars*sizeof(int));
4553
        varListPtr->numVars = numVars;
4554
        for (j = 0;  j < numVars;  j++) {
4555
            char *varName = varvList[i][j];
4556
            int nameChars = strlen(varName);
4557
            varListPtr->varIndexes[j] = LookupCompiledLocal(varName,
4558
                    nameChars, /*createIfNew*/ 1,
4559
                    /*flagsIfCreated*/ VAR_SCALAR, procPtr);
4560
        }
4561
        infoPtr->varLists[i] = varListPtr;
4562
    }
4563
    infoIndex = TclCreateAuxData((ClientData) infoPtr,
4564
            &tclForeachInfoType, envPtr);
4565
 
4566
    /*
4567
     * Emit code to store each value list into the associated temporary.
4568
     */
4569
 
4570
    for (i = 0;  i < numLists;  i++) {
4571
        valueListStart = argInfo.startArray[2*i + 1];
4572
        envPtr->pushSimpleWords = 1;
4573
        result = CompileWord(interp, valueListStart, lastChar, flags,
4574
                envPtr);
4575
        if (result != TCL_OK) {
4576
            goto done;
4577
        }
4578
        maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
4579
 
4580
        tmpIndex = (firstListTmp + i);
4581
        if (tmpIndex <= 255) {
4582
            TclEmitInstUInt1(INST_STORE_SCALAR1, tmpIndex, envPtr);
4583
        } else {
4584
            TclEmitInstUInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
4585
        }
4586
        TclEmitOpcode(INST_POP, envPtr);
4587
    }
4588
 
4589
    /*
4590
     * Emit the instruction to initialize the foreach loop's index temp var.
4591
     */
4592
 
4593
    TclEmitInstUInt4(INST_FOREACH_START4, infoIndex, envPtr);
4594
 
4595
    /*
4596
     * Emit the top of loop code that assigns each loop variable and checks
4597
     * whether to terminate the loop.
4598
     */
4599
 
4600
    envPtr->excRangeArrayPtr[range].continueOffset = TclCurrCodeOffset();
4601
    TclEmitInstUInt4(INST_FOREACH_STEP4, infoIndex, envPtr);
4602
 
4603
    /*
4604
     * Emit the ifFalse jump that terminates the foreach if all value lists
4605
     * are exhausted. We emit a one byte (relative) jump here, and replace
4606
     * it later with a four byte jump if the jump target is more than
4607
     * 127 bytes away.
4608
     */
4609
 
4610
    TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFalseFixup);
4611
 
4612
    /*
4613
     * Compile the loop body word inline. Also register the loop body's
4614
     * starting PC offset and byte length in the ExceptionRange record.
4615
     */
4616
 
4617
    bodyStart = argInfo.startArray[numWords - 1];
4618
    bodyEnd   = argInfo.endArray[numWords - 1];
4619
    savedChar = *(bodyEnd+1);
4620
    *(bodyEnd+1) = '\0';
4621
    envPtr->excRangeArrayPtr[range].codeOffset = TclCurrCodeOffset();
4622
    result = CompileCmdWordInline(interp, bodyStart, bodyEnd+1, flags,
4623
            envPtr);
4624
    *(bodyEnd+1) = savedChar;
4625
    if (result != TCL_OK) {
4626
        if (result == TCL_ERROR) {
4627
            char msg[60];
4628
            sprintf(msg, "\n    (\"foreach\" body line %d)",
4629
                    interp->errorLine);
4630
            Tcl_AddObjErrorInfo(interp, msg, -1);
4631
        }
4632
        goto done;
4633
    }
4634
    maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
4635
    envPtr->excRangeArrayPtr[range].numCodeBytes =
4636
        TclCurrCodeOffset() - envPtr->excRangeArrayPtr[range].codeOffset;
4637
 
4638
    /*
4639
     * Discard the loop body's result.
4640
     */
4641
 
4642
    TclEmitOpcode(INST_POP, envPtr);
4643
 
4644
    /*
4645
     * Emit the unconditional jump back to the test at the top of the
4646
     * loop. We generate a four byte jump if the distance to the to of
4647
     * the foreach is greater than 120 bytes. This is conservative and
4648
     * ensures that we won't have to replace this unconditional jump if
4649
     * we later need to replace the ifFalse jump with a four-byte jump.
4650
     */
4651
 
4652
    jumpBackOffset = TclCurrCodeOffset();
4653
    jumpBackDist =
4654
        (jumpBackOffset - envPtr->excRangeArrayPtr[range].continueOffset);
4655
    if (jumpBackDist > 120) {
4656
        TclEmitInstInt4(INST_JUMP4, /*offset*/ -jumpBackDist, envPtr);
4657
    } else {
4658
        TclEmitInstInt1(INST_JUMP1, /*offset*/ -jumpBackDist, envPtr);
4659
    }
4660
 
4661
    /*
4662
     * Now that we know the target of the jumpFalse after the foreach_step
4663
     * test, update it with the correct distance. If the distance is too
4664
     * great (more than 127 bytes), replace that jump with a four byte
4665
     * instruction and move the instructions after the jump down.
4666
     */
4667
 
4668
    jumpDist = (TclCurrCodeOffset() - jumpFalseFixup.codeOffset);
4669
    if (TclFixupForwardJump(envPtr, &jumpFalseFixup, jumpDist, 127)) {
4670
        /*
4671
         * Update the loop body's starting PC offset since it moved down.
4672
         */
4673
 
4674
        envPtr->excRangeArrayPtr[range].codeOffset += 3;
4675
 
4676
        /*
4677
         * Update the distance for the unconditional jump back to the test
4678
         * at the top of the loop since it moved down 3 bytes too.
4679
         */
4680
 
4681
        jumpBackOffset += 3;
4682
        jumpPc = (envPtr->codeStart + jumpBackOffset);
4683
        if (jumpBackDist > 120) {
4684
            jumpBackDist += 3;
4685
            TclUpdateInstInt4AtPc(INST_JUMP4, /*offset*/ -jumpBackDist,
4686
                                   jumpPc);
4687
        } else {
4688
            jumpBackDist += 3;
4689
            TclUpdateInstInt1AtPc(INST_JUMP1, /*offset*/ -jumpBackDist,
4690
                                   jumpPc);
4691
        }
4692
    }
4693
 
4694
    /*
4695
     * The current PC offset (after the loop's body) is the loop's
4696
     * break target.
4697
     */
4698
 
4699
    envPtr->excRangeArrayPtr[range].breakOffset = TclCurrCodeOffset();
4700
 
4701
    /*
4702
     * Push an empty string object as the foreach command's result.
4703
     */
4704
 
4705
    objIndex = TclObjIndexForString("", 0, /*allocStrRep*/ 0, /*inHeap*/ 0,
4706
                                    envPtr);
4707
    TclEmitPush(objIndex, envPtr);
4708
    if (maxDepth == 0) {
4709
        maxDepth = 1;
4710
    }
4711
 
4712
    done:
4713
    for (i = 0;  i < numLists;  i++) {
4714
        if (varvList[i] != (char **) NULL) {
4715
            ckfree((char *) varvList[i]);
4716
        }
4717
    }
4718
    if (varcList != varcListStaticSpace) {
4719
        ckfree((char *) varcList);
4720
        ckfree((char *) varvList);
4721
    }
4722
    envPtr->termOffset = (argInfo.endArray[numWords-1] + 1 - string);
4723
    envPtr->pushSimpleWords = savePushSimpleWords;
4724
    envPtr->maxStackDepth = maxDepth;
4725
    if (range != -1) {
4726
        envPtr->excRangeDepth--;
4727
    }
4728
    FreeArgInfo(&argInfo);
4729
    return result;
4730
}
4731
 
4732
/*
4733
 *----------------------------------------------------------------------
4734
 *
4735
 * DupForeachInfo --
4736
 *
4737
 *      This procedure duplicates a ForeachInfo structure created as
4738
 *      auxiliary data during the compilation of a foreach command.
4739
 *
4740
 * Results:
4741
 *      A pointer to a newly allocated copy of the existing ForeachInfo
4742
 *      structure is returned.
4743
 *
4744
 * Side effects:
4745
 *      Storage for the copied ForeachInfo record is allocated. If the
4746
 *      original ForeachInfo structure pointed to any ForeachVarList
4747
 *      records, these structures are also copied and pointers to them
4748
 *      are stored in the new ForeachInfo record.
4749
 *
4750
 *----------------------------------------------------------------------
4751
 */
4752
 
4753
static ClientData
4754
DupForeachInfo(clientData)
4755
    ClientData clientData;      /* The foreach command's compilation
4756
                                 * auxiliary data to duplicate. */
4757
{
4758
    register ForeachInfo *srcPtr = (ForeachInfo *) clientData;
4759
    ForeachInfo *dupPtr;
4760
    register ForeachVarList *srcListPtr, *dupListPtr;
4761
    int numLists = srcPtr->numLists;
4762
    int numVars, i, j;
4763
 
4764
    dupPtr = (ForeachInfo *) ckalloc((unsigned)
4765
            (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *))));
4766
    dupPtr->numLists = numLists;
4767
    dupPtr->firstListTmp = srcPtr->firstListTmp;
4768
    dupPtr->loopIterNumTmp = srcPtr->loopIterNumTmp;
4769
 
4770
    for (i = 0;  i < numLists;  i++) {
4771
        srcListPtr = srcPtr->varLists[i];
4772
        numVars = srcListPtr->numVars;
4773
        dupListPtr = (ForeachVarList *) ckalloc((unsigned)
4774
                sizeof(ForeachVarList) + numVars*sizeof(int));
4775
        dupListPtr->numVars = numVars;
4776
        for (j = 0;  j < numVars;  j++) {
4777
            dupListPtr->varIndexes[j] = srcListPtr->varIndexes[j];
4778
        }
4779
        dupPtr->varLists[i] = dupListPtr;
4780
    }
4781
    return (ClientData) dupPtr;
4782
}
4783
 
4784
/*
4785
 *----------------------------------------------------------------------
4786
 *
4787
 * FreeForeachInfo --
4788
 *
4789
 *      Procedure to free a ForeachInfo structure created as auxiliary data
4790
 *      during the compilation of a foreach command.
4791
 *
4792
 * Results:
4793
 *      None.
4794
 *
4795
 * Side effects:
4796
 *      Storage for the ForeachInfo structure pointed to by the ClientData
4797
 *      argument is freed as is any ForeachVarList record pointed to by the
4798
 *      ForeachInfo structure.
4799
 *
4800
 *----------------------------------------------------------------------
4801
 */
4802
 
4803
static void
4804
FreeForeachInfo(clientData)
4805
    ClientData clientData;      /* The foreach command's compilation
4806
                                 * auxiliary data to free. */
4807
{
4808
    register ForeachInfo *infoPtr = (ForeachInfo *) clientData;
4809
    register ForeachVarList *listPtr;
4810
    int numLists = infoPtr->numLists;
4811
    register int i;
4812
 
4813
    for (i = 0;  i < numLists;  i++) {
4814
        listPtr = infoPtr->varLists[i];
4815
        ckfree((char *) listPtr);
4816
    }
4817
    ckfree((char *) infoPtr);
4818
}
4819
 
4820
/*
4821
 *----------------------------------------------------------------------
4822
 *
4823
 * TclCompileIfCmd --
4824
 *
4825
 *      Procedure called to compile the "if" command.
4826
 *
4827
 * Results:
4828
 *      The return value is a standard Tcl result, which is TCL_OK unless
4829
 *      there was an error while parsing string. If an error occurs then
4830
 *      the interpreter's result contains a standard error message.
4831
 *
4832
 *      envPtr->termOffset is filled in with the offset of the character in
4833
 *      "string" just after the last one successfully processed.
4834
 *
4835
 *      envPtr->maxStackDepth is updated with the maximum number of stack
4836
 *      elements needed to execute the command.
4837
 *
4838
 * Side effects:
4839
 *      Instructions are added to envPtr to evaluate the "if" command
4840
 *      at runtime.
4841
 *
4842
 *----------------------------------------------------------------------
4843
 */
4844
 
4845
int
4846
TclCompileIfCmd(interp, string, lastChar, flags, envPtr)
4847
    Tcl_Interp *interp;         /* Used for error reporting. */
4848
    char *string;               /* The source string to compile. */
4849
    char *lastChar;             /* Pointer to terminating character of
4850
                                 * string. */
4851
    int flags;                  /* Flags to control compilation (same as
4852
                                 * passed to Tcl_Eval). */
4853
    CompileEnv *envPtr;         /* Holds resulting instructions. */
4854
{
4855
    register char *src = string;/* Points to current source char. */
4856
    register int type;          /* Current char's CHAR_TYPE type. */
4857
    int maxDepth = 0;            /* Maximum number of stack elements needed
4858
                                 * to execute cmd. */
4859
    JumpFixupArray jumpFalseFixupArray;
4860
                                /* Used to fix up the ifFalse jump after
4861
                                 * each "if"/"elseif" test when its target
4862
                                 * PC is determined. */
4863
    JumpFixupArray jumpEndFixupArray;
4864
                                /* Used to fix up the unconditional jump
4865
                                 * after each "then" command to the end of
4866
                                 * the "if" when that PC is determined. */
4867
    char *testSrcStart;
4868
    int jumpDist, jumpFalseDist, jumpIndex, objIndex, j, result;
4869
    unsigned char *ifFalsePc;
4870
    unsigned char opCode;
4871
    int savePushSimpleWords = envPtr->pushSimpleWords;
4872
 
4873
    /*
4874
     * Loop compiling "expr then body" clauses after an "if" or "elseif".
4875
     */
4876
 
4877
    TclInitJumpFixupArray(&jumpFalseFixupArray);
4878
    TclInitJumpFixupArray(&jumpEndFixupArray);
4879
    while (1) {
4880
        /*
4881
         * At this point in the loop, we have an expression to test, either
4882
         * the main expression or an expression following an "elseif".
4883
         * The arguments after the expression must be "then" (optional) and
4884
         * a script to execute if the expression is true.
4885
         */
4886
 
4887
        AdvanceToNextWord(src, envPtr);
4888
        src += envPtr->termOffset;
4889
        type = CHAR_TYPE(src, lastChar);
4890
        if (type == TCL_COMMAND_END) {
4891
            Tcl_ResetResult(interp);
4892
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
4893
                    "wrong # args: no expression after \"if\" argument", -1);
4894
            result = TCL_ERROR;
4895
            goto done;
4896
        }
4897
 
4898
        /*
4899
         * Compile the "if"/"elseif" test expression.
4900
         */
4901
 
4902
        testSrcStart = src;
4903
        envPtr->pushSimpleWords = 1;
4904
        result = CompileExprWord(interp, src, lastChar, flags, envPtr);
4905
        if (result != TCL_OK) {
4906
            if (result == TCL_ERROR) {
4907
                Tcl_AddObjErrorInfo(interp,
4908
                        "\n    (\"if\" test expression)", -1);
4909
            }
4910
            goto done;
4911
        }
4912
        maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
4913
        src += envPtr->termOffset;
4914
 
4915
        /*
4916
         * Emit the ifFalse jump around the "then" part if the test was
4917
         * false. We emit a one byte (relative) jump here, and replace it
4918
         * later with a four byte jump if the jump target is more than 127
4919
         * bytes away.
4920
         */
4921
 
4922
        if (jumpFalseFixupArray.next >= jumpFalseFixupArray.end) {
4923
            TclExpandJumpFixupArray(&jumpFalseFixupArray);
4924
        }
4925
        jumpIndex = jumpFalseFixupArray.next;
4926
        jumpFalseFixupArray.next++;
4927
        TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
4928
                &(jumpFalseFixupArray.fixup[jumpIndex]));
4929
 
4930
        /*
4931
         * Skip over the optional "then" before the then clause.
4932
         */
4933
 
4934
        AdvanceToNextWord(src, envPtr);
4935
        src += envPtr->termOffset;
4936
        type = CHAR_TYPE(src, lastChar);
4937
        if (type == TCL_COMMAND_END) {
4938
            char buf[100];
4939
            sprintf(buf, "wrong # args: no script following \"%.20s\" argument", testSrcStart);
4940
            Tcl_ResetResult(interp);
4941
            Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);
4942
            result = TCL_ERROR;
4943
            goto done;
4944
        }
4945
        if ((*src == 't') && (strncmp(src, "then", 4) == 0)) {
4946
            type = CHAR_TYPE(src+4, lastChar);
4947
            if ((type == TCL_SPACE) || (type == TCL_COMMAND_END)) {
4948
                src += 4;
4949
                AdvanceToNextWord(src, envPtr);
4950
                src += envPtr->termOffset;
4951
                type = CHAR_TYPE(src, lastChar);
4952
                if (type == TCL_COMMAND_END) {
4953
                    Tcl_ResetResult(interp);
4954
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
4955
                            "wrong # args: no script following \"then\" argument", -1);
4956
                    result = TCL_ERROR;
4957
                    goto done;
4958
                }
4959
            }
4960
        }
4961
 
4962
        /*
4963
         * Compile the "then" command word inline.
4964
         */
4965
 
4966
        result = CompileCmdWordInline(interp, src, lastChar, flags, envPtr);
4967
        if (result != TCL_OK) {
4968
            if (result == TCL_ERROR) {
4969
                char msg[60];
4970
                sprintf(msg, "\n    (\"if\" then script line %d)",
4971
                        interp->errorLine);
4972
                Tcl_AddObjErrorInfo(interp, msg, -1);
4973
            }
4974
            goto done;
4975
        }
4976
        maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
4977
        src += envPtr->termOffset;
4978
 
4979
        /*
4980
         * Emit an unconditional jump to the end of the "if" command. We
4981
         * emit a one byte jump here, and replace it later with a four byte
4982
         * jump if the jump target is more than 127 bytes away. Note that
4983
         * both the jumpFalseFixupArray and the jumpEndFixupArray are
4984
         * indexed by the same index, "jumpIndex".
4985
         */
4986
 
4987
        if (jumpEndFixupArray.next >= jumpEndFixupArray.end) {
4988
            TclExpandJumpFixupArray(&jumpEndFixupArray);
4989
        }
4990
        jumpEndFixupArray.next++;
4991
        TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
4992
                &(jumpEndFixupArray.fixup[jumpIndex]));
4993
 
4994
        /*
4995
         * Now that we know the target of the jumpFalse after the if test,
4996
         * update it with the correct distance. We generate a four byte
4997
         * jump if the distance is greater than 120 bytes. This is
4998
         * conservative, and ensures that we won't have to replace this
4999
         * jump if we later also need to replace the preceeding
5000
         * unconditional jump to the end of the "if" with a four-byte jump.
5001
         */
5002
 
5003
        jumpDist = (TclCurrCodeOffset() - jumpFalseFixupArray.fixup[jumpIndex].codeOffset);
5004
        if (TclFixupForwardJump(envPtr,
5005
                &(jumpFalseFixupArray.fixup[jumpIndex]), jumpDist, 120)) {
5006
            /*
5007
             * Adjust the code offset for the unconditional jump at the end
5008
             * of the last "then" clause.
5009
             */
5010
 
5011
            jumpEndFixupArray.fixup[jumpIndex].codeOffset += 3;
5012
        }
5013
 
5014
        /*
5015
         * Check now for a "elseif" word. If we find one, keep looping.
5016
         */
5017
 
5018
        AdvanceToNextWord(src, envPtr);
5019
        src += envPtr->termOffset;
5020
        type = CHAR_TYPE(src, lastChar);
5021
        if ((type != TCL_COMMAND_END)
5022
                && ((*src == 'e') && (strncmp(src, "elseif", 6) == 0))) {
5023
            type = CHAR_TYPE(src+6, lastChar);
5024
            if ((type == TCL_SPACE) || (type == TCL_COMMAND_END)) {
5025
                src += 6;
5026
                AdvanceToNextWord(src, envPtr);
5027
                src += envPtr->termOffset;
5028
                type = CHAR_TYPE(src, lastChar);
5029
                if (type == TCL_COMMAND_END) {
5030
                    Tcl_ResetResult(interp);
5031
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
5032
                            "wrong # args: no expression after \"elseif\" argument", -1);
5033
                    result = TCL_ERROR;
5034
                    goto done;
5035
                }
5036
                continue;         /* continue the "expr then body" loop */
5037
            }
5038
        }
5039
        break;
5040
    } /* end of the "expr then body" loop */
5041
 
5042
    /*
5043
     * No more "elseif expr then body" clauses. Check now for an "else"
5044
     * clause. If there is another word, we are at its start.
5045
     */
5046
 
5047
    if (type != TCL_COMMAND_END) {
5048
        if ((*src == 'e') && (strncmp(src, "else", 4) == 0)) {
5049
            type = CHAR_TYPE(src+4, lastChar);
5050
            if ((type == TCL_SPACE) || (type == TCL_COMMAND_END)) {
5051
                src += 4;
5052
                AdvanceToNextWord(src, envPtr);
5053
                src += envPtr->termOffset;
5054
                type = CHAR_TYPE(src, lastChar);
5055
                if (type == TCL_COMMAND_END) {
5056
                    Tcl_ResetResult(interp);
5057
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
5058
                            "wrong # args: no script following \"else\" argument", -1);
5059
                    result = TCL_ERROR;
5060
                    goto done;
5061
                }
5062
            }
5063
        }
5064
 
5065
        /*
5066
         * Compile the "else" command word inline.
5067
         */
5068
 
5069
        result = CompileCmdWordInline(interp, src, lastChar, flags, envPtr);
5070
        if (result != TCL_OK) {
5071
            if (result == TCL_ERROR) {
5072
                char msg[60];
5073
                sprintf(msg, "\n    (\"if\" else script line %d)",
5074
                        interp->errorLine);
5075
                Tcl_AddObjErrorInfo(interp, msg, -1);
5076
            }
5077
            goto done;
5078
        }
5079
        maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
5080
        src += envPtr->termOffset;
5081
 
5082
        /*
5083
         * Skip over white space until the end of the command.
5084
         */
5085
 
5086
        type = CHAR_TYPE(src, lastChar);
5087
        if (type != TCL_COMMAND_END) {
5088
            AdvanceToNextWord(src, envPtr);
5089
            src += envPtr->termOffset;
5090
            type = CHAR_TYPE(src, lastChar);
5091
            if (type != TCL_COMMAND_END) {
5092
                Tcl_ResetResult(interp);
5093
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
5094
                        "wrong # args: extra words after \"else\" clause in \"if\" command", -1);
5095
                result = TCL_ERROR;
5096
                goto done;
5097
            }
5098
        }
5099
    } else {
5100
        /*
5101
         * The "if" command has no "else" clause: push an empty string
5102
         * object as its result.
5103
         */
5104
 
5105
        objIndex = TclObjIndexForString("", 0, /*allocStrRep*/ 0,
5106
                /*inHeap*/ 0, envPtr);
5107
        TclEmitPush(objIndex, envPtr);
5108
        maxDepth = TclMax(1, maxDepth);
5109
    }
5110
 
5111
    /*
5112
     * Now that we know the target of the unconditional jumps to the end of
5113
     * the "if" command, update them with the correct distance. If the
5114
     * distance is too great (> 127 bytes), replace the jump with a four
5115
     * byte instruction and move instructions after the jump down.
5116
     */
5117
 
5118
    for (j = jumpEndFixupArray.next;  j > 0;  j--) {
5119
        jumpIndex = (j - 1);    /* i.e. process the closest jump first */
5120
        jumpDist = (TclCurrCodeOffset() - jumpEndFixupArray.fixup[jumpIndex].codeOffset);
5121
        if (TclFixupForwardJump(envPtr,
5122
                &(jumpEndFixupArray.fixup[jumpIndex]), jumpDist, 127)) {
5123
            /*
5124
             * Adjust the jump distance for the "ifFalse" jump that
5125
             * immediately preceeds this jump. We've moved it's target
5126
             * (just after this unconditional jump) three bytes down.
5127
             */
5128
 
5129
            ifFalsePc = (envPtr->codeStart + jumpFalseFixupArray.fixup[jumpIndex].codeOffset);
5130
            opCode = *ifFalsePc;
5131
            if (opCode == INST_JUMP_FALSE1) {
5132
                jumpFalseDist = TclGetInt1AtPtr(ifFalsePc + 1);
5133
                jumpFalseDist += 3;
5134
                TclStoreInt1AtPtr(jumpFalseDist, (ifFalsePc + 1));
5135
            } else if (opCode == INST_JUMP_FALSE4) {
5136
                jumpFalseDist = TclGetInt4AtPtr(ifFalsePc + 1);
5137
                jumpFalseDist += 3;
5138
                TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1));
5139
            } else {
5140
                panic("TclCompileIfCmd: unexpected opcode updating ifFalse jump");
5141
            }
5142
        }
5143
    }
5144
 
5145
    /*
5146
     * Free the jumpFixupArray array if malloc'ed storage was used.
5147
     */
5148
 
5149
    done:
5150
    TclFreeJumpFixupArray(&jumpFalseFixupArray);
5151
    TclFreeJumpFixupArray(&jumpEndFixupArray);
5152
    envPtr->termOffset = (src - string);
5153
    envPtr->maxStackDepth = maxDepth;
5154
    envPtr->pushSimpleWords = savePushSimpleWords;
5155
    return result;
5156
}
5157
 
5158
/*
5159
 *----------------------------------------------------------------------
5160
 *
5161
 * TclCompileIncrCmd --
5162
 *
5163
 *      Procedure called to compile the "incr" command.
5164
 *
5165
 * Results:
5166
 *      The return value is a standard Tcl result, which is TCL_OK unless
5167
 *      there was an error while parsing string. If an error occurs then
5168
 *      the interpreter's result contains a standard error message.
5169
 *
5170
 *      envPtr->termOffset is filled in with the offset of the character in
5171
 *      "string" just after the last one successfully processed.
5172
 *
5173
 *      envPtr->maxStackDepth is updated with the maximum number of stack
5174
 *      elements needed to execute the "incr" command.
5175
 *
5176
 * Side effects:
5177
 *      Instructions are added to envPtr to evaluate the "incr" command
5178
 *      at runtime.
5179
 *
5180
 *----------------------------------------------------------------------
5181
 */
5182
 
5183
int
5184
TclCompileIncrCmd(interp, string, lastChar, flags, envPtr)
5185
    Tcl_Interp *interp;         /* Used for error reporting. */
5186
    char *string;               /* The source string to compile. */
5187
    char *lastChar;             /* Pointer to terminating character of
5188
                                 * string. */
5189
    int flags;                  /* Flags to control compilation (same as
5190
                                 * passed to Tcl_Eval). */
5191
    CompileEnv *envPtr;         /* Holds resulting instructions. */
5192
{
5193
    Proc *procPtr = envPtr->procPtr;
5194
                                /* Points to structure describing procedure
5195
                                 * containing incr command, else NULL. */
5196
    register char *src = string;
5197
                                /* Points to current source char. */
5198
    register int type;          /* Current char's CHAR_TYPE type. */
5199
    int simpleVarName;          /* 1 if name is just sequence of chars with
5200
                                 * an optional element name in parens. */
5201
    char *name = NULL;          /* If simpleVarName, points to first char of
5202
                                 * variable name and nameChars is length.
5203
                                 * Otherwise NULL. */
5204
    char *elName = NULL;        /* If simpleVarName, points to first char of
5205
                                 * element name and elNameChars is length.
5206
                                 * Otherwise NULL. */
5207
    int nameChars = 0;           /* Length of the var name. Initialized to
5208
                                 * avoid a compiler warning. */
5209
    int elNameChars = 0; /* Length of array's element name, if any.
5210
                                 * Initialized to avoid a compiler
5211
                                 * warning. */
5212
    int incrementGiven;         /* 1 if an increment amount was given. */
5213
    int isImmIncrValue = 0;      /* 1 if increment amount is a literal
5214
                                 * integer in [-127..127]. */
5215
    int immIncrValue = 0;        /* if isImmIncrValue is 1, the immediate
5216
                                 * integer value. */
5217
    int maxDepth = 0;            /* Maximum number of stack elements needed
5218
                                 * to execute cmd. */
5219
    int localIndex = -1;        /* Index of the variable in the current
5220
                                 * procedure's array of local variables.
5221
                                 * Otherwise -1 if not in a procedure or
5222
                                 * the variable wasn't found. */
5223
    char savedChar;             /* Holds the character from string
5224
                                 * termporarily replaced by a null char
5225
                                 * during name processing. */
5226
    int objIndex;               /* The object array index for a pushed
5227
                                 * object holding a name part. */
5228
    int savePushSimpleWords = envPtr->pushSimpleWords;
5229
    char *p;
5230
    int i, result;
5231
 
5232
    /*
5233
     * Parse the next word: the variable name. If it is "simple" (requires
5234
     * no substitutions at runtime), divide it up into a simple "name" plus
5235
     * an optional "elName". Otherwise, if not simple, just push the name.
5236
     */
5237
 
5238
    AdvanceToNextWord(src, envPtr);
5239
    src += envPtr->termOffset;
5240
    type = CHAR_TYPE(src, lastChar);
5241
    if (type == TCL_COMMAND_END) {
5242
        badArgs:
5243
        Tcl_ResetResult(interp);
5244
        Tcl_AppendToObj(Tcl_GetObjResult(interp),
5245
                "wrong # args: should be \"incr varName ?increment?\"", -1);
5246
        result = TCL_ERROR;
5247
        goto done;
5248
    }
5249
 
5250
    envPtr->pushSimpleWords = 0;
5251
    result = CompileWord(interp, src, lastChar, flags, envPtr);
5252
    if (result != TCL_OK) {
5253
        goto done;
5254
    }
5255
    simpleVarName = envPtr->wordIsSimple;
5256
    if (simpleVarName) {
5257
        name = src;
5258
        nameChars = envPtr->numSimpleWordChars;
5259
        if (type & (TCL_QUOTE | TCL_OPEN_BRACE)) {
5260
            name++;
5261
        }
5262
        elName = NULL;
5263
        elNameChars = 0;
5264
        p = name;
5265
        for (i = 0;  i < nameChars;  i++) {
5266
            if (*p == '(') {
5267
                char *openParen = p;
5268
                p = (src + nameChars-1);
5269
                if (*p == ')') { /* last char is ')' => array reference */
5270
                    nameChars = (openParen - name);
5271
                    elName = openParen+1;
5272
                    elNameChars = (p - elName);
5273
                }
5274
                break;
5275
            }
5276
            p++;
5277
        }
5278
    } else {
5279
        maxDepth = envPtr->maxStackDepth;
5280
    }
5281
    src += envPtr->termOffset;
5282
 
5283
    /*
5284
     * See if there is a next word. If so, we are incrementing the variable
5285
     * by that value (which must be an integer).
5286
     */
5287
 
5288
    incrementGiven = 0;
5289
    type = CHAR_TYPE(src, lastChar);
5290
    if (type != TCL_COMMAND_END) {
5291
        AdvanceToNextWord(src, envPtr);
5292
        src += envPtr->termOffset;
5293
        type = CHAR_TYPE(src, lastChar);
5294
        incrementGiven = (type != TCL_COMMAND_END);
5295
    }
5296
 
5297
    /*
5298
     * Non-simple names have already been pushed. If this is a simple
5299
     * variable, either push its name (if a global or an unknown local
5300
     * variable) or look up the variable's local frame index. If a local is
5301
     * not found, push its name and do the lookup at runtime. If this is an
5302
     * array reference, also push the array element.
5303
     */
5304
 
5305
    if (simpleVarName) {
5306
        if (procPtr == NULL) {
5307
            savedChar = name[nameChars];
5308
            name[nameChars] = '\0';
5309
            objIndex = TclObjIndexForString(name, nameChars,
5310
                    /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
5311
            name[nameChars] = savedChar;
5312
            TclEmitPush(objIndex, envPtr);
5313
            maxDepth = 1;
5314
        } else {
5315
            localIndex = LookupCompiledLocal(name, nameChars,
5316
                    /*createIfNew*/ 0, /*flagsIfCreated*/ 0,
5317
                    envPtr->procPtr);
5318
            if ((localIndex < 0) || (localIndex > 255)) {
5319
                if (localIndex > 255) {       /* we'll push the name */
5320
                    localIndex = -1;
5321
                }
5322
                savedChar = name[nameChars];
5323
                name[nameChars] = '\0';
5324
                objIndex = TclObjIndexForString(name, nameChars,
5325
                        /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
5326
                name[nameChars] = savedChar;
5327
                TclEmitPush(objIndex, envPtr);
5328
                maxDepth = 1;
5329
            } else {
5330
                maxDepth = 0;
5331
            }
5332
        }
5333
 
5334
        if (elName != NULL) {
5335
            /*
5336
             * Parse and push the array element's name. Perform
5337
             * substitutions on it, just as is done for quoted strings.
5338
             */
5339
 
5340
            savedChar = elName[elNameChars];
5341
            elName[elNameChars] = '\0';
5342
            envPtr->pushSimpleWords = 1;
5343
            result = TclCompileQuotes(interp, elName, elName+elNameChars,
5344
                    0, flags, envPtr);
5345
            elName[elNameChars] = savedChar;
5346
            if (result != TCL_OK) {
5347
                char msg[200];
5348
                sprintf(msg, "\n    (parsing index for array \"%.*s\")",
5349
                        TclMin(nameChars, 100), name);
5350
                Tcl_AddObjErrorInfo(interp, msg, -1);
5351
                goto done;
5352
            }
5353
            maxDepth += envPtr->maxStackDepth;
5354
        }
5355
    }
5356
 
5357
    /*
5358
     * If an increment was given, push the new value.
5359
     */
5360
 
5361
    if (incrementGiven) {
5362
        type = CHAR_TYPE(src, lastChar);
5363
        envPtr->pushSimpleWords = 0;
5364
        result = CompileWord(interp, src, lastChar, flags, envPtr);
5365
        if (result != TCL_OK) {
5366
            if (result == TCL_ERROR) {
5367
                Tcl_AddObjErrorInfo(interp,
5368
                        "\n    (increment expression)", -1);
5369
            }
5370
            goto done;
5371
        }
5372
        if (type & (TCL_QUOTE | TCL_OPEN_BRACE)) {
5373
            src++;
5374
        }
5375
        if (envPtr->wordIsSimple) {
5376
            /*
5377
             * See if the word represents an integer whose formatted
5378
             * representation is the same as the word (e.g., this is
5379
             * true for 123 and -1 but not for 00005). If so, just
5380
             * push an integer object.
5381
             */
5382
 
5383
            int isCompilableInt = 0;
5384
            int numChars = envPtr->numSimpleWordChars;
5385
            char savedChar = src[numChars];
5386
            char buf[40];
5387
            Tcl_Obj *objPtr;
5388
            long n;
5389
 
5390
            src[numChars] = '\0';
5391
            if (TclLooksLikeInt(src)) {
5392
                int code = TclGetLong(interp, src, &n);
5393
                if (code == TCL_OK) {
5394
                    if ((-127 <= n) && (n <= 127)) {
5395
                        isCompilableInt = 1;
5396
                        isImmIncrValue = 1;
5397
                        immIncrValue = n;
5398
                    } else {
5399
                        TclFormatInt(buf, n);
5400
                        if (strcmp(src, buf) == 0) {
5401
                            isCompilableInt = 1;
5402
                            isImmIncrValue = 0;
5403
                            objIndex = TclObjIndexForString(src, numChars,
5404
                                /*allocStrRep*/ 0, /*inHeap*/ 0, envPtr);
5405
                            objPtr = envPtr->objArrayPtr[objIndex];
5406
 
5407
                            Tcl_InvalidateStringRep(objPtr);
5408
                            objPtr->internalRep.longValue = n;
5409
                            objPtr->typePtr = &tclIntType;
5410
 
5411
                            TclEmitPush(objIndex, envPtr);
5412
                            maxDepth += 1;
5413
                        }
5414
                    }
5415
                } else {
5416
                    Tcl_ResetResult(interp);
5417
                }
5418
            }
5419
            if (!isCompilableInt) {
5420
                objIndex = TclObjIndexForString(src, numChars,
5421
                        /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
5422
                TclEmitPush(objIndex, envPtr);
5423
                maxDepth += 1;
5424
            }
5425
            src[numChars] = savedChar;
5426
        } else {
5427
            maxDepth += envPtr->maxStackDepth;
5428
        }
5429
        if (type & (TCL_QUOTE | TCL_OPEN_BRACE)) {
5430
            src += (envPtr->termOffset - 1); /* already advanced 1 above */
5431
        } else {
5432
            src += envPtr->termOffset;
5433
        }
5434
    } else {                    /* no incr amount given so use 1 */
5435
        isImmIncrValue = 1;
5436
        immIncrValue = 1;
5437
    }
5438
 
5439
    /*
5440
     * Now emit instructions to increment the variable.
5441
     */
5442
 
5443
    if (simpleVarName) {
5444
        if (elName == NULL) {  /* scalar */
5445
            if (localIndex >= 0) {
5446
                if (isImmIncrValue) {
5447
                    TclEmitInstUInt1(INST_INCR_SCALAR1_IMM, localIndex,
5448
                                    envPtr);
5449
                    TclEmitInt1(immIncrValue, envPtr);
5450
                } else {
5451
                    TclEmitInstUInt1(INST_INCR_SCALAR1, localIndex, envPtr);
5452
                }
5453
            } else {
5454
                if (isImmIncrValue) {
5455
                    TclEmitInstInt1(INST_INCR_SCALAR_STK_IMM, immIncrValue,
5456
                                   envPtr);
5457
                } else {
5458
                    TclEmitOpcode(INST_INCR_SCALAR_STK, envPtr);
5459
                }
5460
            }
5461
        } else {                /* array */
5462
            if (localIndex >= 0) {
5463
                if (isImmIncrValue) {
5464
                    TclEmitInstUInt1(INST_INCR_ARRAY1_IMM, localIndex,
5465
                                    envPtr);
5466
                    TclEmitInt1(immIncrValue, envPtr);
5467
                } else {
5468
                    TclEmitInstUInt1(INST_INCR_ARRAY1, localIndex, envPtr);
5469
                }
5470
            } else {
5471
                if (isImmIncrValue) {
5472
                    TclEmitInstInt1(INST_INCR_ARRAY_STK_IMM, immIncrValue,
5473
                                   envPtr);
5474
                } else {
5475
                    TclEmitOpcode(INST_INCR_ARRAY_STK, envPtr);
5476
                }
5477
            }
5478
        }
5479
    } else {                    /* non-simple variable name */
5480
        if (isImmIncrValue) {
5481
            TclEmitInstInt1(INST_INCR_STK_IMM, immIncrValue, envPtr);
5482
        } else {
5483
            TclEmitOpcode(INST_INCR_STK, envPtr);
5484
        }
5485
    }
5486
 
5487
    /*
5488
     * Skip over white space until the end of the command.
5489
     */
5490
 
5491
    type = CHAR_TYPE(src, lastChar);
5492
    if (type != TCL_COMMAND_END) {
5493
        AdvanceToNextWord(src, envPtr);
5494
        src += envPtr->termOffset;
5495
        type = CHAR_TYPE(src, lastChar);
5496
        if (type != TCL_COMMAND_END) {
5497
            goto badArgs;
5498
        }
5499
    }
5500
 
5501
    done:
5502
    envPtr->termOffset = (src - string);
5503
    envPtr->maxStackDepth = maxDepth;
5504
    envPtr->pushSimpleWords = savePushSimpleWords;
5505
    return result;
5506
}
5507
 
5508
/*
5509
 *----------------------------------------------------------------------
5510
 *
5511
 * TclCompileSetCmd --
5512
 *
5513
 *      Procedure called to compile the "set" command.
5514
 *
5515
 * Results:
5516
 *      The return value is a standard Tcl result, which is normally TCL_OK
5517
 *      unless there was an error while parsing string. If an error occurs
5518
 *      then the interpreter's result contains a standard error message. If
5519
 *      complation fails because the set command requires a second level of
5520
 *      substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the
5521
 *      set command should be compiled "out of line" by emitting code to
5522
 *      invoke its command procedure (Tcl_SetCmd) at runtime.
5523
 *
5524
 *      envPtr->termOffset is filled in with the offset of the character in
5525
 *      "string" just after the last one successfully processed.
5526
 *
5527
 *      envPtr->maxStackDepth is updated with the maximum number of stack
5528
 *      elements needed to execute the incr command.
5529
 *
5530
 * Side effects:
5531
 *      Instructions are added to envPtr to evaluate the "set" command
5532
 *      at runtime.
5533
 *
5534
 *----------------------------------------------------------------------
5535
 */
5536
 
5537
int
5538
TclCompileSetCmd(interp, string, lastChar, flags, envPtr)
5539
    Tcl_Interp *interp;         /* Used for error reporting. */
5540
    char *string;               /* The source string to compile. */
5541
    char *lastChar;             /* Pointer to terminating character of
5542
                                 * string. */
5543
    int flags;                  /* Flags to control compilation (same as
5544
                                 * passed to Tcl_Eval). */
5545
    CompileEnv *envPtr;         /* Holds resulting instructions. */
5546
{
5547
    Proc *procPtr = envPtr->procPtr;
5548
                                /* Points to structure describing procedure
5549
                                 * containing the set command, else NULL. */
5550
    ArgInfo argInfo;            /* Structure holding information about the
5551
                                 * start and end of each argument word. */
5552
    int simpleVarName;          /* 1 if name is just sequence of chars with
5553
                                 * an optional element name in parens. */
5554
    char *elName = NULL;        /* If simpleVarName, points to first char of
5555
                                 * element name and elNameChars is length.
5556
                                 * Otherwise NULL. */
5557
    int isAssignment;           /* 1 if assigning value to var, else 0. */
5558
    int maxDepth = 0;            /* Maximum number of stack elements needed
5559
                                 * to execute cmd. */
5560
    int localIndex = -1;        /* Index of the variable in the current
5561
                                 * procedure's array of local variables.
5562
                                 * Otherwise -1 if not in a procedure, the
5563
                                 * name contains "::"s, or the variable
5564
                                 * wasn't found. */
5565
    char savedChar;             /* Holds the character from string
5566
                                 * termporarily replaced by a null char
5567
                                 * during name processing. */
5568
    int objIndex = -1;          /* The object array index for a pushed
5569
                                 * object holding a name part. Initialized
5570
                                 * to avoid a compiler warning. */
5571
    char *wordStart, *p;
5572
    int numWords, isCompilableInt, i, result;
5573
    Tcl_Obj *objPtr;
5574
    int savePushSimpleWords = envPtr->pushSimpleWords;
5575
 
5576
    /*
5577
     * Scan the words of the command and record the start and finish of
5578
     * each argument word.
5579
     */
5580
 
5581
    InitArgInfo(&argInfo);
5582
    result = CollectArgInfo(interp, string, lastChar, flags, &argInfo);
5583
    numWords = argInfo.numArgs;   /* i.e., the # after the command name */
5584
    if (result != TCL_OK) {
5585
        goto done;
5586
    }
5587
    if ((numWords < 1) || (numWords > 2)) {
5588
        Tcl_ResetResult(interp);
5589
        Tcl_AppendToObj(Tcl_GetObjResult(interp),
5590
                "wrong # args: should be \"set varName ?newValue?\"", -1);
5591
        result = TCL_ERROR;
5592
        goto done;
5593
    }
5594
    isAssignment = (numWords == 2);
5595
 
5596
    /*
5597
     * Parse the next word: the variable name. If the name is enclosed in
5598
     * quotes or braces, we return TCL_OUT_LINE_COMPILE and call the set
5599
     * command procedure at runtime since this makes sure that a second
5600
     * round of substitutions is done properly.
5601
     */
5602
 
5603
    wordStart = argInfo.startArray[0]; /* start of 1st arg word: varname */
5604
    if ((*wordStart == '{') || (*wordStart == '"')) {
5605
        result = TCL_OUT_LINE_COMPILE;
5606
        goto done;
5607
    }
5608
 
5609
    /*
5610
     * Check whether the name is "simple": requires no substitutions at
5611
     * runtime.
5612
     */
5613
 
5614
    envPtr->pushSimpleWords = 0;
5615
    result = CompileWord(interp, wordStart, argInfo.endArray[0] + 1,
5616
            flags, envPtr);
5617
    if (result != TCL_OK) {
5618
        goto done;
5619
    }
5620
    simpleVarName = envPtr->wordIsSimple;
5621
 
5622
    if (!simpleVarName) {
5623
        /*
5624
         * The name isn't simple. CompileWord already pushed it.
5625
         */
5626
 
5627
        maxDepth = envPtr->maxStackDepth;
5628
    } else {
5629
        char *name;             /* If simpleVarName, points to first char of
5630
                                 * variable name and nameChars is length.
5631
                                 * Otherwise NULL. */
5632
        int nameChars;          /* Length of the var name. */
5633
        int nameHasNsSeparators = 0;
5634
                                /* Set 1 if name contains "::"s. */
5635
        int elNameChars;        /* Length of array's element name if any. */
5636
 
5637
        /*
5638
         * A simple name. First divide it up into "name" plus "elName"
5639
         * for an array element name, if any.
5640
         */
5641
 
5642
        name = wordStart;
5643
        nameChars = envPtr->numSimpleWordChars;
5644
        elName = NULL;
5645
        elNameChars = 0;
5646
 
5647
        p = name;
5648
        for (i = 0;  i < nameChars;  i++) {
5649
            if (*p == '(') {
5650
                char *openParen = p;
5651
                p = (name + nameChars-1);
5652
                if (*p == ')') { /* last char is ')' => array reference */
5653
                    nameChars = (openParen - name);
5654
                    elName = openParen+1;
5655
                    elNameChars = (p - elName);
5656
                }
5657
                break;
5658
            }
5659
            p++;
5660
        }
5661
 
5662
        /*
5663
         * Determine if name has any namespace separators (::'s).
5664
         */
5665
 
5666
        p = name;
5667
        for (i = 0;  i < nameChars;  i++) {
5668
            if ((*p == ':') && ((i+1) < nameChars) && (*(p+1) == ':')) {
5669
                nameHasNsSeparators = 1;
5670
                break;
5671
            }
5672
            p++;
5673
        }
5674
 
5675
        /*
5676
         * Now either push the name or determine its index in the array of
5677
         * local variables in a procedure frame. Note that if we are
5678
         * compiling a procedure the variable must be local unless its
5679
         * name has namespace separators ("::"s). Note also that global
5680
         * variables are implemented by a local variable that "points" to
5681
         * the real global. There are two cases:
5682
         *   1) We are not compiling a procedure body. Push the global
5683
         *      variable's name and do the lookup at runtime.
5684
         *   2) We are compiling a procedure and the name has "::"s.
5685
         *      Push the namespace variable's name and do the lookup at
5686
         *      runtime.
5687
         *   3) We are compiling a procedure and the name has no "::"s.
5688
         *      If the variable has already been allocated an local index,
5689
         *      just look it up. If the variable is unknown and we are
5690
         *      doing an assignment, allocate a new index. Otherwise,
5691
         *      push the name and try to do the lookup at runtime.
5692
         */
5693
 
5694
        if ((procPtr == NULL) || nameHasNsSeparators) {
5695
            savedChar = name[nameChars];
5696
            name[nameChars] = '\0';
5697
            objIndex = TclObjIndexForString(name, nameChars,
5698
                    /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
5699
            name[nameChars] = savedChar;
5700
            TclEmitPush(objIndex, envPtr);
5701
            maxDepth = 1;
5702
        } else {
5703
            localIndex = LookupCompiledLocal(name, nameChars,
5704
                    /*createIfNew*/ isAssignment,
5705
                    /*flagsIfCreated*/
5706
                        ((elName == NULL)? VAR_SCALAR : VAR_ARRAY),
5707
                    envPtr->procPtr);
5708
            if (localIndex >= 0) {
5709
                maxDepth = 0;
5710
            } else {
5711
                savedChar = name[nameChars];
5712
                name[nameChars] = '\0';
5713
                objIndex = TclObjIndexForString(name, nameChars,
5714
                        /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
5715
                name[nameChars] = savedChar;
5716
                TclEmitPush(objIndex, envPtr);
5717
                maxDepth = 1;
5718
            }
5719
        }
5720
 
5721
        /*
5722
         * If we are dealing with a reference to an array element, push the
5723
         * array element. Perform substitutions on it, just as is done
5724
         * for quoted strings.
5725
         */
5726
 
5727
        if (elName != NULL) {
5728
            savedChar = elName[elNameChars];
5729
            elName[elNameChars] = '\0';
5730
            envPtr->pushSimpleWords = 1;
5731
            result = TclCompileQuotes(interp, elName, elName+elNameChars,
5732
                    0, flags, envPtr);
5733
            elName[elNameChars] = savedChar;
5734
            if (result != TCL_OK) {
5735
                char msg[200];
5736
                sprintf(msg, "\n    (parsing index for array \"%.*s\")",
5737
                        TclMin(nameChars, 100), name);
5738
                Tcl_AddObjErrorInfo(interp, msg, -1);
5739
                goto done;
5740
            }
5741
            maxDepth += envPtr->maxStackDepth;
5742
        }
5743
    }
5744
 
5745
    /*
5746
     * If we are doing an assignment, push the new value.
5747
     */
5748
 
5749
    if (isAssignment) {
5750
        wordStart = argInfo.startArray[1]; /* start of 2nd arg word */
5751
        envPtr->pushSimpleWords = 0;       /* we will handle simple words */
5752
        result = CompileWord(interp, wordStart, argInfo.endArray[1] + 1,
5753
                flags, envPtr);
5754
        if (result != TCL_OK) {
5755
            goto done;
5756
        }
5757
        if (!envPtr->wordIsSimple) {
5758
            /*
5759
             * The value isn't simple. CompileWord already pushed it.
5760
             */
5761
 
5762
            maxDepth += envPtr->maxStackDepth;
5763
        } else {
5764
            /*
5765
             * The value is simple. See if the word represents an integer
5766
             * whose formatted representation is the same as the word (e.g.,
5767
             * this is true for 123 and -1 but not for 00005). If so, just
5768
             * push an integer object.
5769
             */
5770
 
5771
            char buf[40];
5772
            long n;
5773
 
5774
            p = wordStart;
5775
            if ((*wordStart == '"') || (*wordStart == '{')) {
5776
                p++;
5777
            }
5778
            savedChar = p[envPtr->numSimpleWordChars];
5779
            p[envPtr->numSimpleWordChars] = '\0';
5780
            isCompilableInt = 0;
5781
            if (TclLooksLikeInt(p)) {
5782
                int code = TclGetLong(interp, p, &n);
5783
                if (code == TCL_OK) {
5784
                    TclFormatInt(buf, n);
5785
                    if (strcmp(p, buf) == 0) {
5786
                        isCompilableInt = 1;
5787
                        objIndex = TclObjIndexForString(p,
5788
                                envPtr->numSimpleWordChars,
5789
                                /*allocStrRep*/ 0, /*inHeap*/ 0, envPtr);
5790
                        objPtr = envPtr->objArrayPtr[objIndex];
5791
 
5792
                        Tcl_InvalidateStringRep(objPtr);
5793
                        objPtr->internalRep.longValue = n;
5794
                        objPtr->typePtr = &tclIntType;
5795
                    }
5796
                } else {
5797
                    Tcl_ResetResult(interp);
5798
                }
5799
            }
5800
            if (!isCompilableInt) {
5801
                objIndex = TclObjIndexForString(p,
5802
                        envPtr->numSimpleWordChars, /*allocStrRep*/ 1,
5803
                        /*inHeap*/ 0, envPtr);
5804
            }
5805
            p[envPtr->numSimpleWordChars] = savedChar;
5806
            TclEmitPush(objIndex, envPtr);
5807
            maxDepth += 1;
5808
        }
5809
    }
5810
 
5811
    /*
5812
     * Now emit instructions to set/retrieve the variable.
5813
     */
5814
 
5815
    if (simpleVarName) {
5816
        if (elName == NULL) {  /* scalar */
5817
            if (localIndex >= 0) {
5818
                if (localIndex <= 255) {
5819
                    TclEmitInstUInt1((isAssignment?
5820
                             INST_STORE_SCALAR1 : INST_LOAD_SCALAR1),
5821
                        localIndex, envPtr);
5822
                } else {
5823
                    TclEmitInstUInt4((isAssignment?
5824
                             INST_STORE_SCALAR4 : INST_LOAD_SCALAR4),
5825
                        localIndex, envPtr);
5826
                }
5827
            } else {
5828
                TclEmitOpcode((isAssignment?
5829
                             INST_STORE_SCALAR_STK : INST_LOAD_SCALAR_STK),
5830
                            envPtr);
5831
            }
5832
        } else {                /* array */
5833
            if (localIndex >= 0) {
5834
                if (localIndex <= 255) {
5835
                    TclEmitInstUInt1((isAssignment?
5836
                             INST_STORE_ARRAY1 : INST_LOAD_ARRAY1),
5837
                        localIndex, envPtr);
5838
                } else {
5839
                    TclEmitInstUInt4((isAssignment?
5840
                             INST_STORE_ARRAY4 : INST_LOAD_ARRAY4),
5841
                        localIndex, envPtr);
5842
                }
5843
            } else {
5844
                TclEmitOpcode((isAssignment?
5845
                             INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK),
5846
                            envPtr);
5847
            }
5848
        }
5849
    } else {                    /* non-simple variable name */
5850
        TclEmitOpcode((isAssignment? INST_STORE_STK : INST_LOAD_STK), envPtr);
5851
    }
5852
 
5853
    done:
5854
    if (numWords == 0) {
5855
        envPtr->termOffset = 0;
5856
    } else {
5857
        envPtr->termOffset = (argInfo.endArray[numWords-1] + 1 - string);
5858
    }
5859
    envPtr->pushSimpleWords = savePushSimpleWords;
5860
    envPtr->maxStackDepth = maxDepth;
5861
    FreeArgInfo(&argInfo);
5862
    return result;
5863
}
5864
 
5865
/*
5866
 *----------------------------------------------------------------------
5867
 *
5868
 * TclCompileWhileCmd --
5869
 *
5870
 *      Procedure called to compile the "while" command.
5871
 *
5872
 * Results:
5873
 *      The return value is a standard Tcl result, which is TCL_OK if
5874
 *      compilation was successful. If an error occurs then the
5875
 *      interpreter's result contains a standard error message and TCL_ERROR
5876
 *      is returned. If compilation failed because the command is too
5877
 *      complex for TclCompileWhileCmd, TCL_OUT_LINE_COMPILE is returned
5878
 *      indicating that the while command should be compiled "out of line"
5879
 *      by emitting code to invoke its command procedure at runtime.
5880
 *
5881
 *      envPtr->termOffset is filled in with the offset of the character in
5882
 *      "string" just after the last one successfully processed.
5883
 *
5884
 *      envPtr->maxStackDepth is updated with the maximum number of stack
5885
 *      elements needed to execute the "while" command.
5886
 *
5887
 * Side effects:
5888
 *      Instructions are added to envPtr to evaluate the "while" command
5889
 *      at runtime.
5890
 *
5891
 *----------------------------------------------------------------------
5892
 */
5893
 
5894
int
5895
TclCompileWhileCmd(interp, string, lastChar, flags, envPtr)
5896
    Tcl_Interp *interp;         /* Used for error reporting. */
5897
    char *string;               /* The source string to compile. */
5898
    char *lastChar;              /* Pointer to terminating character of
5899
                                  * string. */
5900
    int flags;                  /* Flags to control compilation (same as
5901
                                 * passed to Tcl_Eval). */
5902
    CompileEnv *envPtr;         /* Holds resulting instructions. */
5903
{
5904
    register char *src = string;/* Points to current source char. */
5905
    register int type;          /* Current char's CHAR_TYPE type. */
5906
    int maxDepth = 0;            /* Maximum number of stack elements needed
5907
                                 * to execute cmd. */
5908
    int range = -1;             /* Index in the ExceptionRange array of the
5909
                                 * ExceptionRange record for this loop. */
5910
    JumpFixup jumpFalseFixup;   /* Used to update or replace the ifFalse
5911
                                 * jump after test when its target PC is
5912
                                 * determined. */
5913
    unsigned char *jumpPc;
5914
    int jumpDist, jumpBackDist, jumpBackOffset, objIndex, result;
5915
    int savePushSimpleWords = envPtr->pushSimpleWords;
5916
 
5917
    AdvanceToNextWord(src, envPtr);
5918
    src += envPtr->termOffset;
5919
    type = CHAR_TYPE(src, lastChar);
5920
    if (type == TCL_COMMAND_END) {
5921
        badArgs:
5922
        Tcl_ResetResult(interp);
5923
        Tcl_AppendToObj(Tcl_GetObjResult(interp),
5924
                "wrong # args: should be \"while test command\"", -1);
5925
        result = TCL_ERROR;
5926
        goto done;
5927
    }
5928
 
5929
    /*
5930
     * If the test expression is not enclosed in braces, don't compile
5931
     * the while inline. As a result of Tcl's two level substitution
5932
     * semantics for expressions, the expression might have a constant
5933
     * value that results in the loop never executing, or executing forever.
5934
     * Consider "set x 0; whie "$x > 5" {incr x}": the loop body
5935
     * should never be executed.
5936
     * NOTE: This is an overly aggressive test, since there are legitimate
5937
     * literals that could be compiled but aren't in braces.  However, until
5938
     * the parser is integrated in 8.1, this is the simplest implementation.
5939
     */
5940
 
5941
    if (*src != '{') {
5942
        result = TCL_OUT_LINE_COMPILE;
5943
        goto done;
5944
    }
5945
 
5946
    /*
5947
     * Create and initialize a ExceptionRange record to hold information
5948
     * about this loop. This is used to implement break and continue.
5949
     */
5950
 
5951
    envPtr->excRangeDepth++;
5952
    envPtr->maxExcRangeDepth =
5953
        TclMax(envPtr->excRangeDepth, envPtr->maxExcRangeDepth);
5954
 
5955
    range = CreateExceptionRange(LOOP_EXCEPTION_RANGE, envPtr);
5956
    envPtr->excRangeArrayPtr[range].continueOffset = TclCurrCodeOffset();
5957
 
5958
    /*
5959
     * Compile the next word: the test expression.
5960
     */
5961
 
5962
    envPtr->pushSimpleWords = 1;
5963
    result = CompileExprWord(interp, src, lastChar, flags, envPtr);
5964
    if (result != TCL_OK) {
5965
        if (result == TCL_ERROR) {
5966
            Tcl_AddObjErrorInfo(interp,
5967
                    "\n    (\"while\" test expression)", -1);
5968
        }
5969
        goto done;
5970
    }
5971
    maxDepth = envPtr->maxStackDepth;
5972
    src += envPtr->termOffset;
5973
 
5974
    /*
5975
     * Emit the ifFalse jump that terminates the while if the test was
5976
     * false. We emit a one byte (relative) jump here, and replace it
5977
     * later with a four byte jump if the jump target is more than
5978
     * 127 bytes away.
5979
     */
5980
 
5981
    TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFalseFixup);
5982
 
5983
    /*
5984
     * Compile the loop body word inline. Also register the loop body's
5985
     * starting PC offset and byte length in the its ExceptionRange record.
5986
     */
5987
 
5988
    AdvanceToNextWord(src, envPtr);
5989
    src += envPtr->termOffset;
5990
    type = CHAR_TYPE(src, lastChar);
5991
    if (type == TCL_COMMAND_END) {
5992
        goto badArgs;
5993
    }
5994
 
5995
    envPtr->excRangeArrayPtr[range].codeOffset = TclCurrCodeOffset();
5996
    result = CompileCmdWordInline(interp, src, lastChar,
5997
            flags, envPtr);
5998
    if (result != TCL_OK) {
5999
        if (result == TCL_ERROR) {
6000
            char msg[60];
6001
            sprintf(msg, "\n    (\"while\" body line %d)", interp->errorLine);
6002
            Tcl_AddObjErrorInfo(interp, msg, -1);
6003
        }
6004
        goto done;
6005
    }
6006
    maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
6007
    src += envPtr->termOffset;
6008
    envPtr->excRangeArrayPtr[range].numCodeBytes =
6009
        (TclCurrCodeOffset() - envPtr->excRangeArrayPtr[range].codeOffset);
6010
 
6011
    /*
6012
     * Discard the loop body's result.
6013
     */
6014
 
6015
    TclEmitOpcode(INST_POP, envPtr);
6016
 
6017
    /*
6018
     * Emit the unconditional jump back to the test at the top of the
6019
     * loop. We generate a four byte jump if the distance to the while's
6020
     * test is greater than 120 bytes. This is conservative, and ensures
6021
     * that we won't have to replace this unconditional jump if we later
6022
     * need to replace the ifFalse jump with a four-byte jump.
6023
     */
6024
 
6025
    jumpBackOffset = TclCurrCodeOffset();
6026
    jumpBackDist =
6027
        (jumpBackOffset - envPtr->excRangeArrayPtr[range].continueOffset);
6028
    if (jumpBackDist > 120) {
6029
        TclEmitInstInt4(INST_JUMP4, /*offset*/ -jumpBackDist, envPtr);
6030
    } else {
6031
        TclEmitInstInt1(INST_JUMP1, /*offset*/ -jumpBackDist, envPtr);
6032
    }
6033
 
6034
    /*
6035
     * Now that we know the target of the jumpFalse after the test, update
6036
     * it with the correct distance. If the distance is too great (more
6037
     * than 127 bytes), replace that jump with a four byte instruction and
6038
     * move the instructions after the jump down.
6039
     */
6040
 
6041
    jumpDist = (TclCurrCodeOffset() - jumpFalseFixup.codeOffset);
6042
    if (TclFixupForwardJump(envPtr, &jumpFalseFixup, jumpDist, 127)) {
6043
        /*
6044
         * Update the loop body's starting PC offset since it moved down.
6045
         */
6046
 
6047
        envPtr->excRangeArrayPtr[range].codeOffset += 3;
6048
 
6049
        /*
6050
         * Update the distance for the unconditional jump back to the test
6051
         * at the top of the loop since it moved down 3 bytes too.
6052
         */
6053
 
6054
        jumpBackOffset += 3;
6055
        jumpPc = (envPtr->codeStart + jumpBackOffset);
6056
        if (jumpBackDist > 120) {
6057
            jumpBackDist += 3;
6058
            TclUpdateInstInt4AtPc(INST_JUMP4, /*offset*/ -jumpBackDist,
6059
                                   jumpPc);
6060
        } else {
6061
            jumpBackDist += 3;
6062
            TclUpdateInstInt1AtPc(INST_JUMP1, /*offset*/ -jumpBackDist,
6063
                                   jumpPc);
6064
        }
6065
    }
6066
 
6067
    /*
6068
     * The current PC offset (after the loop's body) is the loop's
6069
     * break target.
6070
     */
6071
 
6072
    envPtr->excRangeArrayPtr[range].breakOffset = TclCurrCodeOffset();
6073
 
6074
    /*
6075
     * Push an empty string object as the while command's result.
6076
     */
6077
 
6078
    objIndex = TclObjIndexForString("", 0, /*allocStrRep*/ 0, /*inHeap*/ 0,
6079
                                    envPtr);
6080
    TclEmitPush(objIndex, envPtr);
6081
    if (maxDepth == 0) {
6082
        maxDepth = 1;
6083
    }
6084
 
6085
    /*
6086
     * Skip over white space until the end of the command.
6087
     */
6088
 
6089
    type = CHAR_TYPE(src, lastChar);
6090
    if (type != TCL_COMMAND_END) {
6091
        AdvanceToNextWord(src, envPtr);
6092
        src += envPtr->termOffset;
6093
        type = CHAR_TYPE(src, lastChar);
6094
        if (type != TCL_COMMAND_END) {
6095
            goto badArgs;
6096
        }
6097
    }
6098
 
6099
    done:
6100
    envPtr->termOffset = (src - string);
6101
    envPtr->pushSimpleWords = savePushSimpleWords;
6102
    envPtr->maxStackDepth = maxDepth;
6103
    if (range != -1) {
6104
        envPtr->excRangeDepth--;
6105
    }
6106
    return result;
6107
}
6108
 
6109
/*
6110
 *----------------------------------------------------------------------
6111
 *
6112
 * CompileExprWord --
6113
 *
6114
 *      Procedure that compiles a Tcl expression in a command word.
6115
 *
6116
 * Results:
6117
 *      The return value is a standard Tcl result, which is TCL_OK unless
6118
 *      there was an error while compiling string. If an error occurs then
6119
 *      the interpreter's result contains a standard error message.
6120
 *
6121
 *      envPtr->termOffset is filled in with the offset of the character in
6122
 *      "string" just after the last one successfully processed.
6123
 *
6124
 *      envPtr->maxStackDepth is updated with the maximum number of stack
6125
 *      elements needed to execute the "expr" word.
6126
 *
6127
 * Side effects:
6128
 *      Instructions are added to envPtr to evaluate the expression word
6129
 *      at runtime.
6130
 *
6131
 *----------------------------------------------------------------------
6132
 */
6133
 
6134
static int
6135
CompileExprWord(interp, string, lastChar, flags, envPtr)
6136
    Tcl_Interp *interp;         /* Used for error reporting. */
6137
    char *string;               /* The source string to compile. */
6138
    char *lastChar;              /* Pointer to terminating character of
6139
                                  * string. */
6140
    int flags;                  /* Flags to control compilation (same as
6141
                                 * passed to Tcl_Eval). */
6142
    CompileEnv *envPtr;         /* Holds resulting instructions. */
6143
{
6144
    register char *src = string;/* Points to current source char. */
6145
    register int type;          /* Current char's CHAR_TYPE type. */
6146
    int maxDepth = 0;            /* Maximum number of stack elements needed
6147
                                 * to execute the expression. */
6148
    int nestedCmd = (flags & TCL_BRACKET_TERM);
6149
                                /* 1 if script being compiled is a nested
6150
                                 * command and is terminated by a ']';
6151
                                 * otherwise 0. */
6152
    char *first, *last;         /* Points to the first and last significant
6153
                                 * characters of the word. */
6154
    char savedChar;             /* Holds the character termporarily replaced
6155
                                 * by a null character during compilation
6156
                                 * of the expression. */
6157
    int inlineCode;             /* 1 if inline "optimistic" code is
6158
                                 * emitted for the expression; else 0. */
6159
    int range = -1;             /* If we inline compile an un-{}'d
6160
                                 * expression, the index for its catch range
6161
                                 * record in the ExceptionRange array.
6162
                                 * Initialized to enable proper cleanup. */
6163
    JumpFixup jumpFixup;        /* Used to emit the "success" jump after
6164
                                 * the inline expression code. */
6165
    char *p;
6166
    char c;
6167
    int savePushSimpleWords = envPtr->pushSimpleWords;
6168
    int saveExprIsJustVarRef = envPtr->exprIsJustVarRef;
6169
    int saveExprIsComparison = envPtr->exprIsComparison;
6170
    int numChars, result;
6171
 
6172
    /*
6173
     * Skip over leading white space.
6174
     */
6175
 
6176
    AdvanceToNextWord(src, envPtr);
6177
    src += envPtr->termOffset;
6178
    type = CHAR_TYPE(src, lastChar);
6179
    if (type == TCL_COMMAND_END) {
6180
        badArgs:
6181
        Tcl_ResetResult(interp);
6182
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
6183
                    "malformed expression word", -1);
6184
        result = TCL_ERROR;
6185
        goto done;
6186
    }
6187
 
6188
    /*
6189
     * If the word is enclosed in {}s, we may strip them off and safely
6190
     * compile the expression into an inline sequence of instructions using
6191
     * TclCompileExpr. We know these instructions will have the right Tcl7.x
6192
     * expression semantics.
6193
     *
6194
     * Otherwise, if the word is not enclosed in {}s, we may need to call
6195
     * the expr command (Tcl_ExprObjCmd) at runtime. This recompiles the
6196
     * expression each time (typically) and so is slow. However, there are
6197
     * some circumstances where we can still compile inline instructions
6198
     * "optimistically" and check, during their execution, for double
6199
     * substitutions (these appear as nonnumeric operands). We check for any
6200
     * backslash or command substitutions. If none appear, and only variable
6201
     * substitutions are found, we generate inline instructions.
6202
     *
6203
     * For now, if the expression is not enclosed in {}s, we call the expr
6204
     * command at runtime if either command or backslash substitutions
6205
     * appear (but not if only variable substitutions appear).
6206
     */
6207
 
6208
    if (*src == '{') {
6209
        /*
6210
         * Inline compile the expression inside {}s.
6211
         */
6212
 
6213
        first = src+1;
6214
        src = TclWordEnd(src, lastChar, nestedCmd, NULL);
6215
        if (*src == 0) {
6216
            goto badArgs;
6217
        }
6218
        if (*src != '}') {
6219
            goto badArgs;
6220
        }
6221
        last = (src-1);
6222
 
6223
        numChars = (last - first + 1);
6224
        savedChar = first[numChars];
6225
        first[numChars] = '\0';
6226
        result = TclCompileExpr(interp, first, first+numChars,
6227
                flags, envPtr);
6228
        first[numChars] = savedChar;
6229
 
6230
        src++;
6231
        maxDepth = envPtr->maxStackDepth;
6232
    } else {
6233
        /*
6234
         * No braces. If the expression is enclosed in '"'s, call the expr
6235
         * cmd at runtime. Otherwise, scan the word's characters looking for
6236
         * any '['s or (for now) '\'s. If any are found, just call expr cmd
6237
         * at runtime.
6238
         */
6239
 
6240
        first = src;
6241
        last = TclWordEnd(first, lastChar, nestedCmd, NULL);
6242
        if (*last == 0) {        /* word doesn't end properly. */
6243
            src = last;
6244
            goto badArgs;
6245
        }
6246
 
6247
        inlineCode = 1;
6248
        if ((*first == '"') && (*last == '"')) {
6249
            inlineCode = 0;
6250
        } else {
6251
            for (p = first;  p <= last;  p++) {
6252
                c = *p;
6253
                if ((c == '[') || (c == '\\')) {
6254
                    inlineCode = 0;
6255
                    break;
6256
                }
6257
            }
6258
        }
6259
 
6260
        if (inlineCode) {
6261
            /*
6262
             * Inline compile the expression inside a "catch" so that a
6263
             * runtime error will back off to make a (slow) call on expr.
6264
             */
6265
 
6266
            int startCodeOffset = (envPtr->codeNext - envPtr->codeStart);
6267
            int startRangeNext = envPtr->excRangeArrayNext;
6268
 
6269
            /*
6270
             * Create a ExceptionRange record to hold information about
6271
             * the "catch" range for the expression's inline code. Also
6272
             * emit the instruction to mark the start of the range.
6273
             */
6274
 
6275
            envPtr->excRangeDepth++;
6276
            envPtr->maxExcRangeDepth =
6277
                TclMax(envPtr->excRangeDepth, envPtr->maxExcRangeDepth);
6278
            range = CreateExceptionRange(CATCH_EXCEPTION_RANGE, envPtr);
6279
            TclEmitInstUInt4(INST_BEGIN_CATCH4, range, envPtr);
6280
 
6281
            /*
6282
             * Inline compile the expression.
6283
             */
6284
 
6285
            envPtr->excRangeArrayPtr[range].codeOffset = TclCurrCodeOffset();
6286
            numChars = (last - first + 1);
6287
            savedChar = first[numChars];
6288
            first[numChars] = '\0';
6289
            result = TclCompileExpr(interp, first, first + numChars,
6290
                    flags, envPtr);
6291
            first[numChars] = savedChar;
6292
 
6293
            envPtr->excRangeArrayPtr[range].numCodeBytes =
6294
                TclCurrCodeOffset() - envPtr->excRangeArrayPtr[range].codeOffset;
6295
 
6296
            if ((result != TCL_OK) || (envPtr->exprIsJustVarRef)
6297
                    || (envPtr->exprIsComparison)) {
6298
                /*
6299
                 * We must call the expr command at runtime. Either there
6300
                 * was a compilation error or the inline code might fail to
6301
                 * give the correct 2 level substitution semantics.
6302
                 *
6303
                 * The latter can happen if the expression consisted of just
6304
                 * a single variable reference or if the top-level operator
6305
                 * in the expr is a comparison (which might operate on
6306
                 * strings). In the latter case, the expression's code might
6307
                 * execute (apparently) successfully but produce the wrong
6308
                 * result. We depend on its execution failing if a second
6309
                 * level of substitutions is required. This causes the
6310
                 * "catch" code we generate around the inline code to back
6311
                 * off to a call on the expr command at runtime, and this
6312
                 * always gives the right 2 level substitution semantics.
6313
                 *
6314
                 * We delete the inline code by backing up the code pc and
6315
                 * catch index. Note that if there was a compilation error,
6316
                 * we can't report the error yet since the expression might
6317
                 * be valid after the second round of substitutions.
6318
                 */
6319
 
6320
                envPtr->codeNext = (envPtr->codeStart + startCodeOffset);
6321
                envPtr->excRangeArrayNext = startRangeNext;
6322
                inlineCode = 0;
6323
            } else {
6324
                TclEmitOpcode(INST_END_CATCH, envPtr);
6325
                TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
6326
                envPtr->excRangeArrayPtr[range].catchOffset = TclCurrCodeOffset();
6327
            }
6328
        }
6329
 
6330
        /*
6331
         * Arrange to call expr at runtime with the (already substituted
6332
         * once) expression word on the stack.
6333
         */
6334
 
6335
        envPtr->pushSimpleWords = 1;
6336
        result = CompileWord(interp, first, lastChar, flags, envPtr);
6337
        src += envPtr->termOffset;
6338
        maxDepth = envPtr->maxStackDepth;
6339
        if (result == TCL_OK) {
6340
            TclEmitOpcode(INST_EXPR_STK, envPtr);
6341
        }
6342
 
6343
        /*
6344
         * If emitting inline code for this non-{}'d expression, update
6345
         * the target of the jump after that inline code.
6346
         */
6347
 
6348
        if (inlineCode) {
6349
            int jumpDist = (TclCurrCodeOffset() - jumpFixup.codeOffset);
6350
            if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) {
6351
                /*
6352
                 * Update the inline expression code's catch ExceptionRange
6353
                 * target since it, being after the jump, also moved down.
6354
                 */
6355
 
6356
                envPtr->excRangeArrayPtr[range].catchOffset += 3;
6357
            }
6358
        }
6359
    } /* if expression isn't in {}s */
6360
 
6361
    done:
6362
    if (range != -1) {
6363
        envPtr->excRangeDepth--;
6364
    }
6365
    envPtr->termOffset = (src - string);
6366
    envPtr->maxStackDepth = maxDepth;
6367
    envPtr->pushSimpleWords = savePushSimpleWords;
6368
    envPtr->exprIsJustVarRef = saveExprIsJustVarRef;
6369
    envPtr->exprIsComparison = saveExprIsComparison;
6370
    return result;
6371
}
6372
 
6373
/*
6374
 *----------------------------------------------------------------------
6375
 *
6376
 * CompileCmdWordInline --
6377
 *
6378
 *      Procedure that compiles a Tcl command word inline. If the word is
6379
 *      enclosed in quotes or braces, we call TclCompileString to compile it
6380
 *      after stripping them off. Otherwise, we normally push the word's
6381
 *      value and call eval at runtime, but if the word is just a sequence
6382
 *      of alphanumeric characters, we emit an invoke instruction
6383
 *      directly. This procedure assumes that string points to the start of
6384
 *      the word to compile.
6385
 *
6386
 * Results:
6387
 *      The return value is a standard Tcl result, which is TCL_OK unless
6388
 *      there was an error while compiling string. If an error occurs then
6389
 *      the interpreter's result contains a standard error message.
6390
 *
6391
 *      envPtr->termOffset is filled in with the offset of the character in
6392
 *      "string" just after the last one successfully processed.
6393
 *
6394
 *      envPtr->maxStackDepth is updated with the maximum number of stack
6395
 *      elements needed to execute the command.
6396
 *
6397
 * Side effects:
6398
 *      Instructions are added to envPtr to execute the command word
6399
 *      at runtime.
6400
 *
6401
 *----------------------------------------------------------------------
6402
 */
6403
 
6404
static int
6405
CompileCmdWordInline(interp, string, lastChar, flags, envPtr)
6406
    Tcl_Interp *interp;         /* Used for error reporting. */
6407
    char *string;               /* The source string to compile. */
6408
    char *lastChar;             /* Pointer to terminating character of
6409
                                 * string. */
6410
    int flags;                  /* Flags to control compilation (same as
6411
                                 * passed to Tcl_Eval). */
6412
    CompileEnv *envPtr;         /* Holds resulting instructions. */
6413
{
6414
    Interp *iPtr = (Interp *) interp;
6415
    register char *src = string;/* Points to current source char. */
6416
    register int type;          /* Current char's CHAR_TYPE type. */
6417
    int maxDepth = 0;            /* Maximum number of stack elements needed
6418
                                 * to execute cmd. */
6419
    char *termPtr;              /* Points to char that terminated braced
6420
                                 * string. */
6421
    char savedChar;             /* Holds the character termporarily replaced
6422
                                 * by a null character during compilation
6423
                                 * of the command. */
6424
    int savePushSimpleWords = envPtr->pushSimpleWords;
6425
    int objIndex;
6426
    int result = TCL_OK;
6427
    register char c;
6428
 
6429
    type = CHAR_TYPE(src, lastChar);
6430
    if (type & (TCL_QUOTE | TCL_OPEN_BRACE)) {
6431
        src++;
6432
        envPtr->pushSimpleWords = 0;
6433
        if (type == TCL_QUOTE) {
6434
            result = TclCompileQuotes(interp, src, lastChar,
6435
                    '"', flags, envPtr);
6436
        } else {
6437
            result = CompileBraces(interp, src, lastChar, flags, envPtr);
6438
        }
6439
        if (result != TCL_OK) {
6440
            goto done;
6441
        }
6442
 
6443
        /*
6444
         * Make sure the terminating character is the end of word.
6445
         */
6446
 
6447
        termPtr = (src + envPtr->termOffset);
6448
        c = *termPtr;
6449
        if ((c == '\\') && (*(termPtr+1) == '\n')) {
6450
            /*
6451
             * Line is continued on next line; the backslash-newline turns
6452
             * into space, which terminates the word.
6453
             */
6454
        } else {
6455
            type = CHAR_TYPE(termPtr, lastChar);
6456
            if ((type != TCL_SPACE) && (type != TCL_COMMAND_END)) {
6457
                Tcl_ResetResult(interp);
6458
                if (*(src-1) == '"') {
6459
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
6460
                            "extra characters after close-quote", -1);
6461
                } else {
6462
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
6463
                            "extra characters after close-brace", -1);
6464
                }
6465
                result = TCL_ERROR;
6466
                goto done;
6467
            }
6468
        }
6469
 
6470
        if (envPtr->wordIsSimple) {
6471
            /*
6472
             * A simple word enclosed in "" or {}s. Call TclCompileString to
6473
             * compile it inline. Add a null character after the end of the
6474
             * quoted or braced string: i.e., at the " or }. Turn the
6475
             * flag bit TCL_BRACKET_TERM off since the recursively
6476
             * compiled subcommand is now terminated by a null character.
6477
             */
6478
            char *closeCharPos = (termPtr - 1);
6479
 
6480
            savedChar = *closeCharPos;
6481
            *closeCharPos = '\0';
6482
            result = TclCompileString(interp, src, closeCharPos,
6483
                    (flags & ~TCL_BRACKET_TERM), envPtr);
6484
            *closeCharPos = savedChar;
6485
            if (result != TCL_OK) {
6486
                goto done;
6487
            }
6488
        } else {
6489
            /*
6490
             * The braced string contained a backslash-newline. Call eval
6491
             * at runtime.
6492
             */
6493
            TclEmitOpcode(INST_EVAL_STK, envPtr);
6494
        }
6495
        src = termPtr;
6496
        maxDepth = envPtr->maxStackDepth;
6497
    } else {
6498
        /*
6499
         * Not a braced or quoted string. We normally push the word's
6500
         * value and call eval at runtime. However, if the word is just
6501
         * a sequence of alphanumeric characters, we call its compile
6502
         * procedure, if any, or otherwise just emit an invoke instruction.
6503
         */
6504
 
6505
        char *p = src;
6506
        c = *p;
6507
        while (isalnum(UCHAR(c)) || (c == '_')) {
6508
            p++;
6509
            c = *p;
6510
        }
6511
        type = CHAR_TYPE(p, lastChar);
6512
        if ((p > src) && (type == TCL_COMMAND_END)) {
6513
            /*
6514
             * Look for a compile procedure and call it. Otherwise emit an
6515
             * invoke instruction to call the command at runtime.
6516
             */
6517
 
6518
            Tcl_Command cmd;
6519
            Command *cmdPtr = NULL;
6520
            int wasCompiled = 0;
6521
 
6522
            savedChar = *p;
6523
            *p = '\0';
6524
 
6525
            cmd = Tcl_FindCommand(interp, src, (Tcl_Namespace *) NULL,
6526
                    /*flags*/ 0);
6527
            if (cmd != (Tcl_Command) NULL) {
6528
                cmdPtr = (Command *) cmd;
6529
            }
6530
            if (cmdPtr != NULL && cmdPtr->compileProc != NULL) {
6531
                *p = savedChar;
6532
                src = p;
6533
                iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS
6534
                                 | ERROR_CODE_SET);
6535
                result = (*(cmdPtr->compileProc))(interp, src, lastChar, flags, envPtr);
6536
                if (result != TCL_OK) {
6537
                    goto done;
6538
                }
6539
                wasCompiled = 1;
6540
                src += envPtr->termOffset;
6541
                maxDepth = envPtr->maxStackDepth;
6542
            }
6543
            if (!wasCompiled) {
6544
                objIndex = TclObjIndexForString(src, p-src,
6545
                        /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
6546
                *p = savedChar;
6547
                TclEmitPush(objIndex, envPtr);
6548
                TclEmitInstUInt1(INST_INVOKE_STK1, 1, envPtr);
6549
                src = p;
6550
                maxDepth = 1;
6551
            }
6552
        } else {
6553
            /*
6554
             * Push the word and call eval at runtime.
6555
             */
6556
 
6557
            envPtr->pushSimpleWords = 1;
6558
            result = CompileWord(interp, src, lastChar, flags, envPtr);
6559
            if (result != TCL_OK) {
6560
                goto done;
6561
            }
6562
            TclEmitOpcode(INST_EVAL_STK, envPtr);
6563
            src += envPtr->termOffset;
6564
            maxDepth = envPtr->maxStackDepth;
6565
        }
6566
    }
6567
 
6568
    done:
6569
    envPtr->termOffset = (src - string);
6570
    envPtr->maxStackDepth = maxDepth;
6571
    envPtr->pushSimpleWords = savePushSimpleWords;
6572
    return result;
6573
}
6574
 
6575
/*
6576
 *----------------------------------------------------------------------
6577
 *
6578
 * LookupCompiledLocal --
6579
 *
6580
 *      This procedure is called at compile time to look up and optionally
6581
 *      allocate an entry ("slot") for a variable in a procedure's array of
6582
 *      local variables. If the variable's name is NULL, a new temporary
6583
 *      variable is always created. (Such temporary variables can only be
6584
 *      referenced using their slot index.)
6585
 *
6586
 * Results:
6587
 *      If createIfNew is 0 (false) and the name is non-NULL, then if the
6588
 *      variable is found, the index of its entry in the procedure's array
6589
 *      of local variables is returned; otherwise -1 is returned.
6590
 *      If name is NULL, the index of a new temporary variable is returned.
6591
 *      Finally, if createIfNew is 1 and name is non-NULL, the index of a
6592
 *      new entry is returned.
6593
 *
6594
 * Side effects:
6595
 *      Creates and registers a new local variable if createIfNew is 1 and
6596
 *      the variable is unknown, or if the name is NULL.
6597
 *
6598
 *----------------------------------------------------------------------
6599
 */
6600
 
6601
static int
6602
LookupCompiledLocal(name, nameChars, createIfNew, flagsIfCreated, procPtr)
6603
    register char *name;        /* Points to first character of the name of
6604
                                 * a scalar or array variable. If NULL, a
6605
                                 * temporary var should be created. */
6606
    int nameChars;              /* The length of the name excluding the
6607
                                 * terminating null character. */
6608
    int createIfNew;            /* 1 to allocate a local frame entry for the
6609
                                 * variable if it is new. */
6610
    int flagsIfCreated;         /* Flag bits for the compiled local if
6611
                                 * created. Only VAR_SCALAR, VAR_ARRAY, and
6612
                                 * VAR_LINK make sense. */
6613
    register Proc *procPtr;     /* Points to structure describing procedure
6614
                                 * containing the variable reference. */
6615
{
6616
    register CompiledLocal *localPtr;
6617
    int localIndex = -1;
6618
    register int i;
6619
    int localCt;
6620
 
6621
    /*
6622
     * If not creating a temporary, does a local variable of the specified
6623
     * name already exist?
6624
     */
6625
 
6626
    if (name != NULL) {
6627
        localCt = procPtr->numCompiledLocals;
6628
        localPtr = procPtr->firstLocalPtr;
6629
        for (i = 0;  i < localCt;  i++) {
6630
            if (!TclIsVarTemporary(localPtr)) {
6631
                char *localName = localPtr->name;
6632
                if ((name[0] == localName[0])
6633
                        && (nameChars == localPtr->nameLength)
6634
                        && (strncmp(name, localName, (unsigned) nameChars) == 0)) {
6635
                    return i;
6636
                }
6637
            }
6638
            localPtr = localPtr->nextPtr;
6639
        }
6640
    }
6641
 
6642
    /*
6643
     * Create a new variable if appropriate.
6644
     */
6645
 
6646
    if (createIfNew || (name == NULL)) {
6647
        localIndex = procPtr->numCompiledLocals;
6648
        localPtr = (CompiledLocal *) ckalloc((unsigned)
6649
                (sizeof(CompiledLocal) - sizeof(localPtr->name)
6650
                + nameChars+1));
6651
        if (procPtr->firstLocalPtr == NULL) {
6652
            procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
6653
        } else {
6654
            procPtr->lastLocalPtr->nextPtr = localPtr;
6655
            procPtr->lastLocalPtr = localPtr;
6656
        }
6657
        localPtr->nextPtr = NULL;
6658
        localPtr->nameLength = nameChars;
6659
        localPtr->frameIndex = localIndex;
6660
        localPtr->flags = flagsIfCreated;
6661
        if (name == NULL) {
6662
            localPtr->flags |= VAR_TEMPORARY;
6663
        }
6664
        localPtr->defValuePtr = NULL;
6665
        localPtr->resolveInfo = NULL;
6666
 
6667
        if (name != NULL) {
6668
            memcpy((VOID *) localPtr->name, (VOID *) name, (size_t) nameChars);
6669
        }
6670
        localPtr->name[nameChars] = '\0';
6671
        procPtr->numCompiledLocals++;
6672
    }
6673
    return localIndex;
6674
}
6675
 
6676
/*
6677
 *----------------------------------------------------------------------
6678
 *
6679
 * TclInitCompiledLocals --
6680
 *
6681
 *      This routine is invoked in order to initialize the compiled
6682
 *      locals table for a new call frame.
6683
 *
6684
 * Results:
6685
 *      None.
6686
 *
6687
 * Side effects:
6688
 *      May invoke various name resolvers in order to determine which
6689
 *      variables are being referenced at runtime.
6690
 *
6691
 *----------------------------------------------------------------------
6692
 */
6693
 
6694
void
6695
TclInitCompiledLocals(interp, framePtr, nsPtr)
6696
    Tcl_Interp *interp;         /* Current interpreter. */
6697
    CallFrame *framePtr;        /* Call frame to initialize. */
6698
    Namespace *nsPtr;           /* Pointer to current namespace. */
6699
{
6700
    register CompiledLocal *localPtr;
6701
    Interp *iPtr = (Interp*) interp;
6702
    Tcl_ResolvedVarInfo *vinfo, *resVarInfo;
6703
    Var *varPtr = framePtr->compiledLocals;
6704
    Var *resolvedVarPtr;
6705
    ResolverScheme *resPtr;
6706
    int result;
6707
 
6708
    /*
6709
     * Initialize the array of local variables stored in the call frame.
6710
     * Some variables may have special resolution rules.  In that case,
6711
     * we call their "resolver" procs to get our hands on the variable,
6712
     * and we make the compiled local a link to the real variable.
6713
     */
6714
 
6715
    for (localPtr = framePtr->procPtr->firstLocalPtr;
6716
         localPtr != NULL;
6717
         localPtr = localPtr->nextPtr) {
6718
 
6719
        /*
6720
         * Check to see if this local is affected by namespace or
6721
         * interp resolvers.  The resolver to use is cached for the
6722
         * next invocation of the procedure.
6723
         */
6724
 
6725
        if (!(localPtr->flags & (VAR_ARGUMENT|VAR_TEMPORARY|VAR_RESOLVED))
6726
                && (nsPtr->compiledVarResProc || iPtr->resolverPtr)) {
6727
            resPtr = iPtr->resolverPtr;
6728
 
6729
            if (nsPtr->compiledVarResProc) {
6730
                result = (*nsPtr->compiledVarResProc)(nsPtr->interp,
6731
                        localPtr->name, localPtr->nameLength,
6732
                        (Tcl_Namespace *) nsPtr, &vinfo);
6733
            } else {
6734
                result = TCL_CONTINUE;
6735
            }
6736
 
6737
            while ((result == TCL_CONTINUE) && resPtr) {
6738
                if (resPtr->compiledVarResProc) {
6739
                    result = (*resPtr->compiledVarResProc)(nsPtr->interp,
6740
                            localPtr->name, localPtr->nameLength,
6741
                            (Tcl_Namespace *) nsPtr, &vinfo);
6742
                }
6743
                resPtr = resPtr->nextPtr;
6744
            }
6745
            if (result == TCL_OK) {
6746
                localPtr->resolveInfo = vinfo;
6747
                localPtr->flags |= VAR_RESOLVED;
6748
            }
6749
        }
6750
 
6751
        /*
6752
         * Now invoke the resolvers to determine the exact variables that
6753
         * should be used.
6754
         */
6755
 
6756
        resVarInfo = localPtr->resolveInfo;
6757
        resolvedVarPtr = NULL;
6758
 
6759
        if (resVarInfo && resVarInfo->fetchProc) {
6760
            resolvedVarPtr = (Var*) (*resVarInfo->fetchProc)(interp,
6761
                resVarInfo);
6762
        }
6763
 
6764
        if (resolvedVarPtr) {
6765
            varPtr->name = localPtr->name; /* will be just '\0' if temp var */
6766
            varPtr->nsPtr = NULL;
6767
            varPtr->hPtr = NULL;
6768
            varPtr->refCount = 0;
6769
            varPtr->tracePtr = NULL;
6770
            varPtr->searchPtr = NULL;
6771
            varPtr->flags = 0;
6772
            TclSetVarLink(varPtr);
6773
            varPtr->value.linkPtr = resolvedVarPtr;
6774
            resolvedVarPtr->refCount++;
6775
        } else {
6776
            varPtr->value.objPtr = NULL;
6777
            varPtr->name = localPtr->name; /* will be just '\0' if temp var */
6778
            varPtr->nsPtr = NULL;
6779
            varPtr->hPtr = NULL;
6780
            varPtr->refCount = 0;
6781
            varPtr->tracePtr = NULL;
6782
            varPtr->searchPtr = NULL;
6783
            varPtr->flags = (localPtr->flags | VAR_UNDEFINED);
6784
        }
6785
        varPtr++;
6786
    }
6787
}
6788
 
6789
/*
6790
 *----------------------------------------------------------------------
6791
 *
6792
 * AdvanceToNextWord --
6793
 *
6794
 *      This procedure is called to skip over any leading white space at the
6795
 *      start of a word. Note that a backslash-newline is treated as a
6796
 *      space.
6797
 *
6798
 * Results:
6799
 *      None.
6800
 *
6801
 * Side effects:
6802
 *      Updates envPtr->termOffset with the offset of the first
6803
 *      character in "string" that was not white space or a
6804
 *      backslash-newline. This might be the offset of the character that
6805
 *      ends the command: a newline, null, semicolon, or close-bracket.
6806
 *
6807
 *----------------------------------------------------------------------
6808
 */
6809
 
6810
static void
6811
AdvanceToNextWord(string, envPtr)
6812
    char *string;               /* The source string to compile. */
6813
    CompileEnv *envPtr;         /* Holds resulting instructions. */
6814
{
6815
    register char *src;         /* Points to current source char. */
6816
    register int type;          /* Current char's CHAR_TYPE type. */
6817
 
6818
    src = string;
6819
    type = CHAR_TYPE(src, src+1);
6820
    while (type & (TCL_SPACE | TCL_BACKSLASH)) {
6821
        if (type == TCL_BACKSLASH) {
6822
            if (src[1] == '\n') {
6823
                src += 2;
6824
            } else {
6825
                break;          /* exit loop; no longer white space */
6826
            }
6827
        } else {
6828
            src++;
6829
        }
6830
        type = CHAR_TYPE(src, src+1);
6831
    }
6832
    envPtr->termOffset = (src - string);
6833
}
6834
 
6835
/*
6836
 *----------------------------------------------------------------------
6837
 *
6838
 * Tcl_Backslash --
6839
 *
6840
 *      Figure out how to handle a backslash sequence.
6841
 *
6842
 * Results:
6843
 *      The return value is the character that should be substituted
6844
 *      in place of the backslash sequence that starts at src.  If
6845
 *      readPtr isn't NULL then it is filled in with a count of the
6846
 *      number of characters in the backslash sequence.
6847
 *
6848
 * Side effects:
6849
 *      None.
6850
 *
6851
 *----------------------------------------------------------------------
6852
 */
6853
 
6854
char
6855
Tcl_Backslash(src, readPtr)
6856
    CONST char *src;            /* Points to the backslash character of
6857
                                 * a backslash sequence. */
6858
    int *readPtr;               /* Fill in with number of characters read
6859
                                 * from src, unless NULL. */
6860
{
6861
    CONST char *p = src + 1;
6862
    char result;
6863
    int count;
6864
 
6865
    count = 2;
6866
 
6867
    switch (*p) {
6868
        /*
6869
         * Note: in the conversions below, use absolute values (e.g.,
6870
         * 0xa) rather than symbolic values (e.g. \n) that get converted
6871
         * by the compiler.  It's possible that compilers on some
6872
         * platforms will do the symbolic conversions differently, which
6873
         * could result in non-portable Tcl scripts.
6874
         */
6875
 
6876
        case 'a':
6877
            result = 0x7;
6878
            break;
6879
        case 'b':
6880
            result = 0x8;
6881
            break;
6882
        case 'f':
6883
            result = 0xc;
6884
            break;
6885
        case 'n':
6886
            result = 0xa;
6887
            break;
6888
        case 'r':
6889
            result = 0xd;
6890
            break;
6891
        case 't':
6892
            result = 0x9;
6893
            break;
6894
        case 'v':
6895
            result = 0xb;
6896
            break;
6897
        case 'x':
6898
            if (isxdigit(UCHAR(p[1]))) {
6899
                char *end;
6900
 
6901
                result = (char) strtoul(p+1, &end, 16);
6902
                count = end - src;
6903
            } else {
6904
                count = 2;
6905
                result = 'x';
6906
            }
6907
            break;
6908
        case '\n':
6909
            do {
6910
                p++;
6911
            } while ((*p == ' ') || (*p == '\t'));
6912
            result = ' ';
6913
            count = p - src;
6914
            break;
6915
        case 0:
6916
            result = '\\';
6917
            count = 1;
6918
            break;
6919
        default:
6920
            if (isdigit(UCHAR(*p))) {
6921
                result = (char)(*p - '0');
6922
                p++;
6923
                if (!isdigit(UCHAR(*p))) {
6924
                    break;
6925
                }
6926
                count = 3;
6927
                result = (char)((result << 3) + (*p - '0'));
6928
                p++;
6929
                if (!isdigit(UCHAR(*p))) {
6930
                    break;
6931
                }
6932
                count = 4;
6933
                result = (char)((result << 3) + (*p - '0'));
6934
                break;
6935
            }
6936
            result = *p;
6937
            count = 2;
6938
            break;
6939
    }
6940
 
6941
    if (readPtr != NULL) {
6942
        *readPtr = count;
6943
    }
6944
    return result;
6945
}
6946
 
6947
/*
6948
 *----------------------------------------------------------------------
6949
 *
6950
 * TclObjIndexForString --
6951
 *
6952
 *      Procedure to find, or if necessary create, an object in a
6953
 *      CompileEnv's object array that has a string representation
6954
 *      matching the argument string.
6955
 *
6956
 * Results:
6957
 *      The index in the CompileEnv's object array of an object with a
6958
 *      string representation matching the argument "string". The object is
6959
 *      created if necessary. If inHeap is 1, then string is heap allocated
6960
 *      and ownership of the string is passed to TclObjIndexForString;
6961
 *      otherwise, the string is owned by the caller and must not be
6962
 *      modified or freed by TclObjIndexForString. Typically, a caller sets
6963
 *      inHeap 1 if string is an already heap-allocated buffer holding the
6964
 *      result of backslash substitutions.
6965
 *
6966
 * Side effects:
6967
 *      A new Tcl object will be created if no existing object matches the
6968
 *      input string. If allocStrRep is 1 then if a new object is created,
6969
 *      its string representation is allocated in the heap, else it is left
6970
 *      NULL. If inHeap is 1, this procedure is given ownership of the
6971
 *      string: if an object is created and allocStrRep is 1 then its
6972
 *      string representation is set directly from string, otherwise
6973
 *      the string is freed.
6974
 *
6975
 *----------------------------------------------------------------------
6976
 */
6977
 
6978
int
6979
TclObjIndexForString(string, length, allocStrRep, inHeap, envPtr)
6980
    register char *string;      /* Points to string for which an object is
6981
                                 * found or created in CompileEnv's object
6982
                                 * array. */
6983
    int length;                 /* Length of string. */
6984
    int allocStrRep;            /* If 1 then the object's string rep should
6985
                                 * be allocated in the heap. */
6986
    int inHeap;                 /* If 1 then string is heap allocated and
6987
                                 * its ownership is passed to
6988
                                 * TclObjIndexForString. */
6989
    CompileEnv *envPtr;         /* Points to the CompileEnv in whose object
6990
                                 * array an object is found or created. */
6991
{
6992
    register Tcl_Obj *objPtr;   /* Points to the object created for
6993
                                 * the string, if one was created. */
6994
    int objIndex;               /* Index of matching object. */
6995
    Tcl_HashEntry *hPtr;
6996
    int strLength, new;
6997
 
6998
    /*
6999
     * Look up the string in the code's object hashtable. If found, just
7000
     * return the associated object array index.  Note that if the string
7001
     * has embedded nulls, we don't create a hash table entry.  This
7002
     * should be fixed, but we need to update hash tables, first.
7003
     */
7004
 
7005
    strLength = strlen(string);
7006
    if (length == -1) {
7007
        length = strLength;
7008
    }
7009
    if (strLength != length) {
7010
        hPtr = NULL;
7011
    } else {
7012
        hPtr = Tcl_CreateHashEntry(&envPtr->objTable, string, &new);
7013
        if (!new) {             /* already in object table and array */
7014
            objIndex = (int) Tcl_GetHashValue(hPtr);
7015
            if (inHeap) {
7016
                ckfree(string);
7017
            }
7018
            return objIndex;
7019
        }
7020
    }
7021
 
7022
    /*
7023
     * Create a new object holding the string, add it to the object array,
7024
     * and register its index in the object hashtable.
7025
     */
7026
 
7027
    objPtr = Tcl_NewObj();
7028
    if (allocStrRep) {
7029
        if (inHeap) {           /* use input string for obj's string rep */
7030
            objPtr->bytes = string;
7031
        } else {
7032
            if (length > 0) {
7033
                objPtr->bytes = ckalloc((unsigned) length + 1);
7034
                memcpy((VOID *) objPtr->bytes, (VOID *) string,
7035
                        (size_t) length);
7036
                objPtr->bytes[length] = '\0';
7037
            }
7038
        }
7039
        objPtr->length = length;
7040
    } else {                    /* leave the string rep NULL */
7041
        if (inHeap) {
7042
            ckfree(string);
7043
        }
7044
    }
7045
 
7046
    if (envPtr->objArrayNext >= envPtr->objArrayEnd) {
7047
        ExpandObjectArray(envPtr);
7048
    }
7049
    objIndex = envPtr->objArrayNext;
7050
    envPtr->objArrayPtr[objIndex] = objPtr;
7051
    Tcl_IncrRefCount(objPtr);
7052
    envPtr->objArrayNext++;
7053
 
7054
    if (hPtr) {
7055
        Tcl_SetHashValue(hPtr, objIndex);
7056
    }
7057
    return objIndex;
7058
}
7059
 
7060
/*
7061
 *----------------------------------------------------------------------
7062
 *
7063
 * TclExpandCodeArray --
7064
 *
7065
 *      Procedure that uses malloc to allocate more storage for a
7066
 *      CompileEnv's code array.
7067
 *
7068
 * Results:
7069
 *      None.
7070
 *
7071
 * Side effects:
7072
 *      The byte code array in *envPtr is reallocated to a new array of
7073
 *      double the size, and if envPtr->mallocedCodeArray is non-zero the
7074
 *      old array is freed. Byte codes are copied from the old array to the
7075
 *      new one.
7076
 *
7077
 *----------------------------------------------------------------------
7078
 */
7079
 
7080
void
7081
TclExpandCodeArray(envPtr)
7082
    CompileEnv *envPtr;         /* Points to the CompileEnv whose code array
7083
                                 * must be enlarged. */
7084
{
7085
    /*
7086
     * envPtr->codeNext is equal to envPtr->codeEnd. The currently defined
7087
     * code bytes are stored between envPtr->codeStart and
7088
     * (envPtr->codeNext - 1) [inclusive].
7089
     */
7090
 
7091
    size_t currBytes = TclCurrCodeOffset();
7092
    size_t newBytes  = 2*(envPtr->codeEnd  - envPtr->codeStart);
7093
    unsigned char *newPtr = (unsigned char *) ckalloc((unsigned) newBytes);
7094
 
7095
    /*
7096
     * Copy from old code array to new, free old code array if needed, and
7097
     * mark new code array as malloced.
7098
     */
7099
 
7100
    memcpy((VOID *) newPtr, (VOID *) envPtr->codeStart, currBytes);
7101
    if (envPtr->mallocedCodeArray) {
7102
        ckfree((char *) envPtr->codeStart);
7103
    }
7104
    envPtr->codeStart = newPtr;
7105
    envPtr->codeNext = (newPtr + currBytes);
7106
    envPtr->codeEnd  = (newPtr + newBytes);
7107
    envPtr->mallocedCodeArray = 1;
7108
}
7109
 
7110
/*
7111
 *----------------------------------------------------------------------
7112
 *
7113
 * ExpandObjectArray --
7114
 *
7115
 *      Procedure that uses malloc to allocate more storage for a
7116
 *      CompileEnv's object array.
7117
 *
7118
 * Results:
7119
 *      None.
7120
 *
7121
 * Side effects:
7122
 *      The object array in *envPtr is reallocated to a new array of
7123
 *      double the size, and if envPtr->mallocedObjArray is non-zero the
7124
 *      old array is freed. Tcl_Obj pointers are copied from the old array
7125
 *      to the new one.
7126
 *
7127
 *----------------------------------------------------------------------
7128
 */
7129
 
7130
static void
7131
ExpandObjectArray(envPtr)
7132
    CompileEnv *envPtr;         /* Points to the CompileEnv whose object
7133
                                 * array must be enlarged. */
7134
{
7135
    /*
7136
     * envPtr->objArrayNext is equal to envPtr->objArrayEnd. The currently
7137
     * allocated Tcl_Obj pointers are stored between elements
7138
     * 0 and (envPtr->objArrayNext - 1) [inclusive] in the object array
7139
     * pointed to by objArrayPtr.
7140
     */
7141
 
7142
    size_t currBytes = envPtr->objArrayNext * sizeof(Tcl_Obj *);
7143
    int newElems = 2*envPtr->objArrayEnd;
7144
    size_t newBytes = newElems * sizeof(Tcl_Obj *);
7145
    Tcl_Obj **newPtr = (Tcl_Obj **) ckalloc((unsigned) newBytes);
7146
 
7147
    /*
7148
     * Copy from old object array to new, free old object array if needed,
7149
     * and mark new object array as malloced.
7150
     */
7151
 
7152
    memcpy((VOID *) newPtr, (VOID *) envPtr->objArrayPtr, currBytes);
7153
    if (envPtr->mallocedObjArray) {
7154
        ckfree((char *) envPtr->objArrayPtr);
7155
    }
7156
    envPtr->objArrayPtr = (Tcl_Obj **) newPtr;
7157
    envPtr->objArrayEnd = newElems;
7158
    envPtr->mallocedObjArray = 1;
7159
}
7160
 
7161
/*
7162
 *----------------------------------------------------------------------
7163
 *
7164
 * EnterCmdStartData --
7165
 *
7166
 *      Registers the starting source and bytecode location of a
7167
 *      command. This information is used at runtime to map between
7168
 *      instruction pc and source locations.
7169
 *
7170
 * Results:
7171
 *      None.
7172
 *
7173
 * Side effects:
7174
 *      Inserts source and code location information into the compilation
7175
 *      environment envPtr for the command at index cmdIndex. The
7176
 *      compilation environment's CmdLocation array is grown if necessary.
7177
 *
7178
 *----------------------------------------------------------------------
7179
 */
7180
 
7181
static void
7182
EnterCmdStartData(envPtr, cmdIndex, srcOffset, codeOffset)
7183
    CompileEnv *envPtr;         /* Points to the compilation environment
7184
                                 * structure in which to enter command
7185
                                 * location information. */
7186
    int cmdIndex;               /* Index of the command whose start data
7187
                                 * is being set. */
7188
    int srcOffset;              /* Offset of first char of the command. */
7189
    int codeOffset;             /* Offset of first byte of command code. */
7190
{
7191
    CmdLocation *cmdLocPtr;
7192
 
7193
    if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
7194
        panic("EnterCmdStartData: bad command index %d\n", cmdIndex);
7195
    }
7196
 
7197
    if (cmdIndex >= envPtr->cmdMapEnd) {
7198
        /*
7199
         * Expand the command location array by allocating more storage from
7200
         * the heap. The currently allocated CmdLocation entries are stored
7201
         * from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive).
7202
         */
7203
 
7204
        size_t currElems = envPtr->cmdMapEnd;
7205
        size_t newElems  = 2*currElems;
7206
        size_t currBytes = currElems * sizeof(CmdLocation);
7207
        size_t newBytes  = newElems  * sizeof(CmdLocation);
7208
        CmdLocation *newPtr = (CmdLocation *) ckalloc((unsigned) newBytes);
7209
 
7210
        /*
7211
         * Copy from old command location array to new, free old command
7212
         * location array if needed, and mark new array as malloced.
7213
         */
7214
 
7215
        memcpy((VOID *) newPtr, (VOID *) envPtr->cmdMapPtr, currBytes);
7216
        if (envPtr->mallocedCmdMap) {
7217
            ckfree((char *) envPtr->cmdMapPtr);
7218
        }
7219
        envPtr->cmdMapPtr = (CmdLocation *) newPtr;
7220
        envPtr->cmdMapEnd = newElems;
7221
        envPtr->mallocedCmdMap = 1;
7222
    }
7223
 
7224
    if (cmdIndex > 0) {
7225
        if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) {
7226
            panic("EnterCmdStartData: cmd map table not sorted by code offset");
7227
        }
7228
    }
7229
 
7230
    cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
7231
    cmdLocPtr->codeOffset = codeOffset;
7232
    cmdLocPtr->srcOffset = srcOffset;
7233
    cmdLocPtr->numSrcChars = -1;
7234
    cmdLocPtr->numCodeBytes = -1;
7235
}
7236
 
7237
/*
7238
 *----------------------------------------------------------------------
7239
 *
7240
 * EnterCmdExtentData --
7241
 *
7242
 *      Registers the source and bytecode length for a command. This
7243
 *      information is used at runtime to map between instruction pc and
7244
 *      source locations.
7245
 *
7246
 * Results:
7247
 *      None.
7248
 *
7249
 * Side effects:
7250
 *      Inserts source and code length information into the compilation
7251
 *      environment envPtr for the command at index cmdIndex. Starting
7252
 *      source and bytecode information for the command must already
7253
 *      have been registered.
7254
 *
7255
 *----------------------------------------------------------------------
7256
 */
7257
 
7258
static void
7259
EnterCmdExtentData(envPtr, cmdIndex, numSrcChars, numCodeBytes)
7260
    CompileEnv *envPtr;         /* Points to the compilation environment
7261
                                 * structure in which to enter command
7262
                                 * location information. */
7263
    int cmdIndex;               /* Index of the command whose source and
7264
                                 * code length data is being set. */
7265
    int numSrcChars;            /* Number of command source chars. */
7266
    int numCodeBytes;           /* Offset of last byte of command code. */
7267
{
7268
    CmdLocation *cmdLocPtr;
7269
 
7270
    if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
7271
        panic("EnterCmdStartData: bad command index %d\n", cmdIndex);
7272
    }
7273
 
7274
    if (cmdIndex > envPtr->cmdMapEnd) {
7275
        panic("EnterCmdStartData: no start data registered for command with index %d\n", cmdIndex);
7276
    }
7277
 
7278
    cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
7279
    cmdLocPtr->numSrcChars = numSrcChars;
7280
    cmdLocPtr->numCodeBytes = numCodeBytes;
7281
}
7282
 
7283
/*
7284
 *----------------------------------------------------------------------
7285
 *
7286
 * InitArgInfo --
7287
 *
7288
 *      Initializes a ArgInfo structure to hold information about
7289
 *      some number of argument words in a command.
7290
 *
7291
 * Results:
7292
 *      None.
7293
 *
7294
 * Side effects:
7295
 *      The ArgInfo structure is initialized.
7296
 *
7297
 *----------------------------------------------------------------------
7298
 */
7299
 
7300
static void
7301
InitArgInfo(argInfoPtr)
7302
    register ArgInfo *argInfoPtr; /* Points to the ArgInfo structure
7303
                                   * to initialize. */
7304
{
7305
    argInfoPtr->numArgs = 0;
7306
    argInfoPtr->startArray = argInfoPtr->staticStartSpace;
7307
    argInfoPtr->endArray   = argInfoPtr->staticEndSpace;
7308
    argInfoPtr->allocArgs = ARGINFO_INIT_ENTRIES;
7309
    argInfoPtr->mallocedArrays = 0;
7310
}
7311
 
7312
/*
7313
 *----------------------------------------------------------------------
7314
 *
7315
 * CollectArgInfo --
7316
 *
7317
 *      Procedure to scan the argument words of a command and record the
7318
 *      start and finish of each argument word in a ArgInfo structure.
7319
 *
7320
 * Results:
7321
 *      The return value is a standard Tcl result, which is TCL_OK unless
7322
 *      there was an error while scanning string. If an error occurs then
7323
 *      the interpreter's result contains a standard error message.
7324
 *
7325
 * Side effects:
7326
 *      If necessary, the argument start and end arrays in *argInfoPtr
7327
 *      are grown and reallocated to a new arrays of double the size, and
7328
 *      if argInfoPtr->mallocedArray is non-zero the old arrays are freed.
7329
 *
7330
 *----------------------------------------------------------------------
7331
 */
7332
 
7333
static int
7334
CollectArgInfo(interp, string, lastChar, flags, argInfoPtr)
7335
    Tcl_Interp *interp;         /* Used for error reporting. */
7336
    char *string;               /* The source command string to scan. */
7337
    char *lastChar;              /* Pointer to terminating character of
7338
                                  * string. */
7339
    int flags;                  /* Flags to control compilation (same as
7340
                                 * passed to Tcl_Eval). */
7341
    register ArgInfo *argInfoPtr;
7342
                                /* Points to the ArgInfo structure in which
7343
                                 * to record the arg word information. */
7344
{
7345
    register char *src = string;/* Points to current source char. */
7346
    register int type;          /* Current char's CHAR_TYPE type. */
7347
    int nestedCmd = (flags & TCL_BRACKET_TERM);
7348
                                /* 1 if string being scanned is a nested
7349
                                 * command and is terminated by a ']';
7350
                                 * otherwise 0. */
7351
    int scanningArgs;           /* 1 if still scanning argument words to
7352
                                 * determine their start and end. */
7353
    char *wordStart, *wordEnd;  /* Points to the first and last significant
7354
                                 * characters of each word. */
7355
    CompileEnv tempCompEnv;     /* Only used to hold the termOffset field
7356
                                 * updated by AdvanceToNextWord. */
7357
    char *prev;
7358
 
7359
    argInfoPtr->numArgs = 0;
7360
    scanningArgs = 1;
7361
    while (scanningArgs) {
7362
        AdvanceToNextWord(src, &tempCompEnv);
7363
        src += tempCompEnv.termOffset;
7364
        type = CHAR_TYPE(src, lastChar);
7365
 
7366
        if ((type == TCL_COMMAND_END) && ((*src != ']') || nestedCmd)) {
7367
            break;                  /* done collecting argument words */
7368
        } else if (*src == '"') {
7369
            wordStart = src;
7370
            src = TclWordEnd(src, lastChar, nestedCmd, NULL);
7371
            if (src == lastChar) {
7372
                badStringTermination:
7373
                Tcl_ResetResult(interp);
7374
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
7375
                        "quoted string doesn't terminate properly", -1);
7376
                return TCL_ERROR;
7377
            }
7378
            prev = (src-1);
7379
            if (*src == '"') {
7380
                wordEnd = src;
7381
                src++;
7382
            } else if ((*src == ';') && (*prev == '"')) {
7383
                scanningArgs = 0;
7384
                wordEnd = prev;
7385
            } else {
7386
                goto badStringTermination;
7387
            }
7388
        } else if (*src == '{') {
7389
            wordStart = src;
7390
            src = TclWordEnd(src, lastChar, nestedCmd, NULL);
7391
            if (src == lastChar) {
7392
                Tcl_ResetResult(interp);
7393
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
7394
                        "missing close-brace", -1);
7395
                return TCL_ERROR;
7396
            }
7397
            prev = (src-1);
7398
            if (*src == '}') {
7399
                wordEnd = src;
7400
                src++;
7401
            } else if ((*src == ';') && (*prev == '}')) {
7402
                scanningArgs = 0;
7403
                wordEnd = prev;
7404
            } else {
7405
                Tcl_ResetResult(interp);
7406
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
7407
                        "argument word in braces doesn't terminate properly", -1);
7408
                return TCL_ERROR;
7409
            }
7410
        } else {
7411
            wordStart = src;
7412
            src = TclWordEnd(src, lastChar, nestedCmd, NULL);
7413
            prev = (src-1);
7414
            if (src == lastChar) {
7415
                Tcl_ResetResult(interp);
7416
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
7417
                        "missing close-bracket or close-brace", -1);
7418
                return TCL_ERROR;
7419
            } else if (*src == ';') {
7420
                scanningArgs = 0;
7421
                wordEnd = prev;
7422
            } else {
7423
                wordEnd = src;
7424
                src++;
7425
                if ((src == lastChar) || (*src == '\n')
7426
                        || ((*src == ']') && nestedCmd)) {
7427
                    scanningArgs = 0;
7428
                }
7429
            }
7430
        } /* end of test on each kind of word */
7431
 
7432
        if (argInfoPtr->numArgs == argInfoPtr->allocArgs) {
7433
            int newArgs = 2*argInfoPtr->numArgs;
7434
            size_t currBytes = argInfoPtr->numArgs * sizeof(char *);
7435
            size_t newBytes  = newArgs * sizeof(char *);
7436
            char **newStartArrayPtr =
7437
                    (char **) ckalloc((unsigned) newBytes);
7438
            char **newEndArrayPtr =
7439
                    (char **) ckalloc((unsigned) newBytes);
7440
 
7441
            /*
7442
             * Copy from the old arrays to the new, free the old arrays if
7443
             * needed, and mark the new arrays as malloc'ed.
7444
             */
7445
 
7446
            memcpy((VOID *) newStartArrayPtr,
7447
                    (VOID *) argInfoPtr->startArray, currBytes);
7448
            memcpy((VOID *) newEndArrayPtr,
7449
                    (VOID *) argInfoPtr->endArray, currBytes);
7450
            if (argInfoPtr->mallocedArrays) {
7451
                ckfree((char *) argInfoPtr->startArray);
7452
                ckfree((char *) argInfoPtr->endArray);
7453
            }
7454
            argInfoPtr->startArray = newStartArrayPtr;
7455
            argInfoPtr->endArray   = newEndArrayPtr;
7456
            argInfoPtr->allocArgs = newArgs;
7457
            argInfoPtr->mallocedArrays = 1;
7458
        }
7459
        argInfoPtr->startArray[argInfoPtr->numArgs] = wordStart;
7460
        argInfoPtr->endArray[argInfoPtr->numArgs]   = wordEnd;
7461
        argInfoPtr->numArgs++;
7462
    }
7463
    return TCL_OK;
7464
}
7465
 
7466
/*
7467
 *----------------------------------------------------------------------
7468
 *
7469
 * FreeArgInfo --
7470
 *
7471
 *      Free any storage allocated in a ArgInfo structure.
7472
 *
7473
 * Results:
7474
 *      None.
7475
 *
7476
 * Side effects:
7477
 *      Allocated storage in the ArgInfo structure is freed.
7478
 *
7479
 *----------------------------------------------------------------------
7480
 */
7481
 
7482
static void
7483
FreeArgInfo(argInfoPtr)
7484
    register ArgInfo *argInfoPtr; /* Points to the ArgInfo structure
7485
                                   * to free. */
7486
{
7487
    if (argInfoPtr->mallocedArrays) {
7488
        ckfree((char *) argInfoPtr->startArray);
7489
        ckfree((char *) argInfoPtr->endArray);
7490
    }
7491
}
7492
 
7493
/*
7494
 *----------------------------------------------------------------------
7495
 *
7496
 * CreateExceptionRange --
7497
 *
7498
 *      Procedure that allocates and initializes a new ExceptionRange
7499
 *      structure of the specified kind in a CompileEnv's ExceptionRange
7500
 *      array.
7501
 *
7502
 * Results:
7503
 *      Returns the index for the newly created ExceptionRange.
7504
 *
7505
 * Side effects:
7506
 *      If there is not enough room in the CompileEnv's ExceptionRange
7507
 *      array, the array in expanded: a new array of double the size is
7508
 *      allocated, if envPtr->mallocedExcRangeArray is non-zero the old
7509
 *      array is freed, and ExceptionRange entries are copied from the old
7510
 *      array to the new one.
7511
 *
7512
 *----------------------------------------------------------------------
7513
 */
7514
 
7515
static int
7516
CreateExceptionRange(type, envPtr)
7517
    ExceptionRangeType type;    /* The kind of ExceptionRange desired. */
7518
    register CompileEnv *envPtr;/* Points to the CompileEnv for which a new
7519
                                 * loop ExceptionRange structure is to be
7520
                                 * allocated. */
7521
{
7522
    int index;                  /* Index for the newly-allocated
7523
                                 * ExceptionRange structure. */
7524
    register ExceptionRange *rangePtr;
7525
                                /* Points to the new ExceptionRange
7526
                                 * structure */
7527
 
7528
    index = envPtr->excRangeArrayNext;
7529
    if (index >= envPtr->excRangeArrayEnd) {
7530
        /*
7531
         * Expand the ExceptionRange array. The currently allocated entries
7532
         * are stored between elements 0 and (envPtr->excRangeArrayNext - 1)
7533
         * [inclusive].
7534
         */
7535
 
7536
        size_t currBytes =
7537
                envPtr->excRangeArrayNext * sizeof(ExceptionRange);
7538
        int newElems = 2*envPtr->excRangeArrayEnd;
7539
        size_t newBytes = newElems * sizeof(ExceptionRange);
7540
        ExceptionRange *newPtr = (ExceptionRange *)
7541
                ckalloc((unsigned) newBytes);
7542
 
7543
        /*
7544
         * Copy from old ExceptionRange array to new, free old
7545
         * ExceptionRange array if needed, and mark the new ExceptionRange
7546
         * array as malloced.
7547
         */
7548
 
7549
        memcpy((VOID *) newPtr, (VOID *) envPtr->excRangeArrayPtr,
7550
                currBytes);
7551
        if (envPtr->mallocedExcRangeArray) {
7552
            ckfree((char *) envPtr->excRangeArrayPtr);
7553
        }
7554
        envPtr->excRangeArrayPtr = (ExceptionRange *) newPtr;
7555
        envPtr->excRangeArrayEnd = newElems;
7556
        envPtr->mallocedExcRangeArray = 1;
7557
    }
7558
    envPtr->excRangeArrayNext++;
7559
 
7560
    rangePtr = &(envPtr->excRangeArrayPtr[index]);
7561
    rangePtr->type = type;
7562
    rangePtr->nestingLevel = envPtr->excRangeDepth;
7563
    rangePtr->codeOffset = -1;
7564
    rangePtr->numCodeBytes = -1;
7565
    rangePtr->breakOffset = -1;
7566
    rangePtr->continueOffset = -1;
7567
    rangePtr->catchOffset = -1;
7568
    return index;
7569
}
7570
 
7571
/*
7572
 *----------------------------------------------------------------------
7573
 *
7574
 * TclCreateAuxData --
7575
 *
7576
 *      Procedure that allocates and initializes a new AuxData structure in
7577
 *      a CompileEnv's array of compilation auxiliary data records. These
7578
 *      AuxData records hold information created during compilation by
7579
 *      CompileProcs and used by instructions during execution.
7580
 *
7581
 * Results:
7582
 *      Returns the index for the newly created AuxData structure.
7583
 *
7584
 * Side effects:
7585
 *      If there is not enough room in the CompileEnv's AuxData array,
7586
 *      the AuxData array in expanded: a new array of double the size
7587
 *      is allocated, if envPtr->mallocedAuxDataArray is non-zero
7588
 *      the old array is freed, and AuxData entries are copied from
7589
 *      the old array to the new one.
7590
 *
7591
 *----------------------------------------------------------------------
7592
 */
7593
 
7594
int
7595
TclCreateAuxData(clientData, typePtr, envPtr)
7596
    ClientData clientData;      /* The compilation auxiliary data to store
7597
                             * in the new aux data record. */
7598
    AuxDataType *typePtr;       /* Pointer to the type to attach to this AuxData */
7599
    register CompileEnv *envPtr;/* Points to the CompileEnv for which a new
7600
                                 * aux data structure is to be allocated. */
7601
{
7602
    int index;                  /* Index for the new AuxData structure. */
7603
    register AuxData *auxDataPtr;
7604
                                /* Points to the new AuxData structure */
7605
 
7606
    index = envPtr->auxDataArrayNext;
7607
    if (index >= envPtr->auxDataArrayEnd) {
7608
        /*
7609
         * Expand the AuxData array. The currently allocated entries are
7610
         * stored between elements 0 and (envPtr->auxDataArrayNext - 1)
7611
         * [inclusive].
7612
         */
7613
 
7614
        size_t currBytes = envPtr->auxDataArrayNext * sizeof(AuxData);
7615
        int newElems = 2*envPtr->auxDataArrayEnd;
7616
        size_t newBytes = newElems * sizeof(AuxData);
7617
        AuxData *newPtr = (AuxData *) ckalloc((unsigned) newBytes);
7618
 
7619
        /*
7620
         * Copy from old AuxData array to new, free old AuxData array if
7621
         * needed, and mark the new AuxData array as malloced.
7622
         */
7623
 
7624
        memcpy((VOID *) newPtr, (VOID *) envPtr->auxDataArrayPtr,
7625
                currBytes);
7626
        if (envPtr->mallocedAuxDataArray) {
7627
            ckfree((char *) envPtr->auxDataArrayPtr);
7628
        }
7629
        envPtr->auxDataArrayPtr = newPtr;
7630
        envPtr->auxDataArrayEnd = newElems;
7631
        envPtr->mallocedAuxDataArray = 1;
7632
    }
7633
    envPtr->auxDataArrayNext++;
7634
 
7635
    auxDataPtr = &(envPtr->auxDataArrayPtr[index]);
7636
    auxDataPtr->type = typePtr;
7637
    auxDataPtr->clientData = clientData;
7638
    return index;
7639
}
7640
 
7641
/*
7642
 *----------------------------------------------------------------------
7643
 *
7644
 * TclInitJumpFixupArray --
7645
 *
7646
 *      Initializes a JumpFixupArray structure to hold some number of
7647
 *      jump fixup entries.
7648
 *
7649
 * Results:
7650
 *      None.
7651
 *
7652
 * Side effects:
7653
 *      The JumpFixupArray structure is initialized.
7654
 *
7655
 *----------------------------------------------------------------------
7656
 */
7657
 
7658
void
7659
TclInitJumpFixupArray(fixupArrayPtr)
7660
    register JumpFixupArray *fixupArrayPtr;
7661
                                 /* Points to the JumpFixupArray structure
7662
                                  * to initialize. */
7663
{
7664
    fixupArrayPtr->fixup = fixupArrayPtr->staticFixupSpace;
7665
    fixupArrayPtr->next = 0;
7666
    fixupArrayPtr->end = (JUMPFIXUP_INIT_ENTRIES - 1);
7667
    fixupArrayPtr->mallocedArray = 0;
7668
}
7669
 
7670
/*
7671
 *----------------------------------------------------------------------
7672
 *
7673
 * TclExpandJumpFixupArray --
7674
 *
7675
 *      Procedure that uses malloc to allocate more storage for a
7676
 *      jump fixup array.
7677
 *
7678
 * Results:
7679
 *      None.
7680
 *
7681
 * Side effects:
7682
 *      The jump fixup array in *fixupArrayPtr is reallocated to a new array
7683
 *      of double the size, and if fixupArrayPtr->mallocedArray is non-zero
7684
 *      the old array is freed. Jump fixup structures are copied from the
7685
 *      old array to the new one.
7686
 *
7687
 *----------------------------------------------------------------------
7688
 */
7689
 
7690
void
7691
TclExpandJumpFixupArray(fixupArrayPtr)
7692
    register JumpFixupArray *fixupArrayPtr;
7693
                                 /* Points to the JumpFixupArray structure
7694
                                  * to enlarge. */
7695
{
7696
    /*
7697
     * The currently allocated jump fixup entries are stored from fixup[0]
7698
     * up to fixup[fixupArrayPtr->fixupNext] (*not* inclusive). We assume
7699
     * fixupArrayPtr->fixupNext is equal to fixupArrayPtr->fixupEnd.
7700
     */
7701
 
7702
    size_t currBytes = fixupArrayPtr->next * sizeof(JumpFixup);
7703
    int newElems = 2*(fixupArrayPtr->end + 1);
7704
    size_t newBytes = newElems * sizeof(JumpFixup);
7705
    JumpFixup *newPtr = (JumpFixup *) ckalloc((unsigned) newBytes);
7706
 
7707
    /*
7708
     * Copy from the old array to new, free the old array if needed,
7709
     * and mark the new array as malloced.
7710
     */
7711
 
7712
    memcpy((VOID *) newPtr, (VOID *) fixupArrayPtr->fixup, currBytes);
7713
    if (fixupArrayPtr->mallocedArray) {
7714
        ckfree((char *) fixupArrayPtr->fixup);
7715
    }
7716
    fixupArrayPtr->fixup = (JumpFixup *) newPtr;
7717
    fixupArrayPtr->end = newElems;
7718
    fixupArrayPtr->mallocedArray = 1;
7719
}
7720
 
7721
/*
7722
 *----------------------------------------------------------------------
7723
 *
7724
 * TclFreeJumpFixupArray --
7725
 *
7726
 *      Free any storage allocated in a jump fixup array structure.
7727
 *
7728
 * Results:
7729
 *      None.
7730
 *
7731
 * Side effects:
7732
 *      Allocated storage in the JumpFixupArray structure is freed.
7733
 *
7734
 *----------------------------------------------------------------------
7735
 */
7736
 
7737
void
7738
TclFreeJumpFixupArray(fixupArrayPtr)
7739
    register JumpFixupArray *fixupArrayPtr;
7740
                                 /* Points to the JumpFixupArray structure
7741
                                  * to free. */
7742
{
7743
    if (fixupArrayPtr->mallocedArray) {
7744
        ckfree((char *) fixupArrayPtr->fixup);
7745
    }
7746
}
7747
 
7748
/*
7749
 *----------------------------------------------------------------------
7750
 *
7751
 * TclEmitForwardJump --
7752
 *
7753
 *      Procedure to emit a two-byte forward jump of kind "jumpType". Since
7754
 *      the jump may later have to be grown to five bytes if the jump target
7755
 *      is more than, say, 127 bytes away, this procedure also initializes a
7756
 *      JumpFixup record with information about the jump.
7757
 *
7758
 * Results:
7759
 *      None.
7760
 *
7761
 * Side effects:
7762
 *      The JumpFixup record pointed to by "jumpFixupPtr" is initialized
7763
 *      with information needed later if the jump is to be grown. Also,
7764
 *      a two byte jump of the designated type is emitted at the current
7765
 *      point in the bytecode stream.
7766
 *
7767
 *----------------------------------------------------------------------
7768
 */
7769
 
7770
void
7771
TclEmitForwardJump(envPtr, jumpType, jumpFixupPtr)
7772
    CompileEnv *envPtr;         /* Points to the CompileEnv structure that
7773
                                 * holds the resulting instruction. */
7774
    TclJumpType jumpType;       /* Indicates the kind of jump: if true or
7775
                                 * false or unconditional. */
7776
    JumpFixup *jumpFixupPtr;    /* Points to the JumpFixup structure to
7777
                                 * initialize with information about this
7778
                                 * forward jump. */
7779
{
7780
    /*
7781
     * Initialize the JumpFixup structure:
7782
     *    - codeOffset is offset of first byte of jump below
7783
     *    - cmdIndex is index of the command after the current one
7784
     *    - excRangeIndex is the index of the first ExceptionRange after
7785
     *      the current one.
7786
     */
7787
 
7788
    jumpFixupPtr->jumpType = jumpType;
7789
    jumpFixupPtr->codeOffset = TclCurrCodeOffset();
7790
    jumpFixupPtr->cmdIndex = envPtr->numCommands;
7791
    jumpFixupPtr->excRangeIndex = envPtr->excRangeArrayNext;
7792
 
7793
    switch (jumpType) {
7794
    case TCL_UNCONDITIONAL_JUMP:
7795
        TclEmitInstInt1(INST_JUMP1, /*offset*/ 0, envPtr);
7796
        break;
7797
    case TCL_TRUE_JUMP:
7798
        TclEmitInstInt1(INST_JUMP_TRUE1, /*offset*/ 0, envPtr);
7799
        break;
7800
    default:
7801
        TclEmitInstInt1(INST_JUMP_FALSE1, /*offset*/ 0, envPtr);
7802
        break;
7803
    }
7804
}
7805
 
7806
/*
7807
 *----------------------------------------------------------------------
7808
 *
7809
 * TclFixupForwardJump --
7810
 *
7811
 *      Procedure that updates a previously-emitted forward jump to jump
7812
 *      a specified number of bytes, "jumpDist". If necessary, the jump is
7813
 *      grown from two to five bytes; this is done if the jump distance is
7814
 *      greater than "distThreshold" (normally 127 bytes). The jump is
7815
 *      described by a JumpFixup record previously initialized by
7816
 *      TclEmitForwardJump.
7817
 *
7818
 * Results:
7819
 *      1 if the jump was grown and subsequent instructions had to be moved;
7820
 *      otherwise 0. This result is returned to allow callers to update
7821
 *      any additional code offsets they may hold.
7822
 *
7823
 * Side effects:
7824
 *      The jump may be grown and subsequent instructions moved. If this
7825
 *      happens, the code offsets for any commands and any ExceptionRange
7826
 *      records between the jump and the current code address will be
7827
 *      updated to reflect the moved code. Also, the bytecode instruction
7828
 *      array in the CompileEnv structure may be grown and reallocated.
7829
 *
7830
 *----------------------------------------------------------------------
7831
 */
7832
 
7833
int
7834
TclFixupForwardJump(envPtr, jumpFixupPtr, jumpDist, distThreshold)
7835
    CompileEnv *envPtr;         /* Points to the CompileEnv structure that
7836
                                 * holds the resulting instruction. */
7837
    JumpFixup *jumpFixupPtr;    /* Points to the JumpFixup structure that
7838
                                 * describes the forward jump. */
7839
    int jumpDist;               /* Jump distance to set in jump
7840
                                 * instruction. */
7841
    int distThreshold;          /* Maximum distance before the two byte
7842
                                 * jump is grown to five bytes. */
7843
{
7844
    unsigned char *jumpPc, *p;
7845
    int firstCmd, lastCmd, firstRange, lastRange, k;
7846
    unsigned int numBytes;
7847
 
7848
    if (jumpDist <= distThreshold) {
7849
        jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
7850
        switch (jumpFixupPtr->jumpType) {
7851
        case TCL_UNCONDITIONAL_JUMP:
7852
            TclUpdateInstInt1AtPc(INST_JUMP1, jumpDist, jumpPc);
7853
            break;
7854
        case TCL_TRUE_JUMP:
7855
            TclUpdateInstInt1AtPc(INST_JUMP_TRUE1, jumpDist, jumpPc);
7856
            break;
7857
        default:
7858
            TclUpdateInstInt1AtPc(INST_JUMP_FALSE1, jumpDist, jumpPc);
7859
            break;
7860
        }
7861
        return 0;
7862
    }
7863
 
7864
    /*
7865
     * We must grow the jump then move subsequent instructions down.
7866
     */
7867
 
7868
    TclEnsureCodeSpace(3, envPtr);  /* NB: might change code addresses! */
7869
    jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
7870
    for (numBytes = envPtr->codeNext-jumpPc-2, p = jumpPc+2+numBytes-1;
7871
            numBytes > 0;  numBytes--, p--) {
7872
        p[3] = p[0];
7873
    }
7874
    envPtr->codeNext += 3;
7875
    jumpDist += 3;
7876
    switch (jumpFixupPtr->jumpType) {
7877
    case TCL_UNCONDITIONAL_JUMP:
7878
        TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc);
7879
        break;
7880
    case TCL_TRUE_JUMP:
7881
        TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc);
7882
        break;
7883
    default:
7884
        TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc);
7885
        break;
7886
    }
7887
 
7888
    /*
7889
     * Adjust the code offsets for any commands and any ExceptionRange
7890
     * records between the jump and the current code address.
7891
     */
7892
 
7893
    firstCmd = jumpFixupPtr->cmdIndex;
7894
    lastCmd  = (envPtr->numCommands - 1);
7895
    if (firstCmd < lastCmd) {
7896
        for (k = firstCmd;  k <= lastCmd;  k++) {
7897
            (envPtr->cmdMapPtr[k]).codeOffset += 3;
7898
        }
7899
    }
7900
 
7901
    firstRange = jumpFixupPtr->excRangeIndex;
7902
    lastRange  = (envPtr->excRangeArrayNext - 1);
7903
    for (k = firstRange;  k <= lastRange;  k++) {
7904
        ExceptionRange *rangePtr = &(envPtr->excRangeArrayPtr[k]);
7905
        rangePtr->codeOffset += 3;
7906
 
7907
        switch (rangePtr->type) {
7908
        case LOOP_EXCEPTION_RANGE:
7909
            rangePtr->breakOffset += 3;
7910
            if (rangePtr->continueOffset != -1) {
7911
                rangePtr->continueOffset += 3;
7912
            }
7913
            break;
7914
        case CATCH_EXCEPTION_RANGE:
7915
            rangePtr->catchOffset += 3;
7916
            break;
7917
        default:
7918
            panic("TclFixupForwardJump: unrecognized ExceptionRange type %d\n", rangePtr->type);
7919
        }
7920
    }
7921
    return 1;                   /* the jump was grown */
7922
}
7923
 
7924
/*
7925
 *----------------------------------------------------------------------
7926
 *
7927
 * TclGetInstructionTable --
7928
 *
7929
 *  Returns a pointer to the table describing Tcl bytecode instructions.
7930
 *  This procedure is defined so that clients can access the pointer from
7931
 *  outside the TCL DLLs.
7932
 *
7933
 * Results:
7934
 *      Returns a pointer to the global instruction table, same as the expression
7935
 *  (&instructionTable[0]).
7936
 *
7937
 * Side effects:
7938
 *      None.
7939
 *
7940
 *----------------------------------------------------------------------
7941
 */
7942
 
7943
InstructionDesc *
7944
TclGetInstructionTable()
7945
{
7946
    return &instructionTable[0];
7947
}
7948
 
7949
/*
7950
 *--------------------------------------------------------------
7951
 *
7952
 * TclRegisterAuxDataType --
7953
 *
7954
 *      This procedure is called to register a new AuxData type
7955
 *      in the table of all AuxData types supported by Tcl.
7956
 *
7957
 * Results:
7958
 *      None.
7959
 *
7960
 * Side effects:
7961
 *      The type is registered in the AuxData type table. If there was already
7962
 *      a type with the same name as in typePtr, it is replaced with the
7963
 *      new type.
7964
 *
7965
 *--------------------------------------------------------------
7966
 */
7967
 
7968
void
7969
TclRegisterAuxDataType(typePtr)
7970
    AuxDataType *typePtr;       /* Information about object type;
7971
                             * storage must be statically
7972
                             * allocated (must live forever). */
7973
{
7974
    register Tcl_HashEntry *hPtr;
7975
    int new;
7976
 
7977
    if (!auxDataTypeTableInitialized) {
7978
        TclInitAuxDataTypeTable();
7979
    }
7980
 
7981
    /*
7982
     * If there's already a type with the given name, remove it.
7983
     */
7984
 
7985
    hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typePtr->name);
7986
    if (hPtr != (Tcl_HashEntry *) NULL) {
7987
        Tcl_DeleteHashEntry(hPtr);
7988
    }
7989
 
7990
    /*
7991
     * Now insert the new object type.
7992
     */
7993
 
7994
    hPtr = Tcl_CreateHashEntry(&auxDataTypeTable, typePtr->name, &new);
7995
    if (new) {
7996
        Tcl_SetHashValue(hPtr, typePtr);
7997
    }
7998
}
7999
 
8000
/*
8001
 *----------------------------------------------------------------------
8002
 *
8003
 * TclGetAuxDataType --
8004
 *
8005
 *      This procedure looks up an Auxdata type by name.
8006
 *
8007
 * Results:
8008
 *      If an AuxData type with name matching "typeName" is found, a pointer
8009
 *      to its AuxDataType structure is returned; otherwise, NULL is returned.
8010
 *
8011
 * Side effects:
8012
 *      None.
8013
 *
8014
 *----------------------------------------------------------------------
8015
 */
8016
 
8017
AuxDataType *
8018
TclGetAuxDataType(typeName)
8019
    char *typeName;             /* Name of AuxData type to look up. */
8020
{
8021
    register Tcl_HashEntry *hPtr;
8022
    AuxDataType *typePtr = NULL;
8023
 
8024
    if (!auxDataTypeTableInitialized) {
8025
        TclInitAuxDataTypeTable();
8026
    }
8027
 
8028
    hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typeName);
8029
    if (hPtr != (Tcl_HashEntry *) NULL) {
8030
        typePtr = (AuxDataType *) Tcl_GetHashValue(hPtr);
8031
    }
8032
 
8033
    return typePtr;
8034
}
8035
 
8036
/*
8037
 *--------------------------------------------------------------
8038
 *
8039
 * TclInitAuxDataTypeTable --
8040
 *
8041
 *      This procedure is invoked to perform once-only initialization of
8042
 *      the AuxData type table. It also registers the AuxData types defined in
8043
 *      this file.
8044
 *
8045
 * Results:
8046
 *      None.
8047
 *
8048
 * Side effects:
8049
 *      Initializes the table of defined AuxData types "auxDataTypeTable" with
8050
 *      builtin AuxData types defined in this file.
8051
 *
8052
 *--------------------------------------------------------------
8053
 */
8054
 
8055
void
8056
TclInitAuxDataTypeTable()
8057
{
8058
    auxDataTypeTableInitialized = 1;
8059
 
8060
    Tcl_InitHashTable(&auxDataTypeTable, TCL_STRING_KEYS);
8061
    TclRegisterAuxDataType(&tclForeachInfoType);
8062
}
8063
 
8064
/*
8065
 *----------------------------------------------------------------------
8066
 *
8067
 * TclFinalizeAuxDataTypeTable --
8068
 *
8069
 *      This procedure is called by Tcl_Finalize after all exit handlers
8070
 *      have been run to free up storage associated with the table of AuxData
8071
 *      types.
8072
 *
8073
 * Results:
8074
 *      None.
8075
 *
8076
 * Side effects:
8077
 *      Deletes all entries in the hash table of AuxData types, "auxDataTypeTable".
8078
 *
8079
 *----------------------------------------------------------------------
8080
 */
8081
 
8082
void
8083
TclFinalizeAuxDataTypeTable()
8084
{
8085
    if (auxDataTypeTableInitialized) {
8086
        Tcl_DeleteHashTable(&auxDataTypeTable);
8087
        auxDataTypeTableInitialized = 0;
8088
    }
8089
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.