Пример #1
0
        private Variable ExecuteFunction(Variable func, List<Variable> arguments)
        {
            Kerbulator.DebugLine("Executing function: "+ func.id);

            if(func.type == VarType.FUNCTION) {
                if(arguments.Count != func.numArgs)
                    throw new Exception("Function "+ func.id +" takes "+ func.numArgs +" arguments, but "+ arguments.Count +" were supplied.");

                double result = 0;

                switch(func.id) {
                    case "abs":
                        return ApplyUnaryFunction(arguments[0], Math.Abs);

                    case "acos":
                        return ApplyUnaryFunction(arguments[0], Math.Acos);

                    case "asin":
                        return ApplyUnaryFunction(arguments[0], Math.Asin);

                    case "atan":
                        return ApplyUnaryFunction(arguments[0], Math.Atan);

                    case "ceil":
                        return ApplyUnaryFunction(arguments[0], Math.Ceiling);

                    case "cos":
                        return ApplyUnaryFunction(arguments[0], Math.Cos);

                    case "exp":
                        return ApplyUnaryFunction(arguments[0], Math.Exp);

                    case "floor":
                        return ApplyUnaryFunction(arguments[0], Math.Floor);

                    case "ln":
                    case "log":
                        return ApplyUnaryFunction(arguments[0], Math.Log);

                    case "log10":
                        return ApplyUnaryFunction(arguments[0], Math.Log10);

                    case "max":
                        return new Variable(VarType.NUMBER, Math.Max(arguments[0].val, arguments[1].val));

                    case "min":
                        return new Variable(VarType.NUMBER, Math.Min(arguments[0].val, arguments[1].val));

                    case "pow":
                        return new Variable(VarType.NUMBER, Math.Pow(arguments[0].val, arguments[1].val));

                    case "round":
                        if(arguments[1].type != VarType.NUMBER)
                            throw new Exception("Function round takes a number as second parameter.");

                        return ApplyUnaryFunction(arguments[0], delegate(double val) { return Math.Round(val, (int)arguments[1].val); });

                    case "sign":
                        return ApplyUnaryFunction(arguments[0], delegate(double val) { return (double)Math.Sign(val); });

                    case "sin":
                        return ApplyUnaryFunction(arguments[0], Math.Sin);

                    case "sqrt":
                        return ApplyUnaryFunction(arguments[0], Math.Sqrt);

                    case "tan":
                        return ApplyUnaryFunction(arguments[0], Math.Tan);

                    case "len":
                        if(arguments[0].type != VarType.LIST)
                            throw new Exception("Function len expects a list as input.");

                        return new Variable(VarType.NUMBER, (double)arguments[0].elements.Count);

                    case "norm":
                        if(arguments[0].type != VarType.LIST)
                            throw new Exception("Function norm expects a list as input.");

                        double length = 0;
                        foreach(Variable e in arguments[0].elements) {
                            if(e.type != VarType.NUMBER)
                                throw new Exception("Function norm cannot handle nested lists.");
                            length += e.val * e.val;
                        }

                        length = Math.Sqrt(length);

                        List<Variable> elements = new List<Variable>(arguments[0].elements.Count);
                        foreach(Variable e in arguments[0].elements)
                            elements.Add(new Variable(e.id, VarType.NUMBER, e.val/length));

                        return new Variable(VarType.LIST, elements);

                    case "dot":
                        if(arguments[0].type != VarType.LIST || arguments[1].type != VarType.LIST)
                            throw new Exception("Function dot expects two lists as input.");
                        if(arguments[0].elements.Count != arguments[1].elements.Count)
                            throw new Exception("Function dot requires two lists of the same size.");

                        result = 0;
                        for(int i=0; i<arguments[0].elements.Count; i++) {
                            Variable a = arguments[0].elements[i];
                            Variable b = arguments[1].elements[i];

                            if(a.type != VarType.NUMBER || b.type != VarType.NUMBER)
                                throw new Exception("Function dot cannot handle nested lists.");

                            result += a.val * b.val;
                        }

                        return new Variable(VarType.NUMBER, result);

                    case "cross":
                        if(arguments[0].type != VarType.LIST || arguments[1].type != VarType.LIST)
                            throw new Exception("Function cross expects two lists as input.");

                        if(arguments[0].elements.Count != 3 || arguments[1].elements.Count != 3)
                            throw new Exception("Function cross requires two lists of length 3.");

                        List<Variable> x = arguments[0].elements;
                        List<Variable> y = arguments[1].elements;

                        for(int i=0; i<x.Count; i++) {
                            if(x[i].type != VarType.NUMBER || y[i].type != VarType.NUMBER)
                                throw new Exception("Function cross cannot handle nested lists.");
                        }

                        List<Variable>z = new List<Variable>(new[]{
                            new Variable(VarType.NUMBER, x[1].val * y[2].val - x[2].val * y[1].val),
                            new Variable(VarType.NUMBER, x[2].val * y[0].val - x[0].val * y[2].val),
                            new Variable(VarType.NUMBER, x[0].val * y[1].val - x[1].val * y[0].val)
                        });

                        return new Variable(VarType.LIST, z);

                    default:
                        throw new Exception("unknown build-in function: "+ func.id);
                }
            } else {
                // User function
                Kerbulator.DebugLine("Executing "+ func.id);
                Function f = functions[func.id];
                List<Variable> result = f.Execute(arguments, operators, globals, functions);
                if(f.InError)
                    throw new Exception(f.ErrorString);

                if(result.Count == 1)
                    return result[0];
                else {
                    return new Variable(VarType.LIST, result);
                }
            }
        }
