home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume25 / tcl / part26 < prev    next >
Encoding:
Text File  |  1991-11-15  |  36.7 KB  |  1,388 lines

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