Ejemplo n.º 1
0
        object evalNode(Symbol node)
        {
            object left;
            object right;

            //double x;

            switch (node.type)
            {
            case TokenType.number:
            case TokenType.litstring:
                return(node.value);

            case TokenType.mod:
                left  = evalNode(node.left);
                right = evalNode(node.right);

                if (left is string || right is string)
                {
                    string errorString = string.Format("Incompatible types at line {0} position {1}.", node.stRow, node.stCol);
                    throw new Exception(errorString);
                }

                //x = Convert.ToDouble(right);
                //if (x == 0)
                //{
                //	string errorString = string.Format("Division by zero at line {0} position {1}.", node.right.stRow, node.right.stCol);
                //	throw new Exception(errorString);
                //}
                //return left % right;
                return(Convert.ToDouble(left) % Convert.ToDouble(right));

            case TokenType.mul:
                left  = evalNode(node.left);
                right = evalNode(node.right);

                if (left is string || right is string)
                {
                    string errorString = string.Format("Incompatible types at line {0} position {1}.", node.stRow, node.stCol);
                    throw new Exception(errorString);
                }

                return(Convert.ToDouble(left) * Convert.ToDouble(right));

            case TokenType.plus:
                left  = evalNode(node.left);
                right = evalNode(node.right);
                if (left is string || right is string)
                {
                    return(left.ToString() + right.ToString());
                }

                return(Convert.ToDouble(left) + Convert.ToDouble(right));

            case TokenType.minus:
                right = evalNode(node.right);
                if (right is string)
                {
                    string errorString = string.Format("Incompatible types at line {0} position {1}.", node.stRow, node.stCol);
                    throw new Exception(errorString);
                }
                if (node.left == null)
                {
                    return(-Convert.ToDouble(right));
                }

                left = evalNode(node.left);
                if (left is string)
                {
                    string errorString = string.Format("Incompatible types at line {0} position {1}.", node.stRow, node.stCol);
                    throw new Exception(errorString);
                }

                return(Convert.ToDouble(left) - Convert.ToDouble(right));

            case TokenType.div:
                left  = evalNode(node.left);
                right = evalNode(node.right);

                if (left is string || right is string)
                {
                    string errorString = string.Format("Incompatible types at line {0} position {1}.", node.stRow, node.stCol);
                    throw new Exception(errorString);
                }

                //x = Convert.ToDouble(right);
                //if (x == 0)
                //{
                //	string errorString = string.Format("Division by zero at line {0} position {1}.", node.right.stRow, node.right.stCol);
                //	throw new Exception(errorString);
                //}
                //return x / y;
                return(Convert.ToDouble(left) / Convert.ToDouble(right));

            case TokenType.pow:
                left  = evalNode(node.left);
                right = evalNode(node.right);

                if (left is string || right is string)
                {
                    string errorString = string.Format("Incompatible types at line {0} position {1}.", node.stRow, node.stCol);
                    throw new Exception(errorString);
                }

                return(Math.Pow(Convert.ToDouble(left), Convert.ToDouble(right)));

            case TokenType.fact:
                left = evalNode(node.left);
                if (left is string)
                {
                    string errorString = string.Format("Incompatible types at line {0} position {1}.", node.stRow, node.stCol);
                    throw new Exception(errorString);
                }

                return(factorial(Convert.ToDouble(left)));

            case TokenType.identifier:
                object value;
                if (_level > 0)
                {
                    if (_args.TryGetValue(node.name, out value))
                    {
                        return(value);
                    }
                }

                if (!_consts.TryGetValue(node.name, out value))
                {
                    if (!_libVariables.TryGetValue(node.name, out value))
                    {
                        if (!_variables.TryGetValue(node.name, out value))
                        {
                            string errorString = string.Format("Undefined ident \"{0}\" at line {1} position {2}.", node.name, node.stRow, node.stCol);
                            throw new Exception(errorString);
                        }
                    }
                }

                return(value);

            case TokenType.assign:
                if (_consts.TryGetValue(node.name, out value))
                {
                    string errorString = string.Format("Invalid lvalue  \"{0}\" at line {1} position {2}.", node.name, node.stRow, node.stCol);
                    throw new Exception(errorString);
                }

                if (_libMode)
                {
                    _libVariables[node.name] = evalNode((Symbol)node.value);
                }
                //return _libVariables[node.name];
                else
                {
                    if (_libVariables.TryGetValue(node.name, out value))
                    {
                        string errorString = string.Format("Invalid lvalue  \"{0}\" at line {1} position {2}.", node.name, node.stRow, node.stCol);
                        throw new Exception(errorString);
                    }

                    _variables[node.name] = evalNode((Symbol)node.value);
                    //return _variables[node.name];
                }
                return(null);

            case TokenType.call:
                bool builtIn = true;
                if (!_builtInFunctions.ContainsKey(node.name))
                {
                    if (!_userFunctions.ContainsKey(node.name))
                    {
                        string errorString = string.Format("Undefined function \"{0}\" at line {1} position {2}.", node.name, node.stRow, node.stCol);
                        throw new Exception(errorString);
                    }

                    builtIn = false;
                }

                foreach (var arg in node.args)
                {
                    _argValues.Add(evalNode(arg));
                }

                _level++;
                object ret = builtIn ? _builtInFunctions[node.name]() : _userFunctions[node.name]();
                _level--;

                if (_argValues.Count > node.args.Count)
                {
                    _argValues.RemoveRange(_argValues.Count - node.args.Count, node.args.Count);
                }
                else
                {
                    _argValues.Clear();
                }

                return(ret);

            case TokenType.function:
                if (_libMode)
                {
                    _builtInFunctions[node.name] = () =>
                    {
                        for (var i = 0; i < node.args.Count; i++)
                        {
                            _args[node.args[i].name] = getArgValue(node.args.Count - 1 - i);
                        }

                        object result = evalNode((Symbol)node.value);
                        _args.Clear();
                        return(result);
                    }
                }
                ;
                else
                {
                    if (_builtInFunctions.ContainsKey(node.name) || _userFunctions.ContainsKey(node.name))
                    {
                        //string errorString = string.Format("Function \"{0}\" at line {1} position {2} alredy exist.", node.name, node.stRow, node.stCol);
                        string errorString = string.Format("Symbol \"{0}\" at line {1} position {2} alredy defined.", node.name, node.stRow, node.stCol);
                        throw new Exception(errorString);
                    }

                    _userFunctions[node.name] = () =>
                    {
                        for (var i = 0; i < node.args.Count; i++)
                        {
                            _args[node.args[i].name] = getArgValue(node.args.Count - 1 - i);
                        }

                        object result = evalNode((Symbol)node.value);
                        _args.Clear();
                        return(result);
                    };
                }
                return(null);
            }

            return(null);
        }