Пример #2
0
 public void AddGlobal(Variable v)
 {
     if(globals.ContainsKey(v.id))
         globals[v.id] = v;
     else
         globals.Add(v.id, v);
 }
Пример #3
0
        private Variable ApplyBinaryFunction(Variable a, Variable b, BinaryFunction action)
        {
            if(a.type == VarType.NUMBER && b.type == VarType.NUMBER)
                return new Variable("", VarType.NUMBER, action(a.val, b.val));

            else if(a.type == VarType.NUMBER && b.type == VarType.LIST) {
                List<Variable> newElements = new List<Variable>(b.elements.Count);
                foreach(Variable e in b.elements)
                    newElements.Add(ApplyBinaryFunction(a, e, action));
                return new Variable("", VarType.LIST, newElements);
            }

            else if(a.type == VarType.LIST && b.type == VarType.NUMBER) {
                List<Variable> newElements = new List<Variable>(a.elements.Count);
                foreach(Variable e in a.elements)
                    newElements.Add(ApplyBinaryFunction(e, b, action));
                return new Variable("", VarType.LIST, newElements);
            }

            else if(a.type == VarType.LIST && b.type == VarType.LIST) {
                if(a.elements.Count != b.elements.Count)
                    throw new Exception("Trying to perform a binary operation on lists of unequal size.");

                List<Variable> newElements = new List<Variable>(a.elements.Count);
                for(int i=0; i<a.elements.Count; i++)
                    newElements.Add(ApplyBinaryFunction(a.elements[i], b.elements[i], action));
                return new Variable("", VarType.LIST, newElements);
            }

            throw new Exception("Trying to perform an operation on invalid types.");
        }
Пример #4
0
        private Variable ApplyUnaryFunction(Variable v, UnaryFunction action)
        {
            if(v.type == VarType.NUMBER)
                return new Variable(v.id, v.type, action(v.val));
            else if(v.type == VarType.LIST) {
                List<Variable> newElements = new List<Variable>(v.elements.Count);
                foreach(Variable e in v.elements)
                    newElements.Add(ApplyUnaryFunction(e, action));
                return new Variable(v.id, v.type, newElements);
            }

            throw new Exception("Trying to perform an operation on invalid type.");
        }
