Annotation of micropolis/src/tcl/tclexpr.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tclExpr.c --
        !             3:  *
        !             4:  *     This file contains the code to evaluate expressions for
        !             5:  *     Tcl.
        !             6:  *
        !             7:  *     This implementation of floating-point support was modelled
        !             8:  *     after an initial implementation by Bill Carpenter.
        !             9:  *
        !            10:  * Copyright 1987-1991 Regents of the University of California
        !            11:  * Permission to use, copy, modify, and distribute this
        !            12:  * software and its documentation for any purpose and without
        !            13:  * fee is hereby granted, provided that the above copyright
        !            14:  * notice appear in all copies.  The University of California
        !            15:  * makes no representations about the suitability of this
        !            16:  * software for any purpose.  It is provided "as is" without
        !            17:  * express or implied warranty.
        !            18:  */
        !            19: 
        !            20: #ifndef lint
        !            21: static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclExpr.c,v 1.35 92/03/23 09:53:46 ouster Exp $ SPRITE (Berkeley)";
        !            22: #endif
        !            23: 
        !            24: #include "tclint.h"
        !            25: 
        !            26: /*
        !            27:  * The stuff below is a bit of a workaround so that this file can be used
        !            28:  * in environments that include no UNIX, i.e. no errno.  Just define
        !            29:  * errno here.
        !            30:  */
        !            31: 
        !            32: #ifndef TCL_GENERIC_ONLY
        !            33: #include "tclunix.h"
        !            34: #else
        !            35: int errno;
        !            36: #define ERANGE 34
        !            37: #endif
        !            38: 
        !            39: /*
        !            40:  * The data structure below is used to describe an expression value,
        !            41:  * which can be either an integer (the usual case), a double-precision
        !            42:  * floating-point value, or a string.  A given number has only one
        !            43:  * value at a time.
        !            44:  */
        !            45: 
        !            46: #define STATIC_STRING_SPACE 150
        !            47: 
        !            48: typedef struct {
        !            49:     long intValue;             /* Integer value, if any. */
        !            50:     double  doubleValue;       /* Floating-point value, if any. */
        !            51:     ParseValue pv;             /* Used to hold a string value, if any. */
        !            52:     char staticSpace[STATIC_STRING_SPACE];
        !            53:                                /* Storage for small strings;  large ones
        !            54:                                 * are malloc-ed. */
        !            55:     int type;                  /* Type of value:  TYPE_INT, TYPE_DOUBLE,
        !            56:                                 * or TYPE_STRING. */
        !            57: } Value;
        !            58: 
        !            59: /*
        !            60:  * Valid values for type:
        !            61:  */
        !            62: 
        !            63: #define TYPE_INT       0
        !            64: #define TYPE_DOUBLE    1
        !            65: #define TYPE_STRING    2
        !            66: 
        !            67: 
        !            68: /*
        !            69:  * The data structure below describes the state of parsing an expression.
        !            70:  * It's passed among the routines in this module.
        !            71:  */
        !            72: 
        !            73: typedef struct {
        !            74:     char *originalExpr;                /* The entire expression, as originally
        !            75:                                 * passed to Tcl_Expr. */
        !            76:     char *expr;                        /* Position to the next character to be
        !            77:                                 * scanned from the expression string. */
        !            78:     int token;                 /* Type of the last token to be parsed from
        !            79:                                 * expr.  See below for definitions.
        !            80:                                 * Corresponds to the characters just
        !            81:                                 * before expr. */
        !            82: } ExprInfo;
        !            83: 
        !            84: /*
        !            85:  * The token types are defined below.  In addition, there is a table
        !            86:  * associating a precedence with each operator.  The order of types
        !            87:  * is important.  Consult the code before changing it.
        !            88:  */
        !            89: 
        !            90: #define VALUE          0
        !            91: #define OPEN_PAREN     1
        !            92: #define CLOSE_PAREN    2
        !            93: #define END            3
        !            94: #define UNKNOWN                4
        !            95: 
        !            96: /*
        !            97:  * Binary operators:
        !            98:  */
        !            99: 
        !           100: #define MULT           8
        !           101: #define DIVIDE         9
        !           102: #define MOD            10
        !           103: #define PLUS           11
        !           104: #define MINUS          12
        !           105: #define LEFT_SHIFT     13
        !           106: #define RIGHT_SHIFT    14
        !           107: #define LESS           15
        !           108: #define GREATER                16
        !           109: #define LEQ            17
        !           110: #define GEQ            18
        !           111: #define EQUAL          19
        !           112: #define NEQ            20
        !           113: #define BIT_AND                21
        !           114: #define BIT_XOR                22
        !           115: #define BIT_OR         23
        !           116: #define AND            24
        !           117: #define OR             25
        !           118: #define QUESTY         26
        !           119: #define COLON          27
        !           120: 
        !           121: /*
        !           122:  * Unary operators:
        !           123:  */
        !           124: 
        !           125: #define        UNARY_MINUS     28
        !           126: #define NOT            29
        !           127: #define BIT_NOT                30
        !           128: 
        !           129: /*
        !           130:  * Precedence table.  The values for non-operator token types are ignored.
        !           131:  */
        !           132: 
        !           133: int precTable[] = {
        !           134:     0, 0, 0, 0, 0, 0, 0, 0,
        !           135:     11, 11, 11,                                /* MULT, DIVIDE, MOD */
        !           136:     10, 10,                            /* PLUS, MINUS */
        !           137:     9, 9,                              /* LEFT_SHIFT, RIGHT_SHIFT */
        !           138:     8, 8, 8, 8,                                /* LESS, GREATER, LEQ, GEQ */
        !           139:     7, 7,                              /* EQUAL, NEQ */
        !           140:     6,                                 /* BIT_AND */
        !           141:     5,                                 /* BIT_XOR */
        !           142:     4,                                 /* BIT_OR */
        !           143:     3,                                 /* AND */
        !           144:     2,                                 /* OR */
        !           145:     1, 1,                              /* QUESTY, COLON */
        !           146:     12, 12, 12                         /* UNARY_MINUS, NOT, BIT_NOT */
        !           147: };
        !           148: 
        !           149: /*
        !           150:  * Mapping from operator numbers to strings;  used for error messages.
        !           151:  */
        !           152: 
        !           153: char *operatorStrings[] = {
        !           154:     "VALUE", "(", ")", "END", "UNKNOWN", "5", "6", "7",
        !           155:     "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=",
        !           156:     ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", ":",
        !           157:     "-", "!", "~"
        !           158: };
        !           159: 
        !           160: /*
        !           161:  * Declarations for local procedures to this file:
        !           162:  */
        !           163: 
        !           164: static int             ExprGetValue _ANSI_ARGS_((Tcl_Interp *interp,
        !           165:                            ExprInfo *infoPtr, int prec, Value *valuePtr));
        !           166: static int             ExprLex _ANSI_ARGS_((Tcl_Interp *interp,
        !           167:                            ExprInfo *infoPtr, Value *valuePtr));
        !           168: static void            ExprMakeString _ANSI_ARGS_((Value *valuePtr));
        !           169: static int             ExprParseString _ANSI_ARGS_((Tcl_Interp *interp,
        !           170:                            char *string, Value *valuePtr));
        !           171: static int             ExprTopLevel _ANSI_ARGS_((Tcl_Interp *interp,
        !           172:                            char *string, Value *valuePtr));
        !           173: 
        !           174: /*
        !           175:  *--------------------------------------------------------------
        !           176:  *
        !           177:  * ExprParseString --
        !           178:  *
        !           179:  *     Given a string (such as one coming from command or variable
        !           180:  *     substitution), make a Value based on the string.  The value
        !           181:  *     will be a floating-point or integer, if possible, or else it
        !           182:  *     will just be a copy of the string.
        !           183:  *
        !           184:  * Results:
        !           185:  *     TCL_OK is returned under normal circumstances, and TCL_ERROR
        !           186:  *     is returned if a floating-point overflow or underflow occurred
        !           187:  *     while reading in a number.  The value at *valuePtr is modified
        !           188:  *     to hold a number, if possible.
        !           189:  *
        !           190:  * Side effects:
        !           191:  *     None.
        !           192:  *
        !           193:  *--------------------------------------------------------------
        !           194:  */
        !           195: 
        !           196: static int
        !           197: ExprParseString(interp, string, valuePtr)
        !           198:     Tcl_Interp *interp;                /* Where to store error message. */
        !           199:     char *string;              /* String to turn into value. */
        !           200:     Value *valuePtr;           /* Where to store value information. 
        !           201:                                 * Caller must have initialized pv field. */
        !           202: {
        !           203:     register char c;
        !           204: 
        !           205:     /*
        !           206:      * Try to convert the string to a number.
        !           207:      */
        !           208: 
        !           209:     c = *string;
        !           210:     if (((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')) {
        !           211:        char *term;
        !           212: 
        !           213:        valuePtr->type = TYPE_INT;
        !           214:        errno = 0;
        !           215:        valuePtr->intValue = strtol(string, &term, 0);
        !           216:        c = *term;
        !           217:        if ((c == '\0') && (errno != ERANGE)) {
        !           218:            return TCL_OK;
        !           219:        }
        !           220:        if ((c == '.') || (c == 'e') || (c == 'E') || (errno == ERANGE)) {
        !           221:            errno = 0;
        !           222:            valuePtr->doubleValue = strtod(string, &term);
        !           223:            if (errno == ERANGE) {
        !           224:                Tcl_ResetResult(interp);
        !           225:                if (valuePtr->doubleValue == 0.0) {
        !           226:                    Tcl_AppendResult(interp, "floating-point value \"",
        !           227:                            string, "\" too small to represent",
        !           228:                            (char *) NULL);
        !           229:                } else {
        !           230:                    Tcl_AppendResult(interp, "floating-point value \"",
        !           231:                            string, "\" too large to represent",
        !           232:                            (char *) NULL);
        !           233:                }
        !           234:                return TCL_ERROR;
        !           235:            }
        !           236:            if (*term == '\0') {
        !           237:                valuePtr->type = TYPE_DOUBLE;
        !           238:                return TCL_OK;
        !           239:            }
        !           240:        }
        !           241:     }
        !           242: 
        !           243:     /*
        !           244:      * Not a valid number.  Save a string value (but don't do anything
        !           245:      * if it's already the value).
        !           246:      */
        !           247: 
        !           248:     valuePtr->type = TYPE_STRING;
        !           249:     if (string != valuePtr->pv.buffer) {
        !           250:        int length, shortfall;
        !           251: 
        !           252:        length = strlen(string);
        !           253:        valuePtr->pv.next = valuePtr->pv.buffer;
        !           254:        shortfall = length - (valuePtr->pv.end - valuePtr->pv.buffer);
        !           255:        if (shortfall > 0) {
        !           256:            (*valuePtr->pv.expandProc)(&valuePtr->pv, shortfall);
        !           257:        }
        !           258:        strcpy(valuePtr->pv.buffer, string);
        !           259:     }
        !           260:     return TCL_OK;
        !           261: }
        !           262: 
        !           263: /*
        !           264:  *----------------------------------------------------------------------
        !           265:  *
        !           266:  * ExprLex --
        !           267:  *
        !           268:  *     Lexical analyzer for expression parser:  parses a single value,
        !           269:  *     operator, or other syntactic element from an expression string.
        !           270:  *
        !           271:  * Results:
        !           272:  *     TCL_OK is returned unless an error occurred while doing lexical
        !           273:  *     analysis or executing an embedded command.  In that case a
        !           274:  *     standard Tcl error is returned, using interp->result to hold
        !           275:  *     an error message.  In the event of a successful return, the token
        !           276:  *     and field in infoPtr is updated to refer to the next symbol in
        !           277:  *     the expression string, and the expr field is advanced past that
        !           278:  *     token;  if the token is a value, then the value is stored at
        !           279:  *     valuePtr.
        !           280:  *
        !           281:  * Side effects:
        !           282:  *     None.
        !           283:  *
        !           284:  *----------------------------------------------------------------------
        !           285:  */
        !           286: 
        !           287: static int
        !           288: ExprLex(interp, infoPtr, valuePtr)
        !           289:     Tcl_Interp *interp;                        /* Interpreter to use for error
        !           290:                                         * reporting. */
        !           291:     register ExprInfo *infoPtr;                /* Describes the state of the parse. */
        !           292:     register Value *valuePtr;          /* Where to store value, if that is
        !           293:                                         * what's parsed from string.  Caller
        !           294:                                         * must have initialized pv field
        !           295:                                         * correctly. */
        !           296: {
        !           297:     register char *p, c;
        !           298:     char *var, *term;
        !           299:     int result;
        !           300: 
        !           301:     p = infoPtr->expr;
        !           302:     c = *p;
        !           303:     while (isspace(c)) {
        !           304:        p++;
        !           305:        c = *p;
        !           306:     }
        !           307:     infoPtr->expr = p+1;
        !           308:     switch (c) {
        !           309:        case '0':
        !           310:        case '1':
        !           311:        case '2':
        !           312:        case '3':
        !           313:        case '4':
        !           314:        case '5':
        !           315:        case '6':
        !           316:        case '7':
        !           317:        case '8':
        !           318:        case '9':
        !           319:        case '.':
        !           320: 
        !           321:            /*
        !           322:             * Number.  First read an integer.  Then if it looks like
        !           323:             * there's a floating-point number (or if it's too big a
        !           324:             * number to fit in an integer), parse it as a floating-point
        !           325:             * number.
        !           326:             */
        !           327: 
        !           328:            infoPtr->token = VALUE;
        !           329:            valuePtr->type = TYPE_INT;
        !           330:            errno = 0;
        !           331:            valuePtr->intValue = strtoul(p, &term, 0);
        !           332:            c = *term;
        !           333:            if ((c == '.') || (c == 'e') || (c == 'E') || (errno == ERANGE)) {
        !           334:                char *term2;
        !           335: 
        !           336:                errno = 0;
        !           337:                valuePtr->doubleValue = strtod(p, &term2);
        !           338:                if (errno == ERANGE) {
        !           339:                    Tcl_ResetResult(interp);
        !           340:                    if (valuePtr->doubleValue == 0.0) {
        !           341:                        interp->result =
        !           342:                                "floating-point value too small to represent";
        !           343:                    } else {
        !           344:                        interp->result =
        !           345:                                "floating-point value too large to represent";
        !           346:                    }
        !           347:                    return TCL_ERROR;
        !           348:                }
        !           349:                if (term2 == infoPtr->expr) {
        !           350:                    interp->result = "poorly-formed floating-point value";
        !           351:                    return TCL_ERROR;
        !           352:                }
        !           353:                valuePtr->type = TYPE_DOUBLE;
        !           354:                infoPtr->expr = term2;
        !           355:            } else {
        !           356:                infoPtr->expr = term;
        !           357:            }
        !           358:            return TCL_OK;
        !           359: 
        !           360:        case '$':
        !           361: 
        !           362:            /*
        !           363:             * Variable.  Fetch its value, then see if it makes sense
        !           364:             * as an integer or floating-point number.
        !           365:             */
        !           366: 
        !           367:            infoPtr->token = VALUE;
        !           368:            var = Tcl_ParseVar(interp, p, &infoPtr->expr);
        !           369:            if (var == NULL) {
        !           370:                return TCL_ERROR;
        !           371:            }
        !           372:            if (((Interp *) interp)->noEval) {
        !           373:                valuePtr->type = TYPE_INT;
        !           374:                valuePtr->intValue = 0;
        !           375:                return TCL_OK;
        !           376:            }
        !           377:            return ExprParseString(interp, var, valuePtr);
        !           378: 
        !           379:        case '[':
        !           380:            infoPtr->token = VALUE;
        !           381:            result = Tcl_Eval(interp, p+1, TCL_BRACKET_TERM,
        !           382:                    &infoPtr->expr);
        !           383:            if (result != TCL_OK) {
        !           384:                return result;
        !           385:            }
        !           386:            infoPtr->expr++;
        !           387:            if (((Interp *) interp)->noEval) {
        !           388:                valuePtr->type = TYPE_INT;
        !           389:                valuePtr->intValue = 0;
        !           390:                Tcl_ResetResult(interp);
        !           391:                return TCL_OK;
        !           392:            }
        !           393:            result = ExprParseString(interp, interp->result, valuePtr);
        !           394:            if (result != TCL_OK) {
        !           395:                return result;
        !           396:            }
        !           397:            Tcl_ResetResult(interp);
        !           398:            return TCL_OK;
        !           399: 
        !           400:        case '"':
        !           401:            infoPtr->token = VALUE;
        !           402:            result = TclParseQuotes(interp, infoPtr->expr, '"', 0,
        !           403:                    &infoPtr->expr, &valuePtr->pv);
        !           404:            if (result != TCL_OK) {
        !           405:                return result;
        !           406:            }
        !           407:            return ExprParseString(interp, valuePtr->pv.buffer, valuePtr);
        !           408: 
        !           409:        case '{':
        !           410:            infoPtr->token = VALUE;
        !           411:            result = TclParseBraces(interp, infoPtr->expr, &infoPtr->expr,
        !           412:                    &valuePtr->pv);
        !           413:            if (result != TCL_OK) {
        !           414:                return result;
        !           415:            }
        !           416:            return ExprParseString(interp, valuePtr->pv.buffer, valuePtr);
        !           417: 
        !           418:        case '(':
        !           419:            infoPtr->token = OPEN_PAREN;
        !           420:            return TCL_OK;
        !           421: 
        !           422:        case ')':
        !           423:            infoPtr->token = CLOSE_PAREN;
        !           424:            return TCL_OK;
        !           425: 
        !           426:        case '*':
        !           427:            infoPtr->token = MULT;
        !           428:            return TCL_OK;
        !           429: 
        !           430:        case '/':
        !           431:            infoPtr->token = DIVIDE;
        !           432:            return TCL_OK;
        !           433: 
        !           434:        case '%':
        !           435:            infoPtr->token = MOD;
        !           436:            return TCL_OK;
        !           437: 
        !           438:        case '+':
        !           439:            infoPtr->token = PLUS;
        !           440:            return TCL_OK;
        !           441: 
        !           442:        case '-':
        !           443:            infoPtr->token = MINUS;
        !           444:            return TCL_OK;
        !           445: 
        !           446:        case '?':
        !           447:            infoPtr->token = QUESTY;
        !           448:            return TCL_OK;
        !           449: 
        !           450:        case ':':
        !           451:            infoPtr->token = COLON;
        !           452:            return TCL_OK;
        !           453: 
        !           454:        case '<':
        !           455:            switch (p[1]) {
        !           456:                case '<':
        !           457:                    infoPtr->expr = p+2;
        !           458:                    infoPtr->token = LEFT_SHIFT;
        !           459:                    break;
        !           460:                case '=':
        !           461:                    infoPtr->expr = p+2;
        !           462:                    infoPtr->token = LEQ;
        !           463:                    break;
        !           464:                default:
        !           465:                    infoPtr->token = LESS;
        !           466:                    break;
        !           467:            }
        !           468:            return TCL_OK;
        !           469: 
        !           470:        case '>':
        !           471:            switch (p[1]) {
        !           472:                case '>':
        !           473:                    infoPtr->expr = p+2;
        !           474:                    infoPtr->token = RIGHT_SHIFT;
        !           475:                    break;
        !           476:                case '=':
        !           477:                    infoPtr->expr = p+2;
        !           478:                    infoPtr->token = GEQ;
        !           479:                    break;
        !           480:                default:
        !           481:                    infoPtr->token = GREATER;
        !           482:                    break;
        !           483:            }
        !           484:            return TCL_OK;
        !           485: 
        !           486:        case '=':
        !           487:            if (p[1] == '=') {
        !           488:                infoPtr->expr = p+2;
        !           489:                infoPtr->token = EQUAL;
        !           490:            } else {
        !           491:                infoPtr->token = UNKNOWN;
        !           492:            }
        !           493:            return TCL_OK;
        !           494: 
        !           495:        case '!':
        !           496:            if (p[1] == '=') {
        !           497:                infoPtr->expr = p+2;
        !           498:                infoPtr->token = NEQ;
        !           499:            } else {
        !           500:                infoPtr->token = NOT;
        !           501:            }
        !           502:            return TCL_OK;
        !           503: 
        !           504:        case '&':
        !           505:            if (p[1] == '&') {
        !           506:                infoPtr->expr = p+2;
        !           507:                infoPtr->token = AND;
        !           508:            } else {
        !           509:                infoPtr->token = BIT_AND;
        !           510:            }
        !           511:            return TCL_OK;
        !           512: 
        !           513:        case '^':
        !           514:            infoPtr->token = BIT_XOR;
        !           515:            return TCL_OK;
        !           516: 
        !           517:        case '|':
        !           518:            if (p[1] == '|') {
        !           519:                infoPtr->expr = p+2;
        !           520:                infoPtr->token = OR;
        !           521:            } else {
        !           522:                infoPtr->token = BIT_OR;
        !           523:            }
        !           524:            return TCL_OK;
        !           525: 
        !           526:        case '~':
        !           527:            infoPtr->token = BIT_NOT;
        !           528:            return TCL_OK;
        !           529: 
        !           530:        case 0:
        !           531:            infoPtr->token = END;
        !           532:            infoPtr->expr = p;
        !           533:            return TCL_OK;
        !           534: 
        !           535:        default:
        !           536:            infoPtr->expr = p+1;
        !           537:            infoPtr->token = UNKNOWN;
        !           538:            return TCL_OK;
        !           539:     }
        !           540: }
        !           541: 
        !           542: /*
        !           543:  *----------------------------------------------------------------------
        !           544:  *
        !           545:  * ExprGetValue --
        !           546:  *
        !           547:  *     Parse a "value" from the remainder of the expression in infoPtr.
        !           548:  *
        !           549:  * Results:
        !           550:  *     Normally TCL_OK is returned.  The value of the expression is
        !           551:  *     returned in *valuePtr.  If an error occurred, then interp->result
        !           552:  *     contains an error message and TCL_ERROR is returned.
        !           553:  *     InfoPtr->token will be left pointing to the token AFTER the
        !           554:  *     expression, and infoPtr->expr will point to the character just
        !           555:  *     after the terminating token.
        !           556:  *
        !           557:  * Side effects:
        !           558:  *     None.
        !           559:  *
        !           560:  *----------------------------------------------------------------------
        !           561:  */
        !           562: 
        !           563: static int
        !           564: ExprGetValue(interp, infoPtr, prec, valuePtr)
        !           565:     Tcl_Interp *interp;                        /* Interpreter to use for error
        !           566:                                         * reporting. */
        !           567:     register ExprInfo *infoPtr;                /* Describes the state of the parse
        !           568:                                         * just before the value (i.e. ExprLex
        !           569:                                         * will be called to get first token
        !           570:                                         * of value). */
        !           571:     int prec;                          /* Treat any un-parenthesized operator
        !           572:                                         * with precedence <= this as the end
        !           573:                                         * of the expression. */
        !           574:     Value *valuePtr;                   /* Where to store the value of the
        !           575:                                         * expression.   Caller must have
        !           576:                                         * initialized pv field. */
        !           577: {
        !           578:     Interp *iPtr = (Interp *) interp;
        !           579:     Value value2;                      /* Second operand for current
        !           580:                                         * operator.  */
        !           581:     int operator;                      /* Current operator (either unary
        !           582:                                         * or binary). */
        !           583:     int badType;                       /* Type of offending argument;  used
        !           584:                                         * for error messages. */
        !           585:     int gotOp;                         /* Non-zero means already lexed the
        !           586:                                         * operator (while picking up value
        !           587:                                         * for unary operator).  Don't lex
        !           588:                                         * again. */
        !           589:     int result;
        !           590: 
        !           591:     /*
        !           592:      * There are two phases to this procedure.  First, pick off an initial
        !           593:      * value.  Then, parse (binary operator, value) pairs until done.
        !           594:      */
        !           595: 
        !           596:     gotOp = 0;
        !           597:     value2.pv.buffer = value2.pv.next = value2.staticSpace;
        !           598:     value2.pv.end = value2.pv.buffer + STATIC_STRING_SPACE - 1;
        !           599:     value2.pv.expandProc = TclExpandParseValue;
        !           600:     value2.pv.clientData = (ClientData) NULL;
        !           601:     result = ExprLex(interp, infoPtr, valuePtr);
        !           602:     if (result != TCL_OK) {
        !           603:        goto done;
        !           604:     }
        !           605:     if (infoPtr->token == OPEN_PAREN) {
        !           606: 
        !           607:        /*
        !           608:         * Parenthesized sub-expression.
        !           609:         */
        !           610: 
        !           611:        result = ExprGetValue(interp, infoPtr, -1, valuePtr);
        !           612:        if (result != TCL_OK) {
        !           613:            goto done;
        !           614:        }
        !           615:        if (infoPtr->token != CLOSE_PAREN) {
        !           616:            Tcl_ResetResult(interp);
        !           617:            sprintf(interp->result,
        !           618:                    "unmatched parentheses in expression \"%.50s\"",
        !           619:                    infoPtr->originalExpr);
        !           620:            result = TCL_ERROR;
        !           621:            goto done;
        !           622:        }
        !           623:     } else {
        !           624:        if (infoPtr->token == MINUS) {
        !           625:            infoPtr->token = UNARY_MINUS;
        !           626:        }
        !           627:        if (infoPtr->token >= UNARY_MINUS) {
        !           628: 
        !           629:            /*
        !           630:             * Process unary operators.
        !           631:             */
        !           632: 
        !           633:            operator = infoPtr->token;
        !           634:            result = ExprGetValue(interp, infoPtr, precTable[infoPtr->token],
        !           635:                    valuePtr);
        !           636:            if (result != TCL_OK) {
        !           637:                goto done;
        !           638:            }
        !           639:            switch (operator) {
        !           640:                case UNARY_MINUS:
        !           641:                    if (valuePtr->type == TYPE_INT) {
        !           642:                        valuePtr->intValue = -valuePtr->intValue;
        !           643:                    } else if (valuePtr->type == TYPE_DOUBLE){
        !           644:                        valuePtr->doubleValue = -valuePtr->doubleValue;
        !           645:                    } else {
        !           646:                        badType = valuePtr->type;
        !           647:                        goto illegalType;
        !           648:                    } 
        !           649:                    break;
        !           650:                case NOT:
        !           651:                    if (valuePtr->type == TYPE_INT) {
        !           652:                        valuePtr->intValue = !valuePtr->intValue;
        !           653:                    } else if (valuePtr->type == TYPE_DOUBLE) {
        !           654:                        /*
        !           655:                         * Theoretically, should be able to use
        !           656:                         * "!valuePtr->intValue", but apparently some
        !           657:                         * compilers can't handle it.
        !           658:                         */
        !           659:                        if (valuePtr->doubleValue == 0.0) {
        !           660:                            valuePtr->intValue = 1;
        !           661:                        } else {
        !           662:                            valuePtr->intValue = 0;
        !           663:                        }
        !           664:                        valuePtr->type = TYPE_INT;
        !           665:                    } else {
        !           666:                        badType = valuePtr->type;
        !           667:                        goto illegalType;
        !           668:                    }
        !           669:                    break;
        !           670:                case BIT_NOT:
        !           671:                    if (valuePtr->type == TYPE_INT) {
        !           672:                        valuePtr->intValue = ~valuePtr->intValue;
        !           673:                    } else {
        !           674:                        badType  = valuePtr->type;
        !           675:                        goto illegalType;
        !           676:                    }
        !           677:                    break;
        !           678:            }
        !           679:            gotOp = 1;
        !           680:        } else if (infoPtr->token != VALUE) {
        !           681:            goto syntaxError;
        !           682:        }
        !           683:     }
        !           684: 
        !           685:     /*
        !           686:      * Got the first operand.  Now fetch (operator, operand) pairs.
        !           687:      */
        !           688: 
        !           689:     if (!gotOp) {
        !           690:        result = ExprLex(interp, infoPtr, &value2);
        !           691:        if (result != TCL_OK) {
        !           692:            goto done;
        !           693:        }
        !           694:     }
        !           695:     while (1) {
        !           696:        operator = infoPtr->token;
        !           697:        value2.pv.next = value2.pv.buffer;
        !           698:        if ((operator < MULT) || (operator >= UNARY_MINUS)) {
        !           699:            if ((operator == END) || (operator == CLOSE_PAREN)) {
        !           700:                result = TCL_OK;
        !           701:                goto done;
        !           702:            } else {
        !           703:                goto syntaxError;
        !           704:            }
        !           705:        }
        !           706:        if (precTable[operator] <= prec) {
        !           707:            result = TCL_OK;
        !           708:            goto done;
        !           709:        }
        !           710: 
        !           711:        /*
        !           712:         * If we're doing an AND or OR and the first operand already
        !           713:         * determines the result, don't execute anything in the
        !           714:         * second operand:  just parse.  Same style for ?: pairs.
        !           715:         */
        !           716: 
        !           717:        if ((operator == AND) || (operator == OR) || (operator == QUESTY)) {
        !           718:            if (valuePtr->type == TYPE_DOUBLE) {
        !           719:                valuePtr->intValue = valuePtr->doubleValue != 0;
        !           720:                valuePtr->type = TYPE_INT;
        !           721:            } else if (valuePtr->type == TYPE_STRING) {
        !           722:                badType = TYPE_STRING;
        !           723:                goto illegalType;
        !           724:            }
        !           725:            if (((operator == AND) && !valuePtr->intValue)
        !           726:                    || ((operator == OR) && valuePtr->intValue)) {
        !           727:                iPtr->noEval++;
        !           728:                result = ExprGetValue(interp, infoPtr, precTable[operator],
        !           729:                        &value2);
        !           730:                iPtr->noEval--;
        !           731:            } else if (operator == QUESTY) {
        !           732:                if (valuePtr->intValue != 0) {
        !           733:                    valuePtr->pv.next = valuePtr->pv.buffer;
        !           734:                    result = ExprGetValue(interp, infoPtr, precTable[operator],
        !           735:                            valuePtr);
        !           736:                    if (result != TCL_OK) {
        !           737:                        goto done;
        !           738:                    }
        !           739:                    if (infoPtr->token != COLON) {
        !           740:                        goto syntaxError;
        !           741:                    }
        !           742:                    value2.pv.next = value2.pv.buffer;
        !           743:                    iPtr->noEval++;
        !           744:                    result = ExprGetValue(interp, infoPtr, precTable[operator],
        !           745:                            &value2);
        !           746:                    iPtr->noEval--;
        !           747:                } else {
        !           748:                    iPtr->noEval++;
        !           749:                    result = ExprGetValue(interp, infoPtr, precTable[operator],
        !           750:                            &value2);
        !           751:                    iPtr->noEval--;
        !           752:                    if (result != TCL_OK) {
        !           753:                        goto done;
        !           754:                    }
        !           755:                    if (infoPtr->token != COLON) {
        !           756:                        goto syntaxError;
        !           757:                    }
        !           758:                    valuePtr->pv.next = valuePtr->pv.buffer;
        !           759:                    result = ExprGetValue(interp, infoPtr, precTable[operator],
        !           760:                            valuePtr);
        !           761:                }
        !           762:            } else {
        !           763:                result = ExprGetValue(interp, infoPtr, precTable[operator],
        !           764:                        &value2);
        !           765:            }
        !           766:        } else {
        !           767:            result = ExprGetValue(interp, infoPtr, precTable[operator],
        !           768:                    &value2);
        !           769:        }
        !           770:        if (result != TCL_OK) {
        !           771:            goto done;
        !           772:        }
        !           773:        if ((infoPtr->token < MULT) && (infoPtr->token != VALUE)
        !           774:                && (infoPtr->token != END)
        !           775:                && (infoPtr->token != CLOSE_PAREN)) {
        !           776:            goto syntaxError;
        !           777:        }
        !           778: 
        !           779:        /*
        !           780:         * At this point we've got two values and an operator.  Check
        !           781:         * to make sure that the particular data types are appropriate
        !           782:         * for the particular operator, and perform type conversion
        !           783:         * if necessary.
        !           784:         */
        !           785: 
        !           786:        switch (operator) {
        !           787: 
        !           788:            /*
        !           789:             * For the operators below, no strings are allowed and
        !           790:             * ints get converted to floats if necessary.
        !           791:             */
        !           792: 
        !           793:            case MULT: case DIVIDE: case PLUS: case MINUS:
        !           794:                if ((valuePtr->type == TYPE_STRING)
        !           795:                        || (value2.type == TYPE_STRING)) {
        !           796:                    badType = TYPE_STRING;
        !           797:                    goto illegalType;
        !           798:                }
        !           799:                if (valuePtr->type == TYPE_DOUBLE) {
        !           800:                    if (value2.type == TYPE_INT) {
        !           801:                        value2.doubleValue = value2.intValue;
        !           802:                        value2.type = TYPE_DOUBLE;
        !           803:                    }
        !           804:                } else if (value2.type == TYPE_DOUBLE) {
        !           805:                    if (valuePtr->type == TYPE_INT) {
        !           806:                        valuePtr->doubleValue = valuePtr->intValue;
        !           807:                        valuePtr->type = TYPE_DOUBLE;
        !           808:                    }
        !           809:                }
        !           810:                break;
        !           811: 
        !           812:            /*
        !           813:             * For the operators below, only integers are allowed.
        !           814:             */
        !           815: 
        !           816:            case MOD: case LEFT_SHIFT: case RIGHT_SHIFT:
        !           817:            case BIT_AND: case BIT_XOR: case BIT_OR:
        !           818:                 if (valuePtr->type != TYPE_INT) {
        !           819:                     badType = valuePtr->type;
        !           820:                     goto illegalType;
        !           821:                 } else if (value2.type != TYPE_INT) {
        !           822:                     badType = value2.type;
        !           823:                     goto illegalType;
        !           824:                 }
        !           825:                 break;
        !           826: 
        !           827:            /*
        !           828:             * For the operators below, any type is allowed but the
        !           829:             * two operands must have the same type.  Convert integers
        !           830:             * to floats and either to strings, if necessary.
        !           831:             */
        !           832: 
        !           833:            case LESS: case GREATER: case LEQ: case GEQ:
        !           834:            case EQUAL: case NEQ:
        !           835:                if (valuePtr->type == TYPE_STRING) {
        !           836:                    if (value2.type != TYPE_STRING) {
        !           837:                        ExprMakeString(&value2);
        !           838:                    }
        !           839:                } else if (value2.type == TYPE_STRING) {
        !           840:                    if (valuePtr->type != TYPE_STRING) {
        !           841:                        ExprMakeString(valuePtr);
        !           842:                    }
        !           843:                } else if (valuePtr->type == TYPE_DOUBLE) {
        !           844:                    if (value2.type == TYPE_INT) {
        !           845:                        value2.doubleValue = value2.intValue;
        !           846:                        value2.type = TYPE_DOUBLE;
        !           847:                    }
        !           848:                } else if (value2.type == TYPE_DOUBLE) {
        !           849:                     if (valuePtr->type == TYPE_INT) {
        !           850:                        valuePtr->doubleValue = valuePtr->intValue;
        !           851:                        valuePtr->type = TYPE_DOUBLE;
        !           852:                    }
        !           853:                }
        !           854:                break;
        !           855: 
        !           856:            /*
        !           857:             * For the operators below, no strings are allowed, but
        !           858:             * no int->double conversions are performed.
        !           859:             */
        !           860: 
        !           861:            case AND: case OR:
        !           862:                if (valuePtr->type == TYPE_STRING) {
        !           863:                    badType = valuePtr->type;
        !           864:                    goto illegalType;
        !           865:                }
        !           866:                if (value2.type == TYPE_STRING) {
        !           867:                    badType = value2.type;
        !           868:                    goto illegalType;
        !           869:                }
        !           870:                break;
        !           871: 
        !           872:            /*
        !           873:             * For the operators below, type and conversions are
        !           874:             * irrelevant:  they're handled elsewhere.
        !           875:             */
        !           876: 
        !           877:            case QUESTY: case COLON:
        !           878:                break;
        !           879: 
        !           880:            /*
        !           881:             * Any other operator is an error.
        !           882:             */
        !           883: 
        !           884:            default:
        !           885:                interp->result = "unknown operator in expression";
        !           886:                result = TCL_ERROR;
        !           887:                goto done;
        !           888:        }
        !           889: 
        !           890:        /*
        !           891:         * If necessary, convert one of the operands to the type
        !           892:         * of the other.  If the operands are incompatible with
        !           893:         * the operator (e.g. "+" on strings) then return an
        !           894:         * error.
        !           895:         */
        !           896: 
        !           897:        switch (operator) {
        !           898:            case MULT:
        !           899:                if (valuePtr->type == TYPE_INT) {
        !           900:                    valuePtr->intValue *= value2.intValue;
        !           901:                } else {
        !           902:                    valuePtr->doubleValue *= value2.doubleValue;
        !           903:                }
        !           904:                break;
        !           905:            case DIVIDE:
        !           906:                if (valuePtr->type == TYPE_INT) {
        !           907:                    if (value2.intValue == 0) {
        !           908:                        divideByZero:
        !           909:                        interp->result = "divide by zero";
        !           910:                        result = TCL_ERROR;
        !           911:                        goto done;
        !           912:                    }
        !           913:                    valuePtr->intValue /= value2.intValue;
        !           914:                } else {
        !           915:                    if (value2.doubleValue == 0.0) {
        !           916:                        goto divideByZero;
        !           917:                    }
        !           918:                    valuePtr->doubleValue /= value2.doubleValue;
        !           919:                }
        !           920:                break;
        !           921:            case MOD:
        !           922:                if (value2.intValue == 0) {
        !           923:                    goto divideByZero;
        !           924:                }
        !           925:                valuePtr->intValue %= value2.intValue;
        !           926:                break;
        !           927:            case PLUS:
        !           928:                if (valuePtr->type == TYPE_INT) {
        !           929:                    valuePtr->intValue += value2.intValue;
        !           930:                } else {
        !           931:                    valuePtr->doubleValue += value2.doubleValue;
        !           932:                }
        !           933:                break;
        !           934:            case MINUS:
        !           935:                if (valuePtr->type == TYPE_INT) {
        !           936:                    valuePtr->intValue -= value2.intValue;
        !           937:                } else {
        !           938:                    valuePtr->doubleValue -= value2.doubleValue;
        !           939:                }
        !           940:                break;
        !           941:            case LEFT_SHIFT:
        !           942:                valuePtr->intValue <<= value2.intValue;
        !           943:                break;
        !           944:            case RIGHT_SHIFT:
        !           945:                /*
        !           946:                 * The following code is a bit tricky:  it ensures that
        !           947:                 * right shifts propagate the sign bit even on machines
        !           948:                 * where ">>" won't do it by default.
        !           949:                 */
        !           950: 
        !           951:                if (valuePtr->intValue < 0) {
        !           952:                    valuePtr->intValue =
        !           953:                            ~((~valuePtr->intValue) >> value2.intValue);
        !           954:                } else {
        !           955:                    valuePtr->intValue >>= value2.intValue;
        !           956:                }
        !           957:                break;
        !           958:            case LESS:
        !           959:                if (valuePtr->type == TYPE_INT) {
        !           960:                    valuePtr->intValue =
        !           961:                        valuePtr->intValue < value2.intValue;
        !           962:                } else if (valuePtr->type == TYPE_DOUBLE) {
        !           963:                    valuePtr->intValue =
        !           964:                        valuePtr->doubleValue < value2.doubleValue;
        !           965:                } else {
        !           966:                    valuePtr->intValue =
        !           967:                            strcmp(valuePtr->pv.buffer, value2.pv.buffer) < 0;
        !           968:                }
        !           969:                valuePtr->type = TYPE_INT;
        !           970:                break;
        !           971:            case GREATER:
        !           972:                if (valuePtr->type == TYPE_INT) {
        !           973:                    valuePtr->intValue =
        !           974:                        valuePtr->intValue > value2.intValue;
        !           975:                } else if (valuePtr->type == TYPE_DOUBLE) {
        !           976:                    valuePtr->intValue =
        !           977:                        valuePtr->doubleValue > value2.doubleValue;
        !           978:                } else {
        !           979:                    valuePtr->intValue =
        !           980:                            strcmp(valuePtr->pv.buffer, value2.pv.buffer) > 0;
        !           981:                }
        !           982:                valuePtr->type = TYPE_INT;
        !           983:                break;
        !           984:            case LEQ:
        !           985:                if (valuePtr->type == TYPE_INT) {
        !           986:                    valuePtr->intValue =
        !           987:                        valuePtr->intValue <= value2.intValue;
        !           988:                } else if (valuePtr->type == TYPE_DOUBLE) {
        !           989:                    valuePtr->intValue =
        !           990:                        valuePtr->doubleValue <= value2.doubleValue;
        !           991:                } else {
        !           992:                    valuePtr->intValue =
        !           993:                            strcmp(valuePtr->pv.buffer, value2.pv.buffer) <= 0;
        !           994:                }
        !           995:                valuePtr->type = TYPE_INT;
        !           996:                break;
        !           997:            case GEQ:
        !           998:                if (valuePtr->type == TYPE_INT) {
        !           999:                    valuePtr->intValue =
        !          1000:                        valuePtr->intValue >= value2.intValue;
        !          1001:                } else if (valuePtr->type == TYPE_DOUBLE) {
        !          1002:                    valuePtr->intValue =
        !          1003:                        valuePtr->doubleValue >= value2.doubleValue;
        !          1004:                } else {
        !          1005:                    valuePtr->intValue =
        !          1006:                            strcmp(valuePtr->pv.buffer, value2.pv.buffer) >= 0;
        !          1007:                }
        !          1008:                valuePtr->type = TYPE_INT;
        !          1009:                break;
        !          1010:            case EQUAL:
        !          1011:                if (valuePtr->type == TYPE_INT) {
        !          1012:                    valuePtr->intValue =
        !          1013:                        valuePtr->intValue == value2.intValue;
        !          1014:                } else if (valuePtr->type == TYPE_DOUBLE) {
        !          1015:                    valuePtr->intValue =
        !          1016:                        valuePtr->doubleValue == value2.doubleValue;
        !          1017:                } else {
        !          1018:                    valuePtr->intValue =
        !          1019:                            strcmp(valuePtr->pv.buffer, value2.pv.buffer) == 0;
        !          1020:                }
        !          1021:                valuePtr->type = TYPE_INT;
        !          1022:                break;
        !          1023:            case NEQ:
        !          1024:                if (valuePtr->type == TYPE_INT) {
        !          1025:                    valuePtr->intValue =
        !          1026:                        valuePtr->intValue != value2.intValue;
        !          1027:                } else if (valuePtr->type == TYPE_DOUBLE) {
        !          1028:                    valuePtr->intValue =
        !          1029:                        valuePtr->doubleValue != value2.doubleValue;
        !          1030:                } else {
        !          1031:                    valuePtr->intValue =
        !          1032:                            strcmp(valuePtr->pv.buffer, value2.pv.buffer) != 0;
        !          1033:                }
        !          1034:                valuePtr->type = TYPE_INT;
        !          1035:                break;
        !          1036:            case BIT_AND:
        !          1037:                valuePtr->intValue &= value2.intValue;
        !          1038:                break;
        !          1039:            case BIT_XOR:
        !          1040:                valuePtr->intValue ^= value2.intValue;
        !          1041:                break;
        !          1042:            case BIT_OR:
        !          1043:                valuePtr->intValue |= value2.intValue;
        !          1044:                break;
        !          1045: 
        !          1046:            /*
        !          1047:             * For AND and OR, we know that the first value has already
        !          1048:             * been converted to an integer.  Thus we need only consider
        !          1049:             * the possibility of int vs. double for the second value.
        !          1050:             */
        !          1051: 
        !          1052:            case AND:
        !          1053:                if (value2.type == TYPE_DOUBLE) {
        !          1054:                    value2.intValue = value2.doubleValue != 0;
        !          1055:                    value2.type = TYPE_INT;
        !          1056:                }
        !          1057:                valuePtr->intValue = valuePtr->intValue && value2.intValue;
        !          1058:                break;
        !          1059:            case OR:
        !          1060:                if (value2.type == TYPE_DOUBLE) {
        !          1061:                    value2.intValue = value2.doubleValue != 0;
        !          1062:                    value2.type = TYPE_INT;
        !          1063:                }
        !          1064:                valuePtr->intValue = valuePtr->intValue || value2.intValue;
        !          1065:                break;
        !          1066: 
        !          1067:            case COLON:
        !          1068:                interp->result = "can't have : operator without ? first";
        !          1069:                result = TCL_ERROR;
        !          1070:                goto done;
        !          1071:        }
        !          1072:     }
        !          1073: 
        !          1074:     done:
        !          1075:     if (value2.pv.buffer != value2.staticSpace) {
        !          1076:        ckfree(value2.pv.buffer);
        !          1077:     }
        !          1078:     return result;
        !          1079: 
        !          1080:     syntaxError:
        !          1081:     Tcl_ResetResult(interp);
        !          1082:     Tcl_AppendResult(interp, "syntax error in expression \"",
        !          1083:            infoPtr->originalExpr, "\"", (char *) NULL);
        !          1084:     result = TCL_ERROR;
        !          1085:     goto done;
        !          1086: 
        !          1087:     illegalType:
        !          1088:     Tcl_AppendResult(interp, "can't use ", (badType == TYPE_DOUBLE) ?
        !          1089:            "floating-point value" : "non-numeric string",
        !          1090:            " as operand of \"", operatorStrings[operator], "\"",
        !          1091:            (char *) NULL);
        !          1092:     result = TCL_ERROR;
        !          1093:     goto done;
        !          1094: }
        !          1095: 
        !          1096: /*
        !          1097:  *--------------------------------------------------------------
        !          1098:  *
        !          1099:  * ExprMakeString --
        !          1100:  *
        !          1101:  *     Convert a value from int or double representation to
        !          1102:  *     a string.
        !          1103:  *
        !          1104:  * Results:
        !          1105:  *     The information at *valuePtr gets converted to string
        !          1106:  *     format, if it wasn't that way already.
        !          1107:  *
        !          1108:  * Side effects:
        !          1109:  *     None.
        !          1110:  *
        !          1111:  *--------------------------------------------------------------
        !          1112:  */
        !          1113: 
        !          1114: static void
        !          1115: ExprMakeString(valuePtr)
        !          1116:     register Value *valuePtr;          /* Value to be converted. */
        !          1117: {
        !          1118:     int shortfall;
        !          1119: 
        !          1120:     shortfall = 150 - (valuePtr->pv.end - valuePtr->pv.buffer);
        !          1121:     if (shortfall > 0) {
        !          1122:        (*valuePtr->pv.expandProc)(&valuePtr->pv, shortfall);
        !          1123:     }
        !          1124:     if (valuePtr->type == TYPE_INT) {
        !          1125:        sprintf(valuePtr->pv.buffer, "%ld", valuePtr->intValue);
        !          1126:     } else if (valuePtr->type == TYPE_DOUBLE) {
        !          1127:        sprintf(valuePtr->pv.buffer, "%g", valuePtr->doubleValue);
        !          1128:     }
        !          1129:     valuePtr->type = TYPE_STRING;
        !          1130: }
        !          1131: 
        !          1132: /*
        !          1133:  *--------------------------------------------------------------
        !          1134:  *
        !          1135:  * ExprTopLevel --
        !          1136:  *
        !          1137:  *     This procedure provides top-level functionality shared by
        !          1138:  *     procedures like Tcl_ExprInt, Tcl_ExprDouble, etc.
        !          1139:  *
        !          1140:  * Results:
        !          1141:  *     The result is a standard Tcl return value.  If an error
        !          1142:  *     occurs then an error message is left in interp->result.
        !          1143:  *     The value of the expression is returned in *valuePtr, in
        !          1144:  *     whatever form it ends up in (could be string or integer
        !          1145:  *     or double).  Caller may need to convert result.  Caller
        !          1146:  *     is also responsible for freeing string memory in *valuePtr,
        !          1147:  *     if any was allocated.
        !          1148:  *
        !          1149:  * Side effects:
        !          1150:  *     None.
        !          1151:  *
        !          1152:  *--------------------------------------------------------------
        !          1153:  */
        !          1154: 
        !          1155: static int
        !          1156: ExprTopLevel(interp, string, valuePtr)
        !          1157:     Tcl_Interp *interp;                        /* Context in which to evaluate the
        !          1158:                                         * expression. */
        !          1159:     char *string;                      /* Expression to evaluate. */
        !          1160:     Value *valuePtr;                   /* Where to store result.  Should
        !          1161:                                         * not be initialized by caller. */
        !          1162: {
        !          1163:     ExprInfo info;
        !          1164:     int result;
        !          1165: 
        !          1166:     info.originalExpr = string;
        !          1167:     info.expr = string;
        !          1168:     valuePtr->pv.buffer = valuePtr->pv.next = valuePtr->staticSpace;
        !          1169:     valuePtr->pv.end = valuePtr->pv.buffer + STATIC_STRING_SPACE - 1;
        !          1170:     valuePtr->pv.expandProc = TclExpandParseValue;
        !          1171:     valuePtr->pv.clientData = (ClientData) NULL;
        !          1172: 
        !          1173:     result = ExprGetValue(interp, &info, -1, valuePtr);
        !          1174:     if (result != TCL_OK) {
        !          1175:        return result;
        !          1176:     }
        !          1177:     if (info.token != END) {
        !          1178:        Tcl_AppendResult(interp, "syntax error in expression \"",
        !          1179:                string, "\"", (char *) NULL);
        !          1180:        return TCL_ERROR;
        !          1181:     }
        !          1182:     return TCL_OK;
        !          1183: }
        !          1184: 
        !          1185: /*
        !          1186:  *--------------------------------------------------------------
        !          1187:  *
        !          1188:  * Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean --
        !          1189:  *
        !          1190:  *     Procedures to evaluate an expression and return its value
        !          1191:  *     in a particular form.
        !          1192:  *
        !          1193:  * Results:
        !          1194:  *     Each of the procedures below returns a standard Tcl result.
        !          1195:  *     If an error occurs then an error message is left in
        !          1196:  *     interp->result.  Otherwise the value of the expression,
        !          1197:  *     in the appropriate form, is stored at *resultPtr.  If
        !          1198:  *     the expression had a result that was incompatible with the
        !          1199:  *     desired form then an error is returned.
        !          1200:  *
        !          1201:  * Side effects:
        !          1202:  *     None.
        !          1203:  *
        !          1204:  *--------------------------------------------------------------
        !          1205:  */
        !          1206: 
        !          1207: int
        !          1208: Tcl_ExprLong(interp, string, ptr)
        !          1209:     Tcl_Interp *interp;                        /* Context in which to evaluate the
        !          1210:                                         * expression. */
        !          1211:     char *string;                      /* Expression to evaluate. */
        !          1212:     long *ptr;                         /* Where to store result. */
        !          1213: {
        !          1214:     Value value;
        !          1215:     int result;
        !          1216: 
        !          1217:     result = ExprTopLevel(interp, string, &value);
        !          1218:     if (result == TCL_OK) {
        !          1219:        if (value.type == TYPE_INT) {
        !          1220:            *ptr = value.intValue;
        !          1221:        } else if (value.type == TYPE_DOUBLE) {
        !          1222:            *ptr = value.doubleValue;
        !          1223:        } else {
        !          1224:            interp->result = "expression didn't have numeric value";
        !          1225:            result = TCL_ERROR;
        !          1226:        }
        !          1227:     }
        !          1228:     if (value.pv.buffer != value.staticSpace) {
        !          1229:        ckfree(value.pv.buffer);
        !          1230:     }
        !          1231:     return result;
        !          1232: }
        !          1233: 
        !          1234: int
        !          1235: Tcl_ExprDouble(interp, string, ptr)
        !          1236:     Tcl_Interp *interp;                        /* Context in which to evaluate the
        !          1237:                                         * expression. */
        !          1238:     char *string;                      /* Expression to evaluate. */
        !          1239:     double *ptr;                       /* Where to store result. */
        !          1240: {
        !          1241:     Value value;
        !          1242:     int result;
        !          1243: 
        !          1244:     result = ExprTopLevel(interp, string, &value);
        !          1245:     if (result == TCL_OK) {
        !          1246:        if (value.type == TYPE_INT) {
        !          1247:            *ptr = value.intValue;
        !          1248:        } else if (value.type == TYPE_DOUBLE) {
        !          1249:            *ptr = value.doubleValue;
        !          1250:        } else {
        !          1251:            interp->result = "expression didn't have numeric value";
        !          1252:            result = TCL_ERROR;
        !          1253:        }
        !          1254:     }
        !          1255:     if (value.pv.buffer != value.staticSpace) {
        !          1256:        ckfree(value.pv.buffer);
        !          1257:     }
        !          1258:     return result;
        !          1259: }
        !          1260: 
        !          1261: int
        !          1262: Tcl_ExprBoolean(interp, string, ptr)
        !          1263:     Tcl_Interp *interp;                        /* Context in which to evaluate the
        !          1264:                                         * expression. */
        !          1265:     char *string;                      /* Expression to evaluate. */
        !          1266:     int *ptr;                          /* Where to store 0/1 result. */
        !          1267: {
        !          1268:     Value value;
        !          1269:     int result;
        !          1270: 
        !          1271:     result = ExprTopLevel(interp, string, &value);
        !          1272:     if (result == TCL_OK) {
        !          1273:        if (value.type == TYPE_INT) {
        !          1274:            *ptr = value.intValue != 0;
        !          1275:        } else if (value.type == TYPE_DOUBLE) {
        !          1276:            *ptr = value.doubleValue != 0.0;
        !          1277:        } else {
        !          1278:            interp->result = "expression didn't have numeric value";
        !          1279:            result = TCL_ERROR;
        !          1280:        }
        !          1281:     }
        !          1282:     if (value.pv.buffer != value.staticSpace) {
        !          1283:        ckfree(value.pv.buffer);
        !          1284:     }
        !          1285:     return result;
        !          1286: }
        !          1287: 
        !          1288: /*
        !          1289:  *--------------------------------------------------------------
        !          1290:  *
        !          1291:  * Tcl_ExprString --
        !          1292:  *
        !          1293:  *     Evaluate an expression and return its value in string form.
        !          1294:  *
        !          1295:  * Results:
        !          1296:  *     A standard Tcl result.  If the result is TCL_OK, then the
        !          1297:  *     interpreter's result is set to the string value of the
        !          1298:  *     expression.  If the result is TCL_OK, then interp->result
        !          1299:  *     contains an error message.
        !          1300:  *
        !          1301:  * Side effects:
        !          1302:  *     None.
        !          1303:  *
        !          1304:  *--------------------------------------------------------------
        !          1305:  */
        !          1306: 
        !          1307: int
        !          1308: Tcl_ExprString(interp, string)
        !          1309:     Tcl_Interp *interp;                        /* Context in which to evaluate the
        !          1310:                                         * expression. */
        !          1311:     char *string;                      /* Expression to evaluate. */
        !          1312: {
        !          1313:     Value value;
        !          1314:     int result;
        !          1315: 
        !          1316:     result = ExprTopLevel(interp, string, &value);
        !          1317:     if (result == TCL_OK) {
        !          1318:        if (value.type == TYPE_INT) {
        !          1319:            sprintf(interp->result, "%ld", value.intValue);
        !          1320:        } else if (value.type == TYPE_DOUBLE) {
        !          1321:            sprintf(interp->result, "%g", value.doubleValue);
        !          1322:        } else {
        !          1323:            if (value.pv.buffer != value.staticSpace) {
        !          1324:                interp->result = value.pv.buffer;
        !          1325:                interp->freeProc = (Tcl_FreeProc *) free;
        !          1326:                value.pv.buffer = value.staticSpace;
        !          1327:            } else {
        !          1328:                Tcl_SetResult(interp, value.pv.buffer, TCL_VOLATILE);
        !          1329:            }
        !          1330:        }
        !          1331:     }
        !          1332:     if (value.pv.buffer != value.staticSpace) {
        !          1333:        ckfree(value.pv.buffer);
        !          1334:     }
        !          1335:     return result;
        !          1336: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.