2016-09-30 6 views
-2

これは多少負荷のかかる質問です。Java:スタック式評価者:減算または掛け算時の空のスタック例外

(+ (- 6) (* 2 3 4) (/ (+ 3) (*) (- 2 3 1))) 

問題がある:私はとしては、例えば、入力式が書かれとるLispの評価アルゴリズムを書いて、それが原因で操作 のEmptyStackエラーがスローされます( - 6)と(*)

私は( - 0 6)と(* 1)と書くとき、正しい結果で正しくコンパイルします。私はそれがから何かを引くことを探していると思う何かを(何も数字を持つことはできません)を掛けてください。それは私のオペランド評価の構造と関係があります。私は手動で減算のためのゼロと乗算のために1つを追加することなく、プログラム自体にこれを実装したい。どのようにこれをやって行く上の任意のアイデア?

私は一日中それを見つめているので、私のプッシュ/ポップの構造がこのように機能する理由を理解できないようです。私は正規表現を試してみたが、それはそのトリックをしていないようだ。

プログラム構造:expressionStack Object型の、およびDouble型のcurrentOperationStack

1)は、2つのスタックを使用します。方法は、現在の動作を評価()

2)evaluateCurrentOperation:

  • ポップexpressionStackからオペランド及びそれがオペレータを見つけるまでcurrentOperationStackにそれらを押します。

  • currentOperationStackのオペランドの演算子を使用します。

  • 結果をexpressionStackにプッシュします。

3)を評価する()メソッドオペランドの現在のLisp読み取るようにスキャナを用いてinputExpressionにおける発現(およびcase文を評価し)、結果を返します。

import java.util.*; 

public class LispEvaluator { 

/** 
* Input expression 
*/ 
private String inputExp; 

/** 
* Stacks created for the main expression and current operation. 
*/ 
private Stack<Object> expStack; 
private Stack<Double> currentOpStack; 


/** 
* Default constructor initializes input and creates Stack objects. 
*/ 
public LispEvaluator() 
{ 
    inputExp = ""; 
    expStack = new Stack<Object>(); 
    currentOpStack = new Stack<Double>(); 
} 

/** 
* Constructor sets inputExpr to inputExpression and creates Stack objects. 
* @param inputExpression 
* @throws LispEvaluatorException 
*/ 
public LispEvaluator(String input_Expression) throws LispEvaluatorException 
{ 
    // If there is no expression, throws an exception. 
    if(input_Expression == null) 
    { 
     throw new LispEvaluatorException("Input statement is null."); 
    } 

    // Objects created 
    inputExp = input_Expression; 
    expStack = new Stack<Object>(); 
    currentOpStack = new Stack<Double>(); 
} 

/** 
* evaluateCurrentOperation() method evaluates the current operation: 
* - Pops operands from expStack and pushes them onto currentOpStack until it finds an operator. 
* - Uses the operator on the operands on currentOpStack. 
* - Pushes the result into exprStack. 
*/ 
private void evaluateCurrentOperation() 
{ 
    String current_Operation; 
    boolean numeric = true; 

    // Do... while statement sets current operation (while it is numeric). 
    do{ 
     current_Operation = (String.valueOf(expStack.pop())); 

     try{ 
      Double number = Double.parseDouble(current_Operation); 
      currentOpStack.push(number); 

     }catch(NumberFormatException nfe){ 
      numeric = false; 
     } 
    } while(numeric); 


    double result; 
    switch (current_Operation) { 
     case "*": 
      result = currentOpStack.pop(); 
      while(!currentOpStack.isEmpty()){ 
       result *= currentOpStack.pop(); 
      } 
      break; 
     case "/": 
      result = currentOpStack.pop(); 
      while(!currentOpStack.isEmpty()){ 
       result /= currentOpStack.pop(); 
      } 
      break; 
     case "+": 
      result = currentOpStack.pop(); 
      while(!currentOpStack.isEmpty()){ 
       result += currentOpStack.pop(); 
      } 
      break; 
     case "-": 
      result = currentOpStack.pop(); 
      while(!currentOpStack.isEmpty()){ 
       result -= currentOpStack.pop(); 
      } 

      break; 

     default: 
      result = currentOpStack.pop(); 
      break; 
    } 

    expStack.push(result); 

} 

/** 
* evaluate() method evaluates the current Lisp expression in inputExpr and returns the result. 
* @throws LispEvaluatorException 
*/ 
public double evaluate() throws LispEvaluatorException 
{ 
    Scanner inputExprScanner = new Scanner(inputExp); 

    /** 
    * Breaks the string into single characters using a delimiter. 
    */ 
    inputExprScanner = inputExprScanner.useDelimiter("\\s*"); 

    /** 
    * Scans the tokens in the string (runs while there is a next token). 
    */ 
    while (inputExprScanner.hasNext()) 
    { 

     /** 
     * If it has an operand, pushes operand object onto the exprStack. 
     */ 
     if (inputExprScanner.hasNextInt()) 
     { 
      /** 
      * Scanner gets all of the digits (regular expression \\d+ means any digit). 
      */ 
      String dataString = inputExprScanner.findInLine("\\d+"); 

      expStack.push(Double.parseDouble(dataString)); 
     } 

     else 
     { 
      /** 
      * Gets one character in String token. 
      */ 
      String token = inputExprScanner.next(); 
      char item = token.charAt(0); 

      switch(item) 
      { 
      // If "(", next token is an operator (so do nothing). 
      case '(': 
       break; 

      // If ")", it will evaluate that expression since parenthesis are closed. 
      case ')':     
       evaluateCurrentOperation(); 

       break; 

      // If there is an operator "* +/-", then it pushes the operator onto exprStack. 
      case'*': 
       expStack.push("*"); 
       break; 

      case'+': 
       expStack.push("+"); 
       break; 

      case'/': 
       expStack.push("/"); 
       break; 

      case'-': 
       expStack.push("-"); 
       break; 

      /** 
      * Default throws an error. 
      */ 
       default: 
        throw new LispEvaluatorException(item + " is not a valid operator"); 
      } // end switch 
     } // end else 
    } // end while 

    /** 
    * If you run out of tokens, the value on the top of exprStack is the result of the expression. 
    * 
    */ 

    return Double.parseDouble(String.valueOf(expStack.pop())); 
} 

/** 
* Reset method sets inputExpr to inputExpression and clears Stack objects. 
* @param inputExpression 
* @throws LispEvaluatorException 
*/ 
public void reset(String inputExpression) throws LispEvaluatorException 
{ 
    if(inputExpression == null) 
    { 
     throw new LispEvaluatorException("Input statement is null"); 
    } 

    inputExp = inputExpression; 
    expStack.clear(); 
    currentOpStack.clear(); 
} 

/** 
* Test method to print the result of the expression evaluator. 
* @param s 
* @param expr 
* @throws LispEvaluatorException 
*/ 
private static void evaluateExprTest(String s, LispEvaluator expr) throws LispEvaluatorException 
{ 
    Double result; 
    System.out.println("Expression: " + s); 
expr.reset(s); 
    result = expr.evaluate(); 
    System.out.printf("Result: %.2f\n", result); 
    System.out.println("-------"); 
} 

/** 
* Main method uses test cases to test the evaluator. 
* @param args 
* @throws LispEvaluatorException 
*/ 
public static void main (String args[]) throws LispEvaluatorException 
{ 
    LispEvaluator expr= new LispEvaluator(); 

    /** 
    * Expressions are tested. 
    * Note: For each operation written as (- 6), in order for the Stack to continue, 
    * it needs to be written as (- 0 6). This way, it is subtracting from a digit. 
    */ 
    String test1 = "(+ 5 0 10)"; 
    String test2 = "(+ 5 0 10 (- 7 2))"; 
    String test3 = "(+ (- 0 6) (* 2 3 4) (/ (+ 3) (* 1) (- 2 3 1)))"; 
    String test4 = "(+ (- 0 632) (* 21 3 4) (/ (+ 32) (* 1) (- 21 3 1)))"; 
    String test5 = "(+ 2 6) (* 12 18) (/ (+ 32) (* 1) (- 21 3 1))"; 
    String test6 = "(+ 1 2 (- 5 1) (*4 11 14))"; 

    evaluateExprTest(test1, expr); 
    evaluateExprTest(test2, expr); 
    evaluateExprTest(test3, expr); 
    evaluateExprTest(test4, expr); 
    evaluateExprTest(test5, expr); 
    evaluateExprTest(test6, expr); 

} 

} 

