Diff
Not logged in

Differences From Artifact [e54789ab08]:

To Artifact [548caaa1a5]:


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135







136
137

138
139
140
141

142
143
144
145

146
147
148
149
150
151
152

153

154

155
156

157
158

159
160

161
162
163

164
165

166
167

168
169
170

171
172
173

174
175

176
177

178
179

180
181

182
183

184
185

186
187
188
189

190
191
192
193



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210

211
212
213
214
215
216

217
218
219
220
221
222


223
224

225
226
227


228
229

230
231
232
233
234
235
236
237
238
239
240
241
242







243
244
245


246
247

248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263










264
265

266
267
268
269


270
271

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289




290
291

292
293
294
295
296

297
298
299
300
301
302
303
113
114
115
116
117
118
119








120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

136
137
138
139

140
141
142
143

144
145
146
147
148
149
150
151
152
153
154

155
156

157
158

159
160

161
162
163

164
165

166
167

168
169
170

171
172


173


174


175


176


177


178


179
180
181
182

183
184



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202


203
204
205
206
207


208
209
210
211
212


213
214
215

216
217


218
219


220
221
222
223
224
225
226







227
228
229
230
231
232
233



234
235


236
237
238
239
240
241
242










243
244
245
246
247
248
249
250
251
252


253
254
255


256
257


258
259
260
261
262
263
264
265
266
267
268
269
270
271
272




273
274
275
276


277
278
279
280
281
282
283
284
285
286
287
288
289
290







-
-
-
-
-
-
-
-








+
+
+
+
+
+
+

-
+



-
+



-
+







+

+
-
+

-
+

-
+

-
+


-
+

-
+

-
+


-
+

-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+



-
+

-
-
-
+
+
+















-
-
+




-
-
+




-
-
+
+

-
+

-
-
+
+
-
-
+






-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
-
-
+






-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
+


-
-
+
+
-
-
+














-
-
-
-
+
+
+
+
-
-
+





+








/*
 * The constant field is a boolean flag marking which subexpressions are
 * completely known at compile time, and are eligible for computing then
 * rather than waiting until run time.
 */

/*
 * Each lexeme belongs to one of four categories, which determine its place in
 * the parse tree. We use the two high bits of the (unsigned char) value to
 * store a NODE_TYPE code.
 */

#define NODE_TYPE	0xC0

/*
 * The four category values are LEAF, UNARY, and BINARY, explained below, and
 * "uncategorized", which is used either temporarily, until context determines
 * which of the other three categories is correct, or for lexemes like
 * INVALID, which aren't really lexemes at all, but indicators of a parsing
 * error. Note that the codes must be distinct to distinguish categories, but
 * need not take the form of a bit array.
 */
enum LexemeTypes {
    /*
     * Each lexeme belongs to one of four categories, which determine its place
     * in the parse tree. We use the two high bits of the (unsigned char) value
     * to store a NODE_TYPE code.
     */
    NODE_TYPE = 0xC0,

#define BINARY		0x40	/* This lexeme is a binary operator. An OpNode
    BINARY = 0x40,		/* This lexeme is a binary operator. An OpNode
				 * representing it should go into the parse
				 * tree, and two operands should be parsed for
				 * it in the expression. */
#define UNARY		0x80	/* This lexeme is a unary operator. An OpNode
    UNARY = 0x80,		/* This lexeme is a unary operator. An OpNode
				 * representing it should go into the parse
				 * tree, and one operand should be parsed for
				 * it in the expression. */
#define LEAF		0xC0	/* This lexeme is a leaf operand in the parse
    LEAF = 0xC0			/* This lexeme is a leaf operand in the parse
				 * tree. No OpNode will be placed in the tree
				 * for it. Either a literal value will be
				 * appended to the list of literals in this
				 * expression, or appropriate Tcl_Tokens will
				 * be appended in a Tcl_Parse struct to
				 * represent those leaves that require some
				 * form of substitution. */
};

