source: HiSusy/trunk/Delphes-3.0.0/external/tcl/tclCompExpr.c @ 1

Last change on this file since 1 was 1, checked in by zerwas, 11 years ago

first import of structure, PYTHIA8 and DELPHES

File size: 67.8 KB
Line 
1/*
2 * tclCompExpr.c --
3 *
4 *      This file contains the code to compile Tcl expressions.
5 *
6 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
7 *
8 * See the file "license.terms" for information on usage and redistribution
9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10 *
11 * RCS: @(#) $Id: tclCompExpr.c,v 1.1 2008-06-04 13:58:05 demin Exp $
12 */
13
14#include "tclInt.h"
15#include "tclCompile.h"
16
17/*
18 * The stuff below is a bit of a hack so that this file can be used in
19 * environments that include no UNIX, i.e. no errno: just arrange to use
20 * the errno from tclExecute.c here.
21 */
22
23#ifndef TCL_GENERIC_ONLY
24#include "tclPort.h"
25#else
26#define NO_ERRNO_H
27#endif
28
29#ifdef NO_ERRNO_H
30extern int errno;                       /* Use errno from tclExecute.c. */
31#define ERANGE 34
32#endif
33
34/*
35 * Boolean variable that controls whether expression compilation tracing
36 * is enabled.
37 */
38
39#ifdef TCL_COMPILE_DEBUG
40static int traceCompileExpr = 0;
41#endif /* TCL_COMPILE_DEBUG */
42
43/*
44 * The ExprInfo structure describes the state of compiling an expression.
45 * A pointer to an ExprInfo record is passed among the routines in
46 * this module.
47 */
48
49typedef struct ExprInfo {
50    int token;                  /* Type of the last token parsed in expr.
51                                 * See below for definitions. Corresponds
52                                 * to the characters just before next. */
53    int objIndex;               /* If token is a literal value, the index of
54                                 * an object holding the value in the code's
55                                 * object table; otherwise is NULL. */
56    char *funcName;             /* If the token is FUNC_NAME, points to the
57                                 * first character of the math function's
58                                 * name; otherwise is NULL. */
59    char *next;                 /* Position of the next character to be
60                                 * scanned in the expression string. */
61    char *originalExpr;         /* The entire expression that was originally
62                                 * passed to Tcl_ExprString et al. */
63    char *lastChar;             /* Pointer to terminating null in
64                                 * originalExpr. */
65    int hasOperators;           /* Set 1 if the expr has operators; 0 if
66                                 * expr is only a primary. If 1 after
67                                 * compiling an expr, a tryCvtToNumeric
68                                 * instruction is emitted to convert the
69                                 * primary to a number if possible. */
70    int exprIsJustVarRef;       /* Set 1 if the expr consists of just a
71                                 * variable reference as in the expression
72                                 * of "if $b then...". Otherwise 0. If 1 the
73                                 * expr is compiled out-of-line in order to
74                                 * implement expr's 2 level substitution
75                                 * semantics properly. */
76    int exprIsComparison;       /* Set 1 if the top-level operator in the
77                                 * expr is a comparison. Otherwise 0. If 1,
78                                 * because the operands might be strings,
79                                 * the expr is compiled out-of-line in order
80                                 * to implement expr's 2 level substitution
81                                 * semantics properly. */
82} ExprInfo;
83
84/*
85 * Definitions of the different tokens that appear in expressions. The order
86 * of these must match the corresponding entries in the operatorStrings
87 * array below.
88 */
89
90#define LITERAL         0
91#define FUNC_NAME       (LITERAL + 1)
92#define OPEN_BRACKET    (LITERAL + 2)
93#define CLOSE_BRACKET   (LITERAL + 3)
94#define OPEN_PAREN      (LITERAL + 4)
95#define CLOSE_PAREN     (LITERAL + 5)
96#define DOLLAR          (LITERAL + 6)
97#define QUOTE           (LITERAL + 7)
98#define COMMA           (LITERAL + 8)
99#define END             (LITERAL + 9)
100#define UNKNOWN         (LITERAL + 10)
101
102/*
103 * Binary operators:
104 */
105
106#define MULT            (UNKNOWN + 1)
107#define DIVIDE          (MULT + 1)
108#define MOD             (MULT + 2)
109#define PLUS            (MULT + 3)
110#define MINUS           (MULT + 4)
111#define LEFT_SHIFT      (MULT + 5)
112#define RIGHT_SHIFT     (MULT + 6)
113#define LESS            (MULT + 7)
114#define GREATER         (MULT + 8)
115#define LEQ             (MULT + 9)
116#define GEQ             (MULT + 10)
117#define EQUAL           (MULT + 11)
118#define NEQ             (MULT + 12)
119#define BIT_AND         (MULT + 13)
120#define BIT_XOR         (MULT + 14)
121#define BIT_OR          (MULT + 15)
122#define AND             (MULT + 16)
123#define OR              (MULT + 17)
124#define QUESTY          (MULT + 18)
125#define COLON           (MULT + 19)
126
127/*
128 * Unary operators. Unary minus and plus are represented by the (binary)
129 * tokens MINUS and PLUS.
130 */
131
132#define NOT             (COLON + 1)
133#define BIT_NOT         (NOT + 1)
134
135/*
136 * Mapping from tokens to strings; used for debugging messages. These
137 * entries must match the order and number of the token definitions above.
138 */
139
140#ifdef TCL_COMPILE_DEBUG
141static char *tokenStrings[] = {
142    "LITERAL", "FUNCNAME",
143    "[", "]", "(", ")", "$", "\"", ",", "END", "UNKNOWN",
144    "*", "/", "%", "+", "-",
145    "<<", ">>", "<", ">", "<=", ">=", "==", "!=",
146    "&", "^", "|", "&&", "||", "?", ":",
147    "!", "~"
148};
149#endif /* TCL_COMPILE_DEBUG */
150
151/*
152 * Declarations for local procedures to this file:
153 */
154
155static int              CompileAddExpr _ANSI_ARGS_((Tcl_Interp *interp,
156                            ExprInfo *infoPtr, int flags,
157                            CompileEnv *envPtr));
158static int              CompileBitAndExpr _ANSI_ARGS_((Tcl_Interp *interp,
159                            ExprInfo *infoPtr, int flags,
160                            CompileEnv *envPtr));
161static int              CompileBitOrExpr _ANSI_ARGS_((Tcl_Interp *interp,
162                            ExprInfo *infoPtr, int flags,
163                            CompileEnv *envPtr));
164static int              CompileBitXorExpr _ANSI_ARGS_((Tcl_Interp *interp,
165                            ExprInfo *infoPtr, int flags,
166                            CompileEnv *envPtr));
167static int              CompileCondExpr _ANSI_ARGS_((Tcl_Interp *interp,
168                            ExprInfo *infoPtr, int flags,
169                            CompileEnv *envPtr));
170static int              CompileEqualityExpr _ANSI_ARGS_((Tcl_Interp *interp,
171                            ExprInfo *infoPtr, int flags,
172                            CompileEnv *envPtr));
173static int              CompileLandExpr _ANSI_ARGS_((Tcl_Interp *interp,
174                            ExprInfo *infoPtr, int flags,
175                            CompileEnv *envPtr));
176static int              CompileLorExpr _ANSI_ARGS_((Tcl_Interp *interp,
177                            ExprInfo *infoPtr, int flags,
178                            CompileEnv *envPtr));
179static int              CompileMathFuncCall _ANSI_ARGS_((Tcl_Interp *interp,
180                            ExprInfo *infoPtr, int flags,
181                            CompileEnv *envPtr));
182static int              CompileMultiplyExpr _ANSI_ARGS_((Tcl_Interp *interp,
183                            ExprInfo *infoPtr, int flags,
184                            CompileEnv *envPtr));
185static int              CompilePrimaryExpr _ANSI_ARGS_((Tcl_Interp *interp,
186                            ExprInfo *infoPtr, int flags,
187                            CompileEnv *envPtr));
188static int              CompileRelationalExpr _ANSI_ARGS_((
189                            Tcl_Interp *interp, ExprInfo *infoPtr,
190                            int flags, CompileEnv *envPtr));
191static int              CompileShiftExpr _ANSI_ARGS_((Tcl_Interp *interp,
192                            ExprInfo *infoPtr, int flags,
193                            CompileEnv *envPtr));
194static int              CompileUnaryExpr _ANSI_ARGS_((Tcl_Interp *interp,
195                            ExprInfo *infoPtr, int flags,
196                            CompileEnv *envPtr));
197static int              GetToken _ANSI_ARGS_((Tcl_Interp *interp,
198                            ExprInfo *infoPtr, CompileEnv *envPtr));
199
200/*
201 * Macro used to debug the execution of the recursive descent parser used
202 * to compile expressions.
203 */
204
205#ifdef TCL_COMPILE_DEBUG
206#define HERE(production, level) \
207    if (traceCompileExpr) { \
208        fprintf(stderr, "%*s%s: token=%s, next=\"%.20s\"\n", \
209                (level), " ", (production), tokenStrings[infoPtr->token], \
210                infoPtr->next); \
211    }
212#else
213#define HERE(production, level)
214#endif /* TCL_COMPILE_DEBUG */
215
216/*
217 *----------------------------------------------------------------------
218 *
219 * TclCompileExpr --
220 *
221 *      This procedure compiles a string containing a Tcl expression into
222 *      Tcl bytecodes. This procedure is the top-level interface to the
223 *      the expression compilation module, and is used by such public
224 *      procedures as Tcl_ExprString, Tcl_ExprStringObj, Tcl_ExprLong,
225 *      Tcl_ExprDouble, Tcl_ExprBoolean, and Tcl_ExprBooleanObj.
226 *
227 *      Note that the topmost recursive-descent parsing routine used by
228 *      TclCompileExpr to compile expressions is called "CompileCondExpr"
229 *      and not, e.g., "CompileExpr". This is done to avoid an extra
230 *      procedure call since such a procedure would only return the result
231 *      of calling CompileCondExpr. Other recursive-descent procedures
232 *      that need to parse expressions also call CompileCondExpr.
233 *
234 * Results:
235 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
236 *      on failure. If TCL_ERROR is returned, then the interpreter's result
237 *      contains an error message.
238 *
239 *      envPtr->termOffset is filled in with the offset of the character in
240 *      "string" just after the last one successfully processed; this might
241 *      be the offset of the ']' (if flags & TCL_BRACKET_TERM), or the
242 *      offset of the '\0' at the end of the string.
243 *
244 *      envPtr->maxStackDepth is updated with the maximum number of stack
245 *      elements needed to execute the expression.
246 *
247 *      envPtr->exprIsJustVarRef is set 1 if the expression consisted of
248 *      a single variable reference as in the expression of "if $b then...".
249 *      Otherwise it is set 0. This is used to implement Tcl's two level
250 *      expression substitution semantics properly.
251 *
252 *      envPtr->exprIsComparison is set 1 if the top-level operator in the
253 *      expr is a comparison. Otherwise it is set 0. If 1, because the
254 *      operands might be strings, the expr is compiled out-of-line in order
255 *      to implement expr's 2 level substitution semantics properly.
256 *
257 * Side effects:
258 *      Adds instructions to envPtr to evaluate the expression at runtime.
259 *
260 *----------------------------------------------------------------------
261 */
262
263int
264TclCompileExpr(interp, string, lastChar, flags, envPtr)
265    Tcl_Interp *interp;         /* Used for error reporting. */
266    char *string;               /* The source string to compile. */
267    char *lastChar;             /* Pointer to terminating character of
268                                 * string. */
269    int flags;                  /* Flags to control compilation (same as
270                                 * passed to Tcl_Eval). */
271    CompileEnv *envPtr;         /* Holds resulting instructions. */
272{
273    Interp *iPtr = (Interp *) interp;
274    ExprInfo info;
275    int maxDepth = 0;           /* Maximum number of stack elements needed
276                                 * to execute the expression. */
277    int result;
278
279#ifdef TCL_COMPILE_DEBUG
280    if (traceCompileExpr) {
281        fprintf(stderr, "expr: string=\"%.30s\"\n", string);
282    }
283#endif /* TCL_COMPILE_DEBUG */
284
285    /*
286     * Register the builtin math functions the first time an expression is
287     * compiled.
288     */
289
290    if (!(iPtr->flags & EXPR_INITIALIZED)) {
291        BuiltinFunc *funcPtr;
292        Tcl_HashEntry *hPtr;
293        MathFunc *mathFuncPtr;
294        int i;
295
296        iPtr->flags |= EXPR_INITIALIZED;
297        i = 0;
298        for (funcPtr = builtinFuncTable; funcPtr->name != NULL; funcPtr++) {
299            Tcl_CreateMathFunc(interp, funcPtr->name,
300                    funcPtr->numArgs, funcPtr->argTypes,
301                    (Tcl_MathProc *) NULL, (ClientData) 0);
302           
303            hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcPtr->name);
304            if (hPtr == NULL) {
305                panic("TclCompileExpr: Tcl_CreateMathFunc incorrectly registered '%s'", funcPtr->name);
306                return TCL_ERROR;
307            }
308            mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
309            mathFuncPtr->builtinFuncIndex = i;
310            i++;
311        }
312    }
313
314    info.token = UNKNOWN;
315    info.objIndex = -1;
316    info.funcName = NULL;
317    info.next = string;
318    info.originalExpr = string;
319    info.lastChar = lastChar;
320    info.hasOperators = 0;
321    info.exprIsJustVarRef = 1;  /* will be set 0 if anything else is seen */
322    info.exprIsComparison = 0;  /* set 1 if topmost operator is <,==,etc. */
323
324    /*
325     * Get the first token then compile an expression.
326     */
327
328    result = GetToken(interp, &info, envPtr);
329    if (result != TCL_OK) {
330        goto done;
331    }
332   
333    result = CompileCondExpr(interp, &info, flags, envPtr);
334    if (result != TCL_OK) {
335        goto done;
336    }
337    if (info.token != END) {
338        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
339                "syntax error in expression \"", string, "\"", (char *) NULL);
340        result = TCL_ERROR;
341        goto done;
342    }
343    if (!info.hasOperators) {
344        /*
345         * Attempt to convert the primary's object to an int or double.
346         * This is done in order to support Tcl's policy of interpreting
347         * operands if at all possible as first integers, else
348         * floating-point numbers.
349         */
350       
351        TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
352    }
353    maxDepth = envPtr->maxStackDepth;
354
355    done:
356    envPtr->termOffset = (info.next - string);
357    envPtr->maxStackDepth = maxDepth;
358    envPtr->exprIsJustVarRef = info.exprIsJustVarRef;
359    envPtr->exprIsComparison = info.exprIsComparison;
360    return result;
361}
362
363/*
364 *----------------------------------------------------------------------
365 *
366 * CompileCondExpr --
367 *
368 *      This procedure compiles a Tcl conditional expression:
369 *      condExpr ::= lorExpr ['?' condExpr ':' condExpr]
370 *
371 *      Note that this is the topmost recursive-descent parsing routine used
372 *      by TclCompileExpr to compile expressions. It does not call an
373 *      separate, higher-level "CompileExpr" procedure. This avoids an extra
374 *      procedure call since such a procedure would only return the result
375 *      of calling CompileCondExpr. Other recursive-descent procedures that
376 *      need to parse expressions also call CompileCondExpr.
377 *
378 * Results:
379 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
380 *      on failure. If TCL_ERROR is returned, then the interpreter's result
381 *      contains an error message.
382 *
383 *      envPtr->maxStackDepth is updated with the maximum number of stack
384 *      elements needed to execute the expression.
385 *
386 * Side effects:
387 *      Adds instructions to envPtr to evaluate the expression at runtime.
388 *
389 *----------------------------------------------------------------------
390 */
391
392static int
393CompileCondExpr(interp, infoPtr, flags, envPtr)
394    Tcl_Interp *interp;         /* Used for error reporting. */
395    ExprInfo *infoPtr;          /* Describes the compilation state for the
396                                 * expression being compiled. */
397    int flags;                  /* Flags to control compilation (same as
398                                 * passed to Tcl_Eval). */
399    CompileEnv *envPtr;         /* Holds resulting instructions. */
400{
401    int maxDepth = 0;           /* Maximum number of stack elements needed
402                                 * to execute the expression. */
403    JumpFixup jumpAroundThenFixup, jumpAroundElseFixup;
404                                /* Used to update or replace one-byte jumps
405                                 * around the then and else expressions when
406                                 * their target PCs are determined. */
407    int elseCodeOffset, currCodeOffset, jumpDist, result;
408   
409    HERE("condExpr", 1);
410    result = CompileLorExpr(interp, infoPtr, flags, envPtr);
411    if (result != TCL_OK) {
412        goto done;
413    }
414    maxDepth = envPtr->maxStackDepth;
415   
416    if (infoPtr->token == QUESTY) {
417        result = GetToken(interp, infoPtr, envPtr); /* skip over the '?' */
418        if (result != TCL_OK) {
419            goto done;
420        }
421
422        /*
423         * Emit the jump around the "then" clause to the "else" condExpr if
424         * the test was false. We emit a one byte (relative) jump here, and
425         * replace it later with a four byte jump if the jump target is more
426         * than 127 bytes away.
427         */
428
429        TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpAroundThenFixup);
430
431        /*
432         * Compile the "then" expression. Note that if a subexpression
433         * is only a primary, we need to try to convert it to numeric.
434         * This is done in order to support Tcl's policy of interpreting
435         * operands if at all possible as first integers, else
436         * floating-point numbers.
437         */
438
439        infoPtr->hasOperators = 0;
440        infoPtr->exprIsJustVarRef = 0;
441        infoPtr->exprIsComparison = 0;
442        result = CompileCondExpr(interp, infoPtr, flags, envPtr);
443        if (result != TCL_OK) {
444            goto done;
445        }
446        maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
447        if (infoPtr->token != COLON) {
448            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
449                    "syntax error in expression \"", infoPtr->originalExpr,
450                    "\"", (char *) NULL);
451            result = TCL_ERROR;
452            goto done;
453        }
454        if (!infoPtr->hasOperators) {
455            TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
456        }
457        result = GetToken(interp, infoPtr, envPtr); /* skip over the ':' */
458        if (result != TCL_OK) {
459            goto done;
460        }
461
462        /*
463         * Emit an unconditional jump around the "else" condExpr.
464         */
465
466        TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
467                &jumpAroundElseFixup);
468
469        /*
470         * Compile the "else" expression.
471         */
472
473        infoPtr->hasOperators = 0;
474        elseCodeOffset = TclCurrCodeOffset();
475        result = CompileCondExpr(interp, infoPtr, flags, envPtr);
476        if (result != TCL_OK) {
477            goto done;
478        }
479        maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
480        if (!infoPtr->hasOperators) {
481            TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
482        }
483
484        /*
485         * Fix up the second jump: the unconditional jump around the "else"
486         * expression. If the distance is too great (> 127 bytes), replace
487         * it with a four byte instruction and move the instructions after
488         * the jump down.
489         */
490
491        currCodeOffset = TclCurrCodeOffset();
492        jumpDist = (currCodeOffset - jumpAroundElseFixup.codeOffset);
493        if (TclFixupForwardJump(envPtr, &jumpAroundElseFixup, jumpDist, 127)) {
494            /*
495             * Update the else expression's starting code offset since it
496             * moved down 3 bytes too.
497             */
498           
499            elseCodeOffset += 3;
500        }
501       
502        /*
503         * Now fix up the first branch: the jumpFalse after the test. If the
504         * distance is too great, replace it with a four byte instruction
505         * and update the code offsets for the commands in both the "then"
506         * and "else" expressions.
507         */
508
509        jumpDist = (elseCodeOffset - jumpAroundThenFixup.codeOffset);
510        TclFixupForwardJump(envPtr, &jumpAroundThenFixup, jumpDist, 127);
511
512        infoPtr->hasOperators = 1;
513
514        /*
515         * A comparison is not the top-level operator in this expression.
516         */
517
518        infoPtr->exprIsComparison = 0;
519    }
520
521    done:
522    envPtr->maxStackDepth = maxDepth;
523    return result;
524}
525
526/*
527 *----------------------------------------------------------------------
528 *
529 * CompileLorExpr --
530 *
531 *      This procedure compiles a Tcl logical or expression:
532 *      lorExpr ::= landExpr {'||' landExpr}
533 *
534 * Results:
535 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
536 *      on failure. If TCL_ERROR is returned, then the interpreter's result
537 *      contains an error message.
538 *
539 *      envPtr->maxStackDepth is updated with the maximum number of stack
540 *      elements needed to execute the expression.
541 *
542 * Side effects:
543 *      Adds instructions to envPtr to evaluate the expression at runtime.
544 *
545 *----------------------------------------------------------------------
546 */
547
548static int
549CompileLorExpr(interp, infoPtr, flags, envPtr)
550    Tcl_Interp *interp;         /* Used for error reporting. */
551    ExprInfo *infoPtr;          /* Describes the compilation state for the
552                                 * expression being compiled. */
553    int flags;                  /* Flags to control compilation (same as
554                                 * passed to Tcl_Eval). */
555    CompileEnv *envPtr;         /* Holds resulting instructions. */
556{
557    int maxDepth;               /* Maximum number of stack elements needed
558                                 * to execute the expression. */
559    JumpFixupArray jumpFixupArray;
560                                /* Used to fix up the forward "short
561                                 * circuit" jump after each or-ed
562                                 * subexpression to just after the last
563                                 * subexpression. */
564    JumpFixup jumpTrueFixup, jumpFixup;
565                                /* Used to emit the jumps in the code to
566                                 * convert the first operand to a 0 or 1. */
567    int fixupIndex, jumpDist, currCodeOffset, objIndex, j, result;
568    Tcl_Obj *objPtr;
569   
570    HERE("lorExpr", 2);
571    result = CompileLandExpr(interp, infoPtr, flags, envPtr);
572    if ((result != TCL_OK) || (infoPtr->token != OR)) {
573        return result;          /* envPtr->maxStackDepth is already set */
574    }
575
576    infoPtr->hasOperators = 1;
577    infoPtr->exprIsJustVarRef = 0;
578    maxDepth = envPtr->maxStackDepth;
579    TclInitJumpFixupArray(&jumpFixupArray);
580    while (infoPtr->token == OR) {
581        result = GetToken(interp, infoPtr, envPtr); /* skip over the '||' */
582        if (result != TCL_OK) {
583            goto done;
584        }
585
586        if (jumpFixupArray.next == 0) {
587            /*
588             * Just the first "lor" operand is on the stack. The following
589             * is slightly ugly: we need to convert that first "lor" operand
590             * to a "0" or "1" to get the correct result if it is nonzero.
591             * Eventually we'll use a new instruction for this.
592             */
593
594            TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &jumpTrueFixup);
595           
596            objIndex = TclObjIndexForString("0", 1, /*allocStrRep*/ 0,
597                                            /*inHeap*/ 0, envPtr);
598            objPtr = envPtr->objArrayPtr[objIndex];
599
600            Tcl_InvalidateStringRep(objPtr);
601            objPtr->internalRep.longValue = 0;
602            objPtr->typePtr = &tclIntType;
603           
604            TclEmitPush(objIndex, envPtr);
605            TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
606
607            jumpDist = (TclCurrCodeOffset() - jumpTrueFixup.codeOffset);
608            if (TclFixupForwardJump(envPtr, &jumpTrueFixup, jumpDist, 127)) {
609                panic("CompileLorExpr: bad jump distance %d\n", jumpDist);
610            }
611            objIndex = TclObjIndexForString("1", 1, /*allocStrRep*/ 0,
612                                            /*inHeap*/ 0, envPtr);
613            objPtr = envPtr->objArrayPtr[objIndex];
614
615            Tcl_InvalidateStringRep(objPtr);
616            objPtr->internalRep.longValue = 1;
617            objPtr->typePtr = &tclIntType;
618           
619            TclEmitPush(objIndex, envPtr);
620
621            jumpDist = (TclCurrCodeOffset() - jumpFixup.codeOffset);
622            if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) {
623                panic("CompileLorExpr: bad jump distance %d\n", jumpDist);
624            }
625        }
626
627        /*
628         * Duplicate the value on top of the stack to prevent the jump from
629         * consuming it.
630         */
631
632        TclEmitOpcode(INST_DUP, envPtr);
633
634        /*
635         * Emit the "short circuit" jump around the rest of the lorExp if
636         * the previous expression was true. We emit a one byte (relative)
637         * jump here, and replace it later with a four byte jump if the jump
638         * target is more than 127 bytes away.
639         */
640
641        if (jumpFixupArray.next == jumpFixupArray.end) {
642            TclExpandJumpFixupArray(&jumpFixupArray);
643        }
644        fixupIndex = jumpFixupArray.next;
645        jumpFixupArray.next++;
646        TclEmitForwardJump(envPtr, TCL_TRUE_JUMP,
647                &(jumpFixupArray.fixup[fixupIndex]));
648       
649        /*
650         * Compile the subexpression.
651         */
652
653        result = CompileLandExpr(interp, infoPtr, flags, envPtr);
654        if (result != TCL_OK) {
655            goto done;
656        }
657        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
658
659        /*
660         * Emit a "logical or" instruction. This does not try to "short-
661         * circuit" the evaluation of both operands of a Tcl "||" operator,
662         * but instead ensures that we either have a "1" or a "0" result.
663         */
664
665        TclEmitOpcode(INST_LOR, envPtr);
666    }
667
668    /*
669     * Now that we know the target of the forward jumps, update the jumps
670     * with the correct distance. Also, if the distance is too great (> 127
671     * bytes), replace the jump with a four byte instruction and move the
672     * instructions after the jump down.
673     */
674   
675    for (j = jumpFixupArray.next;  j > 0;  j--) {
676        fixupIndex = (j - 1);   /* process closest jump first */
677        currCodeOffset = TclCurrCodeOffset();
678        jumpDist = (currCodeOffset - jumpFixupArray.fixup[fixupIndex].codeOffset);
679        TclFixupForwardJump(envPtr, &(jumpFixupArray.fixup[fixupIndex]), jumpDist, 127);
680    }
681
682    /*
683     * We get here only if one or more ||'s appear as top-level operators.
684     */
685
686    done:
687    infoPtr->exprIsComparison = 0;
688    TclFreeJumpFixupArray(&jumpFixupArray);
689    envPtr->maxStackDepth = maxDepth;
690    return result;
691}
692
693/*
694 *----------------------------------------------------------------------
695 *
696 * CompileLandExpr --
697 *
698 *      This procedure compiles a Tcl logical and expression:
699 *      landExpr ::= bitOrExpr {'&&' bitOrExpr}
700 *
701 * Results:
702 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
703 *      on failure. If TCL_ERROR is returned, then the interpreter's result
704 *      contains an error message.
705 *
706 *      envPtr->maxStackDepth is updated with the maximum number of stack
707 *      elements needed to execute the expression.
708 *
709 * Side effects:
710 *      Adds instructions to envPtr to evaluate the expression at runtime.
711 *
712 *----------------------------------------------------------------------
713 */
714
715static int
716CompileLandExpr(interp, infoPtr, flags, envPtr)
717    Tcl_Interp *interp;         /* Used for error reporting. */
718    ExprInfo *infoPtr;          /* Describes the compilation state for the
719                                 * expression being compiled. */
720    int flags;                  /* Flags to control compilation (same as
721                                 * passed to Tcl_Eval). */
722    CompileEnv *envPtr;         /* Holds resulting instructions. */
723{
724    int maxDepth;               /* Maximum number of stack elements needed
725                                 * to execute the expression. */
726    JumpFixupArray jumpFixupArray;
727                                /* Used to fix up the forward "short
728                                 * circuit" jump after each and-ed
729                                 * subexpression to just after the last
730                                 * subexpression. */
731    JumpFixup jumpTrueFixup, jumpFixup;
732                                /* Used to emit the jumps in the code to
733                                 * convert the first operand to a 0 or 1. */
734    int fixupIndex, jumpDist, currCodeOffset, objIndex, j, result;
735    Tcl_Obj *objPtr;
736
737    HERE("landExpr", 3);
738    result = CompileBitOrExpr(interp, infoPtr, flags, envPtr);
739    if ((result != TCL_OK) || (infoPtr->token != AND)) {
740        return result;          /* envPtr->maxStackDepth is already set */
741    }
742
743    infoPtr->hasOperators = 1;
744    infoPtr->exprIsJustVarRef = 0;
745    maxDepth = envPtr->maxStackDepth;
746    TclInitJumpFixupArray(&jumpFixupArray);
747    while (infoPtr->token == AND) {
748        result = GetToken(interp, infoPtr, envPtr); /* skip over the '&&' */
749        if (result != TCL_OK) {
750            goto done;
751        }
752
753        if (jumpFixupArray.next == 0) {
754            /*
755             * Just the first "land" operand is on the stack. The following
756             * is slightly ugly: we need to convert the first "land" operand
757             * to a "0" or "1" to get the correct result if it is
758             * nonzero. Eventually we'll use a new instruction.
759             */
760
761            TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &jumpTrueFixup);
762             
763            objIndex = TclObjIndexForString("0", 1, /*allocStrRep*/ 0,
764                                            /*inHeap*/ 0, envPtr);
765            objPtr = envPtr->objArrayPtr[objIndex];
766
767            Tcl_InvalidateStringRep(objPtr);
768            objPtr->internalRep.longValue = 0;
769            objPtr->typePtr = &tclIntType;
770           
771            TclEmitPush(objIndex, envPtr);
772            TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
773
774            jumpDist = (TclCurrCodeOffset() - jumpTrueFixup.codeOffset);
775            if (TclFixupForwardJump(envPtr, &jumpTrueFixup, jumpDist, 127)) {
776                panic("CompileLandExpr: bad jump distance %d\n", jumpDist);
777            }
778            objIndex = TclObjIndexForString("1", 1, /*allocStrRep*/ 0,
779                                            /*inHeap*/ 0, envPtr);
780            objPtr = envPtr->objArrayPtr[objIndex];
781
782            Tcl_InvalidateStringRep(objPtr);
783            objPtr->internalRep.longValue = 1;
784            objPtr->typePtr = &tclIntType;
785           
786            TclEmitPush(objIndex, envPtr);
787
788            jumpDist = (TclCurrCodeOffset() - jumpFixup.codeOffset);
789            if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) {
790                panic("CompileLandExpr: bad jump distance %d\n", jumpDist);
791            }
792        }
793
794        /*
795         * Duplicate the value on top of the stack to prevent the jump from
796         * consuming it.
797         */
798
799        TclEmitOpcode(INST_DUP, envPtr);
800
801        /*
802         * Emit the "short circuit" jump around the rest of the landExp if
803         * the previous expression was false. We emit a one byte (relative)
804         * jump here, and replace it later with a four byte jump if the jump
805         * target is more than 127 bytes away.
806         */
807
808        if (jumpFixupArray.next == jumpFixupArray.end) {
809            TclExpandJumpFixupArray(&jumpFixupArray);
810        }
811        fixupIndex = jumpFixupArray.next;
812        jumpFixupArray.next++;
813        TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
814                &(jumpFixupArray.fixup[fixupIndex]));
815       
816        /*
817         * Compile the subexpression.
818         */
819
820        result = CompileBitOrExpr(interp, infoPtr, flags, envPtr);
821        if (result != TCL_OK) {
822            goto done;
823        }
824        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
825
826        /*
827         * Emit a "logical and" instruction. This does not try to "short-
828         * circuit" the evaluation of both operands of a Tcl "&&" operator,
829         * but instead ensures that we either have a "1" or a "0" result.
830         */
831
832        TclEmitOpcode(INST_LAND, envPtr);
833    }
834
835    /*
836     * Now that we know the target of the forward jumps, update the jumps
837     * with the correct distance. Also, if the distance is too great (> 127
838     * bytes), replace the jump with a four byte instruction and move the
839     * instructions after the jump down.
840     */
841   
842    for (j = jumpFixupArray.next;  j > 0;  j--) {
843        fixupIndex = (j - 1);   /* process closest jump first */
844        currCodeOffset = TclCurrCodeOffset();
845        jumpDist = (currCodeOffset - jumpFixupArray.fixup[fixupIndex].codeOffset);
846        TclFixupForwardJump(envPtr, &(jumpFixupArray.fixup[fixupIndex]),
847                jumpDist, 127);
848    }
849
850    /*
851     * We get here only if one or more &&'s appear as top-level operators.
852     */
853
854    done:
855    infoPtr->exprIsComparison = 0;
856    TclFreeJumpFixupArray(&jumpFixupArray);
857    envPtr->maxStackDepth = maxDepth;
858    return result;
859}
860
861/*
862 *----------------------------------------------------------------------
863 *
864 * CompileBitOrExpr --
865 *
866 *      This procedure compiles a Tcl bitwise or expression:
867 *      bitOrExpr ::= bitXorExpr {'|' bitXorExpr}
868 *
869 * Results:
870 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
871 *      on failure. If TCL_ERROR is returned, then the interpreter's result
872 *      contains an error message.
873 *
874 *      envPtr->maxStackDepth is updated with the maximum number of stack
875 *      elements needed to execute the expression.
876 *
877 * Side effects:
878 *      Adds instructions to envPtr to evaluate the expression at runtime.
879 *
880 *----------------------------------------------------------------------
881 */
882
883static int
884CompileBitOrExpr(interp, infoPtr, flags, envPtr)
885    Tcl_Interp *interp;         /* Used for error reporting. */
886    ExprInfo *infoPtr;          /* Describes the compilation state for the
887                                 * expression being compiled. */
888    int flags;                  /* Flags to control compilation (same as
889                                 * passed to Tcl_Eval). */
890    CompileEnv *envPtr;         /* Holds resulting instructions. */
891{
892    int maxDepth = 0;           /* Maximum number of stack elements needed
893                                 * to execute the expression. */
894    int result;
895
896    HERE("bitOrExpr", 4);
897    result = CompileBitXorExpr(interp, infoPtr, flags, envPtr);
898    if (result != TCL_OK) {
899        goto done;
900    }
901    maxDepth = envPtr->maxStackDepth;
902   
903    while (infoPtr->token == BIT_OR) {
904        infoPtr->hasOperators = 1;
905        infoPtr->exprIsJustVarRef = 0;
906        result = GetToken(interp, infoPtr, envPtr); /* skip over the '|' */
907        if (result != TCL_OK) {
908            goto done;
909        }
910
911        result = CompileBitXorExpr(interp, infoPtr, flags, envPtr);
912        if (result != TCL_OK) {
913            goto done;
914        }
915        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
916       
917        TclEmitOpcode(INST_BITOR, envPtr);
918
919        /*
920         * A comparison is not the top-level operator in this expression.
921         */
922
923        infoPtr->exprIsComparison = 0;
924    }
925
926    done:
927    envPtr->maxStackDepth = maxDepth;
928    return result;
929}
930
931/*
932 *----------------------------------------------------------------------
933 *
934 * CompileBitXorExpr --
935 *
936 *      This procedure compiles a Tcl bitwise exclusive or expression:
937 *      bitXorExpr ::= bitAndExpr {'^' bitAndExpr}
938 *
939 * Results:
940 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
941 *      on failure. If TCL_ERROR is returned, then the interpreter's result
942 *      contains an error message.
943 *
944 *      envPtr->maxStackDepth is updated with the maximum number of stack
945 *      elements needed to execute the expression.
946 *
947 * Side effects:
948 *      Adds instructions to envPtr to evaluate the expression at runtime.
949 *
950 *----------------------------------------------------------------------
951 */
952
953static int
954CompileBitXorExpr(interp, infoPtr, flags, envPtr)
955    Tcl_Interp *interp;         /* Used for error reporting. */
956    ExprInfo *infoPtr;          /* Describes the compilation state for the
957                                 * expression being compiled. */
958    int flags;                  /* Flags to control compilation (same as
959                                 * passed to Tcl_Eval). */
960    CompileEnv *envPtr;         /* Holds resulting instructions. */
961{
962    int maxDepth = 0;           /* Maximum number of stack elements needed
963                                 * to execute the expression. */
964    int result;
965
966    HERE("bitXorExpr", 5);
967    result = CompileBitAndExpr(interp, infoPtr, flags, envPtr);
968    if (result != TCL_OK) {
969        goto done;
970    }
971    maxDepth = envPtr->maxStackDepth;
972   
973    while (infoPtr->token == BIT_XOR) {
974        infoPtr->hasOperators = 1;
975        infoPtr->exprIsJustVarRef = 0;
976        result = GetToken(interp, infoPtr, envPtr); /* skip over the '^' */
977        if (result != TCL_OK) {
978            goto done;
979        }
980
981        result = CompileBitAndExpr(interp, infoPtr, flags, envPtr);
982        if (result != TCL_OK) {
983            goto done;
984        }
985        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
986       
987        TclEmitOpcode(INST_BITXOR, envPtr);
988
989        /*
990         * A comparison is not the top-level operator in this expression.
991         */
992
993        infoPtr->exprIsComparison = 0;
994    }
995
996    done:
997    envPtr->maxStackDepth = maxDepth;
998    return result;
999}
1000
1001/*
1002 *----------------------------------------------------------------------
1003 *
1004 * CompileBitAndExpr --
1005 *
1006 *      This procedure compiles a Tcl bitwise and expression:
1007 *      bitAndExpr ::= equalityExpr {'&' equalityExpr}
1008 *
1009 * Results:
1010 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1011 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1012 *      contains an error message.
1013 *
1014 *      envPtr->maxStackDepth is updated with the maximum number of stack
1015 *      elements needed to execute the expression.
1016 *
1017 * Side effects:
1018 *      Adds instructions to envPtr to evaluate the expression at runtime.
1019 *
1020 *----------------------------------------------------------------------
1021 */
1022
1023static int
1024CompileBitAndExpr(interp, infoPtr, flags, envPtr)
1025    Tcl_Interp *interp;         /* Used for error reporting. */
1026    ExprInfo *infoPtr;          /* Describes the compilation state for the
1027                                 * expression being compiled. */
1028    int flags;                  /* Flags to control compilation (same as
1029                                 * passed to Tcl_Eval). */
1030    CompileEnv *envPtr;         /* Holds resulting instructions. */
1031{
1032    int maxDepth = 0;           /* Maximum number of stack elements needed
1033                                 * to execute the expression. */
1034    int result;
1035
1036    HERE("bitAndExpr", 6);
1037    result = CompileEqualityExpr(interp, infoPtr, flags, envPtr);
1038    if (result != TCL_OK) {
1039        goto done;
1040    }
1041    maxDepth = envPtr->maxStackDepth;
1042   
1043    while (infoPtr->token == BIT_AND) {
1044        infoPtr->hasOperators = 1;
1045        infoPtr->exprIsJustVarRef = 0;
1046        result = GetToken(interp, infoPtr, envPtr); /* skip over the '&' */
1047        if (result != TCL_OK) {
1048            goto done;
1049        }
1050
1051        result = CompileEqualityExpr(interp, infoPtr, flags, envPtr);
1052        if (result != TCL_OK) {
1053            goto done;
1054        }
1055        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
1056       
1057        TclEmitOpcode(INST_BITAND, envPtr);
1058
1059        /*
1060         * A comparison is not the top-level operator in this expression.
1061         */
1062
1063        infoPtr->exprIsComparison = 0;
1064    }
1065
1066    done:
1067    envPtr->maxStackDepth = maxDepth;
1068    return result;
1069}
1070
1071/*
1072 *----------------------------------------------------------------------
1073 *
1074 * CompileEqualityExpr --
1075 *
1076 *      This procedure compiles a Tcl equality (inequality) expression:
1077 *      equalityExpr ::= relationalExpr {('==' | '!=') relationalExpr}
1078 *
1079 * Results:
1080 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1081 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1082 *      contains an error message.
1083 *
1084 *      envPtr->maxStackDepth is updated with the maximum number of stack
1085 *      elements needed to execute the expression.
1086 *
1087 * Side effects:
1088 *      Adds instructions to envPtr to evaluate the expression at runtime.
1089 *
1090 *----------------------------------------------------------------------
1091 */
1092
1093static int
1094CompileEqualityExpr(interp, infoPtr, flags, envPtr)
1095    Tcl_Interp *interp;         /* Used for error reporting. */
1096    ExprInfo *infoPtr;          /* Describes the compilation state for the
1097                                 * expression being compiled. */
1098    int flags;                  /* Flags to control compilation (same as
1099                                 * passed to Tcl_Eval). */
1100    CompileEnv *envPtr;         /* Holds resulting instructions. */
1101{
1102    int maxDepth = 0;           /* Maximum number of stack elements needed
1103                                 * to execute the expression. */
1104    int op, result;
1105
1106    HERE("equalityExpr", 7);
1107    result = CompileRelationalExpr(interp, infoPtr, flags, envPtr);
1108    if (result != TCL_OK) {
1109        goto done;
1110    }
1111    maxDepth = envPtr->maxStackDepth;
1112
1113    op = infoPtr->token;
1114    while ((op == EQUAL) || (op == NEQ)) {
1115        infoPtr->hasOperators = 1;
1116        infoPtr->exprIsJustVarRef = 0;
1117        result = GetToken(interp, infoPtr, envPtr); /* skip over == or != */
1118        if (result != TCL_OK) {
1119            goto done;
1120        }
1121
1122        result = CompileRelationalExpr(interp, infoPtr, flags, envPtr);
1123        if (result != TCL_OK) {
1124            goto done;
1125        }
1126        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
1127
1128        if (op == EQUAL) {
1129            TclEmitOpcode(INST_EQ, envPtr);
1130        } else {
1131            TclEmitOpcode(INST_NEQ, envPtr);
1132        }
1133       
1134        op = infoPtr->token;
1135
1136        /*
1137         * A comparison _is_ the top-level operator in this expression.
1138         */
1139       
1140        infoPtr->exprIsComparison = 1;
1141    }
1142
1143    done:
1144    envPtr->maxStackDepth = maxDepth;
1145    return result;
1146}
1147
1148/*
1149 *----------------------------------------------------------------------
1150 *
1151 * CompileRelationalExpr --
1152 *
1153 *      This procedure compiles a Tcl relational expression:
1154 *      relationalExpr ::= shiftExpr {('<' | '>' | '<=' | '>=') shiftExpr}
1155 *
1156 * Results:
1157 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1158 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1159 *      contains an error message.
1160 *
1161 *      envPtr->maxStackDepth is updated with the maximum number of stack
1162 *      elements needed to execute the expression.
1163 *
1164 * Side effects:
1165 *      Adds instructions to envPtr to evaluate the expression at runtime.
1166 *
1167 *----------------------------------------------------------------------
1168 */
1169
1170static int
1171CompileRelationalExpr(interp, infoPtr, flags, envPtr)
1172    Tcl_Interp *interp;         /* Used for error reporting. */
1173    ExprInfo *infoPtr;          /* Describes the compilation state for the
1174                                 * expression being compiled. */
1175    int flags;                  /* Flags to control compilation (same as
1176                                 * passed to Tcl_Eval). */
1177    CompileEnv *envPtr;         /* Holds resulting instructions. */
1178{
1179    int maxDepth = 0;           /* Maximum number of stack elements needed
1180                                 * to execute the expression. */
1181    int op, result;
1182
1183    HERE("relationalExpr", 8);
1184    result = CompileShiftExpr(interp, infoPtr, flags, envPtr);
1185    if (result != TCL_OK) {
1186        goto done;
1187    }
1188    maxDepth = envPtr->maxStackDepth;
1189
1190    op = infoPtr->token;
1191    while ((op == LESS) || (op == GREATER) || (op == LEQ) || (op == GEQ)) {
1192        infoPtr->hasOperators = 1;
1193        infoPtr->exprIsJustVarRef = 0;
1194        result = GetToken(interp, infoPtr, envPtr); /* skip over the op */
1195        if (result != TCL_OK) {
1196            goto done;
1197        }
1198
1199        result = CompileShiftExpr(interp, infoPtr, flags, envPtr);
1200        if (result != TCL_OK) {
1201            goto done;
1202        }
1203        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
1204
1205        switch (op) {
1206        case LESS:
1207            TclEmitOpcode(INST_LT, envPtr);
1208            break;
1209        case GREATER:
1210            TclEmitOpcode(INST_GT, envPtr);
1211            break;
1212        case LEQ:
1213            TclEmitOpcode(INST_LE, envPtr);
1214            break;
1215        case GEQ:
1216            TclEmitOpcode(INST_GE, envPtr);
1217            break;
1218        }
1219
1220        op = infoPtr->token;
1221
1222        /*
1223         * A comparison _is_ the top-level operator in this expression.
1224         */
1225       
1226        infoPtr->exprIsComparison = 1;
1227    }
1228
1229    done:
1230    envPtr->maxStackDepth = maxDepth;
1231    return result;
1232}
1233
1234/*
1235 *----------------------------------------------------------------------
1236 *
1237 * CompileShiftExpr --
1238 *
1239 *      This procedure compiles a Tcl shift expression:
1240 *      shiftExpr ::= addExpr {('<<' | '>>') addExpr}
1241 *
1242 * Results:
1243 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1244 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1245 *      contains an error message.
1246 *
1247 *      envPtr->maxStackDepth is updated with the maximum number of stack
1248 *      elements needed to execute the expression.
1249 *
1250 * Side effects:
1251 *      Adds instructions to envPtr to evaluate the expression at runtime.
1252 *
1253 *----------------------------------------------------------------------
1254 */
1255
1256static int
1257CompileShiftExpr(interp, infoPtr, flags, envPtr)
1258    Tcl_Interp *interp;         /* Used for error reporting. */
1259    ExprInfo *infoPtr;          /* Describes the compilation state for the
1260                                 * expression being compiled. */
1261    int flags;                  /* Flags to control compilation (same as
1262                                 * passed to Tcl_Eval). */
1263    CompileEnv *envPtr;         /* Holds resulting instructions. */
1264{
1265    int maxDepth = 0;           /* Maximum number of stack elements needed
1266                                 * to execute the expression. */
1267    int op, result;
1268
1269    HERE("shiftExpr", 9);
1270    result = CompileAddExpr(interp, infoPtr, flags, envPtr);
1271    if (result != TCL_OK) {
1272        goto done;
1273    }
1274    maxDepth = envPtr->maxStackDepth;
1275
1276    op = infoPtr->token;
1277    while ((op == LEFT_SHIFT) || (op == RIGHT_SHIFT)) {
1278        infoPtr->hasOperators = 1;
1279        infoPtr->exprIsJustVarRef = 0;
1280        result = GetToken(interp, infoPtr, envPtr); /* skip over << or >> */
1281        if (result != TCL_OK) {
1282            goto done;
1283        }
1284
1285        result = CompileAddExpr(interp, infoPtr, flags, envPtr);
1286        if (result != TCL_OK) {
1287            goto done;
1288        }
1289        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
1290
1291        if (op == LEFT_SHIFT) {
1292            TclEmitOpcode(INST_LSHIFT, envPtr);
1293        } else {
1294            TclEmitOpcode(INST_RSHIFT, envPtr);
1295        }
1296
1297        op = infoPtr->token;
1298
1299        /*
1300         * A comparison is not the top-level operator in this expression.
1301         */
1302
1303        infoPtr->exprIsComparison = 0;
1304    }
1305
1306    done:
1307    envPtr->maxStackDepth = maxDepth;
1308    return result;
1309}
1310
1311/*
1312 *----------------------------------------------------------------------
1313 *
1314 * CompileAddExpr --
1315 *
1316 *      This procedure compiles a Tcl addition expression:
1317 *      addExpr ::= multiplyExpr {('+' | '-') multiplyExpr}
1318 *
1319 * Results:
1320 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1321 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1322 *      contains an error message.
1323 *
1324 *      envPtr->maxStackDepth is updated with the maximum number of stack
1325 *      elements needed to execute the expression.
1326 *
1327 * Side effects:
1328 *      Adds instructions to envPtr to evaluate the expression at runtime.
1329 *
1330 *----------------------------------------------------------------------
1331 */
1332
1333static int
1334CompileAddExpr(interp, infoPtr, flags, envPtr)
1335    Tcl_Interp *interp;         /* Used for error reporting. */
1336    ExprInfo *infoPtr;          /* Describes the compilation state for the
1337                                 * expression being compiled. */
1338    int flags;                  /* Flags to control compilation (same as
1339                                 * passed to Tcl_Eval). */
1340    CompileEnv *envPtr;         /* Holds resulting instructions. */
1341{
1342    int maxDepth = 0;           /* Maximum number of stack elements needed
1343                                 * to execute the expression. */
1344    int op, result;
1345
1346    HERE("addExpr", 10);
1347    result = CompileMultiplyExpr(interp, infoPtr, flags, envPtr);
1348    if (result != TCL_OK) {
1349        goto done;
1350    }
1351    maxDepth = envPtr->maxStackDepth;
1352
1353    op = infoPtr->token;
1354    while ((op == PLUS) || (op == MINUS)) {
1355        infoPtr->hasOperators = 1;
1356        infoPtr->exprIsJustVarRef = 0;
1357        result = GetToken(interp, infoPtr, envPtr); /* skip over + or - */
1358        if (result != TCL_OK) {
1359            goto done;
1360        }
1361
1362        result = CompileMultiplyExpr(interp, infoPtr, flags, envPtr);
1363        if (result != TCL_OK) {
1364            goto done;
1365        }
1366        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
1367
1368        if (op == PLUS) {
1369            TclEmitOpcode(INST_ADD, envPtr);
1370        } else {
1371            TclEmitOpcode(INST_SUB, envPtr);
1372        }
1373
1374        op = infoPtr->token;
1375
1376        /*
1377         * A comparison is not the top-level operator in this expression.
1378         */
1379
1380        infoPtr->exprIsComparison = 0;
1381    }
1382
1383    done:
1384    envPtr->maxStackDepth = maxDepth;
1385    return result;
1386}
1387
1388/*
1389 *----------------------------------------------------------------------
1390 *
1391 * CompileMultiplyExpr --
1392 *
1393 *      This procedure compiles a Tcl multiply expression:
1394 *      multiplyExpr ::= unaryExpr {('*' | '/' | '%') unaryExpr}
1395 *
1396 * Results:
1397 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1398 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1399 *      contains an error message.
1400 *
1401 *      envPtr->maxStackDepth is updated with the maximum number of stack
1402 *      elements needed to execute the expression.
1403 *
1404 * Side effects:
1405 *      Adds instructions to envPtr to evaluate the expression at runtime.
1406 *
1407 *----------------------------------------------------------------------
1408 */
1409
1410static int
1411CompileMultiplyExpr(interp, infoPtr, flags, envPtr)
1412    Tcl_Interp *interp;         /* Used for error reporting. */
1413    ExprInfo *infoPtr;          /* Describes the compilation state for the
1414                                 * expression being compiled. */
1415    int flags;                  /* Flags to control compilation (same as
1416                                 * passed to Tcl_Eval). */
1417    CompileEnv *envPtr;         /* Holds resulting instructions. */
1418{
1419    int maxDepth = 0;           /* Maximum number of stack elements needed
1420                                 * to execute the expression. */
1421    int op, result;
1422
1423    HERE("multiplyExpr", 11);
1424    result = CompileUnaryExpr(interp, infoPtr, flags, envPtr);
1425    if (result != TCL_OK) {
1426        goto done;
1427    }
1428    maxDepth = envPtr->maxStackDepth;
1429
1430    op = infoPtr->token;
1431    while ((op == MULT) || (op == DIVIDE) || (op == MOD)) {
1432        infoPtr->hasOperators = 1;
1433        infoPtr->exprIsJustVarRef = 0;
1434        result = GetToken(interp, infoPtr, envPtr); /* skip over * or / */
1435        if (result != TCL_OK) {
1436            goto done;
1437        }
1438
1439        result = CompileUnaryExpr(interp, infoPtr, flags, envPtr);
1440        if (result != TCL_OK) {
1441            goto done;
1442        }
1443        maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
1444
1445        if (op == MULT) {
1446            TclEmitOpcode(INST_MULT, envPtr);
1447        } else if (op == DIVIDE) {
1448            TclEmitOpcode(INST_DIV, envPtr);
1449        } else {
1450            TclEmitOpcode(INST_MOD, envPtr);
1451        }
1452
1453        op = infoPtr->token;
1454
1455        /*
1456         * A comparison is not the top-level operator in this expression.
1457         */
1458
1459        infoPtr->exprIsComparison = 0;
1460    }
1461
1462    done:
1463    envPtr->maxStackDepth = maxDepth;
1464    return result;
1465}
1466
1467/*
1468 *----------------------------------------------------------------------
1469 *
1470 * CompileUnaryExpr --
1471 *
1472 *      This procedure compiles a Tcl unary expression:
1473 *      unaryExpr ::= ('+' | '-' | '~' | '!') unaryExpr | primaryExpr
1474 *
1475 * Results:
1476 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1477 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1478 *      contains an error message.
1479 *
1480 *      envPtr->maxStackDepth is updated with the maximum number of stack
1481 *      elements needed to execute the expression.
1482 *
1483 * Side effects:
1484 *      Adds instructions to envPtr to evaluate the expression at runtime.
1485 *
1486 *----------------------------------------------------------------------
1487 */
1488
1489static int
1490CompileUnaryExpr(interp, infoPtr, flags, envPtr)
1491    Tcl_Interp *interp;         /* Used for error reporting. */
1492    ExprInfo *infoPtr;          /* Describes the compilation state for the
1493                                 * expression being compiled. */
1494    int flags;                  /* Flags to control compilation (same as
1495                                 * passed to Tcl_Eval). */
1496    CompileEnv *envPtr;         /* Holds resulting instructions. */
1497{
1498    int maxDepth = 0;           /* Maximum number of stack elements needed
1499                                 * to execute the expression. */
1500    int op, result;
1501
1502    HERE("unaryExpr", 12);
1503    op = infoPtr->token;
1504    if ((op == PLUS) || (op == MINUS) || (op == BIT_NOT) || (op == NOT)) {
1505        infoPtr->hasOperators = 1;
1506        infoPtr->exprIsJustVarRef = 0;
1507        result = GetToken(interp, infoPtr, envPtr); /* skip over the op */
1508        if (result != TCL_OK) {
1509            goto done;
1510        }
1511
1512        result = CompileUnaryExpr(interp, infoPtr, flags, envPtr);
1513        if (result != TCL_OK) {
1514            goto done;
1515        }
1516        maxDepth = envPtr->maxStackDepth;
1517
1518        switch (op) {
1519        case PLUS:
1520            TclEmitOpcode(INST_UPLUS, envPtr);
1521            break;
1522        case MINUS:
1523            TclEmitOpcode(INST_UMINUS, envPtr);
1524            break;
1525        case BIT_NOT:
1526            TclEmitOpcode(INST_BITNOT, envPtr);
1527            break;
1528        case NOT:
1529            TclEmitOpcode(INST_LNOT, envPtr);
1530            break;
1531        }
1532
1533        /*
1534         * A comparison is not the top-level operator in this expression.
1535         */
1536
1537        infoPtr->exprIsComparison = 0;
1538    } else {                    /* must be a primaryExpr */
1539        result = CompilePrimaryExpr(interp, infoPtr, flags, envPtr);
1540        if (result != TCL_OK) {
1541            goto done;
1542        }
1543        maxDepth = envPtr->maxStackDepth;
1544    }
1545
1546    done:
1547    envPtr->maxStackDepth = maxDepth;
1548    return result;
1549}
1550
1551/*
1552 *----------------------------------------------------------------------
1553 *
1554 * CompilePrimaryExpr --
1555 *
1556 *      This procedure compiles a Tcl primary expression:
1557 *      primaryExpr ::= literal | varReference | quotedString |
1558 *                      '[' command ']' | mathFuncCall | '(' condExpr ')'
1559 *
1560 * Results:
1561 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1562 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1563 *      contains an error message.
1564 *
1565 *      envPtr->maxStackDepth is updated with the maximum number of stack
1566 *      elements needed to execute the expression.
1567 *
1568 * Side effects:
1569 *      Adds instructions to envPtr to evaluate the expression at runtime.
1570 *
1571 *----------------------------------------------------------------------
1572 */
1573
1574static int
1575CompilePrimaryExpr(interp, infoPtr, flags, envPtr)
1576    Tcl_Interp *interp;         /* Used for error reporting. */
1577    ExprInfo *infoPtr;          /* Describes the compilation state for the
1578                                 * expression being compiled. */
1579    int flags;                  /* Flags to control compilation (same as
1580                                 * passed to Tcl_Eval). */
1581    CompileEnv *envPtr;         /* Holds resulting instructions. */
1582{
1583    int maxDepth = 0;           /* Maximum number of stack elements needed
1584                                 * to execute the expression. */
1585    int theToken;
1586    char *dollarPtr, *quotePtr, *cmdPtr, *termPtr;
1587    int result = TCL_OK;
1588
1589    /*
1590     * We emit tryCvtToNumeric instructions after most of these primary
1591     * expressions in order to support Tcl's policy of interpreting operands
1592     * as first integers if possible, otherwise floating-point numbers if
1593     * possible.
1594     */
1595
1596    HERE("primaryExpr", 13);
1597    theToken = infoPtr->token;
1598
1599    if ((theToken != DOLLAR) && (theToken != OPEN_PAREN)) {
1600        infoPtr->exprIsJustVarRef = 0;
1601    }
1602    switch (theToken) {
1603    case LITERAL:               /* int, double, or string in braces */
1604        TclEmitPush(infoPtr->objIndex, envPtr);
1605        maxDepth = 1;
1606        break;
1607       
1608    case DOLLAR:                /* $var variable reference */
1609        dollarPtr = (infoPtr->next - 1);
1610        envPtr->pushSimpleWords = 1;
1611        result = TclCompileDollarVar(interp, dollarPtr,
1612                infoPtr->lastChar, flags, envPtr);
1613        if (result != TCL_OK) {
1614            goto done;
1615        }
1616        maxDepth = envPtr->maxStackDepth;
1617        infoPtr->next = (dollarPtr + envPtr->termOffset);
1618        break;
1619       
1620    case QUOTE:                 /* quotedString */
1621        quotePtr = infoPtr->next;
1622        envPtr->pushSimpleWords = 1;
1623        result = TclCompileQuotes(interp, quotePtr,
1624                infoPtr->lastChar, '"', flags, envPtr);
1625        if (result != TCL_OK) {
1626            goto done;
1627        }
1628        maxDepth = envPtr->maxStackDepth;
1629        infoPtr->next = (quotePtr + envPtr->termOffset);
1630        break;
1631       
1632    case OPEN_BRACKET:          /* '[' command ']' */
1633        cmdPtr = infoPtr->next;
1634        envPtr->pushSimpleWords = 1;
1635        result = TclCompileString(interp, cmdPtr,
1636                infoPtr->lastChar, (flags | TCL_BRACKET_TERM), envPtr);
1637        if (result != TCL_OK) {
1638            goto done;
1639        }
1640        termPtr = (cmdPtr + envPtr->termOffset);
1641        if (*termPtr == ']') {
1642            infoPtr->next = (termPtr + 1); /* advance over the ']'. */
1643        } else if (termPtr == infoPtr->lastChar) {
1644            /*
1645             * Missing ] at end of nested command.
1646             */
1647           
1648            Tcl_ResetResult(interp);
1649            Tcl_AppendToObj(Tcl_GetObjResult(interp),
1650                    "missing close-bracket", -1);
1651            result = TCL_ERROR;
1652            goto done;
1653        } else {
1654            panic("CompilePrimaryExpr: unexpected termination char '%c' for nested command\n", *termPtr);
1655        }
1656        maxDepth = envPtr->maxStackDepth;
1657        break;
1658       
1659    case FUNC_NAME:
1660        result = CompileMathFuncCall(interp, infoPtr, flags, envPtr);
1661        if (result != TCL_OK) {
1662            goto done;
1663        }
1664        maxDepth = envPtr->maxStackDepth;
1665        break;
1666       
1667    case OPEN_PAREN:
1668        result = GetToken(interp, infoPtr, envPtr); /* skip over the '(' */
1669        if (result != TCL_OK) {
1670            goto done;
1671        }
1672        infoPtr->exprIsComparison = 0;
1673        result = CompileCondExpr(interp, infoPtr, flags, envPtr);
1674        if (result != TCL_OK) {
1675            goto done;
1676        }
1677        maxDepth = envPtr->maxStackDepth;
1678        if (infoPtr->token != CLOSE_PAREN) {
1679            goto syntaxError;
1680        }
1681        break;
1682       
1683    default:
1684        goto syntaxError;
1685    }
1686
1687    if (theToken != FUNC_NAME) {
1688        /*
1689         * Advance to the next token before returning.
1690         */
1691       
1692        result = GetToken(interp, infoPtr, envPtr);
1693        if (result != TCL_OK) {
1694            goto done;
1695        }
1696    }
1697
1698    done:
1699    envPtr->maxStackDepth = maxDepth;
1700    return result;
1701
1702    syntaxError:
1703    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1704            "syntax error in expression \"", infoPtr->originalExpr,
1705            "\"", (char *) NULL);
1706    return TCL_ERROR;
1707}
1708
1709/*
1710 *----------------------------------------------------------------------
1711 *
1712 * CompileMathFuncCall --
1713 *
1714 *      This procedure compiles a call on a math function in an expression:
1715 *      mathFuncCall ::= funcName '(' [condExpr {',' condExpr}] ')'
1716 *
1717 * Results:
1718 *      The return value is TCL_OK on a successful compilation and TCL_ERROR
1719 *      on failure. If TCL_ERROR is returned, then the interpreter's result
1720 *      contains an error message.
1721 *
1722 *      envPtr->maxStackDepth is updated with the maximum number of stack
1723 *      elements needed to execute the function.
1724 *
1725 * Side effects:
1726 *      Adds instructions to envPtr to evaluate the math function at
1727 *      runtime.
1728 *
1729 *----------------------------------------------------------------------
1730 */
1731
1732static int
1733CompileMathFuncCall(interp, infoPtr, flags, envPtr)
1734    Tcl_Interp *interp;         /* Used for error reporting. */
1735    ExprInfo *infoPtr;          /* Describes the compilation state for the
1736                                 * expression being compiled. */
1737    int flags;                  /* Flags to control compilation (same as
1738                                 * passed to Tcl_Eval). */
1739    CompileEnv *envPtr;         /* Holds resulting instructions. */
1740{
1741    Interp *iPtr = (Interp *) interp;
1742    int maxDepth = 0;           /* Maximum number of stack elements needed
1743                                 * to execute the expression. */
1744    MathFunc *mathFuncPtr;      /* Info about math function. */
1745    int objIndex;               /* The object array index for an object
1746                                 * holding the function name if it is not
1747                                 * builtin. */
1748    Tcl_HashEntry *hPtr;
1749    char *p, *funcName;
1750    char savedChar;
1751    int result, i;
1752
1753    /*
1754     * infoPtr->funcName points to the first character of the math
1755     * function's name. Look for the end of its name and look up the
1756     * MathFunc record for the function.
1757     */
1758
1759    funcName = p = infoPtr->funcName;
1760    while (isalnum(UCHAR(*p)) || (*p == '_')) {
1761        p++;
1762    }
1763    infoPtr->next = p;
1764   
1765    result = GetToken(interp, infoPtr, envPtr); /* skip over func name */
1766    if (result != TCL_OK) {
1767        goto done;
1768    }
1769    if (infoPtr->token != OPEN_PAREN) {
1770        goto syntaxError;
1771    }
1772    result = GetToken(interp, infoPtr, envPtr); /* skip over '(' */
1773    if (result != TCL_OK) {
1774        goto done;
1775    }
1776   
1777    savedChar = *p;
1778    *p = 0;
1779    hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcName);
1780    if (hPtr == NULL) {
1781        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1782                "unknown math function \"", funcName, "\"", (char *) NULL);
1783        result = TCL_ERROR;
1784        *p = savedChar;
1785        goto done;
1786    }
1787    mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
1788
1789    /*
1790     * If not a builtin function, push an object with the function's name.
1791     */
1792
1793    if (mathFuncPtr->builtinFuncIndex < 0) {   /* not builtin */
1794        objIndex = TclObjIndexForString(funcName, -1, /*allocStrRep*/ 1,
1795                                        /*inHeap*/ 0, envPtr);
1796        TclEmitPush(objIndex, envPtr);
1797        maxDepth = 1;
1798    }
1799
1800    /*
1801     * Restore the saved character after the function name.
1802     */
1803
1804    *p = savedChar;
1805
1806    /*
1807     * Compile the arguments for the function, if there are any.
1808     */
1809
1810    if (mathFuncPtr->numArgs > 0) {
1811        for (i = 0;  ;  i++) {
1812            infoPtr->exprIsComparison = 0;
1813            result = CompileCondExpr(interp, infoPtr, flags, envPtr);
1814            if (result != TCL_OK) {
1815                goto done;
1816            }
1817   
1818            /*
1819             * Check for a ',' between arguments or a ')' ending the
1820             * argument list.
1821             */
1822   
1823            if (i == (mathFuncPtr->numArgs-1)) {
1824                if (infoPtr->token == CLOSE_PAREN) {
1825                    break;      /* exit the argument parsing loop */
1826                } else if (infoPtr->token == COMMA) {
1827                    Tcl_ResetResult(interp);
1828                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
1829                            "too many arguments for math function", -1);
1830                    result = TCL_ERROR;
1831                    goto done;
1832                } else {
1833                    goto syntaxError;
1834                }
1835            }
1836            if (infoPtr->token != COMMA) {
1837                if (infoPtr->token == CLOSE_PAREN) {
1838                    Tcl_ResetResult(interp);
1839                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
1840                            "too few arguments for math function", -1);
1841                    result = TCL_ERROR;
1842                    goto done;
1843                } else {
1844                    goto syntaxError;
1845                }
1846            }
1847            result = GetToken(interp, infoPtr, envPtr); /* skip over , */
1848            if (result != TCL_OK) {
1849                goto done;
1850            }
1851            maxDepth++;
1852        }
1853    }
1854
1855    if (infoPtr->token != CLOSE_PAREN) {
1856        goto syntaxError;
1857    }
1858    result = GetToken(interp, infoPtr, envPtr); /* skip over ')' */
1859    if (result != TCL_OK) {
1860        goto done;
1861    }
1862   
1863    /*
1864     * Compile the call on the math function. Note that the "objc" argument
1865     * count for non-builtin functions is incremented by 1 to include the
1866     * the function name itself.
1867     */
1868
1869    if (mathFuncPtr->builtinFuncIndex >= 0) { /* a builtin function */
1870        TclEmitInstUInt1(INST_CALL_BUILTIN_FUNC1,
1871                        mathFuncPtr->builtinFuncIndex, envPtr);
1872    } else {
1873        TclEmitInstUInt1(INST_CALL_FUNC1, (mathFuncPtr->numArgs+1), envPtr);
1874    }
1875
1876    /*
1877     * A comparison is not the top-level operator in this expression.
1878     */
1879
1880    done:
1881    infoPtr->exprIsComparison = 0;
1882    envPtr->maxStackDepth = maxDepth;
1883    return result;
1884
1885    syntaxError:
1886        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1887                "syntax error in expression \"", infoPtr->originalExpr,
1888                "\"", (char *) NULL);
1889    return TCL_ERROR;
1890}
1891
1892/*
1893 *----------------------------------------------------------------------
1894 *
1895 * GetToken --
1896 *
1897 *      Lexical scanner used to compile expressions: parses a single
1898 *      operator or other syntactic element from an expression string.
1899 *
1900 * Results:
1901 *      TCL_OK is returned unless an error occurred. In that case a standard
1902 *      Tcl error is returned, using the interpreter's result to hold an
1903 *      error message. TCL_ERROR is returned if an integer overflow, or a
1904 *      floating-point overflow or underflow occurred while reading in a
1905 *      number. If the lexical analysis is successful, infoPtr->token refers
1906 *      to the next symbol in the expression string, and infoPtr->next is
1907 *      advanced past the token. Also, if the token is a integer, double, or
1908 *      string literal, then infoPtr->objIndex the index of an object
1909 *      holding the value in the code's object table; otherwise is NULL.
1910 *
1911 * Side effects:
1912 *      Object are added to envPtr to hold the values of scanned literal
1913 *      integers, doubles, or strings.
1914 *
1915 *----------------------------------------------------------------------
1916 */
1917
1918static int
1919GetToken(interp, infoPtr, envPtr)
1920    Tcl_Interp *interp;                 /* Interpreter to use for error
1921                                         * reporting. */
1922    register ExprInfo *infoPtr;         /* Describes the state of the
1923                                         * compiling the expression,
1924                                         * including the resulting token. */
1925    CompileEnv *envPtr;                 /* Holds objects that store literal
1926                                         * values that are scanned. */
1927{
1928    register char *src;         /* Points to current source char. */
1929    register char c;            /* The current char. */
1930    register int type;          /* Current char's CHAR_TYPE type. */
1931    char *termPtr;              /* Points to char terminating a literal. */
1932    char savedChar;             /* Holds the character termporarily replaced
1933                                 * by a null character during processing of
1934                                 * literal tokens. */
1935    int objIndex;               /* The object array index for an object
1936                                 * holding a scanned literal. */
1937    long longValue;             /* Value of a scanned integer literal. */
1938    double doubleValue;         /* Value of a scanned double literal. */
1939    Tcl_Obj *objPtr;
1940
1941    /*
1942     * First initialize the scanner's "result" fields to default values.
1943     */
1944   
1945    infoPtr->token = UNKNOWN;
1946    infoPtr->objIndex = -1;
1947    infoPtr->funcName = NULL;
1948
1949    /*
1950     * Scan over leading white space at the start of a token. Note that a
1951     * backslash-newline is treated as a space.
1952     */
1953
1954    src = infoPtr->next;
1955    c = *src;
1956    type = CHAR_TYPE(src, infoPtr->lastChar);
1957    while ((type & (TCL_SPACE | TCL_BACKSLASH)) || (c == '\n')) {
1958        if (type == TCL_BACKSLASH) {
1959            if (src[1] == '\n') {
1960                src += 2;
1961            } else {
1962                break;  /* no longer white space */
1963            }
1964        } else {
1965            src++;
1966        }
1967        c = *src;
1968        type = CHAR_TYPE(src, infoPtr->lastChar);
1969    }
1970    if (src == infoPtr->lastChar) {
1971        infoPtr->token = END;
1972        infoPtr->next = src;
1973        return TCL_OK;
1974    }
1975
1976    /*
1977     * Try to parse the token first as an integer or floating-point
1978     * number. Don't check for a number if the first character is "+" or
1979     * "-". If we did, we might treat a binary operator as unary by mistake,
1980     * which would eventually cause a syntax error.
1981     */
1982
1983    if ((*src != '+') && (*src != '-')) {
1984        int startsWithDigit = isdigit(UCHAR(*src));
1985       
1986        if (startsWithDigit && TclLooksLikeInt(src)) {
1987            errno = 0;
1988            longValue = strtoul(src, &termPtr, 0);
1989            if (errno == ERANGE) {
1990                char *s = "integer value too large to represent";
1991               
1992                Tcl_ResetResult(interp);
1993                Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
1994                Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s,
1995                        (char *) NULL);
1996                return TCL_ERROR;
1997            }
1998            if (termPtr != src) {
1999                /*
2000                 * src was the start of a valid integer. Find/create an
2001                 * object in envPtr's object array to contain the integer.
2002                 */
2003           
2004                savedChar = *termPtr;
2005                *termPtr = '\0';
2006                objIndex = TclObjIndexForString(src, termPtr - src,
2007                        /*allocStrRep*/ 0, /*inHeap*/ 0, envPtr);
2008                *termPtr = savedChar;  /* restore the saved char */
2009               
2010                objPtr = envPtr->objArrayPtr[objIndex];
2011                Tcl_InvalidateStringRep(objPtr);
2012                objPtr->internalRep.longValue = longValue;
2013                objPtr->typePtr = &tclIntType;
2014               
2015                infoPtr->token = LITERAL;
2016                infoPtr->objIndex = objIndex;
2017                infoPtr->next = termPtr;
2018                return TCL_OK;
2019            }
2020        } else if (startsWithDigit || (*src == '.')
2021                || (*src == 'n') || (*src == 'N')) {
2022            errno = 0;
2023            doubleValue = strtod(src, &termPtr);
2024            if (termPtr != src) {
2025                if (errno != 0) {
2026                    TclExprFloatError(interp, doubleValue);
2027                    return TCL_ERROR;
2028                }
2029
2030                /*
2031                 * Find/create an object in the object array containing the
2032                 * double.
2033                 */
2034               
2035                savedChar = *termPtr;
2036                *termPtr = '\0';
2037                objIndex = TclObjIndexForString(src, termPtr - src,
2038                        /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
2039                *termPtr = savedChar;  /* restore the saved char */
2040               
2041                objPtr = envPtr->objArrayPtr[objIndex];
2042                objPtr->internalRep.doubleValue = doubleValue;
2043                objPtr->typePtr = &tclDoubleType;
2044               
2045                infoPtr->token = LITERAL;
2046                infoPtr->objIndex = objIndex;
2047                infoPtr->next = termPtr;
2048                return TCL_OK;
2049            }
2050        }
2051    }
2052
2053    /*
2054     * Not an integer or double literal. Check next for a string literal
2055     * in braces.
2056     */
2057
2058    if (*src == '{') {
2059        int level = 0;           /* The {} nesting level. */
2060        int hasBackslashNL = 0;  /* Nonzero if '\newline' was found. */
2061        char *string = src;      /* Set below to point just after the
2062                                  * starting '{'. */
2063        char *last;              /* Points just before terminating '}'. */
2064        int numChars;            /* Number of chars in braced string. */
2065        char savedChar;          /* Holds the character from string
2066                                  * termporarily replaced by a null char
2067                                  * during braced string processing. */
2068        int numRead;
2069
2070        /*
2071         * Check first for any backslash-newlines, since we must treat
2072         * backslash-newlines specially (they must be replaced by spaces).
2073         */
2074
2075        while (1) {
2076            if (src == infoPtr->lastChar) {
2077                Tcl_ResetResult(interp);
2078                Tcl_AppendToObj(Tcl_GetObjResult(interp),
2079                        "missing close-brace", -1);
2080                return TCL_ERROR;
2081            } else if (CHAR_TYPE(src, infoPtr->lastChar) == TCL_NORMAL) {
2082                src++;
2083                continue;
2084            }
2085            c = *src++;
2086            if (c == '{') {
2087                level++;
2088            } else if (c == '}') {
2089                --level;
2090                if (level == 0) {
2091                    last = (src - 2); /* i.e. just before terminating } */
2092                    break;
2093                }
2094            } else if (c == '\\') {
2095                if (*src == '\n') {
2096                    hasBackslashNL = 1;
2097                }
2098                (void) Tcl_Backslash(src-1, &numRead);
2099                src += numRead - 1;
2100            }
2101        }
2102
2103        /*
2104         * Create a string object for the braced string. This will start at
2105         * "string" and ends just after "last" (which points to the final
2106         * character before the terminating '}'). If backslash-newlines were
2107         * found, we copy characters one at a time into a heap-allocated
2108         * buffer and do backslash-newline substitutions.
2109         */
2110
2111        string++;
2112        numChars = (last - string + 1);
2113        savedChar = string[numChars];
2114        string[numChars] = '\0';
2115        if (hasBackslashNL && (numChars > 0)) {
2116            char *buffer = ckalloc((unsigned) numChars + 1);
2117            register char *dst = buffer;
2118            register char *p = string;
2119            while (p <= last) {
2120                c = *dst++ = *p++;
2121                if (c == '\\') {
2122                    if (*p == '\n') {
2123                        dst[-1] = Tcl_Backslash(p-1, &numRead);
2124                        p += numRead - 1;
2125                    } else {
2126                        (void) Tcl_Backslash(p-1, &numRead);
2127                        while (numRead > 1) {
2128                            *dst++ = *p++;
2129                            numRead--;
2130                        }
2131                    }
2132                }
2133            }
2134            *dst = '\0';
2135            objIndex = TclObjIndexForString(buffer, dst - buffer,
2136                    /*allocStrRep*/ 1, /*inHeap*/ 1, envPtr);
2137        } else {
2138            objIndex = TclObjIndexForString(string, numChars,
2139                    /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
2140        }
2141        string[numChars] = savedChar;   /* restore the saved char */
2142
2143        infoPtr->token = LITERAL;
2144        infoPtr->objIndex = objIndex;
2145        infoPtr->next = src;
2146        return TCL_OK;
2147    }
2148
2149    /*
2150     * Not an literal value.
2151     */
2152
2153    infoPtr->next = src+1;   /* assume a 1 char token and advance over it */
2154    switch (*src) {
2155        case '[':
2156            infoPtr->token = OPEN_BRACKET;
2157            return TCL_OK;
2158
2159        case ']':
2160            infoPtr->token = CLOSE_BRACKET;
2161            return TCL_OK;
2162
2163        case '(':
2164            infoPtr->token = OPEN_PAREN;
2165            return TCL_OK;
2166
2167        case ')':
2168            infoPtr->token = CLOSE_PAREN;
2169            return TCL_OK;
2170
2171        case '$':
2172            infoPtr->token = DOLLAR;
2173            return TCL_OK;
2174
2175        case '"':
2176            infoPtr->token = QUOTE;
2177            return TCL_OK;
2178
2179        case ',':
2180            infoPtr->token = COMMA;
2181            return TCL_OK;
2182
2183        case '*':
2184            infoPtr->token = MULT;
2185            return TCL_OK;
2186
2187        case '/':
2188            infoPtr->token = DIVIDE;
2189            return TCL_OK;
2190
2191        case '%':
2192            infoPtr->token = MOD;
2193            return TCL_OK;
2194
2195        case '+':
2196            infoPtr->token = PLUS;
2197            return TCL_OK;
2198
2199        case '-':
2200            infoPtr->token = MINUS;
2201            return TCL_OK;
2202
2203        case '?':
2204            infoPtr->token = QUESTY;
2205            return TCL_OK;
2206
2207        case ':':
2208            infoPtr->token = COLON;
2209            return TCL_OK;
2210
2211        case '<':
2212            switch (src[1]) {
2213                case '<':
2214                    infoPtr->next = src+2;
2215                    infoPtr->token = LEFT_SHIFT;
2216                    break;
2217                case '=':
2218                    infoPtr->next = src+2;
2219                    infoPtr->token = LEQ;
2220                    break;
2221                default:
2222                    infoPtr->token = LESS;
2223                    break;
2224            }
2225            return TCL_OK;
2226
2227        case '>':
2228            switch (src[1]) {
2229                case '>':
2230                    infoPtr->next = src+2;
2231                    infoPtr->token = RIGHT_SHIFT;
2232                    break;
2233                case '=':
2234                    infoPtr->next = src+2;
2235                    infoPtr->token = GEQ;
2236                    break;
2237                default:
2238                    infoPtr->token = GREATER;
2239                    break;
2240            }
2241            return TCL_OK;
2242
2243        case '=':
2244            if (src[1] == '=') {
2245                infoPtr->next = src+2;
2246                infoPtr->token = EQUAL;
2247            } else {
2248                infoPtr->token = UNKNOWN;
2249            }
2250            return TCL_OK;
2251
2252        case '!':
2253            if (src[1] == '=') {
2254                infoPtr->next = src+2;
2255                infoPtr->token = NEQ;
2256            } else {
2257                infoPtr->token = NOT;
2258            }
2259            return TCL_OK;
2260
2261        case '&':
2262            if (src[1] == '&') {
2263                infoPtr->next = src+2;
2264                infoPtr->token = AND;
2265            } else {
2266                infoPtr->token = BIT_AND;
2267            }
2268            return TCL_OK;
2269
2270        case '^':
2271            infoPtr->token = BIT_XOR;
2272            return TCL_OK;
2273
2274        case '|':
2275            if (src[1] == '|') {
2276                infoPtr->next = src+2;
2277                infoPtr->token = OR;
2278            } else {
2279                infoPtr->token = BIT_OR;
2280            }
2281            return TCL_OK;
2282
2283        case '~':
2284            infoPtr->token = BIT_NOT;
2285            return TCL_OK;
2286
2287        default:
2288            if (isalpha(UCHAR(*src))) {
2289                infoPtr->token = FUNC_NAME;
2290                infoPtr->funcName = src;
2291                while (isalnum(UCHAR(*src)) || (*src == '_')) {
2292                    src++;
2293                }
2294                infoPtr->next = src;
2295                return TCL_OK;
2296            }
2297            infoPtr->next = src+1;
2298            infoPtr->token = UNKNOWN;
2299            return TCL_OK;
2300    }
2301}
2302
2303/*
2304 *----------------------------------------------------------------------
2305 *
2306 * Tcl_CreateMathFunc --
2307 *
2308 *      Creates a new math function for expressions in a given
2309 *      interpreter.
2310 *
2311 * Results:
2312 *      None.
2313 *
2314 * Side effects:
2315 *      The function defined by "name" is created or redefined. If the
2316 *      function already exists then its definition is replaced; this
2317 *      includes the builtin functions. Redefining a builtin function forces
2318 *      all existing code to be invalidated since that code may be compiled
2319 *      using an instruction specific to the replaced function. In addition,
2320 *      redefioning a non-builtin function will force existing code to be
2321 *      invalidated if the number of arguments has changed.
2322 *
2323 *----------------------------------------------------------------------
2324 */
2325
2326void
2327Tcl_CreateMathFunc(interp, name, numArgs, argTypes, proc, clientData)
2328    Tcl_Interp *interp;                 /* Interpreter in which function is
2329                                         * to be available. */
2330    char *name;                         /* Name of function (e.g. "sin"). */
2331    int numArgs;                        /* Nnumber of arguments required by
2332                                         * function. */
2333    Tcl_ValueType *argTypes;            /* Array of types acceptable for
2334                                         * each argument. */
2335    Tcl_MathProc *proc;                 /* Procedure that implements the
2336                                         * math function. */
2337    ClientData clientData;              /* Additional value to pass to the
2338                                         * function. */
2339{
2340    Interp *iPtr = (Interp *) interp;
2341    Tcl_HashEntry *hPtr;
2342    MathFunc *mathFuncPtr;
2343    int new, i;
2344
2345    hPtr = Tcl_CreateHashEntry(&iPtr->mathFuncTable, name, &new);
2346    if (new) {
2347        Tcl_SetHashValue(hPtr, ckalloc(sizeof(MathFunc)));
2348    }
2349    mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
2350
2351    if (!new) { 
2352        if (mathFuncPtr->builtinFuncIndex >= 0) {
2353            /*
2354             * We are redefining a builtin math function. Invalidate the
2355             * interpreter's existing code by incrementing its
2356             * compileEpoch member. This field is checked in Tcl_EvalObj
2357             * and ObjInterpProc, and code whose compilation epoch doesn't
2358             * match is recompiled. Newly compiled code will no longer
2359             * treat the function as builtin.
2360             */
2361
2362            iPtr->compileEpoch++;
2363        } else {
2364            /*
2365             * A non-builtin function is being redefined. We must invalidate
2366             * existing code if the number of arguments has changed. This
2367             * is because existing code was compiled assuming that number.
2368             */
2369
2370            if (numArgs != mathFuncPtr->numArgs) {
2371                iPtr->compileEpoch++;
2372            }
2373        }
2374    }
2375   
2376    mathFuncPtr->builtinFuncIndex = -1; /* can't be a builtin function */
2377    if (numArgs > MAX_MATH_ARGS) {
2378        numArgs = MAX_MATH_ARGS;
2379    }
2380    mathFuncPtr->numArgs = numArgs;
2381    for (i = 0;  i < numArgs;  i++) {
2382        mathFuncPtr->argTypes[i] = argTypes[i];
2383    }
2384    mathFuncPtr->proc = proc;
2385    mathFuncPtr->clientData = clientData;
2386}
Note: See TracBrowser for help on using the repository browser.