tclCompExpr.c

Go 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  doxygen 1.5.1