enum LexemeCodes {
/* Uncategorized lexemes */
    /* Uncategorized lexemes */

#define PLUS		1	/* Ambiguous. Resolves to UNARY_PLUS or
    PLUS = 1,			/* Ambiguous. Resolves to UNARY_PLUS or
				 * BINARY_PLUS according to context. */
#define MINUS		2	/* Ambiguous. Resolves to UNARY_MINUS or
    MINUS = 2,			/* Ambiguous. Resolves to UNARY_MINUS or
				 * BINARY_MINUS according to context. */
#define BAREWORD	3	/* Ambiguous. Resolves to BOOLEAN or to
    BAREWORD = 3,		/* Ambiguous. Resolves to BOOL_LIT or to
				 * FUNCTION or a parse error according to
				 * context and value. */
#define INCOMPLETE	4	/* A parse error. Used only when the single
    INCOMPLETE = 4,		/* A parse error. Used only when the single
				 * "=" is encountered.  */
#define INVALID		5	/* A parse error. Used when any punctuation
    INVALID = 5,		/* A parse error. Used when any punctuation
				 * appears that's not a supported operator. */
#define COMMENT		6	/* Comment. Lasts to end of line or end of
    COMMENT = 6,		/* Comment. Lasts to end of line or end of
				 * expression, whichever comes first. */

/* Leaf lexemes */
    /* Leaf lexemes */

#define NUMBER		(LEAF | 1)
				/* For literal numbers */
    NUMBER = LEAF | 1,		/* For literal numbers */
#define SCRIPT		(LEAF | 2)
				/* Script substitution; [foo] */
    SCRIPT = LEAF | 2,		/* Script substitution; [foo] */
#define BOOLEAN		(LEAF | BAREWORD)
				/* For literal booleans */
    BOOL_LIT = LEAF | BAREWORD,	/* For literal booleans */
#define BRACED		(LEAF | 4)
				/* Braced string; {foo bar} */
    BRACED = LEAF | 4,		/* Braced string; {foo bar} */
#define VARIABLE	(LEAF | 5)
				/* Variable substitution; $x */
    VARIABLE = LEAF | 5,	/* Variable substitution; $x */
#define QUOTED		(LEAF | 6)
				/* Quoted string; "foo $bar [soom]" */
    QUOTED = LEAF | 6,		/* Quoted string; "foo $bar [soom]" */
#define EMPTY		(LEAF | 7)
				/* Used only for an empty argument list to a
    EMPTY = LEAF | 7,		/* Used only for an empty argument list to a
				 * function. Represents the empty string
				 * within parens in the expression: rand() */

/* Unary operator lexemes */
    /* Unary operator lexemes */

#define UNARY_PLUS	(UNARY | PLUS)
#define UNARY_MINUS	(UNARY | MINUS)
#define FUNCTION	(UNARY | BAREWORD)
    UNARY_PLUS = UNARY | PLUS,
    UNARY_MINUS = UNARY | MINUS,
    FUNCTION = UNARY | BAREWORD,
				/* This is a bit of "creative interpretation"
				 * on the part of the parser. A function call
				 * is parsed into the parse tree according to
				 * the perspective that the function name is a
				 * unary operator and its argument list,
				 * enclosed in parens, is its operand. The
				 * additional requirements not implied
				 * generally by treatment as a unary operator
				 * -- for example, the requirement that the
				 * operand be enclosed in parens -- are hard
				 * coded in the relevant portions of
				 * ParseExpr(). We trade off the need to
				 * include such exceptional handling in the
				 * code against the need we would otherwise
				 * have for more lexeme categories. */
#define START		(UNARY | 4)
				/* This lexeme isn't parsed from the
    START = UNARY | 4,		/* This lexeme isn't parsed from the
				 * expression text at all. It represents the
				 * start of the expression and sits at the
				 * root of the parse tree where it serves as
				 * the start/end point of traversals. */
#define OPEN_PAREN	(UNARY | 5)
				/* Another bit of creative interpretation,
    OPEN_PAREN = UNARY | 5,	/* Another bit of creative interpretation,
				 * where we treat "(" as a unary operator with
				 * the sub-expression between it and its
				 * matching ")" as its operand. See
				 * CLOSE_PAREN below. */
#define NOT		(UNARY | 6)
#define BIT_NOT		(UNARY | 7)
    NOT = UNARY | 6,
    BIT_NOT = UNARY | 7,

/* Binary operator lexemes */
    /* Binary operator lexemes */

#define BINARY_PLUS	(BINARY |  PLUS)
#define BINARY_MINUS	(BINARY |  MINUS)
    BINARY_PLUS = BINARY | PLUS,
    BINARY_MINUS = BINARY | MINUS,
#define COMMA		(BINARY |  3)
				/* The "," operator is a low precedence binary
    COMMA = BINARY | 3,		/* The "," operator is a low precedence binary
				 * operator that separates the arguments in a
				 * function call. The additional constraint
				 * that this operator can only legally appear
				 * at the right places within a function call
				 * argument list are hard coded within
				 * ParseExpr().  */
#define MULT		(BINARY |  4)
#define DIVIDE		(BINARY |  5)
#define MOD		(BINARY |  6)
#define LESS		(BINARY |  7)
#define GREATER		(BINARY |  8)
#define BIT_AND		(BINARY |  9)
#define BIT_XOR		(BINARY | 10)
    MULT = BINARY | 4,
    DIVIDE = BINARY | 5,
    MOD = BINARY | 6,
    LESS = BINARY | 7,
    GREATER = BINARY | 8,
    BIT_AND = BINARY | 9,
    BIT_XOR = BINARY | 10,
#define BIT_OR		(BINARY | 11)
#define QUESTION	(BINARY | 12)
				/* These two lexemes make up the */
    BIT_OR = BINARY | 11,
    QUESTION = BINARY | 12,	/* These two lexemes make up the */
#define COLON		(BINARY | 13)
				/* ternary conditional operator, $x ? $y : $z.
    COLON = BINARY | 13,	/* ternary conditional operator, $x ? $y : $z.
				 * We treat them as two binary operators to
				 * avoid another lexeme category, and code the
				 * additional constraints directly in
				 * ParseExpr(). For instance, the right
				 * operand of a "?" operator must be a ":"
				 * operator. */
#define LEFT_SHIFT	(BINARY | 14)
#define RIGHT_SHIFT	(BINARY | 15)
#define LEQ		(BINARY | 16)
#define GEQ		(BINARY | 17)
#define EQUAL		(BINARY | 18)
#define NEQ		(BINARY | 19)
#define AND		(BINARY | 20)
#define OR		(BINARY | 21)
#define STREQ		(BINARY | 22)
#define STRNEQ		(BINARY | 23)
    LEFT_SHIFT = BINARY | 14,
    RIGHT_SHIFT = BINARY | 15,
    LEQ = BINARY | 16,
    GEQ = BINARY | 17,
    EQUAL = BINARY | 18,
    NEQ = BINARY | 19,
    AND = BINARY | 20,
    OR = BINARY | 21,
    STREQ = BINARY | 22,
    STRNEQ = BINARY | 23,
#define EXPON		(BINARY | 24)
				/* Unlike the other binary operators, EXPON is
    EXPON = BINARY | 24,	/* Unlike the other binary operators, EXPON is
				 * right associative and this distinction is
				 * coded directly in ParseExpr(). */
#define IN_LIST		(BINARY | 25)
#define NOT_IN_LIST	(BINARY | 26)
    IN_LIST = BINARY | 25,
    NOT_IN_LIST = BINARY | 26,
#define CLOSE_PAREN	(BINARY | 27)
				/* By categorizing the CLOSE_PAREN lexeme as a
    CLOSE_PAREN = BINARY | 27,	/* By categorizing the CLOSE_PAREN lexeme as a
				 * BINARY operator, the normal parsing rules
				 * for binary operators assure that a close
				 * paren will not directly follow another
				 * operator, and the machinery already in
				 * place to connect operands to operators
				 * according to precedence performs most of
				 * the work of matching open and close parens
				 * 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 STR_LT		(BINARY | 28)
#define STR_GT		(BINARY | 29)
#define STR_LEQ		(BINARY | 30)
#define STR_GEQ		(BINARY | 31)
    STR_LT = BINARY | 28,
    STR_GT = BINARY | 29,
    STR_LEQ = BINARY | 30,
    STR_GEQ = BINARY | 31,
#define END		(BINARY | 32)
				/* This lexeme represents the end of the
    END = BINARY | 32		/* 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. */
};