Пример #5
0
        protected Variable ExecuteExpression()
        {
            Stack<Variable> expr = new Stack<Variable>();
            Stack<Operator> ops = new Stack<Operator>();

            Token t = null;
            while(tokens.Count > 0 && tokens.Peek().type != TokenType.END) {
                t = tokens.Peek();
                Kerbulator.DebugLine("Token: "+ Enum.GetName(typeof(TokenType), t.type) +": "+ t.val);

                if(t.type == TokenType.BRACE) {
                    // Determine whether it's a left or right brace
                    bool isLeft = false;

                    switch(t.val) {
                        case "(":
                        case "{":
                        case "⌊":
                        case "⌈":
                            isLeft = true;
                            break;
                        case "|":
                            isLeft = !PossiblyValidExpression(expr, ops);

                            if(isLeft)
                                Kerbulator.DebugLine("| is left brace");
                            else {
                                Kerbulator.DebugLine("| is right brace");
                            }
                            break;
                    }

                    // If it's a left brace, start a sub-expression
                    if(isLeft) {
                        Consume();

                        // Execute sub-expression
                        Kerbulator.DebugLine("Starting subexpression");
                        Variable subexpr = ExecuteExpression();
                        Kerbulator.DebugLine("Answer of subexpression: "+ subexpr.ToString());
                        expr.Push(subexpr);

                        // Consume right brace. Execute operation if any
                        switch(t.val) {
                            case "(":
                                Consume(")");
                                break;
                            case "{":
                                Consume("}");
                                break;
                            case "⌊":
                                Consume("⌋");
                                ops.Push(operators[t.val]);
                                break;
                            case "⌈":
                                Consume("⌉");
                                ops.Push(operators[t.val]);
                                break;
                            case "|":
                                Consume("|");
                                ops.Push(operators[t.val]);
                                break;
                        }
                    } else {
                        // It's a right brace, just end the sub-expression
                        break;
                    }
                }

                else if(t.type == TokenType.NUMBER) {
                    expr.Push( new Variable(VarType.NUMBER, Double.Parse(t.val, System.Globalization.CultureInfo.InvariantCulture)) );
                    Consume();
                }

                else if(t.type == TokenType.OPERATOR) {
                    Operator op = operators[t.val];

                    // Handle ambiguous cases of arity
                    if(op.arity == Arity.BOTH) {
                        if(PossiblyValidExpression(expr, ops) ) {
                            op = new Operator(op.id, op.precidence, Arity.BINARY);
                            Kerbulator.DebugLine(op.id +" is binary.");
                        } else {
                            op = new Operator(op.id, 3, Arity.UNARY);
                            Kerbulator.DebugLine(op.id +" is unary.");
                        }
                    }

                    // Handle operators with higher precidence
                    while(ops.Count > 0) {
                        Operator prevOp = ops.Peek();
                        if(op.arity == Arity.BINARY && prevOp.precidence >= op.precidence) {
                            try {
                                expr.Push( ExecuteOperator(ops.Pop(), expr, ops) );
                            } catch(Exception e) {
                                throw new Exception(t.pos + e.Message);
                            }
                        } else
                            break;
                    }

                    ops.Push(op);
                    Consume();
                }

                else if(t.type == TokenType.IDENTIFIER) {
                    Variable var;

                    if(locals.ContainsKey(t.val))
                        var = locals[t.val];
                    else if(functions.ContainsKey(t.val))
                        var = new Variable(t.val, VarType.USER_FUNCTION, null);
                    else if(globals.ContainsKey(t.val))
                        var = globals[t.val];
                    else
                        throw new Exception(t.pos +"undefined variable or function: "+ t.val);

                    Consume();

                    if(var.type == VarType.FUNCTION || var.type == VarType.USER_FUNCTION) {
                        List<Variable> arguments = new List<Variable>();

                        // Check for argument list
                        if(tokens.Peek().val == "(") {
                            Consume();
                            Kerbulator.DebugLine("Arguments specified");
                            while(tokens.Peek().val != ")") {
                                Kerbulator.DebugLine("Starting subexpression");
                                Variable subexpr = ExecuteExpression();
                                Kerbulator.DebugLine("Answer of subexpression: "+ subexpr.ToString());
                                arguments.Add(subexpr);

                                if(tokens.Peek().val != ")")
                                    Consume(TokenType.COMMA);
                            }
                            Consume(")");

                            // Execute function right now with the given argument list
                            try {
                                Variable result = ExecuteFunction(var, arguments);
                                Kerbulator.DebugLine("Result of function: "+ result.ToString());
                                expr.Push(result);
                            } catch(Exception e) {
                                throw new Exception(e.Message +" (called from "+ t.func +", line "+ t.line +")");
                            }
                        } else {
                            int numArgs = 0;
                            if(var.type == VarType.FUNCTION)
                                numArgs = globals[t.val].numArgs;
                            else
                                numArgs = functions[t.val].Ins.Count;

                            if(numArgs == 0) {
                                // Function doesn't take arguments, execute right now with empty argument list
                                try {
                                    Variable result = ExecuteFunction(var, new List<Variable>());
                                    Kerbulator.DebugLine("Result of function: "+ result.ToString());
                                    expr.Push(result);
                                } catch(Exception e) {
                                    throw new Exception(e.Message +" (called from "+ t.func +", line "+ t.line +")");
                                }
                            } else {
                                // Push the execution of the function onto the stack
                                Kerbulator.DebugLine("No arguments specified");
                                expr.Push(var);
                                ops.Push(operators["func"]);
                            }
                        }
                    } else {
                        expr.Push(var);
                    }

                } else if(t.type == TokenType.LIST) {
                    if(t.val == "]")
                        break; // Right brace ends list

                    List<Variable> elements = new List<Variable>();
                    Consume();
                    while(tokens.Peek().val != "]") {
                        Kerbulator.DebugLine("Starting subexpression");
                        Variable subexpr = ExecuteExpression();
                        Kerbulator.DebugLine("Answer of subexpression: "+ subexpr.ToString());
                        elements.Add(subexpr);

                        if(tokens.Peek().val != "]")
                            Consume(TokenType.COMMA);
                    }
                    Consume("]");
                    expr.Push(new Variable("", VarType.LIST, elements));
                } else
                    break;
            }

            // Handle remaining ops
            while(ops.Count > 0) {
                Operator op = ops.Pop();
                try {
                    expr.Push( ExecuteOperator(op, expr, ops) );
                } catch(Exception e) {
                    if(t == null)
                        throw new Exception(e.Message);
                    else
                        throw new Exception(t.pos + e.Message);
                }
            }

            if(expr.Count > 1) {
                if(t == null)
                    throw new Exception("malformed expression");
                else
                    throw new Exception(t.pos + "malformed expression");
            }

            return expr.Pop();
        }
