tclCompExpr.cGo to the documentation of this file.00001 /* 00002 * tclCompExpr.c -- 00003 * 00004 * This file contains the code to parse and compile Tcl expressions 00005 * and implementations of the Tcl commands corresponding to expression 00006 * operators, such as the command ::tcl::mathop::+ . 00007 * 00008 * Contributions from Don Porter, NIST, 2006-2007. (not subject to US copyright) 00009 * 00010 * See the file "license.terms" for information on usage and redistribution of 00011 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00012 * 00013 * RCS: @(#) $Id: tclCompExpr.c,v 1.95 2008/01/23 19:41:28 dgp Exp $ 00014 */ 00015 00016 #include "tclInt.h" 00017 #include "tclCompile.h" /* CompileEnv */ 00018 00019 /* 00020 * Expression parsing takes place in the routine ParseExpr(). It takes a 00021 * string as input, parses that string, and generates a representation of 00022 * the expression in the form of a tree of operators, a list of literals, 00023 * a list of function names, and an array of Tcl_Token's within a Tcl_Parse 00024 * struct. The tree is composed of OpNodes. 00025 */ 00026 00027 typedef struct OpNode { 00028 int left; /* "Pointer" to the left operand. */ 00029 int right; /* "Pointer" to the right operand. */ 00030 union { 00031 int parent; /* "Pointer" to the parent operand. */ 00032 int prev; /* "Pointer" joining incomplete tree stack */ 00033 } p; 00034 unsigned char lexeme; /* Code that identifies the operator. */ 00035 unsigned char precedence; /* Precedence of the operator */ 00036 unsigned char mark; /* Mark used to control traversal. */ 00037 unsigned char constant; /* Flag marking constant subexpressions. */ 00038 } OpNode; 00039 00040 /* 00041 * The storage for the tree is dynamically allocated array of OpNodes. The 00042 * array is grown as parsing needs dictate according to a scheme similar to 00043 * Tcl's string growth algorithm, so that the resizing costs are O(N) and so 00044 * that we use at least half the memory allocated as expressions get large. 00045 * 00046 * Each OpNode in the tree represents an operator in the expression, either 00047 * unary or binary. When parsing is completed successfully, a binary operator 00048 * OpNode will have its left and right fields filled with "pointers" to its 00049 * left and right operands. A unary operator OpNode will have its right field 00050 * filled with a pointer to its single operand. When an operand is a 00051 * subexpression the "pointer" takes the form of the index -- a non-negative 00052 * integer -- into the OpNode storage array where the root of that 00053 * subexpression parse tree is found. 00054 * 00055 * Non-operator elements of the expression do not get stored in the OpNode 00056 * tree. They are stored in the other structures according to their type. 00057 * Literal values get appended to the literal list. Elements that denote 00058 * forms of quoting or substitution known to the Tcl parser get stored as 00059 * Tcl_Tokens. These non-operator elements of the expression are the 00060 * leaves of the completed parse tree. When an operand of an OpNode is 00061 * one of these leaf elements, the following negative integer codes are used 00062 * to indicate which kind of elements it is. 00063 */ 00064 00065 enum OperandTypes { 00066 OT_LITERAL = -3, /* Operand is a literal in the literal list */ 00067 OT_TOKENS = -2, /* Operand is sequence of Tcl_Tokens */ 00068 OT_EMPTY = -1 /* "Operand" is an empty string. This is a 00069 * special case used only to represent the 00070 * EMPTY lexeme. See below. */ 00071 }; 00072 00073 /* 00074 * Readable macros to test whether a "pointer" value points to an operator. 00075 * They operate on the "non-negative integer -> operator; negative integer -> 00076 * a non-operator OperandType" distinction. 00077 */ 00078 00079 #define IsOperator(l) ((l) >= 0) 00080 #define NotOperator(l) ((l) < 0) 00081 00082 /* 00083 * Note that it is sufficient to store in the tree just the type of leaf 00084 * operand, without any explicit pointer to which leaf. This is true because 00085 * the traversals of the completed tree we perform are known to visit 00086 * the leaves in the same order as the original parse. 00087 * 00088 * In a completed parse tree, those OpNodes that are themselves (roots of 00089 * subexpression trees that are) operands of some operator store in their 00090 * p.parent field a "pointer" to the OpNode of that operator. The p.parent 00091 * field permits a traversal of the tree within a * non-recursive routine 00092 * (ConvertTreeToTokens() and CompileExprTree()). This means that even 00093 * expression trees of great depth pose no risk of blowing the C stack. 00094 * 00095 * While the parse tree is being constructed, the same memory space is used 00096 * to hold the p.prev field which chains together a stack of incomplete 00097 * trees awaiting their right operands. 00098 * 00099 * The lexeme field is filled in with the lexeme of the operator that is 00100 * returned by the ParseLexeme() routine. Only lexemes for unary and 00101 * binary operators get stored in an OpNode. Other lexmes get different 00102 * treatement. 00103 * 00104 * The precedence field provides a place to store the precedence of the 00105 * operator, so it need not be looked up again and again. 00106 * 00107 * The mark field is use to control the traversal of the tree, so 00108 * that it can be done non-recursively. The mark values are: 00109 */ 00110 00111 enum Marks { 00112 MARK_LEFT, /* Next step of traversal is to visit left subtree */ 00113 MARK_RIGHT, /* Next step of traversal is to visit right subtree */ 00114 MARK_PARENT, /* Next step of traversal is to return to parent */ 00115 }; 00116 00117 /* 00118 * The constant field is a boolean flag marking which subexpressions are 00119 * completely known at compile time, and are eligible for computing then 00120 * rather than waiting until run time. 00121 */ 00122 00123 /* 00124 * Each lexeme belongs to one of four categories, which determine 00125 * its place in the parse tree. We use the two high bits of the 00126 * (unsigned char) value to store a NODE_TYPE code. 00127 */ 00128 00129 #define NODE_TYPE 0xC0 00130 00131 /* 00132 * The four category values are LEAF, UNARY, and BINARY, explained below, 00133 * and "uncategorized", which is used either temporarily, until context 00134 * determines which of the other three categories is correct, or for 00135 * lexemes like INVALID, which aren't really lexemes at all, but indicators 00136 * of a parsing error. Note that the codes must be distinct to distinguish 00137 * categories, but need not take the form of a bit array. 00138 */ 00139 00140 #define BINARY 0x40 /* This lexeme is a binary operator. An 00141 * OpNode representing it should go into the 00142 * parse tree, and two operands should be 00143 * parsed for it in the expression. */ 00144 #define UNARY 0x80 /* This lexeme is a unary operator. An OpNode 00145 * representing it should go into the parse 00146 * tree, and one operand should be parsed for 00147 * it in the expression. */ 00148 #define LEAF 0xC0 /* This lexeme is a leaf operand in the parse 00149 * tree. No OpNode will be placed in the tree 00150 * for it. Either a literal value will be 00151 * appended to the list of literals in this 00152 * expression, or appropriate Tcl_Tokens will 00153 * be appended in a Tcl_Parse struct to 00154 * represent those leaves that require some 00155 * form of substitution. 00156 */ 00157 00158 /* Uncategorized lexemes */ 00159 00160 #define PLUS 1 /* Ambiguous. Resolves to UNARY_PLUS or 00161 * BINARY_PLUS according to context. */ 00162 #define MINUS 2 /* Ambiguous. Resolves to UNARY_MINUS or 00163 * BINARY_MINUS according to context. */ 00164 #define BAREWORD 3 /* Ambigous. Resolves to BOOLEAN or to 00165 * FUNCTION or a parse error according to 00166 * context and value. */ 00167 #define INCOMPLETE 4 /* A parse error. Used only when the single 00168 * "=" is encountered. */ 00169 #define INVALID 5 /* A parse error. Used when any punctuation 00170 * appears that's not a supported operator. */ 00171 00172 /* Leaf lexemes */ 00173 00174 #define NUMBER ( LEAF | 1) /* For literal numbers */ 00175 #define SCRIPT ( LEAF | 2) /* Script substitution; [foo] */ 00176 #define BOOLEAN ( LEAF | BAREWORD) /* For literal booleans */ 00177 #define BRACED ( LEAF | 4) /* Braced string; {foo bar} */ 00178 #define VARIABLE ( LEAF | 5) /* Variable substitution; $x */ 00179 #define QUOTED ( LEAF | 6) /* Quoted string; "foo $bar [soom]" */ 00180 #define EMPTY ( LEAF | 7) /* Used only for an empty argument 00181 * list to a function. Represents 00182 * the empty string within parens in 00183 * the expression: rand() */ 00184 00185 /* Unary operator lexemes */ 00186 00187 #define UNARY_PLUS ( UNARY | PLUS) 00188 #define UNARY_MINUS ( UNARY | MINUS) 00189 #define FUNCTION ( UNARY | BAREWORD) /* This is a bit of "creative 00190 * interpretation" on the part of the 00191 * parser. A function call is parsed 00192 * into the parse tree according to 00193 * the perspective that the function 00194 * name is a unary operator and its 00195 * argument list, enclosed in parens, 00196 * is its operand. The additional 00197 * requirements not implied generally 00198 * by treatment as a unary operator -- 00199 * for example, the requirement that 00200 * the operand be enclosed in parens -- 00201 * are hard coded in the relevant 00202 * portions of ParseExpr(). We trade 00203 * off the need to include such 00204 * exceptional handling in the code 00205 * against the need we would otherwise 00206 * have for more lexeme categories. */ 00207 #define START ( UNARY | 4) /* This lexeme isn't parsed from the 00208 * expression text at all. It 00209 * represents the start of the 00210 * expression and sits at the root of 00211 * the parse tree where it serves as 00212 * the start/end point of traversals. */ 00213 #define OPEN_PAREN ( UNARY | 5) /* Another bit of creative 00214 * interpretation, where we treat "(" 00215 * as a unary operator with the 00216 * sub-expression between it and its 00217 * matching ")" as its operand. See 00218 * CLOSE_PAREN below. */ 00219 #define NOT ( UNARY | 6) 00220 #define BIT_NOT ( UNARY | 7) 00221 00222 /* Binary operator lexemes */ 00223 00224 #define BINARY_PLUS ( BINARY | PLUS) 00225 #define BINARY_MINUS ( BINARY | MINUS) 00226 #define COMMA ( BINARY | 3) /* The "," operator is a low precedence 00227 * binary operator that separates the 00228 * arguments in a function call. The 00229 * additional constraint that this 00230 * operator can only legally appear 00231 * at the right places within a 00232 * function call argument list are 00233 * hard coded within ParseExpr(). */ 00234 #define MULT ( BINARY | 4) 00235 #define DIVIDE ( BINARY | 5) 00236 #define MOD ( BINARY | 6) 00237 #define LESS ( BINARY | 7) 00238 #define GREATER ( BINARY | 8) 00239 #define BIT_AND ( BINARY | 9) 00240 #define BIT_XOR ( BINARY | 10) 00241 #define BIT_OR ( BINARY | 11) 00242 #define QUESTION ( BINARY | 12) /* These two lexemes make up the */ 00243 #define COLON ( BINARY | 13) /* ternary conditional operator, 00244 * $x ? $y : $z . We treat them as 00245 * two binary operators to avoid 00246 * another lexeme category, and 00247 * code the additional constraints 00248 * directly in ParseExpr(). For 00249 * instance, the right operand of 00250 * a "?" operator must be a ":" 00251 * operator. */ 00252 #define LEFT_SHIFT ( BINARY | 14) 00253 #define RIGHT_SHIFT ( BINARY | 15) 00254 #define LEQ ( BINARY | 16) 00255 #define GEQ ( BINARY | 17) 00256 #define EQUAL ( BINARY | 18) 00257 #define NEQ ( BINARY | 19) 00258 #define AND ( BINARY | 20) 00259 #define OR ( BINARY | 21) 00260 #define STREQ ( BINARY | 22) 00261 #define STRNEQ ( BINARY | 23) 00262 #define EXPON ( BINARY | 24) /* Unlike the other binary operators, 00263 * EXPON is right associative and this 00264 * distinction is coded directly in 00265 * ParseExpr(). */ 00266 #define IN_LIST ( BINARY | 25) 00267 #define NOT_IN_LIST ( BINARY | 26) 00268 #define CLOSE_PAREN ( BINARY | 27) /* By categorizing the CLOSE_PAREN 00269 * lexeme as a BINARY operator, the 00270 * normal parsing rules for binary 00271 * operators assure that a close paren 00272 * will not directly follow another 00273 * operator, and the machinery already 00274 * in place to connect operands to 00275 * operators according to precedence 00276 * performs most of the work of 00277 * matching open and close parens for 00278 * us. In the end though, a close 00279 * paren is not really a binary 00280 * operator, and some special coding 00281 * in ParseExpr() make sure we never 00282 * put an actual CLOSE_PAREN node 00283 * in the parse tree. The 00284 * sub-expression between parens 00285 * becomes the single argument of 00286 * the matching OPEN_PAREN unary 00287 * operator. */ 00288 #define END ( BINARY | 28) /* This lexeme represents the end of 00289 * the string being parsed. Treating 00290 * it as a binary operator follows the 00291 * same logic as the CLOSE_PAREN lexeme 00292 * and END pairs with START, in the 00293 * same way that CLOSE_PAREN pairs with 00294 * OPEN_PAREN. */ 00295 /* 00296 * When ParseExpr() builds the parse tree it must choose which operands to 00297 * connect to which operators. This is done according to operator precedence. 00298 * The greater an operator's precedence the greater claim it has to link to 00299 * an available operand. The Precedence enumeration lists the precedence 00300 * values used by Tcl expression operators, from lowest to highest claim. 00301 * Each precedence level is commented with the operators that hold that 00302 * precedence. 00303 */ 00304 00305 enum Precedence { 00306 PREC_END = 1, /* END */ 00307 PREC_START, /* START */ 00308 PREC_CLOSE_PAREN, /* ")" */ 00309 PREC_OPEN_PAREN, /* "(" */ 00310 PREC_COMMA, /* "," */ 00311 PREC_CONDITIONAL, /* "?", ":" */ 00312 PREC_OR, /* "||" */ 00313 PREC_AND, /* "&&" */ 00314 PREC_BIT_OR, /* "|" */ 00315 PREC_BIT_XOR, /* "^" */ 00316 PREC_BIT_AND, /* "&" */ 00317 PREC_EQUAL, /* "==", "!=", "eq", "ne", "in", "ni" */ 00318 PREC_COMPARE, /* "<", ">", "<=", ">=" */ 00319 PREC_SHIFT, /* "<<", ">>" */ 00320 PREC_ADD, /* "+", "-" */ 00321 PREC_MULT, /* "*", "/", "%" */ 00322 PREC_EXPON, /* "**" */ 00323 PREC_UNARY /* "+", "-", FUNCTION, "!", "~" */ 00324 }; 00325 00326 /* 00327 * Here the same information contained in the comments above is stored 00328 * in inverted form, so that given a lexeme, one can quickly look up 00329 * its precedence value. 00330 */ 00331 00332 static const unsigned char prec[] = { 00333 /* Non-operator lexemes */ 00334 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00336 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00337 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00338 0, 00339 /* Binary operator lexemes */ 00340 PREC_ADD, /* BINARY_PLUS */ 00341 PREC_ADD, /* BINARY_MINUS */ 00342 PREC_COMMA, /* COMMA */ 00343 PREC_MULT, /* MULT */ 00344 PREC_MULT, /* DIVIDE */ 00345 PREC_MULT, /* MOD */ 00346 PREC_COMPARE, /* LESS */ 00347 PREC_COMPARE, /* GREATER */ 00348 PREC_BIT_AND, /* BIT_AND */ 00349 PREC_BIT_XOR, /* BIT_XOR */ 00350 PREC_BIT_OR, /* BIT_OR */ 00351 PREC_CONDITIONAL, /* QUESTION */ 00352 PREC_CONDITIONAL, /* COLON */ 00353 PREC_SHIFT, /* LEFT_SHIFT */ 00354 PREC_SHIFT, /* RIGHT_SHIFT */ 00355 PREC_COMPARE, /* LEQ */ 00356 PREC_COMPARE, /* GEQ */ 00357 PREC_EQUAL, /* EQUAL */ 00358 PREC_EQUAL, /* NEQ */ 00359 PREC_AND, /* AND */ 00360 PREC_OR, /* OR */ 00361 PREC_EQUAL, /* STREQ */ 00362 PREC_EQUAL, /* STRNEQ */ 00363 PREC_EXPON, /* EXPON */ 00364 PREC_EQUAL, /* IN_LIST */ 00365 PREC_EQUAL, /* NOT_IN_LIST */ 00366 PREC_CLOSE_PAREN, /* CLOSE_PAREN */ 00367 PREC_END, /* END */ 00368 /* Expansion room for more binary operators */ 00369 0, 0, 0, 00370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00372 0, 00373 /* Unary operator lexemes */ 00374 PREC_UNARY, /* UNARY_PLUS */ 00375 PREC_UNARY, /* UNARY_MINUS */ 00376 PREC_UNARY, /* FUNCTION */ 00377 PREC_START, /* START */ 00378 PREC_OPEN_PAREN, /* OPEN_PAREN */ 00379 PREC_UNARY, /* NOT*/ 00380 PREC_UNARY, /* BIT_NOT*/ 00381 }; 00382 00383 /* 00384 * A table mapping lexemes to bytecode instructions, used by CompileExprTree(). 00385 */ 00386 00387 static const unsigned char instruction[] = { 00388 /* Non-operator lexemes */ 00389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00392 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00393 0, 00394 /* Binary operator lexemes */ 00395 INST_ADD, /* BINARY_PLUS */ 00396 INST_SUB, /* BINARY_MINUS */ 00397 0, /* COMMA */ 00398 INST_MULT, /* MULT */ 00399 INST_DIV, /* DIVIDE */ 00400 INST_MOD, /* MOD */ 00401 INST_LT, /* LESS */ 00402 INST_GT, /* GREATER */ 00403 INST_BITAND, /* BIT_AND */ 00404 INST_BITXOR, /* BIT_XOR */ 00405 INST_BITOR, /* BIT_OR */ 00406 0, /* QUESTION */ 00407 0, /* COLON */ 00408 INST_LSHIFT, /* LEFT_SHIFT */ 00409 INST_RSHIFT, /* RIGHT_SHIFT */ 00410 INST_LE, /* LEQ */ 00411 INST_GE, /* GEQ */ 00412 INST_EQ, /* EQUAL */ 00413 INST_NEQ, /* NEQ */ 00414 0, /* AND */ 00415 0, /* OR */ 00416 INST_STR_EQ, /* STREQ */ 00417 INST_STR_NEQ, /* STRNEQ */ 00418 INST_EXPON, /* EXPON */ 00419 INST_LIST_IN, /* IN_LIST */ 00420 INST_LIST_NOT_IN, /* NOT_IN_LIST */ 00421 0, /* CLOSE_PAREN */ 00422 0, /* END */ 00423 /* Expansion room for more binary operators */ 00424 0, 0, 0, 00425 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00426 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00427 0, 00428 /* Unary operator lexemes */ 00429 INST_UPLUS, /* UNARY_PLUS */ 00430 INST_UMINUS, /* UNARY_MINUS */ 00431 0, /* FUNCTION */ 00432 0, /* START */ 00433 0, /* OPEN_PAREN */ 00434 INST_LNOT, /* NOT*/ 00435 INST_BITNOT, /* BIT_NOT*/ 00436 }; 00437 00438 /* 00439 * A table mapping a byte value to the corresponding lexeme for use by 00440 * ParseLexeme(). 00441 */ 00442 00443 static unsigned char Lexeme[] = { 00444 INVALID /* NUL */, INVALID /* SOH */, 00445 INVALID /* STX */, INVALID /* ETX */, 00446 INVALID /* EOT */, INVALID /* ENQ */, 00447 INVALID /* ACK */, INVALID /* BEL */, 00448 INVALID /* BS */, INVALID /* HT */, 00449 INVALID /* LF */, INVALID /* VT */, 00450 INVALID /* FF */, INVALID /* CR */, 00451 INVALID /* SO */, INVALID /* SI */, 00452 INVALID /* DLE */, INVALID /* DC1 */, 00453 INVALID /* DC2 */, INVALID /* DC3 */, 00454 INVALID /* DC4 */, INVALID /* NAK */, 00455 INVALID /* SYN */, INVALID /* ETB */, 00456 INVALID /* CAN */, INVALID /* EM */, 00457 INVALID /* SUB */, INVALID /* ESC */, 00458 INVALID /* FS */, INVALID /* GS */, 00459 INVALID /* RS */, INVALID /* US */, 00460 INVALID /* SPACE */, 0 /* ! or != */, 00461 QUOTED /* " */, INVALID /* # */, 00462 VARIABLE /* $ */, MOD /* % */, 00463 0 /* & or && */, INVALID /* ' */, 00464 OPEN_PAREN /* ( */, CLOSE_PAREN /* ) */, 00465 0 /* * or ** */, PLUS /* + */, 00466 COMMA /* , */, MINUS /* - */, 00467 0 /* . */, DIVIDE /* / */, 00468 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-9 */ 00469 COLON /* : */, INVALID /* ; */, 00470 0 /* < or << or <= */, 00471 0 /* == or INVALID */, 00472 0 /* > or >> or >= */, 00473 QUESTION /* ? */, INVALID /* @ */, 00474 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A-M */ 00475 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* N-Z */ 00476 SCRIPT /* [ */, INVALID /* \ */, 00477 INVALID /* ] */, BIT_XOR /* ^ */, 00478 INVALID /* _ */, INVALID /* ` */, 00479 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a-m */ 00480 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* n-z */ 00481 BRACED /* { */, 0 /* | or || */, 00482 INVALID /* } */, BIT_NOT /* ~ */, 00483 INVALID /* DEL */ 00484 }; 00485 00486 /* 00487 * The JumpList struct is used to create a stack of data needed for the 00488 * TclEmitForwardJump() and TclFixupForwardJump() calls that are performed 00489 * when compiling the short-circuiting operators QUESTION/COLON, AND, and OR. 00490 * Keeping a stack permits the CompileExprTree() routine to be non-recursive. 00491 */ 00492 00493 typedef struct JumpList { 00494 JumpFixup jump; /* Pass this argument to matching calls of 00495 * TclEmitForwardJump() and 00496 * TclFixupForwardJump(). */ 00497 int depth; /* Remember the currStackDepth of the 00498 * CompileEnv here. */ 00499 int offset; /* Data used to compute jump lengths to pass 00500 * to TclFixupForwardJump() */ 00501 int convert; /* Temporary storage used to compute whether 00502 * numeric conversion will be needed following 00503 * the operator we're compiling. */ 00504 struct JumpList *next; /* Point to next item on the stack */ 00505 } JumpList; 00506 00507 /* 00508 * Declarations for local functions to this file: 00509 */ 00510 00511 static void CompileExprTree(Tcl_Interp *interp, OpNode *nodes, 00512 int index, Tcl_Obj *const **litObjvPtr, 00513 Tcl_Obj *const *funcObjv, Tcl_Token *tokenPtr, 00514 CompileEnv *envPtr, int optimize); 00515 static void ConvertTreeToTokens(const char *start, int numBytes, 00516 OpNode *nodes, Tcl_Token *tokenPtr, 00517 Tcl_Parse *parsePtr); 00518 static int ExecConstantExprTree(Tcl_Interp *interp, OpNode *nodes, 00519 int index, Tcl_Obj * const **litObjvPtr); 00520 static int ParseExpr(Tcl_Interp *interp, const char *start, 00521 int numBytes, OpNode **opTreePtr, 00522 Tcl_Obj *litList, Tcl_Obj *funcList, 00523 Tcl_Parse *parsePtr, int parseOnly); 00524 static int ParseLexeme(const char *start, int numBytes, 00525 unsigned char *lexemePtr, Tcl_Obj **literalPtr); 00526 00527 00528 /* 00529 *---------------------------------------------------------------------- 00530 * 00531 * ParseExpr -- 00532 * 00533 * Given a string, the numBytes bytes starting at start, this function 00534 * parses it as a Tcl expression and constructs a tree representing 00535 * the structure of the expression. The caller must pass in empty 00536 * lists as the funcList and litList arguments. The elements of the 00537 * parsed expression are returned to the caller as that tree, a list of 00538 * literal values, a list of function names, and in Tcl_Tokens 00539 * added to a Tcl_Parse struct passed in by the caller. 00540 * 00541 * Results: 00542 * If the string is successfully parsed as a valid Tcl expression, TCL_OK 00543 * is returned, and data about the expression structure is written to 00544 * the last four arguments. If the string cannot be parsed as a valid 00545 * Tcl expression, TCL_ERROR is returned, and if interp is non-NULL, an 00546 * error message is written to interp. 00547 * 00548 * Side effects: 00549 * Memory will be allocated. If TCL_OK is returned, the caller must 00550 * clean up the returned data structures. The (OpNode *) value written 00551 * to opTreePtr should be passed to ckfree() and the parsePtr argument 00552 * should be passed to Tcl_FreeParse(). The elements appended to the 00553 * litList and funcList will automatically be freed whenever the 00554 * refcount on those lists indicates they can be freed. 00555 * 00556 *---------------------------------------------------------------------- 00557 */ 00558 00559 static int 00560 ParseExpr( 00561 Tcl_Interp *interp, /* Used for error reporting. */ 00562 const char *start, /* Start of source string to parse. */ 00563 int numBytes, /* Number of bytes in string. */ 00564 OpNode **opTreePtr, /* Points to space where a pointer to the 00565 * allocated OpNode tree should go. */ 00566 Tcl_Obj *litList, /* List to append literals to. */ 00567 Tcl_Obj *funcList, /* List to append function names to. */ 00568 Tcl_Parse *parsePtr, /* Structure to fill with tokens representing 00569 * those operands that require run time 00570 * substitutions. */ 00571 int parseOnly) /* A boolean indicating whether the caller's 00572 * aim is just a parse, or whether it will go 00573 * on to compile the expression. Different 00574 * optimizations are appropriate for the 00575 * two scenarios. */ 00576 { 00577 OpNode *nodes = NULL; /* Pointer to the OpNode storage array where 00578 * we build the parse tree. */ 00579 int nodesAvailable = 64; /* Initial size of the storage array. This 00580 * value establishes a minimum tree memory cost 00581 * of only about 1 kibyte, and is large enough 00582 * for most expressions to parse with no need 00583 * for array growth and reallocation. */ 00584 int nodesUsed = 0; /* Number of OpNodes filled. */ 00585 int scanned = 0; /* Capture number of byte scanned by 00586 * parsing routines. */ 00587 int lastParsed; /* Stores info about what the lexeme parsed 00588 * the previous pass through the parsing loop 00589 * was. If it was an operator, lastParsed is 00590 * the index of the OpNode for that operator. 00591 * If it was not an operator, lastParsed holds 00592 * an OperandTypes value encoding what we 00593 * need to know about it. */ 00594 int incomplete; /* Index of the most recent incomplete tree 00595 * in the OpNode array. Heads a stack of 00596 * incomplete trees linked by p.prev. */ 00597 int complete = OT_EMPTY; /* "Index" of the complete tree (that is, a 00598 * complete subexpression) determined at the 00599 * moment. OT_EMPTY is a nonsense value 00600 * used only to silence compiler warnings. 00601 * During a parse, complete will always hold 00602 * an index or an OperandTypes value pointing 00603 * to an actual leaf at the time the complete 00604 * tree is needed. */ 00605 00606 /* These variables control generation of the error message. */ 00607 Tcl_Obj *msg = NULL; /* The error message. */ 00608 Tcl_Obj *post = NULL; /* In a few cases, an additional postscript 00609 * for the error message, supplying more 00610 * information after the error msg and 00611 * location have been reported. */ 00612 const char *mark = "_@_"; /* In the portion of the complete error message 00613 * where the error location is reported, this 00614 * "mark" substring is inserted into the 00615 * string being parsed to aid in pinpointing 00616 * the location of the syntax error in the 00617 * expression. */ 00618 int insertMark = 0; /* A boolean controlling whether the "mark" 00619 * should be inserted. */ 00620 const int limit = 25; /* Portions of the error message are 00621 * constructed out of substrings of the 00622 * original expression. In order to keep the 00623 * error message readable, we impose this limit 00624 * on the substring size we extract. */ 00625 00626 TclParseInit(interp, start, numBytes, parsePtr); 00627 00628 nodes = (OpNode *) attemptckalloc(nodesAvailable * sizeof(OpNode)); 00629 if (nodes == NULL) { 00630 TclNewLiteralStringObj(msg, "not enough memory to parse expression"); 00631 goto error; 00632 } 00633 00634 /* Initialize the parse tree with the special "START" node. */ 00635 nodes->lexeme = START; 00636 nodes->precedence = prec[START]; 00637 nodes->mark = MARK_RIGHT; 00638 nodes->constant = 1; 00639 incomplete = lastParsed = nodesUsed; 00640 nodesUsed++; 00641 00642 /* 00643 * Main parsing loop parses one lexeme per iteration. We exit the 00644 * loop only when there's a syntax error with a "goto error" which 00645 * takes us to the error handling code following the loop, or when 00646 * we've successfully completed the parse and we return to the caller. 00647 */ 00648 00649 while (1) { 00650 OpNode *nodePtr; /* Points to the OpNode we may fill this 00651 * pass through the loop. */ 00652 unsigned char lexeme; /* The lexeme we parse this iteration. */ 00653 Tcl_Obj *literal; /* Filled by the ParseLexeme() call when 00654 * a literal is parsed that has a Tcl_Obj 00655 * rep worth preserving. */ 00656 const char *lastStart = start - scanned; 00657 /* Compute where the lexeme parsed the 00658 * previous pass through the loop began. 00659 * This is helpful for detecting invalid 00660 * octals and providing more complete error 00661 * messages. */ 00662 00663 /* 00664 * Each pass through this loop adds up to one more OpNode. Allocate 00665 * space for one if required. 00666 */ 00667 00668 if (nodesUsed >= nodesAvailable) { 00669 int size = nodesUsed * 2; 00670 OpNode *newPtr; 00671 00672 do { 00673 newPtr = (OpNode *) attemptckrealloc((char *) nodes, 00674 (unsigned int) size * sizeof(OpNode)); 00675 } while ((newPtr == NULL) 00676 && ((size -= (size - nodesUsed) / 2) > nodesUsed)); 00677 if (newPtr == NULL) { 00678 TclNewLiteralStringObj(msg, 00679 "not enough memory to parse expression"); 00680 goto error; 00681 } 00682 nodesAvailable = size; 00683 nodes = newPtr; 00684 } 00685 nodePtr = nodes + nodesUsed; 00686 00687 /* Skip white space between lexemes. */ 00688 scanned = TclParseAllWhiteSpace(start, numBytes); 00689 start += scanned; 00690 numBytes -= scanned; 00691 00692 scanned = ParseLexeme(start, numBytes, &lexeme, &literal); 00693 00694 /* Use context to categorize the lexemes that are ambiguous. */ 00695 if ((NODE_TYPE & lexeme) == 0) { 00696 switch (lexeme) { 00697 case INVALID: 00698 msg = Tcl_ObjPrintf( 00699 "invalid character \"%.*s\"", scanned, start); 00700 goto error; 00701 case INCOMPLETE: 00702 msg = Tcl_ObjPrintf( 00703 "incomplete operator \"%.*s\"", scanned, start); 00704 goto error; 00705 case BAREWORD: 00706 00707 /* 00708 * Most barewords in an expression are a syntax error. 00709 * The exceptions are that when a bareword is followed by 00710 * an open paren, it might be a function call, and when the 00711 * bareword is a legal literal boolean value, we accept that 00712 * as well. 00713 */ 00714 00715 if (start[scanned+TclParseAllWhiteSpace( 00716 start+scanned, numBytes-scanned)] == '(') { 00717 lexeme = FUNCTION; 00718 00719 /* 00720 * When we compile the expression we'll need the function 00721 * name, and there's no place in the parse tree to store 00722 * it, so we keep a separate list of all the function 00723 * names we've parsed in the order we found them. 00724 */ 00725 00726 Tcl_ListObjAppendElement(NULL, funcList, literal); 00727 } else { 00728 int b; 00729 if (Tcl_GetBooleanFromObj(NULL, literal, &b) == TCL_OK) { 00730 lexeme = BOOLEAN; 00731 } else { 00732 Tcl_DecrRefCount(literal); 00733 msg = Tcl_ObjPrintf( 00734 "invalid bareword \"%.*s%s\"", 00735 (scanned < limit) ? scanned : limit - 3, start, 00736 (scanned < limit) ? "" : "..."); 00737 post = Tcl_ObjPrintf( 00738 "should be \"$%.*s%s\" or \"{%.*s%s}\"", 00739 (scanned < limit) ? scanned : limit - 3, 00740 start, (scanned < limit) ? "" : "...", 00741 (scanned < limit) ? scanned : limit - 3, 00742 start, (scanned < limit) ? "" : "..."); 00743 Tcl_AppendPrintfToObj(post, 00744 " or \"%.*s%s(...)\" or ...", 00745 (scanned < limit) ? scanned : limit - 3, 00746 start, (scanned < limit) ? "" : "..."); 00747 if (NotOperator(lastParsed)) { 00748 if ((lastStart[0] == '0') 00749 && ((lastStart[1] == 'o') 00750 || (lastStart[1] == 'O')) 00751 && (lastStart[2] >= '0') 00752 && (lastStart[2] <= '9')) { 00753 const char *end = lastStart + 2; 00754 Tcl_Obj* copy; 00755 while (isdigit(*end)) { 00756 end++; 00757 } 00758 copy = Tcl_NewStringObj(lastStart, 00759 end - lastStart); 00760 if (TclCheckBadOctal(NULL, 00761 Tcl_GetString(copy))) { 00762 TclNewLiteralStringObj(post, 00763 "(invalid octal number?)"); 00764 } 00765 Tcl_DecrRefCount(copy); 00766 } 00767 scanned = 0; 00768 insertMark = 1; 00769 parsePtr->errorType = TCL_PARSE_BAD_NUMBER; 00770 } 00771 goto error; 00772 } 00773 } 00774 break; 00775 case PLUS: 00776 case MINUS: 00777 if (IsOperator(lastParsed)) { 00778 00779 /* 00780 * A "+" or "-" coming just after another operator 00781 * must be interpreted as a unary operator. 00782 */ 00783 00784 lexeme |= UNARY; 00785 } else { 00786 lexeme |= BINARY; 00787 } 00788 } 00789 } /* Uncategorized lexemes */ 00790 00791 /* Handle lexeme based on its category. */ 00792 switch (NODE_TYPE & lexeme) { 00793 00794 /* 00795 * Each LEAF results in either a literal getting appended to the 00796 * litList, or a sequence of Tcl_Tokens representing a Tcl word 00797 * getting appended to the parsePtr->tokens. No OpNode is filled 00798 * for this lexeme. 00799 */ 00800 00801 case LEAF: { 00802 Tcl_Token *tokenPtr; 00803 const char *end = start; 00804 int wordIndex; 00805 int code = TCL_OK; 00806 00807 /* 00808 * A leaf operand appearing just after something that's not an 00809 * operator is a syntax error. 00810 */ 00811 00812 if (NotOperator(lastParsed)) { 00813 msg = Tcl_ObjPrintf("missing operator at %s", mark); 00814 if (lastStart[0] == '0') { 00815 Tcl_Obj *copy = Tcl_NewStringObj(lastStart, 00816 start + scanned - lastStart); 00817 if (TclCheckBadOctal(NULL, Tcl_GetString(copy))) { 00818 TclNewLiteralStringObj(post, 00819 "looks like invalid octal number"); 00820 } 00821 Tcl_DecrRefCount(copy); 00822 } 00823 scanned = 0; 00824 insertMark = 1; 00825 parsePtr->errorType = TCL_PARSE_BAD_NUMBER; 00826 00827 /* Free any literal to avoid a memleak. */ 00828 if ((lexeme == NUMBER) || (lexeme == BOOLEAN)) { 00829 Tcl_DecrRefCount(literal); 00830 } 00831 goto error; 00832 } 00833 00834 switch (lexeme) { 00835 case NUMBER: 00836 case BOOLEAN: 00837 /* 00838 * TODO: Consider using a dict or hash to collapse all 00839 * duplicate literals into a single representative value. 00840 * (Like what is done with [split $s {}]). 00841 * Pro: ~75% memory saving on expressions like 00842 * {1+1+1+1+1+.....+1} (Convert "pointer + Tcl_Obj" cost 00843 * to "pointer" cost only) 00844 * Con: Cost of the dict store/retrieve on every literal 00845 * in every expression when expressions like the above 00846 * tend to be uncommon. 00847 * The memory savings is temporary; Compiling to bytecode 00848 * will collapse things as literals are registered 00849 * anyway, so the savings applies only to the time 00850 * between parsing and compiling. Possibly important 00851 * due to high-water mark nature of memory allocation. 00852 */ 00853 Tcl_ListObjAppendElement(NULL, litList, literal); 00854 complete = lastParsed = OT_LITERAL; 00855 start += scanned; 00856 numBytes -= scanned; 00857 continue; 00858 00859 default: 00860 break; 00861 } 00862 00863 /* 00864 * Remaining LEAF cases may involve filling Tcl_Tokens, so 00865 * make room for at least 2 more tokens. 00866 */ 00867 00868 TclGrowParseTokenArray(parsePtr, 2); 00869 wordIndex = parsePtr->numTokens; 00870 tokenPtr = parsePtr->tokenPtr + wordIndex; 00871 tokenPtr->type = TCL_TOKEN_WORD; 00872 tokenPtr->start = start; 00873 parsePtr->numTokens++; 00874 00875 switch (lexeme) { 00876 case QUOTED: 00877 code = Tcl_ParseQuotedString(NULL, start, numBytes, 00878 parsePtr, 1, &end); 00879 scanned = end - start; 00880 break; 00881 00882 case BRACED: 00883 code = Tcl_ParseBraces(NULL, start, numBytes, 00884 parsePtr, 1, &end); 00885 scanned = end - start; 00886 break; 00887 00888 case VARIABLE: 00889 code = Tcl_ParseVarName(NULL, start, numBytes, parsePtr, 1); 00890 00891 /* 00892 * Handle the quirk that Tcl_ParseVarName reports a successful 00893 * parse even when it gets only a "$" with no variable name. 00894 */ 00895 00896 tokenPtr = parsePtr->tokenPtr + wordIndex + 1; 00897 if (code == TCL_OK && tokenPtr->type != TCL_TOKEN_VARIABLE) { 00898 TclNewLiteralStringObj(msg, "invalid character \"$\""); 00899 goto error; 00900 } 00901 scanned = tokenPtr->size; 00902 break; 00903 00904 case SCRIPT: { 00905 Tcl_Parse *nestedPtr = 00906 (Tcl_Parse *) TclStackAlloc(interp, sizeof(Tcl_Parse)); 00907 00908 tokenPtr = parsePtr->tokenPtr + parsePtr->numTokens; 00909 tokenPtr->type = TCL_TOKEN_COMMAND; 00910 tokenPtr->start = start; 00911 tokenPtr->numComponents = 0; 00912 00913 end = start + numBytes; 00914 start++; 00915 while (1) { 00916 code = Tcl_ParseCommand(interp, start, (end - start), 1, 00917 nestedPtr); 00918 if (code != TCL_OK) { 00919 parsePtr->term = nestedPtr->term; 00920 parsePtr->errorType = nestedPtr->errorType; 00921 parsePtr->incomplete = nestedPtr->incomplete; 00922 break; 00923 } 00924 start = (nestedPtr->commandStart + nestedPtr->commandSize); 00925 Tcl_FreeParse(nestedPtr); 00926 if ((nestedPtr->term < end) && (*(nestedPtr->term) == ']') 00927 && !(nestedPtr->incomplete)) { 00928 break; 00929 } 00930 00931 if (start == end) { 00932 TclNewLiteralStringObj(msg, "missing close-bracket"); 00933 parsePtr->term = tokenPtr->start; 00934 parsePtr->errorType = TCL_PARSE_MISSING_BRACKET; 00935 parsePtr->incomplete = 1; 00936 code = TCL_ERROR; 00937 break; 00938 } 00939 } 00940 TclStackFree(interp, nestedPtr); 00941 end = start; 00942 start = tokenPtr->start; 00943 scanned = end - start; 00944 tokenPtr->size = scanned; 00945 parsePtr->numTokens++; 00946 break; 00947 } 00948 } 00949 if (code != TCL_OK) { 00950 00951 /* 00952 * Here we handle all the syntax errors generated by 00953 * the Tcl_Token generating parsing routines called in the 00954 * switch just above. If the value of parsePtr->incomplete 00955 * is 1, then the error was an unbalanced '[', '(', '{', 00956 * or '"' and parsePtr->term is pointing to that unbalanced 00957 * character. If the value of parsePtr->incomplete is 0, 00958 * then the error is one of lacking whitespace following a 00959 * quoted word, for example: expr {[an error {foo}bar]}, 00960 * and parsePtr->term points to where the whitespace is 00961 * missing. We reset our values of start and scanned so that 00962 * when our error message is constructed, the location of 00963 * the syntax error is sure to appear in it, even if the 00964 * quoted expression is truncated. 00965 */ 00966 00967 start = parsePtr->term; 00968 scanned = parsePtr->incomplete; 00969 goto error; 00970 } 00971 00972 tokenPtr = parsePtr->tokenPtr + wordIndex; 00973 tokenPtr->size = scanned; 00974 tokenPtr->numComponents = parsePtr->numTokens - wordIndex - 1; 00975 if (!parseOnly && ((lexeme == QUOTED) || (lexeme == BRACED))) { 00976 00977 /* 00978 * When this expression is destined to be compiled, and a 00979 * braced or quoted word within an expression is known at 00980 * compile time (no runtime substitutions in it), we can 00981 * store it as a literal rather than in its tokenized form. 00982 * This is an advantage since the compiled bytecode is going 00983 * to need the argument in Tcl_Obj form eventually, so it's 00984 * just as well to get there now. Another advantage is that 00985 * with this conversion, larger constant expressions might 00986 * be grown and optimized. 00987 * 00988 * On the contrary, if the end goal of this parse is to 00989 * fill a Tcl_Parse for a caller of Tcl_ParseExpr(), then it's 00990 * wasteful to convert to a literal only to convert back again 00991 * later. 00992 */ 00993 00994 literal = Tcl_NewObj(); 00995 if (TclWordKnownAtCompileTime(tokenPtr, literal)) { 00996 Tcl_ListObjAppendElement(NULL, litList, literal); 00997 complete = lastParsed = OT_LITERAL; 00998 parsePtr->numTokens = wordIndex; 00999 break; 01000 } 01001 Tcl_DecrRefCount(literal); 01002 } 01003 complete = lastParsed = OT_TOKENS; 01004 break; 01005 } /* case LEAF */ 01006 01007 case UNARY: 01008 01009 /* 01010 * A unary operator appearing just after something that's not an 01011 * operator is a syntax error -- something trying to be the left 01012 * operand of an operator that doesn't take one. 01013 */ 01014 01015 if (NotOperator(lastParsed)) { 01016 msg = Tcl_ObjPrintf("missing operator at %s", mark); 01017 scanned = 0; 01018 insertMark = 1; 01019 goto error; 01020 } 01021 01022 /* Create an OpNode for the unary operator */ 01023 nodePtr->lexeme = lexeme; 01024 nodePtr->precedence = prec[lexeme]; 01025 nodePtr->mark = MARK_RIGHT; 01026 01027 /* 01028 * A FUNCTION cannot be a constant expression, because Tcl allows 01029 * functions to return variable results with the same arguments; 01030 * for example, rand(). Other unary operators can root a constant 01031 * expression, so long as the argument is a constant expression. 01032 */ 01033 01034 nodePtr->constant = (lexeme != FUNCTION); 01035 01036 /* 01037 * This unary operator is a new incomplete tree, so push it 01038 * onto our stack of incomplete trees. Also remember it as 01039 * the last lexeme we parsed. 01040 */ 01041 01042 nodePtr->p.prev = incomplete; 01043 incomplete = lastParsed = nodesUsed; 01044 nodesUsed++; 01045 break; 01046 01047 case BINARY: { 01048 OpNode *incompletePtr; 01049 unsigned char precedence = prec[lexeme]; 01050 01051 /* 01052 * A binary operator appearing just after another operator is a 01053 * syntax error -- one of the two operators is missing an operand. 01054 */ 01055 01056 if (IsOperator(lastParsed)) { 01057 if ((lexeme == CLOSE_PAREN) 01058 && (nodePtr[-1].lexeme == OPEN_PAREN)) { 01059 if (nodePtr[-2].lexeme == FUNCTION) { 01060 01061 /* 01062 * Normally, "()" is a syntax error, but as a special 01063 * case accept it as an argument list for a function. 01064 * Treat this as a special LEAF lexeme, and restart 01065 * the parsing loop with zero characters scanned. 01066 * We'll parse the ")" again the next time through, 01067 * but with the OT_EMPTY leaf as the subexpression 01068 * between the parens. 01069 */ 01070 01071 scanned = 0; 01072 complete = lastParsed = OT_EMPTY; 01073 break; 01074 } 01075 msg = Tcl_ObjPrintf("empty subexpression at %s", mark); 01076 scanned = 0; 01077 insertMark = 1; 01078 goto error; 01079 } 01080 01081 if (nodePtr[-1].precedence > precedence) { 01082 if (nodePtr[-1].lexeme == OPEN_PAREN) { 01083 TclNewLiteralStringObj(msg, "unbalanced open paren"); 01084 parsePtr->errorType = TCL_PARSE_MISSING_PAREN; 01085 } else if (nodePtr[-1].lexeme == COMMA) { 01086 msg = Tcl_ObjPrintf( 01087 "missing function argument at %s", mark); 01088 scanned = 0; 01089 insertMark = 1; 01090 } else if (nodePtr[-1].lexeme == START) { 01091 TclNewLiteralStringObj(msg, "empty expression"); 01092 } 01093 } else { 01094 if (lexeme == CLOSE_PAREN) { 01095 TclNewLiteralStringObj(msg, "unbalanced close paren"); 01096 } else if ((lexeme == COMMA) 01097 && (nodePtr[-1].lexeme == OPEN_PAREN) 01098 && (nodePtr[-2].lexeme == FUNCTION)) { 01099 msg = Tcl_ObjPrintf( 01100 "missing function argument at %s", mark); 01101 scanned = 0; 01102 insertMark = 1; 01103 } 01104 } 01105 if (msg == NULL) { 01106 msg = Tcl_ObjPrintf("missing operand at %s", mark); 01107 scanned = 0; 01108 insertMark = 1; 01109 } 01110 goto error; 01111 } 01112 01113 /* 01114 * Here is where the tree comes together. At this point, we 01115 * have a stack of incomplete trees corresponding to 01116 * substrings that are incomplete expressions, followed by 01117 * a complete tree corresponding to a substring that is itself 01118 * a complete expression, followed by the binary operator we have 01119 * just parsed. The incomplete trees can each be completed by 01120 * adding a right operand. 01121 * 01122 * To illustrate with an example, when we parse the expression 01123 * "1+2*3-4" and we reach this point having just parsed the "-" 01124 * operator, we have these incomplete trees: START, "1+", and 01125 * "2*". Next we have the complete subexpression "3". Last is 01126 * the "-" we've just parsed. 01127 * 01128 * The next step is to join our complete tree to an operator. 01129 * The choice is governed by the precedence and associativity 01130 * of the competing operators. If we connect it as the right 01131 * operand of our most recent incomplete tree, we get a new 01132 * complete tree, and we can repeat the process. The while 01133 * loop following repeats this until precedence indicates it 01134 * is time to join the complete tree as the left operand of 01135 * the just parsed binary operator. 01136 * 01137 * Continuing the example, the first pass through the loop 01138 * will join "3" to "2*"; the next pass will join "2*3" to 01139 * "1+". Then we'll exit the loop and join "1+2*3" to "-". 01140 * When we return to parse another lexeme, our stack of 01141 * incomplete trees is START and "1+2*3-". 01142 */ 01143 01144 while (1) { 01145 incompletePtr = nodes + incomplete; 01146 01147 if (incompletePtr->precedence < precedence) { 01148 break; 01149 } 01150 01151 if (incompletePtr->precedence == precedence) { 01152 01153 /* Right association rules for exponentiation. */ 01154 if (lexeme == EXPON) { 01155 break; 01156 } 01157 01158 /* 01159 * Special association rules for the conditional operators. 01160 * The "?" and ":" operators have equal precedence, but 01161 * must be linked up in sensible pairs. 01162 */ 01163 01164 if ((incompletePtr->lexeme == QUESTION) 01165 && (NotOperator(complete) 01166 || (nodes[complete].lexeme != COLON))) { 01167 break; 01168 } 01169 if ((incompletePtr->lexeme == COLON) 01170 && (lexeme == QUESTION)) { 01171 break; 01172 } 01173 } 01174 01175 /* Some special syntax checks... */ 01176 01177 /* Parens must balance */ 01178 if ((incompletePtr->lexeme == OPEN_PAREN) 01179 && (lexeme != CLOSE_PAREN)) { 01180 TclNewLiteralStringObj(msg, "unbalanced open paren"); 01181 parsePtr->errorType = TCL_PARSE_MISSING_PAREN; 01182 goto error; 01183 } 01184 01185 /* Right operand of "?" must be ":" */ 01186 if ((incompletePtr->lexeme == QUESTION) 01187 && (NotOperator(complete) 01188 || (nodes[complete].lexeme != COLON))) { 01189 msg = Tcl_ObjPrintf( 01190 "missing operator \":\" at %s", mark); 01191 scanned = 0; 01192 insertMark = 1; 01193 goto error; 01194 } 01195 01196 /* Operator ":" may only be right operand of "?" */ 01197 if (IsOperator(complete) 01198 && (nodes[complete].lexeme == COLON) 01199 && (incompletePtr->lexeme != QUESTION)) { 01200 TclNewLiteralStringObj(msg, 01201 "unexpected operator \":\" " 01202 "without preceding \"?\""); 01203 goto error; 01204 } 01205 01206 /* 01207 * Attach complete tree as right operand of most recent 01208 * incomplete tree. 01209 */ 01210 01211 incompletePtr->right = complete; 01212 if (IsOperator(complete)) { 01213 nodes[complete].p.parent = incomplete; 01214 incompletePtr->constant = incompletePtr->constant 01215 && nodes[complete].constant; 01216 } else { 01217 incompletePtr->constant = incompletePtr->constant 01218 && (complete == OT_LITERAL); 01219 } 01220 01221 /* 01222 * The QUESTION/COLON and FUNCTION/OPEN_PAREN combinations each 01223 * make up a single operator. Force them to agree whether they 01224 * have a constant expression. 01225 */ 01226 01227 if ((incompletePtr->lexeme == QUESTION) 01228 || (incompletePtr->lexeme == FUNCTION)) { 01229 nodes[complete].constant = incompletePtr->constant; 01230 } 01231 01232 if (incompletePtr->lexeme == START) { 01233 01234 /* 01235 * Completing the START tree indicates we're done. 01236 * Transfer the parse tree to the caller and return. 01237 */ 01238 01239 *opTreePtr = nodes; 01240 return TCL_OK; 01241 } 01242 01243 /* 01244 * With a right operand attached, last incomplete tree has 01245 * become the complete tree. Pop it from the incomplete 01246 * tree stack. 01247 */ 01248 01249 complete = incomplete; 01250 incomplete = incompletePtr->p.prev; 01251 01252 /* CLOSE_PAREN can only close one OPEN_PAREN. */ 01253 if (incompletePtr->lexeme == OPEN_PAREN) { 01254 break; 01255 } 01256 } 01257 01258 /* More syntax checks... */ 01259 01260 /* Parens must balance. */ 01261 if (lexeme == CLOSE_PAREN) { 01262 if (incompletePtr->lexeme != OPEN_PAREN) { 01263 TclNewLiteralStringObj(msg, "unbalanced close paren"); 01264 goto error; 01265 } 01266 } 01267 01268 /* Commas must appear only in function argument lists. */ 01269 if (lexeme == COMMA) { 01270 if ((incompletePtr->lexeme != OPEN_PAREN) 01271 || (incompletePtr[-1].lexeme != FUNCTION)) { 01272 TclNewLiteralStringObj(msg, 01273 "unexpected \",\" outside function argument list"); 01274 goto error; 01275 } 01276 } 01277 01278 /* Operator ":" may only be right operand of "?" */ 01279 if (IsOperator(complete) && (nodes[complete].lexeme == COLON)) { 01280 TclNewLiteralStringObj(msg, 01281 "unexpected operator \":\" without preceding \"?\""); 01282 goto error; 01283 } 01284 01285 /* Create no node for a CLOSE_PAREN lexeme. */ 01286 if (lexeme == CLOSE_PAREN) { 01287 break; 01288 } 01289 01290 /* Link complete tree as left operand of new node. */ 01291 nodePtr->lexeme = lexeme; 01292 nodePtr->precedence = precedence; 01293 nodePtr->mark = MARK_LEFT; 01294 nodePtr->left = complete; 01295 01296 /* 01297 * The COMMA operator cannot be optimized, since the function 01298 * needs all of its arguments, and optimization would reduce 01299 * the number. Other binary operators root constant expressions 01300 * when both arguments are constant expressions. 01301 */ 01302 01303 nodePtr->constant = (lexeme != COMMA); 01304 01305 if (IsOperator(complete)) { 01306 nodes[complete].p.parent = nodesUsed; 01307 nodePtr->constant = nodePtr->constant 01308 && nodes[complete].constant; 01309 } else { 01310 nodePtr->constant = nodePtr->constant 01311 && (complete == OT_LITERAL); 01312 } 01313 01314 /* 01315 * With a left operand attached and a right operand missing, 01316 * the just-parsed binary operator is root of a new incomplete 01317 * tree. Push it onto the stack of incomplete trees. 01318 */ 01319 01320 nodePtr->p.prev = incomplete; 01321 incomplete = lastParsed = nodesUsed; 01322 nodesUsed++; 01323 break; 01324 } /* case BINARY */ 01325 } /* lexeme handler */ 01326 01327 /* Advance past the just-parsed lexeme */ 01328 start += scanned; 01329 numBytes -= scanned; 01330 } /* main parsing loop */ 01331 01332 error: 01333 01334 /* 01335 * We only get here if there's been an error. 01336 * Any errors that didn't get a suitable parsePtr->errorType, 01337 * get recorded as syntax errors. 01338 */ 01339 01340 if (parsePtr->errorType == TCL_PARSE_SUCCESS) { 01341 parsePtr->errorType = TCL_PARSE_SYNTAX; 01342 } 01343 01344 /* Free any partial parse tree we've built. */ 01345 if (nodes != NULL) { 01346 ckfree((char*) nodes); 01347 } 01348 01349 if (interp == NULL) { 01350 01351 /* Nowhere to report an error message, so just free it */ 01352 if (msg) { 01353 Tcl_DecrRefCount(msg); 01354 } 01355 } else { 01356 01357 /* 01358 * Construct the complete error message. Start with the simple 01359 * error message, pulled from the interp result if necessary... 01360 */ 01361 01362 if (msg == NULL) { 01363 msg = Tcl_GetObjResult(interp); 01364 } 01365 01366 /* 01367 * Add a detailed quote from the bad expression, displaying and 01368 * sometimes marking the precise location of the syntax error. 01369 */ 01370 01371 Tcl_AppendPrintfToObj(msg, "\nin expression \"%s%.*s%.*s%s%s%.*s%s\"", 01372 ((start - limit) < parsePtr->string) ? "" : "...", 01373 ((start - limit) < parsePtr->string) 01374 ? (start - parsePtr->string) : limit - 3, 01375 ((start - limit) < parsePtr->string) 01376 ? parsePtr->string : start - limit + 3, 01377 (scanned < limit) ? scanned : limit - 3, start, 01378 (scanned < limit) ? "" : "...", insertMark ? mark : "", 01379 (start + scanned + limit > parsePtr->end) 01380 ? parsePtr->end - (start + scanned) : limit-3, 01381 start + scanned, 01382 (start + scanned + limit > parsePtr->end) ? "" : "..."); 01383 01384 /* Next, append any postscript message. */ 01385 if (post != NULL) { 01386 Tcl_AppendToObj(msg, ";\n", -1); 01387 Tcl_AppendObjToObj(msg, post); 01388 Tcl_DecrRefCount(post); 01389 } 01390 Tcl_SetObjResult(interp, msg); 01391 01392 /* Finally, place context information in the errorInfo. */ 01393 numBytes = parsePtr->end - parsePtr->string; 01394 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( 01395 "\n (parsing expression \"%.*s%s\")", 01396 (numBytes < limit) ? numBytes : limit - 3, 01397 parsePtr->string, (numBytes < limit) ? "" : "...")); 01398 } 01399 01400 return TCL_ERROR; 01401 } 01402 01403 /* 01404 *---------------------------------------------------------------------- 01405 * 01406 * ConvertTreeToTokens -- 01407 * 01408 * Given a string, the numBytes bytes starting at start, and an OpNode 01409 * tree and Tcl_Token array created by passing that same string to 01410 * ParseExpr(), this function writes into *parsePtr the sequence of 01411 * Tcl_Tokens needed so to satisfy the historical interface provided 01412 * by Tcl_ParseExpr(). Note that this routine exists only for the sake 01413 * of the public Tcl_ParseExpr() routine. It is not used by Tcl itself 01414 * at all. 01415 * 01416 * Results: 01417 * None. 01418 * 01419 * Side effects: 01420 * The Tcl_Parse *parsePtr is filled with Tcl_Tokens representing the 01421 * parsed expression. 01422 * 01423 *---------------------------------------------------------------------- 01424 */ 01425 01426 static void 01427 ConvertTreeToTokens( 01428 const char *start, 01429 int numBytes, 01430 OpNode *nodes, 01431 Tcl_Token *tokenPtr, 01432 Tcl_Parse *parsePtr) 01433 { 01434 int subExprTokenIdx = 0; 01435 OpNode *nodePtr = nodes; 01436 int next = nodePtr->right; 01437 01438 while (1) { 01439 Tcl_Token *subExprTokenPtr; 01440 int scanned, parentIdx; 01441 unsigned char lexeme; 01442 01443 /* 01444 * Advance the mark so the next exit from this node won't retrace 01445 * steps over ground already covered. 01446 */ 01447 01448 nodePtr->mark++; 01449 01450 /* Handle next child node or leaf */ 01451 switch (next) { 01452 case OT_EMPTY: 01453 01454 /* No tokens and no characters for the OT_EMPTY leaf. */ 01455 break; 01456 01457 case OT_LITERAL: 01458 01459 /* Skip any white space that comes before the literal */ 01460 scanned = TclParseAllWhiteSpace(start, numBytes); 01461 start +=scanned; 01462 numBytes -= scanned; 01463 01464 /* Reparse the literal to get pointers into source string */ 01465 scanned = ParseLexeme(start, numBytes, &lexeme, NULL); 01466 01467 TclGrowParseTokenArray(parsePtr, 2); 01468 subExprTokenPtr = parsePtr->tokenPtr + parsePtr->numTokens; 01469 subExprTokenPtr->type = TCL_TOKEN_SUB_EXPR; 01470 subExprTokenPtr->start = start; 01471 subExprTokenPtr->size = scanned; 01472 subExprTokenPtr->numComponents = 1; 01473 subExprTokenPtr[1].type = TCL_TOKEN_TEXT; 01474 subExprTokenPtr[1].start = start; 01475 subExprTokenPtr[1].size = scanned; 01476 subExprTokenPtr[1].numComponents = 0; 01477 01478 parsePtr->numTokens += 2; 01479 start +=scanned; 01480 numBytes -= scanned; 01481 break; 01482 01483 case OT_TOKENS: { 01484 01485 /* 01486 * tokenPtr points to a token sequence that came from parsing 01487 * a Tcl word. A Tcl word is made up of a sequence of one or 01488 * more elements. When the word is only a single element, it's 01489 * been the historical practice to replace the TCL_TOKEN_WORD 01490 * token directly with a TCL_TOKEN_SUB_EXPR token. However, 01491 * when the word has multiple elements, a TCL_TOKEN_WORD token 01492 * is kept as a grouping device so that TCL_TOKEN_SUB_EXPR 01493 * always has only one element. Wise or not, these are the 01494 * rules the Tcl expr parser has followed, and for the sake 01495 * of those few callers of Tcl_ParseExpr() we do not change 01496 * them now. Internally, we can do better. 01497 */ 01498 01499 int toCopy = tokenPtr->numComponents + 1; 01500 01501 if (tokenPtr->numComponents == tokenPtr[1].numComponents + 1) { 01502 01503 /* 01504 * Single element word. Copy tokens and convert the leading 01505 * token to TCL_TOKEN_SUB_EXPR. 01506 */ 01507 01508 TclGrowParseTokenArray(parsePtr, toCopy); 01509 subExprTokenPtr = parsePtr->tokenPtr + parsePtr->numTokens; 01510 memcpy(subExprTokenPtr, tokenPtr, 01511 (size_t) toCopy * sizeof(Tcl_Token)); 01512 subExprTokenPtr->type = TCL_TOKEN_SUB_EXPR; 01513 parsePtr->numTokens += toCopy; 01514 } else { 01515 01516 /* 01517 * Multiple element word. Create a TCL_TOKEN_SUB_EXPR 01518 * token to lead, with fields initialized from the leading 01519 * token, then copy entire set of word tokens. 01520 */ 01521 01522 TclGrowParseTokenArray(parsePtr, toCopy+1); 01523 subExprTokenPtr = parsePtr->tokenPtr + parsePtr->numTokens; 01524 *subExprTokenPtr = *tokenPtr; 01525 subExprTokenPtr->type = TCL_TOKEN_SUB_EXPR; 01526 subExprTokenPtr->numComponents++; 01527 subExprTokenPtr++; 01528 memcpy(subExprTokenPtr, tokenPtr, 01529 (size_t) toCopy * sizeof(Tcl_Token)); 01530 parsePtr->numTokens += toCopy + 1; 01531 } 01532 01533 scanned = tokenPtr->start + tokenPtr->size - start; 01534 start +=scanned; 01535 numBytes -= scanned; 01536 tokenPtr += toCopy; 01537 break; 01538 } 01539 01540 default: 01541 01542 /* Advance to the child node, which is an operator. */ 01543 nodePtr = nodes + next; 01544 01545 /* Skip any white space that comes before the subexpression */ 01546 scanned = TclParseAllWhiteSpace(start, numBytes); 01547 start +=scanned; 01548 numBytes -= scanned; 01549 01550 /* Generate tokens for the operator / subexpression... */ 01551 switch (nodePtr->lexeme) { 01552 case OPEN_PAREN: 01553 case COMMA: 01554 case COLON: 01555 01556 /* 01557 * Historical practice has been to have no Tcl_Tokens for 01558 * these operators. 01559 */ 01560 01561 break; 01562 01563 default: { 01564 01565 /* 01566 * Remember the index of the last subexpression we were 01567 * working on -- that of our parent. We'll stack it later. 01568 */ 01569 01570 parentIdx = subExprTokenIdx; 01571 01572 /* 01573 * Verify space for the two leading Tcl_Tokens representing 01574 * the subexpression rooted by this operator. The first 01575 * Tcl_Token will be of type TCL_TOKEN_SUB_EXPR; the second 01576 * of type TCL_TOKEN_OPERATOR. 01577 */ 01578 01579 TclGrowParseTokenArray(parsePtr, 2); 01580 subExprTokenIdx = parsePtr->numTokens; 01581 subExprTokenPtr = parsePtr->tokenPtr + subExprTokenIdx; 01582 parsePtr->numTokens += 2; 01583 subExprTokenPtr->type = TCL_TOKEN_SUB_EXPR; 01584 subExprTokenPtr[1].type = TCL_TOKEN_OPERATOR; 01585 01586 /* 01587 * Our current position scanning the string is the starting 01588 * point for this subexpression. 01589 */ 01590 01591 subExprTokenPtr->start = start; 01592 01593 /* 01594 * Eventually, we know that the numComponents field of the 01595 * Tcl_Token of type TCL_TOKEN_OPERATOR will be 0. This means 01596 * we can make other use of this field for now to track the 01597 * stack of subexpressions we have pending. 01598 */ 01599 01600 subExprTokenPtr[1].numComponents = parentIdx; 01601 break; 01602 } 01603 } 01604 break; 01605 } 01606 01607 /* Determine which way to exit the node on this pass. */ 01608 router: 01609 switch (nodePtr->mark) { 01610 case MARK_LEFT: 01611 next = nodePtr->left; 01612 break; 01613 01614 case MARK_RIGHT: 01615 next = nodePtr->right; 01616 01617 /* Skip any white space that comes before the operator */ 01618 scanned = TclParseAllWhiteSpace(start, numBytes); 01619 start +=scanned; 01620 numBytes -= scanned; 01621 01622 /* 01623 * Here we scan from the string the operator corresponding to 01624 * nodePtr->lexeme. 01625 */ 01626 01627 scanned = ParseLexeme(start, numBytes, &lexeme, NULL); 01628 01629 switch(nodePtr->lexeme) { 01630 case OPEN_PAREN: 01631 case COMMA: 01632 case COLON: 01633 01634 /* No tokens for these lexemes -> nothing to do. */ 01635 break; 01636 01637 default: 01638 01639 /* 01640 * Record in the TCL_TOKEN_OPERATOR token the pointers into 01641 * the string marking where the operator is. 01642 */ 01643 01644 subExprTokenPtr = parsePtr->tokenPtr + subExprTokenIdx; 01645 subExprTokenPtr[1].start = start; 01646 subExprTokenPtr[1].size = scanned; 01647 break; 01648 } 01649 01650 start +=scanned; 01651 numBytes -= scanned; 01652 break; 01653 01654 case MARK_PARENT: 01655 switch (nodePtr->lexeme) { 01656 case START: 01657 01658 /* When we get back to the START node, we're done. */ 01659 return; 01660 01661 case COMMA: 01662 case COLON: 01663 01664 /* No tokens for these lexemes -> nothing to do. */ 01665 break; 01666 01667 case OPEN_PAREN: 01668 01669 /* Skip past matching close paren. */ 01670 scanned = TclParseAllWhiteSpace(start, numBytes); 01671 start +=scanned; 01672 numBytes -= scanned; 01673 scanned = ParseLexeme(start, numBytes, &lexeme, NULL); 01674 start +=scanned; 01675 numBytes -= scanned; 01676 break; 01677 01678 default: { 01679 01680 /* 01681 * Before we leave this node/operator/subexpression for the 01682 * last time, finish up its tokens.... 01683 * 01684 * Our current position scanning the string is where the 01685 * substring for the subexpression ends. 01686 */ 01687 01688 subExprTokenPtr = parsePtr->tokenPtr + subExprTokenIdx; 01689 subExprTokenPtr->size = start - subExprTokenPtr->start; 01690 01691 /* 01692 * All the Tcl_Tokens allocated and filled belong to 01693 * this subexpresion. The first token is the leading 01694 * TCL_TOKEN_SUB_EXPR token, and all the rest (one fewer) 01695 * are its components. 01696 */ 01697 01698 subExprTokenPtr->numComponents = 01699 (parsePtr->numTokens - subExprTokenIdx) - 1; 01700 01701 /* 01702 * Finally, as we return up the tree to our parent, pop the 01703 * parent subexpression off our subexpression stack, and 01704 * fill in the zero numComponents for the operator Tcl_Token. 01705 */ 01706 01707 parentIdx = subExprTokenPtr[1].numComponents; 01708 subExprTokenPtr[1].numComponents = 0; 01709 subExprTokenIdx = parentIdx; 01710 break; 01711 } 01712 } 01713 01714 /* Since we're returning to parent, skip child handling code. */ 01715 nodePtr = nodes + nodePtr->p.parent; 01716 goto router; 01717 } 01718 } 01719 } 01720 01721 /* 01722 *---------------------------------------------------------------------- 01723 * 01724 * Tcl_ParseExpr -- 01725 * 01726 * Given a string, the numBytes bytes starting at start, this function 01727 * parses it as a Tcl expression and stores information about the 01728 * structure of the expression in the Tcl_Parse struct indicated by the 01729 * caller. 01730 * 01731 * Results: 01732 * If the string is successfully parsed as a valid Tcl expression, TCL_OK 01733 * is returned, and data about the expression structure is written to 01734 * *parsePtr. If the string cannot be parsed as a valid Tcl expression, 01735 * TCL_ERROR is returned, and if interp is non-NULL, an error message is 01736 * written to interp. 01737 * 01738 * Side effects: 01739 * If there is insufficient space in parsePtr to hold all the information 01740 * about the expression, then additional space is malloc-ed. If the 01741 * function returns TCL_OK then the caller must eventually invoke 01742 * Tcl_FreeParse to release any additional space that was allocated. 01743 * 01744 *---------------------------------------------------------------------- 01745 */ 01746 01747 int 01748 Tcl_ParseExpr( 01749 Tcl_Interp *interp, /* Used for error reporting. */ 01750 const char *start, /* Start of source string to parse. */ 01751 int numBytes, /* Number of bytes in string. If < 0, the 01752 * string consists of all bytes up to the 01753 * first null character. */ 01754 Tcl_Parse *parsePtr) /* Structure to fill with information about 01755 * the parsed expression; any previous 01756 * information in the structure is ignored. */ 01757 { 01758 int code; 01759 OpNode *opTree = NULL; /* Will point to the tree of operators */ 01760 Tcl_Obj *litList = Tcl_NewObj(); /* List to hold the literals */ 01761 Tcl_Obj *funcList = Tcl_NewObj(); /* List to hold the functon names*/ 01762 Tcl_Parse *exprParsePtr = 01763 (Tcl_Parse *) TclStackAlloc(interp, sizeof(Tcl_Parse)); 01764 /* Holds the Tcl_Tokens of substitutions */ 01765 01766 if (numBytes < 0) { 01767 numBytes = (start ? strlen(start) : 0); 01768 } 01769 01770 code = ParseExpr(interp, start, numBytes, &opTree, litList, 01771 funcList, exprParsePtr, 1 /* parseOnly */); 01772 Tcl_DecrRefCount(funcList); 01773 Tcl_DecrRefCount(litList); 01774 01775 TclParseInit(interp, start, numBytes, parsePtr); 01776 if (code == TCL_OK) { 01777 ConvertTreeToTokens(start, numBytes, 01778 opTree, exprParsePtr->tokenPtr, parsePtr); 01779 } else { 01780 parsePtr->term = exprParsePtr->term; 01781 parsePtr->errorType = exprParsePtr->errorType; 01782 } 01783 01784 Tcl_FreeParse(exprParsePtr); 01785 TclStackFree(interp, exprParsePtr); 01786 ckfree((char *) opTree); 01787 return code; 01788 } 01789 01790 /* 01791 *---------------------------------------------------------------------- 01792 * 01793 * ParseLexeme -- 01794 * 01795 * Parse a single lexeme from the start of a string, scanning no more 01796 * than numBytes bytes. 01797 * 01798 * Results: 01799 * Returns the number of bytes scanned to produce the lexeme. 01800 * 01801 * Side effects: 01802 * Code identifying lexeme parsed is writen to *lexemePtr. 01803 * 01804 *---------------------------------------------------------------------- 01805 */ 01806 01807 static int 01808 ParseLexeme( 01809 const char *start, /* Start of lexeme to parse. */ 01810 int numBytes, /* Number of bytes in string. */ 01811 unsigned char *lexemePtr, /* Write code of parsed lexeme to this 01812 * storage. */ 01813 Tcl_Obj **literalPtr) /* Write corresponding literal value to this 01814 storage, if non-NULL. */ 01815 { 01816 const char *end; 01817 int scanned; 01818 Tcl_UniChar ch; 01819 Tcl_Obj *literal = NULL; 01820 unsigned char byte; 01821 01822 if (numBytes == 0) { 01823 *lexemePtr = END; 01824 return 0; 01825 } 01826 byte = (unsigned char)(*start); 01827 if (byte < sizeof(Lexeme) && Lexeme[byte] != 0) { 01828 *lexemePtr = Lexeme[byte]; 01829 return 1; 01830 } 01831 switch (byte) { 01832 case '*': 01833 if ((numBytes > 1) && (start[1] == '*')) { 01834 *lexemePtr = EXPON; 01835 return 2; 01836 } 01837 *lexemePtr = MULT; 01838 return 1; 01839 01840 case '=': 01841 if ((numBytes > 1) && (start[1] == '=')) { 01842 *lexemePtr = EQUAL; 01843 return 2; 01844 } 01845 *lexemePtr = INCOMPLETE; 01846 return 1; 01847 01848 case '!': 01849 if ((numBytes > 1) && (start[1] == '=')) { 01850 *lexemePtr = NEQ; 01851 return 2; 01852 } 01853 *lexemePtr = NOT; 01854 return 1; 01855 01856 case '&': 01857 if ((numBytes > 1) && (start[1] == '&')) { 01858 *lexemePtr = AND; 01859 return 2; 01860 } 01861 *lexemePtr = BIT_AND; 01862 return 1; 01863 01864 case '|': 01865 if ((numBytes > 1) && (start[1] == '|')) { 01866 *lexemePtr = OR; 01867 return 2; 01868 } 01869 *lexemePtr = BIT_OR; 01870 return 1; 01871 01872 case '<': 01873 if (numBytes > 1) { 01874 switch (start[1]) { 01875 case '<': 01876 *lexemePtr = LEFT_SHIFT; 01877 return 2; 01878 case '=': 01879 *lexemePtr = LEQ; 01880 return 2; 01881 } 01882 } 01883 *lexemePtr = LESS; 01884 return 1; 01885 01886 case '>': 01887 if (numBytes > 1) { 01888 switch (start[1]) { 01889 case '>': 01890 *lexemePtr = RIGHT_SHIFT; 01891 return 2; 01892 case '=': 01893 *lexemePtr = GEQ; 01894 return 2; 01895 } 01896 } 01897 *lexemePtr = GREATER; 01898 return 1; 01899 01900 case 'i': 01901 if ((numBytes > 1) && (start[1] == 'n') 01902 && ((numBytes == 2) || !isalpha(UCHAR(start[2])))) { 01903 01904 /* 01905 * Must make this check so we can tell the difference between 01906 * the "in" operator and the "int" function name and the 01907 * "infinity" numeric value. 01908 */ 01909 01910 *lexemePtr = IN_LIST; 01911 return 2; 01912 } 01913 break; 01914 01915 case 'e': 01916 if ((numBytes > 1) && (start[1] == 'q') 01917 && ((numBytes == 2) || !isalpha(UCHAR(start[2])))) { 01918 *lexemePtr = STREQ; 01919 return 2; 01920 } 01921 break; 01922 01923 case 'n': 01924 if ((numBytes > 1) && ((numBytes == 2) || !isalpha(UCHAR(start[2])))) { 01925 switch (start[1]) { 01926 case 'e': 01927 *lexemePtr = STRNEQ; 01928 return 2; 01929 case 'i': 01930 *lexemePtr = NOT_IN_LIST; 01931 return 2; 01932 } 01933 } 01934 } 01935 01936 literal = Tcl_NewObj(); 01937 if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end, 01938 TCL_PARSE_NO_WHITESPACE) == TCL_OK) { 01939 TclInitStringRep(literal, start, end-start); 01940 *lexemePtr = NUMBER; 01941 if (literalPtr) { 01942 *literalPtr = literal; 01943 } else { 01944 Tcl_DecrRefCount(literal); 01945 } 01946 return (end-start); 01947 } 01948 01949 if (Tcl_UtfCharComplete(start, numBytes)) { 01950 scanned = Tcl_UtfToUniChar(start, &ch); 01951 } else { 01952 char utfBytes[TCL_UTF_MAX]; 01953 memcpy(utfBytes, start, (size_t) numBytes); 01954 utfBytes[numBytes] = '\0'; 01955 scanned = Tcl_UtfToUniChar(utfBytes, &ch); 01956 } 01957 if (!isalpha(UCHAR(ch))) { 01958 *lexemePtr = INVALID; 01959 Tcl_DecrRefCount(literal); 01960 return scanned; 01961 } 01962 end = start; 01963 while (isalnum(UCHAR(ch)) || (UCHAR(ch) == '_')) { 01964 end += scanned; 01965 numBytes -= scanned; 01966 if (Tcl_UtfCharComplete(end, numBytes)) { 01967 scanned = Tcl_UtfToUniChar(end, &ch); 01968 } else { 01969 char utfBytes[TCL_UTF_MAX]; 01970 memcpy(utfBytes, end, (size_t) numBytes); 01971 utfBytes[numBytes] = '\0'; 01972 scanned = Tcl_UtfToUniChar(utfBytes, &ch); 01973 } 01974 } 01975 *lexemePtr = BAREWORD; 01976 if (literalPtr) { 01977 Tcl_SetStringObj(literal, start, (int) (end-start)); 01978 *literalPtr = literal; 01979 } else { 01980 Tcl_DecrRefCount(literal); 01981 } 01982 return (end-start); 01983 } 01984 01985 /* 01986 *---------------------------------------------------------------------- 01987 * 01988 * TclCompileExpr -- 01989 * 01990 * This procedure compiles a string containing a Tcl expression into Tcl 01991 * bytecodes. 01992 * 01993 * Results: 01994 * None. 01995 * 01996 * Side effects: 01997 * Adds instructions to envPtr to evaluate the expression at runtime. 01998 * 01999 *---------------------------------------------------------------------- 02000 */ 02001 02002 void 02003 TclCompileExpr( 02004 Tcl_Interp *interp, /* Used for error reporting. */ 02005 const char *script, /* The source script to compile. */ 02006 int numBytes, /* Number of bytes in script. */ 02007 CompileEnv *envPtr, /* Holds resulting instructions. */ 02008 int optimize) /* 0 for one-off expressions */ 02009 { 02010 OpNode *opTree = NULL; /* Will point to the tree of operators */ 02011 Tcl_Obj *litList = Tcl_NewObj(); /* List to hold the literals */ 02012 Tcl_Obj *funcList = Tcl_NewObj(); /* List to hold the functon names*/ 02013 Tcl_Parse *parsePtr = 02014 (Tcl_Parse *) TclStackAlloc(interp, sizeof(Tcl_Parse)); 02015 /* Holds the Tcl_Tokens of substitutions */ 02016 02017 int code = ParseExpr(interp, script, numBytes, &opTree, litList, 02018 funcList, parsePtr, 0 /* parseOnly */); 02019 02020 if (code == TCL_OK) { 02021 02022 /* Valid parse; compile the tree. */ 02023 int objc; 02024 Tcl_Obj *const *litObjv; 02025 Tcl_Obj **funcObjv; 02026 02027 /* TIP #280 : Track Lines within the expression */ 02028 TclAdvanceLines(&envPtr->line, script, 02029 script + TclParseAllWhiteSpace(script, numBytes)); 02030 02031 TclListObjGetElements(NULL, litList, &objc, (Tcl_Obj ***)&litObjv); 02032 TclListObjGetElements(NULL, funcList, &objc, &funcObjv); 02033 CompileExprTree(interp, opTree, 0, &litObjv, funcObjv, 02034 parsePtr->tokenPtr, envPtr, optimize); 02035 } else { 02036 TclCompileSyntaxError(interp, envPtr); 02037 } 02038 02039 Tcl_FreeParse(parsePtr); 02040 TclStackFree(interp, parsePtr); 02041 Tcl_DecrRefCount(funcList); 02042 Tcl_DecrRefCount(litList); 02043 ckfree((char *) opTree); 02044 } 02045 02046 /* 02047 *---------------------------------------------------------------------- 02048 * 02049 * ExecConstantExprTree -- 02050 * Compiles and executes bytecode for the subexpression tree at index 02051 * in the nodes array. This subexpression must be constant, made up 02052 * of only constant operators (not functions) and literals. 02053 * 02054 * Results: 02055 * A standard Tcl return code and result left in interp. 02056 * 02057 * Side effects: 02058 * Consumes subtree of nodes rooted at index. Advances the pointer 02059 * *litObjvPtr. 02060 * 02061 *---------------------------------------------------------------------- 02062 */ 02063 02064 static int 02065 ExecConstantExprTree( 02066 Tcl_Interp *interp, 02067 OpNode *nodes, 02068 int index, 02069 Tcl_Obj *const **litObjvPtr) 02070 { 02071 CompileEnv *envPtr; 02072 ByteCode *byteCodePtr; 02073 int code; 02074 Tcl_Obj *byteCodeObj = Tcl_NewObj(); 02075 02076 /* 02077 * Note we are compiling an expression with literal arguments. This means 02078 * there can be no [info frame] calls when we execute the resulting 02079 * bytecode, so there's no need to tend to TIP 280 issues. 02080 */ 02081 02082 envPtr = (CompileEnv *) TclStackAlloc(interp, sizeof(CompileEnv)); 02083 TclInitCompileEnv(interp, envPtr, NULL, 0, NULL, 0); 02084 CompileExprTree(interp, nodes, index, litObjvPtr, NULL, NULL, envPtr, 02085 0 /* optimize */); 02086 TclEmitOpcode(INST_DONE, envPtr); 02087 Tcl_IncrRefCount(byteCodeObj); 02088 TclInitByteCodeObj(byteCodeObj, envPtr); 02089 TclFreeCompileEnv(envPtr); 02090 TclStackFree(interp, envPtr); 02091 byteCodePtr = (ByteCode *) byteCodeObj->internalRep.otherValuePtr; 02092 code = TclExecuteByteCode(interp, byteCodePtr); 02093 Tcl_DecrRefCount(byteCodeObj); 02094 return code; 02095 } 02096 02097 /* 02098 *---------------------------------------------------------------------- 02099 * 02100 * CompileExprTree -- 02101 * Compiles and writes to envPtr instructions for the subexpression 02102 * tree at index in the nodes array. (*litObjvPtr) must point to the 02103 * proper location in a corresponding literals list. Likewise, when 02104 * non-NULL, funcObjv and tokenPtr must point into matching arrays of 02105 * function names and Tcl_Token's derived from earlier call to 02106 * ParseExpr(). When optimize is true, any constant subexpressions 02107 * will be precomputed. 02108 * 02109 * Results: 02110 * None. 02111 * 02112 * Side effects: 02113 * Adds instructions to envPtr to evaluate the expression at runtime. 02114 * Consumes subtree of nodes rooted at index. Advances the pointer 02115 * *litObjvPtr. 02116 * 02117 *---------------------------------------------------------------------- 02118 */ 02119 02120 static void 02121 CompileExprTree( 02122 Tcl_Interp *interp, 02123 OpNode *nodes, 02124 int index, 02125 Tcl_Obj *const **litObjvPtr, 02126 Tcl_Obj *const *funcObjv, 02127 Tcl_Token *tokenPtr, 02128 CompileEnv *envPtr, 02129 int optimize) 02130 { 02131 OpNode *nodePtr = nodes + index; 02132 OpNode *rootPtr = nodePtr; 02133 int numWords = 0; 02134 JumpList *jumpPtr = NULL; 02135 int convert = 1; 02136 02137 while (1) { 02138 int next; 02139 JumpList *freePtr, *newJump; 02140 02141 if (nodePtr->mark == MARK_LEFT) { 02142 next = nodePtr->left; 02143 02144 switch (nodePtr->lexeme) { 02145 case QUESTION: 02146 newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); 02147 newJump->next = jumpPtr; 02148 jumpPtr = newJump; 02149 newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); 02150 newJump->next = jumpPtr; 02151 jumpPtr = newJump; 02152 jumpPtr->depth = envPtr->currStackDepth; 02153 convert = 1; 02154 break; 02155 case AND: 02156 case OR: 02157 newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); 02158 newJump->next = jumpPtr; 02159 jumpPtr = newJump; 02160 newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); 02161 newJump->next = jumpPtr; 02162 jumpPtr = newJump; 02163 newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); 02164 newJump->next = jumpPtr; 02165 jumpPtr = newJump; 02166 jumpPtr->depth = envPtr->currStackDepth; 02167 break; 02168 } 02169 } else if (nodePtr->mark == MARK_RIGHT) { 02170 next = nodePtr->right; 02171 02172 switch (nodePtr->lexeme) { 02173 case FUNCTION: { 02174 Tcl_DString cmdName; 02175 const char *p; 02176 int length; 02177 02178 Tcl_DStringInit(&cmdName); 02179 Tcl_DStringAppend(&cmdName, "tcl::mathfunc::", -1); 02180 p = TclGetStringFromObj(*funcObjv, &length); 02181 funcObjv++; 02182 Tcl_DStringAppend(&cmdName, p, length); 02183 TclEmitPush(TclRegisterNewNSLiteral(envPtr, 02184 Tcl_DStringValue(&cmdName), 02185 Tcl_DStringLength(&cmdName)), envPtr); 02186 Tcl_DStringFree(&cmdName); 02187 02188 /* 02189 * Start a count of the number of words in this function 02190 * command invocation. In case there's already a count 02191 * in progress (nested functions), save it in our unused 02192 * "left" field for restoring later. 02193 */ 02194 02195 nodePtr->left = numWords; 02196 numWords = 2; /* Command plus one argument */ 02197 break; 02198 } 02199 case QUESTION: 02200 TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &(jumpPtr->jump)); 02201 break; 02202 case COLON: 02203 TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, 02204 &(jumpPtr->next->jump)); 02205 envPtr->currStackDepth = jumpPtr->depth; 02206 jumpPtr->offset = (envPtr->codeNext - envPtr->codeStart); 02207 jumpPtr->convert = convert; 02208 convert = 1; 02209 break; 02210 case AND: 02211 TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &(jumpPtr->jump)); 02212 break; 02213 case OR: 02214 TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &(jumpPtr->jump)); 02215 break; 02216 } 02217 } else { 02218 switch (nodePtr->lexeme) { 02219 case START: 02220 case QUESTION: 02221 if (convert && (nodePtr == rootPtr)) { 02222 TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr); 02223 } 02224 break; 02225 case OPEN_PAREN: 02226 02227 /* do nothing */ 02228 break; 02229 case FUNCTION: 02230 02231 /* 02232 * Use the numWords count we've kept to invoke the 02233 * function command with the correct number of arguments. 02234 */ 02235 02236 if (numWords < 255) { 02237 TclEmitInstInt1(INST_INVOKE_STK1, numWords, envPtr); 02238 } else { 02239 TclEmitInstInt4(INST_INVOKE_STK4, numWords, envPtr); 02240 } 02241 02242 /* Restore any saved numWords value. */ 02243 numWords = nodePtr->left; 02244 convert = 1; 02245 break; 02246 case COMMA: 02247 02248 /* Each comma implies another function argument. */ 02249 numWords++; 02250 break; 02251 case COLON: 02252 if (TclFixupForwardJump(envPtr, &(jumpPtr->next->jump), 02253 (envPtr->codeNext - envPtr->codeStart) 02254 - jumpPtr->next->jump.codeOffset, 127)) { 02255 jumpPtr->offset += 3; 02256 } 02257 TclFixupForwardJump(envPtr, &(jumpPtr->jump), 02258 jumpPtr->offset - jumpPtr->jump.codeOffset, 127); 02259 convert |= jumpPtr->convert; 02260 envPtr->currStackDepth = jumpPtr->depth + 1; 02261 freePtr = jumpPtr; 02262 jumpPtr = jumpPtr->next; 02263 TclStackFree(interp, freePtr); 02264 freePtr = jumpPtr; 02265 jumpPtr = jumpPtr->next; 02266 TclStackFree(interp, freePtr); 02267 break; 02268 case AND: 02269 case OR: 02270 TclEmitForwardJump(envPtr, (nodePtr->lexeme == AND) 02271 ? TCL_FALSE_JUMP : TCL_TRUE_JUMP, 02272 &(jumpPtr->next->jump)); 02273 TclEmitPush(TclRegisterNewLiteral(envPtr, 02274 (nodePtr->lexeme == AND) ? "1" : "0", 1), envPtr); 02275 TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, 02276 &(jumpPtr->next->next->jump)); 02277 TclFixupForwardJumpToHere(envPtr, &(jumpPtr->next->jump), 127); 02278 if (TclFixupForwardJumpToHere(envPtr, &(jumpPtr->jump), 127)) { 02279 jumpPtr->next->next->jump.codeOffset += 3; 02280 } 02281 TclEmitPush(TclRegisterNewLiteral(envPtr, 02282 (nodePtr->lexeme == AND) ? "0" : "1", 1), envPtr); 02283 TclFixupForwardJumpToHere(envPtr, &(jumpPtr->next->next->jump), 02284 127); 02285 convert = 0; 02286 envPtr->currStackDepth = jumpPtr->depth + 1; 02287 freePtr = jumpPtr; 02288 jumpPtr = jumpPtr->next; 02289 TclStackFree(interp, freePtr); 02290 freePtr = jumpPtr; 02291 jumpPtr = jumpPtr->next; 02292 TclStackFree(interp, freePtr); 02293 freePtr = jumpPtr; 02294 jumpPtr = jumpPtr->next; 02295 TclStackFree(interp, freePtr); 02296 break; 02297 default: 02298 TclEmitOpcode(instruction[nodePtr->lexeme], envPtr); 02299 convert = 0; 02300 break; 02301 } 02302 if (nodePtr == rootPtr) { 02303 02304 /* We're done */ 02305 return; 02306 } 02307 nodePtr = nodes + nodePtr->p.parent; 02308 continue; 02309 } 02310 02311 nodePtr->mark++; 02312 switch (next) { 02313 case OT_EMPTY: 02314 numWords = 1; /* No arguments, so just the command */ 02315 break; 02316 case OT_LITERAL: { 02317 Tcl_Obj *const *litObjv = *litObjvPtr; 02318 Tcl_Obj *literal = *litObjv; 02319 02320 if (optimize) { 02321 int length, index; 02322 const char *bytes = TclGetStringFromObj(literal, &length); 02323 LiteralEntry *lePtr; 02324 Tcl_Obj *objPtr; 02325 02326 index = TclRegisterNewLiteral(envPtr, bytes, length); 02327 lePtr = envPtr->literalArrayPtr + index; 02328 objPtr = lePtr->objPtr; 02329 if ((objPtr->typePtr == NULL) && (literal->typePtr != NULL)) { 02330 /* 02331 * Would like to do this: 02332 * 02333 * lePtr->objPtr = literal; 02334 * Tcl_IncrRefCount(literal); 02335 * Tcl_DecrRefCount(objPtr); 02336 * 02337 * However, the design of the "global" and "local" 02338 * LiteralTable does not permit the value of lePtr->objPtr 02339 * to change. So rather than replace lePtr->objPtr, we 02340 * do surgery to transfer our desired intrep into it. 02341 * 02342 */ 02343 objPtr->typePtr = literal->typePtr; 02344 objPtr->internalRep = literal->internalRep; 02345 literal->typePtr = NULL; 02346 } 02347 TclEmitPush(index, envPtr); 02348 } else { 02349 /* 02350 * When optimize==0, we know the expression is a one-off 02351 * and there's nothing to be gained from sharing literals 02352 * when they won't live long, and the copies we have already 02353 * have an appropriate intrep. In this case, skip literal 02354 * registration that would enable sharing, and use the routine 02355 * that preserves intreps. 02356 */ 02357 TclEmitPush(TclAddLiteralObj(envPtr, literal, NULL), envPtr); 02358 } 02359 (*litObjvPtr)++; 02360 break; 02361 } 02362 case OT_TOKENS: 02363 TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, 02364 envPtr); 02365 tokenPtr += tokenPtr->numComponents + 1; 02366 break; 02367 default: 02368 if (optimize && nodes[next].constant) { 02369 Tcl_InterpState save = Tcl_SaveInterpState(interp, TCL_OK); 02370 if (ExecConstantExprTree(interp, nodes, next, litObjvPtr) 02371 == TCL_OK) { 02372 TclEmitPush(TclAddLiteralObj(envPtr, 02373 Tcl_GetObjResult(interp), NULL), envPtr); 02374 } else { 02375 TclCompileSyntaxError(interp, envPtr); 02376 } 02377 Tcl_RestoreInterpState(interp, save); 02378 convert = 0; 02379 } else { 02380 nodePtr = nodes + next; 02381 } 02382 } 02383 } 02384 } 02385 02386 /* 02387 *---------------------------------------------------------------------- 02388 * 02389 * TclSingleOpCmd -- 02390 * Implements the commands: ~, !, <<, >>, %, !=, ne, in, ni 02391 * in the ::tcl::mathop namespace. These commands have no 02392 * extension to arbitrary arguments; they accept only exactly one 02393 * or exactly two arguments as suitable for the operator. 02394 * 02395 * Results: 02396 * A standard Tcl return code and result left in interp. 02397 * 02398 * Side effects: 02399 * None. 02400 * 02401 *---------------------------------------------------------------------- 02402 */ 02403 02404 int 02405 TclSingleOpCmd( 02406 ClientData clientData, 02407 Tcl_Interp *interp, 02408 int objc, 02409 Tcl_Obj *const objv[]) 02410 { 02411 TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; 02412 unsigned char lexeme; 02413 OpNode nodes[2]; 02414 Tcl_Obj *const *litObjv = objv + 1; 02415 02416 if (objc != 1+occdPtr->i.numArgs) { 02417 Tcl_WrongNumArgs(interp, 1, objv, occdPtr->expected); 02418 return TCL_ERROR; 02419 } 02420 02421 ParseLexeme(occdPtr->op, strlen(occdPtr->op), &lexeme, NULL); 02422 nodes[0].lexeme = START; 02423 nodes[0].mark = MARK_RIGHT; 02424 nodes[0].right = 1; 02425 nodes[1].lexeme = lexeme; 02426 if (objc == 2) { 02427 nodes[1].mark = MARK_RIGHT; 02428 } else { 02429 nodes[1].mark = MARK_LEFT; 02430 nodes[1].left = OT_LITERAL; 02431 } 02432 nodes[1].right = OT_LITERAL; 02433 nodes[1].p.parent = 0; 02434 02435 return ExecConstantExprTree(interp, nodes, 0, &litObjv); 02436 } 02437 02438 /* 02439 *---------------------------------------------------------------------- 02440 * 02441 * TclSortingOpCmd -- 02442 * Implements the commands: <, <=, >, >=, ==, eq 02443 * in the ::tcl::mathop namespace. These commands are defined for 02444 * arbitrary number of arguments by computing the AND of the base 02445 * operator applied to all neighbor argument pairs. 02446 * 02447 * Results: 02448 * A standard Tcl return code and result left in interp. 02449 * 02450 * Side effects: 02451 * None. 02452 * 02453 *---------------------------------------------------------------------- 02454 */ 02455 02456 int 02457 TclSortingOpCmd( 02458 ClientData clientData, 02459 Tcl_Interp *interp, 02460 int objc, 02461 Tcl_Obj *const objv[]) 02462 { 02463 int code = TCL_OK; 02464 02465 if (objc < 3) { 02466 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); 02467 } else { 02468 TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; 02469 Tcl_Obj **litObjv = (Tcl_Obj **) TclStackAlloc(interp, 02470 2*(objc-2)*sizeof(Tcl_Obj *)); 02471 OpNode *nodes = (OpNode *) TclStackAlloc(interp, 02472 2*(objc-2)*sizeof(OpNode)); 02473 unsigned char lexeme; 02474 int i, lastAnd = 1; 02475 Tcl_Obj *const *litObjPtrPtr = litObjv; 02476 02477 ParseLexeme(occdPtr->op, strlen(occdPtr->op), &lexeme, NULL); 02478 02479 litObjv[0] = objv[1]; 02480 nodes[0].lexeme = START; 02481 nodes[0].mark = MARK_RIGHT; 02482 for (i=2; i<objc-1; i++) { 02483 litObjv[2*(i-1)-1] = objv[i]; 02484 nodes[2*(i-1)-1].lexeme = lexeme; 02485 nodes[2*(i-1)-1].mark = MARK_LEFT; 02486 nodes[2*(i-1)-1].left = OT_LITERAL; 02487 nodes[2*(i-1)-1].right = OT_LITERAL; 02488 02489 litObjv[2*(i-1)] = objv[i]; 02490 nodes[2*(i-1)].lexeme = AND; 02491 nodes[2*(i-1)].mark = MARK_LEFT; 02492 nodes[2*(i-1)].left = lastAnd; 02493 nodes[lastAnd].p.parent = 2*(i-1); 02494 02495 nodes[2*(i-1)].right = 2*(i-1)+1; 02496 nodes[2*(i-1)+1].p.parent= 2*(i-1); 02497 02498 lastAnd = 2*(i-1); 02499 } 02500 litObjv[2*(objc-2)-1] = objv[objc-1]; 02501 02502 nodes[2*(objc-2)-1].lexeme = lexeme; 02503 nodes[2*(objc-2)-1].mark = MARK_LEFT; 02504 nodes[2*(objc-2)-1].left = OT_LITERAL; 02505 nodes[2*(objc-2)-1].right = OT_LITERAL; 02506 02507 nodes[0].right = lastAnd; 02508 nodes[lastAnd].p.parent = 0; 02509 02510 code = ExecConstantExprTree(interp, nodes, 0, &litObjPtrPtr); 02511 02512 TclStackFree(interp, nodes); 02513 TclStackFree(interp, litObjv); 02514 } 02515 return code; 02516 } 02517 02518 /* 02519 *---------------------------------------------------------------------- 02520 * 02521 * TclVariadicOpCmd -- 02522 * Implements the commands: +, *, &, |, ^, ** 02523 * in the ::tcl::mathop namespace. These commands are defined for 02524 * arbitrary number of arguments by repeatedly applying the base 02525 * operator with suitable associative rules. When fewer than two 02526 * arguments are provided, suitable identity values are returned. 02527 * 02528 * Results: 02529 * A standard Tcl return code and result left in interp. 02530 * 02531 * Side effects: 02532 * None. 02533 * 02534 *---------------------------------------------------------------------- 02535 */ 02536 02537 int 02538 TclVariadicOpCmd( 02539 ClientData clientData, 02540 Tcl_Interp *interp, 02541 int objc, 02542 Tcl_Obj *const objv[]) 02543 { 02544 TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; 02545 unsigned char lexeme; 02546 int code; 02547 02548 if (objc < 2) { 02549 Tcl_SetObjResult(interp, Tcl_NewIntObj(occdPtr->i.identity)); 02550 return TCL_OK; 02551 } 02552 02553 ParseLexeme(occdPtr->op, strlen(occdPtr->op), &lexeme, NULL); 02554 lexeme |= BINARY; 02555 02556 if (objc == 2) { 02557 Tcl_Obj *litObjv[2]; 02558 OpNode nodes[2]; 02559 int decrMe = 0; 02560 Tcl_Obj *const *litObjPtrPtr = litObjv; 02561 02562 if (lexeme == EXPON) { 02563 litObjv[1] = Tcl_NewIntObj(occdPtr->i.identity); 02564 Tcl_IncrRefCount(litObjv[1]); 02565 decrMe = 1; 02566 litObjv[0] = objv[1]; 02567 nodes[0].lexeme = START; 02568 nodes[0].mark = MARK_RIGHT; 02569 nodes[0].right = 1; 02570 nodes[1].lexeme = lexeme; 02571 nodes[1].mark = MARK_LEFT; 02572 nodes[1].left = OT_LITERAL; 02573 nodes[1].right = OT_LITERAL; 02574 nodes[1].p.parent = 0; 02575 } else { 02576 if (lexeme == DIVIDE) { 02577 litObjv[0] = Tcl_NewDoubleObj(1.0); 02578 } else { 02579 litObjv[0] = Tcl_NewIntObj(occdPtr->i.identity); 02580 } 02581 Tcl_IncrRefCount(litObjv[0]); 02582 litObjv[1] = objv[1]; 02583 nodes[0].lexeme = START; 02584 nodes[0].mark = MARK_RIGHT; 02585 nodes[0].right = 1; 02586 nodes[1].lexeme = lexeme; 02587 nodes[1].mark = MARK_LEFT; 02588 nodes[1].left = OT_LITERAL; 02589 nodes[1].right = OT_LITERAL; 02590 nodes[1].p.parent = 0; 02591 } 02592 02593 code = ExecConstantExprTree(interp, nodes, 0, &litObjPtrPtr); 02594 02595 Tcl_DecrRefCount(litObjv[decrMe]); 02596 return code; 02597 } else { 02598 Tcl_Obj *const *litObjv = objv + 1; 02599 OpNode *nodes = (OpNode *) TclStackAlloc(interp, 02600 (objc-1)*sizeof(OpNode)); 02601 int i, lastOp = OT_LITERAL; 02602 02603 nodes[0].lexeme = START; 02604 nodes[0].mark = MARK_RIGHT; 02605 if (lexeme == EXPON) { 02606 for (i=objc-2; i>0; i-- ) { 02607 nodes[i].lexeme = lexeme; 02608 nodes[i].mark = MARK_LEFT; 02609 nodes[i].left = OT_LITERAL; 02610 nodes[i].right = lastOp; 02611 if (lastOp >= 0) { 02612 nodes[lastOp].p.parent = i; 02613 } 02614 lastOp = i; 02615 } 02616 } else { 02617 for (i=1; i<objc-1; i++ ) { 02618 nodes[i].lexeme = lexeme; 02619 nodes[i].mark = MARK_LEFT; 02620 nodes[i].left = lastOp; 02621 if (lastOp >= 0) { 02622 nodes[lastOp].p.parent = i; 02623 } 02624 nodes[i].right = OT_LITERAL; 02625 lastOp = i; 02626 } 02627 } 02628 nodes[0].right = lastOp; 02629 nodes[lastOp].p.parent = 0; 02630 02631 code = ExecConstantExprTree(interp, nodes, 0, &litObjv); 02632 02633 TclStackFree(interp, nodes); 02634 02635 return code; 02636 } 02637 } 02638 02639 /* 02640 *---------------------------------------------------------------------- 02641 * 02642 * TclNoIdentOpCmd -- 02643 * Implements the commands: -, / 02644 * in the ::tcl::mathop namespace. These commands are defined for 02645 * arbitrary non-zero number of arguments by repeatedly applying 02646 * the base operator with suitable associative rules. When no 02647 * arguments are provided, an error is raised. 02648 * 02649 * Results: 02650 * A standard Tcl return code and result left in interp. 02651 * 02652 * Side effects: 02653 * None. 02654 * 02655 *---------------------------------------------------------------------- 02656 */ 02657 02658 int 02659 TclNoIdentOpCmd( 02660 ClientData clientData, 02661 Tcl_Interp *interp, 02662 int objc, 02663 Tcl_Obj *const objv[]) 02664 { 02665 TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; 02666 if (objc < 2) { 02667 Tcl_WrongNumArgs(interp, 1, objv, occdPtr->expected); 02668 return TCL_ERROR; 02669 } 02670 return TclVariadicOpCmd(clientData, interp, objc, objv); 02671 } 02672 /* 02673 * Local Variables: 02674 * mode: c 02675 * c-basic-offset: 4 02676 * fill-column: 78 02677 * End: 02678 */
Generated on Wed Mar 12 12:18:13 2008 by 1.5.1 |