List<Expression> GetParameters() // e.g. myfun(a, b, c+2)
		{
			// check whether next token is a (, 
			// restore state and bail if it's not
			var pos  = _ptr;
			var tk = _token;
			GetToken();
			if (_token.ID != TKID.OPEN)
			{
                _ptr = pos;
                _token = tk;
				return null;
			}

			// check for empty Parameter list
			pos = _ptr;
			GetToken();
            if (_token.ID == TKID.CLOSE)
            {
                return null;
            }
			_ptr = pos;

			// get Parameters until we reach the end of the list
            var parms = new List<Expression>();
			var expr = ParseExpression();
			parms.Add(expr);
			while (_token.ID == TKID.COMMA)
			{
				expr = ParseExpression();
				parms.Add(expr);
			}

			// make sure the list was closed correctly
			if (_token.ID != TKID.CLOSE)
			{
                Throw();
			}

			// done
			return parms;
    	}
        Token GetMember()
        {
            // check whether next token is a MEMBER token ('.'), 
            // restore state and bail if it's not
            var pos = _ptr;
            var tk = _token;
            GetToken();
            if (_token.ID != TKID.PERIOD)
            {
                _ptr = pos;
                _token = tk;
                return null;
            }

            // skip member token
            GetToken();
            if (_token.Type != TKTYPE.IDENTIFIER)
            {
                Throw("Identifier expected");
            }
            return _token;
        }
 void AddToken(object symbol, TKID id, TKTYPE type)
 {
     var token = new Token(symbol, id, type);
     _tkTbl.Add(symbol, token);
 }
		//---------------------------------------------------------------------------
		#region ** parser

        void GetToken()
        {
			// eat white space 
			while (_ptr < _len && _expr[_ptr] <= ' ')
			{
				_ptr++;
			}

			// are we done?
			if (_ptr >= _len)
			{
                _token = new Token(null, TKID.END, TKTYPE.GROUP);
				return;
			}

			// prepare to parse
            int i;
			var c = _expr[_ptr];

			// operators
			// this gets called a lot, so it's pretty optimized.
			// note that operators must start with non-letter/digit characters.
            var isLetter = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
            var isDigit = c >= '0' && c <= '9';
			if (!isLetter && !isDigit)
			{
				// if this is a number starting with a decimal, don't parse as operator
                var nxt = _ptr + 1 < _len ? _expr[_ptr + 1] : 0;
                bool isNumber = c == _decimal && nxt >= '0' && nxt <= '9';
				if (!isNumber)
				{
                    // look up localized list separator
                    if (c == _listSep)
                    {
                        _token = new Token(c, TKID.COMMA, TKTYPE.GROUP);
                        _ptr++;
                        return;
                    }
                    
                    // look up single-char tokens on table
                    Token tk;
                    if (_tkTbl.TryGetValue(c, out tk))
					{
						// save token we found
						_token = tk;
						_ptr++;

						// look for double-char tokens (special case)
						if (_ptr < _len && (c == '>' || c == '<'))
						{
                            if (_tkTbl.TryGetValue(_expr.Substring(_ptr - 1, 2), out tk))
							{
								_token = tk;
								_ptr++;
							}
						}

                        // found token on the table
						return;
					}
				}
			}

			// parse numbers
            if (isDigit || c == _decimal)
			{
				var sci = false;
                var pct = false;
                var div = -1.0; // use double, not int (this may get really big)
                var val = 0.0;
                for (i = 0; i + _ptr < _len; i++)
				{
					c = _expr[_ptr + i];

                    // digits always OK
                    if (c >= '0' && c <= '9')
                    {
                        val = val * 10 + (c - '0');
                        if (div > -1)
                        {
                            div *= 10;
                        }
                        continue;
                    }

					// one decimal is OK
                    if (c == _decimal && div < 0)
					{
						div = 1;
						continue;
					}
                    
					// scientific notation?
					if ((c == 'E' || c == 'e') && !sci) 
					{
						sci = true;
						c = _expr[_ptr + i + 1];
						if (c == '+' || c == '-') i++;
						continue;
					}

                    // percentage?
                    if (c == _percent)
                    {
                        pct = true;
                        i++;
                        break;
                    }

					// end of literal
					break;
				}

                // end of number, get value
                if (!sci)
                {
                    // much faster than ParseDouble
                    if (div > 1)
                    {
                        val /= div;
                    }
                    if (pct)
                    {
                        val /= 100.0;
                    }
                }
                else
                {
                    var lit = _expr.Substring(_ptr, i);
                    val = ParseDouble(lit, _ci);
                }

                // build token
                _token = new Token(val, TKID.ATOM, TKTYPE.LITERAL);

                // advance pointer and return
                _ptr += i;
                return;
			}

			// parse strings
			if (c == '\"')
			{
				// look for end quote, skip double quotes
				for (i = 1; i + _ptr < _len; i++)
				{
					c = _expr[_ptr + i];
					if (c != '\"') continue;
					char cNext = i + _ptr < _len - 1 ? _expr[_ptr + i + 1]: ' ';
					if (cNext != '\"') break;
					i++;
				}

				// check that we got the end of the string
				if (c != '\"')
				{
					Throw("Can't find final quote.");
				}

				// end of string
				var lit = _expr.Substring(_ptr + 1, i - 1);
				_ptr += i + 1;
                _token = new Token(lit.Replace("\"\"", "\""), TKID.ATOM, TKTYPE.LITERAL);
				return;
			}

			// parse dates (review)
			if (c == '#')
			{
				// look for end #
				for (i = 1; i + _ptr < _len; i++)
				{
					c = _expr[_ptr + i];
					if (c == '#') break;
				}

				// check that we got the end of the date
				if (c != '#') 
				{
					Throw("Can't find final date delimiter ('#').");
				}

				// end of date
				var lit = _expr.Substring(_ptr + 1, i - 1);
				_ptr += i + 1;
                _token = new Token(DateTime.Parse(lit, _ci), TKID.ATOM, TKTYPE.LITERAL);
				return;
			}

            // identifiers (functions, objects) must start with alpha or underscore
            if (!isLetter && c != '_' && (_idChars == null || _idChars.IndexOf(c) < 0))
            {
                Throw("Identifier expected.");
            }

            // and must contain only letters/digits/_idChars
            for (i = 1; i + _ptr < _len; i++)
            {
                c = _expr[_ptr + i];
                isLetter = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
                isDigit = c >= '0' && c <= '9';
                if (!isLetter && !isDigit && c != '_' && (_idChars == null || _idChars.IndexOf(c) < 0))
                {
                    break;
                }
            }

            // got identifier
            var id = _expr.Substring(_ptr, i);
            _ptr += i;
            _token = new Token(id, TKID.ATOM, TKTYPE.IDENTIFIER);
		}
Example #5
0
 internal Expression(Token tk)
 {
     _token = tk;
 }
Example #6
0
 internal Expression(object value)
 {
     _token = new Token(value, TKID.ATOM, TKTYPE.LITERAL);
 }
Example #7
0
        //---------------------------------------------------------------------------
        #region ** ctors

        internal Expression()
        {
            _token = new Token(null, TKID.ATOM, TKTYPE.IDENTIFIER);
        }
Example #8
0
 // ** ctor
 public BinaryExpression(Token tk, Expression exprLeft, Expression exprRight) : base(tk)
 {
     _lft = exprLeft;
     _rgt = exprRight;
 }
Example #9
0
 // ** ctor
 public UnaryExpression(Token tk, Expression expr) : base(tk)
 {
     _expr = expr;
 }