Annotation of micropolis/src/tcl/tclexpr.c, revision 1.1.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.