-1

我正在用 java 制作一个 lisp 表达式求值器。在我的输出窗口(见下文)中,我的主要方法中收到多个错误。谁能解释为什么会发生这些错误?

evaluateCurrentOperation调用Double.valueOf并给它一个字符串。它给它一个字符串“+”,它的双精度格式不正确。我该如何解决?

输出窗口:

[

(java.lang.NumberFormatException: For input string: "+"
  at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1222)
  at java.lang.Double.valueOf(Double.java:475)
  at SimpleLispExpressionEvaluator.evaluateCurrentOperation(SimpleLispExpressionEvaluator.java:63)
  at SimpleLispExpressionEvaluator.evaluate(SimpleLispExpressionEvaluator.java:242)
  at SimpleLispExpressionEvaluator.evaluateExprTest(SimpleLispExpressionEvaluator.java:269)
  at SimpleLispExpressionEvaluator.main(SimpleLispExpressionEvaluator.java:283)

]

代码:

import java.util.*;

public class SimpleLispExpressionEvaluator {
    // Current input Lisp expression
    private String inputExpr;

    // Main expression stack & current operation stack, see algorithm in
    // evaluate()
    private Stack<Object> exprStack;
    private Stack<Double> currentOpStack;

    // default constructor
    // set inputExpr to ""
    // create stack objects
    public SimpleLispExpressionEvaluator() {
        // add statements
        inputExpr = "";
        exprStack = new Stack<Object>();
        currentOpStack = new Stack<Double>();

    }

    // default constructor
    // set inputExpr to inputExpression
    // create stack objects
    public SimpleLispExpressionEvaluator(String inputExpression) {
        // add statements
        inputExpr = inputExpression;
        exprStack = new Stack<Object>();
        currentOpStack = new Stack<Double>();

    }


    // set inputExpr to inputExpression
    // clear stack objects
    public void reset(String inputExpression) {
        // add statements
        inputExpr = inputExpression;
        exprStack.clear();
        currentOpStack.clear();
    }

    // This function evaluate current operator with its operands
    // See complete algorithm in evaluate()
    //
    // Main Steps:
    // Pop operands from exprStack and push them onto
    // currentOpStack until you find an operator
    // Apply the operator to the operands on currentOpStack
    // Push the result into exprStack
    //
    private void evaluateCurrentOperation() {

        // add statements
        char thing = '0';
        double result = 0;

        do {

            Object obj = exprStack.pop();
            String a = obj.toString();
            double b = Double.valueOf(a).doubleValue();

            currentOpStack.push(b);

            String grab = exprStack.peek().toString();

            if (grab.length() > 1) {
                continue;
            }

            else {
                thing = grab.charAt(0);
            }

            if (thing == '+' || thing == '-' || thing == '/' || thing == '*') {
                exprStack.pop();
                break;
            }
        } while (thing != '%');

        switch (thing) {
        case '+':

            while (currentOpStack.isEmpty() != true) {
                result += (double) currentOpStack.pop();
            }
            break;

        case '-':

            Object obj0 = currentOpStack.pop();
            String a0 = obj0.toString();
            double b0 = Double.valueOf(a0).doubleValue();

            if (currentOpStack.isEmpty() != true) {
                result = b0;
            } else {
                result = -(b0);
            }

            while (currentOpStack.isEmpty() != true) {
                result -= (double) currentOpStack.pop();
            }
            break;

        case '/':

            if (currentOpStack.size() == 1) {
                if (currentOpStack.peek() == 0) {
                    throw new RuntimeException("Cannot divide by zero");
                }
                result = (1 / ((double) currentOpStack.pop()));
                break;
            } else {
                Object obj1 = currentOpStack.pop();
                String a1 = obj1.toString();
                double b1 = Double.valueOf(a1).doubleValue();

                if (currentOpStack.isEmpty() != true) {
                    result = b1;
                } else {
                    result = -(b1);
                }

                while (currentOpStack.isEmpty() != true) {
                    result -= (double) currentOpStack.pop();
                }
                break;
            }
        case '*':
            Object obj2 = currentOpStack.pop();
            String a2 = obj2.toString();
            double b2 = Double.valueOf(a2).doubleValue();

            result = b2;

            while (currentOpStack.isEmpty() != true) {
                result *= (double) currentOpStack.pop();
            }
            break;
        default:

            throw new IndexOutOfBoundsException(
                    "The next node does not work in this program");

        }

        exprStack.push(result);

    }

