]> cvs.zerfleddert.de Git - micropolis/blame - src/tcl/tclexpr.c
fix for main window not appearing on all window managers
[micropolis] / src / tcl / tclexpr.c
CommitLineData
6a5fa4e0
MG
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
21static 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
35int 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
48typedef 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
73typedef 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
133int 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
153char *operatorStrings[] = {
154 "VALUE", "(", ")", "END", "UNKNOWN", "5", "6", "7",
155 "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=",
156 ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", ":",
157 "-", "!", "~"
158};
159
160/*
161 * Declarations for local procedures to this file:
162 */
163
164static int ExprGetValue _ANSI_ARGS_((Tcl_Interp *interp,
165 ExprInfo *infoPtr, int prec, Value *valuePtr));
166static int ExprLex _ANSI_ARGS_((Tcl_Interp *interp,
167 ExprInfo *infoPtr, Value *valuePtr));
168static void ExprMakeString _ANSI_ARGS_((Value *valuePtr));
169static int ExprParseString _ANSI_ARGS_((Tcl_Interp *interp,
170 char *string, Value *valuePtr));
171static int ExprTopLevel _ANSI_ARGS_((Tcl_Interp *interp,
172 char *string, Value *valuePtr));
173\f
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
196static int
197ExprParseString(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\f
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
287static int
288ExprLex(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\f
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
563static int
564ExprGetValue(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\f
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
1114static void
1115ExprMakeString(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\f
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
1155static int
1156ExprTopLevel(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\f
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
1207int
1208Tcl_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
1234int
1235Tcl_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
1261int
1262Tcl_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\f
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
1307int
1308Tcl_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}
Impressum, Datenschutz