Diff
Not logged in

Differences From Artifact [4df2b60992]:

To Artifact [d584ceb3ea]:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclCompExpr.c --
 *
 *	This file contains the code to compile Tcl expressions.
 *
 * Copyright (c) 1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompExpr.c,v 1.6.14.1 2002/02/05 02:21:58 wolfsuit Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * The stuff below is a bit of a hack so that this file can be used in











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclCompExpr.c --
 *
 *	This file contains the code to compile Tcl expressions.
 *
 * Copyright (c) 1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompExpr.c,v 1.6.14.2 2002/06/10 05:33:10 wolfsuit Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * The stuff below is a bit of a hack so that this file can be used in
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
				 * to TclCompileExpr. */
    char *lastChar;		/* Points just after last byte of expr. */
    int hasOperators;		/* Set 1 if the expr has operators; 0 if
				 * expr is only a primary. If 1 after
				 * compiling an expr, a tryCvtToNumeric
				 * instruction is emitted to convert the
				 * primary to a number if possible. */
    int exprIsJustVarRef;	/* Set 1 if the expr consists of just a
				 * variable reference as in the expression
				 * of "if $b then...". Otherwise 0. If 1 the
				 * expr is compiled out-of-line in order to
				 * implement expr's 2 level substitution
				 * semantics properly. */
    int exprIsComparison;	/* Set 1 if the top-level operator in the
				 * expr is a comparison. Otherwise 0. If 1,
				 * because the operands might be strings,
				 * the expr is compiled out-of-line in order
				 * to implement expr's 2 level substitution
				 * semantics properly. */
} ExprInfo;

/*
 * Definitions of numeric codes representing each expression operator.
 * The order of these must match the entries in the operatorTable below.
 * Also the codes for the relational operators (OP_LESS, OP_GREATER, 
 * OP_LE, OP_GE, OP_EQ, and OP_NE) must be consecutive and in that order.







<
<
<
<
<
<
<
<
<
<
<
<







55
56
57
58
59
60
61












62
63
64
65
66
67
68
				 * to TclCompileExpr. */
    char *lastChar;		/* Points just after last byte of expr. */
    int hasOperators;		/* Set 1 if the expr has operators; 0 if
				 * expr is only a primary. If 1 after
				 * compiling an expr, a tryCvtToNumeric
				 * instruction is emitted to convert the
				 * primary to a number if possible. */












} ExprInfo;

/*
 * Definitions of numeric codes representing each expression operator.
 * The order of these must match the entries in the operatorTable below.
 * Also the codes for the relational operators (OP_LESS, OP_GREATER, 
 * OP_LE, OP_GE, OP_EQ, and OP_NE) must be consecutive and in that order.
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
 *	Tcl_ExprDouble, Tcl_ExprBoolean, and Tcl_ExprBooleanObj.
 *
 * Results:
 *	The return value is TCL_OK on a successful compilation and TCL_ERROR
 *	on failure. If TCL_ERROR is returned, then the interpreter's result
 *	contains an error message.
 *
 *	envPtr->exprIsJustVarRef is set 1 if the expression consisted of
 *	a single variable reference as in the expression of "if $b then...".
 *	Otherwise it is set 0. This is used to implement Tcl's two level
 *	expression substitution semantics properly.
 *
 *	envPtr->exprIsComparison is set 1 if the top-level operator in the
 *	expr is a comparison. Otherwise it is set 0. If 1, because the
 *	operands might be strings, the expr is compiled out-of-line in order
 *	to implement expr's 2 level substitution semantics properly.
 *
 * Side effects:
 *	Adds instructions to envPtr to evaluate the expression at runtime.
 *
 *----------------------------------------------------------------------
 */

int







<
<
<
<
<
<
<
<
<
<







190
191
192
193
194
195
196










197
198
199
200
201
202
203
 *	Tcl_ExprDouble, Tcl_ExprBoolean, and Tcl_ExprBooleanObj.
 *
 * Results:
 *	The return value is TCL_OK on a successful compilation and TCL_ERROR
 *	on failure. If TCL_ERROR is returned, then the interpreter's result
 *	contains an error message.
 *










 * Side effects:
 *	Adds instructions to envPtr to evaluate the expression at runtime.
 *
 *----------------------------------------------------------------------
 */

