1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/*
* tclCompExpr.c --
*
* This file contains the code to parse and compile Tcl expressions
* and implementations of the Tcl commands corresponding to expression
* operators, such as the command ::tcl::mathop::+ .
*
* Contributions from Don Porter, NIST, 2006-2007. (not subject to US copyright)
*
* 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.14.2.34 2008/01/16 21:56:20 dgp Exp $
*/
#include "tclInt.h"
#include "tclCompile.h" /* CompileEnv */
/*
* Expression parsing takes place in the routine ParseExpr(). It takes a
|
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/*
* tclCompExpr.c --
*
* This file contains the code to parse and compile Tcl expressions
* and implementations of the Tcl commands corresponding to expression
* operators, such as the command ::tcl::mathop::+ .
*
* Contributions from Don Porter, NIST, 2006-2007. (not subject to US copyright)
*
* 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.14.2.35 2008/01/17 22:03:14 dgp Exp $
*/
#include "tclInt.h"
#include "tclCompile.h" /* CompileEnv */
/*
* Expression parsing takes place in the routine ParseExpr(). It takes a
|
830
831
832
833
834
835
836
837
838
839
840
841
842
843
|
}
goto error;
}
switch (lexeme) {
case NUMBER:
case BOOLEAN:
Tcl_ListObjAppendElement(NULL, litList, literal);
complete = lastParsed = OT_LITERAL;
start += scanned;
numBytes -= scanned;
continue;
default:
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
|
}
goto error;
}
switch (lexeme) {
case NUMBER:
case BOOLEAN:
/*
* TODO: Consider using a dict or hash to collapse all
* duplicate literals into a single representative value.
* (Like what is done with [split $s {}]).
* Pro: ~75% memory saving on expressions like
* {1+1+1+1+1+.....+1} (Convert "pointer + Tcl_Obj" cost
* to "pointer" cost only)
* Con: Cost of the dict store/retrieve on every literal
* in every expression when expressions like the above
* tend to be uncommon.
* The memory savings is temporary; Compiling to bytecode
* will collapse things as literals are registered
* anyway, so the savings applies only to the time
* between parsing and compiling. Possibly important
* due to high-water mark nature of memory allocation.
*/
Tcl_ListObjAppendElement(NULL, litList, literal);
complete = lastParsed = OT_LITERAL;
start += scanned;
numBytes -= scanned;
continue;
default:
|
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
|
numWords = 1; /* No arguments, so just the command */
break;
case OT_LITERAL: {
Tcl_Obj *const *litObjv = *litObjvPtr;
Tcl_Obj *literal = *litObjv;
if (optimize) {
int length;
const char *bytes = TclGetStringFromObj(literal, &length);
/* TODO: Consider ways to preserve intrep */
TclEmitPush(TclRegisterNewLiteral(envPtr, bytes, length),
envPtr);
} else {
/*
* When optimize==0, we know the expression is a one-off
* and there's nothing to be gained from sharing literals
* when they won't live long, and the copies we have already
* have an appropriate intrep. In this case, skip literal
* registration that would enable sharing, and use the routine
|
|
>
>
<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
|
numWords = 1; /* No arguments, so just the command */
break;
case OT_LITERAL: {
Tcl_Obj *const *litObjv = *litObjvPtr;
Tcl_Obj *literal = *litObjv;
if (optimize) {
int length, index;
const char *bytes = TclGetStringFromObj(literal, &length);
LiteralEntry *lePtr;
Tcl_Obj *objPtr;
index = TclRegisterNewLiteral(envPtr, bytes, length);
lePtr = envPtr->literalArrayPtr + index;
objPtr = lePtr->objPtr;
if ((objPtr->typePtr == NULL) && (literal->typePtr != NULL)) {
/*
* Would like to do this:
*
* lePtr->objPtr = literal;
* Tcl_IncrRefCount(literal);
* Tcl_DecrRefCount(objPtr);
*
* However, the design of the "global" and "local"
* LiteralTable does not permit the value of lePtr->objPtr
* to change. So rather than replace lePtr->objPtr, we
* do surgery to transfer our desired intrep into it.
*
*/
objPtr->typePtr = literal->typePtr;
objPtr->internalRep = literal->internalRep;
literal->typePtr = NULL;
}
TclEmitPush(index, envPtr);
} else {
/*
* When optimize==0, we know the expression is a one-off
* and there's nothing to be gained from sharing literals
* when they won't live long, and the copies we have already
* have an appropriate intrep. In this case, skip literal
* registration that would enable sharing, and use the routine
|