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