Beispiel #1
0
		/// <summary> Converts a value from int or double representation to a string.</summary>
		/// <param name="interp">interpreter to use for precision information.
		/// </param>
		/// <param name="value">Value to be converted.
		/// </param>
		
		internal static void  ExprMakeString(Interp interp, ExprValue value)
		{
			if (value.type == ExprValue.INT)
			{
				value.stringValue = System.Convert.ToString(value.intValue);
			}
			else if (value.type == ExprValue.DOUBLE)
			{
				value.stringValue = value.doubleValue.ToString();
			}
			value.type = ExprValue.STRING;
		}
Beispiel #2
0
		/// <summary> Parse a "value" from the remainder of the expression.
		/// 
		/// </summary>
		/// <param name="interp">the context in which to evaluate the expression.
		/// </param>
		/// <param name="prec">treat any un-parenthesized operator with precedence
		/// <= this as the end of the expression.
		/// </param>
		/// <exception cref=""> TclException for malformed expressions.
		/// </exception>
		/// <returns> the value of the expression.
		/// </returns>
		private ExprValue ExprGetValue(Interp interp, int prec)
		{
			int Operator;
			bool gotOp = false; // True means already lexed the
			// operator (while picking up value
			// for unary operator).  Don't lex
			// again.
			ExprValue value, value2;
			
			// There are two phases to this procedure.  First, pick off an
			// initial value.  Then, parse (binary operator, value) pairs
			// until done.
			
			value = ExprLex(interp);
			
			if (m_token == OPEN_PAREN)
			{
				
				// Parenthesized sub-expression.
				
				value = ExprGetValue(interp, - 1);
				if (m_token != CLOSE_PAREN)
				{
					SyntaxError(interp);
				}
			}
			else
			{
				if (m_token == MINUS)
				{
					m_token = UNARY_MINUS;
				}
				if (m_token == PLUS)
				{
					m_token = UNARY_PLUS;
				}
				if (m_token >= UNARY_MINUS)
				{
					
					// Process unary operators.
					
					Operator = m_token;
					value = ExprGetValue(interp, precTable[m_token]);
					
					if (interp.noEval == 0)
					{
						switch (Operator)
						{
							
							case UNARY_MINUS: 
								if (value.type == ExprValue.INT)
								{
									value.intValue = - value.intValue;
								}
								else if (value.type == ExprValue.DOUBLE)
								{
									value.doubleValue = - value.doubleValue;
								}
								else
								{
									IllegalType(interp, value.type, Operator);
								}
								break;
							
							case UNARY_PLUS: 
								if ((value.type != ExprValue.INT) && (value.type != ExprValue.DOUBLE))
								{
									IllegalType(interp, value.type, Operator);
								}
								break;
							
							case NOT: 
								if (value.type == ExprValue.INT)
								{
									if (value.intValue != 0)
									{
										value.intValue = 0;
									}
									else
									{
										value.intValue = 1;
									}
								}
								else if (value.type == ExprValue.DOUBLE)
								{
									if (value.doubleValue == 0.0)
									{
										value.intValue = 1;
									}
									else
									{
										value.intValue = 0;
									}
									value.type = ExprValue.INT;
								}
								else
								{
									IllegalType(interp, value.type, Operator);
								}
								break;
							
							case BIT_NOT: 
								if (value.type == ExprValue.INT)
								{
									value.intValue = ~ value.intValue;
								}
								else
								{
									IllegalType(interp, value.type, Operator);
								}
								break;
							}
					}
					gotOp = true;
				}
				else if (m_token == CLOSE_PAREN)
				{
					// Caller needs to deal with close paren token.
					return null;
				}
				else if (m_token != VALUE)
				{
					SyntaxError(interp);
				}
			}
			if (value == null)
			{
				SyntaxError(interp);
			}
			
			// Got the first operand.  Now fetch (operator, operand) pairs.
			
			if (!gotOp)
			{
				value2 = ExprLex(interp);
			}
			
			while (true)
			{
				Operator = m_token;
				if ((Operator < MULT) || (Operator >= UNARY_MINUS))
				{
					if ((Operator == END) || (Operator == CLOSE_PAREN) || (Operator == COMMA))
					{
						return value; // Goto Done
					}
					else
					{
						SyntaxError(interp);
					}
				}
				if (precTable[Operator] <= prec)
				{
					return value; // (goto done)
				}
				
				// If we're doing an AND or OR and the first operand already
				// determines the result, don't execute anything in the
				// second operand:  just parse.  Same style for ?: pairs.
				
				if ((Operator == AND) || (Operator == OR) || (Operator == QUESTY))
				{
					
					if (value.type == ExprValue.DOUBLE)
					{
						value.intValue = (value.doubleValue != 0)?1:0;
						value.type = ExprValue.INT;
					}
					else if (value.type == ExprValue.STRING)
					{
						try
						{
							bool b = Util.getBoolean(null, value.stringValue);
							value = new ExprValue(b?1:0);
						}
						catch (TclException e)
						{
							if (interp.noEval == 0)
							{
								IllegalType(interp, ExprValue.STRING, Operator);
							}
							
							// Must set value.intValue to avoid referencing
							// uninitialized memory in the "if" below;  the actual
							// value doesn't matter, since it will be ignored.
							
							value.intValue = 0;
						}
					}
					if (((Operator == AND) && (value.intValue == 0)) || ((Operator == OR) && (value.intValue != 0)))
					{
						interp.noEval++;
						try
						{
							value2 = ExprGetValue(interp, precTable[Operator]);
						}
						finally
						{
							interp.noEval--;
						}
						if (Operator == OR)
						{
							value.intValue = 1;
						}
						continue;
					}
					else if (Operator == QUESTY)
					{
						// Special note:  ?: operators must associate right to
						// left.  To make this happen, use a precedence one lower
						// than QUESTY when calling ExprGetValue recursively.
						
						if (value.intValue != 0)
						{
							value = ExprGetValue(interp, precTable[QUESTY] - 1);
							if (m_token != COLON)
							{
								SyntaxError(interp);
							}
							
							interp.noEval++;
							try
							{
								value2 = ExprGetValue(interp, precTable[QUESTY] - 1);
							}
							finally
							{
								interp.noEval--;
							}
						}
						else
						{
							interp.noEval++;
							try
							{
								value2 = ExprGetValue(interp, precTable[QUESTY] - 1);
							}
							finally
							{
								interp.noEval--;
							}
							if (m_token != COLON)
							{
								SyntaxError(interp);
							}
							value = ExprGetValue(interp, precTable[QUESTY] - 1);
						}
						continue;
					}
					else
					{
						value2 = ExprGetValue(interp, precTable[Operator]);
					}
				}
				else
				{
					value2 = ExprGetValue(interp, precTable[Operator]);
				}
				
				
				if ((m_token < MULT) && (m_token != VALUE) && (m_token != END) && (m_token != COMMA) && (m_token != CLOSE_PAREN))
				{
					SyntaxError(interp);
				}
				
				if (interp.noEval != 0)
				{
					continue;
				}
				
				// At this point we've got two values and an operator.  Check
				// to make sure that the particular data types are appropriate
				// for the particular operator, and perform type conversion
				// if necessary.
				
				switch (Operator)
				{
					
					
					// For the operators below, no strings are allowed and
					// ints get converted to floats if necessary.
					case MULT: 
					case DIVIDE: 
					case PLUS: 
					case MINUS: 
						if ((value.type == ExprValue.STRING) || (value2.type == ExprValue.STRING))
						{
							IllegalType(interp, ExprValue.STRING, Operator);
						}
						if (value.type == ExprValue.DOUBLE)
						{
							if (value2.type == ExprValue.INT)
							{
								value2.doubleValue = value2.intValue;
								value2.type = ExprValue.DOUBLE;
							}
						}
						else if (value2.type == ExprValue.DOUBLE)
						{
							if (value.type == ExprValue.INT)
							{
								value.doubleValue = value.intValue;
								value.type = ExprValue.DOUBLE;
							}
						}
						break;
						
						// For the operators below, only integers are allowed.
					
					
					case MOD: 
					case LEFT_SHIFT: 
					case RIGHT_SHIFT: 
					case BIT_AND: 
					case BIT_XOR: 
					case BIT_OR: 
						if (value.type != ExprValue.INT)
						{
							IllegalType(interp, value.type, Operator);
						}
						else if (value2.type != ExprValue.INT)
						{
							IllegalType(interp, value2.type, Operator);
						}
						break;
						
						// For the operators below, any type is allowed but the
						// two operands must have the same type.  Convert integers
						// to floats and either to strings, if necessary.
					
					
					case LESS: 
					case GREATER: 
					case LEQ: 
					case GEQ: 
					case EQUAL: 
          case EQ:
					case NEQ:
          case NE:
            if ( value.type == ExprValue.STRING )
						{
							if (value2.type != ExprValue.STRING)
							{
								ExprMakeString(interp, value2);
							}
						}
						else if (value2.type == ExprValue.STRING)
						{
							if (value.type != ExprValue.STRING)
							{
								ExprMakeString(interp, value);
							}
						}
						else if (value.type == ExprValue.DOUBLE)
						{
							if (value2.type == ExprValue.INT)
							{
								value2.doubleValue = value2.intValue;
								value2.type = ExprValue.DOUBLE;
							}
						}
						else if (value2.type == ExprValue.DOUBLE)
						{
							if (value.type == ExprValue.INT)
							{
								value.doubleValue = value.intValue;
								value.type = ExprValue.DOUBLE;
							}
						}
						break;
						
						// For the operators below, no strings are allowed, but
						// no int->double conversions are performed.
					
					
					case AND: 
					case OR: 
						if (value.type == ExprValue.STRING)
						{
							IllegalType(interp, value.type, Operator);
						}
						if (value2.type == ExprValue.STRING)
						{
							try
							{
								bool b = Util.getBoolean(null, value2.stringValue);
								value2 = new ExprValue(b?1:0);
							}
							catch (TclException e)
							{
								IllegalType(interp, value2.type, Operator);
							}
						}
						break;
						
						// For the operators below, type and conversions are
						// irrelevant:  they're handled elsewhere.
					
					
					case QUESTY: 
					case COLON: 
						break;
						
						// Any other operator is an error.
					
					
					default: 
						throw new TclException(interp, "unknown operator in expression");
					
				}
				
				// Carry out the function of the specified operator.
				
				switch (Operator)
				{
					
					case MULT: 
						if (value.type == ExprValue.INT)
						{
							value.intValue = value.intValue * value2.intValue;
						}
						else
						{
							value.doubleValue *= value2.doubleValue;
						}
						break;
					
					case DIVIDE: 
					case MOD: 
						if (value.type == ExprValue.INT)
						{
							long divisor, quot, rem;
							bool negative;
							
							if (value2.intValue == 0)
							{
								DivideByZero(interp);
							}
							
							// The code below is tricky because C doesn't guarantee
							// much about the properties of the quotient or
							// remainder, but Tcl does:  the remainder always has
							// the same sign as the divisor and a smaller absolute
							// value.
							
							divisor = value2.intValue;
							negative = false;
							if (divisor < 0)
							{
								divisor = - divisor;
								value.intValue = - value.intValue;
								negative = true;
							}
							quot = value.intValue / divisor;
							rem = value.intValue % divisor;
							if (rem < 0)
							{
								rem += divisor;
								quot -= 1;
							}
							if (negative)
							{
								rem = - rem;
							}
							value.intValue = (Operator == DIVIDE)?quot:rem;
						}
						else
						{
							if (value2.doubleValue == 0.0)
							{
								DivideByZero(interp);
							}
							value.doubleValue /= value2.doubleValue;
						}
						break;
					
					case PLUS: 
						if (value.type == ExprValue.INT)
						{
							value.intValue = value.intValue + value2.intValue;
						}
						else
						{
							value.doubleValue += value2.doubleValue;
						}
						break;
					
					case MINUS: 
						if (value.type == ExprValue.INT)
						{
							value.intValue = value.intValue - value2.intValue;
						}
						else
						{
							value.doubleValue -= value2.doubleValue;
						}
						break;
					
					case LEFT_SHIFT: 
						value.intValue <<= (int) value2.intValue;
						break;
					
					case RIGHT_SHIFT: 
						
						if (value.intValue < 0)
						{
							value.intValue = ~ ((~ value.intValue) >> (int) value2.intValue);
						}
						else
						{
							value.intValue >>= (int) value2.intValue;
						}
						break;
					
					case LESS: 
						if (value.type == ExprValue.INT)
						{
							value.intValue = (value.intValue < value2.intValue)?1:0;
						}
						else if (value.type == ExprValue.DOUBLE)
						{
							value.intValue = (value.doubleValue < value2.doubleValue)?1:0;
						}
						else
						{
							value.intValue = (value.stringValue.CompareTo(value2.stringValue) < 0)?1:0;
						}
						value.type = ExprValue.INT;
						break;
					
					case GREATER: 
						if (value.type == ExprValue.INT)
						{
							value.intValue = (value.intValue > value2.intValue)?1:0;
						}
						else if (value.type == ExprValue.DOUBLE)
						{
							value.intValue = (value.doubleValue > value2.doubleValue)?1:0;
						}
						else
						{
							value.intValue = (value.stringValue.CompareTo(value2.stringValue) > 0)?1:0;
						}
						value.type = ExprValue.INT;
						break;
					
					case LEQ: 
						if (value.type == ExprValue.INT)
						{
							value.intValue = (value.intValue <= value2.intValue)?1:0;
						}
						else if (value.type == ExprValue.DOUBLE)
						{
							value.intValue = (value.doubleValue <= value2.doubleValue)?1:0;
						}
						else
						{
							value.intValue = (value.stringValue.CompareTo(value2.stringValue) <= 0)?1:0;
						}
						value.type = ExprValue.INT;
						break;
					
					case GEQ: 
						if (value.type == ExprValue.INT)
						{
							value.intValue = (value.intValue >= value2.intValue)?1:0;
						}
						else if (value.type == ExprValue.DOUBLE)
						{
							value.intValue = (value.doubleValue >= value2.doubleValue)?1:0;
						}
						else
						{
							value.intValue = (value.stringValue.CompareTo(value2.stringValue) >= 0)?1:0;
						}
						value.type = ExprValue.INT;
						break;
					
					case EQUAL: 
          case EQ: 
						if (value.type == ExprValue.INT)
						{
							value.intValue = (value.intValue == value2.intValue)?1:0;
						}
						else if (value.type == ExprValue.DOUBLE)
						{
							value.intValue = (value.doubleValue == value2.doubleValue)?1:0;
						}
						else
						{
							value.intValue = (value.stringValue.CompareTo(value2.stringValue) == 0)?1:0;
						}
						value.type = ExprValue.INT;
						break;
					
					case NEQ: 
          case NE:
						if (value.type == ExprValue.INT)
						{
							value.intValue = (value.intValue != value2.intValue)?1:0;
						}
						else if (value.type == ExprValue.DOUBLE)
						{
							value.intValue = (value.doubleValue != value2.doubleValue)?1:0;
						}
						else
						{
							value.intValue = (value.stringValue.CompareTo(value2.stringValue) != 0)?1:0;
						}
						value.type = ExprValue.INT;
						break;
					
					case BIT_AND: 
						value.intValue &= value2.intValue;
						break;
					
					case BIT_XOR: 
						value.intValue ^= value2.intValue;
						break;
					
					case BIT_OR: 
						value.intValue |= value2.intValue;
						break;
						
						// For AND and OR, we know that the first value has already
						// been converted to an integer.  Thus we need only consider
						// the possibility of int vs. double for the second value.
					
					
					case AND: 
						if (value2.type == ExprValue.DOUBLE)
						{
							value2.intValue = (value2.doubleValue != 0)?1:0;
							value2.type = ExprValue.INT;
						}
						value.intValue = ((value.intValue != 0) && (value2.intValue != 0))?1:0;
						break;
					
					case OR: 
						if (value2.type == ExprValue.DOUBLE)
						{
							value2.intValue = (value2.doubleValue != 0)?1:0;
							value2.type = ExprValue.INT;
						}
						value.intValue = ((value.intValue != 0) || (value2.intValue != 0))?1:0;
						break;
					
					
					case COLON: 
						SyntaxError(interp);
						break;
					}
			}
		}