/*
 * When ParseExpr() builds the parse tree it must choose which operands to
 * connect to which operators.  This is done according to operator precedence.
 * The greater an operator's precedence the greater claim it has to link to an
 * available operand.  The Precedence enumeration lists the precedence values
 * used by Tcl expression operators, from lowest to highest claim.  Each
729
730
731
732
733
734
735
736

737
738
739
740
741
742
743
716
717
718
719
720
721
722

723
724
725
726
727
728
729
730







-
+







		     * 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;
		    lexeme = BOOL_LIT;
		} else {
		    /*
		     * Tricky case: see test expr-62.10
		     */

		    int scanned2 = scanned;
		    do {
855
856
857
858
859
860
861
862

863
864
865
866
867
868
869
870

871
872
873
874
875
876
877
842
843
844
845
846
847
848

849
850
851
852
853
854
855
856

857
858
859
860
861
862
863
864







-
+







-
+







		scanned = 0;
		insertMark = 1;

		/*
		 * Free any literal to avoid a memleak.
		 */

		if ((lexeme == NUMBER) || (lexeme == BOOLEAN)) {
		if ((lexeme == NUMBER) || (lexeme == BOOL_LIT)) {
		    Tcl_DecrRefCount(literal);
		}
		goto error;
	    }

	    switch (lexeme) {
	    case NUMBER:
	    case BOOLEAN:
	    case BOOL_LIT:
		/*
		 * 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)