    /**
     * This function evaluates current Lisp expression in inputExpr It return
     * result of the expression
     * 
     * The algorithm:
     * 
     * Step 1 Scan the tokens in the string. Step 2 If you see an operand, push
     * operand object onto the exprStack Step 3 If you see "(", next token
     * should be an operator Step 4 If you see an operator, push operator object
     * onto the exprStack Step 5 If you see ")",
     * 
     * do steps 6,7,8 in evaluateCurrentOperation() : Step 6 Pop operands and
     * push them onto currentOpStack until you find an operator Step 7 Apply the
     * operator to the operands on currentOpStack Step 8 Push the result into
     * exprStack Step 9 If you run out of tokens, the value on the top of
     * exprStack is is the result of the expression.
     */
    public double evaluate() {
        // only outline is given...
        // you need to add statements/local variables
        // you may delete or modify any statements in this method
        double result;
        // use scanner to tokenize inputExpr
        Scanner inputExprScanner = new Scanner(inputExpr);

        // Use zero or more white space as delimiter,
        // which breaks the string into single character tokens
        inputExprScanner = inputExprScanner.useDelimiter("\\s*");

        // Step 1: Scan the tokens in the string.
        while (inputExprScanner.hasNext()) {

            // Step 2: If you see an operand, push operand object onto the
            // exprStack
            if (inputExprScanner.hasNextInt()) {
                // This force scanner to grab all of the digits
                // Otherwise, it will just get one char
                String dataString = inputExprScanner.findInLine("\\d+");

                exprStack.push(dataString);
                // more ...
            }

            else {
                // Get next token, only one char in string token
                String nextEntry = inputExprScanner.next();
                char entity = nextEntry.charAt(0);
                String nextToken;

                switch (entity) {
                // Step 3: If you see "(", next token should an operator
                case '(':
                    nextEntry = inputExprScanner.next();
                    entity = nextEntry.charAt(0);
                    // Step 4: If you see an operator, push operator object onto
                    // the
                    // exprStack
                    if (entity == '+') {
                        exprStack.push(nextEntry);
                    }

                    else if (entity == '-') {
                        exprStack.push(entity);
                    }

                    else if (entity == '*') {
                        exprStack.push(entity);
                    }

                    else {
                        exprStack.push(nextEntry);
                    }

                    // Step 5: If you see ")" do steps 6,7,8 in
                    // evaluateCurrentOperation() :

                case ')':

                    evaluateCurrentOperation();
                    break;

                default: // error
                    throw new SimpleLispExpressionEvaluatorException(entity
                            + " is not a legal expression operator");

                } // end switch
            } // end else
        } // end while

        // Step 9: If you run out of tokens, the value on the top of exprStack
        // is the result of the expression.
        Object obj4 = exprStack.pop();
        String str4 = obj4.toString();
        double d3 = Double.valueOf(str4).doubleValue();
        return d3;
    }

    // =====================================================================

    // This static method is used by main() only
    private static void evaluateExprTest(String s,
            SimpleLispExpressionEvaluator expr) {
        Double result;
        System.out.println("Expression " + s);
        expr.reset(s);
        result = expr.evaluate();
        System.out.printf("Result %.2f\n", result);
        System.out.println("-----------------------------");
    }

    // define few test cases, exception may happen
    public static void main(String args[]) {
        SimpleLispExpressionEvaluator expr = new SimpleLispExpressionEvaluator();
        String test1 = "(+ (- 6) (* 2 3 4) (/ (+ 3) (* 1) (- 2 3 1)))";
        String test2 = "(+ (- 632) (* 21 3 4) (/ (+ 32) (* 1) (- 21 3 1)))";
        String test3 = "(+ (/ 2) (* 2) (/ (+ 1) (+ 1) (- 2 1 )))";
        String test4 = "(+ (/2))";
        String test5 = "(+ (/2 3 0))";
        String test6 = "(+ (/ 2) (* 2) (/ (+ 1) (+ 3) (- 2 1 )))";
        evaluateExprTest(test1, expr);
        evaluateExprTest(test2, expr);
        evaluateExprTest(test3, expr);
        evaluateExprTest(test4, expr);
        evaluateExprTest(test5, expr);
        evaluateExprTest(test6, expr);
    }
}
4

2 回答 2

1

你在打电话

Double.valueOf(x)

当 x 是字符串“+”时,这表明您的数字和运算符以某种方式混淆了。

我怀疑问题出在您解析字符串并找到括号的部分。下一组 switch 案例在某种程度上似乎是错误的。它不是对称的。如果它找到一个加号,则推动字符串的其余部分。如果它是减号或开始,则按单个字符。

于 2013-10-22T23:06:24.790 回答
0

您当前的实现是一个纠缠不清的解析和评估。

如果你通过明确分离步骤来解决这个问题(在经典的 Lisp 实现策略中,这将是函数readeval),那么这里应该自然而然地解决你的具体问题。

于 2013-10-23T12:53:14.683 回答