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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [insight/] [tcl/] [generic/] [tclCompExpr.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
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.1.1 2002-01-16 10:25:25 markom 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
30
extern 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
40
static 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
 
49
typedef 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
141
static 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
 
155
static int              CompileAddExpr _ANSI_ARGS_((Tcl_Interp *interp,
156
                            ExprInfo *infoPtr, int flags,
157
                            CompileEnv *envPtr));
158
static int              CompileBitAndExpr _ANSI_ARGS_((Tcl_Interp *interp,
159
                            ExprInfo *infoPtr, int flags,
160
                            CompileEnv *envPtr));
161
static int              CompileBitOrExpr _ANSI_ARGS_((Tcl_Interp *interp,
162
                            ExprInfo *infoPtr, int flags,
163
                            CompileEnv *envPtr));
164
static int              CompileBitXorExpr _ANSI_ARGS_((Tcl_Interp *interp,
165
                            ExprInfo *infoPtr, int flags,
166
                            CompileEnv *envPtr));
167
static int              CompileCondExpr _ANSI_ARGS_((Tcl_Interp *interp,
168
                            ExprInfo *infoPtr, int flags,
169
                            CompileEnv *envPtr));
170
static int              CompileEqualityExpr _ANSI_ARGS_((Tcl_Interp *interp,
171
                            ExprInfo *infoPtr, int flags,
172
                            CompileEnv *envPtr));
173
static int              CompileLandExpr _ANSI_ARGS_((Tcl_Interp *interp,
174
                            ExprInfo *infoPtr, int flags,
175
                            CompileEnv *envPtr));
176
static int              CompileLorExpr _ANSI_ARGS_((Tcl_Interp *interp,
177
                            ExprInfo *infoPtr, int flags,
178
                            CompileEnv *envPtr));
179
static int              CompileMathFuncCall _ANSI_ARGS_((Tcl_Interp *interp,
180
                            ExprInfo *infoPtr, int flags,
181
                            CompileEnv *envPtr));
182
static int              CompileMultiplyExpr _ANSI_ARGS_((Tcl_Interp *interp,
183
                            ExprInfo *infoPtr, int flags,
184
                            CompileEnv *envPtr));
185
static int              CompilePrimaryExpr _ANSI_ARGS_((Tcl_Interp *interp,
186
                            ExprInfo *infoPtr, int flags,
187
                            CompileEnv *envPtr));
188
static int              CompileRelationalExpr _ANSI_ARGS_((
189
                            Tcl_Interp *interp, ExprInfo *infoPtr,
190
                            int flags, CompileEnv *envPtr));
191
static int              CompileShiftExpr _ANSI_ARGS_((Tcl_Interp *interp,
192
                            ExprInfo *infoPtr, int flags,
193
                            CompileEnv *envPtr));
194
static int              CompileUnaryExpr _ANSI_ARGS_((Tcl_Interp *interp,
195
                            ExprInfo *infoPtr, int flags,
196
                            CompileEnv *envPtr));
197
static 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
 
263
int
264
TclCompileExpr(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
 
392
static int
393
CompileCondExpr(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
 
548
static int
549
CompileLorExpr(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
 
715
static int
716
CompileLandExpr(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
 
883
static int
884
CompileBitOrExpr(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
 
953
static int
954
CompileBitXorExpr(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
 
1023
static int
1024
CompileBitAndExpr(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
 
1093
static int
1094
CompileEqualityExpr(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
 
1170
static int
1171
CompileRelationalExpr(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
 
1256
static int
1257
CompileShiftExpr(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
 
1333
static int
1334
CompileAddExpr(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
 
1410
static int
1411
CompileMultiplyExpr(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
 
1489
static int
1490
CompileUnaryExpr(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
 
1574
static int
1575
CompilePrimaryExpr(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
 
1732
static int
1733
CompileMathFuncCall(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
 
1918
static int
1919
GetToken(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
 
2326
void
2327
Tcl_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
}

powered by: WebSVN 2.1.0

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