diff options
Diffstat (limited to 'generic/tclCompExpr.c')
-rw-r--r-- | generic/tclCompExpr.c | 1353 |
1 files changed, 624 insertions, 729 deletions
diff --git a/generic/tclCompExpr.c b/generic/tclCompExpr.c index 50edbec..abb917f 100644 --- a/generic/tclCompExpr.c +++ b/generic/tclCompExpr.c @@ -1,8 +1,8 @@ /* * tclCompExpr.c -- * - * This file contains the code to parse and compile Tcl expressions and - * implementations of the Tcl commands corresponding to expression + * This file contains the code to parse and compile Tcl expressions + * and implementations of the Tcl commands corresponding to expression * operators, such as the command ::tcl::mathop::+ . * * Contributions from Don Porter, NIST, 2006-2007. (not subject to US copyright) @@ -15,11 +15,11 @@ #include "tclCompile.h" /* CompileEnv */ /* - * Expression parsing takes place in the routine ParseExpr(). It takes a - * string as input, parses that string, and generates a representation of the - * expression in the form of a tree of operators, a list of literals, a list - * of function names, and an array of Tcl_Token's within a Tcl_Parse struct. - * The tree is composed of OpNodes. + * Expression parsing takes place in the routine ParseExpr(). It takes a + * string as input, parses that string, and generates a representation of + * the expression in the form of a tree of operators, a list of literals, + * a list of function names, and an array of Tcl_Token's within a Tcl_Parse + * struct. The tree is composed of OpNodes. */ typedef struct OpNode { @@ -36,36 +36,36 @@ typedef struct OpNode { } OpNode; /* - * The storage for the tree is dynamically allocated array of OpNodes. The + * The storage for the tree is dynamically allocated array of OpNodes. The * array is grown as parsing needs dictate according to a scheme similar to * Tcl's string growth algorithm, so that the resizing costs are O(N) and so * that we use at least half the memory allocated as expressions get large. * * Each OpNode in the tree represents an operator in the expression, either - * unary or binary. When parsing is completed successfully, a binary operator + * unary or binary. When parsing is completed successfully, a binary operator * OpNode will have its left and right fields filled with "pointers" to its - * left and right operands. A unary operator OpNode will have its right field - * filled with a pointer to its single operand. When an operand is a + * left and right operands. A unary operator OpNode will have its right field + * filled with a pointer to its single operand. When an operand is a * subexpression the "pointer" takes the form of the index -- a non-negative * integer -- into the OpNode storage array where the root of that * subexpression parse tree is found. * * Non-operator elements of the expression do not get stored in the OpNode - * tree. They are stored in the other structures according to their type. - * Literal values get appended to the literal list. Elements that denote forms - * of quoting or substitution known to the Tcl parser get stored as - * Tcl_Tokens. These non-operator elements of the expression are the leaves of - * the completed parse tree. When an operand of an OpNode is one of these leaf - * elements, the following negative integer codes are used to indicate which - * kind of elements it is. + * tree. They are stored in the other structures according to their type. + * Literal values get appended to the literal list. Elements that denote + * forms of quoting or substitution known to the Tcl parser get stored as + * Tcl_Tokens. These non-operator elements of the expression are the + * leaves of the completed parse tree. When an operand of an OpNode is + * one of these leaf elements, the following negative integer codes are used + * to indicate which kind of elements it is. */ enum OperandTypes { OT_LITERAL = -3, /* Operand is a literal in the literal list */ OT_TOKENS = -2, /* Operand is sequence of Tcl_Tokens */ - OT_EMPTY = -1 /* "Operand" is an empty string. This is a special - * case used only to represent the EMPTY lexeme. See - * below. */ + OT_EMPTY = -1 /* "Operand" is an empty string. This is a + * special case used only to represent the + * EMPTY lexeme. See below. */ }; /* @@ -79,30 +79,31 @@ enum OperandTypes { /* * Note that it is sufficient to store in the tree just the type of leaf - * operand, without any explicit pointer to which leaf. This is true because - * the traversals of the completed tree we perform are known to visit the - * leaves in the same order as the original parse. + * operand, without any explicit pointer to which leaf. This is true because + * the traversals of the completed tree we perform are known to visit + * the leaves in the same order as the original parse. * * In a completed parse tree, those OpNodes that are themselves (roots of * subexpression trees that are) operands of some operator store in their - * p.parent field a "pointer" to the OpNode of that operator. The p.parent - * field permits a traversal of the tree within a non-recursive routine - * (ConvertTreeToTokens() and CompileExprTree()). This means that even + * p.parent field a "pointer" to the OpNode of that operator. The p.parent + * field permits a traversal of the tree within a * non-recursive routine + * (ConvertTreeToTokens() and CompileExprTree()). This means that even * expression trees of great depth pose no risk of blowing the C stack. * - * While the parse tree is being constructed, the same memory space is used to - * hold the p.prev field which chains together a stack of incomplete trees - * awaiting their right operands. + * While the parse tree is being constructed, the same memory space is used + * to hold the p.prev field which chains together a stack of incomplete + * trees awaiting their right operands. * * The lexeme field is filled in with the lexeme of the operator that is - * returned by the ParseLexeme() routine. Only lexemes for unary and binary - * operators get stored in an OpNode. Other lexmes get different treatement. + * returned by the ParseLexeme() routine. Only lexemes for unary and + * binary operators get stored in an OpNode. Other lexmes get different + * treatement. * * The precedence field provides a place to store the precedence of the * operator, so it need not be looked up again and again. * - * The mark field is use to control the traversal of the tree, so that it can - * be done non-recursively. The mark values are: + * The mark field is use to control the traversal of the tree, so + * that it can be done non-recursively. The mark values are: */ enum Marks { @@ -118,184 +119,185 @@ enum Marks { */ /* - * 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. + * 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. + * 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. */ -#define 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 +#define 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 * 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 - * tree. No OpNode will be placed in the tree - * for it. Either a literal value will be + * 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. */ + * form of substitution. + */ /* Uncategorized lexemes */ -#define PLUS 1 /* Ambiguous. Resolves to UNARY_PLUS or +#define PLUS 1 /* Ambiguous. Resolves to UNARY_PLUS or * BINARY_PLUS according to context. */ -#define MINUS 2 /* Ambiguous. Resolves to UNARY_MINUS or +#define MINUS 2 /* Ambiguous. Resolves to UNARY_MINUS or * BINARY_MINUS according to context. */ -#define BAREWORD 3 /* Ambigous. Resolves to BOOLEAN or to +#define BAREWORD 3 /* Ambigous. Resolves to BOOLEAN or to * FUNCTION or a parse error according to * context and value. */ -#define INCOMPLETE 4 /* A parse error. Used only when the single +#define INCOMPLETE 4 /* A parse error. Used only when the single * "=" is encountered. */ -#define INVALID 5 /* A parse error. Used when any punctuation +#define INVALID 5 /* A parse error. Used when any punctuation * appears that's not a supported operator. */ /* Leaf lexemes */ -#define NUMBER (LEAF | 1) - /* For literal numbers */ -#define SCRIPT (LEAF | 2) - /* Script substitution; [foo] */ -#define BOOLEAN (LEAF | BAREWORD) - /* For literal booleans */ -#define BRACED (LEAF | 4) - /* Braced string; {foo bar} */ -#define VARIABLE (LEAF | 5) - /* Variable substitution; $x */ -#define QUOTED (LEAF | 6) - /* Quoted string; "foo $bar [soom]" */ -#define EMPTY (LEAF | 7) - /* Used only for an empty argument list to a - * function. Represents the empty string - * within parens in the expression: rand() */ +#define NUMBER ( LEAF | 1) /* For literal numbers */ +#define SCRIPT ( LEAF | 2) /* Script substitution; [foo] */ +#define BOOLEAN ( LEAF | BAREWORD) /* For literal booleans */ +#define BRACED ( LEAF | 4) /* Braced string; {foo bar} */ +#define VARIABLE ( LEAF | 5) /* Variable substitution; $x */ +#define QUOTED ( LEAF | 6) /* Quoted string; "foo $bar [soom]" */ +#define EMPTY ( LEAF | 7) /* Used only for an empty argument + * list to a function. Represents + * the empty string within parens in + * the expression: rand() */ /* Unary operator lexemes */ -#define UNARY_PLUS (UNARY | PLUS) -#define UNARY_MINUS (UNARY | MINUS) -#define 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 - * 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, - * 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) +#define UNARY_PLUS ( UNARY | PLUS) +#define UNARY_MINUS ( UNARY | MINUS) +#define 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 + * 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, 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) /* Binary operator lexemes */ -#define BINARY_PLUS (BINARY | PLUS) -#define BINARY_MINUS (BINARY | MINUS) -#define 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) -#define BIT_OR (BINARY | 11) -#define QUESTION (BINARY | 12) - /* These two lexemes make up the */ -#define 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) -#define 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) -#define 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 END (BINARY | 28) - /* 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. */ - +#define BINARY_PLUS ( BINARY | PLUS) +#define BINARY_MINUS ( BINARY | MINUS) +#define 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) +#define BIT_OR ( BINARY | 11) +#define QUESTION ( BINARY | 12) /* These two lexemes make up the */ +#define 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) +#define 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) +#define 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 END ( BINARY | 28) /* 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 - * precedence level is commented with the operators that hold that 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 precedence level is commented with the operators that hold that + * precedence. */ enum Precedence { @@ -320,9 +322,9 @@ enum Precedence { }; /* - * Here the same information contained in the comments above is stored in - * inverted form, so that given a lexeme, one can quickly look up its - * precedence value. + * Here the same information contained in the comments above is stored + * in inverted form, so that given a lexeme, one can quickly look up + * its precedence value. */ static const unsigned char prec[] = { @@ -453,7 +455,7 @@ static const unsigned char Lexeme[] = { INVALID /* SUB */, INVALID /* ESC */, INVALID /* FS */, INVALID /* GS */, INVALID /* RS */, INVALID /* US */, - INVALID /* SPACE */, 0 /* ! or != */, + INVALID /* SPACE */, 0 /* ! or != */, QUOTED /* " */, INVALID /* # */, VARIABLE /* $ */, MOD /* % */, 0 /* & or && */, INVALID /* ' */, @@ -490,6 +492,13 @@ typedef struct JumpList { JumpFixup jump; /* Pass this argument to matching calls of * TclEmitForwardJump() and * TclFixupForwardJump(). */ + int depth; /* Remember the currStackDepth of the + * CompileEnv here. */ + int offset; /* Data used to compute jump lengths to pass + * to TclFixupForwardJump() */ + int convert; /* Temporary storage used to compute whether + * numeric conversion will be needed following + * the operator we're compiling. */ struct JumpList *next; /* Point to next item on the stack */ } JumpList; @@ -512,6 +521,7 @@ static int ParseExpr(Tcl_Interp *interp, const char *start, Tcl_Parse *parsePtr, int parseOnly); static int ParseLexeme(const char *start, int numBytes, unsigned char *lexemePtr, Tcl_Obj **literalPtr); + /* *---------------------------------------------------------------------- @@ -519,27 +529,27 @@ static int ParseLexeme(const char *start, int numBytes, * ParseExpr -- * * Given a string, the numBytes bytes starting at start, this function - * parses it as a Tcl expression and constructs a tree representing the - * structure of the expression. The caller must pass in empty lists as - * the funcList and litList arguments. The elements of the parsed - * expression are returned to the caller as that tree, a list of literal - * values, a list of function names, and in Tcl_Tokens added to a - * Tcl_Parse struct passed in by the caller. + * parses it as a Tcl expression and constructs a tree representing + * the structure of the expression. The caller must pass in empty + * lists as the funcList and litList arguments. The elements of the + * parsed expression are returned to the caller as that tree, a list of + * literal values, a list of function names, and in Tcl_Tokens + * added to a Tcl_Parse struct passed in by the caller. * * Results: * If the string is successfully parsed as a valid Tcl expression, TCL_OK - * is returned, and data about the expression structure is written to the - * last four arguments. If the string cannot be parsed as a valid Tcl - * expression, TCL_ERROR is returned, and if interp is non-NULL, an error - * message is written to interp. + * is returned, and data about the expression structure is written to + * the last four arguments. If the string cannot be parsed as a valid + * Tcl expression, TCL_ERROR is returned, and if interp is non-NULL, an + * error message is written to interp. * * Side effects: - * Memory will be allocated. If TCL_OK is returned, the caller must clean - * up the returned data structures. The (OpNode *) value written to - * opTreePtr should be passed to ckfree() and the parsePtr argument - * should be passed to Tcl_FreeParse(). The elements appended to the - * litList and funcList will automatically be freed whenever the refcount - * on those lists indicates they can be freed. + * Memory will be allocated. If TCL_OK is returned, the caller must + * clean up the returned data structures. The (OpNode *) value written + * to opTreePtr should be passed to ckfree() and the parsePtr argument + * should be passed to Tcl_FreeParse(). The elements appended to the + * litList and funcList will automatically be freed whenever the + * refcount on those lists indicates they can be freed. * *---------------------------------------------------------------------- */ @@ -558,82 +568,68 @@ ParseExpr( * substitutions. */ int parseOnly) /* A boolean indicating whether the caller's * aim is just a parse, or whether it will go - * on to compile the expression. Different - * optimizations are appropriate for the two - * scenarios. */ + * on to compile the expression. Different + * optimizations are appropriate for the + * two scenarios. */ { OpNode *nodes = NULL; /* Pointer to the OpNode storage array where * we build the parse tree. */ - int nodesAvailable = 64; /* Initial size of the storage array. This - * value establishes a minimum tree memory - * cost of only about 1 kibyte, and is large - * enough for most expressions to parse with - * no need for array growth and - * reallocation. */ + int nodesAvailable = 64; /* Initial size of the storage array. This + * value establishes a minimum tree memory cost + * of only about 1 kibyte, and is large enough + * for most expressions to parse with no need + * for array growth and reallocation. */ int nodesUsed = 0; /* Number of OpNodes filled. */ - int scanned = 0; /* Capture number of byte scanned by parsing - * routines. */ + int scanned = 0; /* Capture number of byte scanned by + * parsing routines. */ int lastParsed; /* Stores info about what the lexeme parsed * the previous pass through the parsing loop - * was. If it was an operator, lastParsed is + * was. If it was an operator, lastParsed is * the index of the OpNode for that operator. * If it was not an operator, lastParsed holds - * an OperandTypes value encoding what we need - * to know about it. */ - int incomplete; /* Index of the most recent incomplete tree in - * the OpNode array. Heads a stack of + * an OperandTypes value encoding what we + * need to know about it. */ + int incomplete; /* Index of the most recent incomplete tree + * in the OpNode array. Heads a stack of * incomplete trees linked by p.prev. */ int complete = OT_EMPTY; /* "Index" of the complete tree (that is, a * complete subexpression) determined at the - * moment. OT_EMPTY is a nonsense value used - * only to silence compiler warnings. During a - * parse, complete will always hold an index - * or an OperandTypes value pointing to an - * actual leaf at the time the complete tree - * is needed. */ - - /* - * These variables control generation of the error message. - */ - + * moment. OT_EMPTY is a nonsense value + * used only to silence compiler warnings. + * During a parse, complete will always hold + * an index or an OperandTypes value pointing + * to an actual leaf at the time the complete + * tree is needed. */ + + /* These variables control generation of the error message. */ Tcl_Obj *msg = NULL; /* The error message. */ Tcl_Obj *post = NULL; /* In a few cases, an additional postscript * for the error message, supplying more * information after the error msg and * location have been reported. */ - const char *errCode = NULL; /* The detail word of the errorCode list, or - * NULL to indicate that no changes to the - * errorCode are to be done. */ - const char *subErrCode = NULL; - /* Extra information for use in generating the - * errorCode. */ - const char *mark = "_@_"; /* In the portion of the complete error - * message where the error location is - * reported, this "mark" substring is inserted - * into the string being parsed to aid in - * pinpointing the location of the syntax - * error in the expression. */ + const char *mark = "_@_"; /* In the portion of the complete error message + * where the error location is reported, this + * "mark" substring is inserted into the + * string being parsed to aid in pinpointing + * the location of the syntax error in the + * expression. */ int insertMark = 0; /* A boolean controlling whether the "mark" * should be inserted. */ const int limit = 25; /* Portions of the error message are * constructed out of substrings of the - * original expression. In order to keep the - * error message readable, we impose this - * limit on the substring size we extract. */ + * original expression. In order to keep the + * error message readable, we impose this limit + * on the substring size we extract. */ TclParseInit(interp, start, numBytes, parsePtr); - nodes = attemptckalloc(nodesAvailable * sizeof(OpNode)); + nodes = (OpNode *) attemptckalloc(nodesAvailable * sizeof(OpNode)); if (nodes == NULL) { TclNewLiteralStringObj(msg, "not enough memory to parse expression"); - errCode = "NOMEM"; goto error; } - /* - * Initialize the parse tree with the special "START" node. - */ - + /* Initialize the parse tree with the special "START" node. */ nodes->lexeme = START; nodes->precedence = prec[START]; nodes->mark = MARK_RIGHT; @@ -642,19 +638,19 @@ ParseExpr( nodesUsed++; /* - * Main parsing loop parses one lexeme per iteration. We exit the loop - * only when there's a syntax error with a "goto error" which takes us to - * the error handling code following the loop, or when we've successfully - * completed the parse and we return to the caller. + * Main parsing loop parses one lexeme per iteration. We exit the + * loop only when there's a syntax error with a "goto error" which + * takes us to the error handling code following the loop, or when + * we've successfully completed the parse and we return to the caller. */ while (1) { - OpNode *nodePtr; /* Points to the OpNode we may fill this pass - * through the loop. */ + OpNode *nodePtr; /* Points to the OpNode we may fill this + * pass through the loop. */ unsigned char lexeme; /* The lexeme we parse this iteration. */ - Tcl_Obj *literal; /* Filled by the ParseLexeme() call when a - * literal is parsed that has a Tcl_Obj rep - * worth preserving. */ + Tcl_Obj *literal; /* Filled by the ParseLexeme() call when + * a literal is parsed that has a Tcl_Obj + * rep worth preserving. */ /* * Each pass through this loop adds up to one more OpNode. Allocate @@ -667,14 +663,14 @@ ParseExpr( do { if (size <= UINT_MAX/sizeof(OpNode)) { - newPtr = attemptckrealloc(nodes, size * sizeof(OpNode)); + newPtr = (OpNode *) attemptckrealloc((char *) nodes, + (unsigned int) size * sizeof(OpNode)); } } while ((newPtr == NULL) && ((size -= (size - nodesUsed) / 2) > nodesUsed)); if (newPtr == NULL) { TclNewLiteralStringObj(msg, "not enough memory to parse expression"); - errCode = "NOMEM"; goto error; } nodesAvailable = size; @@ -682,41 +678,32 @@ ParseExpr( } nodePtr = nodes + nodesUsed; - /* - * Skip white space between lexemes. - */ - + /* Skip white space between lexemes. */ scanned = TclParseAllWhiteSpace(start, numBytes); start += scanned; numBytes -= scanned; scanned = ParseLexeme(start, numBytes, &lexeme, &literal); - /* - * Use context to categorize the lexemes that are ambiguous. - */ - + /* Use context to categorize the lexemes that are ambiguous. */ if ((NODE_TYPE & lexeme) == 0) { - int b; - switch (lexeme) { case INVALID: - msg = Tcl_ObjPrintf("invalid character \"%.*s\"", - scanned, start); - errCode = "BADCHAR"; + msg = Tcl_ObjPrintf( + "invalid character \"%.*s\"", scanned, start); goto error; case INCOMPLETE: - msg = Tcl_ObjPrintf("incomplete operator \"%.*s\"", - scanned, start); - errCode = "PARTOP"; + msg = Tcl_ObjPrintf( + "incomplete operator \"%.*s\"", scanned, start); goto error; case BAREWORD: /* - * Most barewords in an expression are a syntax error. The - * exceptions are that when a bareword is followed by an open - * paren, it might be a function call, and when the bareword - * is a legal literal boolean value, we accept that as well. + * Most barewords in an expression are a syntax error. + * The exceptions are that when a bareword is followed by + * an open paren, it might be a function call, and when the + * bareword is a legal literal boolean value, we accept that + * as well. */ if (start[scanned+TclParseAllWhiteSpace( @@ -731,65 +718,63 @@ ParseExpr( */ Tcl_ListObjAppendElement(NULL, funcList, literal); - } else if (Tcl_GetBooleanFromObj(NULL,literal,&b) == TCL_OK) { - lexeme = BOOLEAN; } else { - Tcl_DecrRefCount(literal); - msg = Tcl_ObjPrintf("invalid bareword \"%.*s%s\"", - (scanned < limit) ? scanned : limit - 3, start, - (scanned < limit) ? "" : "..."); - post = Tcl_ObjPrintf( - "should be \"$%.*s%s\" or \"{%.*s%s}\"", - (scanned < limit) ? scanned : limit - 3, - start, (scanned < limit) ? "" : "...", - (scanned < limit) ? scanned : limit - 3, - start, (scanned < limit) ? "" : "..."); - Tcl_AppendPrintfToObj(post, " or \"%.*s%s(...)\" or ...", - (scanned < limit) ? scanned : limit - 3, - start, (scanned < limit) ? "" : "..."); - errCode = "BAREWORD"; - if (start[0] == '0') { - const char *stop; - TclParseNumber(NULL, NULL, NULL, start, scanned, - &stop, TCL_PARSE_NO_WHITESPACE); - - if (isdigit(UCHAR(*stop)) || (stop == start + 1)) { - switch (start[1]) { - case 'b': - Tcl_AppendToObj(post, - " (invalid binary number?)", -1); - parsePtr->errorType = TCL_PARSE_BAD_NUMBER; - errCode = "BADNUMBER"; - subErrCode = "BINARY"; - break; - case 'o': - Tcl_AppendToObj(post, - " (invalid octal number?)", -1); + int b; + if (Tcl_GetBooleanFromObj(NULL, literal, &b) == TCL_OK) { + lexeme = BOOLEAN; + } else { + Tcl_DecrRefCount(literal); + msg = Tcl_ObjPrintf( + "invalid bareword \"%.*s%s\"", + (scanned < limit) ? scanned : limit - 3, start, + (scanned < limit) ? "" : "..."); + post = Tcl_ObjPrintf( + "should be \"$%.*s%s\" or \"{%.*s%s}\"", + (scanned < limit) ? scanned : limit - 3, + start, (scanned < limit) ? "" : "...", + (scanned < limit) ? scanned : limit - 3, + start, (scanned < limit) ? "" : "..."); + Tcl_AppendPrintfToObj(post, + " or \"%.*s%s(...)\" or ...", + (scanned < limit) ? scanned : limit - 3, + start, (scanned < limit) ? "" : "..."); + if (start[0] == '0') { + const char *stop; + TclParseNumber(NULL, NULL, NULL, start, scanned, + &stop, TCL_PARSE_NO_WHITESPACE); + + if (isdigit(UCHAR(*stop)) || (stop == start + 1)) { parsePtr->errorType = TCL_PARSE_BAD_NUMBER; - errCode = "BADNUMBER"; - subErrCode = "OCTAL"; - break; - default: - if (isdigit(UCHAR(start[1]))) { + + switch (start[1]) { + case 'b': + Tcl_AppendToObj(post, + " (invalid binary number?)", -1); + break; + case 'o': Tcl_AppendToObj(post, " (invalid octal number?)", -1); - parsePtr->errorType = TCL_PARSE_BAD_NUMBER; - errCode = "BADNUMBER"; - subErrCode = "OCTAL"; + break; + default: + if (isdigit(UCHAR(start[1]))) { + Tcl_AppendToObj(post, + " (invalid octal number?)", -1); + } + break; } - break; } } + goto error; } - goto error; } break; case PLUS: case MINUS: if (IsOperator(lastParsed)) { + /* - * A "+" or "-" coming just after another operator must be - * interpreted as a unary operator. + * A "+" or "-" coming just after another operator + * must be interpreted as a unary operator. */ lexeme |= UNARY; @@ -799,19 +784,17 @@ ParseExpr( } } /* Uncategorized lexemes */ + /* Handle lexeme based on its category. */ + switch (NODE_TYPE & lexeme) { + /* - * Handle lexeme based on its category. + * Each LEAF results in either a literal getting appended to the + * litList, or a sequence of Tcl_Tokens representing a Tcl word + * getting appended to the parsePtr->tokens. No OpNode is filled + * for this lexeme. */ - switch (NODE_TYPE & lexeme) { case LEAF: { - /* - * Each LEAF results in either a literal getting appended to the - * litList, or a sequence of Tcl_Tokens representing a Tcl word - * getting appended to the parsePtr->tokens. No OpNode is filled - * for this lexeme. - */ - Tcl_Token *tokenPtr; const char *end = start; int wordIndex; @@ -824,14 +807,10 @@ ParseExpr( if (NotOperator(lastParsed)) { msg = Tcl_ObjPrintf("missing operator at %s", mark); - errCode = "MISSING"; scanned = 0; insertMark = 1; - /* - * Free any literal to avoid a memleak. - */ - + /* Free any literal to avoid a memleak. */ if ((lexeme == NUMBER) || (lexeme == BOOLEAN)) { Tcl_DecrRefCount(literal); } @@ -848,16 +827,15 @@ ParseExpr( * Pro: ~75% memory saving on expressions like * {1+1+1+1+1+.....+1} (Convert "pointer + Tcl_Obj" cost * to "pointer" cost only) - * Con: Cost of the dict store/retrieve on every literal in - * every expression when expressions like the above tend - * to be uncommon. + * Con: Cost of the dict store/retrieve on every literal + * in every expression when expressions like the above + * tend to be uncommon. * The memory savings is temporary; Compiling to bytecode * will collapse things as literals are registered - * anyway, so the savings applies only to the time - * between parsing and compiling. Possibly important due - * to high-water mark nature of memory allocation. + * anyway, so the savings applies only to the time + * between parsing and compiling. Possibly important + * due to high-water mark nature of memory allocation. */ - Tcl_ListObjAppendElement(NULL, litList, literal); complete = lastParsed = OT_LITERAL; start += scanned; @@ -869,8 +847,8 @@ ParseExpr( } /* - * Remaining LEAF cases may involve filling Tcl_Tokens, so make - * room for at least 2 more tokens. + * Remaining LEAF cases may involve filling Tcl_Tokens, so + * make room for at least 2 more tokens. */ TclGrowParseTokenArray(parsePtr, 2); @@ -889,7 +867,7 @@ ParseExpr( case BRACED: code = Tcl_ParseBraces(NULL, start, numBytes, - parsePtr, 1, &end); + parsePtr, 1, &end); scanned = end - start; break; @@ -904,7 +882,6 @@ ParseExpr( tokenPtr = parsePtr->tokenPtr + wordIndex + 1; if (code == TCL_OK && tokenPtr->type != TCL_TOKEN_VARIABLE) { TclNewLiteralStringObj(msg, "invalid character \"$\""); - errCode = "BADCHAR"; goto error; } scanned = tokenPtr->size; @@ -912,7 +889,7 @@ ParseExpr( case SCRIPT: { Tcl_Parse *nestedPtr = - TclStackAlloc(interp, sizeof(Tcl_Parse)); + (Tcl_Parse *) TclStackAlloc(interp, sizeof(Tcl_Parse)); tokenPtr = parsePtr->tokenPtr + parsePtr->numTokens; tokenPtr->type = TCL_TOKEN_COMMAND; @@ -922,7 +899,7 @@ ParseExpr( end = start + numBytes; start++; while (1) { - code = Tcl_ParseCommand(interp, start, end - start, 1, + code = Tcl_ParseCommand(interp, start, (end - start), 1, nestedPtr); if (code != TCL_OK) { parsePtr->term = nestedPtr->term; @@ -930,10 +907,10 @@ ParseExpr( parsePtr->incomplete = nestedPtr->incomplete; break; } - start = nestedPtr->commandStart + nestedPtr->commandSize; + start = (nestedPtr->commandStart + nestedPtr->commandSize); Tcl_FreeParse(nestedPtr); - if ((nestedPtr->term < end) && (nestedPtr->term[0] == ']') - && !nestedPtr->incomplete) { + if ((nestedPtr->term < end) && (*(nestedPtr->term) == ']') + && !(nestedPtr->incomplete)) { break; } @@ -943,7 +920,6 @@ ParseExpr( parsePtr->errorType = TCL_PARSE_MISSING_BRACKET; parsePtr->incomplete = 1; code = TCL_ERROR; - errCode = "UNBALANCED"; break; } } @@ -954,29 +930,28 @@ ParseExpr( tokenPtr->size = scanned; parsePtr->numTokens++; break; - } /* SCRIPT case */ + } } if (code != TCL_OK) { + /* - * Here we handle all the syntax errors generated by the - * Tcl_Token generating parsing routines called in the switch - * just above. If the value of parsePtr->incomplete is 1, then - * the error was an unbalanced '[', '(', '{', or '"' and - * parsePtr->term is pointing to that unbalanced character. If - * the value of parsePtr->incomplete is 0, then the error is - * one of lacking whitespace following a quoted word, for - * example: expr {[an error {foo}bar]}, and parsePtr->term - * points to where the whitespace is missing. We reset our - * values of start and scanned so that when our error message - * is constructed, the location of the syntax error is sure to - * appear in it, even if the quoted expression is truncated. + * Here we handle all the syntax errors generated by + * the Tcl_Token generating parsing routines called in the + * switch just above. If the value of parsePtr->incomplete + * is 1, then the error was an unbalanced '[', '(', '{', + * or '"' and parsePtr->term is pointing to that unbalanced + * character. If the value of parsePtr->incomplete is 0, + * then the error is one of lacking whitespace following a + * quoted word, for example: expr {[an error {foo}bar]}, + * and parsePtr->term points to where the whitespace is + * missing. We reset our values of start and scanned so that + * when our error message is constructed, the location of + * the syntax error is sure to appear in it, even if the + * quoted expression is truncated. */ start = parsePtr->term; scanned = parsePtr->incomplete; - if (parsePtr->incomplete) { - errCode = "UNBALANCED"; - } goto error; } @@ -984,19 +959,20 @@ ParseExpr( tokenPtr->size = scanned; tokenPtr->numComponents = parsePtr->numTokens - wordIndex - 1; if (!parseOnly && ((lexeme == QUOTED) || (lexeme == BRACED))) { + /* * When this expression is destined to be compiled, and a * braced or quoted word within an expression is known at - * compile time (no runtime substitutions in it), we can store - * it as a literal rather than in its tokenized form. This is - * an advantage since the compiled bytecode is going to need - * the argument in Tcl_Obj form eventually, so it's just as - * well to get there now. Another advantage is that with this - * conversion, larger constant expressions might be grown and - * optimized. + * compile time (no runtime substitutions in it), we can + * store it as a literal rather than in its tokenized form. + * This is an advantage since the compiled bytecode is going + * to need the argument in Tcl_Obj form eventually, so it's + * just as well to get there now. Another advantage is that + * with this conversion, larger constant expressions might + * be grown and optimized. * - * On the contrary, if the end goal of this parse is to fill a - * Tcl_Parse for a caller of Tcl_ParseExpr(), then it's + * On the contrary, if the end goal of this parse is to + * fill a Tcl_Parse for a caller of Tcl_ParseExpr(), then it's * wasteful to convert to a literal only to convert back again * later. */ @@ -1026,14 +1002,10 @@ ParseExpr( msg = Tcl_ObjPrintf("missing operator at %s", mark); scanned = 0; insertMark = 1; - errCode = "MISSING"; goto error; } - /* - * Create an OpNode for the unary operator. - */ - + /* Create an OpNode for the unary operator */ nodePtr->lexeme = lexeme; nodePtr->precedence = prec[lexeme]; nodePtr->mark = MARK_RIGHT; @@ -1041,16 +1013,16 @@ ParseExpr( /* * A FUNCTION cannot be a constant expression, because Tcl allows * functions to return variable results with the same arguments; - * for example, rand(). Other unary operators can root a constant + * for example, rand(). Other unary operators can root a constant * expression, so long as the argument is a constant expression. */ nodePtr->constant = (lexeme != FUNCTION); /* - * This unary operator is a new incomplete tree, so push it onto - * our stack of incomplete trees. Also remember it as the last - * lexeme we parsed. + * This unary operator is a new incomplete tree, so push it + * onto our stack of incomplete trees. Also remember it as + * the last lexeme we parsed. */ nodePtr->p.prev = incomplete; @@ -1071,14 +1043,15 @@ ParseExpr( if ((lexeme == CLOSE_PAREN) && (nodePtr[-1].lexeme == OPEN_PAREN)) { if (nodePtr[-2].lexeme == FUNCTION) { + /* * Normally, "()" is a syntax error, but as a special * case accept it as an argument list for a function. * Treat this as a special LEAF lexeme, and restart - * the parsing loop with zero characters scanned. We - * will parse the ")" again the next time through, but - * with the OT_EMPTY leaf as the subexpression between - * the parens. + * the parsing loop with zero characters scanned. + * We'll parse the ")" again the next time through, + * but with the OT_EMPTY leaf as the subexpression + * between the parens. */ scanned = 0; @@ -1088,7 +1061,6 @@ ParseExpr( msg = Tcl_ObjPrintf("empty subexpression at %s", mark); scanned = 0; insertMark = 1; - errCode = "EMPTY"; goto error; } @@ -1096,66 +1068,63 @@ ParseExpr( if (nodePtr[-1].lexeme == OPEN_PAREN) { TclNewLiteralStringObj(msg, "unbalanced open paren"); parsePtr->errorType = TCL_PARSE_MISSING_PAREN; - errCode = "UNBALANCED"; } else if (nodePtr[-1].lexeme == COMMA) { msg = Tcl_ObjPrintf( "missing function argument at %s", mark); scanned = 0; insertMark = 1; - errCode = "MISSING"; } else if (nodePtr[-1].lexeme == START) { TclNewLiteralStringObj(msg, "empty expression"); - errCode = "EMPTY"; } - } else if (lexeme == CLOSE_PAREN) { - TclNewLiteralStringObj(msg, "unbalanced close paren"); - errCode = "UNBALANCED"; - } else if ((lexeme == COMMA) - && (nodePtr[-1].lexeme == OPEN_PAREN) - && (nodePtr[-2].lexeme == FUNCTION)) { - msg = Tcl_ObjPrintf("missing function argument at %s", - mark); - scanned = 0; - insertMark = 1; - errCode = "UNBALANCED"; + } else { + if (lexeme == CLOSE_PAREN) { + TclNewLiteralStringObj(msg, "unbalanced close paren"); + } else if ((lexeme == COMMA) + && (nodePtr[-1].lexeme == OPEN_PAREN) + && (nodePtr[-2].lexeme == FUNCTION)) { + msg = Tcl_ObjPrintf( + "missing function argument at %s", mark); + scanned = 0; + insertMark = 1; + } } if (msg == NULL) { msg = Tcl_ObjPrintf("missing operand at %s", mark); scanned = 0; insertMark = 1; - errCode = "MISSING"; } goto error; } /* - * Here is where the tree comes together. At this point, we have a - * stack of incomplete trees corresponding to substrings that are - * incomplete expressions, followed by a complete tree - * corresponding to a substring that is itself a complete - * expression, followed by the binary operator we have just - * parsed. The incomplete trees can each be completed by adding a - * right operand. + * Here is where the tree comes together. At this point, we + * have a stack of incomplete trees corresponding to + * substrings that are incomplete expressions, followed by + * a complete tree corresponding to a substring that is itself + * a complete expression, followed by the binary operator we have + * just parsed. The incomplete trees can each be completed by + * adding a right operand. * * To illustrate with an example, when we parse the expression * "1+2*3-4" and we reach this point having just parsed the "-" * operator, we have these incomplete trees: START, "1+", and - * "2*". Next we have the complete subexpression "3". Last is the - * "-" we've just parsed. + * "2*". Next we have the complete subexpression "3". Last is + * the "-" we've just parsed. * - * The next step is to join our complete tree to an operator. The - * choice is governed by the precedence and associativity of the - * competing operators. If we connect it as the right operand of - * our most recent incomplete tree, we get a new complete tree, - * and we can repeat the process. The while loop following repeats - * this until precedence indicates it is time to join the complete - * tree as the left operand of the just parsed binary operator. + * The next step is to join our complete tree to an operator. + * The choice is governed by the precedence and associativity + * of the competing operators. If we connect it as the right + * operand of our most recent incomplete tree, we get a new + * complete tree, and we can repeat the process. The while + * loop following repeats this until precedence indicates it + * is time to join the complete tree as the left operand of + * the just parsed binary operator. * - * Continuing the example, the first pass through the loop will - * join "3" to "2*"; the next pass will join "2*3" to "1+". Then - * we'll exit the loop and join "1+2*3" to "-". When we return to - * parse another lexeme, our stack of incomplete trees is START - * and "1+2*3-". + * Continuing the example, the first pass through the loop + * will join "3" to "2*"; the next pass will join "2*3" to + * "1+". Then we'll exit the loop and join "1+2*3" to "-". + * When we return to parse another lexeme, our stack of + * incomplete trees is START and "1+2*3-". */ while (1) { @@ -1166,18 +1135,16 @@ ParseExpr( } if (incompletePtr->precedence == precedence) { - /* - * Right association rules for exponentiation. - */ + /* Right association rules for exponentiation. */ if (lexeme == EXPON) { break; } /* - * Special association rules for the conditional - * operators. The "?" and ":" operators have equal - * precedence, but must be linked up in sensible pairs. + * Special association rules for the conditional operators. + * The "?" and ":" operators have equal precedence, but + * must be linked up in sensible pairs. */ if ((incompletePtr->lexeme == QUESTION) @@ -1191,16 +1158,13 @@ ParseExpr( } } - /* - * Some special syntax checks... - */ + /* Some special syntax checks... */ /* Parens must balance */ if ((incompletePtr->lexeme == OPEN_PAREN) && (lexeme != CLOSE_PAREN)) { TclNewLiteralStringObj(msg, "unbalanced open paren"); parsePtr->errorType = TCL_PARSE_MISSING_PAREN; - errCode = "UNBALANCED"; goto error; } @@ -1208,10 +1172,10 @@ ParseExpr( if ((incompletePtr->lexeme == QUESTION) && (NotOperator(complete) || (nodes[complete].lexeme != COLON))) { - msg = Tcl_ObjPrintf("missing operator \":\" at %s", mark); + msg = Tcl_ObjPrintf( + "missing operator \":\" at %s", mark); scanned = 0; insertMark = 1; - errCode = "MISSING"; goto error; } @@ -1222,7 +1186,6 @@ ParseExpr( TclNewLiteralStringObj(msg, "unexpected operator \":\" " "without preceding \"?\""); - errCode = "SURPRISE"; goto error; } @@ -1242,9 +1205,9 @@ ParseExpr( } /* - * The QUESTION/COLON and FUNCTION/OPEN_PAREN combinations - * each make up a single operator. Force them to agree whether - * they have a constant expression. + * The QUESTION/COLON and FUNCTION/OPEN_PAREN combinations each + * make up a single operator. Force them to agree whether they + * have a constant expression. */ if ((incompletePtr->lexeme == QUESTION) @@ -1253,6 +1216,7 @@ ParseExpr( } if (incompletePtr->lexeme == START) { + /* * Completing the START tree indicates we're done. * Transfer the parse tree to the caller and return. @@ -1264,8 +1228,8 @@ ParseExpr( /* * With a right operand attached, last incomplete tree has - * become the complete tree. Pop it from the incomplete tree - * stack. + * become the complete tree. Pop it from the incomplete + * tree stack. */ complete = incomplete; @@ -1277,15 +1241,12 @@ ParseExpr( } } - /* - * More syntax checks... - */ + /* More syntax checks... */ /* Parens must balance. */ if (lexeme == CLOSE_PAREN) { if (incompletePtr->lexeme != OPEN_PAREN) { TclNewLiteralStringObj(msg, "unbalanced close paren"); - errCode = "UNBALANCED"; goto error; } } @@ -1296,7 +1257,6 @@ ParseExpr( || (incompletePtr[-1].lexeme != FUNCTION)) { TclNewLiteralStringObj(msg, "unexpected \",\" outside function argument list"); - errCode = "SURPRISE"; goto error; } } @@ -1305,22 +1265,15 @@ ParseExpr( if (IsOperator(complete) && (nodes[complete].lexeme == COLON)) { TclNewLiteralStringObj(msg, "unexpected operator \":\" without preceding \"?\""); - errCode = "SURPRISE"; goto error; } - /* - * Create no node for a CLOSE_PAREN lexeme. - */ - + /* Create no node for a CLOSE_PAREN lexeme. */ if (lexeme == CLOSE_PAREN) { break; } - /* - * Link complete tree as left operand of new node. - */ - + /* Link complete tree as left operand of new node. */ nodePtr->lexeme = lexeme; nodePtr->precedence = precedence; nodePtr->mark = MARK_LEFT; @@ -1328,9 +1281,9 @@ ParseExpr( /* * The COMMA operator cannot be optimized, since the function - * needs all of its arguments, and optimization would reduce the - * number. Other binary operators root constant expressions when - * both arguments are constant expressions. + * needs all of its arguments, and optimization would reduce + * the number. Other binary operators root constant expressions + * when both arguments are constant expressions. */ nodePtr->constant = (lexeme != COMMA); @@ -1345,9 +1298,9 @@ ParseExpr( } /* - * With a left operand attached and a right operand missing, the - * just-parsed binary operator is root of a new incomplete tree. - * Push it onto the stack of incomplete trees. + * With a left operand attached and a right operand missing, + * the just-parsed binary operator is root of a new incomplete + * tree. Push it onto the stack of incomplete trees. */ nodePtr->p.prev = incomplete; @@ -1362,36 +1315,34 @@ ParseExpr( numBytes -= scanned; } /* main parsing loop */ + error: + /* - * We only get here if there's been an error. Any errors that didn't get a - * suitable parsePtr->errorType, get recorded as syntax errors. + * We only get here if there's been an error. + * Any errors that didn't get a suitable parsePtr->errorType, + * get recorded as syntax errors. */ - error: if (parsePtr->errorType == TCL_PARSE_SUCCESS) { parsePtr->errorType = TCL_PARSE_SYNTAX; } - /* - * Free any partial parse tree we've built. - */ - + /* Free any partial parse tree we've built. */ if (nodes != NULL) { - ckfree(nodes); + ckfree((char*) nodes); } if (interp == NULL) { - /* - * Nowhere to report an error message, so just free it. - */ + /* Nowhere to report an error message, so just free it */ if (msg) { Tcl_DecrRefCount(msg); } } else { + /* - * Construct the complete error message. Start with the simple error - * message, pulled from the interp result if necessary... + * Construct the complete error message. Start with the simple + * error message, pulled from the interp result if necessary... */ if (msg == NULL) { @@ -1416,10 +1367,7 @@ ParseExpr( start + scanned, (start + scanned + limit > parsePtr->end) ? "" : "..."); - /* - * Next, append any postscript message. - */ - + /* Next, append any postscript message. */ if (post != NULL) { Tcl_AppendToObj(msg, ";\n", -1); Tcl_AppendObjToObj(msg, post); @@ -1427,19 +1375,12 @@ ParseExpr( } Tcl_SetObjResult(interp, msg); - /* - * Finally, place context information in the errorInfo. - */ - + /* Finally, place context information in the errorInfo. */ numBytes = parsePtr->end - parsePtr->string; Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (parsing expression \"%.*s%s\")", (numBytes < limit) ? numBytes : limit - 3, parsePtr->string, (numBytes < limit) ? "" : "...")); - if (errCode) { - Tcl_SetErrorCode(interp, "TCL", "PARSE", "EXPR", errCode, - subErrCode, NULL); - } } return TCL_ERROR; @@ -1453,10 +1394,10 @@ ParseExpr( * Given a string, the numBytes bytes starting at start, and an OpNode * tree and Tcl_Token array created by passing that same string to * ParseExpr(), this function writes into *parsePtr the sequence of - * Tcl_Tokens needed so to satisfy the historical interface provided by - * Tcl_ParseExpr(). Note that this routine exists only for the sake of - * the public Tcl_ParseExpr() routine. It is not used by Tcl itself at - * all. + * Tcl_Tokens needed so to satisfy the historical interface provided + * by Tcl_ParseExpr(). Note that this routine exists only for the sake + * of the public Tcl_ParseExpr() routine. It is not used by Tcl itself + * at all. * * Results: * None. @@ -1492,10 +1433,7 @@ ConvertTreeToTokens( nodePtr->mark++; - /* - * Handle next child node or leaf. - */ - + /* Handle next child node or leaf */ switch (next) { case OT_EMPTY: @@ -1504,18 +1442,12 @@ ConvertTreeToTokens( case OT_LITERAL: - /* - * Skip any white space that comes before the literal. - */ - + /* Skip any white space that comes before the literal */ scanned = TclParseAllWhiteSpace(start, numBytes); - start += scanned; + start +=scanned; numBytes -= scanned; - /* - * Reparse the literal to get pointers into source string. - */ - + /* Reparse the literal to get pointers into source string */ scanned = ParseLexeme(start, numBytes, &lexeme, NULL); TclGrowParseTokenArray(parsePtr, 2); @@ -1530,30 +1462,32 @@ ConvertTreeToTokens( subExprTokenPtr[1].numComponents = 0; parsePtr->numTokens += 2; - start += scanned; + start +=scanned; numBytes -= scanned; break; case OT_TOKENS: { + /* - * tokenPtr points to a token sequence that came from parsing a - * Tcl word. A Tcl word is made up of a sequence of one or more - * elements. When the word is only a single element, it's been the - * historical practice to replace the TCL_TOKEN_WORD token - * directly with a TCL_TOKEN_SUB_EXPR token. However, when the - * word has multiple elements, a TCL_TOKEN_WORD token is kept as a - * grouping device so that TCL_TOKEN_SUB_EXPR always has only one - * element. Wise or not, these are the rules the Tcl expr parser - * has followed, and for the sake of those few callers of - * Tcl_ParseExpr() we do not change them now. Internally, we can - * do better. + * tokenPtr points to a token sequence that came from parsing + * a Tcl word. A Tcl word is made up of a sequence of one or + * more elements. When the word is only a single element, it's + * been the historical practice to replace the TCL_TOKEN_WORD + * token directly with a TCL_TOKEN_SUB_EXPR token. However, + * when the word has multiple elements, a TCL_TOKEN_WORD token + * is kept as a grouping device so that TCL_TOKEN_SUB_EXPR + * always has only one element. Wise or not, these are the + * rules the Tcl expr parser has followed, and for the sake + * of those few callers of Tcl_ParseExpr() we do not change + * them now. Internally, we can do better. */ int toCopy = tokenPtr->numComponents + 1; if (tokenPtr->numComponents == tokenPtr[1].numComponents + 1) { + /* - * Single element word. Copy tokens and convert the leading + * Single element word. Copy tokens and convert the leading * token to TCL_TOKEN_SUB_EXPR. */ @@ -1564,10 +1498,11 @@ ConvertTreeToTokens( subExprTokenPtr->type = TCL_TOKEN_SUB_EXPR; parsePtr->numTokens += toCopy; } else { + /* - * Multiple element word. Create a TCL_TOKEN_SUB_EXPR token to - * lead, with fields initialized from the leading token, then - * copy entire set of word tokens. + * Multiple element word. Create a TCL_TOKEN_SUB_EXPR + * token to lead, with fields initialized from the leading + * token, then copy entire set of word tokens. */ TclGrowParseTokenArray(parsePtr, toCopy+1); @@ -1582,7 +1517,7 @@ ConvertTreeToTokens( } scanned = tokenPtr->start + tokenPtr->size - start; - start += scanned; + start +=scanned; numBytes -= scanned; tokenPtr += toCopy; break; @@ -1590,24 +1525,15 @@ ConvertTreeToTokens( default: - /* - * Advance to the child node, which is an operator. - */ - + /* Advance to the child node, which is an operator. */ nodePtr = nodes + next; - /* - * Skip any white space that comes before the subexpression. - */ - + /* Skip any white space that comes before the subexpression */ scanned = TclParseAllWhiteSpace(start, numBytes); - start += scanned; + start +=scanned; numBytes -= scanned; - /* - * Generate tokens for the operator / subexpression... - */ - + /* Generate tokens for the operator / subexpression... */ switch (nodePtr->lexeme) { case OPEN_PAREN: case COMMA: @@ -1624,16 +1550,16 @@ ConvertTreeToTokens( /* * Remember the index of the last subexpression we were - * working on -- that of our parent. We'll stack it later. + * working on -- that of our parent. We'll stack it later. */ parentIdx = subExprTokenIdx; /* * Verify space for the two leading Tcl_Tokens representing - * the subexpression rooted by this operator. The first - * Tcl_Token will be of type TCL_TOKEN_SUB_EXPR; the second of - * type TCL_TOKEN_OPERATOR. + * the subexpression rooted by this operator. The first + * Tcl_Token will be of type TCL_TOKEN_SUB_EXPR; the second + * of type TCL_TOKEN_OPERATOR. */ TclGrowParseTokenArray(parsePtr, 2); @@ -1652,7 +1578,7 @@ ConvertTreeToTokens( /* * Eventually, we know that the numComponents field of the - * Tcl_Token of type TCL_TOKEN_OPERATOR will be 0. This means + * Tcl_Token of type TCL_TOKEN_OPERATOR will be 0. This means * we can make other use of this field for now to track the * stack of subexpressions we have pending. */ @@ -1674,12 +1600,9 @@ ConvertTreeToTokens( case MARK_RIGHT: next = nodePtr->right; - /* - * Skip any white space that comes before the operator. - */ - + /* Skip any white space that comes before the operator */ scanned = TclParseAllWhiteSpace(start, numBytes); - start += scanned; + start +=scanned; numBytes -= scanned; /* @@ -1694,10 +1617,7 @@ ConvertTreeToTokens( case COMMA: case COLON: - /* - * No tokens for these lexemes -> nothing to do. - */ - + /* No tokens for these lexemes -> nothing to do. */ break; default: @@ -1713,7 +1633,7 @@ ConvertTreeToTokens( break; } - start += scanned; + start +=scanned; numBytes -= scanned; break; @@ -1732,19 +1652,16 @@ ConvertTreeToTokens( case OPEN_PAREN: - /* - * Skip past matching close paren. - */ - + /* Skip past matching close paren. */ scanned = TclParseAllWhiteSpace(start, numBytes); - start += scanned; + start +=scanned; numBytes -= scanned; scanned = ParseLexeme(start, numBytes, &lexeme, NULL); - start += scanned; + start +=scanned; numBytes -= scanned; break; - default: + default: { /* * Before we leave this node/operator/subexpression for the @@ -1759,7 +1676,7 @@ ConvertTreeToTokens( /* * All the Tcl_Tokens allocated and filled belong to - * this subexpresion. The first token is the leading + * this subexpresion. The first token is the leading * TCL_TOKEN_SUB_EXPR token, and all the rest (one fewer) * are its components. */ @@ -1778,11 +1695,9 @@ ConvertTreeToTokens( subExprTokenIdx = parentIdx; break; } + } - /* - * Since we're returning to parent, skip child handling code. - */ - + /* Since we're returning to parent, skip child handling code. */ nodePtr = nodes + nodePtr->p.parent; goto router; } @@ -1827,18 +1742,19 @@ Tcl_ParseExpr( * information in the structure is ignored. */ { int code; - OpNode *opTree = NULL; /* Will point to the tree of operators. */ - Tcl_Obj *litList = Tcl_NewObj(); /* List to hold the literals. */ - Tcl_Obj *funcList = Tcl_NewObj(); /* List to hold the functon names. */ - Tcl_Parse *exprParsePtr = TclStackAlloc(interp, sizeof(Tcl_Parse)); - /* Holds the Tcl_Tokens of substitutions. */ + OpNode *opTree = NULL; /* Will point to the tree of operators */ + Tcl_Obj *litList = Tcl_NewObj(); /* List to hold the literals */ + Tcl_Obj *funcList = Tcl_NewObj(); /* List to hold the functon names*/ + Tcl_Parse *exprParsePtr = + (Tcl_Parse *) TclStackAlloc(interp, sizeof(Tcl_Parse)); + /* Holds the Tcl_Tokens of substitutions */ if (numBytes < 0) { numBytes = (start ? strlen(start) : 0); } - code = ParseExpr(interp, start, numBytes, &opTree, litList, funcList, - exprParsePtr, 1 /* parseOnly */); + code = ParseExpr(interp, start, numBytes, &opTree, litList, + funcList, exprParsePtr, 1 /* parseOnly */); Tcl_DecrRefCount(funcList); Tcl_DecrRefCount(litList); @@ -1853,7 +1769,7 @@ Tcl_ParseExpr( Tcl_FreeParse(exprParsePtr); TclStackFree(interp, exprParsePtr); - ckfree(opTree); + ckfree((char *) opTree); return code; } @@ -1893,7 +1809,7 @@ ParseLexeme( *lexemePtr = END; return 0; } - byte = UCHAR(*start); + byte = (unsigned char)(*start); if (byte < sizeof(Lexeme) && Lexeme[byte] != 0) { *lexemePtr = Lexeme[byte]; return 1; @@ -1970,10 +1886,11 @@ ParseLexeme( case 'i': if ((numBytes > 1) && (start[1] == 'n') && ((numBytes == 2) || start[2] & 0x80 || !isalpha(UCHAR(start[2])))) { + /* - * Must make this check so we can tell the difference between the - * "in" operator and the "int" function name and the "infinity" - * numeric value. + * Must make this check so we can tell the difference between + * the "in" operator and the "int" function name and the + * "infinity" numeric value. */ *lexemePtr = IN_LIST; @@ -2007,7 +1924,7 @@ ParseLexeme( if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end, TCL_PARSE_NO_WHITESPACE) == TCL_OK) { if (end < start + numBytes && !TclIsBareword(*end)) { - + number: TclInitStringRep(literal, start, end-start); *lexemePtr = NUMBER; @@ -2029,11 +1946,10 @@ ParseLexeme( */ if (literal->typePtr == &tclDoubleType) { const char *p = start; - while (p < end) { if (!TclIsBareword(*p++)) { /* - * The number has non-bareword characters, so we + * The number has non-bareword characters, so we * must treat it as a number. */ goto number; @@ -2049,7 +1965,6 @@ ParseLexeme( */ goto number; } - /* * Otherwise, fall through and parse the whole as a bareword. */ @@ -2060,14 +1975,13 @@ ParseLexeme( * We reject leading underscores in bareword. No sensible reason why. * Might be inspired by reserved identifier rules in C, which of course * have no direct relevance here. - */ + */ if (!TclIsBareword(*start) || *start == '_') { if (Tcl_UtfCharComplete(start, numBytes)) { scanned = Tcl_UtfToUniChar(start, &ch); } else { char utfBytes[TCL_UTF_MAX]; - memcpy(utfBytes, start, (size_t) numBytes); utfBytes[numBytes] = '\0'; scanned = Tcl_UtfToUniChar(utfBytes, &ch); @@ -2114,22 +2028,21 @@ TclCompileExpr( const char *script, /* The source script to compile. */ int numBytes, /* Number of bytes in script. */ CompileEnv *envPtr, /* Holds resulting instructions. */ - int optimize) /* 0 for one-off expressions. */ + int optimize) /* 0 for one-off expressions */ { OpNode *opTree = NULL; /* Will point to the tree of operators */ Tcl_Obj *litList = Tcl_NewObj(); /* List to hold the literals */ Tcl_Obj *funcList = Tcl_NewObj(); /* List to hold the functon names*/ - Tcl_Parse *parsePtr = TclStackAlloc(interp, sizeof(Tcl_Parse)); + Tcl_Parse *parsePtr = + (Tcl_Parse *) TclStackAlloc(interp, sizeof(Tcl_Parse)); /* Holds the Tcl_Tokens of substitutions */ int code = ParseExpr(interp, script, numBytes, &opTree, litList, funcList, parsePtr, 0 /* parseOnly */); if (code == TCL_OK) { - /* - * Valid parse; compile the tree. - */ + /* Valid parse; compile the tree. */ int objc; Tcl_Obj *const *litObjv; Tcl_Obj **funcObjv; @@ -2150,7 +2063,7 @@ TclCompileExpr( TclStackFree(interp, parsePtr); Tcl_DecrRefCount(funcList); Tcl_DecrRefCount(litList); - ckfree(opTree); + ckfree((char *) opTree); } /* @@ -2182,7 +2095,6 @@ ExecConstantExprTree( ByteCode *byteCodePtr; int code; Tcl_Obj *byteCodeObj = Tcl_NewObj(); - NRE_callback *rootPtr = TOP_CB(interp); /* * Note we are compiling an expression with literal arguments. This means @@ -2190,7 +2102,7 @@ ExecConstantExprTree( * bytecode, so there's no need to tend to TIP 280 issues. */ - envPtr = TclStackAlloc(interp, sizeof(CompileEnv)); + envPtr = (CompileEnv *) TclStackAlloc(interp, sizeof(CompileEnv)); TclInitCompileEnv(interp, envPtr, NULL, 0, NULL, 0); CompileExprTree(interp, nodes, index, litObjvPtr, NULL, NULL, envPtr, 0 /* optimize */); @@ -2199,9 +2111,8 @@ ExecConstantExprTree( TclInitByteCodeObj(byteCodeObj, envPtr); TclFreeCompileEnv(envPtr); TclStackFree(interp, envPtr); - byteCodePtr = byteCodeObj->internalRep.twoPtrValue.ptr1; - TclNRExecuteByteCode(interp, byteCodePtr); - code = TclNRRunCallbacks(interp, TCL_OK, rootPtr); + byteCodePtr = (ByteCode *) byteCodeObj->internalRep.twoPtrValue.ptr1; + code = TclExecuteByteCode(interp, byteCodePtr); Tcl_DecrRefCount(byteCodeObj); return code; } @@ -2210,20 +2121,20 @@ ExecConstantExprTree( *---------------------------------------------------------------------- * * CompileExprTree -- - * - * Compiles and writes to envPtr instructions for the subexpression tree - * at index in the nodes array. (*litObjvPtr) must point to the proper - * location in a corresponding literals list. Likewise, when non-NULL, - * funcObjv and tokenPtr must point into matching arrays of function - * names and Tcl_Token's derived from earlier call to ParseExpr(). When - * optimize is true, any constant subexpressions will be precomputed. + * Compiles and writes to envPtr instructions for the subexpression + * tree at index in the nodes array. (*litObjvPtr) must point to the + * proper location in a corresponding literals list. Likewise, when + * non-NULL, funcObjv and tokenPtr must point into matching arrays of + * function names and Tcl_Token's derived from earlier call to + * ParseExpr(). When optimize is true, any constant subexpressions + * will be precomputed. * * Results: * None. * * Side effects: * Adds instructions to envPtr to evaluate the expression at runtime. - * Consumes subtree of nodes rooted at index. Advances the pointer + * Consumes subtree of nodes rooted at index. Advances the pointer * *litObjvPtr. * *---------------------------------------------------------------------- @@ -2253,8 +2164,30 @@ CompileExprTree( if (nodePtr->mark == MARK_LEFT) { next = nodePtr->left; - if (nodePtr->lexeme == QUESTION) { + switch (nodePtr->lexeme) { + case QUESTION: + newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); + newJump->next = jumpPtr; + jumpPtr = newJump; + newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); + newJump->next = jumpPtr; + jumpPtr = newJump; + jumpPtr->depth = envPtr->currStackDepth; convert = 1; + break; + case AND: + case OR: + newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); + newJump->next = jumpPtr; + jumpPtr = newJump; + newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); + newJump->next = jumpPtr; + jumpPtr = newJump; + newJump = (JumpList *) TclStackAlloc(interp, sizeof(JumpList)); + newJump->next = jumpPtr; + jumpPtr = newJump; + jumpPtr->depth = envPtr->currStackDepth; + break; } } else if (nodePtr->mark == MARK_RIGHT) { next = nodePtr->right; @@ -2266,20 +2199,20 @@ CompileExprTree( int length; Tcl_DStringInit(&cmdName); - TclDStringAppendLiteral(&cmdName, "tcl::mathfunc::"); + Tcl_DStringAppend(&cmdName, "tcl::mathfunc::", -1); p = TclGetStringFromObj(*funcObjv, &length); funcObjv++; Tcl_DStringAppend(&cmdName, p, length); - TclEmitPush(TclRegisterNewCmdLiteral(envPtr, + TclEmitPush(TclRegisterNewNSLiteral(envPtr, Tcl_DStringValue(&cmdName), Tcl_DStringLength(&cmdName)), envPtr); Tcl_DStringFree(&cmdName); /* * Start a count of the number of words in this function - * command invocation. In case there's already a count in - * progress (nested functions), save it in our unused "left" - * field for restoring later. + * command invocation. In case there's already a count + * in progress (nested functions), save it in our unused + * "left" field for restoring later. */ nodePtr->left = numWords; @@ -2287,35 +2220,24 @@ CompileExprTree( break; } case QUESTION: - newJump = TclStackAlloc(interp, sizeof(JumpList)); - newJump->next = jumpPtr; - jumpPtr = newJump; - TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpPtr->jump); + TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &(jumpPtr->jump)); break; case COLON: - newJump = TclStackAlloc(interp, sizeof(JumpList)); - newJump->next = jumpPtr; - jumpPtr = newJump; TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, - &jumpPtr->jump); - TclAdjustStackDepth(-1, envPtr); - if (convert) { - jumpPtr->jump.jumpType = TCL_TRUE_JUMP; - } + &(jumpPtr->next->jump)); + envPtr->currStackDepth = jumpPtr->depth; + jumpPtr->offset = (envPtr->codeNext - envPtr->codeStart); + jumpPtr->convert = convert; convert = 1; break; case AND: + TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &(jumpPtr->jump)); + break; case OR: - newJump = TclStackAlloc(interp, sizeof(JumpList)); - newJump->next = jumpPtr; - jumpPtr = newJump; - TclEmitForwardJump(envPtr, (nodePtr->lexeme == AND) - ? TCL_FALSE_JUMP : TCL_TRUE_JUMP, &jumpPtr->jump); + TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &(jumpPtr->jump)); break; } } else { - int pc1, pc2, target; - switch (nodePtr->lexeme) { case START: case QUESTION: @@ -2328,72 +2250,69 @@ CompileExprTree( /* do nothing */ break; case FUNCTION: + /* - * Use the numWords count we've kept to invoke the function - * command with the correct number of arguments. + * Use the numWords count we've kept to invoke the + * function command with the correct number of arguments. */ if (numWords < 255) { - TclEmitInvoke(envPtr, INST_INVOKE_STK1, numWords); + TclEmitInstInt1(INST_INVOKE_STK1, numWords, envPtr); } else { - TclEmitInvoke(envPtr, INST_INVOKE_STK4, numWords); + TclEmitInstInt4(INST_INVOKE_STK4, numWords, envPtr); } - /* - * Restore any saved numWords value. - */ - + /* Restore any saved numWords value. */ numWords = nodePtr->left; convert = 1; break; case COMMA: - /* - * Each comma implies another function argument. - */ + /* Each comma implies another function argument. */ numWords++; break; case COLON: - CLANG_ASSERT(jumpPtr); - if (jumpPtr->jump.jumpType == TCL_TRUE_JUMP) { - jumpPtr->jump.jumpType = TCL_UNCONDITIONAL_JUMP; - convert = 1; - } - target = jumpPtr->jump.codeOffset + 2; - if (TclFixupForwardJumpToHere(envPtr, &jumpPtr->jump, 127)) { - target += 3; + if (TclFixupForwardJump(envPtr, &(jumpPtr->next->jump), + (envPtr->codeNext - envPtr->codeStart) + - jumpPtr->next->jump.codeOffset, 127)) { + jumpPtr->offset += 3; } + TclFixupForwardJump(envPtr, &(jumpPtr->jump), + jumpPtr->offset - jumpPtr->jump.codeOffset, 127); + convert |= jumpPtr->convert; + envPtr->currStackDepth = jumpPtr->depth + 1; freePtr = jumpPtr; jumpPtr = jumpPtr->next; TclStackFree(interp, freePtr); - TclFixupForwardJump(envPtr, &jumpPtr->jump, - target - jumpPtr->jump.codeOffset, 127); - freePtr = jumpPtr; jumpPtr = jumpPtr->next; TclStackFree(interp, freePtr); break; case AND: case OR: - CLANG_ASSERT(jumpPtr); - pc1 = CurrentOffset(envPtr); - TclEmitInstInt1((nodePtr->lexeme == AND) ? INST_JUMP_FALSE1 - : INST_JUMP_TRUE1, 0, envPtr); + TclEmitForwardJump(envPtr, (nodePtr->lexeme == AND) + ? TCL_FALSE_JUMP : TCL_TRUE_JUMP, + &(jumpPtr->next->jump)); TclEmitPush(TclRegisterNewLiteral(envPtr, (nodePtr->lexeme == AND) ? "1" : "0", 1), envPtr); - pc2 = CurrentOffset(envPtr); - TclEmitInstInt1(INST_JUMP1, 0, envPtr); - TclAdjustStackDepth(-1, envPtr); - TclStoreInt1AtPtr(CurrentOffset(envPtr) - pc1, - envPtr->codeStart + pc1 + 1); - if (TclFixupForwardJumpToHere(envPtr, &jumpPtr->jump, 127)) { - pc2 += 3; + TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, + &(jumpPtr->next->next->jump)); + TclFixupForwardJumpToHere(envPtr, &(jumpPtr->next->jump), 127); + if (TclFixupForwardJumpToHere(envPtr, &(jumpPtr->jump), 127)) { + jumpPtr->next->next->jump.codeOffset += 3; } TclEmitPush(TclRegisterNewLiteral(envPtr, (nodePtr->lexeme == AND) ? "0" : "1", 1), envPtr); - TclStoreInt1AtPtr(CurrentOffset(envPtr) - pc2, - envPtr->codeStart + pc2 + 1); + TclFixupForwardJumpToHere(envPtr, &(jumpPtr->next->next->jump), + 127); convert = 0; + envPtr->currStackDepth = jumpPtr->depth + 1; + freePtr = jumpPtr; + jumpPtr = jumpPtr->next; + TclStackFree(interp, freePtr); + freePtr = jumpPtr; + jumpPtr = jumpPtr->next; + TclStackFree(interp, freePtr); freePtr = jumpPtr; jumpPtr = jumpPtr->next; TclStackFree(interp, freePtr); @@ -2404,8 +2323,8 @@ CompileExprTree( break; } if (nodePtr == rootPtr) { - /* We're done */ + /* We're done */ return; } nodePtr = nodes + nodePtr->p.parent; @@ -2422,11 +2341,14 @@ CompileExprTree( Tcl_Obj *literal = *litObjv; if (optimize) { - int length; + int length, index; const char *bytes = TclGetStringFromObj(literal, &length); - int index = TclRegisterNewLiteral(envPtr, bytes, length); - Tcl_Obj *objPtr = TclFetchLiteral(envPtr, index); + LiteralEntry *lePtr; + Tcl_Obj *objPtr; + index = TclRegisterNewLiteral(envPtr, bytes, length); + lePtr = envPtr->literalArrayPtr + index; + objPtr = lePtr->objPtr; if ((objPtr->typePtr == NULL) && (literal->typePtr != NULL)) { /* * Would like to do this: @@ -2437,10 +2359,10 @@ CompileExprTree( * * However, the design of the "global" and "local" * LiteralTable does not permit the value of lePtr->objPtr - * to change. So rather than replace lePtr->objPtr, we do - * surgery to transfer our desired intrep into it. + * to change. So rather than replace lePtr->objPtr, we + * do surgery to transfer our desired intrep into it. + * */ - objPtr->typePtr = literal->typePtr; objPtr->internalRep = literal->internalRep; literal->typePtr = NULL; @@ -2448,57 +2370,30 @@ CompileExprTree( TclEmitPush(index, envPtr); } else { /* - * When optimize==0, we know the expression is a one-off and - * there's nothing to be gained from sharing literals when - * they won't live long, and the copies we have already have - * an appropriate intrep. In this case, skip literal + * When optimize==0, we know the expression is a one-off + * and there's nothing to be gained from sharing literals + * when they won't live long, and the copies we have already + * have an appropriate intrep. In this case, skip literal * registration that would enable sharing, and use the routine * that preserves intreps. */ - TclEmitPush(TclAddLiteralObj(envPtr, literal, NULL), envPtr); } (*litObjvPtr)++; break; } case OT_TOKENS: - CompileTokens(envPtr, tokenPtr, interp); + TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, + envPtr); tokenPtr += tokenPtr->numComponents + 1; break; default: if (optimize && nodes[next].constant) { Tcl_InterpState save = Tcl_SaveInterpState(interp, TCL_OK); - if (ExecConstantExprTree(interp, nodes, next, litObjvPtr) == TCL_OK) { - int index; - Tcl_Obj *objPtr = Tcl_GetObjResult(interp); - - /* - * Don't generate a string rep, but if we have one - * already, then use it to share via the literal table. - */ - - if (objPtr->bytes) { - Tcl_Obj *tableValue; - - index = TclRegisterNewLiteral(envPtr, objPtr->bytes, - objPtr->length); - tableValue = TclFetchLiteral(envPtr, index); - if ((tableValue->typePtr == NULL) && - (objPtr->typePtr != NULL)) { - /* - * Same intrep surgery as for OT_LITERAL. - */ - - tableValue->typePtr = objPtr->typePtr; - tableValue->internalRep = objPtr->internalRep; - objPtr->typePtr = NULL; - } - } else { - index = TclAddLiteralObj(envPtr, objPtr, NULL); - } - TclEmitPush(index, envPtr); + TclEmitPush(TclAddLiteralObj(envPtr, + Tcl_GetObjResult(interp), NULL), envPtr); } else { TclCompileSyntaxError(interp, envPtr); } @@ -2515,7 +2410,6 @@ CompileExprTree( *---------------------------------------------------------------------- * * TclSingleOpCmd -- - * * Implements the commands: ~, !, <<, >>, %, !=, ne, in, ni * in the ::tcl::mathop namespace. These commands have no * extension to arbitrary arguments; they accept only exactly one @@ -2525,7 +2419,7 @@ CompileExprTree( * A standard Tcl return code and result left in interp. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -2537,12 +2431,12 @@ TclSingleOpCmd( int objc, Tcl_Obj *const objv[]) { - TclOpCmdClientData *occdPtr = clientData; + TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; unsigned char lexeme; OpNode nodes[2]; Tcl_Obj *const *litObjv = objv + 1; - if (objc != 1 + occdPtr->i.numArgs) { + if (objc != 1+occdPtr->i.numArgs) { Tcl_WrongNumArgs(interp, 1, objv, occdPtr->expected); return TCL_ERROR; } @@ -2568,17 +2462,16 @@ TclSingleOpCmd( *---------------------------------------------------------------------- * * TclSortingOpCmd -- - * Implements the commands: - * <, <=, >, >=, ==, eq - * in the ::tcl::mathop namespace. These commands are defined for + * Implements the commands: <, <=, >, >=, ==, eq + * in the ::tcl::mathop namespace. These commands are defined for * arbitrary number of arguments by computing the AND of the base - * operator applied to all neighbor argument pairs. + * operator applied to all neighbor argument pairs. * * Results: * A standard Tcl return code and result left in interp. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -2595,10 +2488,11 @@ TclSortingOpCmd( if (objc < 3) { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1)); } else { - TclOpCmdClientData *occdPtr = clientData; - Tcl_Obj **litObjv = TclStackAlloc(interp, - 2 * (objc-2) * sizeof(Tcl_Obj *)); - OpNode *nodes = TclStackAlloc(interp, 2 * (objc-2) * sizeof(OpNode)); + TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; + Tcl_Obj **litObjv = (Tcl_Obj **) TclStackAlloc(interp, + 2*(objc-2)*sizeof(Tcl_Obj *)); + OpNode *nodes = (OpNode *) TclStackAlloc(interp, + 2*(objc-2)*sizeof(OpNode)); unsigned char lexeme; int i, lastAnd = 1; Tcl_Obj *const *litObjPtrPtr = litObjv; @@ -2649,16 +2543,16 @@ TclSortingOpCmd( * * TclVariadicOpCmd -- * Implements the commands: +, *, &, |, ^, ** - * in the ::tcl::mathop namespace. These commands are defined for + * in the ::tcl::mathop namespace. These commands are defined for * arbitrary number of arguments by repeatedly applying the base - * operator with suitable associative rules. When fewer than two + * operator with suitable associative rules. When fewer than two * arguments are provided, suitable identity values are returned. * * Results: * A standard Tcl return code and result left in interp. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -2670,7 +2564,7 @@ TclVariadicOpCmd( int objc, Tcl_Obj *const objv[]) { - TclOpCmdClientData *occdPtr = clientData; + TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; unsigned char lexeme; int code; @@ -2725,13 +2619,14 @@ TclVariadicOpCmd( return code; } else { Tcl_Obj *const *litObjv = objv + 1; - OpNode *nodes = TclStackAlloc(interp, (objc-1) * sizeof(OpNode)); + OpNode *nodes = (OpNode *) TclStackAlloc(interp, + (objc-1)*sizeof(OpNode)); int i, lastOp = OT_LITERAL; nodes[0].lexeme = START; nodes[0].mark = MARK_RIGHT; if (lexeme == EXPON) { - for (i=objc-2; i>0; i--) { + for (i=objc-2; i>0; i-- ) { nodes[i].lexeme = lexeme; nodes[i].mark = MARK_LEFT; nodes[i].left = OT_LITERAL; @@ -2742,7 +2637,7 @@ TclVariadicOpCmd( lastOp = i; } } else { - for (i=1; i<objc-1; i++) { + for (i=1; i<objc-1; i++ ) { nodes[i].lexeme = lexeme; nodes[i].mark = MARK_LEFT; nodes[i].left = lastOp; @@ -2759,6 +2654,7 @@ TclVariadicOpCmd( code = ExecConstantExprTree(interp, nodes, 0, &litObjv); TclStackFree(interp, nodes); + return code; } } @@ -2768,16 +2664,16 @@ TclVariadicOpCmd( * * TclNoIdentOpCmd -- * Implements the commands: -, / - * in the ::tcl::mathop namespace. These commands are defined for - * arbitrary non-zero number of arguments by repeatedly applying the base - * operator with suitable associative rules. When no arguments are - * provided, an error is raised. + * in the ::tcl::mathop namespace. These commands are defined for + * arbitrary non-zero number of arguments by repeatedly applying + * the base operator with suitable associative rules. When no + * arguments are provided, an error is raised. * * Results: * A standard Tcl return code and result left in interp. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -2789,8 +2685,7 @@ TclNoIdentOpCmd( int objc, Tcl_Obj *const objv[]) { - TclOpCmdClientData *occdPtr = clientData; - + TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, occdPtr->expected); return TCL_ERROR; |