int
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
     */

    info.interp = interp;
    info.parsePtr = &parse;
    info.expr = script;
    info.lastChar = (script + numBytes); 
    info.hasOperators = 0;
    info.exprIsJustVarRef = 1;	/* will be set 0 if anything else is seen */
    info.exprIsComparison = 0;

    /*
     * Parse the expression then compile it.
     */

    code = Tcl_ParseExpr(interp, script, numBytes, &parse);
    if (code != TCL_OK) {







<
<







244
245
246
247
248
249
250


251
252
253
254
255
256
257
     */

    info.interp = interp;
    info.parsePtr = &parse;
    info.expr = script;
    info.lastChar = (script + numBytes); 
    info.hasOperators = 0;



    /*
     * Parse the expression then compile it.
     */

    code = Tcl_ParseExpr(interp, script, numBytes, &parse);
    if (code != TCL_OK) {
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
	 */
	
	TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
    }
    Tcl_FreeParse(&parse);

    done:
    envPtr->exprIsJustVarRef = info.exprIsJustVarRef;
    envPtr->exprIsComparison = info.exprIsComparison;
    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * TclFinalizeCompilation --







<
<







273
274
275
276
277
278
279


280
281
282
283
284
285
286
	 */
	
	TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
    }
    Tcl_FreeParse(&parse);

    done:


    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * TclFinalizeCompilation --
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
 *	subexpression at runtime.
 *
 * Results:
 *	The return value is TCL_OK on a successful compilation and TCL_ERROR
 *	on failure. If TCL_ERROR is returned, then the interpreter's result
 *	contains an error message.
 *
 *	envPtr->exprIsJustVarRef is set 1 if the subexpression consisted of
 *	a single variable reference as in the expression of "if $b then...".
 *	Otherwise it is set 0. This is used to implement Tcl's two level
 *	expression substitution semantics properly.
 *
 *	envPtr->exprIsComparison is set 1 if the top-level operator in the
 *	subexpression is a comparison. Otherwise it is set 0. If 1, because
 *	the operands might be strings, the expr is compiled out-of-line in
 *	order to implement expr's 2 level substitution semantics properly.
 *
 * Side effects:
 *	Adds instructions to envPtr to evaluate the subexpression.
 *
 *----------------------------------------------------------------------
 */

static int







<
<
<
<
<
<
<
<
<
<







321
322
323
324
325
326
327










328
329
330
331
332
333
334
 *	subexpression at runtime.
 *
 * Results:
 *	The return value is TCL_OK on a successful compilation and TCL_ERROR
 *	on failure. If TCL_ERROR is returned, then the interpreter's result
 *	contains an error message.
 *










 * Side effects:
 *	Adds instructions to envPtr to evaluate the subexpression.
 *
 *----------------------------------------------------------------------
 */

