wasCSharpSQLite – Blame information for rev

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * Expression.java
3 *
4 * Copyright (c) 1997 Cornell University.
5 * Copyright (c) 1997 Sun Microsystems, Inc.
6 *
7 * See the file "license.terms" for information on usage and
8 * redistribution of this file, and for a DISCLAIMER OF ALL
9 * WARRANTIES.
10 *
11 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
12 *
13 * RCS @(#) $Id: Expression.java,v 1.10 2003/02/04 00:35:41 mdejong Exp $
14 *
15 */
16 using System;
17 using System.Collections;
18  
19 namespace tcl.lang
20 {
21  
22 /// <summary> This class handles Tcl expressions.</summary>
23 class Expression
24 {
25  
26 // The token types are defined below. In addition, there is a
27 // table associating a precedence with each operator. The order
28 // of types is important. Consult the code before changing it.
29  
30 internal const int VALUE = 0;
31 internal const int OPEN_PAREN = 1;
32 internal const int CLOSE_PAREN = 2;
33 internal const int COMMA = 3;
34 internal const int END = 4;
35 internal const int UNKNOWN = 5;
36  
37 // Binary operators:
38  
39 internal const int MULT = 8;
40 internal const int DIVIDE = 9;
41 internal const int MOD = 10;
42 internal const int PLUS = 11;
43 internal const int MINUS = 12;
44 internal const int LEFT_SHIFT = 13;
45 internal const int RIGHT_SHIFT = 14;
46 internal const int LESS = 15;
47 internal const int GREATER = 16;
48 internal const int LEQ = 17;
49 internal const int GEQ = 18;
50 internal const int EQUAL = 19;
51 internal const int NEQ = 20;
52 internal const int BIT_AND = 21;
53 internal const int BIT_XOR = 22;
54 internal const int BIT_OR = 23;
55 internal const int AND = 24;
56 internal const int OR = 25;
57 internal const int QUESTY = 26;
58 internal const int COLON = 27;
59  
60 // Unary operators:
61  
62 internal const int UNARY_MINUS = 28;
63 internal const int UNARY_PLUS = 29;
64 internal const int NOT = 30;
65 internal const int BIT_NOT = 31;
66 internal const int EQ = 32;
67 internal const int NE = 33;
68  
69 // Precedence table. The values for non-operator token types are ignored.
70  
71 internal static int[] precTable = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 11, 11, 10, 10, 9, 9, 9, 9, 8, 8, 7, 6, 5, 4, 3, 2, 1, 13, 13, 13, 13 };
72  
73 // Mapping from operator numbers to strings; used for error messages.
74  
75 internal static string[] operatorStrings = new string[] { "VALUE", "(", ")", ",", "END", "UNKNOWN", "6", "7", "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=", ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", ":", "-", "+", "!", "~", "eq", "ne" };
76  
77 internal Hashtable mathFuncTable;
78  
79 /// <summary> The entire expression, as originally passed to eval et al.</summary>
80 private string m_expr;
81  
82 /// <summary> Length of the expression.</summary>
83 private int m_len;
84  
85 /// <summary> Type of the last token to be parsed from the expression.
86 /// Corresponds to the characters just before expr.
87 /// </summary>
88 internal int m_token;
89  
90 /// <summary> Position to the next character to be scanned from the expression
91 /// string.
92 /// </summary>
93 private int m_ind;
94  
95 /// <summary> Evaluate a Tcl expression.
96 ///
97 /// </summary>
98 /// <param name="interp">the context in which to evaluate the expression.
99 /// </param>
100 /// <param name="string">expression to evaluate.
101 /// </param>
102 /// <returns> the value of the expression.
103 /// </returns>
104 /// <exception cref=""> TclException for malformed expressions.
105 /// </exception>
106  
107 internal TclObject eval( Interp interp, string inString )
108 {
109 ExprValue value = ExprTopLevel( interp, inString );
110 switch ( value.type )
111 {
112  
113 case ExprValue.INT:
114 return TclInteger.newInstance( (int)value.intValue );
115  
116 case ExprValue.DOUBLE:
117 return TclDouble.newInstance( value.doubleValue );
118  
119 case ExprValue.STRING:
120 return TclString.newInstance( value.stringValue );
121  
122 default:
123 throw new TclRuntimeError( "internal error: expression, unknown" );
124  
125 }
126 }
127  
128 /// <summary> Evaluate an Tcl expression.</summary>
129 /// <param name="interp">the context in which to evaluate the expression.
130 /// </param>
131 /// <param name="string">expression to evaluate.
132 /// </param>
133 /// <exception cref=""> TclException for malformed expressions.
134 /// </exception>
135 /// <returns> the value of the expression in boolean.
136 /// </returns>
137 internal bool evalBoolean( Interp interp, string inString )
138 {
139 ExprValue value = ExprTopLevel( interp, inString );
140 switch ( value.type )
141 {
142  
143 case ExprValue.INT:
144 return ( value.intValue != 0 );
145  
146 case ExprValue.DOUBLE:
147 return ( value.doubleValue != 0.0 );
148  
149 case ExprValue.STRING:
150 return Util.getBoolean( interp, value.stringValue );
151  
152 default:
153 throw new TclRuntimeError( "internal error: expression, unknown" );
154  
155 }
156 }
157  
158 /// <summary> Constructor.</summary>
159 internal Expression()
160 {
161 mathFuncTable = new Hashtable();
162  
163 // rand -- needs testing
164 // srand -- needs testing
165 // hypot -- needs testing
166 // fmod -- needs testing
167 // try [expr fmod(4.67, 2.2)]
168 // the answer should be .27, but I got .2699999999999996
169  
170 SupportClass.PutElement( mathFuncTable, "atan2", new Atan2Function() );
171 SupportClass.PutElement( mathFuncTable, "pow", new PowFunction() );
172 SupportClass.PutElement( mathFuncTable, "acos", new AcosFunction() );
173 SupportClass.PutElement( mathFuncTable, "asin", new AsinFunction() );
174 SupportClass.PutElement( mathFuncTable, "atan", new AtanFunction() );
175 SupportClass.PutElement( mathFuncTable, "ceil", new CeilFunction() );
176 SupportClass.PutElement( mathFuncTable, "cos", new CosFunction() );
177 SupportClass.PutElement( mathFuncTable, "cosh", new CoshFunction() );
178 SupportClass.PutElement( mathFuncTable, "exp", new ExpFunction() );
179 SupportClass.PutElement( mathFuncTable, "floor", new FloorFunction() );
180 SupportClass.PutElement( mathFuncTable, "fmod", new FmodFunction() );
181 SupportClass.PutElement( mathFuncTable, "hypot", new HypotFunction() );
182 SupportClass.PutElement( mathFuncTable, "log", new LogFunction() );
183 SupportClass.PutElement( mathFuncTable, "log10", new Log10Function() );
184 SupportClass.PutElement( mathFuncTable, "rand", new RandFunction() );
185 SupportClass.PutElement( mathFuncTable, "sin", new SinFunction() );
186 SupportClass.PutElement( mathFuncTable, "sinh", new SinhFunction() );
187 SupportClass.PutElement( mathFuncTable, "sqrt", new SqrtFunction() );
188 SupportClass.PutElement( mathFuncTable, "srand", new SrandFunction() );
189 SupportClass.PutElement( mathFuncTable, "tan", new TanFunction() );
190 SupportClass.PutElement( mathFuncTable, "tanh", new TanhFunction() );
191  
192 SupportClass.PutElement( mathFuncTable, "abs", new AbsFunction() );
193 SupportClass.PutElement( mathFuncTable, "double", new DoubleFunction() );
194 SupportClass.PutElement( mathFuncTable, "int", new IntFunction() );
195 SupportClass.PutElement( mathFuncTable, "round", new RoundFunction() );
196 SupportClass.PutElement( mathFuncTable, "wide", new WideFunction() );
197  
198 m_expr = null;
199 m_ind = 0;
200 m_len = 0;
201 m_token = UNKNOWN;
202 }
203  
204 /// <summary> Provides top-level functionality shared by procedures like ExprInt,
205 /// ExprDouble, etc.
206 /// </summary>
207 /// <param name="interp">the context in which to evaluate the expression.
208 /// </param>
209 /// <param name="string">the expression.
210 /// </param>
211 /// <exception cref=""> TclException for malformed expressions.
212 /// </exception>
213 /// <returns> the value of the expression.
214 /// </returns>
215 private ExprValue ExprTopLevel( Interp interp, string inString )
216 {
217  
218 // Saved the state variables so that recursive calls to expr
219 // can work:
220 // expr {[expr 1+2] + 3}
221  
222 string m_expr_saved = m_expr;
223 int m_len_saved = m_len;
224 int m_token_saved = m_token;
225 int m_ind_saved = m_ind;
226  
227 try
228 {
229 m_expr = inString;
230 m_ind = 0;
231 m_len = inString.Length;
232 m_token = UNKNOWN;
233  
234 ExprValue val = ExprGetValue( interp, -1 );
235 if ( m_token != END )
236 {
237 SyntaxError( interp );
238 }
239 return val;
240 }
241 finally
242 {
243 m_expr = m_expr_saved;
244 m_len = m_len_saved;
245 m_token = m_token_saved;
246 m_ind = m_ind_saved;
247 }
248 }
249  
250 internal static void IllegalType( Interp interp, int badType, int Operator )
251 {
252 throw new TclException( interp, "can't use " + ( ( badType == ExprValue.DOUBLE ) ? "floating-point value" : "non-numeric string" ) + " as operand of \"" + operatorStrings[Operator] + "\"" );
253 }
254  
255 internal void SyntaxError( Interp interp )
256 {
257 throw new TclException( interp, "syntax error in expression \"" + m_expr + "\"" );
258 }
259  
260 internal static void DivideByZero( Interp interp )
261 {
262 interp.setErrorCode( TclString.newInstance( "ARITH DIVZERO {divide by zero}" ) );
263 throw new TclException( interp, "divide by zero" );
264 }
265  
266 internal static void IntegerTooLarge( Interp interp )
267 {
268 interp.setErrorCode( TclString.newInstance( "ARITH IOVERFLOW {integer value too large to represent}" ) );
269 throw new TclException( interp, "integer value too large to represent" );
270 }
271  
272 internal static void WideTooLarge( Interp interp )
273 {
274 interp.setErrorCode( TclString.newInstance( "ARITH IOVERFLOW {wide value too large to represent}" ) );
275 throw new TclException( interp, "wide value too large to represent" );
276 }
277  
278 internal static void DoubleTooLarge( Interp interp )
279 {
280 interp.setErrorCode( TclString.newInstance( "ARITH OVERFLOW {floating-point value too large to represent}" ) );
281 throw new TclException( interp, "floating-point value too large to represent" );
282 }
283  
284 internal static void DoubleTooSmall( Interp interp )
285 {
286 interp.setErrorCode( TclString.newInstance( "ARITH UNDERFLOW {floating-point value too small to represent}" ) );
287 throw new TclException( interp, "floating-point value too small to represent" );
288 }
289  
290 internal static void DomainError( Interp interp )
291 {
292 interp.setErrorCode( TclString.newInstance( "ARITH DOMAIN {domain error: argument not in valid range}" ) );
293 throw new TclException( interp, "domain error: argument not in valid range" );
294 }
295  
296 /// <summary> Given a string (such as one coming from command or variable
297 /// substitution), make a Value based on the string. The value
298 /// be a floating-point or integer, if possible, or else it
299 /// just be a copy of the string.
300 ///
301 /// </summary>
302 /// <param name="interp">the context in which to evaluate the expression.
303 /// </param>
304 /// <param name="s">the string to parse.
305 /// </param>
306 /// <exception cref=""> TclException for malformed expressions.
307 /// </exception>
308 /// <returns> the value of the expression.
309 /// </returns>
310  
311 private ExprValue ExprParseString( Interp interp, string s )
312 {
313  
314 int len = s.Length;
315  
316 /*
317 System.out.println("now to ExprParseString ->" + s +
318 "<- of length " + len);*/
319  
320 // Take shortcut when string is of length 0, as there is
321 // only a string rep for an empty string (no int or double rep)
322 // this will happend a lot so this shortcut will speed things up!
323  
324 if ( len == 0 )
325 {
326 return new ExprValue( s );
327 }
328  
329 // The strings "0" and "1" are going to occure a lot
330 // it might be wise to include shortcuts for these cases
331  
332  
333 int i;
334 if ( looksLikeInt( s, len, 0 ) )
335 {
336 //System.out.println("string looks like an int");
337  
338 // Note: use strtoul instead of strtol for integer conversions
339 // to allow full-size unsigned numbers, but don't depend on
340 // strtoul to handle sign characters; it won't in some
341 // implementations.
342  
343 for ( i = 0; System.Char.IsWhiteSpace( s[i] ); i++ )
344 {
345 // Empty loop body.
346 }
347  
348 StrtoulResult res;
349 if ( s[i] == '-' )
350 {
351 i++;
352 res = Util.strtoul( s, i, 0 );
353 res.value = -res.value;
354 }
355 else if ( s[i] == '+' )
356 {
357 i++;
358 res = Util.strtoul( s, i, 0 );
359 }
360 else
361 {
362 res = Util.strtoul( s, i, 0 );
363 }
364  
365 if ( res.errno == 0 )
366 {
367 // We treat this string as a number if all the charcters
368 // following the parsed number are a whitespace char
369 // E.g.: " 1", "1", "1 ", and " 1 " are all good numbers
370  
371 bool trailing_blanks = true;
372  
373 for ( i = res.index; i < len; i++ )
374 {
375 if ( !System.Char.IsWhiteSpace( s[i] ) )
376 {
377 trailing_blanks = false;
378 }
379 }
380  
381 if ( trailing_blanks )
382 {
383 //System.out.println("string is an Integer of value " + res.value);
384 m_token = VALUE;
385 return new ExprValue( res.value );
386 }
387 }
388 else if ( res.errno == TCL.INTEGER_RANGE )
389 {
390 IntegerTooLarge( interp );
391 }
392  
393  
394 /*
395 if (res.index == len) {
396 // We treat this string as a number only if the number
397 // ends at the end of the string. E.g.: " 1", "1" are
398 // good numbers but "1 " is not.
399  
400 if (res.errno == TCL.INTEGER_RANGE) {
401 IntegerTooLarge(interp);
402 } else {
403 m_token = VALUE;
404 return new ExprValue(res.value);
405 }
406 }*/
407 }
408 else
409 {
410 //System.out.println("string does not look like an int, checking for Double");
411  
412 StrtodResult res = Util.strtod( s, 0 );
413  
414 if ( res.errno == 0 )
415 {
416 // Trailing whitespaces are treated just like the Integer case
417  
418 bool trailing_blanks = true;
419  
420 for ( i = res.index; i < len; i++ )
421 {
422 if ( !System.Char.IsWhiteSpace( s[i] ) )
423 {
424 trailing_blanks = false;
425 }
426 }
427  
428 if ( trailing_blanks )
429 {
430 //System.out.println("string is a Double of value " + res.value);
431 m_token = VALUE;
432 return new ExprValue( res.value );
433 }
434 }
435 else if ( res.errno == TCL.DOUBLE_RANGE )
436 {
437 if ( res.value != 0 )
438 {
439 DoubleTooLarge( interp );
440 }
441 else
442 {
443 DoubleTooSmall( interp );
444 }
445 }
446 // if res.errno is any other value (like TCL.INVALID_DOUBLE)
447 // just fall through and use the string rep
448  
449  
450 /*
451 if (res.index == len) {
452  
453 if (res.errno == 0) {
454 //System.out.println("string is a Double of value " + res.value);
455 m_token = VALUE;
456 return new ExprValue(res.value);
457 } else if (res.errno == TCL.DOUBLE_RANGE) {
458 DoubleTooLarge(interp);
459 }
460 }*/
461 }
462  
463 //System.out.println("string is not a valid number, returning as string");
464  
465 // Not a valid number. Save a string value (but don't do anything
466 // if it's already the value).
467  
468 return new ExprValue( s );
469 }
470  
471 /// <summary> Parse a "value" from the remainder of the expression.
472 ///
473 /// </summary>
474 /// <param name="interp">the context in which to evaluate the expression.
475 /// </param>
476 /// <param name="prec">treat any un-parenthesized operator with precedence
477 /// <= this as the end of the expression.
478 /// </param>
479 /// <exception cref=""> TclException for malformed expressions.
480 /// </exception>
481 /// <returns> the value of the expression.
482 /// </returns>
483 private ExprValue ExprGetValue( Interp interp, int prec )
484 {
485 int Operator;
486 bool gotOp = false; // True means already lexed the
487 // operator (while picking up value
488 // for unary operator). Don't lex
489 // again.
490 ExprValue value, value2;
491  
492 // There are two phases to this procedure. First, pick off an
493 // initial value. Then, parse (binary operator, value) pairs
494 // until done.
495  
496 value = ExprLex( interp );
497  
498 if ( m_token == OPEN_PAREN )
499 {
500  
501 // Parenthesized sub-expression.
502  
503 value = ExprGetValue( interp, -1 );
504 if ( m_token != CLOSE_PAREN )
505 {
506 SyntaxError( interp );
507 }
508 }
509 else
510 {
511 if ( m_token == MINUS )
512 {
513 m_token = UNARY_MINUS;
514 }
515 if ( m_token == PLUS )
516 {
517 m_token = UNARY_PLUS;
518 }
519 if ( m_token >= UNARY_MINUS )
520 {
521  
522 // Process unary operators.
523  
524 Operator = m_token;
525 value = ExprGetValue( interp, precTable[m_token] );
526  
527 if ( interp.noEval == 0 )
528 {
529 switch ( Operator )
530 {
531  
532 case UNARY_MINUS:
533 if ( value.type == ExprValue.INT )
534 {
535 value.intValue = -value.intValue;
536 }
537 else if ( value.type == ExprValue.DOUBLE )
538 {
539 value.doubleValue = -value.doubleValue;
540 }
541 else
542 {
543 IllegalType( interp, value.type, Operator );
544 }
545 break;
546  
547 case UNARY_PLUS:
548 if ( ( value.type != ExprValue.INT ) && ( value.type != ExprValue.DOUBLE ) )
549 {
550 IllegalType( interp, value.type, Operator );
551 }
552 break;
553  
554 case NOT:
555 if ( value.type == ExprValue.INT )
556 {
557 if ( value.intValue != 0 )
558 {
559 value.intValue = 0;
560 }
561 else
562 {
563 value.intValue = 1;
564 }
565 }
566 else if ( value.type == ExprValue.DOUBLE )
567 {
568 if ( value.doubleValue == 0.0 )
569 {
570 value.intValue = 1;
571 }
572 else
573 {
574 value.intValue = 0;
575 }
576 value.type = ExprValue.INT;
577 }
578 else
579 {
580 IllegalType( interp, value.type, Operator );
581 }
582 break;
583  
584 case BIT_NOT:
585 if ( value.type == ExprValue.INT )
586 {
587 value.intValue = ~value.intValue;
588 }
589 else
590 {
591 IllegalType( interp, value.type, Operator );
592 }
593 break;
594 }
595 }
596 gotOp = true;
597 }
598 else if ( m_token == CLOSE_PAREN )
599 {
600 // Caller needs to deal with close paren token.
601 return null;
602 }
603 else if ( m_token != VALUE )
604 {
605 SyntaxError( interp );
606 }
607 }
608 if ( value == null )
609 {
610 SyntaxError( interp );
611 }
612  
613 // Got the first operand. Now fetch (operator, operand) pairs.
614  
615 if ( !gotOp )
616 {
617 value2 = ExprLex( interp );
618 }
619  
620 while ( true )
621 {
622 Operator = m_token;
623 if ( ( Operator < MULT ) || ( Operator >= UNARY_MINUS ) )
624 {
625 if ( ( Operator == END ) || ( Operator == CLOSE_PAREN ) || ( Operator == COMMA ) )
626 {
627 return value; // Goto Done
628 }
629 else
630 {
631 SyntaxError( interp );
632 }
633 }
634 if ( precTable[Operator] <= prec )
635 {
636 return value; // (goto done)
637 }
638  
639 // If we're doing an AND or OR and the first operand already
640 // determines the result, don't execute anything in the
641 // second operand: just parse. Same style for ?: pairs.
642  
643 if ( ( Operator == AND ) || ( Operator == OR ) || ( Operator == QUESTY ) )
644 {
645  
646 if ( value.type == ExprValue.DOUBLE )
647 {
648 value.intValue = ( value.doubleValue != 0 ) ? 1 : 0;
649 value.type = ExprValue.INT;
650 }
651 else if ( value.type == ExprValue.STRING )
652 {
653 try
654 {
655 bool b = Util.getBoolean( null, value.stringValue );
656 value = new ExprValue( b ? 1 : 0 );
657 }
658 catch ( TclException e )
659 {
660 if ( interp.noEval == 0 )
661 {
662 IllegalType( interp, ExprValue.STRING, Operator );
663 }
664  
665 // Must set value.intValue to avoid referencing
666 // uninitialized memory in the "if" below; the actual
667 // value doesn't matter, since it will be ignored.
668  
669 value.intValue = 0;
670 }
671 }
672 if ( ( ( Operator == AND ) && ( value.intValue == 0 ) ) || ( ( Operator == OR ) && ( value.intValue != 0 ) ) )
673 {
674 interp.noEval++;
675 try
676 {
677 value2 = ExprGetValue( interp, precTable[Operator] );
678 }
679 finally
680 {
681 interp.noEval--;
682 }
683 if ( Operator == OR )
684 {
685 value.intValue = 1;
686 }
687 continue;
688 }
689 else if ( Operator == QUESTY )
690 {
691 // Special note: ?: operators must associate right to
692 // left. To make this happen, use a precedence one lower
693 // than QUESTY when calling ExprGetValue recursively.
694  
695 if ( value.intValue != 0 )
696 {
697 value = ExprGetValue( interp, precTable[QUESTY] - 1 );
698 if ( m_token != COLON )
699 {
700 SyntaxError( interp );
701 }
702  
703 interp.noEval++;
704 try
705 {
706 value2 = ExprGetValue( interp, precTable[QUESTY] - 1 );
707 }
708 finally
709 {
710 interp.noEval--;
711 }
712 }
713 else
714 {
715 interp.noEval++;
716 try
717 {
718 value2 = ExprGetValue( interp, precTable[QUESTY] - 1 );
719 }
720 finally
721 {
722 interp.noEval--;
723 }
724 if ( m_token != COLON )
725 {
726 SyntaxError( interp );
727 }
728 value = ExprGetValue( interp, precTable[QUESTY] - 1 );
729 }
730 continue;
731 }
732 else
733 {
734 value2 = ExprGetValue( interp, precTable[Operator] );
735 }
736 }
737 else
738 {
739 value2 = ExprGetValue( interp, precTable[Operator] );
740 }
741  
742  
743 if ( ( m_token < MULT ) && ( m_token != VALUE ) && ( m_token != END ) && ( m_token != COMMA ) && ( m_token != CLOSE_PAREN ) )
744 {
745 SyntaxError( interp );
746 }
747  
748 if ( interp.noEval != 0 )
749 {
750 continue;
751 }
752  
753 // At this point we've got two values and an operator. Check
754 // to make sure that the particular data types are appropriate
755 // for the particular operator, and perform type conversion
756 // if necessary.
757  
758 switch ( Operator )
759 {
760  
761  
762 // For the operators below, no strings are allowed and
763 // ints get converted to floats if necessary.
764 case MULT:
765 case DIVIDE:
766 case PLUS:
767 case MINUS:
768 if ( ( value.type == ExprValue.STRING ) || ( value2.type == ExprValue.STRING ) )
769 {
770 IllegalType( interp, ExprValue.STRING, Operator );
771 }
772 if ( value.type == ExprValue.DOUBLE )
773 {
774 if ( value2.type == ExprValue.INT )
775 {
776 value2.doubleValue = value2.intValue;
777 value2.type = ExprValue.DOUBLE;
778 }
779 }
780 else if ( value2.type == ExprValue.DOUBLE )
781 {
782 if ( value.type == ExprValue.INT )
783 {
784 value.doubleValue = value.intValue;
785 value.type = ExprValue.DOUBLE;
786 }
787 }
788 break;
789  
790 // For the operators below, only integers are allowed.
791  
792  
793 case MOD:
794 case LEFT_SHIFT:
795 case RIGHT_SHIFT:
796 case BIT_AND:
797 case BIT_XOR:
798 case BIT_OR:
799 if ( value.type != ExprValue.INT )
800 {
801 IllegalType( interp, value.type, Operator );
802 }
803 else if ( value2.type != ExprValue.INT )
804 {
805 IllegalType( interp, value2.type, Operator );
806 }
807 break;
808  
809 // For the operators below, any type is allowed but the
810 // two operands must have the same type. Convert integers
811 // to floats and either to strings, if necessary.
812  
813  
814 case LESS:
815 case GREATER:
816 case LEQ:
817 case GEQ:
818 case EQUAL:
819 case EQ:
820 case NEQ:
821 case NE:
822 if ( value.type == ExprValue.STRING )
823 {
824 if ( value2.type != ExprValue.STRING )
825 {
826 ExprMakeString( interp, value2 );
827 }
828 }
829 else if ( value2.type == ExprValue.STRING )
830 {
831 if ( value.type != ExprValue.STRING )
832 {
833 ExprMakeString( interp, value );
834 }
835 }
836 else if ( value.type == ExprValue.DOUBLE )
837 {
838 if ( value2.type == ExprValue.INT )
839 {
840 value2.doubleValue = value2.intValue;
841 value2.type = ExprValue.DOUBLE;
842 }
843 }
844 else if ( value2.type == ExprValue.DOUBLE )
845 {
846 if ( value.type == ExprValue.INT )
847 {
848 value.doubleValue = value.intValue;
849 value.type = ExprValue.DOUBLE;
850 }
851 }
852 break;
853  
854 // For the operators below, no strings are allowed, but
855 // no int->double conversions are performed.
856  
857  
858 case AND:
859 case OR:
860 if ( value.type == ExprValue.STRING )
861 {
862 IllegalType( interp, value.type, Operator );
863 }
864 if ( value2.type == ExprValue.STRING )
865 {
866 try
867 {
868 bool b = Util.getBoolean( null, value2.stringValue );
869 value2 = new ExprValue( b ? 1 : 0 );
870 }
871 catch ( TclException e )
872 {
873 IllegalType( interp, value2.type, Operator );
874 }
875 }
876 break;
877  
878 // For the operators below, type and conversions are
879 // irrelevant: they're handled elsewhere.
880  
881  
882 case QUESTY:
883 case COLON:
884 break;
885  
886 // Any other operator is an error.
887  
888  
889 default:
890 throw new TclException( interp, "unknown operator in expression" );
891  
892 }
893  
894 // Carry out the function of the specified operator.
895  
896 switch ( Operator )
897 {
898  
899 case MULT:
900 if ( value.type == ExprValue.INT )
901 {
902 value.intValue = value.intValue * value2.intValue;
903 }
904 else
905 {
906 value.doubleValue *= value2.doubleValue;
907 }
908 break;
909  
910 case DIVIDE:
911 case MOD:
912 if ( value.type == ExprValue.INT )
913 {
914 long divisor, quot, rem;
915 bool negative;
916  
917 if ( value2.intValue == 0 )
918 {
919 DivideByZero( interp );
920 }
921  
922 // The code below is tricky because C doesn't guarantee
923 // much about the properties of the quotient or
924 // remainder, but Tcl does: the remainder always has
925 // the same sign as the divisor and a smaller absolute
926 // value.
927  
928 divisor = value2.intValue;
929 negative = false;
930 if ( divisor < 0 )
931 {
932 divisor = -divisor;
933 value.intValue = -value.intValue;
934 negative = true;
935 }
936 quot = value.intValue / divisor;
937 rem = value.intValue % divisor;
938 if ( rem < 0 )
939 {
940 rem += divisor;
941 quot -= 1;
942 }
943 if ( negative )
944 {
945 rem = -rem;
946 }
947 value.intValue = ( Operator == DIVIDE ) ? quot : rem;
948 }
949 else
950 {
951 if ( value2.doubleValue == 0.0 )
952 {
953 DivideByZero( interp );
954 }
955 value.doubleValue /= value2.doubleValue;
956 }
957 break;
958  
959 case PLUS:
960 if ( value.type == ExprValue.INT )
961 {
962 value.intValue = value.intValue + value2.intValue;
963 }
964 else
965 {
966 value.doubleValue += value2.doubleValue;
967 }
968 break;
969  
970 case MINUS:
971 if ( value.type == ExprValue.INT )
972 {
973 value.intValue = value.intValue - value2.intValue;
974 }
975 else
976 {
977 value.doubleValue -= value2.doubleValue;
978 }
979 break;
980  
981 case LEFT_SHIFT:
982 value.intValue <<= (int)value2.intValue;
983 break;
984  
985 case RIGHT_SHIFT:
986  
987 if ( value.intValue < 0 )
988 {
989 value.intValue = ~( ( ~value.intValue ) >> (int)value2.intValue );
990 }
991 else
992 {
993 value.intValue >>= (int)value2.intValue;
994 }
995 break;
996  
997 case LESS:
998 if ( value.type == ExprValue.INT )
999 {
1000 value.intValue = ( value.intValue < value2.intValue ) ? 1 : 0;
1001 }
1002 else if ( value.type == ExprValue.DOUBLE )
1003 {
1004 value.intValue = ( value.doubleValue < value2.doubleValue ) ? 1 : 0;
1005 }
1006 else
1007 {
1008 value.intValue = ( value.stringValue.CompareTo( value2.stringValue ) < 0 ) ? 1 : 0;
1009 }
1010 value.type = ExprValue.INT;
1011 break;
1012  
1013 case GREATER:
1014 if ( value.type == ExprValue.INT )
1015 {
1016 value.intValue = ( value.intValue > value2.intValue ) ? 1 : 0;
1017 }
1018 else if ( value.type == ExprValue.DOUBLE )
1019 {
1020 value.intValue = ( value.doubleValue > value2.doubleValue ) ? 1 : 0;
1021 }
1022 else
1023 {
1024 value.intValue = ( value.stringValue.CompareTo( value2.stringValue ) > 0 ) ? 1 : 0;
1025 }
1026 value.type = ExprValue.INT;
1027 break;
1028  
1029 case LEQ:
1030 if ( value.type == ExprValue.INT )
1031 {
1032 value.intValue = ( value.intValue <= value2.intValue ) ? 1 : 0;
1033 }
1034 else if ( value.type == ExprValue.DOUBLE )
1035 {
1036 value.intValue = ( value.doubleValue <= value2.doubleValue ) ? 1 : 0;
1037 }
1038 else
1039 {
1040 value.intValue = ( value.stringValue.CompareTo( value2.stringValue ) <= 0 ) ? 1 : 0;
1041 }
1042 value.type = ExprValue.INT;
1043 break;
1044  
1045 case GEQ:
1046 if ( value.type == ExprValue.INT )
1047 {
1048 value.intValue = ( value.intValue >= value2.intValue ) ? 1 : 0;
1049 }
1050 else if ( value.type == ExprValue.DOUBLE )
1051 {
1052 value.intValue = ( value.doubleValue >= value2.doubleValue ) ? 1 : 0;
1053 }
1054 else
1055 {
1056 value.intValue = ( value.stringValue.CompareTo( value2.stringValue ) >= 0 ) ? 1 : 0;
1057 }
1058 value.type = ExprValue.INT;
1059 break;
1060  
1061 case EQUAL:
1062 case EQ:
1063 if ( value.type == ExprValue.INT )
1064 {
1065 value.intValue = ( value.intValue == value2.intValue ) ? 1 : 0;
1066 }
1067 else if ( value.type == ExprValue.DOUBLE )
1068 {
1069 value.intValue = ( value.doubleValue == value2.doubleValue ) ? 1 : 0;
1070 }
1071 else
1072 {
1073 value.intValue = ( value.stringValue.CompareTo( value2.stringValue ) == 0 ) ? 1 : 0;
1074 }
1075 value.type = ExprValue.INT;
1076 break;
1077  
1078 case NEQ:
1079 case NE:
1080 if ( value.type == ExprValue.INT )
1081 {
1082 value.intValue = ( value.intValue != value2.intValue ) ? 1 : 0;
1083 }
1084 else if ( value.type == ExprValue.DOUBLE )
1085 {
1086 value.intValue = ( value.doubleValue != value2.doubleValue ) ? 1 : 0;
1087 }
1088 else
1089 {
1090 value.intValue = ( value.stringValue.CompareTo( value2.stringValue ) != 0 ) ? 1 : 0;
1091 }
1092 value.type = ExprValue.INT;
1093 break;
1094  
1095 case BIT_AND:
1096 value.intValue &= value2.intValue;
1097 break;
1098  
1099 case BIT_XOR:
1100 value.intValue ^= value2.intValue;
1101 break;
1102  
1103 case BIT_OR:
1104 value.intValue |= value2.intValue;
1105 break;
1106  
1107 // For AND and OR, we know that the first value has already
1108 // been converted to an integer. Thus we need only consider
1109 // the possibility of int vs. double for the second value.
1110  
1111  
1112 case AND:
1113 if ( value2.type == ExprValue.DOUBLE )
1114 {
1115 value2.intValue = ( value2.doubleValue != 0 ) ? 1 : 0;
1116 value2.type = ExprValue.INT;
1117 }
1118 value.intValue = ( ( value.intValue != 0 ) && ( value2.intValue != 0 ) ) ? 1 : 0;
1119 break;
1120  
1121 case OR:
1122 if ( value2.type == ExprValue.DOUBLE )
1123 {
1124 value2.intValue = ( value2.doubleValue != 0 ) ? 1 : 0;
1125 value2.type = ExprValue.INT;
1126 }
1127 value.intValue = ( ( value.intValue != 0 ) || ( value2.intValue != 0 ) ) ? 1 : 0;
1128 break;
1129  
1130  
1131 case COLON:
1132 SyntaxError( interp );
1133 break;
1134 }
1135 }
1136 }
1137  
1138 /// <summary> GetLexeme -> ExprLex
1139 ///
1140 /// Lexical analyzer for expression parser: parses a single value,
1141 /// operator, or other syntactic element from an expression string.
1142 ///
1143 /// Size effects: the "m_token" member variable is set to the value of
1144 /// the current token.
1145 ///
1146 /// </summary>
1147 /// <param name="interp">the context in which to evaluate the expression.
1148 /// </param>
1149 /// <exception cref=""> TclException for malformed expressions.
1150 /// </exception>
1151 /// <returns> the value of the expression.
1152 /// </returns>
1153 private ExprValue ExprLex( Interp interp )
1154 {
1155 char c, c2;
1156  
1157 while ( m_ind < m_len && System.Char.IsWhiteSpace( m_expr[m_ind] ) )
1158 {
1159 m_ind++;
1160 }
1161 if ( m_ind >= m_len )
1162 {
1163 m_token = END;
1164 return null;
1165 }
1166  
1167 // First try to parse the token as an integer or
1168 // floating-point number. Don't want to check for a number if
1169 // the first character is "+" or "-". If we do, we might
1170 // treat a binary operator as unary by
1171 // mistake, which will eventually cause a syntax error.
1172  
1173 c = m_expr[m_ind];
1174 if ( m_ind < m_len - 1 )
1175 {
1176 c2 = m_expr[m_ind + 1];
1177 }
1178 else
1179 {
1180 c2 = '\x0000';
1181 }
1182  
1183 if ( ( c != '+' ) && ( c != '-' ) )
1184 {
1185 bool startsWithDigit = System.Char.IsDigit( c );
1186 if ( startsWithDigit && looksLikeInt( m_expr, m_len, m_ind ) )
1187 {
1188 StrtoulResult res = Util.strtoul( m_expr, m_ind, 0 );
1189  
1190 if ( res.errno == 0 )
1191 {
1192 m_ind = res.index;
1193 m_token = VALUE;
1194 return new ExprValue( res.value );
1195 }
1196 else
1197 {
1198 if ( res.errno == TCL.INTEGER_RANGE )
1199 {
1200 IntegerTooLarge( interp );
1201 }
1202 }
1203 }
1204 else if ( startsWithDigit || ( c == '.' ) || ( c == 'n' ) || ( c == 'N' ) )
1205 {
1206 StrtodResult res = Util.strtod( m_expr, m_ind );
1207 if ( res.errno == 0 )
1208 {
1209 m_ind = res.index;
1210 m_token = VALUE;
1211 return new ExprValue( res.value );
1212 }
1213 else
1214 {
1215 if ( res.errno == TCL.DOUBLE_RANGE )
1216 {
1217 if ( res.value != 0 )
1218 {
1219 DoubleTooLarge( interp );
1220 }
1221 else
1222 {
1223 DoubleTooSmall( interp );
1224 }
1225 }
1226 }
1227 }
1228 }
1229  
1230 ParseResult pres;
1231 ExprValue retval;
1232 m_ind += 1; // ind is advanced to point to the next token
1233  
1234 switch ( c )
1235 {
1236  
1237 case '$':
1238 m_token = VALUE;
1239 pres = ParseAdaptor.parseVar( interp, m_expr, m_ind, m_len );
1240 m_ind = pres.nextIndex;
1241  
1242 if ( interp.noEval != 0 )
1243 {
1244 retval = new ExprValue( 0 );
1245 }
1246 else
1247 {
1248  
1249 retval = ExprParseString( interp, pres.value.ToString() );
1250 }
1251 pres.release();
1252 return retval;
1253  
1254 case '[':
1255 m_token = VALUE;
1256 pres = ParseAdaptor.parseNestedCmd( interp, m_expr, m_ind, m_len );
1257 m_ind = pres.nextIndex;
1258  
1259 if ( interp.noEval != 0 )
1260 {
1261 retval = new ExprValue( 0 );
1262 }
1263 else
1264 {
1265  
1266 retval = ExprParseString( interp, pres.value.ToString() );
1267 }
1268 pres.release();
1269 return retval;
1270  
1271 case '"':
1272 m_token = VALUE;
1273  
1274  
1275 //System.out.println("now to parse from ->" + m_expr + "<- at index "
1276 // + m_ind);
1277  
1278 pres = ParseAdaptor.parseQuotes( interp, m_expr, m_ind, m_len );
1279 m_ind = pres.nextIndex;
1280  
1281 // System.out.println("after parse next index is " + m_ind);
1282  
1283 if ( interp.noEval != 0 )
1284 {
1285 // System.out.println("returning noEval zero value");
1286 retval = new ExprValue( 0 );
1287 }
1288 else
1289 {
1290 // System.out.println("returning value string ->" + pres.value.toString() + "<-" );
1291  
1292 retval = ExprParseString( interp, pres.value.ToString() );
1293 }
1294 pres.release();
1295 return retval;
1296  
1297 case '{':
1298 m_token = VALUE;
1299 pres = ParseAdaptor.parseBraces( interp, m_expr, m_ind, m_len );
1300 m_ind = pres.nextIndex;
1301 if ( interp.noEval != 0 )
1302 {
1303 retval = new ExprValue( 0 );
1304 }
1305 else
1306 {
1307  
1308 retval = ExprParseString( interp, pres.value.ToString() );
1309 }
1310 pres.release();
1311 return retval;
1312  
1313 case '(':
1314 m_token = OPEN_PAREN;
1315 return null;
1316  
1317  
1318 case ')':
1319 m_token = CLOSE_PAREN;
1320 return null;
1321  
1322  
1323 case ',':
1324 m_token = COMMA;
1325 return null;
1326  
1327  
1328 case '*':
1329 m_token = MULT;
1330 return null;
1331  
1332  
1333 case '/':
1334 m_token = DIVIDE;
1335 return null;
1336  
1337  
1338 case '%':
1339 m_token = MOD;
1340 return null;
1341  
1342  
1343 case '+':
1344 m_token = PLUS;
1345 return null;
1346  
1347  
1348 case '-':
1349 m_token = MINUS;
1350 return null;
1351  
1352  
1353 case '?':
1354 m_token = QUESTY;
1355 return null;
1356  
1357  
1358 case ':':
1359 m_token = COLON;
1360 return null;
1361  
1362  
1363 case '<':
1364 switch ( c2 )
1365 {
1366  
1367 case '<':
1368 m_ind += 1;
1369 m_token = LEFT_SHIFT;
1370 break;
1371  
1372 case '=':
1373 m_ind += 1;
1374 m_token = LEQ;
1375 break;
1376  
1377 default:
1378 m_token = LESS;
1379 break;
1380  
1381 }
1382 return null;
1383  
1384  
1385 case '>':
1386 switch ( c2 )
1387 {
1388  
1389 case '>':
1390 m_ind += 1;
1391 m_token = RIGHT_SHIFT;
1392 break;
1393  
1394 case '=':
1395 m_ind += 1;
1396 m_token = GEQ;
1397 break;
1398  
1399 default:
1400 m_token = GREATER;
1401 break;
1402  
1403 }
1404 return null;
1405  
1406  
1407 case '=':
1408 if ( c2 == '=' )
1409 {
1410 m_ind += 1;
1411 m_token = EQUAL;
1412 }
1413 else
1414 {
1415 m_token = UNKNOWN;
1416 }
1417 return null;
1418  
1419  
1420 case 'e':
1421 if ( c2 == 'q' )
1422 {
1423 m_ind += 1;
1424 m_token = EQUAL;
1425 }
1426 else
1427 {
1428 m_token = UNKNOWN;
1429 }
1430 return null;
1431  
1432  
1433 case 'n':
1434 if ( c2 == 'e' )
1435 {
1436 m_ind += 1;
1437 m_token = NEQ;
1438 }
1439 else
1440 {
1441 m_token = UNKNOWN;
1442 }
1443 return null;
1444  
1445  
1446 case '!':
1447 if ( c2 == '=' )
1448 {
1449 m_ind += 1;
1450 m_token = NEQ;
1451 }
1452 else
1453 {
1454 m_token = NOT;
1455 }
1456 return null;
1457  
1458  
1459 case '&':
1460 if ( c2 == '&' )
1461 {
1462 m_ind += 1;
1463 m_token = AND;
1464 }
1465 else
1466 {
1467 m_token = BIT_AND;
1468 }
1469 return null;
1470  
1471  
1472 case '^':
1473 m_token = BIT_XOR;
1474 return null;
1475  
1476  
1477 case '|':
1478 if ( c2 == '|' )
1479 {
1480 m_ind += 1;
1481 m_token = OR;
1482 }
1483 else
1484 {
1485 m_token = BIT_OR;
1486 }
1487 return null;
1488  
1489  
1490 case '~':
1491 m_token = BIT_NOT;
1492 return null;
1493  
1494  
1495 default:
1496 if ( System.Char.IsLetter( c ) )
1497 {
1498 // Oops, re-adjust m_ind so that it points to the beginning
1499 // of the function name.
1500  
1501 m_ind--;
1502 return mathFunction( interp );
1503 }
1504 m_token = UNKNOWN;
1505 return null;
1506  
1507 }
1508 }
1509  
1510 /// <summary> Parses a math function from an expression string, carry out the
1511 /// function, and return the value computed.
1512 ///
1513 /// </summary>
1514 /// <param name="interp">current interpreter.
1515 /// </param>
1516 /// <returns> the value computed by the math function.
1517 /// </returns>
1518 /// <exception cref=""> TclException if any error happens.
1519 /// </exception>
1520 internal ExprValue mathFunction( Interp interp )
1521 {
1522 int startIdx = m_ind;
1523 ExprValue value;
1524 string funcName;
1525 MathFunction mathFunc;
1526 TclObject[] argv = null;
1527 int numArgs;
1528  
1529 // Find the end of the math function's name and lookup the MathFunc
1530 // record for the function. Search until the char at m_ind is not
1531 // alphanumeric or '_'
1532  
1533 for ( ; m_ind < m_len; m_ind++ )
1534 {
1535 if ( !( System.Char.IsLetterOrDigit( m_expr[m_ind] ) || m_expr[m_ind] == '_' ) )
1536 {
1537 break;
1538 }
1539 }
1540  
1541 // Get the funcName BEFORE calling ExprLex, so the funcName
1542 // will not have trailing whitespace.
1543  
1544 funcName = m_expr.Substring( startIdx, ( m_ind ) - ( startIdx ) );
1545  
1546 // Parse errors are thrown BEFORE unknown function names
1547  
1548 ExprLex( interp );
1549 if ( m_token != OPEN_PAREN )
1550 {
1551 SyntaxError( interp );
1552 }
1553  
1554 // Now test for unknown funcName. Doing the above statements
1555 // out of order will cause some tests to fail.
1556  
1557 mathFunc = (MathFunction)mathFuncTable[funcName];
1558 if ( mathFunc == null )
1559 {
1560 throw new TclException( interp, "unknown math function \"" + funcName + "\"" );
1561 }
1562  
1563 // Scan off the arguments for the function, if there are any.
1564  
1565 numArgs = mathFunc.argTypes.Length;
1566  
1567 if ( numArgs == 0 )
1568 {
1569 ExprLex( interp );
1570 if ( m_token != CLOSE_PAREN )
1571 {
1572 SyntaxError( interp );
1573 }
1574 }
1575 else
1576 {
1577 argv = new TclObject[numArgs];
1578  
1579 for ( int i = 0; ; i++ )
1580 {
1581 value = ExprGetValue( interp, -1 );
1582  
1583 // Handle close paren with no value
1584 // % expr {srand()}
1585  
1586 if ( ( value == null ) && ( m_token == CLOSE_PAREN ) )
1587 {
1588 if ( i == numArgs )
1589 break;
1590 else
1591 throw new TclException( interp, "too few arguments for math function" );
1592 }
1593  
1594 if ( value.type == ExprValue.STRING )
1595 {
1596 throw new TclException( interp, "argument to math function didn't have numeric value" );
1597 }
1598  
1599 // Copy the value to the argument record, converting it if
1600 // necessary.
1601  
1602 if ( value.type == ExprValue.INT )
1603 {
1604 if ( mathFunc.argTypes[i] == MathFunction.DOUBLE )
1605 {
1606 argv[i] = TclDouble.newInstance( (int)value.intValue );
1607 }
1608 else
1609 {
1610 argv[i] = TclLong.newInstance( value.intValue );
1611 }
1612 }
1613 else
1614 {
1615 if ( mathFunc.argTypes[i] == MathFunction.INT )
1616 {
1617  
1618 argv[i] = TclInteger.newInstance( (int)value.doubleValue );
1619 }
1620 else
1621 {
1622 argv[i] = TclDouble.newInstance( value.doubleValue );
1623 }
1624 }
1625  
1626 // Check for a comma separator between arguments or a
1627 // close-paren to end the argument list.
1628  
1629 if ( i == ( numArgs - 1 ) )
1630 {
1631 if ( m_token == CLOSE_PAREN )
1632 {
1633 break;
1634 }
1635 if ( m_token == COMMA )
1636 {
1637 throw new TclException( interp, "too many arguments for math function" );
1638 }
1639 else
1640 {
1641 SyntaxError( interp );
1642 }
1643 }
1644 if ( m_token != COMMA )
1645 {
1646 if ( m_token == CLOSE_PAREN )
1647 {
1648 throw new TclException( interp, "too few arguments for math function" );
1649 }
1650 else
1651 {
1652 SyntaxError( interp );
1653 }
1654 }
1655 }
1656 }
1657  
1658 m_token = VALUE;
1659 if ( interp.noEval != 0 )
1660 {
1661 return new ExprValue( 0 );
1662 }
1663 else
1664 {
1665 /*
1666 * Invoke the function and copy its result back into valuePtr.
1667 */
1668 return mathFunc.apply( interp, argv );
1669 }
1670 }
1671  
1672 /// <summary> This procedure decides whether the leading characters of a
1673 /// string look like an integer or something else (such as a
1674 /// floating-point number or string).
1675 /// </summary>
1676 /// <returns> a boolean value indicating if the string looks like an integer.
1677 /// </returns>
1678  
1679 internal static bool looksLikeInt( string s, int len, int i )
1680 {
1681 while ( i < len && System.Char.IsWhiteSpace( s[i] ) )
1682 {
1683 i++;
1684 }
1685 if ( i >= len )
1686 {
1687 return false;
1688 }
1689 char c = s[i];
1690 if ( ( c == '+' ) || ( c == '-' ) )
1691 {
1692 i++;
1693 if ( i >= len )
1694 {
1695 return false;
1696 }
1697 c = s[i];
1698 }
1699 if ( !System.Char.IsDigit( c ) )
1700 {
1701 return false;
1702 }
1703 while ( i < len && System.Char.IsDigit( s[i] ) )
1704 {
1705 //System.out.println("'" + s.charAt(i) + "' is a digit");
1706 i++;
1707 }
1708 if ( i >= len )
1709 {
1710 return true;
1711 }
1712  
1713 //ported from C code
1714 c = s[i];
1715 if ( ( c != '.' ) && ( c != 'e' ) && ( c != 'E' ) )
1716 {
1717 return true;
1718 }
1719  
1720 //original
1721 /*
1722 if (i < len) {
1723 c = s.charAt(i);
1724 if ((c == '.') || (c == 'e') || (c == 'E')) {
1725 return false;
1726 }
1727 }*/
1728  
1729 return false;
1730 }
1731  
1732 /// <summary> Converts a value from int or double representation to a string.</summary>
1733 /// <param name="interp">interpreter to use for precision information.
1734 /// </param>
1735 /// <param name="value">Value to be converted.
1736 /// </param>
1737  
1738 internal static void ExprMakeString( Interp interp, ExprValue value )
1739 {
1740 if ( value.type == ExprValue.INT )
1741 {
1742 value.stringValue = System.Convert.ToString( value.intValue );
1743 }
1744 else if ( value.type == ExprValue.DOUBLE )
1745 {
1746 value.stringValue = value.doubleValue.ToString();
1747 }
1748 value.type = ExprValue.STRING;
1749 }
1750  
1751 internal static void checkIntegerRange( Interp interp, double d )
1752 {
1753 if ( d < 0 )
1754 {
1755  
1756 if ( d < ( (double)TCL.INT_MIN ) )
1757 {
1758 Expression.IntegerTooLarge( interp );
1759 }
1760 }
1761 else
1762 {
1763  
1764 if ( d > ( (double)TCL.INT_MAX ) )
1765 {
1766 Expression.IntegerTooLarge( interp );
1767 }
1768 }
1769 }
1770 internal static void checkWideRange( Interp interp, double d )
1771 {
1772 if ( d < 0 )
1773 {
1774 if ( d < Int64.MinValue )
1775 {
1776 Expression.WideTooLarge( interp );
1777 }
1778 }
1779 else
1780 {
1781 if ( d > Int64.MaxValue )
1782 {
1783 Expression.WideTooLarge( interp );
1784 }
1785 }
1786 }
1787  
1788 internal static void checkDoubleRange( Interp interp, double d )
1789 {
1790 if ( ( d == System.Double.NaN ) || ( d == System.Double.NegativeInfinity ) || ( d == System.Double.PositiveInfinity ) )
1791 {
1792 Expression.DoubleTooLarge( interp );
1793 }
1794 }
1795 }
1796  
1797 abstract class MathFunction
1798 {
1799 internal const int INT = 0;
1800 internal const int DOUBLE = 1;
1801 internal const int EITHER = 2;
1802  
1803 internal int[] argTypes;
1804  
1805 internal abstract ExprValue apply( Interp interp, TclObject[] argv );
1806 }
1807  
1808 abstract class UnaryMathFunction : MathFunction
1809 {
1810 internal UnaryMathFunction()
1811 {
1812 argTypes = new int[1];
1813 argTypes[0] = DOUBLE;
1814 }
1815 }
1816  
1817 abstract class BinaryMathFunction : MathFunction
1818 {
1819 internal BinaryMathFunction()
1820 {
1821 argTypes = new int[2];
1822 argTypes[0] = DOUBLE;
1823 argTypes[1] = DOUBLE;
1824 }
1825 }
1826  
1827  
1828 abstract class NoArgMathFunction : MathFunction
1829 {
1830 internal NoArgMathFunction()
1831 {
1832 argTypes = new int[0];
1833 }
1834 }
1835  
1836  
1837 class Atan2Function : BinaryMathFunction
1838 {
1839 internal override ExprValue apply( Interp interp, TclObject[] argv )
1840 {
1841 return new ExprValue( System.Math.Atan2( TclDouble.get( interp, argv[0] ), TclDouble.get( interp, argv[1] ) ) );
1842 }
1843 }
1844  
1845 class AbsFunction : MathFunction
1846 {
1847 internal AbsFunction()
1848 {
1849 argTypes = new int[1];
1850 argTypes[0] = EITHER;
1851 }
1852  
1853 internal override ExprValue apply( Interp interp, TclObject[] argv )
1854 {
1855 if ( argv[0].InternalRep is TclDouble )
1856 {
1857 double d = TclDouble.get( interp, argv[0] );
1858 if ( d > 0 )
1859 {
1860 return new ExprValue( d );
1861 }
1862 else
1863 {
1864 return new ExprValue( -d );
1865 }
1866 }
1867 else
1868 {
1869 int i = TclInteger.get( interp, argv[0] );
1870 if ( i > 0 )
1871 {
1872 return new ExprValue( i );
1873 }
1874 else
1875 {
1876 return new ExprValue( -i );
1877 }
1878 }
1879 }
1880 }
1881  
1882 class DoubleFunction : MathFunction
1883 {
1884 internal DoubleFunction()
1885 {
1886 argTypes = new int[1];
1887 argTypes[0] = EITHER;
1888 }
1889  
1890 internal override ExprValue apply( Interp interp, TclObject[] argv )
1891 {
1892 return new ExprValue( TclDouble.get( interp, argv[0] ) );
1893 }
1894 }
1895  
1896 class IntFunction : MathFunction
1897 {
1898 internal IntFunction()
1899 {
1900 argTypes = new int[1];
1901 argTypes[0] = EITHER;
1902 }
1903  
1904 internal override ExprValue apply( Interp interp, TclObject[] argv )
1905 {
1906 double d = TclDouble.get( interp, argv[0] );
1907 Expression.checkIntegerRange( interp, d );
1908 return new ExprValue( (int)d );
1909 }
1910 }
1911  
1912 class WideFunction : MathFunction
1913 {
1914 internal WideFunction()
1915 {
1916 argTypes = new int[1];
1917 argTypes[0] = EITHER;
1918 }
1919  
1920 internal override ExprValue apply( Interp interp, TclObject[] argv )
1921 {
1922 double d = TclDouble.get( interp, argv[0] );
1923 Expression.checkWideRange( interp, d );
1924 return new ExprValue( (long)d );
1925 }
1926 }
1927 class RoundFunction :
1928 MathFunction
1929 {
1930 internal RoundFunction()
1931 {
1932 argTypes = new int[1];
1933 argTypes[0] = EITHER;
1934 }
1935  
1936 internal override ExprValue apply( Interp interp, TclObject[] argv )
1937 {
1938 if ( argv[0].InternalRep is TclDouble )
1939 {
1940 double d = TclDouble.get( interp, argv[0] );
1941 if ( d < 0 )
1942 {
1943 Expression.checkIntegerRange( interp, d - 0.5 );
1944  
1945 return new ExprValue( (int)( d - 0.5 ) );
1946 }
1947 else
1948 {
1949 Expression.checkIntegerRange( interp, d + 0.5 );
1950  
1951 return new ExprValue( (int)( d + 0.5 ) );
1952 }
1953 }
1954 else
1955 {
1956 return new ExprValue( TclInteger.get( interp, argv[0] ) );
1957 }
1958 }
1959 }
1960  
1961 class PowFunction : BinaryMathFunction
1962 {
1963 internal override ExprValue apply( Interp interp, TclObject[] argv )
1964 {
1965 double d = System.Math.Pow( TclDouble.get( interp, argv[0] ), TclDouble.get( interp, argv[1] ) );
1966 Expression.checkDoubleRange( interp, d );
1967 return new ExprValue( d );
1968 }
1969 }
1970  
1971 /*
1972 * The following section is generated by this script.
1973 *
1974 set missing {fmod}
1975 set byhand {atan2 pow}
1976  
1977  
1978 foreach func {Acos Asin Atan Ceil Cos Exp Floor Log Sin
1979 Sqrt Tan} {
1980 puts "
1981 class $func\Function extends UnaryMathFunction {
1982 ExprValue apply(Interp interp, TclObject argv\[\])
1983 throws TclException {
1984 return new ExprValue(Math.[string tolower $func](TclDouble.get(interp, argv\[0\])));
1985 }
1986 }
1987 "
1988 }
1989  
1990 */
1991  
1992 class AcosFunction : UnaryMathFunction
1993 {
1994 internal override ExprValue apply( Interp interp, TclObject[] argv )
1995 {
1996 double d = TclDouble.get( interp, argv[0] );
1997 if ( ( d < -1 ) || ( d > 1 ) )
1998 {
1999 Expression.DomainError( interp );
2000 }
2001 return new ExprValue( System.Math.Acos( d ) );
2002 }
2003 }
2004  
2005 class AsinFunction : UnaryMathFunction
2006 {
2007 internal override ExprValue apply( Interp interp, TclObject[] argv )
2008 {
2009 return new ExprValue( System.Math.Asin( TclDouble.get( interp, argv[0] ) ) );
2010 }
2011 }
2012  
2013 class AtanFunction : UnaryMathFunction
2014 {
2015 internal override ExprValue apply( Interp interp, TclObject[] argv )
2016 {
2017 return new ExprValue( System.Math.Atan( TclDouble.get( interp, argv[0] ) ) );
2018 }
2019 }
2020  
2021  
2022 class CeilFunction : UnaryMathFunction
2023 {
2024 internal override ExprValue apply( Interp interp, TclObject[] argv )
2025 {
2026 return new ExprValue( System.Math.Ceiling( TclDouble.get( interp, argv[0] ) ) );
2027 }
2028 }
2029  
2030  
2031 class CosFunction : UnaryMathFunction
2032 {
2033 internal override ExprValue apply( Interp interp, TclObject[] argv )
2034 {
2035 return new ExprValue( System.Math.Cos( TclDouble.get( interp, argv[0] ) ) );
2036 }
2037 }
2038  
2039  
2040 class CoshFunction : UnaryMathFunction
2041 {
2042 internal override ExprValue apply( Interp interp, TclObject[] argv )
2043 {
2044 double x = TclDouble.get( interp, argv[0] );
2045 double d1 = System.Math.Pow( System.Math.E, x );
2046 double d2 = System.Math.Pow( System.Math.E, -x );
2047  
2048 Expression.checkDoubleRange( interp, d1 );
2049 Expression.checkDoubleRange( interp, d2 );
2050 return new ExprValue( ( d1 + d2 ) / 2 );
2051 }
2052 }
2053  
2054 class ExpFunction : UnaryMathFunction
2055 {
2056 internal override ExprValue apply( Interp interp, TclObject[] argv )
2057 {
2058 double d = System.Math.Exp( TclDouble.get( interp, argv[0] ) );
2059 if ( ( d == System.Double.NaN ) || ( d == System.Double.NegativeInfinity ) || ( d == System.Double.PositiveInfinity ) )
2060 {
2061 Expression.DoubleTooLarge( interp );
2062 }
2063 return new ExprValue( d );
2064 }
2065 }
2066  
2067  
2068 class FloorFunction : UnaryMathFunction
2069 {
2070 internal override ExprValue apply( Interp interp, TclObject[] argv )
2071 {
2072 return new ExprValue( System.Math.Floor( TclDouble.get( interp, argv[0] ) ) );
2073 }
2074 }
2075  
2076  
2077 class FmodFunction : BinaryMathFunction
2078 {
2079 internal override ExprValue apply( Interp interp, TclObject[] argv )
2080 {
2081 return new ExprValue( System.Math.IEEERemainder( TclDouble.get( interp, argv[0] ), TclDouble.get( interp, argv[1] ) ) );
2082 }
2083 }
2084  
2085 class HypotFunction : BinaryMathFunction
2086 {
2087 internal override ExprValue apply( Interp interp, TclObject[] argv )
2088 {
2089 double x = TclDouble.get( interp, argv[0] );
2090 double y = TclDouble.get( interp, argv[1] );
2091 return new ExprValue( System.Math.Sqrt( ( ( x * x ) + ( y * y ) ) ) );
2092 }
2093 }
2094  
2095  
2096 class LogFunction : UnaryMathFunction
2097 {
2098 internal override ExprValue apply( Interp interp, TclObject[] argv )
2099 {
2100 return new ExprValue( System.Math.Log( TclDouble.get( interp, argv[0] ) ) );
2101 }
2102 }
2103  
2104  
2105 class Log10Function : UnaryMathFunction
2106 {
2107 private static readonly double log10;
2108 internal override ExprValue apply( Interp interp, TclObject[] argv )
2109 {
2110 return new ExprValue( System.Math.Log( TclDouble.get( interp, argv[0] ) ) / log10 );
2111 }
2112 static Log10Function()
2113 {
2114 log10 = System.Math.Log( 10 );
2115 }
2116 }
2117  
2118  
2119 class SinFunction : UnaryMathFunction
2120 {
2121 internal override ExprValue apply( Interp interp, TclObject[] argv )
2122 {
2123 return new ExprValue( System.Math.Sin( TclDouble.get( interp, argv[0] ) ) );
2124 }
2125 }
2126  
2127  
2128 class SinhFunction : UnaryMathFunction
2129 {
2130 internal override ExprValue apply( Interp interp, TclObject[] argv )
2131 {
2132 double x = TclDouble.get( interp, argv[0] );
2133  
2134 double d1 = System.Math.Pow( System.Math.E, x );
2135 double d2 = System.Math.Pow( System.Math.E, -x );
2136  
2137 Expression.checkDoubleRange( interp, d1 );
2138 Expression.checkDoubleRange( interp, d2 );
2139  
2140 return new ExprValue( ( d1 - d2 ) / 2 );
2141 }
2142 }
2143  
2144  
2145 class SqrtFunction : UnaryMathFunction
2146 {
2147 internal override ExprValue apply( Interp interp, TclObject[] argv )
2148 {
2149 return new ExprValue( System.Math.Sqrt( TclDouble.get( interp, argv[0] ) ) );
2150 }
2151 }
2152  
2153  
2154 class TanFunction : UnaryMathFunction
2155 {
2156 internal override ExprValue apply( Interp interp, TclObject[] argv )
2157 {
2158 return new ExprValue( System.Math.Tan( TclDouble.get( interp, argv[0] ) ) );
2159 }
2160 }
2161  
2162 class TanhFunction : UnaryMathFunction
2163 {
2164 internal override ExprValue apply( Interp interp, TclObject[] argv )
2165 {
2166 double x = TclDouble.get( interp, argv[0] );
2167 if ( x == 0 )
2168 {
2169 return new ExprValue( 0.0 );
2170 }
2171  
2172 double d1 = System.Math.Pow( System.Math.E, x );
2173 double d2 = System.Math.Pow( System.Math.E, -x );
2174  
2175 Expression.checkDoubleRange( interp, d1 );
2176 Expression.checkDoubleRange( interp, d2 );
2177  
2178 return new ExprValue( ( d1 - d2 ) / ( d1 + d2 ) );
2179 }
2180 }
2181  
2182 class RandFunction : NoArgMathFunction
2183 {
2184  
2185 // Generate the random number using the linear congruential
2186 // generator defined by the following recurrence:
2187 // seed = ( IA * seed ) mod IM
2188 // where IA is 16807 and IM is (2^31) - 1. In order to avoid
2189 // potential problems with integer overflow, the code uses
2190 // additional constants IQ and IR such that
2191 // IM = IA*IQ + IR
2192 // For details on how this algorithm works, refer to the following
2193 // papers:
2194 //
2195 // S.K. Park & K.W. Miller, "Random number generators: good ones
2196 // are hard to find," Comm ACM 31(10):1192-1201, Oct 1988
2197 //
2198 // W.H. Press & S.A. Teukolsky, "Portable random number
2199 // generators," Computers in Physics 6(5):522-524, Sep/Oct 1992.
2200  
2201  
2202 private const int randIA = 16807;
2203 private const int randIM = 2147483647;
2204 private const int randIQ = 127773;
2205 private const int randIR = 2836;
2206 private static readonly System.DateTime date = System.DateTime.Now;
2207  
2208 /// <summary> Srand calls the main algorithm for rand after it sets the seed.
2209 /// To facilitate this call, the method is static and can be used
2210 /// w/o creating a new object. But we also need to maintain the
2211 /// inheritance hierarchy, thus the dynamic apply() calls the static
2212 /// statApply().
2213 /// </summary>
2214  
2215 internal override ExprValue apply( Interp interp, TclObject[] argv )
2216 {
2217 return ( statApply( interp, argv ) );
2218 }
2219  
2220  
2221 internal static ExprValue statApply( Interp interp, TclObject[] argv )
2222 {
2223  
2224 int tmp;
2225  
2226 if ( !( interp.randSeedInit ) )
2227 {
2228 interp.randSeedInit = true;
2229 interp.randSeed = (int)date.Ticks;
2230 }
2231  
2232 if ( interp.randSeed == 0 )
2233 {
2234 // Don't allow a 0 seed, since it breaks the generator. Shift
2235 // it to some other value.
2236  
2237 interp.randSeed = 123459876;
2238 }
2239  
2240 tmp = (int)( interp.randSeed / randIQ );
2241 interp.randSeed = ( ( randIA * ( interp.randSeed - tmp * randIQ ) ) - randIR * tmp );
2242  
2243 if ( interp.randSeed < 0 )
2244 {
2245 interp.randSeed += randIM;
2246 }
2247  
2248 return new ExprValue( interp.randSeed * ( 1.0 / randIM ) );
2249 }
2250 }
2251  
2252  
2253 class SrandFunction : UnaryMathFunction
2254 {
2255  
2256 internal override ExprValue apply( Interp interp, TclObject[] argv )
2257 {
2258  
2259 // Reset the seed.
2260  
2261 interp.randSeedInit = true;
2262  
2263 interp.randSeed = (long)TclDouble.get( interp, argv[0] );
2264  
2265 // To avoid duplicating the random number generation code we simply
2266 // call the static random number generator in the RandFunction
2267 // class.
2268  
2269 return ( RandFunction.statApply( interp, null ) );
2270 }
2271 }
2272 }