tclCompExpr.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:27k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclCompExpr.c --
  3.  *
  4.  * This file contains the code to compile Tcl expressions.
  5.  *
  6.  * Copyright (c) 1997 Sun Microsystems, Inc.
  7.  * Copyright (c) 1998-2000 by Scriptics Corporation.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tclCompExpr.c,v 1.13.2.3 2006/11/28 22:20:00 andreas_kupries Exp $
  13.  */
  14. #include "tclInt.h"
  15. #include "tclCompile.h"
  16. /*
  17.  * The stuff below is a bit of a hack so that this file can be used in
  18.  * environments that include no UNIX, i.e. no errno: just arrange to use
  19.  * the errno from tclExecute.c here.
  20.  */
  21. #ifndef TCL_GENERIC_ONLY
  22. #include "tclPort.h"
  23. #else
  24. #define NO_ERRNO_H
  25. #endif
  26. #ifdef NO_ERRNO_H
  27. extern int errno; /* Use errno from tclExecute.c. */
  28. #define ERANGE 34
  29. #endif
  30. /*
  31.  * Boolean variable that controls whether expression compilation tracing
  32.  * is enabled.
  33.  */
  34. #ifdef TCL_COMPILE_DEBUG
  35. static int traceExprComp = 0;
  36. #endif /* TCL_COMPILE_DEBUG */
  37. /*
  38.  * The ExprInfo structure describes the state of compiling an expression.
  39.  * A pointer to an ExprInfo record is passed among the routines in
  40.  * this module.
  41.  */
  42. typedef struct ExprInfo {
  43.     Tcl_Interp *interp; /* Used for error reporting. */
  44.     Tcl_Parse *parsePtr; /* Structure filled with information about
  45.  * the parsed expression. */
  46.     CONST char *expr; /* The expression that was originally passed
  47.  * to TclCompileExpr. */
  48.     CONST char *lastChar; /* Points just after last byte of expr. */
  49.     int hasOperators; /* Set 1 if the expr has operators; 0 if
  50.  * expr is only a primary. If 1 after
  51.  * compiling an expr, a tryCvtToNumeric
  52.  * instruction is emitted to convert the
  53.  * primary to a number if possible. */
  54. } ExprInfo;
  55. /*
  56.  * Definitions of numeric codes representing each expression operator.
  57.  * The order of these must match the entries in the operatorTable below.
  58.  * Also the codes for the relational operators (OP_LESS, OP_GREATER, 
  59.  * OP_LE, OP_GE, OP_EQ, and OP_NE) must be consecutive and in that order.
  60.  * Note that OP_PLUS and OP_MINUS represent both unary and binary operators.
  61.  */
  62. #define OP_MULT 0
  63. #define OP_DIVIDE 1
  64. #define OP_MOD 2
  65. #define OP_PLUS 3
  66. #define OP_MINUS 4
  67. #define OP_LSHIFT 5
  68. #define OP_RSHIFT 6
  69. #define OP_LESS 7
  70. #define OP_GREATER 8
  71. #define OP_LE 9
  72. #define OP_GE 10
  73. #define OP_EQ 11
  74. #define OP_NEQ 12
  75. #define OP_BITAND 13
  76. #define OP_BITXOR 14
  77. #define OP_BITOR 15
  78. #define OP_LAND 16
  79. #define OP_LOR 17
  80. #define OP_QUESTY 18
  81. #define OP_LNOT 19
  82. #define OP_BITNOT 20
  83. #define OP_STREQ 21
  84. #define OP_STRNEQ 22
  85. /*
  86.  * Table describing the expression operators. Entries in this table must
  87.  * correspond to the definitions of numeric codes for operators just above.
  88.  */
  89. static int opTableInitialized = 0; /* 0 means not yet initialized. */
  90. TCL_DECLARE_MUTEX(opMutex)
  91. typedef struct OperatorDesc {
  92.     char *name; /* Name of the operator. */
  93.     int numOperands; /* Number of operands. 0 if the operator
  94.  * requires special handling. */
  95.     int instruction; /* Instruction opcode for the operator.
  96.  * Ignored if numOperands is 0. */
  97. } OperatorDesc;
  98. static OperatorDesc operatorTable[] = {
  99.     {"*",   2,  INST_MULT},
  100.     {"/",   2,  INST_DIV},
  101.     {"%",   2,  INST_MOD},
  102.     {"+",   0}, 
  103.     {"-",   0},
  104.     {"<<",  2,  INST_LSHIFT},
  105.     {">>",  2,  INST_RSHIFT},
  106.     {"<",   2,  INST_LT},
  107.     {">",   2,  INST_GT},
  108.     {"<=",  2,  INST_LE},
  109.     {">=",  2,  INST_GE},
  110.     {"==",  2,  INST_EQ},
  111.     {"!=",  2,  INST_NEQ},
  112.     {"&",   2,  INST_BITAND},
  113.     {"^",   2,  INST_BITXOR},
  114.     {"|",   2,  INST_BITOR},
  115.     {"&&",  0},
  116.     {"||",  0},
  117.     {"?",   0},
  118.     {"!",   1,  INST_LNOT},
  119.     {"~",   1,  INST_BITNOT},
  120.     {"eq",  2,  INST_STR_EQ},
  121.     {"ne",  2,  INST_STR_NEQ},
  122.     {NULL}
  123. };
  124. /*
  125.  * Hashtable used to map the names of expression operators to the index
  126.  * of their OperatorDesc description.
  127.  */
  128. static Tcl_HashTable opHashTable;
  129. /*
  130.  * Declarations for local procedures to this file:
  131.  */
  132. static int CompileCondExpr _ANSI_ARGS_((
  133.     Tcl_Token *exprTokenPtr, ExprInfo *infoPtr,
  134.     CompileEnv *envPtr, Tcl_Token **endPtrPtr));
  135. static int CompileLandOrLorExpr _ANSI_ARGS_((
  136.     Tcl_Token *exprTokenPtr, int opIndex,
  137.     ExprInfo *infoPtr, CompileEnv *envPtr,
  138.     Tcl_Token **endPtrPtr));
  139. static int CompileMathFuncCall _ANSI_ARGS_((
  140.     Tcl_Token *exprTokenPtr, CONST char *funcName,
  141.     ExprInfo *infoPtr, CompileEnv *envPtr,
  142.     Tcl_Token **endPtrPtr));
  143. static int CompileSubExpr _ANSI_ARGS_((
  144.     Tcl_Token *exprTokenPtr, ExprInfo *infoPtr,
  145.     CompileEnv *envPtr));
  146. static void LogSyntaxError _ANSI_ARGS_((ExprInfo *infoPtr));
  147. /*
  148.  * Macro used to debug the execution of the expression compiler.
  149.  */
  150. #ifdef TCL_COMPILE_DEBUG
  151. #define TRACE(exprBytes, exprLength, tokenBytes, tokenLength) 
  152.     if (traceExprComp) { 
  153. fprintf(stderr, "CompileSubExpr: "%.*s", token "%.*s"n", 
  154.         (exprLength), (exprBytes), (tokenLength), (tokenBytes)); 
  155.     }
  156. #else
  157. #define TRACE(exprBytes, exprLength, tokenBytes, tokenLength)
  158. #endif /* TCL_COMPILE_DEBUG */
  159. /*
  160.  *----------------------------------------------------------------------
  161.  *
  162.  * TclCompileExpr --
  163.  *
  164.  * This procedure compiles a string containing a Tcl expression into
  165.  * Tcl bytecodes. This procedure is the top-level interface to the
  166.  * the expression compilation module, and is used by such public
  167.  * procedures as Tcl_ExprString, Tcl_ExprStringObj, Tcl_ExprLong,
  168.  * Tcl_ExprDouble, Tcl_ExprBoolean, and Tcl_ExprBooleanObj.
  169.  *
  170.  * Results:
  171.  * The return value is TCL_OK on a successful compilation and TCL_ERROR
  172.  * on failure. If TCL_ERROR is returned, then the interpreter's result
  173.  * contains an error message.
  174.  *
  175.  * Side effects:
  176.  * Adds instructions to envPtr to evaluate the expression at runtime.
  177.  *
  178.  *----------------------------------------------------------------------
  179.  */
  180. int
  181. TclCompileExpr(interp, script, numBytes, envPtr)
  182.     Tcl_Interp *interp; /* Used for error reporting. */
  183.     CONST char *script; /* The source script to compile. */
  184.     int numBytes; /* Number of bytes in script. If < 0, the
  185.  * string consists of all bytes up to the
  186.  * first null character. */
  187.     CompileEnv *envPtr; /* Holds resulting instructions. */
  188. {
  189.     ExprInfo info;
  190.     Tcl_Parse parse;
  191.     Tcl_HashEntry *hPtr;
  192.     int new, i, code;
  193.     /*
  194.      * If this is the first time we've been called, initialize the table
  195.      * of expression operators.
  196.      */
  197.     if (numBytes < 0) {
  198. numBytes = (script? strlen(script) : 0);
  199.     }
  200.     if (!opTableInitialized) {
  201. Tcl_MutexLock(&opMutex);
  202. if (!opTableInitialized) {
  203.     Tcl_InitHashTable(&opHashTable, TCL_STRING_KEYS);
  204.     for (i = 0;  operatorTable[i].name != NULL;  i++) {
  205. hPtr = Tcl_CreateHashEntry(&opHashTable,
  206. operatorTable[i].name, &new);
  207. if (new) {
  208.     Tcl_SetHashValue(hPtr, (ClientData) i);
  209. }
  210.     }
  211.     opTableInitialized = 1;
  212. }
  213. Tcl_MutexUnlock(&opMutex);
  214.     }
  215.     /*
  216.      * Initialize the structure containing information abvout this
  217.      * expression compilation.
  218.      */
  219.     info.interp = interp;
  220.     info.parsePtr = &parse;
  221.     info.expr = script;
  222.     info.lastChar = (script + numBytes); 
  223.     info.hasOperators = 0;
  224.     /*
  225.      * Parse the expression then compile it.
  226.      */
  227.     code = Tcl_ParseExpr(interp, script, numBytes, &parse);
  228.     if (code != TCL_OK) {
  229. goto done;
  230.     }
  231. #ifdef TCL_TIP280
  232.     /* TIP #280 : Track Lines within the expression */
  233.     TclAdvanceLines (&envPtr->line, script, parse.tokenPtr->start);
  234. #endif
  235.     code = CompileSubExpr(parse.tokenPtr, &info, envPtr);
  236.     if (code != TCL_OK) {
  237. Tcl_FreeParse(&parse);
  238. goto done;
  239.     }
  240.     
  241.     if (!info.hasOperators) {
  242. /*
  243.  * Attempt to convert the primary's object to an int or double.
  244.  * This is done in order to support Tcl's policy of interpreting
  245.  * operands if at all possible as first integers, else
  246.  * floating-point numbers.
  247.  */
  248. TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
  249.     }
  250.     Tcl_FreeParse(&parse);
  251.     done:
  252.     return code;
  253. }
  254. /*
  255.  *----------------------------------------------------------------------
  256.  *
  257.  * TclFinalizeCompilation --
  258.  *
  259.  * Clean up the compilation environment so it can later be
  260.  * properly reinitialized. This procedure is called by Tcl_Finalize().
  261.  *
  262.  * Results:
  263.  * None.
  264.  *
  265.  * Side effects:
  266.  * Cleans up the compilation environment. At the moment, just the
  267.  * table of expression operators is freed.
  268.  *
  269.  *----------------------------------------------------------------------
  270.  */
  271. void
  272. TclFinalizeCompilation()
  273. {
  274.     Tcl_MutexLock(&opMutex);
  275.     if (opTableInitialized) {
  276.         Tcl_DeleteHashTable(&opHashTable);
  277.         opTableInitialized = 0;
  278.     }
  279.     Tcl_MutexUnlock(&opMutex);
  280. }
  281. /*
  282.  *----------------------------------------------------------------------
  283.  *
  284.  * CompileSubExpr --
  285.  *
  286.  * Given a pointer to a TCL_TOKEN_SUB_EXPR token describing a
  287.  * subexpression, this procedure emits instructions to evaluate the
  288.  * subexpression at runtime.
  289.  *
  290.  * Results:
  291.  * The return value is TCL_OK on a successful compilation and TCL_ERROR
  292.  * on failure. If TCL_ERROR is returned, then the interpreter's result
  293.  * contains an error message.
  294.  *
  295.  * Side effects:
  296.  * Adds instructions to envPtr to evaluate the subexpression.
  297.  *
  298.  *----------------------------------------------------------------------
  299.  */
  300. static int
  301. CompileSubExpr(exprTokenPtr, infoPtr, envPtr)
  302.     Tcl_Token *exprTokenPtr; /* Points to TCL_TOKEN_SUB_EXPR token
  303.  * to compile. */
  304.     ExprInfo *infoPtr; /* Describes the compilation state for the
  305.  * expression being compiled. */
  306.     CompileEnv *envPtr; /* Holds resulting instructions. */
  307. {
  308.     Tcl_Interp *interp = infoPtr->interp;
  309.     Tcl_Token *tokenPtr, *endPtr = NULL; /* silence gcc 4 warning */
  310.     Tcl_Token *afterSubexprPtr;
  311.     OperatorDesc *opDescPtr;
  312.     Tcl_HashEntry *hPtr;
  313.     CONST char *operator;
  314.     Tcl_DString opBuf;
  315.     int objIndex, opIndex, length, code;
  316.     char buffer[TCL_UTF_MAX];
  317.     if (exprTokenPtr->type != TCL_TOKEN_SUB_EXPR) {
  318. panic("CompileSubExpr: token type %d not TCL_TOKEN_SUB_EXPRn",
  319.         exprTokenPtr->type);
  320.     }
  321.     code = TCL_OK;
  322.     /*
  323.      * Switch on the type of the first token after the subexpression token.
  324.      * After processing it, advance tokenPtr to point just after the
  325.      * subexpression's last token.
  326.      */
  327.     
  328.     tokenPtr = exprTokenPtr+1;
  329.     TRACE(exprTokenPtr->start, exprTokenPtr->size,
  330.     tokenPtr->start, tokenPtr->size);
  331.     switch (tokenPtr->type) {
  332.         case TCL_TOKEN_WORD:
  333.     code = TclCompileTokens(interp, tokenPtr+1,
  334.             tokenPtr->numComponents, envPtr);
  335.     if (code != TCL_OK) {
  336. goto done;
  337.     }
  338.     tokenPtr += (tokenPtr->numComponents + 1);
  339.     break;
  340.     
  341.         case TCL_TOKEN_TEXT:
  342.     if (tokenPtr->size > 0) {
  343. objIndex = TclRegisterNewLiteral(envPtr, tokenPtr->start,
  344.                 tokenPtr->size);
  345.     } else {
  346. objIndex = TclRegisterNewLiteral(envPtr, "", 0);
  347.     }
  348.     TclEmitPush(objIndex, envPtr);
  349.     tokenPtr += 1;
  350.     break;
  351.     
  352.         case TCL_TOKEN_BS:
  353.     length = Tcl_UtfBackslash(tokenPtr->start, (int *) NULL,
  354.     buffer);
  355.     if (length > 0) {
  356. objIndex = TclRegisterNewLiteral(envPtr, buffer, length);
  357.     } else {
  358. objIndex = TclRegisterNewLiteral(envPtr, "", 0);
  359.     }
  360.     TclEmitPush(objIndex, envPtr);
  361.     tokenPtr += 1;
  362.     break;
  363.     
  364.         case TCL_TOKEN_COMMAND:
  365.     code = TclCompileScript(interp, tokenPtr->start+1,
  366.     tokenPtr->size-2, /*nested*/ 0, envPtr);
  367.     if (code != TCL_OK) {
  368. goto done;
  369.     }
  370.     tokenPtr += 1;
  371.     break;
  372.     
  373.         case TCL_TOKEN_VARIABLE:
  374.     code = TclCompileTokens(interp, tokenPtr, 1, envPtr);
  375.     if (code != TCL_OK) {
  376. goto done;
  377.     }
  378.     tokenPtr += (tokenPtr->numComponents + 1);
  379.     break;
  380.     
  381.         case TCL_TOKEN_SUB_EXPR:
  382.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  383.     if (code != TCL_OK) {
  384. goto done;
  385.     }
  386.     tokenPtr += (tokenPtr->numComponents + 1);
  387.     break;
  388.     
  389.         case TCL_TOKEN_OPERATOR:
  390.     /*
  391.      * Look up the operator.  If the operator isn't found, treat it
  392.      * as a math function.
  393.      */
  394.     Tcl_DStringInit(&opBuf);
  395.     operator = Tcl_DStringAppend(&opBuf, 
  396.     tokenPtr->start, tokenPtr->size);
  397.     hPtr = Tcl_FindHashEntry(&opHashTable, operator);
  398.     if (hPtr == NULL) {
  399. code = CompileMathFuncCall(exprTokenPtr, operator, infoPtr,
  400. envPtr, &endPtr);
  401. Tcl_DStringFree(&opBuf);
  402. if (code != TCL_OK) {
  403.     goto done;
  404. }
  405. tokenPtr = endPtr;
  406. break;
  407.     }
  408.     Tcl_DStringFree(&opBuf);
  409.     opIndex = (int) Tcl_GetHashValue(hPtr);
  410.     opDescPtr = &(operatorTable[opIndex]);
  411.     /*
  412.      * If the operator is "normal", compile it using information
  413.      * from the operator table.
  414.      */
  415.     if (opDescPtr->numOperands > 0) {
  416. tokenPtr++;
  417. code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  418. if (code != TCL_OK) {
  419.     goto done;
  420. }
  421. tokenPtr += (tokenPtr->numComponents + 1);
  422. if (opDescPtr->numOperands == 2) {
  423.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  424.     if (code != TCL_OK) {
  425. goto done;
  426.     }
  427.     tokenPtr += (tokenPtr->numComponents + 1);
  428. }
  429. TclEmitOpcode(opDescPtr->instruction, envPtr);
  430. infoPtr->hasOperators = 1;
  431. break;
  432.     }
  433.     
  434.     /*
  435.      * The operator requires special treatment, and is either
  436.      * "+" or "-", or one of "&&", "||" or "?".
  437.      */
  438.     
  439.     switch (opIndex) {
  440.         case OP_PLUS:
  441.         case OP_MINUS:
  442.     tokenPtr++;
  443.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  444.     if (code != TCL_OK) {
  445. goto done;
  446.     }
  447.     tokenPtr += (tokenPtr->numComponents + 1);
  448.     
  449.     /*
  450.      * Check whether the "+" or "-" is unary.
  451.      */
  452.     
  453.     afterSubexprPtr = exprTokenPtr
  454.     + exprTokenPtr->numComponents+1;
  455.     if (tokenPtr == afterSubexprPtr) {
  456. TclEmitOpcode(((opIndex==OP_PLUS)?
  457.         INST_UPLUS : INST_UMINUS),
  458.         envPtr);
  459. break;
  460.     }
  461.     
  462.     /*
  463.      * The "+" or "-" is binary.
  464.      */
  465.     
  466.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  467.     if (code != TCL_OK) {
  468. goto done;
  469.     }
  470.     tokenPtr += (tokenPtr->numComponents + 1);
  471.     TclEmitOpcode(((opIndex==OP_PLUS)? INST_ADD : INST_SUB),
  472.     envPtr);
  473.     break;
  474.         case OP_LAND:
  475.         case OP_LOR:
  476.     code = CompileLandOrLorExpr(exprTokenPtr, opIndex,
  477.     infoPtr, envPtr, &endPtr);
  478.     if (code != TCL_OK) {
  479. goto done;
  480.     }
  481.     tokenPtr = endPtr;
  482.     break;
  483.         case OP_QUESTY:
  484.     code = CompileCondExpr(exprTokenPtr, infoPtr,
  485.     envPtr, &endPtr);
  486.     if (code != TCL_OK) {
  487. goto done;
  488.     }
  489.     tokenPtr = endPtr;
  490.     break;
  491.     
  492. default:
  493.     panic("CompileSubExpr: unexpected operator %d requiring special treatmentn",
  494.         opIndex);
  495.     } /* end switch on operator requiring special treatment */
  496.     infoPtr->hasOperators = 1;
  497.     break;
  498.         default:
  499.     panic("CompileSubExpr: unexpected token type %dn",
  500.             tokenPtr->type);
  501.     }
  502.     /*
  503.      * Verify that the subexpression token had the required number of
  504.      * subtokens: that we've advanced tokenPtr just beyond the
  505.      * subexpression's last token. For example, a "*" subexpression must
  506.      * contain the tokens for exactly two operands.
  507.      */
  508.     
  509.     if (tokenPtr != (exprTokenPtr + exprTokenPtr->numComponents+1)) {
  510. LogSyntaxError(infoPtr);
  511. code = TCL_ERROR;
  512.     }
  513.     
  514.     done:
  515.     return code;
  516. }
  517. /*
  518.  *----------------------------------------------------------------------
  519.  *
  520.  * CompileLandOrLorExpr --
  521.  *
  522.  * This procedure compiles a Tcl logical and ("&&") or logical or
  523.  * ("||") subexpression.
  524.  *
  525.  * Results:
  526.  * The return value is TCL_OK on a successful compilation and TCL_ERROR
  527.  * on failure. If TCL_OK is returned, a pointer to the token just after
  528.  * the last one in the subexpression is stored at the address in
  529.  * endPtrPtr. If TCL_ERROR is returned, then the interpreter's result
  530.  * contains an error message.
  531.  *
  532.  * Side effects:
  533.  * Adds instructions to envPtr to evaluate the expression at runtime.
  534.  *
  535.  *----------------------------------------------------------------------
  536.  */
  537. static int
  538. CompileLandOrLorExpr(exprTokenPtr, opIndex, infoPtr, envPtr, endPtrPtr)
  539.     Tcl_Token *exprTokenPtr;  /* Points to TCL_TOKEN_SUB_EXPR token
  540.   * containing the "&&" or "||" operator. */
  541.     int opIndex;  /* A code describing the expression
  542.   * operator: either OP_LAND or OP_LOR. */
  543.     ExprInfo *infoPtr;  /* Describes the compilation state for the
  544.   * expression being compiled. */
  545.     CompileEnv *envPtr;  /* Holds resulting instructions. */
  546.     Tcl_Token **endPtrPtr;  /* If successful, a pointer to the token
  547.   * just after the last token in the
  548.   * subexpression is stored here. */
  549. {
  550.     JumpFixup shortCircuitFixup; /* Used to fix up the short circuit jump
  551.   * after the first subexpression. */
  552.     JumpFixup lhsTrueFixup, lhsEndFixup;
  553.       /* Used to fix up jumps used to convert the
  554.   * first operand to 0 or 1. */
  555.     Tcl_Token *tokenPtr;
  556.     int dist, code;
  557.     int savedStackDepth = envPtr->currStackDepth;
  558.     /*
  559.      * Emit code for the first operand.
  560.      */
  561.     tokenPtr = exprTokenPtr+2;
  562.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  563.     if (code != TCL_OK) {
  564. goto done;
  565.     }
  566.     tokenPtr += (tokenPtr->numComponents + 1);
  567.     /*
  568.      * Convert the first operand to the result that Tcl requires:
  569.      * "0" or "1". Eventually we'll use a new instruction for this.
  570.      */
  571.     
  572.     TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &lhsTrueFixup);
  573.     TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
  574.     TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &lhsEndFixup);
  575.     dist = (envPtr->codeNext - envPtr->codeStart) - lhsTrueFixup.codeOffset;
  576.     if (TclFixupForwardJump(envPtr, &lhsTrueFixup, dist, 127)) {
  577.         badDist:
  578. panic("CompileLandOrLorExpr: bad jump distance %dn", dist);
  579.     }
  580.     envPtr->currStackDepth = savedStackDepth;
  581.     TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
  582.     dist = (envPtr->codeNext - envPtr->codeStart) - lhsEndFixup.codeOffset;
  583.     if (TclFixupForwardJump(envPtr, &lhsEndFixup, dist, 127)) {
  584. goto badDist;
  585.     }
  586.     /*
  587.      * Emit the "short circuit" jump around the rest of the expression.
  588.      * Duplicate the "0" or "1" on top of the stack first to keep the
  589.      * jump from consuming it.
  590.      */
  591.     TclEmitOpcode(INST_DUP, envPtr);
  592.     TclEmitForwardJump(envPtr,
  593.     ((opIndex==OP_LAND)? TCL_FALSE_JUMP : TCL_TRUE_JUMP),
  594.     &shortCircuitFixup);
  595.     /*
  596.      * Emit code for the second operand.
  597.      */
  598.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  599.     if (code != TCL_OK) {
  600. goto done;
  601.     }
  602.     tokenPtr += (tokenPtr->numComponents + 1);
  603.     /*
  604.      * Emit a "logical and" or "logical or" instruction. This does not try
  605.      * to "short- circuit" the evaluation of both operands, but instead
  606.      * ensures that we either have a "1" or a "0" result.
  607.      */
  608.     TclEmitOpcode(((opIndex==OP_LAND)? INST_LAND : INST_LOR), envPtr);
  609.     /*
  610.      * Now that we know the target of the forward jump, update it with the
  611.      * correct distance.
  612.      */
  613.     dist = (envPtr->codeNext - envPtr->codeStart)
  614.     - shortCircuitFixup.codeOffset;
  615.     TclFixupForwardJump(envPtr, &shortCircuitFixup, dist, 127);
  616.     *endPtrPtr = tokenPtr;
  617.     done:
  618.     envPtr->currStackDepth = savedStackDepth + 1;
  619.     return code;
  620. }
  621. /*
  622.  *----------------------------------------------------------------------
  623.  *
  624.  * CompileCondExpr --
  625.  *
  626.  * This procedure compiles a Tcl conditional expression:
  627.  * condExpr ::= lorExpr ['?' condExpr ':' condExpr]
  628.  *
  629.  * Results:
  630.  * The return value is TCL_OK on a successful compilation and TCL_ERROR
  631.  * on failure. If TCL_OK is returned, a pointer to the token just after
  632.  * the last one in the subexpression is stored at the address in
  633.  * endPtrPtr. If TCL_ERROR is returned, then the interpreter's result
  634.  * contains an error message.
  635.  *
  636.  * Side effects:
  637.  * Adds instructions to envPtr to evaluate the expression at runtime.
  638.  *
  639.  *----------------------------------------------------------------------
  640.  */
  641. static int
  642. CompileCondExpr(exprTokenPtr, infoPtr, envPtr, endPtrPtr)
  643.     Tcl_Token *exprTokenPtr; /* Points to TCL_TOKEN_SUB_EXPR token
  644.  * containing the "?" operator. */
  645.     ExprInfo *infoPtr; /* Describes the compilation state for the
  646.  * expression being compiled. */
  647.     CompileEnv *envPtr; /* Holds resulting instructions. */
  648.     Tcl_Token **endPtrPtr; /* If successful, a pointer to the token
  649.  * just after the last token in the
  650.  * subexpression is stored here. */
  651. {
  652.     JumpFixup jumpAroundThenFixup, jumpAroundElseFixup;
  653. /* Used to update or replace one-byte jumps
  654.  * around the then and else expressions when
  655.  * their target PCs are determined. */
  656.     Tcl_Token *tokenPtr;
  657.     int elseCodeOffset, dist, code;
  658.     int savedStackDepth = envPtr->currStackDepth;
  659.     /*
  660.      * Emit code for the test.
  661.      */
  662.     tokenPtr = exprTokenPtr+2;
  663.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  664.     if (code != TCL_OK) {
  665. goto done;
  666.     }
  667.     tokenPtr += (tokenPtr->numComponents + 1);
  668.     
  669.     /*
  670.      * Emit the jump to the "else" expression if the test was false.
  671.      */
  672.     
  673.     TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpAroundThenFixup);
  674.     /*
  675.      * Compile the "then" expression. Note that if a subexpression is only
  676.      * a primary, we need to try to convert it to numeric. We do this to
  677.      * support Tcl's policy of interpreting operands if at all possible as
  678.      * first integers, else floating-point numbers.
  679.      */
  680.     infoPtr->hasOperators = 0;
  681.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  682.     if (code != TCL_OK) {
  683. goto done;
  684.     }
  685.     tokenPtr += (tokenPtr->numComponents + 1);
  686.     if (!infoPtr->hasOperators) {
  687. TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
  688.     }
  689.     /*
  690.      * Emit an unconditional jump around the "else" condExpr.
  691.      */
  692.     
  693.     TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
  694.     &jumpAroundElseFixup);
  695.     /*
  696.      * Compile the "else" expression.
  697.      */
  698.     envPtr->currStackDepth = savedStackDepth;
  699.     elseCodeOffset = (envPtr->codeNext - envPtr->codeStart);
  700.     infoPtr->hasOperators = 0;
  701.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  702.     if (code != TCL_OK) {
  703. goto done;
  704.     }
  705.     tokenPtr += (tokenPtr->numComponents + 1);
  706.     if (!infoPtr->hasOperators) {
  707. TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
  708.     }
  709.     /*
  710.      * Fix up the second jump around the "else" expression.
  711.      */
  712.     dist = (envPtr->codeNext - envPtr->codeStart)
  713.     - jumpAroundElseFixup.codeOffset;
  714.     if (TclFixupForwardJump(envPtr, &jumpAroundElseFixup, dist, 127)) {
  715. /*
  716.  * Update the else expression's starting code offset since it
  717.  * moved down 3 bytes too.
  718.  */
  719. elseCodeOffset += 3;
  720.     }
  721.     /*
  722.      * Fix up the first jump to the "else" expression if the test was false.
  723.      */
  724.     
  725.     dist = (elseCodeOffset - jumpAroundThenFixup.codeOffset);
  726.     TclFixupForwardJump(envPtr, &jumpAroundThenFixup, dist, 127);
  727.     *endPtrPtr = tokenPtr;
  728.     done:
  729.     envPtr->currStackDepth = savedStackDepth + 1;
  730.     return code;
  731. }
  732. /*
  733.  *----------------------------------------------------------------------
  734.  *
  735.  * CompileMathFuncCall --
  736.  *
  737.  * This procedure compiles a call on a math function in an expression:
  738.  * mathFuncCall ::= funcName '(' [condExpr {',' condExpr}] ')'
  739.  *
  740.  * Results:
  741.  * The return value is TCL_OK on a successful compilation and TCL_ERROR
  742.  * on failure. If TCL_OK is returned, a pointer to the token just after
  743.  * the last one in the subexpression is stored at the address in
  744.  * endPtrPtr. If TCL_ERROR is returned, then the interpreter's result
  745.  * contains an error message.
  746.  *
  747.  * Side effects:
  748.  * Adds instructions to envPtr to evaluate the math function at
  749.  * runtime.
  750.  *
  751.  *----------------------------------------------------------------------
  752.  */
  753. static int
  754. CompileMathFuncCall(exprTokenPtr, funcName, infoPtr, envPtr, endPtrPtr)
  755.     Tcl_Token *exprTokenPtr; /* Points to TCL_TOKEN_SUB_EXPR token
  756.  * containing the math function call. */
  757.     CONST char *funcName; /* Name of the math function. */
  758.     ExprInfo *infoPtr; /* Describes the compilation state for the
  759.  * expression being compiled. */
  760.     CompileEnv *envPtr; /* Holds resulting instructions. */
  761.     Tcl_Token **endPtrPtr; /* If successful, a pointer to the token
  762.  * just after the last token in the
  763.  * subexpression is stored here. */
  764. {
  765.     Tcl_Interp *interp = infoPtr->interp;
  766.     Interp *iPtr = (Interp *) interp;
  767.     MathFunc *mathFuncPtr;
  768.     Tcl_HashEntry *hPtr;
  769.     Tcl_Token *tokenPtr, *afterSubexprPtr;
  770.     int code, i;
  771.     /*
  772.      * Look up the MathFunc record for the function.
  773.      */
  774.     code = TCL_OK;
  775.     hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcName);
  776.     if (hPtr == NULL) {
  777. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  778. "unknown math function "", funcName, """, (char *) NULL);
  779. code = TCL_ERROR;
  780. goto done;
  781.     }
  782.     mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
  783.     /*
  784.      * If not a builtin function, push an object with the function's name.
  785.      */
  786.     if (mathFuncPtr->builtinFuncIndex < 0) {
  787. TclEmitPush(TclRegisterNewLiteral(envPtr, funcName, -1), envPtr);
  788.     }
  789.     /*
  790.      * Compile any arguments for the function.
  791.      */
  792.     tokenPtr = exprTokenPtr+2;
  793.     afterSubexprPtr = exprTokenPtr + (exprTokenPtr->numComponents + 1);
  794.     if (mathFuncPtr->numArgs > 0) {
  795. for (i = 0;  i < mathFuncPtr->numArgs;  i++) {
  796.     if (tokenPtr == afterSubexprPtr) {
  797. Tcl_ResetResult(interp);
  798. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  799.         "too few arguments for math function", -1);
  800. code = TCL_ERROR;
  801. goto done;
  802.     }
  803.     code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
  804.     if (code != TCL_OK) {
  805. goto done;
  806.     }
  807.     tokenPtr += (tokenPtr->numComponents + 1);
  808. }
  809. if (tokenPtr != afterSubexprPtr) {
  810.     Tcl_ResetResult(interp);
  811.     Tcl_AppendToObj(Tcl_GetObjResult(interp),
  812.     "too many arguments for math function", -1);
  813.     code = TCL_ERROR;
  814.     goto done;
  815.     } else if (tokenPtr != afterSubexprPtr) {
  816. Tcl_ResetResult(interp);
  817. Tcl_AppendToObj(Tcl_GetObjResult(interp),
  818. "too many arguments for math function", -1);
  819. code = TCL_ERROR;
  820. goto done;
  821.     }
  822.     
  823.     /*
  824.      * Compile the call on the math function. Note that the "objc" argument
  825.      * count for non-builtin functions is incremented by 1 to include the
  826.      * function name itself.
  827.      */
  828.     if (mathFuncPtr->builtinFuncIndex >= 0) { /* a builtin function */
  829. /*
  830.  * Adjust the current stack depth by the number of arguments
  831.  * of the builtin function. This cannot be handled by the 
  832.  * TclEmitInstInt1 macro as the number of arguments is not
  833.  * passed as an operand.
  834.  */
  835. if (envPtr->maxStackDepth < envPtr->currStackDepth) {
  836.     envPtr->maxStackDepth = envPtr->currStackDepth;
  837. }
  838. TclEmitInstInt1(INST_CALL_BUILTIN_FUNC1,
  839.         mathFuncPtr->builtinFuncIndex, envPtr);
  840. envPtr->currStackDepth -= mathFuncPtr->numArgs;
  841.     } else {
  842. TclEmitInstInt1(INST_CALL_FUNC1, (mathFuncPtr->numArgs+1), envPtr);
  843.     }
  844.     *endPtrPtr = afterSubexprPtr;
  845.     done:
  846.     return code;
  847. }
  848. /*
  849.  *----------------------------------------------------------------------
  850.  *
  851.  * LogSyntaxError --
  852.  *
  853.  * This procedure is invoked after an error occurs when compiling an
  854.  * expression. It sets the interpreter result to an error message
  855.  * describing the error.
  856.  *
  857.  * Results:
  858.  * None.
  859.  *
  860.  * Side effects:
  861.  * Sets the interpreter result to an error message describing the
  862.  * expression that was being compiled when the error occurred.
  863.  *
  864.  *----------------------------------------------------------------------
  865.  */
  866. static void
  867. LogSyntaxError(infoPtr)
  868.     ExprInfo *infoPtr; /* Describes the compilation state for the
  869.  * expression being compiled. */
  870. {
  871.     int numBytes = (infoPtr->lastChar - infoPtr->expr);
  872.     char buffer[100];
  873.     sprintf(buffer, "syntax error in expression "%.*s"",
  874.     ((numBytes > 60)? 60 : numBytes), infoPtr->expr);
  875.     Tcl_ResetResult(infoPtr->interp);
  876.     Tcl_AppendStringsToObj(Tcl_GetObjResult(infoPtr->interp),
  877.     buffer, (char *) NULL);
  878. }