カスタム例外クラス:

public class LispEvaluatorException extends Exception{ 

    public LispEvaluatorException(String message) { 
     super(message); 

    } 
} 
+2

あなたは運と一日中それを見つめてきたが、あなたは私たちがさえなくて、それを解決したいです一見? – shmosel

+0

デバッグを試しましたか? – shmosel

+0

@dasblinkenlight私の間違いは、オリジナルにコードを含めることを意味します。すべてのコードがアップロードされました。 – pmcg521

答えて

0

修正は非常に簡単です:単項演算は明確な機能ですので、あなたが明示的に彼らのためにコーディングする必要があるので、あなたが取得するクラッシュがあります。別々のコードパスを有する単項マイナス-と単項分割/、チェックを入れる前に最初pop()

  • に空のスタックのチェックを追加

    • :この問題を修正

      は二つの部分から構成されています。ここで

    固定必要なコードの一部です:

    switch (current_Operation) { 
        case "*": 
         if (currentOpStack.isEmpty()) { 
          result = 1; 
          break; 
         } 
         result = currentOpStack.pop(); 
         while(!currentOpStack.isEmpty()){ 
          result *= currentOpStack.pop(); 
         } 
         break; 
        case "/": 
         if (currentOpStack.isEmpty()) { 
          result = 1; 
          break; 
         } 
         result = currentOpStack.pop(); 
         if (currentOpStack.isEmpty()) { 
          // Unary division 
          result = 1.0/result; 
          break; 
         } 
         while(!currentOpStack.isEmpty()){ 
          result /= currentOpStack.pop(); 
         } 
         break; 
        case "+": 
         if (currentOpStack.isEmpty()) { 
          result = 0; 
          break; 
         } 
         result = currentOpStack.pop(); 
         while(!currentOpStack.isEmpty()){ 
          result += currentOpStack.pop(); 
         } 
         break; 
        case "-": 
         if (currentOpStack.isEmpty()) { 
          result = 0; 
          break; 
         } 
         result = currentOpStack.pop(); 
         if (currentOpStack.isEmpty()) { 
          // Unary minus 
          result = -result; 
          break; 
         } 
         while(!currentOpStack.isEmpty()){ 
          result -= currentOpStack.pop(); 
         } 
         break; 
    
        default: 
         result = currentOpStack.pop(); 
         break; 
    } 
    

    Demo.

  • 関連する問題