Пример #6
0
        public List<Variable> Execute(List<Variable> arguments, Dictionary<string, Operator> operators, Dictionary<string, Variable> globals, Dictionary<string, Function> functions)
        {
            List<Variable> result = new List<Variable>();
            Queue<Token> oldTokens = new Queue<Token>(tokens);

            try {
                this.InError = false;

                this.locals = new Dictionary<string, Variable>();
                this.operators = operators;
                this.globals = globals;
                this.functions = functions;

                if(ins.Count != arguments.Count)
                    throw new Exception("function "+ this.id +" takes "+ ins.Count +" arguments, but "+ arguments.Count +" were supplied");

                for(int i=0; i<ins.Count; i++)
                    locals.Add(ins[i], arguments[i].Copy(ins[i]));

                Variable lastVal = new Variable(VarType.NUMBER, 0.0);
                while(tokens.Count > 0) {
                    Variable val = ExecuteStatement();
                    if(val != null)
                        lastVal = val;
                    Consume(TokenType.END);
                }

                if(outs.Count > 0) {
                    foreach(string id in outs) {
                        if(!locals.ContainsKey(id))
                            throw new Exception("output variable "+ id +" is not defined in the code of function "+ this.id);
                        result.Add(locals[id]);
                    }
                } else
                    result.Add(lastVal);
            } catch(Exception e) {
                this.InError = true;
                this.ErrorString = e.Message;
            }

            tokens = oldTokens;
            return result;
        }
Пример #7
0
 public static void AddBool(Kerbulator kalc, string id, bool v)
 {
     double val = v ? 1.0 : 0.0;
     Variable g = new Variable(id, VarType.NUMBER, val);
     kalc.AddGlobal(g);
 }
Пример #8
0
        public static void AddVector3d(Kerbulator kalc, string id, Vector3d v)
        {
            Variable x = new Variable("x", VarType.NUMBER, v.x);
            Variable y = new Variable("y", VarType.NUMBER, v.y);
            Variable z = new Variable("z", VarType.NUMBER, v.z);

            List<Variable> elements = new List<Variable>(3);
            elements.Add(x);
            elements.Add(y);
            elements.Add(z);

            Variable g = new Variable(id, VarType.LIST, elements);
            kalc.AddGlobal(g);
        }
Пример #9
0
 public static void AddDouble(Kerbulator kalc, string id, double v)
 {
     Variable g = new Variable(id, VarType.NUMBER, v);
     kalc.AddGlobal(g);
 }