Beispiel #3
0
		/// <summary> GetLexeme -> ExprLex
		/// 
		/// Lexical analyzer for expression parser:  parses a single value,
		/// operator, or other syntactic element from an expression string.
		/// 
		/// Size effects: the "m_token" member variable is set to the value of
		/// the current token.
		/// 
		/// </summary>
		/// <param name="interp">the context in which to evaluate the expression.
		/// </param>
		/// <exception cref=""> TclException for malformed expressions.
		/// </exception>
		/// <returns> the value of the expression.
		/// </returns>
		private ExprValue ExprLex(Interp interp)
		{
			char c, c2;
			
			while (m_ind < m_len && System.Char.IsWhiteSpace(m_expr[m_ind]))
			{
				m_ind++;
			}
			if (m_ind >= m_len)
			{
				m_token = END;
				return null;
			}
			
			// First try to parse the token as an integer or
			// floating-point number.  Don't want to check for a number if
			// the first character is "+" or "-".  If we do, we might
			// treat a binary operator as unary by
			// mistake, which will eventually cause a syntax error.
			
			c = m_expr[m_ind];
			if (m_ind < m_len - 1)
			{
				c2 = m_expr[m_ind + 1];
			}
			else
			{
				c2 = '\x0000';
			}
			
			if ((c != '+') && (c != '-'))
			{
				bool startsWithDigit = System.Char.IsDigit(c);
				if (startsWithDigit && looksLikeInt(m_expr, m_len, m_ind))
				{
					StrtoulResult res = Util.strtoul(m_expr, m_ind, 0);
					
					if (res.errno == 0)
					{
						m_ind = res.index;
						m_token = VALUE;
						return new ExprValue(res.value);
					}
					else
					{
						if (res.errno == TCL.INTEGER_RANGE)
						{
							IntegerTooLarge(interp);
						}
					}
				}
				else if (startsWithDigit || (c == '.') || (c == 'n') || (c == 'N'))
				{
					StrtodResult res = Util.strtod(m_expr, m_ind);
					if (res.errno == 0)
					{
						m_ind = res.index;
						m_token = VALUE;
						return new ExprValue(res.value);
					}
					else
					{
						if (res.errno == TCL.DOUBLE_RANGE)
						{
							if (res.value != 0)
							{
								DoubleTooLarge(interp);
							}
							else
							{
								DoubleTooSmall(interp);
							}
						}
					}
				}
			}
			
			ParseResult pres;
			ExprValue retval;
			m_ind += 1; // ind is advanced to point to the next token
			
			switch (c)
			{
				
				case '$': 
					m_token = VALUE;
					pres = ParseAdaptor.parseVar(interp, m_expr, m_ind, m_len);
					m_ind = pres.nextIndex;
					
					if (interp.noEval != 0)
					{
						retval = new ExprValue(0);
					}
					else
					{
						
						retval = ExprParseString(interp, pres.value.ToString());
					}
					pres.release();
					return retval;
				
				case '[': 
					m_token = VALUE;
					pres = ParseAdaptor.parseNestedCmd(interp, m_expr, m_ind, m_len);
					m_ind = pres.nextIndex;
					
					if (interp.noEval != 0)
					{
						retval = new ExprValue(0);
					}
					else
					{
						
						retval = ExprParseString(interp, pres.value.ToString());
					}
					pres.release();
					return retval;
				
				case '"': 
					m_token = VALUE;
					
					
					//System.out.println("now to parse from ->" + m_expr + "<- at index "
					//	+ m_ind);
					
					pres = ParseAdaptor.parseQuotes(interp, m_expr, m_ind, m_len);
					m_ind = pres.nextIndex;
					
					//   System.out.println("after parse next index is " + m_ind);
					
					if (interp.noEval != 0)
					{
						//      System.out.println("returning noEval zero value");
						retval = new ExprValue(0);
					}
					else
					{
						//     System.out.println("returning value string ->" + pres.value.toString() + "<-" );
						
						retval = ExprParseString(interp, pres.value.ToString());
					}
					pres.release();
					return retval;
				
				case '{': 
					m_token = VALUE;
					pres = ParseAdaptor.parseBraces(interp, m_expr, m_ind, m_len);
					m_ind = pres.nextIndex;
					if (interp.noEval != 0)
					{
						retval = new ExprValue(0);
					}
					else
					{
						
						retval = ExprParseString(interp, pres.value.ToString());
					}
					pres.release();
					return retval;
				
				case '(': 
					m_token = OPEN_PAREN;
					return null;
				
				
				case ')': 
					m_token = CLOSE_PAREN;
					return null;
				
				
				case ',': 
					m_token = COMMA;
					return null;
				
				
				case '*': 
					m_token = MULT;
					return null;
				
				
				case '/': 
					m_token = DIVIDE;
					return null;
				
				
				case '%': 
					m_token = MOD;
					return null;
				
				
				case '+': 
					m_token = PLUS;
					return null;
				
				
				case '-': 
					m_token = MINUS;
					return null;
				
				
				case '?': 
					m_token = QUESTY;
					return null;
				
				
				case ':': 
					m_token = COLON;
					return null;
				
				
				case '<': 
					switch (c2)
					{
						
						case '<': 
							m_ind += 1;
							m_token = LEFT_SHIFT;
							break;
						
						case '=': 
							m_ind += 1;
							m_token = LEQ;
							break;
						
						default: 
							m_token = LESS;
							break;
						
					}
					return null;
				
				
				case '>': 
					switch (c2)
					{
						
						case '>': 
							m_ind += 1;
							m_token = RIGHT_SHIFT;
							break;
						
						case '=': 
							m_ind += 1;
							m_token = GEQ;
							break;
						
						default: 
							m_token = GREATER;
							break;
						
					}
					return null;
				
				
				case '=': 
					if (c2 == '=')
					{
						m_ind += 1;
						m_token = EQUAL;
					}
					else
					{
						m_token = UNKNOWN;
					}
					return null;


        case 'e':
          if ( c2 == 'q' )
          {
            m_ind += 1;
            m_token = EQUAL;
          }
          else
          {
            m_token = UNKNOWN;
          }
          return null;


        case 'n':
          if ( c2 == 'e' )
          {
            m_ind += 1;
            m_token = NEQ;
          }
          else
          {
            m_token = UNKNOWN;
          }
          return null;
        
        
        case '!': 
					if (c2 == '=')
					{
						m_ind += 1;
						m_token = NEQ;
					}
					else
					{
						m_token = NOT;
					}
					return null;
				
				
				case '&': 
					if (c2 == '&')
					{
						m_ind += 1;
						m_token = AND;
					}
					else
					{
						m_token = BIT_AND;
					}
					return null;
				
				
				case '^': 
					m_token = BIT_XOR;
					return null;
				
				
				case '|': 
					if (c2 == '|')
					{
						m_ind += 1;
						m_token = OR;
					}
					else
					{
						m_token = BIT_OR;
					}
					return null;
				
				
				case '~': 
					m_token = BIT_NOT;
					return null;
				
				
				default: 
					if (System.Char.IsLetter(c))
					{
						// Oops, re-adjust m_ind so that it points to the beginning
						// of the function name.
						
						m_ind--;
						return mathFunction(interp);
					}
					m_token = UNKNOWN;
					return null;
				
			}
		}