예제 #1
0
        private Variable ExecuteOperator(Operator op, Stack<Variable> expr, Stack<Operator> ops)
        {
            Kerbulator.DebugLine("executing: "+ op.id);
            if(op.arity == Arity.BINARY && expr.Count < 2)
                throw new Exception("operator "+ op.id +" needs a number or expression on both the left and the right hand side");
            else if(op.arity == Arity.UNARY && expr.Count < 1)
                throw new Exception("operator "+ op.id +" needs a number or expression on the right hand side");
            else if(op.arity == Arity.BOTH)
                throw new Exception("arity of "+ op.id +" still undefined");

            Variable a,b;

            switch(op.id) {
                case "+":
                    b = expr.Pop(); a = expr.Pop();
                    return ApplyBinaryFunction(a, b, delegate(double c, double d) { return c + d; });

                case "-":
                    b = expr.Pop();
                    if(op.arity == Arity.UNARY)
                        return new Variable(VarType.NUMBER, -b.val);
                    else {
                        a = expr.Pop();
                        return new Variable(VarType.NUMBER, a.val - b.val);
                    }

                case "*":
                case "·":
                case "×":
                    b = expr.Pop(); a = expr.Pop();
                    return new Variable(VarType.NUMBER, a.val * b.val);

                case "/":
                case "÷":
                    b = expr.Pop(); a = expr.Pop();
                    return new Variable(VarType.NUMBER, a.val / b.val);

                case "%":
                    b = expr.Pop(); a = expr.Pop();
                    return new Variable(VarType.NUMBER, a.val % b.val);

                case "^":
                    b = expr.Pop(); a = expr.Pop();
                    return new Variable(VarType.NUMBER, Math.Pow(a.val, b.val));

                case "√":
                    b = expr.Pop();
                    if(op.arity == Arity.UNARY)
                        return new Variable(VarType.NUMBER, Math.Sqrt(b.val));
                    else {
                        a = expr.Pop();
                        return new Variable(VarType.NUMBER, Math.Pow(a.val, 1/b.val));
                    }

                case "⌊":
                    return new Variable(VarType.NUMBER, Math.Floor(expr.Pop().val));

                case "⌈":
                    return new Variable(VarType.NUMBER, Math.Ceiling(expr.Pop().val));

                case "|":
                    return new Variable(VarType.NUMBER, Math.Abs(expr.Pop().val));

                case "func":
                    b = expr.Pop();

                    Variable func = expr.Pop();
                    List<Variable> arguments = new List<Variable>();
                    arguments.Add(b);

                    return ExecuteFunction(func, arguments);

                default:
                    throw new Exception("Unknown operator: "+ op.id);
            }
        }
예제 #2
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();
        }