home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / generic / tclCompExpr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  67.7 KB  |  2,384 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tclCompExpr.c --
  3.  *
  4.  *    This file contains the code to compile Tcl expressions.
  5.  *
  6.  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * SCCS: @(#) tclCompExpr.c 1.31 97/08/07 10:14:07
  12.  */
  13.  
  14. #include "tclInt.h"
  15. #include "tclCompile.h"
  16.  
  17. /*
  18.  * The stuff below is a bit of a hack so that this file can be used in
  19.  * environments that include no UNIX, i.e. no errno: just arrange to use
  20.  * the errno from tclExecute.c here.
  21.  */
  22.  
  23. #ifndef TCL_GENERIC_ONLY
  24. #include "tclPort.h"
  25. #else
  26. #define NO_ERRNO_H
  27. #endif
  28.  
  29. #ifdef NO_ERRNO_H
  30. extern int errno;            /* Use errno from tclExecute.c. */
  31. #define ERANGE 34
  32. #endif
  33.  
  34. /*
  35.  * Boolean variable that controls whether expression compilation tracing
  36.  * is enabled.
  37.  */
  38.  
  39. #ifdef TCL_COMPILE_DEBUG
  40. static int traceCompileExpr = 0;
  41. #endif /* TCL_COMPILE_DEBUG */
  42.  
  43. /*
  44.  * The ExprInfo structure describes the state of compiling an expression.
  45.  * A pointer to an ExprInfo record is passed among the routines in
  46.  * this module.
  47.  */
  48.  
  49. typedef struct ExprInfo {
  50.     int token;            /* Type of the last token parsed in expr.
  51.                  * See below for definitions. Corresponds
  52.                  * to the characters just before next. */
  53.     int objIndex;        /* If token is a literal value, the index of
  54.                  * an object holding the value in the code's
  55.                  * object table; otherwise is NULL. */
  56.     char *funcName;        /* If the token is FUNC_NAME, points to the
  57.                  * first character of the math function's
  58.                  * name; otherwise is NULL. */
  59.     char *next;            /* Position of the next character to be
  60.                  * scanned in the expression string. */
  61.     char *originalExpr;        /* The entire expression that was originally
  62.                  * passed to Tcl_ExprString et al. */
  63.     char *lastChar;        /* Pointer to terminating null in
  64.                  * originalExpr. */
  65.     int hasOperators;        /* Set 1 if the expr has operators; 0 if
  66.                  * expr is only a primary. If 1 after
  67.                  * compiling an expr, a tryCvtToNumeric
  68.                  * instruction is emitted to convert the
  69.                  * primary to a number if possible. */
  70.     int exprIsJustVarRef;    /* Set 1 if the expr consists of just a
  71.                  * variable reference as in the expression
  72.                  * of "if $b then...". Otherwise 0. If 1 the
  73.                  * expr is compiled out-of-line in order to
  74.                  * implement expr's 2 level substitution
  75.                  * semantics properly. */
  76.     int exprIsComparison;    /* Set 1 if the top-level operator in the
  77.                  * expr is a comparison. Otherwise 0. If 1,
  78.                  * because the operands might be strings,
  79.                  * the expr is compiled out-of-line in order
  80.                  * to implement expr's 2 level substitution
  81.                  * semantics properly. */
  82. } ExprInfo;
  83.  
  84. /*
  85.  * Definitions of the different tokens that appear in expressions. The order
  86.  * of these must match the corresponding entries in the operatorStrings
  87.  * array below.
  88.  */
  89.  
  90. #define LITERAL        0
  91. #define FUNC_NAME    (LITERAL + 1)
  92. #define OPEN_BRACKET    (LITERAL + 2)
  93. #define CLOSE_BRACKET    (LITERAL + 3)
  94. #define OPEN_PAREN    (LITERAL + 4)
  95. #define CLOSE_PAREN    (LITERAL + 5)
  96. #define DOLLAR        (LITERAL + 6)
  97. #define QUOTE        (LITERAL + 7)
  98. #define COMMA        (LITERAL + 8)
  99. #define END        (LITERAL + 9)
  100. #define UNKNOWN        (LITERAL + 10)
  101.  
  102. /*
  103.  * Binary operators:
  104.  */
  105.  
  106. #define MULT        (UNKNOWN + 1)
  107. #define DIVIDE        (MULT + 1)
  108. #define MOD        (MULT + 2)
  109. #define PLUS        (MULT + 3)
  110. #define MINUS        (MULT + 4)
  111. #define LEFT_SHIFT    (MULT + 5)
  112. #define RIGHT_SHIFT    (MULT + 6)
  113. #define LESS        (MULT + 7)
  114. #define GREATER        (MULT + 8)
  115. #define LEQ        (MULT + 9)
  116. #define GEQ        (MULT + 10)
  117. #define EQUAL        (MULT + 11)
  118. #define NEQ        (MULT + 12)
  119. #define BIT_AND        (MULT + 13)
  120. #define BIT_XOR        (MULT + 14)
  121. #define BIT_OR        (MULT + 15)
  122. #define AND        (MULT + 16)
  123. #define OR        (MULT + 17)
  124. #define QUESTY        (MULT + 18)
  125. #define COLON        (MULT + 19)
  126.  
  127. /*
  128.  * Unary operators. Unary minus and plus are represented by the (binary)
  129.  * tokens MINUS and PLUS.
  130.  */
  131.  
  132. #define NOT        (COLON + 1)
  133. #define BIT_NOT        (NOT + 1)
  134.  
  135. /*
  136.  * Mapping from tokens to strings; used for debugging messages. These
  137.  * entries must match the order and number of the token definitions above.
  138.  */
  139.  
  140. #ifdef TCL_COMPILE_DEBUG
  141. static char *tokenStrings[] = {
  142.     "LITERAL", "FUNCNAME",
  143.     "[", "]", "(", ")", "$", "\"", ",", "END", "UNKNOWN",
  144.     "*", "/", "%", "+", "-",
  145.     "<<", ">>", "<", ">", "<=", ">=", "==", "!=",
  146.     "&", "^", "|", "&&", "||", "?", ":",
  147.     "!", "~"
  148. };
  149. #endif /* TCL_COMPILE_DEBUG */
  150.  
  151. /*
  152.  * Declarations for local procedures to this file:
  153.  */
  154.  
  155. static int        CompileAddExpr _ANSI_ARGS_((Tcl_Interp *interp,
  156.                 ExprInfo *infoPtr, int flags,
  157.                 CompileEnv *envPtr));
  158. static int        CompileBitAndExpr _ANSI_ARGS_((Tcl_Interp *interp,
  159.                 ExprInfo *infoPtr, int flags,
  160.                 CompileEnv *envPtr));
  161. static int        CompileBitOrExpr _ANSI_ARGS_((Tcl_Interp *interp,
  162.                 ExprInfo *infoPtr, int flags,
  163.                 CompileEnv *envPtr));
  164. static int        CompileBitXorExpr _ANSI_ARGS_((Tcl_Interp *interp,
  165.                 ExprInfo *infoPtr, int flags,
  166.                 CompileEnv *envPtr));
  167. static int        CompileCondExpr _ANSI_ARGS_((Tcl_Interp *interp,
  168.                 ExprInfo *infoPtr, int flags,
  169.                 CompileEnv *envPtr));
  170. static int        CompileEqualityExpr _ANSI_ARGS_((Tcl_Interp *interp,
  171.                 ExprInfo *infoPtr, int flags,
  172.                 CompileEnv *envPtr));
  173. static int        CompileLandExpr _ANSI_ARGS_((Tcl_Interp *interp,
  174.                 ExprInfo *infoPtr, int flags,
  175.                 CompileEnv *envPtr));
  176. static int        CompileLorExpr _ANSI_ARGS_((Tcl_Interp *interp,
  177.                 ExprInfo *infoPtr, int flags,
  178.                 CompileEnv *envPtr));
  179. static int        CompileMathFuncCall _ANSI_ARGS_((Tcl_Interp *interp,
  180.                 ExprInfo *infoPtr, int flags,
  181.                 CompileEnv *envPtr));
  182. static int        CompileMultiplyExpr _ANSI_ARGS_((Tcl_Interp *interp,
  183.                 ExprInfo *infoPtr, int flags,
  184.                 CompileEnv *envPtr));
  185. static int        CompilePrimaryExpr _ANSI_ARGS_((Tcl_Interp *interp,
  186.                 ExprInfo *infoPtr, int flags,
  187.                 CompileEnv *envPtr));
  188. static int        CompileRelationalExpr _ANSI_ARGS_((
  189.                     Tcl_Interp *interp, ExprInfo *infoPtr,
  190.                 int flags, CompileEnv *envPtr));
  191. static int        CompileShiftExpr _ANSI_ARGS_((Tcl_Interp *interp,
  192.                 ExprInfo *infoPtr, int flags,
  193.                 CompileEnv *envPtr));
  194. static int        CompileUnaryExpr _ANSI_ARGS_((Tcl_Interp *interp,
  195.                 ExprInfo *infoPtr, int flags,
  196.                 CompileEnv *envPtr));
  197. static int        GetToken _ANSI_ARGS_((Tcl_Interp *interp,
  198.                 ExprInfo *infoPtr, CompileEnv *envPtr));
  199.  
  200. /*
  201.  * Macro used to debug the execution of the recursive descent parser used
  202.  * to compile expressions.
  203.  */
  204.  
  205. #ifdef TCL_COMPILE_DEBUG
  206. #define HERE(production, level) \
  207.     if (traceCompileExpr) { \
  208.     fprintf(stderr, "%*s%s: token=%s, next=\"%.20s\"\n", \
  209.         (level), " ", (production), tokenStrings[infoPtr->token], \
  210.         infoPtr->next); \
  211.     }
  212. #else
  213. #define HERE(production, level)
  214. #endif /* TCL_COMPILE_DEBUG */
  215.  
  216. /*
  217.  *----------------------------------------------------------------------
  218.  *
  219.  * TclCompileExpr --
  220.  *
  221.  *    This procedure compiles a string containing a Tcl expression into
  222.  *    Tcl bytecodes. This procedure is the top-level interface to the
  223.  *    the expression compilation module, and is used by such public
  224.  *    procedures as Tcl_ExprString, Tcl_ExprStringObj, Tcl_ExprLong,
  225.  *    Tcl_ExprDouble, Tcl_ExprBoolean, and Tcl_ExprBooleanObj.
  226.  *
  227.  *    Note that the topmost recursive-descent parsing routine used by
  228.  *    TclCompileExpr to compile expressions is called "CompileCondExpr"
  229.  *    and not, e.g., "CompileExpr". This is done to avoid an extra
  230.  *    procedure call since such a procedure would only return the result
  231.  *    of calling CompileCondExpr. Other recursive-descent procedures
  232.  *    that need to parse expressions also call CompileCondExpr.
  233.  *
  234.  * Results:
  235.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  236.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  237.  *    contains an error message.
  238.  *
  239.  *    envPtr->termOffset is filled in with the offset of the character in
  240.  *    "string" just after the last one successfully processed; this might
  241.  *    be the offset of the ']' (if flags & TCL_BRACKET_TERM), or the
  242.  *    offset of the '\0' at the end of the string.
  243.  *
  244.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  245.  *    elements needed to execute the expression.
  246.  *
  247.  *    envPtr->exprIsJustVarRef is set 1 if the expression consisted of
  248.  *    a single variable reference as in the expression of "if $b then...".
  249.  *    Otherwise it is set 0. This is used to implement Tcl's two level
  250.  *    expression substitution semantics properly.
  251.  *
  252.  *    envPtr->exprIsComparison is set 1 if the top-level operator in the
  253.  *    expr is a comparison. Otherwise it is set 0. If 1, because the
  254.  *    operands might be strings, the expr is compiled out-of-line in order
  255.  *    to implement expr's 2 level substitution semantics properly.
  256.  *
  257.  * Side effects:
  258.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  259.  *
  260.  *----------------------------------------------------------------------
  261.  */
  262.  
  263. int
  264. TclCompileExpr(interp, string, lastChar, flags, envPtr)
  265.     Tcl_Interp *interp;        /* Used for error reporting. */
  266.     char *string;        /* The source string to compile. */
  267.     char *lastChar;        /* Pointer to terminating character of
  268.                  * string. */
  269.     int flags;            /* Flags to control compilation (same as
  270.                  * passed to Tcl_Eval). */
  271.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  272. {
  273.     Interp *iPtr = (Interp *) interp;
  274.     ExprInfo info;
  275.     int maxDepth = 0;        /* Maximum number of stack elements needed
  276.                  * to execute the expression. */
  277.     int result;
  278.  
  279. #ifdef TCL_COMPILE_DEBUG
  280.     if (traceCompileExpr) {
  281.     fprintf(stderr, "expr: string=\"%.30s\"\n", string);
  282.     }
  283. #endif /* TCL_COMPILE_DEBUG */
  284.  
  285.     /*
  286.      * Register the builtin math functions the first time an expression is
  287.      * compiled.
  288.      */
  289.  
  290.     if (!(iPtr->flags & EXPR_INITIALIZED)) {
  291.     BuiltinFunc *funcPtr;
  292.     Tcl_HashEntry *hPtr;
  293.     MathFunc *mathFuncPtr;
  294.     int i;
  295.  
  296.     iPtr->flags |= EXPR_INITIALIZED;
  297.     i = 0;
  298.     for (funcPtr = builtinFuncTable; funcPtr->name != NULL; funcPtr++) {
  299.         Tcl_CreateMathFunc(interp, funcPtr->name,
  300.             funcPtr->numArgs, funcPtr->argTypes,
  301.             (Tcl_MathProc *) NULL, (ClientData) 0);
  302.         
  303.         hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcPtr->name);
  304.         if (hPtr == NULL) {
  305.         panic("TclCompileExpr: Tcl_CreateMathFunc incorrectly registered '%s'", funcPtr->name);
  306.         return TCL_ERROR;
  307.         }
  308.         mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
  309.         mathFuncPtr->builtinFuncIndex = i;
  310.         i++;
  311.     }
  312.     }
  313.  
  314.     info.token = UNKNOWN;
  315.     info.objIndex = -1;
  316.     info.funcName = NULL;
  317.     info.next = string;
  318.     info.originalExpr = string;
  319.     info.lastChar = lastChar;
  320.     info.hasOperators = 0;
  321.     info.exprIsJustVarRef = 1;    /* will be set 0 if anything else is seen */
  322.     info.exprIsComparison = 0;    /* set 1 if topmost operator is <,==,etc. */
  323.  
  324.     /*
  325.      * Get the first token then compile an expression.
  326.      */
  327.  
  328.     result = GetToken(interp, &info, envPtr);
  329.     if (result != TCL_OK) {
  330.     goto done;
  331.     }
  332.     
  333.     result = CompileCondExpr(interp, &info, flags, envPtr);
  334.     if (result != TCL_OK) {
  335.     goto done;
  336.     }
  337.     if (info.token != END) {
  338.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  339.         "syntax error in expression \"", string, "\"", (char *) NULL);
  340.     result = TCL_ERROR;
  341.     goto done;
  342.     }
  343.     if (!info.hasOperators) {
  344.     /*
  345.      * Attempt to convert the primary's object to an int or double.
  346.      * This is done in order to support Tcl's policy of interpreting
  347.      * operands if at all possible as first integers, else
  348.      * floating-point numbers.
  349.      */
  350.     
  351.     TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
  352.     }
  353.     maxDepth = envPtr->maxStackDepth;
  354.  
  355.     done:
  356.     envPtr->termOffset = (info.next - string);
  357.     envPtr->maxStackDepth = maxDepth;
  358.     envPtr->exprIsJustVarRef = info.exprIsJustVarRef;
  359.     envPtr->exprIsComparison = info.exprIsComparison;
  360.     return result;
  361. }
  362.  
  363. /*
  364.  *----------------------------------------------------------------------
  365.  *
  366.  * CompileCondExpr --
  367.  *
  368.  *    This procedure compiles a Tcl conditional expression:
  369.  *    condExpr ::= lorExpr ['?' condExpr ':' condExpr]
  370.  *
  371.  *    Note that this is the topmost recursive-descent parsing routine used
  372.  *    by TclCompileExpr to compile expressions. It does not call an
  373.  *    separate, higher-level "CompileExpr" procedure. This avoids an extra
  374.  *    procedure call since such a procedure would only return the result
  375.  *    of calling CompileCondExpr. Other recursive-descent procedures that
  376.  *    need to parse expressions also call CompileCondExpr.
  377.  *
  378.  * Results:
  379.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  380.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  381.  *    contains an error message.
  382.  *
  383.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  384.  *    elements needed to execute the expression.
  385.  *
  386.  * Side effects:
  387.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  388.  *
  389.  *----------------------------------------------------------------------
  390.  */
  391.  
  392. static int
  393. CompileCondExpr(interp, infoPtr, flags, envPtr)
  394.     Tcl_Interp *interp;        /* Used for error reporting. */
  395.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  396.                  * expression being compiled. */
  397.     int flags;            /* Flags to control compilation (same as
  398.                  * passed to Tcl_Eval). */
  399.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  400. {
  401.     int maxDepth = 0;        /* Maximum number of stack elements needed
  402.                  * to execute the expression. */
  403.     JumpFixup jumpAroundThenFixup, jumpAroundElseFixup;
  404.                 /* Used to update or replace one-byte jumps
  405.                  * around the then and else expressions when
  406.                  * their target PCs are determined. */
  407.     int elseCodeOffset, currCodeOffset, jumpDist, result;
  408.     
  409.     HERE("condExpr", 1);
  410.     result = CompileLorExpr(interp, infoPtr, flags, envPtr);
  411.     if (result != TCL_OK) {
  412.     goto done;
  413.     }
  414.     maxDepth = envPtr->maxStackDepth;
  415.     
  416.     if (infoPtr->token == QUESTY) {
  417.     result = GetToken(interp, infoPtr, envPtr); /* skip over the '?' */
  418.     if (result != TCL_OK) {
  419.         goto done;
  420.     }
  421.  
  422.     /*
  423.      * Emit the jump around the "then" clause to the "else" condExpr if
  424.      * the test was false. We emit a one byte (relative) jump here, and
  425.      * replace it later with a four byte jump if the jump target is more
  426.      * than 127 bytes away.
  427.      */
  428.  
  429.     TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpAroundThenFixup);
  430.  
  431.     /*
  432.      * Compile the "then" expression. Note that if a subexpression
  433.      * is only a primary, we need to try to convert it to numeric.
  434.      * This is done in order to support Tcl's policy of interpreting
  435.      * operands if at all possible as first integers, else
  436.      * floating-point numbers.
  437.      */
  438.  
  439.     infoPtr->hasOperators = 0;
  440.     infoPtr->exprIsJustVarRef = 0;
  441.     infoPtr->exprIsComparison = 0;
  442.     result = CompileCondExpr(interp, infoPtr, flags, envPtr);
  443.     if (result != TCL_OK) {
  444.         goto done;
  445.     }
  446.     maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
  447.     if (infoPtr->token != COLON) {
  448.         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  449.             "syntax error in expression \"", infoPtr->originalExpr,
  450.             "\"", (char *) NULL);
  451.         result = TCL_ERROR;
  452.         goto done;
  453.     }
  454.     if (!infoPtr->hasOperators) {
  455.         TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
  456.     }
  457.     result = GetToken(interp, infoPtr, envPtr); /* skip over the ':' */
  458.     if (result != TCL_OK) {
  459.         goto done;
  460.     }
  461.  
  462.     /*
  463.      * Emit an unconditional jump around the "else" condExpr.
  464.      */
  465.  
  466.     TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
  467.             &jumpAroundElseFixup);
  468.  
  469.     /*
  470.      * Compile the "else" expression.
  471.      */
  472.  
  473.     infoPtr->hasOperators = 0;
  474.     elseCodeOffset = TclCurrCodeOffset();
  475.     result = CompileCondExpr(interp, infoPtr, flags, envPtr);
  476.     if (result != TCL_OK) {
  477.         goto done;
  478.     }
  479.     maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
  480.     if (!infoPtr->hasOperators) {
  481.         TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
  482.     }
  483.  
  484.     /*
  485.      * Fix up the second jump: the unconditional jump around the "else"
  486.      * expression. If the distance is too great (> 127 bytes), replace
  487.      * it with a four byte instruction and move the instructions after
  488.      * the jump down.
  489.      */
  490.  
  491.     currCodeOffset = TclCurrCodeOffset();
  492.     jumpDist = (currCodeOffset - jumpAroundElseFixup.codeOffset);
  493.     if (TclFixupForwardJump(envPtr, &jumpAroundElseFixup, jumpDist, 127)) {
  494.         /*
  495.          * Update the else expression's starting code offset since it
  496.          * moved down 3 bytes too.
  497.          */
  498.         
  499.         elseCodeOffset += 3;
  500.     }
  501.     
  502.     /*
  503.      * Now fix up the first branch: the jumpFalse after the test. If the
  504.      * distance is too great, replace it with a four byte instruction
  505.      * and update the code offsets for the commands in both the "then"
  506.      * and "else" expressions.
  507.      */
  508.  
  509.     jumpDist = (elseCodeOffset - jumpAroundThenFixup.codeOffset);
  510.     TclFixupForwardJump(envPtr, &jumpAroundThenFixup, jumpDist, 127);
  511.  
  512.     infoPtr->hasOperators = 1;
  513.  
  514.     /*
  515.      * A comparison is not the top-level operator in this expression.
  516.      */
  517.  
  518.     infoPtr->exprIsComparison = 0;
  519.     }
  520.  
  521.     done:
  522.     envPtr->maxStackDepth = maxDepth;
  523.     return result;
  524. }
  525.  
  526. /*
  527.  *----------------------------------------------------------------------
  528.  *
  529.  * CompileLorExpr --
  530.  *
  531.  *    This procedure compiles a Tcl logical or expression:
  532.  *    lorExpr ::= landExpr {'||' landExpr}
  533.  *
  534.  * Results:
  535.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  536.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  537.  *    contains an error message.
  538.  *
  539.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  540.  *    elements needed to execute the expression.
  541.  *
  542.  * Side effects:
  543.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  544.  *
  545.  *----------------------------------------------------------------------
  546.  */
  547.  
  548. static int
  549. CompileLorExpr(interp, infoPtr, flags, envPtr)
  550.     Tcl_Interp *interp;        /* Used for error reporting. */
  551.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  552.                  * expression being compiled. */
  553.     int flags;            /* Flags to control compilation (same as
  554.                  * passed to Tcl_Eval). */
  555.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  556. {
  557.     int maxDepth;        /* Maximum number of stack elements needed
  558.                  * to execute the expression. */
  559.     JumpFixupArray jumpFixupArray;
  560.                 /* Used to fix up the forward "short
  561.                  * circuit" jump after each or-ed
  562.                  * subexpression to just after the last
  563.                  * subexpression. */
  564.     JumpFixup jumpTrueFixup, jumpFixup;
  565.                     /* Used to emit the jumps in the code to
  566.                  * convert the first operand to a 0 or 1. */
  567.     int fixupIndex, jumpDist, currCodeOffset, objIndex, j, result;
  568.     Tcl_Obj *objPtr;
  569.     
  570.     HERE("lorExpr", 2);
  571.     result = CompileLandExpr(interp, infoPtr, flags, envPtr);
  572.     if ((result != TCL_OK) || (infoPtr->token != OR)) {
  573.     return result;        /* envPtr->maxStackDepth is already set */
  574.     }
  575.  
  576.     infoPtr->hasOperators = 1;
  577.     infoPtr->exprIsJustVarRef = 0;
  578.     maxDepth = envPtr->maxStackDepth;
  579.     TclInitJumpFixupArray(&jumpFixupArray);
  580.     while (infoPtr->token == OR) {
  581.     result = GetToken(interp, infoPtr, envPtr); /* skip over the '||' */
  582.     if (result != TCL_OK) {
  583.         goto done;
  584.     }
  585.  
  586.     if (jumpFixupArray.next == 0) {
  587.         /*
  588.          * Just the first "lor" operand is on the stack. The following
  589.          * is slightly ugly: we need to convert that first "lor" operand
  590.          * to a "0" or "1" to get the correct result if it is nonzero.
  591.          * Eventually we'll use a new instruction for this.
  592.          */
  593.  
  594.         TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &jumpTrueFixup);
  595.         
  596.         objIndex = TclObjIndexForString("0", 1, /*allocStrRep*/ 0,
  597.                         /*inHeap*/ 0, envPtr);
  598.         objPtr = envPtr->objArrayPtr[objIndex];
  599.  
  600.         Tcl_InvalidateStringRep(objPtr);
  601.         objPtr->internalRep.longValue = 0;
  602.         objPtr->typePtr = &tclIntType;
  603.         
  604.         TclEmitPush(objIndex, envPtr);
  605.         TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
  606.  
  607.         jumpDist = (TclCurrCodeOffset() - jumpTrueFixup.codeOffset);
  608.         if (TclFixupForwardJump(envPtr, &jumpTrueFixup, jumpDist, 127)) {
  609.         panic("CompileLorExpr: bad jump distance %d\n", jumpDist);
  610.         }
  611.         objIndex = TclObjIndexForString("1", 1, /*allocStrRep*/ 0,
  612.                             /*inHeap*/ 0, envPtr);
  613.         objPtr = envPtr->objArrayPtr[objIndex];
  614.  
  615.         Tcl_InvalidateStringRep(objPtr);
  616.         objPtr->internalRep.longValue = 1;
  617.         objPtr->typePtr = &tclIntType;
  618.         
  619.         TclEmitPush(objIndex, envPtr);
  620.  
  621.         jumpDist = (TclCurrCodeOffset() - jumpFixup.codeOffset);
  622.         if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) {
  623.         panic("CompileLorExpr: bad jump distance %d\n", jumpDist);
  624.         }
  625.     }
  626.  
  627.     /*
  628.      * Duplicate the value on top of the stack to prevent the jump from
  629.      * consuming it.
  630.      */
  631.  
  632.     TclEmitOpcode(INST_DUP, envPtr);
  633.  
  634.     /*
  635.      * Emit the "short circuit" jump around the rest of the lorExp if
  636.      * the previous expression was true. We emit a one byte (relative)
  637.      * jump here, and replace it later with a four byte jump if the jump
  638.      * target is more than 127 bytes away.
  639.      */
  640.  
  641.     if (jumpFixupArray.next == jumpFixupArray.end) {
  642.         TclExpandJumpFixupArray(&jumpFixupArray);
  643.     }
  644.     fixupIndex = jumpFixupArray.next;
  645.     jumpFixupArray.next++;
  646.     TclEmitForwardJump(envPtr, TCL_TRUE_JUMP,
  647.             &(jumpFixupArray.fixup[fixupIndex]));
  648.     
  649.     /*
  650.      * Compile the subexpression.
  651.      */
  652.  
  653.     result = CompileLandExpr(interp, infoPtr, flags, envPtr);
  654.     if (result != TCL_OK) {
  655.         goto done;
  656.     }
  657.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  658.  
  659.     /*
  660.      * Emit a "logical or" instruction. This does not try to "short-
  661.      * circuit" the evaluation of both operands of a Tcl "||" operator,
  662.      * but instead ensures that we either have a "1" or a "0" result.
  663.      */
  664.  
  665.     TclEmitOpcode(INST_LOR, envPtr);
  666.     }
  667.  
  668.     /*
  669.      * Now that we know the target of the forward jumps, update the jumps
  670.      * with the correct distance. Also, if the distance is too great (> 127
  671.      * bytes), replace the jump with a four byte instruction and move the
  672.      * instructions after the jump down.
  673.      */
  674.     
  675.     for (j = jumpFixupArray.next;  j > 0;  j--) {
  676.     fixupIndex = (j - 1);    /* process closest jump first */
  677.     currCodeOffset = TclCurrCodeOffset();
  678.     jumpDist = (currCodeOffset - jumpFixupArray.fixup[fixupIndex].codeOffset);
  679.     TclFixupForwardJump(envPtr, &(jumpFixupArray.fixup[fixupIndex]), jumpDist, 127);
  680.     }
  681.  
  682.     /*
  683.      * We get here only if one or more ||'s appear as top-level operators.
  684.      */
  685.  
  686.     done:
  687.     infoPtr->exprIsComparison = 0;
  688.     TclFreeJumpFixupArray(&jumpFixupArray);
  689.     envPtr->maxStackDepth = maxDepth;
  690.     return result;
  691. }
  692.  
  693. /*
  694.  *----------------------------------------------------------------------
  695.  *
  696.  * CompileLandExpr --
  697.  *
  698.  *    This procedure compiles a Tcl logical and expression:
  699.  *    landExpr ::= bitOrExpr {'&&' bitOrExpr}
  700.  *
  701.  * Results:
  702.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  703.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  704.  *    contains an error message.
  705.  *
  706.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  707.  *    elements needed to execute the expression.
  708.  *
  709.  * Side effects:
  710.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  711.  *
  712.  *----------------------------------------------------------------------
  713.  */
  714.  
  715. static int
  716. CompileLandExpr(interp, infoPtr, flags, envPtr)
  717.     Tcl_Interp *interp;        /* Used for error reporting. */
  718.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  719.                  * expression being compiled. */
  720.     int flags;            /* Flags to control compilation (same as
  721.                  * passed to Tcl_Eval). */
  722.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  723. {
  724.     int maxDepth;        /* Maximum number of stack elements needed
  725.                  * to execute the expression. */
  726.     JumpFixupArray jumpFixupArray;
  727.                 /* Used to fix up the forward "short
  728.                  * circuit" jump after each and-ed
  729.                  * subexpression to just after the last
  730.                  * subexpression. */
  731.     JumpFixup jumpTrueFixup, jumpFixup;
  732.                     /* Used to emit the jumps in the code to
  733.                  * convert the first operand to a 0 or 1. */
  734.     int fixupIndex, jumpDist, currCodeOffset, objIndex, j, result;
  735.     Tcl_Obj *objPtr;
  736.  
  737.     HERE("landExpr", 3);
  738.     result = CompileBitOrExpr(interp, infoPtr, flags, envPtr);
  739.     if ((result != TCL_OK) || (infoPtr->token != AND)) {
  740.     return result;        /* envPtr->maxStackDepth is already set */
  741.     }
  742.  
  743.     infoPtr->hasOperators = 1;
  744.     infoPtr->exprIsJustVarRef = 0;
  745.     maxDepth = envPtr->maxStackDepth;
  746.     TclInitJumpFixupArray(&jumpFixupArray);
  747.     while (infoPtr->token == AND) {
  748.     result = GetToken(interp, infoPtr, envPtr); /* skip over the '&&' */
  749.     if (result != TCL_OK) {
  750.         goto done;
  751.     }
  752.  
  753.     if (jumpFixupArray.next == 0) {
  754.         /*
  755.          * Just the first "land" operand is on the stack. The following
  756.          * is slightly ugly: we need to convert the first "land" operand
  757.          * to a "0" or "1" to get the correct result if it is
  758.          * nonzero. Eventually we'll use a new instruction.
  759.          */
  760.  
  761.         TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &jumpTrueFixup);
  762.          
  763.         objIndex = TclObjIndexForString("0", 1, /*allocStrRep*/ 0,
  764.                             /*inHeap*/ 0, envPtr);
  765.         objPtr = envPtr->objArrayPtr[objIndex];
  766.  
  767.         Tcl_InvalidateStringRep(objPtr);
  768.         objPtr->internalRep.longValue = 0;
  769.         objPtr->typePtr = &tclIntType;
  770.         
  771.         TclEmitPush(objIndex, envPtr);
  772.         TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
  773.  
  774.         jumpDist = (TclCurrCodeOffset() - jumpTrueFixup.codeOffset);
  775.         if (TclFixupForwardJump(envPtr, &jumpTrueFixup, jumpDist, 127)) {
  776.         panic("CompileLandExpr: bad jump distance %d\n", jumpDist);
  777.         }
  778.         objIndex = TclObjIndexForString("1", 1, /*allocStrRep*/ 0,
  779.                             /*inHeap*/ 0, envPtr);
  780.         objPtr = envPtr->objArrayPtr[objIndex];
  781.  
  782.         Tcl_InvalidateStringRep(objPtr);
  783.         objPtr->internalRep.longValue = 1;
  784.         objPtr->typePtr = &tclIntType;
  785.         
  786.         TclEmitPush(objIndex, envPtr);
  787.  
  788.         jumpDist = (TclCurrCodeOffset() - jumpFixup.codeOffset);
  789.         if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) {
  790.         panic("CompileLandExpr: bad jump distance %d\n", jumpDist);
  791.         }
  792.     }
  793.  
  794.     /*
  795.      * Duplicate the value on top of the stack to prevent the jump from
  796.      * consuming it.
  797.      */
  798.  
  799.     TclEmitOpcode(INST_DUP, envPtr);
  800.  
  801.     /*
  802.      * Emit the "short circuit" jump around the rest of the landExp if
  803.      * the previous expression was false. We emit a one byte (relative)
  804.      * jump here, and replace it later with a four byte jump if the jump
  805.      * target is more than 127 bytes away.
  806.      */
  807.  
  808.     if (jumpFixupArray.next == jumpFixupArray.end) {
  809.         TclExpandJumpFixupArray(&jumpFixupArray);
  810.     }
  811.     fixupIndex = jumpFixupArray.next;
  812.     jumpFixupArray.next++;
  813.     TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
  814.         &(jumpFixupArray.fixup[fixupIndex]));
  815.     
  816.     /*
  817.      * Compile the subexpression.
  818.      */
  819.  
  820.     result = CompileBitOrExpr(interp, infoPtr, flags, envPtr);
  821.     if (result != TCL_OK) {
  822.         goto done;
  823.     }
  824.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  825.  
  826.     /*
  827.      * Emit a "logical and" instruction. This does not try to "short-
  828.      * circuit" the evaluation of both operands of a Tcl "&&" operator,
  829.      * but instead ensures that we either have a "1" or a "0" result.
  830.      */
  831.  
  832.     TclEmitOpcode(INST_LAND, envPtr);
  833.     }
  834.  
  835.     /*
  836.      * Now that we know the target of the forward jumps, update the jumps
  837.      * with the correct distance. Also, if the distance is too great (> 127
  838.      * bytes), replace the jump with a four byte instruction and move the
  839.      * instructions after the jump down.
  840.      */
  841.     
  842.     for (j = jumpFixupArray.next;  j > 0;  j--) {
  843.     fixupIndex = (j - 1);    /* process closest jump first */
  844.     currCodeOffset = TclCurrCodeOffset();
  845.     jumpDist = (currCodeOffset - jumpFixupArray.fixup[fixupIndex].codeOffset);
  846.     TclFixupForwardJump(envPtr, &(jumpFixupArray.fixup[fixupIndex]),
  847.             jumpDist, 127);
  848.     }
  849.  
  850.     /*
  851.      * We get here only if one or more &&'s appear as top-level operators.
  852.      */
  853.  
  854.     done:
  855.     infoPtr->exprIsComparison = 0;
  856.     TclFreeJumpFixupArray(&jumpFixupArray);
  857.     envPtr->maxStackDepth = maxDepth;
  858.     return result;
  859. }
  860.  
  861. /*
  862.  *----------------------------------------------------------------------
  863.  *
  864.  * CompileBitOrExpr --
  865.  *
  866.  *    This procedure compiles a Tcl bitwise or expression:
  867.  *    bitOrExpr ::= bitXorExpr {'|' bitXorExpr}
  868.  *
  869.  * Results:
  870.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  871.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  872.  *    contains an error message.
  873.  *
  874.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  875.  *    elements needed to execute the expression.
  876.  *
  877.  * Side effects:
  878.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  879.  *
  880.  *----------------------------------------------------------------------
  881.  */
  882.  
  883. static int
  884. CompileBitOrExpr(interp, infoPtr, flags, envPtr)
  885.     Tcl_Interp *interp;        /* Used for error reporting. */
  886.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  887.                  * expression being compiled. */
  888.     int flags;            /* Flags to control compilation (same as
  889.                  * passed to Tcl_Eval). */
  890.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  891. {
  892.     int maxDepth = 0;        /* Maximum number of stack elements needed
  893.                  * to execute the expression. */
  894.     int result;
  895.  
  896.     HERE("bitOrExpr", 4);
  897.     result = CompileBitXorExpr(interp, infoPtr, flags, envPtr);
  898.     if (result != TCL_OK) {
  899.     goto done;
  900.     }
  901.     maxDepth = envPtr->maxStackDepth;
  902.     
  903.     while (infoPtr->token == BIT_OR) {
  904.     infoPtr->hasOperators = 1;
  905.     infoPtr->exprIsJustVarRef = 0;
  906.     result = GetToken(interp, infoPtr, envPtr); /* skip over the '|' */
  907.     if (result != TCL_OK) {
  908.         goto done;
  909.     }
  910.  
  911.     result = CompileBitXorExpr(interp, infoPtr, flags, envPtr);
  912.     if (result != TCL_OK) {
  913.         goto done;
  914.     }
  915.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  916.     
  917.     TclEmitOpcode(INST_BITOR, envPtr);
  918.  
  919.     /*
  920.      * A comparison is not the top-level operator in this expression.
  921.      */
  922.  
  923.     infoPtr->exprIsComparison = 0;
  924.     }
  925.  
  926.     done:
  927.     envPtr->maxStackDepth = maxDepth;
  928.     return result;
  929. }
  930.  
  931. /*
  932.  *----------------------------------------------------------------------
  933.  *
  934.  * CompileBitXorExpr --
  935.  *
  936.  *    This procedure compiles a Tcl bitwise exclusive or expression:
  937.  *    bitXorExpr ::= bitAndExpr {'^' bitAndExpr}
  938.  *
  939.  * Results:
  940.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  941.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  942.  *    contains an error message.
  943.  *
  944.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  945.  *    elements needed to execute the expression.
  946.  *
  947.  * Side effects:
  948.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  949.  *
  950.  *----------------------------------------------------------------------
  951.  */
  952.  
  953. static int
  954. CompileBitXorExpr(interp, infoPtr, flags, envPtr)
  955.     Tcl_Interp *interp;        /* Used for error reporting. */
  956.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  957.                  * expression being compiled. */
  958.     int flags;            /* Flags to control compilation (same as
  959.                  * passed to Tcl_Eval). */
  960.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  961. {
  962.     int maxDepth = 0;        /* Maximum number of stack elements needed
  963.                  * to execute the expression. */
  964.     int result;
  965.  
  966.     HERE("bitXorExpr", 5);
  967.     result = CompileBitAndExpr(interp, infoPtr, flags, envPtr);
  968.     if (result != TCL_OK) {
  969.     goto done;
  970.     }
  971.     maxDepth = envPtr->maxStackDepth;
  972.     
  973.     while (infoPtr->token == BIT_XOR) {
  974.     infoPtr->hasOperators = 1;
  975.     infoPtr->exprIsJustVarRef = 0;
  976.     result = GetToken(interp, infoPtr, envPtr); /* skip over the '^' */
  977.     if (result != TCL_OK) {
  978.         goto done;
  979.     }
  980.  
  981.     result = CompileBitAndExpr(interp, infoPtr, flags, envPtr);
  982.     if (result != TCL_OK) {
  983.         goto done;
  984.     }
  985.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  986.     
  987.     TclEmitOpcode(INST_BITXOR, envPtr);
  988.  
  989.     /*
  990.      * A comparison is not the top-level operator in this expression.
  991.      */
  992.  
  993.     infoPtr->exprIsComparison = 0;
  994.     }
  995.  
  996.     done:
  997.     envPtr->maxStackDepth = maxDepth;
  998.     return result;
  999. }
  1000.  
  1001. /*
  1002.  *----------------------------------------------------------------------
  1003.  *
  1004.  * CompileBitAndExpr --
  1005.  *
  1006.  *    This procedure compiles a Tcl bitwise and expression:
  1007.  *    bitAndExpr ::= equalityExpr {'&' equalityExpr}
  1008.  *
  1009.  * Results:
  1010.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  1011.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  1012.  *    contains an error message.
  1013.  *
  1014.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  1015.  *    elements needed to execute the expression.
  1016.  *
  1017.  * Side effects:
  1018.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  1019.  *
  1020.  *----------------------------------------------------------------------
  1021.  */
  1022.  
  1023. static int
  1024. CompileBitAndExpr(interp, infoPtr, flags, envPtr)
  1025.     Tcl_Interp *interp;        /* Used for error reporting. */
  1026.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  1027.                  * expression being compiled. */
  1028.     int flags;            /* Flags to control compilation (same as
  1029.                  * passed to Tcl_Eval). */
  1030.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  1031. {
  1032.     int maxDepth = 0;        /* Maximum number of stack elements needed
  1033.                  * to execute the expression. */
  1034.     int result;
  1035.  
  1036.     HERE("bitAndExpr", 6);
  1037.     result = CompileEqualityExpr(interp, infoPtr, flags, envPtr);
  1038.     if (result != TCL_OK) {
  1039.     goto done;
  1040.     }
  1041.     maxDepth = envPtr->maxStackDepth;
  1042.     
  1043.     while (infoPtr->token == BIT_AND) {
  1044.     infoPtr->hasOperators = 1;
  1045.     infoPtr->exprIsJustVarRef = 0;
  1046.     result = GetToken(interp, infoPtr, envPtr); /* skip over the '&' */
  1047.     if (result != TCL_OK) {
  1048.         goto done;
  1049.     }
  1050.  
  1051.     result = CompileEqualityExpr(interp, infoPtr, flags, envPtr);
  1052.     if (result != TCL_OK) {
  1053.         goto done;
  1054.     }
  1055.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  1056.     
  1057.     TclEmitOpcode(INST_BITAND, envPtr);
  1058.  
  1059.     /*
  1060.      * A comparison is not the top-level operator in this expression.
  1061.      */
  1062.  
  1063.     infoPtr->exprIsComparison = 0;
  1064.     }
  1065.  
  1066.     done:
  1067.     envPtr->maxStackDepth = maxDepth;
  1068.     return result;
  1069. }
  1070.  
  1071. /*
  1072.  *----------------------------------------------------------------------
  1073.  *
  1074.  * CompileEqualityExpr --
  1075.  *
  1076.  *    This procedure compiles a Tcl equality (inequality) expression:
  1077.  *    equalityExpr ::= relationalExpr {('==' | '!=') relationalExpr}
  1078.  *
  1079.  * Results:
  1080.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  1081.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  1082.  *    contains an error message.
  1083.  *
  1084.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  1085.  *    elements needed to execute the expression.
  1086.  *
  1087.  * Side effects:
  1088.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  1089.  *
  1090.  *----------------------------------------------------------------------
  1091.  */
  1092.  
  1093. static int
  1094. CompileEqualityExpr(interp, infoPtr, flags, envPtr)
  1095.     Tcl_Interp *interp;        /* Used for error reporting. */
  1096.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  1097.                  * expression being compiled. */
  1098.     int flags;            /* Flags to control compilation (same as
  1099.                  * passed to Tcl_Eval). */
  1100.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  1101. {
  1102.     int maxDepth = 0;        /* Maximum number of stack elements needed
  1103.                  * to execute the expression. */
  1104.     int op, result;
  1105.  
  1106.     HERE("equalityExpr", 7);
  1107.     result = CompileRelationalExpr(interp, infoPtr, flags, envPtr);
  1108.     if (result != TCL_OK) {
  1109.     goto done;
  1110.     }
  1111.     maxDepth = envPtr->maxStackDepth;
  1112.  
  1113.     op = infoPtr->token;
  1114.     while ((op == EQUAL) || (op == NEQ)) {
  1115.     infoPtr->hasOperators = 1;
  1116.     infoPtr->exprIsJustVarRef = 0;
  1117.     result = GetToken(interp, infoPtr, envPtr); /* skip over == or != */
  1118.     if (result != TCL_OK) {
  1119.         goto done;
  1120.     }
  1121.  
  1122.     result = CompileRelationalExpr(interp, infoPtr, flags, envPtr);
  1123.     if (result != TCL_OK) {
  1124.         goto done;
  1125.     }
  1126.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  1127.  
  1128.     if (op == EQUAL) {
  1129.         TclEmitOpcode(INST_EQ, envPtr);
  1130.     } else {
  1131.         TclEmitOpcode(INST_NEQ, envPtr);
  1132.     }
  1133.     
  1134.     op = infoPtr->token;
  1135.  
  1136.     /*
  1137.      * A comparison _is_ the top-level operator in this expression.
  1138.      */
  1139.     
  1140.     infoPtr->exprIsComparison = 1;
  1141.     }
  1142.  
  1143.     done:
  1144.     envPtr->maxStackDepth = maxDepth;
  1145.     return result;
  1146. }
  1147.  
  1148. /*
  1149.  *----------------------------------------------------------------------
  1150.  *
  1151.  * CompileRelationalExpr --
  1152.  *
  1153.  *    This procedure compiles a Tcl relational expression:
  1154.  *    relationalExpr ::= shiftExpr {('<' | '>' | '<=' | '>=') shiftExpr}
  1155.  *
  1156.  * Results:
  1157.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  1158.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  1159.  *    contains an error message.
  1160.  *
  1161.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  1162.  *    elements needed to execute the expression.
  1163.  *
  1164.  * Side effects:
  1165.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  1166.  *
  1167.  *----------------------------------------------------------------------
  1168.  */
  1169.  
  1170. static int
  1171. CompileRelationalExpr(interp, infoPtr, flags, envPtr)
  1172.     Tcl_Interp *interp;        /* Used for error reporting. */
  1173.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  1174.                  * expression being compiled. */
  1175.     int flags;            /* Flags to control compilation (same as
  1176.                  * passed to Tcl_Eval). */
  1177.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  1178. {
  1179.     int maxDepth = 0;        /* Maximum number of stack elements needed
  1180.                  * to execute the expression. */
  1181.     int op, result;
  1182.  
  1183.     HERE("relationalExpr", 8);
  1184.     result = CompileShiftExpr(interp, infoPtr, flags, envPtr);
  1185.     if (result != TCL_OK) {
  1186.     goto done;
  1187.     }
  1188.     maxDepth = envPtr->maxStackDepth;
  1189.  
  1190.     op = infoPtr->token;
  1191.     while ((op == LESS) || (op == GREATER) || (op == LEQ) || (op == GEQ)) {
  1192.     infoPtr->hasOperators = 1;
  1193.     infoPtr->exprIsJustVarRef = 0;
  1194.     result = GetToken(interp, infoPtr, envPtr); /* skip over the op */
  1195.     if (result != TCL_OK) {
  1196.         goto done;
  1197.     }
  1198.  
  1199.     result = CompileShiftExpr(interp, infoPtr, flags, envPtr);
  1200.     if (result != TCL_OK) {
  1201.         goto done;
  1202.     }
  1203.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  1204.  
  1205.     switch (op) {
  1206.     case LESS:
  1207.         TclEmitOpcode(INST_LT, envPtr);
  1208.         break;
  1209.     case GREATER:
  1210.         TclEmitOpcode(INST_GT, envPtr);
  1211.         break;
  1212.     case LEQ:
  1213.         TclEmitOpcode(INST_LE, envPtr);
  1214.         break;
  1215.     case GEQ:
  1216.         TclEmitOpcode(INST_GE, envPtr);
  1217.         break;
  1218.     }
  1219.  
  1220.     op = infoPtr->token;
  1221.  
  1222.     /*
  1223.      * A comparison _is_ the top-level operator in this expression.
  1224.      */
  1225.     
  1226.     infoPtr->exprIsComparison = 1;
  1227.     }
  1228.  
  1229.     done:
  1230.     envPtr->maxStackDepth = maxDepth;
  1231.     return result;
  1232. }
  1233.  
  1234. /*
  1235.  *----------------------------------------------------------------------
  1236.  *
  1237.  * CompileShiftExpr --
  1238.  *
  1239.  *    This procedure compiles a Tcl shift expression:
  1240.  *    shiftExpr ::= addExpr {('<<' | '>>') addExpr}
  1241.  *
  1242.  * Results:
  1243.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  1244.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  1245.  *    contains an error message.
  1246.  *
  1247.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  1248.  *    elements needed to execute the expression.
  1249.  *
  1250.  * Side effects:
  1251.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  1252.  *
  1253.  *----------------------------------------------------------------------
  1254.  */
  1255.  
  1256. static int
  1257. CompileShiftExpr(interp, infoPtr, flags, envPtr)
  1258.     Tcl_Interp *interp;        /* Used for error reporting. */
  1259.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  1260.                  * expression being compiled. */
  1261.     int flags;            /* Flags to control compilation (same as
  1262.                  * passed to Tcl_Eval). */
  1263.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  1264. {
  1265.     int maxDepth = 0;        /* Maximum number of stack elements needed
  1266.                  * to execute the expression. */
  1267.     int op, result;
  1268.  
  1269.     HERE("shiftExpr", 9);
  1270.     result = CompileAddExpr(interp, infoPtr, flags, envPtr);
  1271.     if (result != TCL_OK) {
  1272.     goto done;
  1273.     }
  1274.     maxDepth = envPtr->maxStackDepth;
  1275.  
  1276.     op = infoPtr->token;
  1277.     while ((op == LEFT_SHIFT) || (op == RIGHT_SHIFT)) {
  1278.     infoPtr->hasOperators = 1;
  1279.     infoPtr->exprIsJustVarRef = 0;
  1280.     result = GetToken(interp, infoPtr, envPtr); /* skip over << or >> */
  1281.     if (result != TCL_OK) {
  1282.         goto done;
  1283.     }
  1284.  
  1285.     result = CompileAddExpr(interp, infoPtr, flags, envPtr);
  1286.     if (result != TCL_OK) {
  1287.         goto done;
  1288.     }
  1289.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  1290.  
  1291.     if (op == LEFT_SHIFT) {
  1292.         TclEmitOpcode(INST_LSHIFT, envPtr);
  1293.     } else {
  1294.         TclEmitOpcode(INST_RSHIFT, envPtr);
  1295.     }
  1296.  
  1297.     op = infoPtr->token;
  1298.  
  1299.     /*
  1300.      * A comparison is not the top-level operator in this expression.
  1301.      */
  1302.  
  1303.     infoPtr->exprIsComparison = 0;
  1304.     }
  1305.  
  1306.     done:
  1307.     envPtr->maxStackDepth = maxDepth;
  1308.     return result;
  1309. }
  1310.  
  1311. /*
  1312.  *----------------------------------------------------------------------
  1313.  *
  1314.  * CompileAddExpr --
  1315.  *
  1316.  *    This procedure compiles a Tcl addition expression:
  1317.  *    addExpr ::= multiplyExpr {('+' | '-') multiplyExpr}
  1318.  *
  1319.  * Results:
  1320.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  1321.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  1322.  *    contains an error message.
  1323.  *
  1324.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  1325.  *    elements needed to execute the expression.
  1326.  *
  1327.  * Side effects:
  1328.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  1329.  *
  1330.  *----------------------------------------------------------------------
  1331.  */
  1332.  
  1333. static int
  1334. CompileAddExpr(interp, infoPtr, flags, envPtr)
  1335.     Tcl_Interp *interp;        /* Used for error reporting. */
  1336.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  1337.                  * expression being compiled. */
  1338.     int flags;            /* Flags to control compilation (same as
  1339.                  * passed to Tcl_Eval). */
  1340.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  1341. {
  1342.     int maxDepth = 0;        /* Maximum number of stack elements needed
  1343.                  * to execute the expression. */
  1344.     int op, result;
  1345.  
  1346.     HERE("addExpr", 10);
  1347.     result = CompileMultiplyExpr(interp, infoPtr, flags, envPtr);
  1348.     if (result != TCL_OK) {
  1349.     goto done;
  1350.     }
  1351.     maxDepth = envPtr->maxStackDepth;
  1352.  
  1353.     op = infoPtr->token;
  1354.     while ((op == PLUS) || (op == MINUS)) {
  1355.     infoPtr->hasOperators = 1;
  1356.     infoPtr->exprIsJustVarRef = 0;
  1357.     result = GetToken(interp, infoPtr, envPtr); /* skip over + or - */
  1358.     if (result != TCL_OK) {
  1359.         goto done;
  1360.     }
  1361.  
  1362.     result = CompileMultiplyExpr(interp, infoPtr, flags, envPtr);
  1363.     if (result != TCL_OK) {
  1364.         goto done;
  1365.     }
  1366.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  1367.  
  1368.     if (op == PLUS) {
  1369.         TclEmitOpcode(INST_ADD, envPtr);
  1370.     } else {
  1371.         TclEmitOpcode(INST_SUB, envPtr);
  1372.     }
  1373.  
  1374.     op = infoPtr->token;
  1375.  
  1376.     /*
  1377.      * A comparison is not the top-level operator in this expression.
  1378.      */
  1379.  
  1380.     infoPtr->exprIsComparison = 0;
  1381.     }
  1382.  
  1383.     done:
  1384.     envPtr->maxStackDepth = maxDepth;
  1385.     return result;
  1386. }
  1387.  
  1388. /*
  1389.  *----------------------------------------------------------------------
  1390.  *
  1391.  * CompileMultiplyExpr --
  1392.  *
  1393.  *    This procedure compiles a Tcl multiply expression:
  1394.  *    multiplyExpr ::= unaryExpr {('*' | '/' | '%') unaryExpr}
  1395.  *
  1396.  * Results:
  1397.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  1398.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  1399.  *    contains an error message.
  1400.  *
  1401.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  1402.  *    elements needed to execute the expression.
  1403.  *
  1404.  * Side effects:
  1405.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  1406.  *
  1407.  *----------------------------------------------------------------------
  1408.  */
  1409.  
  1410. static int
  1411. CompileMultiplyExpr(interp, infoPtr, flags, envPtr)
  1412.     Tcl_Interp *interp;        /* Used for error reporting. */
  1413.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  1414.                  * expression being compiled. */
  1415.     int flags;            /* Flags to control compilation (same as
  1416.                  * passed to Tcl_Eval). */
  1417.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  1418. {
  1419.     int maxDepth = 0;        /* Maximum number of stack elements needed
  1420.                  * to execute the expression. */
  1421.     int op, result;
  1422.  
  1423.     HERE("multiplyExpr", 11);
  1424.     result = CompileUnaryExpr(interp, infoPtr, flags, envPtr);
  1425.     if (result != TCL_OK) {
  1426.     goto done;
  1427.     }
  1428.     maxDepth = envPtr->maxStackDepth;
  1429.  
  1430.     op = infoPtr->token;
  1431.     while ((op == MULT) || (op == DIVIDE) || (op == MOD)) {
  1432.     infoPtr->hasOperators = 1;
  1433.     infoPtr->exprIsJustVarRef = 0;
  1434.     result = GetToken(interp, infoPtr, envPtr); /* skip over * or / */
  1435.     if (result != TCL_OK) {
  1436.         goto done;
  1437.     }
  1438.  
  1439.     result = CompileUnaryExpr(interp, infoPtr, flags, envPtr);
  1440.     if (result != TCL_OK) {
  1441.         goto done;
  1442.     }
  1443.     maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
  1444.  
  1445.     if (op == MULT) {
  1446.         TclEmitOpcode(INST_MULT, envPtr);
  1447.     } else if (op == DIVIDE) {
  1448.         TclEmitOpcode(INST_DIV, envPtr);
  1449.     } else {
  1450.         TclEmitOpcode(INST_MOD, envPtr);
  1451.     }
  1452.  
  1453.     op = infoPtr->token;
  1454.  
  1455.     /*
  1456.      * A comparison is not the top-level operator in this expression.
  1457.      */
  1458.  
  1459.     infoPtr->exprIsComparison = 0;
  1460.     }
  1461.  
  1462.     done:
  1463.     envPtr->maxStackDepth = maxDepth;
  1464.     return result;
  1465. }
  1466.  
  1467. /*
  1468.  *----------------------------------------------------------------------
  1469.  *
  1470.  * CompileUnaryExpr --
  1471.  *
  1472.  *    This procedure compiles a Tcl unary expression:
  1473.  *    unaryExpr ::= ('+' | '-' | '~' | '!') unaryExpr | primaryExpr
  1474.  *
  1475.  * Results:
  1476.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  1477.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  1478.  *    contains an error message.
  1479.  *
  1480.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  1481.  *    elements needed to execute the expression.
  1482.  *
  1483.  * Side effects:
  1484.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  1485.  *
  1486.  *----------------------------------------------------------------------
  1487.  */
  1488.  
  1489. static int
  1490. CompileUnaryExpr(interp, infoPtr, flags, envPtr)
  1491.     Tcl_Interp *interp;        /* Used for error reporting. */
  1492.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  1493.                  * expression being compiled. */
  1494.     int flags;            /* Flags to control compilation (same as
  1495.                  * passed to Tcl_Eval). */
  1496.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  1497. {
  1498.     int maxDepth = 0;        /* Maximum number of stack elements needed
  1499.                  * to execute the expression. */
  1500.     int op, result;
  1501.  
  1502.     HERE("unaryExpr", 12);
  1503.     op = infoPtr->token;
  1504.     if ((op == PLUS) || (op == MINUS) || (op == BIT_NOT) || (op == NOT)) {
  1505.     infoPtr->hasOperators = 1;
  1506.     infoPtr->exprIsJustVarRef = 0;
  1507.     result = GetToken(interp, infoPtr, envPtr); /* skip over the op */
  1508.     if (result != TCL_OK) {
  1509.         goto done;
  1510.     }
  1511.  
  1512.     result = CompileUnaryExpr(interp, infoPtr, flags, envPtr);
  1513.     if (result != TCL_OK) {
  1514.         goto done;
  1515.     }
  1516.     maxDepth = envPtr->maxStackDepth;
  1517.  
  1518.     switch (op) {
  1519.     case PLUS:
  1520.         TclEmitOpcode(INST_UPLUS, envPtr);
  1521.         break;
  1522.     case MINUS:
  1523.         TclEmitOpcode(INST_UMINUS, envPtr);
  1524.         break;
  1525.     case BIT_NOT:
  1526.         TclEmitOpcode(INST_BITNOT, envPtr);
  1527.         break;
  1528.     case NOT:
  1529.         TclEmitOpcode(INST_LNOT, envPtr);
  1530.         break;
  1531.     }
  1532.  
  1533.     /*
  1534.      * A comparison is not the top-level operator in this expression.
  1535.      */
  1536.  
  1537.     infoPtr->exprIsComparison = 0;
  1538.     } else {            /* must be a primaryExpr */
  1539.     result = CompilePrimaryExpr(interp, infoPtr, flags, envPtr);
  1540.     if (result != TCL_OK) {
  1541.         goto done;
  1542.     }
  1543.     maxDepth = envPtr->maxStackDepth;
  1544.     }
  1545.  
  1546.     done:
  1547.     envPtr->maxStackDepth = maxDepth;
  1548.     return result;
  1549. }
  1550.  
  1551. /*
  1552.  *----------------------------------------------------------------------
  1553.  *
  1554.  * CompilePrimaryExpr --
  1555.  *
  1556.  *    This procedure compiles a Tcl primary expression:
  1557.  *    primaryExpr ::= literal | varReference | quotedString |
  1558.  *            '[' command ']' | mathFuncCall | '(' condExpr ')'
  1559.  *
  1560.  * Results:
  1561.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  1562.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  1563.  *    contains an error message.
  1564.  *
  1565.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  1566.  *    elements needed to execute the expression.
  1567.  *
  1568.  * Side effects:
  1569.  *    Adds instructions to envPtr to evaluate the expression at runtime.
  1570.  *
  1571.  *----------------------------------------------------------------------
  1572.  */
  1573.  
  1574. static int
  1575. CompilePrimaryExpr(interp, infoPtr, flags, envPtr)
  1576.     Tcl_Interp *interp;        /* Used for error reporting. */
  1577.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  1578.                  * expression being compiled. */
  1579.     int flags;            /* Flags to control compilation (same as
  1580.                  * passed to Tcl_Eval). */
  1581.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  1582. {
  1583.     int maxDepth = 0;        /* Maximum number of stack elements needed
  1584.                  * to execute the expression. */
  1585.     int theToken;
  1586.     char *dollarPtr, *quotePtr, *cmdPtr, *termPtr;
  1587.     int result = TCL_OK;
  1588.  
  1589.     /*
  1590.      * We emit tryCvtToNumeric instructions after most of these primary
  1591.      * expressions in order to support Tcl's policy of interpreting operands
  1592.      * as first integers if possible, otherwise floating-point numbers if
  1593.      * possible.
  1594.      */
  1595.  
  1596.     HERE("primaryExpr", 13);
  1597.     theToken = infoPtr->token;
  1598.  
  1599.     if (theToken != DOLLAR) {
  1600.     infoPtr->exprIsJustVarRef = 0;
  1601.     }
  1602.     switch (theToken) {
  1603.     case LITERAL:        /* int, double, or string in braces */
  1604.     TclEmitPush(infoPtr->objIndex, envPtr);
  1605.     maxDepth = 1;
  1606.     break;
  1607.     
  1608.     case DOLLAR:        /* $var variable reference */
  1609.     dollarPtr = (infoPtr->next - 1);
  1610.     envPtr->pushSimpleWords = 1;
  1611.     result = TclCompileDollarVar(interp, dollarPtr,
  1612.         infoPtr->lastChar, flags, envPtr);
  1613.     if (result != TCL_OK) {
  1614.         goto done;
  1615.     }
  1616.     maxDepth = envPtr->maxStackDepth;
  1617.     infoPtr->next = (dollarPtr + envPtr->termOffset);
  1618.     break;
  1619.     
  1620.     case QUOTE:            /* quotedString */
  1621.     quotePtr = infoPtr->next;
  1622.     envPtr->pushSimpleWords = 1;
  1623.     result = TclCompileQuotes(interp, quotePtr,
  1624.         infoPtr->lastChar, '"', flags, envPtr);
  1625.     if (result != TCL_OK) {
  1626.         goto done;
  1627.     }
  1628.     maxDepth = envPtr->maxStackDepth;
  1629.     infoPtr->next = (quotePtr + envPtr->termOffset);
  1630.     break;
  1631.     
  1632.     case OPEN_BRACKET:        /* '[' command ']' */
  1633.     cmdPtr = infoPtr->next;
  1634.     envPtr->pushSimpleWords = 1;
  1635.     result = TclCompileString(interp, cmdPtr,
  1636.         infoPtr->lastChar, (flags | TCL_BRACKET_TERM), envPtr);
  1637.     if (result != TCL_OK) {
  1638.         goto done;
  1639.     }
  1640.     termPtr = (cmdPtr + envPtr->termOffset);
  1641.     if (*termPtr == ']') {
  1642.         infoPtr->next = (termPtr + 1); /* advance over the ']'. */
  1643.     } else if (termPtr == infoPtr->lastChar) {
  1644.         /*
  1645.          * Missing ] at end of nested command.
  1646.          */
  1647.         
  1648.         Tcl_ResetResult(interp);
  1649.         Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1650.                 "missing close-bracket", -1);
  1651.         result = TCL_ERROR;
  1652.         goto done;
  1653.     } else {
  1654.         panic("CompilePrimaryExpr: unexpected termination char '%c' for nested command\n", *termPtr);
  1655.     }
  1656.     maxDepth = envPtr->maxStackDepth;
  1657.     break;
  1658.     
  1659.     case FUNC_NAME:
  1660.     result = CompileMathFuncCall(interp, infoPtr, flags, envPtr);
  1661.     if (result != TCL_OK) {
  1662.         goto done;
  1663.     }
  1664.     maxDepth = envPtr->maxStackDepth;
  1665.     break;
  1666.     
  1667.     case OPEN_PAREN:
  1668.     result = GetToken(interp, infoPtr, envPtr); /* skip over the '(' */
  1669.     if (result != TCL_OK) {
  1670.         goto done;
  1671.     }
  1672.     infoPtr->exprIsComparison = 0;
  1673.     result = CompileCondExpr(interp, infoPtr, flags, envPtr);
  1674.     if (result != TCL_OK) {
  1675.         goto done;
  1676.     }
  1677.     maxDepth = envPtr->maxStackDepth;
  1678.     if (infoPtr->token != CLOSE_PAREN) {
  1679.         goto syntaxError;
  1680.     }
  1681.     break;
  1682.     
  1683.     default:
  1684.     goto syntaxError;
  1685.     }
  1686.  
  1687.     if (theToken != FUNC_NAME) {
  1688.     /*
  1689.      * Advance to the next token before returning.
  1690.      */
  1691.     
  1692.     result = GetToken(interp, infoPtr, envPtr);
  1693.     if (result != TCL_OK) {
  1694.         goto done;
  1695.     }
  1696.     }
  1697.  
  1698.     done:
  1699.     envPtr->maxStackDepth = maxDepth;
  1700.     return result;
  1701.  
  1702.     syntaxError:
  1703.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1704.         "syntax error in expression \"", infoPtr->originalExpr,
  1705.         "\"", (char *) NULL);
  1706.     return TCL_ERROR;
  1707. }
  1708.  
  1709. /*
  1710.  *----------------------------------------------------------------------
  1711.  *
  1712.  * CompileMathFuncCall --
  1713.  *
  1714.  *    This procedure compiles a call on a math function in an expression:
  1715.  *    mathFuncCall ::= funcName '(' [condExpr {',' condExpr}] ')'
  1716.  *
  1717.  * Results:
  1718.  *    The return value is TCL_OK on a successful compilation and TCL_ERROR
  1719.  *    on failure. If TCL_ERROR is returned, then the interpreter's result
  1720.  *    contains an error message.
  1721.  *
  1722.  *    envPtr->maxStackDepth is updated with the maximum number of stack
  1723.  *    elements needed to execute the function.
  1724.  *
  1725.  * Side effects:
  1726.  *    Adds instructions to envPtr to evaluate the math function at
  1727.  *    runtime.
  1728.  *
  1729.  *----------------------------------------------------------------------
  1730.  */
  1731.  
  1732. static int
  1733. CompileMathFuncCall(interp, infoPtr, flags, envPtr)
  1734.     Tcl_Interp *interp;        /* Used for error reporting. */
  1735.     ExprInfo *infoPtr;        /* Describes the compilation state for the
  1736.                  * expression being compiled. */
  1737.     int flags;            /* Flags to control compilation (same as
  1738.                  * passed to Tcl_Eval). */
  1739.     CompileEnv *envPtr;        /* Holds resulting instructions. */
  1740. {
  1741.     Interp *iPtr = (Interp *) interp;
  1742.     int maxDepth = 0;        /* Maximum number of stack elements needed
  1743.                  * to execute the expression. */
  1744.     MathFunc *mathFuncPtr;    /* Info about math function. */
  1745.     int objIndex;        /* The object array index for an object
  1746.                  * holding the function name if it is not
  1747.                  * builtin. */
  1748.     Tcl_HashEntry *hPtr;
  1749.     char *p, *funcName;
  1750.     char savedChar;
  1751.     int result, i;
  1752.  
  1753.     /*
  1754.      * infoPtr->funcName points to the first character of the math
  1755.      * function's name. Look for the end of its name and look up the
  1756.      * MathFunc record for the function.
  1757.      */
  1758.  
  1759.     funcName = p = infoPtr->funcName;
  1760.     while (isalnum(UCHAR(*p)) || (*p == '_')) {
  1761.     p++;
  1762.     }
  1763.     infoPtr->next = p;
  1764.     
  1765.     result = GetToken(interp, infoPtr, envPtr); /* skip over func name */
  1766.     if (result != TCL_OK) {
  1767.     goto done;
  1768.     }
  1769.     if (infoPtr->token != OPEN_PAREN) {
  1770.     goto syntaxError;
  1771.     }
  1772.     result = GetToken(interp, infoPtr, envPtr); /* skip over '(' */
  1773.     if (result != TCL_OK) {
  1774.     goto done;
  1775.     }
  1776.     
  1777.     savedChar = *p;
  1778.     *p = 0;
  1779.     hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcName);
  1780.     if (hPtr == NULL) {
  1781.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1782.         "unknown math function \"", funcName, "\"", (char *) NULL);
  1783.     result = TCL_ERROR;
  1784.     *p = savedChar;
  1785.     goto done;
  1786.     }
  1787.     mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
  1788.  
  1789.     /*
  1790.      * If not a builtin function, push an object with the function's name.
  1791.      */
  1792.  
  1793.     if (mathFuncPtr->builtinFuncIndex < 0) {   /* not builtin */
  1794.     objIndex = TclObjIndexForString(funcName, -1, /*allocStrRep*/ 1,
  1795.                         /*inHeap*/ 0, envPtr);
  1796.     TclEmitPush(objIndex, envPtr);
  1797.     maxDepth = 1;
  1798.     }
  1799.  
  1800.     /*
  1801.      * Restore the saved character after the function name.
  1802.      */
  1803.  
  1804.     *p = savedChar;
  1805.  
  1806.     /*
  1807.      * Compile the arguments for the function, if there are any.
  1808.      */
  1809.  
  1810.     if (mathFuncPtr->numArgs > 0) {
  1811.     for (i = 0;  ;  i++) {
  1812.         infoPtr->exprIsComparison = 0;
  1813.         result = CompileCondExpr(interp, infoPtr, flags, envPtr);
  1814.         if (result != TCL_OK) {
  1815.         goto done;
  1816.         }
  1817.     
  1818.         /*
  1819.          * Check for a ',' between arguments or a ')' ending the
  1820.          * argument list.
  1821.          */
  1822.     
  1823.         if (i == (mathFuncPtr->numArgs-1)) {
  1824.         if (infoPtr->token == CLOSE_PAREN) {
  1825.             break;    /* exit the argument parsing loop */
  1826.         } else if (infoPtr->token == COMMA) {
  1827.             Tcl_ResetResult(interp);
  1828.             Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1829.                     "too many arguments for math function", -1);
  1830.             result = TCL_ERROR;
  1831.             goto done;
  1832.         } else {
  1833.             goto syntaxError;
  1834.         }
  1835.         }
  1836.         if (infoPtr->token != COMMA) {
  1837.         if (infoPtr->token == CLOSE_PAREN) {
  1838.             Tcl_ResetResult(interp);
  1839.             Tcl_AppendToObj(Tcl_GetObjResult(interp),
  1840.                     "too few arguments for math function", -1);
  1841.             result = TCL_ERROR;
  1842.             goto done;
  1843.         } else {
  1844.             goto syntaxError;
  1845.         }
  1846.         }
  1847.         result = GetToken(interp, infoPtr, envPtr); /* skip over , */
  1848.         if (result != TCL_OK) {
  1849.         goto done;
  1850.         }
  1851.         maxDepth++;
  1852.     }
  1853.     }
  1854.  
  1855.     if (infoPtr->token != CLOSE_PAREN) {
  1856.     goto syntaxError;
  1857.     }
  1858.     result = GetToken(interp, infoPtr, envPtr); /* skip over ')' */
  1859.     if (result != TCL_OK) {
  1860.     goto done;
  1861.     }
  1862.     
  1863.     /*
  1864.      * Compile the call on the math function. Note that the "objc" argument
  1865.      * count for non-builtin functions is incremented by 1 to include the
  1866.      * the function name itself.
  1867.      */
  1868.  
  1869.     if (mathFuncPtr->builtinFuncIndex >= 0) { /* a builtin function */
  1870.     TclEmitInstUInt1(INST_CALL_BUILTIN_FUNC1,
  1871.             mathFuncPtr->builtinFuncIndex, envPtr);
  1872.     } else {
  1873.     TclEmitInstUInt1(INST_CALL_FUNC1, (mathFuncPtr->numArgs+1), envPtr);
  1874.     }
  1875.  
  1876.     /*
  1877.      * A comparison is not the top-level operator in this expression.
  1878.      */
  1879.  
  1880.     done:
  1881.     infoPtr->exprIsComparison = 0;
  1882.     envPtr->maxStackDepth = maxDepth;
  1883.     return result;
  1884.  
  1885.     syntaxError:
  1886.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  1887.         "syntax error in expression \"", infoPtr->originalExpr,
  1888.         "\"", (char *) NULL);
  1889.     return TCL_ERROR;
  1890. }
  1891.  
  1892. /*
  1893.  *----------------------------------------------------------------------
  1894.  *
  1895.  * GetToken --
  1896.  *
  1897.  *    Lexical scanner used to compile expressions: parses a single 
  1898.  *    operator or other syntactic element from an expression string.
  1899.  *
  1900.  * Results:
  1901.  *    TCL_OK is returned unless an error occurred. In that case a standard
  1902.  *    Tcl error is returned, using the interpreter's result to hold an
  1903.  *    error message. TCL_ERROR is returned if an integer overflow, or a
  1904.  *    floating-point overflow or underflow occurred while reading in a
  1905.  *    number. If the lexical analysis is successful, infoPtr->token refers
  1906.  *    to the next symbol in the expression string, and infoPtr->next is
  1907.  *    advanced past the token. Also, if the token is a integer, double, or
  1908.  *    string literal, then infoPtr->objIndex the index of an object
  1909.  *    holding the value in the code's object table; otherwise is NULL.
  1910.  *
  1911.  * Side effects:
  1912.  *    Object are added to envPtr to hold the values of scanned literal
  1913.  *    integers, doubles, or strings.
  1914.  *
  1915.  *----------------------------------------------------------------------
  1916.  */
  1917.  
  1918. static int
  1919. GetToken(interp, infoPtr, envPtr)
  1920.     Tcl_Interp *interp;            /* Interpreter to use for error
  1921.                      * reporting. */
  1922.     register ExprInfo *infoPtr;         /* Describes the state of the
  1923.                      * compiling the expression,
  1924.                      * including the resulting token. */
  1925.     CompileEnv *envPtr;            /* Holds objects that store literal
  1926.                      * values that are scanned. */
  1927. {
  1928.     register char *src;        /* Points to current source char. */
  1929.     register char c;        /* The current char. */
  1930.     register int type;        /* Current char's CHAR_TYPE type. */
  1931.     char *termPtr;        /* Points to char terminating a literal. */
  1932.     char savedChar;        /* Holds the character termporarily replaced
  1933.                  * by a null character during processing of
  1934.                  * literal tokens. */
  1935.     int objIndex;        /* The object array index for an object
  1936.                  * holding a scanned literal. */
  1937.     long longValue;        /* Value of a scanned integer literal. */
  1938.     double doubleValue;        /* Value of a scanned double literal. */
  1939.     Tcl_Obj *objPtr;
  1940.  
  1941.     /*
  1942.      * First initialize the scanner's "result" fields to default values.
  1943.      */
  1944.     
  1945.     infoPtr->token = UNKNOWN;
  1946.     infoPtr->objIndex = -1;
  1947.     infoPtr->funcName = NULL;
  1948.  
  1949.     /*
  1950.      * Scan over leading white space at the start of a token. Note that a
  1951.      * backslash-newline is treated as a space.
  1952.      */
  1953.  
  1954.     src = infoPtr->next;
  1955.     c = *src;
  1956.     type = CHAR_TYPE(src, infoPtr->lastChar);
  1957.     while ((type & (TCL_SPACE | TCL_BACKSLASH)) || (c == '\n')) {
  1958.     if (type == TCL_BACKSLASH) {
  1959.         if (src[1] == '\n') {
  1960.         src += 2;
  1961.         } else {
  1962.         break;    /* no longer white space */
  1963.         }
  1964.     } else {
  1965.         src++;
  1966.     }
  1967.     c = *src;
  1968.     type = CHAR_TYPE(src, infoPtr->lastChar);
  1969.     }
  1970.     if (src == infoPtr->lastChar) {
  1971.     infoPtr->token = END;
  1972.     infoPtr->next = src;
  1973.     return TCL_OK;
  1974.     }
  1975.  
  1976.     /*
  1977.      * Try to parse the token first as an integer or floating-point
  1978.      * number. Don't check for a number if the first character is "+" or
  1979.      * "-". If we did, we might treat a binary operator as unary by mistake,
  1980.      * which would eventually cause a syntax error.
  1981.      */
  1982.  
  1983.     if ((*src != '+') && (*src != '-')) {
  1984.     int startsWithDigit = isdigit(UCHAR(*src));
  1985.     
  1986.     if (startsWithDigit && TclLooksLikeInt(src)) {
  1987.         errno = 0;
  1988.         longValue = strtoul(src, &termPtr, 0);
  1989.         if (errno == ERANGE) {
  1990.         char *s = "integer value too large to represent";
  1991.         
  1992.         Tcl_ResetResult(interp);
  1993.         Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
  1994.         Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s,
  1995.             (char *) NULL);
  1996.         return TCL_ERROR;
  1997.         }
  1998.  
  1999.         /*
  2000.          * Find/create an object in envPtr's object array that contains
  2001.          * the integer.
  2002.          */
  2003.         
  2004.         savedChar = *termPtr;
  2005.         *termPtr = '\0';
  2006.         objIndex = TclObjIndexForString(src, termPtr - src,
  2007.             /*allocStrRep*/ 0, /*inHeap*/ 0, envPtr);
  2008.         *termPtr = savedChar;  /* restore the saved char */
  2009.  
  2010.         objPtr = envPtr->objArrayPtr[objIndex];
  2011.         Tcl_InvalidateStringRep(objPtr);
  2012.         objPtr->internalRep.longValue = longValue;
  2013.         objPtr->typePtr = &tclIntType;
  2014.         
  2015.         infoPtr->token = LITERAL;
  2016.         infoPtr->objIndex = objIndex;
  2017.         infoPtr->next = termPtr;
  2018.         return TCL_OK;
  2019.     } else if (startsWithDigit || (*src == '.')
  2020.             || (*src == 'n') || (*src == 'N')) {
  2021.         errno = 0;
  2022.         doubleValue = strtod(src, &termPtr);
  2023.         if (termPtr != src) {
  2024.         if (errno != 0) {
  2025.             TclExprFloatError(interp, doubleValue);
  2026.             return TCL_ERROR;
  2027.         }
  2028.  
  2029.         /*
  2030.          * Find/create an object in the object array containing the
  2031.          * double.
  2032.          */
  2033.         
  2034.         savedChar = *termPtr;
  2035.         *termPtr = '\0';
  2036.         objIndex = TclObjIndexForString(src, termPtr - src,
  2037.             /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
  2038.         *termPtr = savedChar;  /* restore the saved char */
  2039.         
  2040.         objPtr = envPtr->objArrayPtr[objIndex];
  2041.         objPtr->internalRep.doubleValue = doubleValue;
  2042.         objPtr->typePtr = &tclDoubleType;
  2043.         
  2044.         infoPtr->token = LITERAL;
  2045.         infoPtr->objIndex = objIndex;
  2046.         infoPtr->next = termPtr;
  2047.         return TCL_OK;
  2048.         }
  2049.     }
  2050.     }
  2051.  
  2052.     /*
  2053.      * Not an integer or double literal. Check next for a string literal
  2054.      * in braces.
  2055.      */
  2056.  
  2057.     if (*src == '{') {
  2058.     int level = 0;         /* The {} nesting level. */
  2059.     int hasBackslashNL = 0;  /* Nonzero if '\newline' was found. */
  2060.     char *string = src+1;     /* Points just after the starting '{'. */
  2061.     char *last;         /* Points just before terminating '}'. */
  2062.     int numChars;         /* Number of chars in braced string. */
  2063.     char savedChar;         /* Holds the character from string
  2064.                   * termporarily replaced by a null char
  2065.                   * during braced string processing. */
  2066.     int numRead;
  2067.  
  2068.     /*
  2069.      * Check first for any backslash-newlines, since we must treat
  2070.      * backslash-newlines specially (they must be replaced by spaces).
  2071.      */
  2072.     
  2073.     while (1) {
  2074.         if (src == infoPtr->lastChar) {
  2075.         Tcl_ResetResult(interp);
  2076.         Tcl_AppendToObj(Tcl_GetObjResult(interp),
  2077.                 "missing close-brace", -1);
  2078.         return TCL_ERROR;
  2079.         } else if (CHAR_TYPE(src, infoPtr->lastChar) == TCL_NORMAL) {
  2080.         src++;
  2081.         continue;
  2082.         }
  2083.         c = *src++;
  2084.         if (c == '{') {
  2085.         level++;
  2086.         } else if (c == '}') {
  2087.         --level;
  2088.         if (level == 0) {
  2089.             last = (src - 2); /* i.e. just before terminating } */
  2090.             break;
  2091.         }
  2092.         } else if (c == '\\') {
  2093.         if (*src == '\n') {
  2094.             hasBackslashNL = 1;
  2095.         }
  2096.         (void) Tcl_Backslash(src-1, &numRead);
  2097.         src += numRead - 1;
  2098.         }
  2099.     }
  2100.  
  2101.     /*
  2102.      * Create a string object for the braced string. This starts at
  2103.      * "string" and ends just after "last" (which points to the final
  2104.      * character before the terminating '}'). If backslash-newlines were
  2105.      * found, we copy characters one at a time into a heap-allocated
  2106.      * buffer and do backslash-newline substitutions.
  2107.      */
  2108.     
  2109.     numChars = (last - string + 1);
  2110.     savedChar = string[numChars];
  2111.     string[numChars] = '\0';
  2112.     if (hasBackslashNL && (numChars > 0)) {
  2113.         char *buffer = ckalloc((unsigned) numChars + 1);
  2114.         register char *dst = buffer;
  2115.         register char *p = string;
  2116.         while (p <= last) {
  2117.         c = *dst++ = *p++;
  2118.         if (c == '\\') {
  2119.             if (*p == '\n') {
  2120.             dst[-1] = Tcl_Backslash(p-1, &numRead);
  2121.             p += numRead - 1;
  2122.             } else {
  2123.             (void) Tcl_Backslash(p-1, &numRead);
  2124.             while (numRead > 1) {
  2125.                 *dst++ = *p++;
  2126.                 numRead--;
  2127.             }
  2128.             }
  2129.         }
  2130.         }
  2131.         *dst = '\0';
  2132.         objIndex = TclObjIndexForString(buffer, dst - buffer,
  2133.             /*allocStrRep*/ 1, /*inHeap*/ 1, envPtr);
  2134.     } else {
  2135.         objIndex = TclObjIndexForString(string, numChars,
  2136.             /*allocStrRep*/ 1, /*inHeap*/ 0, envPtr);
  2137.     }
  2138.     string[numChars] = savedChar;   /* restore the saved char */
  2139.  
  2140.     infoPtr->token = LITERAL;
  2141.     infoPtr->objIndex = objIndex;
  2142.     infoPtr->next = src;
  2143.     return TCL_OK;
  2144.     }
  2145.  
  2146.     /*
  2147.      * Not an literal value.
  2148.      */
  2149.  
  2150.     infoPtr->next = src+1;   /* assume a 1 char token and advance over it */
  2151.     switch (*src) {
  2152.     case '[':
  2153.         infoPtr->token = OPEN_BRACKET;
  2154.         return TCL_OK;
  2155.  
  2156.     case ']':
  2157.         infoPtr->token = CLOSE_BRACKET;
  2158.         return TCL_OK;
  2159.  
  2160.     case '(':
  2161.         infoPtr->token = OPEN_PAREN;
  2162.         return TCL_OK;
  2163.  
  2164.     case ')':
  2165.         infoPtr->token = CLOSE_PAREN;
  2166.         return TCL_OK;
  2167.  
  2168.     case '$':
  2169.         infoPtr->token = DOLLAR;
  2170.         return TCL_OK;
  2171.  
  2172.     case '"':
  2173.         infoPtr->token = QUOTE;
  2174.         return TCL_OK;
  2175.  
  2176.     case ',':
  2177.         infoPtr->token = COMMA;
  2178.         return TCL_OK;
  2179.  
  2180.     case '*':
  2181.         infoPtr->token = MULT;
  2182.         return TCL_OK;
  2183.  
  2184.     case '/':
  2185.         infoPtr->token = DIVIDE;
  2186.         return TCL_OK;
  2187.  
  2188.     case '%':
  2189.         infoPtr->token = MOD;
  2190.         return TCL_OK;
  2191.  
  2192.     case '+':
  2193.         infoPtr->token = PLUS;
  2194.         return TCL_OK;
  2195.  
  2196.     case '-':
  2197.         infoPtr->token = MINUS;
  2198.         return TCL_OK;
  2199.  
  2200.     case '?':
  2201.         infoPtr->token = QUESTY;
  2202.         return TCL_OK;
  2203.  
  2204.     case ':':
  2205.         infoPtr->token = COLON;
  2206.         return TCL_OK;
  2207.  
  2208.     case '<':
  2209.         switch (src[1]) {
  2210.         case '<':
  2211.             infoPtr->next = src+2;
  2212.             infoPtr->token = LEFT_SHIFT;
  2213.             break;
  2214.         case '=':
  2215.             infoPtr->next = src+2;
  2216.             infoPtr->token = LEQ;
  2217.             break;
  2218.         default:
  2219.             infoPtr->token = LESS;
  2220.             break;
  2221.         }
  2222.         return TCL_OK;
  2223.  
  2224.     case '>':
  2225.         switch (src[1]) {
  2226.         case '>':
  2227.             infoPtr->next = src+2;
  2228.             infoPtr->token = RIGHT_SHIFT;
  2229.             break;
  2230.         case '=':
  2231.             infoPtr->next = src+2;
  2232.             infoPtr->token = GEQ;
  2233.             break;
  2234.         default:
  2235.             infoPtr->token = GREATER;
  2236.             break;
  2237.         }
  2238.         return TCL_OK;
  2239.  
  2240.     case '=':
  2241.         if (src[1] == '=') {
  2242.         infoPtr->next = src+2;
  2243.         infoPtr->token = EQUAL;
  2244.         } else {
  2245.         infoPtr->token = UNKNOWN;
  2246.         }
  2247.         return TCL_OK;
  2248.  
  2249.     case '!':
  2250.         if (src[1] == '=') {
  2251.         infoPtr->next = src+2;
  2252.         infoPtr->token = NEQ;
  2253.         } else {
  2254.         infoPtr->token = NOT;
  2255.         }
  2256.         return TCL_OK;
  2257.  
  2258.     case '&':
  2259.         if (src[1] == '&') {
  2260.         infoPtr->next = src+2;
  2261.         infoPtr->token = AND;
  2262.         } else {
  2263.         infoPtr->token = BIT_AND;
  2264.         }
  2265.         return TCL_OK;
  2266.  
  2267.     case '^':
  2268.         infoPtr->token = BIT_XOR;
  2269.         return TCL_OK;
  2270.  
  2271.     case '|':
  2272.         if (src[1] == '|') {
  2273.         infoPtr->next = src+2;
  2274.         infoPtr->token = OR;
  2275.         } else {
  2276.         infoPtr->token = BIT_OR;
  2277.         }
  2278.         return TCL_OK;
  2279.  
  2280.     case '~':
  2281.         infoPtr->token = BIT_NOT;
  2282.         return TCL_OK;
  2283.  
  2284.     default:
  2285.         if (isalpha(UCHAR(*src))) {
  2286.         infoPtr->token = FUNC_NAME;
  2287.         infoPtr->funcName = src;
  2288.         while (isalnum(UCHAR(*src)) || (*src == '_')) {
  2289.             src++;
  2290.         }
  2291.         infoPtr->next = src;
  2292.         return TCL_OK;
  2293.         }
  2294.         infoPtr->next = src+1;
  2295.         infoPtr->token = UNKNOWN;
  2296.         return TCL_OK;
  2297.     }
  2298. }
  2299.  
  2300. /*
  2301.  *----------------------------------------------------------------------
  2302.  *
  2303.  * Tcl_CreateMathFunc --
  2304.  *
  2305.  *    Creates a new math function for expressions in a given
  2306.  *    interpreter.
  2307.  *
  2308.  * Results:
  2309.  *    None.
  2310.  *
  2311.  * Side effects:
  2312.  *    The function defined by "name" is created or redefined. If the
  2313.  *    function already exists then its definition is replaced; this
  2314.  *    includes the builtin functions. Redefining a builtin function forces
  2315.  *    all existing code to be invalidated since that code may be compiled
  2316.  *    using an instruction specific to the replaced function. In addition,
  2317.  *    redefioning a non-builtin function will force existing code to be
  2318.  *    invalidated if the number of arguments has changed.
  2319.  *
  2320.  *----------------------------------------------------------------------
  2321.  */
  2322.  
  2323. void
  2324. Tcl_CreateMathFunc(interp, name, numArgs, argTypes, proc, clientData)
  2325.     Tcl_Interp *interp;            /* Interpreter in which function is
  2326.                      * to be available. */
  2327.     char *name;                /* Name of function (e.g. "sin"). */
  2328.     int numArgs;            /* Nnumber of arguments required by
  2329.                      * function. */
  2330.     Tcl_ValueType *argTypes;        /* Array of types acceptable for
  2331.                      * each argument. */
  2332.     Tcl_MathProc *proc;            /* Procedure that implements the
  2333.                      * math function. */
  2334.     ClientData clientData;        /* Additional value to pass to the
  2335.                      * function. */
  2336. {
  2337.     Interp *iPtr = (Interp *) interp;
  2338.     Tcl_HashEntry *hPtr;
  2339.     MathFunc *mathFuncPtr;
  2340.     int new, i;
  2341.  
  2342.     hPtr = Tcl_CreateHashEntry(&iPtr->mathFuncTable, name, &new);
  2343.     if (new) {
  2344.     Tcl_SetHashValue(hPtr, ckalloc(sizeof(MathFunc)));
  2345.     }
  2346.     mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
  2347.  
  2348.     if (!new) {    
  2349.     if (mathFuncPtr->builtinFuncIndex >= 0) {
  2350.         /*
  2351.          * We are redefining a builtin math function. Invalidate the
  2352.              * interpreter's existing code by incrementing its
  2353.              * compileEpoch member. This field is checked in Tcl_EvalObj
  2354.              * and ObjInterpProc, and code whose compilation epoch doesn't
  2355.              * match is recompiled. Newly compiled code will no longer
  2356.              * treat the function as builtin.
  2357.          */
  2358.  
  2359.         iPtr->compileEpoch++;
  2360.     } else {
  2361.         /*
  2362.          * A non-builtin function is being redefined. We must invalidate
  2363.              * existing code if the number of arguments has changed. This
  2364.          * is because existing code was compiled assuming that number.
  2365.          */
  2366.  
  2367.         if (numArgs != mathFuncPtr->numArgs) {
  2368.         iPtr->compileEpoch++;
  2369.         }
  2370.     }
  2371.     }
  2372.     
  2373.     mathFuncPtr->builtinFuncIndex = -1;    /* can't be a builtin function */
  2374.     if (numArgs > MAX_MATH_ARGS) {
  2375.     numArgs = MAX_MATH_ARGS;
  2376.     }
  2377.     mathFuncPtr->numArgs = numArgs;
  2378.     for (i = 0;  i < numArgs;  i++) {
  2379.     mathFuncPtr->argTypes[i] = argTypes[i];
  2380.     }
  2381.     mathFuncPtr->proc = proc;
  2382.     mathFuncPtr->clientData = clientData;
  2383. }
  2384.