| ︙ | | |
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
+
+
|
/* Variable substitution; $x */
#define QUOTED (LEAF | 6)
/* Quoted string; "foo $bar [soom]" */
#define EMPTY (LEAF | 7)
/* Used only for an empty argument list to a
* function. Represents the empty string
* within parens in the expression: rand() */
#define VARNAME (LEAF | 8)
/* Bareword as varname target of assignment */
/* Unary operator lexemes */
#define UNARY_PLUS (UNARY | PLUS)
#define UNARY_MINUS (UNARY | MINUS)
#define FUNCTION (UNARY | BAREWORD)
/* This is a bit of "creative interpretation"
|
| ︙ | | |
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
|
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
|
+
+
+
+
+
+
+
-
+
|
* for us. In the end though, a close paren is
* not really a binary operator, and some
* special coding in ParseExpr() make sure we
* never put an actual CLOSE_PAREN node in the
* parse tree. The sub-expression between
* parens becomes the single argument of the
* matching OPEN_PAREN unary operator. */
#define SEPARATOR ( BINARY | 29)
#define ASSIGN ( BINARY | 30)
/* ASSIGN, like EXPON, is right
* associative, and this distinction
* is coded directly in ParseExpr() */
#define END (BINARY | 28)
#define END (BINARY | 31)
/* This lexeme represents the end of the
* string being parsed. Treating it as a
* binary operator follows the same logic as
* the CLOSE_PAREN lexeme and END pairs with
* START, in the same way that CLOSE_PAREN
* pairs with OPEN_PAREN. */
|
| ︙ | | |
300
301
302
303
304
305
306
307
308
309
310
311
312
313
|
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
|
+
+
|
enum Precedence {
PREC_END = 1, /* END */
PREC_START, /* START */
PREC_CLOSE_PAREN, /* ")" */
PREC_OPEN_PAREN, /* "(" */
PREC_COMMA, /* "," */
PREC_SEPARATOR, /* ";" */
PREC_ASSIGN, /* "=" */
PREC_CONDITIONAL, /* "?", ":" */
PREC_OR, /* "||" */
PREC_AND, /* "&&" */
PREC_BIT_OR, /* "|" */
PREC_BIT_XOR, /* "^" */
PREC_BIT_AND, /* "&" */
PREC_EQUAL, /* "==", "!=", "eq", "ne", "in", "ni" */
|
| ︙ | | |
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
|
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
|
+
+
-
+
|
PREC_EQUAL, /* STREQ */
PREC_EQUAL, /* STRNEQ */
PREC_EXPON, /* EXPON */
PREC_EQUAL, /* IN_LIST */
PREC_EQUAL, /* NOT_IN_LIST */
PREC_CLOSE_PAREN, /* CLOSE_PAREN */
PREC_END, /* END */
PREC_SEPARATOR, /* SEPARATOR */
PREC_ASSIGN, /* ASSIGN */
/* Expansion room for more binary operators */
0, 0, 0,
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
/* Unary operator lexemes */
PREC_UNARY, /* UNARY_PLUS */
PREC_UNARY, /* UNARY_MINUS */
PREC_UNARY, /* FUNCTION */
|
| ︙ | | |
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
|
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
|
+
+
-
+
|
INST_STR_EQ, /* STREQ */
INST_STR_NEQ, /* STRNEQ */
INST_EXPON, /* EXPON */
INST_LIST_IN, /* IN_LIST */
INST_LIST_NOT_IN, /* NOT_IN_LIST */
0, /* CLOSE_PAREN */
0, /* END */
0, /* SEPARATOR */
0, /* ASSIGN */
/* Expansion room for more binary operators */
0, 0, 0,
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
/* Unary operator lexemes */
INST_UPLUS, /* UNARY_PLUS */
INST_UMINUS, /* UNARY_MINUS */
0, /* FUNCTION */
|
| ︙ | | |
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
|
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
|
-
+
-
+
|
VARIABLE /* $ */, MOD /* % */,
0 /* & or && */, INVALID /* ' */,
OPEN_PAREN /* ( */, CLOSE_PAREN /* ) */,
0 /* * or ** */, PLUS /* + */,
COMMA /* , */, MINUS /* - */,
0 /* . */, DIVIDE /* / */,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-9 */
COLON /* : */, INVALID /* ; */,
/*COLON*/0 /* : */, SEPARATOR /* ; */,
0 /* < or << or <= */,
0 /* == or INVALID */,
0 /* = or == */,
0 /* > or >> or >= */,
QUESTION /* ? */, INVALID /* @ */,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A-M */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* N-Z */
SCRIPT /* [ */, INVALID /* \ */,
INVALID /* ] */, BIT_XOR /* ^ */,
INVALID /* _ */, INVALID /* ` */,
|
| ︙ | | |
727
728
729
730
731
732
733
734
735
736
737
738
739
740
|
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
* When we compile the expression we'll need the function
* name, and there's no place in the parse tree to store
* it, so we keep a separate list of all the function
* names we've parsed in the order we found them.
*/
Tcl_ListObjAppendElement(NULL, funcList, literal);
} else if (start[scanned+TclParseAllWhiteSpace(
start+scanned, numBytes-scanned)] == ':' &&
start[scanned+TclParseAllWhiteSpace(
start+scanned, numBytes-scanned)+1] == '=') {
lexeme = VARNAME;
/*
* When we compile the expression we'll need the function
* name, and there's no place in the parse tree to store
* it, so we keep a separate list of all the function
* names we've parsed in the order we found them.
*/
// Tcl_ListObjAppendElement(NULL, funcList, literal);
} else if (Tcl_GetBooleanFromObj(NULL,literal,&b) == TCL_OK) {
lexeme = BOOLEAN;
} else {
Tcl_DecrRefCount(literal);
msg = Tcl_ObjPrintf("invalid bareword \"%.*s%s\"",
(scanned < limit) ? scanned : limit - 3, start,
(scanned < limit) ? "" : "...");
|
| ︙ | | |
837
838
839
840
841
842
843
844
845
846
847
848
849
850
|
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
|
+
|
}
goto error;
}
switch (lexeme) {
case NUMBER:
case BOOLEAN:
case VARNAME:
/*
* 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)
|
| ︙ | | |
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
|
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
|
+
+
+
+
+
|
/*
* Right association rules for exponentiation.
*/
if (lexeme == EXPON) {
break;
}
/* Right association rules for assignment. */
if (lexeme == ASSIGN) {
break;
}
/*
* Special association rules for the conditional
* operators. The "?" and ":" operators have equal
* precedence, but must be linked up in sensible pairs.
*/
|
| ︙ | | |
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
|
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
|
+
+
+
+
+
+
+
+
+
+
|
* they have a constant expression.
*/
if ((incompletePtr->lexeme == QUESTION)
|| (incompletePtr->lexeme == FUNCTION)) {
nodes[complete].constant = incompletePtr->constant;
}
/*
* We declare all ASSIGN operators to be non-constant
* expressions because we do not want to optimize their
* variable-setting side effects out of existence.
*/
if (incompletePtr->lexeme == ASSIGN) {
incompletePtr->constant = 0;
}
if (incompletePtr->lexeme == START) {
/*
* Completing the START tree indicates we're done.
* Transfer the parse tree to the caller and return.
*/
|
| ︙ | | |
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
|
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
|
+
+
+
+
+
+
+
+
+
-
+
|
if ((numBytes > 1) && (start[1] == '*')) {
*lexemePtr = EXPON;
return 2;
}
*lexemePtr = MULT;
return 1;
case ':':
if ((numBytes > 1) && (start[1] == '=')) {
*lexemePtr = ASSIGN;
return 2;
}
*lexemePtr = COLON;
return 1;
case '=':
if ((numBytes > 1) && (start[1] == '=')) {
*lexemePtr = EQUAL;
return 2;
}
*lexemePtr = INCOMPLETE;
*lexemePtr = ASSIGN;
return 1;
case '!':
if ((numBytes > 1) && (start[1] == '=')) {
*lexemePtr = NEQ;
return 2;
}
|
| ︙ | | |
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
|
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
|
+
+
+
|
* progress (nested functions), save it in our unused "left"
* field for restoring later.
*/
nodePtr->left = numWords;
numWords = 2; /* Command plus one argument */
break;
case SEPARATOR:
TclEmitOpcode(INST_POP, envPtr);
break;
}
case QUESTION:
newJump = TclStackAlloc(interp, sizeof(JumpList));
newJump->next = jumpPtr;
jumpPtr = newJump;
TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpPtr->jump);
break;
|
| ︙ | | |
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
|
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
|
+
+
+
+
+
+
+
+
+
+
+
|
switch (nodePtr->lexeme) {
case START:
case QUESTION:
if (convert && (nodePtr == rootPtr)) {
TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
}
break;
case ASSIGN:
if (convert) {
/*
* Make sure we assign to a variable only values that
* have been numerically normalized in the expr way.
*/
TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
}
TclEmitOpcode(INST_STORE_STK, envPtr);
break;
case OPEN_PAREN:
case SEPARATOR:
/* do nothing */
break;
case FUNCTION:
/*
* Use the numWords count we've kept to invoke the function
* command with the correct number of arguments.
|
| ︙ | | |