2013-10-22 52 views
-1

我正在java中製作一個lisp表達式求值器。在我的輸出窗口中(見下文),我在主要方法中收到多個錯誤。任何人都可以解釋爲什麼這些錯誤發生?lisp表達式求值器主要例外

evaluateCurrentOperation調用Double.valueOf並給它一個字符串。它給它一個字符串「+」,這對於一個雙精度格式來說沒有正確的格式。我該如何解決?

OUTPUT窗口:

[ 

(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) 

] 

CODE:

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); 
    } 
} 
+0

請保留您的問題完好無損。 – Svante

回答

1

要調用

Double.valueOf(x) 

當x是字符串 「+」,這意味着你的號碼和運營商越來越混不知何故。

我懷疑問題出在你解析字符串並找到paren的地方。不知何故,下一組開關盒似乎是錯誤的。它不對稱。如果它找到了一個加號,則會推動字符串的其餘部分。如果它減一或開始推動單個字符。

0

你目前的實現是一個糾纏不清的解析和評估。

如果您通過清晰地分離步驟(在經典的Lisp實現策略中,這將是函數readeval)來解決這個問題,那麼對於您的具體問題的修復應該自然遵循。