static int
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
        case TCL_TOKEN_WORD:
	    code = TclCompileTokens(interp, tokenPtr+1,
	            tokenPtr->numComponents, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += (tokenPtr->numComponents + 1);
	    infoPtr->exprIsJustVarRef = 0;
	    break;
	    
        case TCL_TOKEN_TEXT:
	    if (tokenPtr->size > 0) {
		objIndex = TclRegisterLiteral(envPtr, tokenPtr->start,
	                tokenPtr->size, /*onHeap*/ 0);
	    } else {
		objIndex = TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0);
	    }
	    TclEmitPush(objIndex, envPtr);
	    tokenPtr += 1;
	    infoPtr->exprIsJustVarRef = 0;
	    break;
	    
        case TCL_TOKEN_BS:
	    length = Tcl_UtfBackslash(tokenPtr->start, (int *) NULL,
		    buffer);
	    if (length > 0) {
		objIndex = TclRegisterLiteral(envPtr, buffer, length,
	                /*onHeap*/ 0);
	    } else {
		objIndex = TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0);
	    }
	    TclEmitPush(objIndex, envPtr);
	    tokenPtr += 1;
	    infoPtr->exprIsJustVarRef = 0;
	    break;
	    
        case TCL_TOKEN_COMMAND:
	    code = TclCompileScript(interp, tokenPtr->start+1,
		    tokenPtr->size-2, /*nested*/ 1, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += 1;
	    infoPtr->exprIsJustVarRef = 0;
	    break;
	    
        case TCL_TOKEN_VARIABLE:
	    code = TclCompileTokens(interp, tokenPtr, 1, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += (tokenPtr->numComponents + 1);
	    break;
	    
        case TCL_TOKEN_SUB_EXPR:
	    infoPtr->exprIsComparison = 0;
	    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += (tokenPtr->numComponents + 1);
	    break;
	    







<











<













<









<











<







367
368
369
370
371
372
373

374
375
376
377
378
379
380
381
382
383
384

385
386
387
388
389
390
391
392
393
394
395
396
397

398
399
400
401
402
403
404
405
406

407
408
409
410
411
412
413
414
415
416
417

418
419
420
421
422
423
424
        case TCL_TOKEN_WORD:
	    code = TclCompileTokens(interp, tokenPtr+1,
	            tokenPtr->numComponents, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += (tokenPtr->numComponents + 1);

	    break;
	    
        case TCL_TOKEN_TEXT:
	    if (tokenPtr->size > 0) {
		objIndex = TclRegisterLiteral(envPtr, tokenPtr->start,
	                tokenPtr->size, /*onHeap*/ 0);
	    } else {
		objIndex = TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0);
	    }
	    TclEmitPush(objIndex, envPtr);
	    tokenPtr += 1;

	    break;
	    
        case TCL_TOKEN_BS:
	    length = Tcl_UtfBackslash(tokenPtr->start, (int *) NULL,
		    buffer);
	    if (length > 0) {
		objIndex = TclRegisterLiteral(envPtr, buffer, length,
	                /*onHeap*/ 0);
	    } else {
		objIndex = TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0);
	    }
	    TclEmitPush(objIndex, envPtr);
	    tokenPtr += 1;

	    break;
	    
        case TCL_TOKEN_COMMAND:
	    code = TclCompileScript(interp, tokenPtr->start+1,
		    tokenPtr->size-2, /*nested*/ 1, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += 1;

	    break;
	    
        case TCL_TOKEN_VARIABLE:
	    code = TclCompileTokens(interp, tokenPtr, 1, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += (tokenPtr->numComponents + 1);
	    break;
	    
        case TCL_TOKEN_SUB_EXPR:

	    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += (tokenPtr->numComponents + 1);
	    break;
	    
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
		code = CompileMathFuncCall(exprTokenPtr, operator, infoPtr,
			envPtr, &endPtr);
		operator[tokenPtr->size] = (char) savedChar;
		if (code != TCL_OK) {
		    goto done;
		}
		tokenPtr = endPtr;
		infoPtr->exprIsJustVarRef = 0;
		infoPtr->exprIsComparison = 0;
		break;
	    }
	    operator[tokenPtr->size] = (char) savedChar;
	    opIndex = (int) Tcl_GetHashValue(hPtr);
	    opDescPtr = &(operatorTable[opIndex]);

	    /*







<
<







444
445
446
447
448
449
450


451
452
453
454
455
456
457
		code = CompileMathFuncCall(exprTokenPtr, operator, infoPtr,
			envPtr, &endPtr);
		operator[tokenPtr->size] = (char) savedChar;
		if (code != TCL_OK) {
		    goto done;
		}
		tokenPtr = endPtr;


		break;
	    }
	    operator[tokenPtr->size] = (char) savedChar;
	    opIndex = (int) Tcl_GetHashValue(hPtr);
	    opDescPtr = &(operatorTable[opIndex]);

	    /*
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
		    if (code != TCL_OK) {
			goto done;
		    }
		    tokenPtr += (tokenPtr->numComponents + 1);
		}
		TclEmitOpcode(opDescPtr->instruction, envPtr);
		infoPtr->hasOperators = 1;
		infoPtr->exprIsJustVarRef = 0;
		infoPtr->exprIsComparison =
		    (((opIndex >= OP_LESS) && (opIndex <= OP_NEQ))
			    || ((opIndex >= OP_STREQ) && (opIndex <= OP_STRNEQ)));
		break;
	    }
	    
	    /*
	     * The operator requires special treatment, and is either
	     * "+" or "-", or one of "&&", "||" or "?".
	     */







<
<
<
<







472
473
474
475
476
477
478




479
480
481
482
483
484
485
		    if (code != TCL_OK) {
			goto done;
		    }
		    tokenPtr += (tokenPtr->numComponents + 1);
		}
		TclEmitOpcode(opDescPtr->instruction, envPtr);
		infoPtr->hasOperators = 1;




		break;
	    }
	    
	    /*
	     * The operator requires special treatment, and is either
	     * "+" or "-", or one of "&&", "||" or "?".
	     */
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
		    break;
		    
		default:
		    panic("CompileSubExpr: unexpected operator %d requiring special treatment\n",
		        opIndex);
	    } /* end switch on operator requiring special treatment */
	    infoPtr->hasOperators = 1;
	    infoPtr->exprIsJustVarRef = 0;
	    infoPtr->exprIsComparison = 0;
	    break;

        default:
	    panic("CompileSubExpr: unexpected token type %d\n",
	            tokenPtr->type);
    }








<
<







540
541
542
543
544
545
546


547
548
549
550
551
552
553
		    break;
		    
		default:
		    panic("CompileSubExpr: unexpected operator %d requiring special treatment\n",
		        opIndex);
	    } /* end switch on operator requiring special treatment */
	    infoPtr->hasOperators = 1;


	    break;

        default:
	    panic("CompileSubExpr: unexpected token type %d\n",
	            tokenPtr->type);
    }

934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
	    if (tokenPtr == afterSubexprPtr) {
		Tcl_ResetResult(interp);
		Tcl_AppendToObj(Tcl_GetObjResult(interp),
		        "too few arguments for math function", -1);
		code = TCL_ERROR;
		goto done;
	    }
	    infoPtr->exprIsComparison = 0;
	    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += (tokenPtr->numComponents + 1);
	}
	if (tokenPtr != afterSubexprPtr) {







<







885
886
887
888
889
890
891

892
893
894
895
896
897
898
	    if (tokenPtr == afterSubexprPtr) {
		Tcl_ResetResult(interp);
		Tcl_AppendToObj(Tcl_GetObjResult(interp),
		        "too few arguments for math function", -1);
		code = TCL_ERROR;
		goto done;
	    }

	    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
	    if (code != TCL_OK) {
		goto done;
	    }
	    tokenPtr += (tokenPtr->numComponents + 1);
	}
	if (tokenPtr != afterSubexprPtr) {