public InitialValue EvaluateConstExpression(TokenExpression expression, bool constOnly)
        {
            if (expression == null)
            {
                return(null);
            }
            //leaf? )
            if (expression.Subexpressions.Count == 0)
            {
                if (expression.TokenType == TokenType.Identifier)
                {
                    IVariable variable = Symbols.GetOrNull(expression.Token.Value);
                    if (variable == null)
                    {
                        return(null);
                    }
                    if (constOnly)
                    {
                        if (Parent.Constants.Contains(expression.Token.Value))
                        {
                        }
                        else
                        {
                            return(null);
                        }
                    }
                    if (InitialValues.ContainsKey(variable))
                    {
                        return(InitialValues[variable]);
                    }
                    else
                    {
                        if (variable.DataType.IsInteger())
                        {
                            return(new InitialValue(0));
                        }
                        else if (variable.DataType.IsFloat())
                        {
                            return(new InitialValue(0.0f));
                        }
                        else if (variable.DataType.IsString())
                        {
                            return(new InitialValue(""));
                        }
                        else if (variable.DataType == DataType.Bool || variable.DataType == DataType.RefBool)
                        {
                            return(new InitialValue(false));
                        }
                        else if (variable is Function)
                        {
                            return(new InitialValue(variable.Index));
                        }
                    }
                    return(null);
                }
                else if (expression.TokenType == TokenType.Number)
                {
                    if (expression.Token.IsInt())
                    {
                        return(new InitialValue(expression.Token.ToInt()));
                    }
                    else if (expression.Token.IsFloat())
                    {
                        return(new InitialValue(expression.Token.ToFloat()));
                    }
                }
                else if (expression.TokenType == TokenType.StringLiteral)
                {
                    return(new InitialValue(expression.Token.Value));
                }
                else if (expression.TokenType == TokenType.CharLiteral)
                {
                    var bytes = Extensions.BinaryEncoding.GetBytes(expression.Token.Value);
                    if (bytes.Length > 1)
                    {
                        return(new InitialValue(bytes[1] * 256 + bytes[0]));
                    }
                    else
                    {
                        return(new InitialValue(bytes[0]));
                    }
                }
                return(null);
            }
            //unary operator?
            if (expression.Subexpressions.Count == 1)
            {
                var a = EvaluateConstExpression(expression.Subexpressions[0], constOnly);
                if (a == null)
                {
                    return(null);
                }

                switch (expression.TokenType)
                {
                case TokenType.Complement:
                {
                    if (a.DataType == DataType.Int || a.DataType == DataType.Bool)
                    {
                        return(new InitialValue(~a.IntValue));
                    }
                    return(null);
                }

                case TokenType.Not:
                {
                    if (a.DataType == DataType.Int || a.DataType == DataType.Bool)
                    {
                        return(new InitialValue(a.IntValue != 0));
                    }
                    if (a.DataType == DataType.Float)
                    {
                        return(new InitialValue(a.FloatValue != 0));
                    }
                    return(null);
                }

                case TokenType.Negative:
                {
                    if (a.DataType == DataType.Int || a.DataType == DataType.Bool)
                    {
                        return(new InitialValue(-a.IntValue));
                    }
                    else if (a.DataType == DataType.Float)
                    {
                        return(new InitialValue(-a.FloatValue));
                    }
                    return(null);
                }

                case TokenType.Positive:
                case TokenType.PostDecrement:
                case TokenType.PostIncrement:
                {
                    if (a.DataType == DataType.Int || a.DataType == DataType.Bool || a.DataType == DataType.Float)
                    {
                        return(a);
                    }
                    return(null);
                }

                case TokenType.PreIncrement:
                {
                    if (a.DataType == DataType.Int || a.DataType == DataType.Bool)
                    {
                        return(new InitialValue(a.IntValue + 1));
                    }
                    else if (a.DataType == DataType.Float)
                    {
                        return(new InitialValue(a.FloatValue + 1.0f));
                    }
                    return(null);
                }

                case TokenType.PreDecrement:
                {
                    if (a.DataType == DataType.Int || a.DataType == DataType.Bool)
                    {
                        return(new InitialValue(a.IntValue - 1));
                    }
                    else if (a.DataType == DataType.Float)
                    {
                        return(new InitialValue(a.FloatValue - 1.0f));
                    }
                    return(null);
                }

                case TokenType.AddressOf:
                {
                    if (a.DataType == DataType.Int)
                    {
                        if (expression.Subexpressions[0].TokenType == TokenType.Identifier && Symbols[expression.Subexpressions[0].Token.Value] is Function)
                        {
                            return(a);
                        }
                    }
                    return(null);
                }
                }
                return(null);
            }
            //binary expression?
            if (expression.Subexpressions.Count == 2)
            {
                var a = EvaluateConstExpression(expression.Subexpressions[0], constOnly);
                var b = EvaluateConstExpression(expression.Subexpressions[1], constOnly);

                //cast expressions (expressed as a functioncall)
                if (expression.TokenType == TokenType.FunctionCall && b != null)
                {
                    var exprA = expression.Subexpressions[0];
                    if (exprA.TokenType == TokenType.String)
                    {
                        if (b.DataType == DataType.String)
                        {
                            return(b);
                        }
                        else
                        {
                            return(new InitialValue(b.GetValue()));
                        }
                    }
                    else if (exprA.TokenType == TokenType.Float)
                    {
                        InitialValue v = new InitialValue();
                        if (v.SetValue(DataType.Float, b.GetValue()))
                        {
                            return(v);
                        }
                        else
                        {
                            return(null);
                        }
                    }
                    else if (exprA.TokenType == TokenType.Int)
                    {
                        InitialValue v = new InitialValue();
                        if (v.SetValue(DataType.Int, b.GetValue()))
                        {
                            return(v);
                        }
                        else
                        {
                            return(null);
                        }
                    }
                }

                if (expression.TokenType == TokenType.Assign)
                {
                    return(b);
                }

                if (a == null || b == null)
                {
                    return(null);
                }

                if (a.DataType == DataType.Float || b.DataType == DataType.Float)
                {
                    float floatA;
                    float floatB;

                    if (a.DataType == DataType.Int || a.DataType == DataType.Bool)
                    {
                        floatA = a.IntValue;
                    }
                    else if (a.DataType == DataType.Float)
                    {
                        floatA = a.FloatValue;
                    }
                    else
                    {
                        return(null);
                    }

                    if (b.DataType == DataType.Int || b.DataType == DataType.Bool)
                    {
                        floatB = b.IntValue;
                    }
                    else if (b.DataType == DataType.Float)
                    {
                        floatB = b.FloatValue;
                    }
                    else
                    {
                        return(null);
                    }

                    switch (expression.TokenType)
                    {
                    case TokenType.Multiply:
                    case TokenType.MultiplyAssign:
                        return(new InitialValue(floatA * floatB));

                    case TokenType.Divide:
                    case TokenType.DivideAssign:
                        return(new InitialValue(floatA / floatB));

                    case TokenType.Modulo:
                    case TokenType.ModuloAssign:
                        return(new InitialValue(floatA % floatB));

                    case TokenType.Plus:
                    case TokenType.PlusAssign:
                        return(new InitialValue(floatA + floatB));

                    case TokenType.Minus:
                    case TokenType.MinusAssign:
                        return(new InitialValue(floatA - floatB));

                    case TokenType.LeftShift:
                    case TokenType.LeftShiftAssign:
                        return(new InitialValue((int)floatA << (int)floatB));

                    case TokenType.RightShift:
                    case TokenType.RightShiftAssign:
                        return(new InitialValue((int)floatA << (int)floatB));

                    case TokenType.LessThan:
                        return(new InitialValue(floatA < floatB));

                    case TokenType.LessThanOrEqualTo:
                        return(new InitialValue(floatA <= floatB));

                    case TokenType.GreaterThan:
                        return(new InitialValue(floatA > floatB));

                    case TokenType.GreaterThanOrEqualTo:
                        return(new InitialValue(floatA >= floatB));

                    case TokenType.EqualTo:
                        return(new InitialValue(floatA == floatB));

                    case TokenType.NotEqualTo:
                        return(new InitialValue(floatA != floatB));

                    case TokenType.And:
                    case TokenType.AndAssign:
                        return(new InitialValue((int)floatA & (int)floatB));

                    case TokenType.Xor:
                    case TokenType.XorAssign:
                        return(new InitialValue((int)floatA ^ (int)floatB));

                    case TokenType.Or:
                    case TokenType.OrAssign:
                        return(new InitialValue((int)floatA | (int)floatB));

                    case TokenType.LogicalAnd:
                        return(new InitialValue((floatA != 0) && (floatB != 0)));

                    case TokenType.LogicalOr:
                        return(new InitialValue((floatA != 0) || (floatB != 0)));

                    case TokenType.Assign:
                        return(new InitialValue(floatB));
                    }
                    return(null);
                }

                if (a.DataType == DataType.String && b.DataType == DataType.String)
                {
                    string stringA = a.StringValue ?? "";
                    string stringB = b.StringValue ?? "";

                    switch (expression.TokenType)
                    {
                    case TokenType.Plus:
                    case TokenType.PlusAssign:
                        return(new InitialValue(stringA + stringB));

                    case TokenType.LessThan:
                        return(new InitialValue(String.Compare(stringA, stringB) < 0));

                    case TokenType.LessThanOrEqualTo:
                        return(new InitialValue(String.Compare(stringA, stringB) <= 0));

                    case TokenType.GreaterThan:
                        return(new InitialValue(String.Compare(stringA, stringB) > 0));

                    case TokenType.GreaterThanOrEqualTo:
                        return(new InitialValue(String.Compare(stringA, stringB) >= 0));

                    case TokenType.EqualTo:
                        return(new InitialValue(stringA == stringB));

                    case TokenType.NotEqualTo:
                        return(new InitialValue(stringA != stringB));

                    case TokenType.LogicalAnd:
                        return(new InitialValue((stringA != "") && (stringB != "")));

                    case TokenType.LogicalOr:
                        return(new InitialValue((stringA != "") || (stringB != "")));

                    case TokenType.Assign:
                        return(new InitialValue(stringB));
                    }
                    return(null);
                }

                {
                    int intA;
                    int intB;

                    if (a.DataType == DataType.Int || a.DataType == DataType.Bool)
                    {
                        intA = a.IntValue;
                    }
                    else
                    {
                        return(null);
                    }

                    if (b.DataType == DataType.Int || b.DataType == DataType.Bool)
                    {
                        intB = b.IntValue;
                    }
                    else
                    {
                        return(null);
                    }

                    switch (expression.TokenType)
                    {
                    case TokenType.Multiply:
                    case TokenType.MultiplyAssign:
                        return(new InitialValue(intA * intB));

                    case TokenType.Divide:
                    case TokenType.DivideAssign:
                        return(new InitialValue(intA / intB));

                    case TokenType.Modulo:
                    case TokenType.ModuloAssign:
                        return(new InitialValue(intA % intB));

                    case TokenType.Plus:
                    case TokenType.PlusAssign:
                        return(new InitialValue(intA + intB));

                    case TokenType.Minus:
                    case TokenType.MinusAssign:
                        return(new InitialValue(intA - intB));

                    case TokenType.LeftShift:
                    case TokenType.LeftShiftAssign:
                        return(new InitialValue(intA << intB));

                    case TokenType.RightShift:
                    case TokenType.RightShiftAssign:
                        return(new InitialValue(intA << intB));

                    case TokenType.LessThan:
                        return(new InitialValue(intA < intB));

                    case TokenType.LessThanOrEqualTo:
                        return(new InitialValue(intA <= intB));

                    case TokenType.GreaterThan:
                        return(new InitialValue(intA > intB));

                    case TokenType.GreaterThanOrEqualTo:
                        return(new InitialValue(intA >= intB));

                    case TokenType.EqualTo:
                        return(new InitialValue(intA == intB));

                    case TokenType.NotEqualTo:
                        return(new InitialValue(intA != intB));

                    case TokenType.And:
                    case TokenType.AndAssign:
                        return(new InitialValue(intA & intB));

                    case TokenType.Xor:
                    case TokenType.XorAssign:
                        return(new InitialValue(intA ^ intB));

                    case TokenType.Or:
                    case TokenType.OrAssign:
                        return(new InitialValue(intA | intB));

                    case TokenType.LogicalAnd:
                        return(new InitialValue((intA != 0) && (intB != 0)));

                    case TokenType.LogicalOr:
                        return(new InitialValue((intA != 0) || (intB != 0)));

                    case TokenType.Assign:
                        return(new InitialValue(intB));
                    }
                    return(null);
                }
            }
            return(null);
        }