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