在堆栈中捕获错误

时间:2017-04-15 06:30:24

标签: data-structures error-handling stack

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import static java.lang.Math.pow;



public class InfixExpressionEvaluator {
// Tokenizer to break up our input into tokens
StreamTokenizer tokenizer;

// Stacks for operators (for converting to postfix) and operands (for
// evaluating)
StackInterface<Character> operatorStack;
StackInterface<Double> operandStack;

//counts brackets
int Bracket1=0, Bracket2=0, count = 0;

/**
 * Initializes the evaluator to read an infix expression from an input
 * stream.
 * @param input the input stream from which to read the expression
 */
public InfixExpressionEvaluator(InputStream input) {
    // Initialize the tokenizer to read from the given InputStream
    tokenizer = new StreamTokenizer(new BufferedReader(
                    new InputStreamReader(input)));

    // StreamTokenizer likes to consider - and / to have special 
meaning.
    // Tell it that these are regular characters, so that they can be 
parsed
    // as operators
    tokenizer.ordinaryChar('-');
    tokenizer.ordinaryChar('/');

    // Allow the tokenizer to recognize end-of-line, which marks the 
end of
    // the expression
    tokenizer.eolIsSignificant(true);

    // Initialize the stacks
    operatorStack = new ArrayStack<Character>();
    operandStack = new ArrayStack<Double>();
}

/**
 * Parses and evaluates the expression read from the provided input 
stream,
 * then returns the resulting value
 * @return the value of the infix expression that was parsed
 */
public Double evaluate() throws ExpressionError {
    // Get the first token. If an IO exception occurs, replace it with 
a
    // runtime exception, causing an immediate crash.
    try {
        tokenizer.nextToken();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    boolean preNum = false, preOp = false;
    boolean preOpenbracket = false, preClosebracket = false;
    int Bracket1 = 0, Bracket2 = 0, count = 0;

    // Continue processing tokens until we find end-of-line
    while (tokenizer.ttype != StreamTokenizer.TT_EOL) {
        // Consider possible token type
        switch (tokenizer.ttype) {
            case StreamTokenizer.TT_NUMBER:
                // Expression error handling
                if ((preNum == true) && (count > 0)) {
                    throw new ExpressionError("Two operands in a row");
                }
                if ((preClosebracket == true) && (count > 0)) {
                    throw new ExpressionError("A close bracket cannot 
be followed by a number");
                }

                // If the token is a number, process it as a double-
valued
                // operand
                processOperand((double) tokenizer.nval);
                preOp = false;
                preNum = true;
                preOpenbracket = false;
                preClosebracket = false;
               break;
            case '+':
            case '-':
            case '*':
            case '/':
            case '^':
                // check for errror in input
                if (count == 0) {
                    throw new ExpressionError("Leading off with 
 operator is illegal");
                }
                if ((preOp == true) && (count > 0)) {
                    throw new ExpressionError("Two operators in a 
row");
                }
                if ((preOpenbracket == true) && (count > 0)) {
                    throw new ExpressionError("An open bracket cannot 
be followed by an operator");
                }

                // If the token is any of the above characters, process 
  it
                // is an operator
                processOperator((char) tokenizer.ttype);
                preOp = true;
                preNum = false;
                preOpenbracket = false;
                preClosebracket = false;
                break;
            case '(':
            case '[':
                // Expression error handling
                if ((preNum == true) && (count > 0)) {
                    throw new ExpressionError("An open bracket cannot 
be preceded by a number");
                }
                // If the token is open bracket, process it as such. 
Forms
                // of bracket are interchangeable but must nest 
properly.
                processOpenBracket((char) tokenizer.ttype);

                preOp = false;
                preNum = false;
                preOpenbracket = true;
                preClosebracket = false;
                Bracket1++;
                break;
            case ')':
            case ']':
                 // Expression error handling
                if ((preOp == true) && (count > 0)) {
                    throw new ExpressionError("A close bracket cannot 
 be preceded by a operator");
                }

                // If the token is close bracket, process it as such. 
Forms
                // of bracket are interchangeable but must nest 
properly.
                processCloseBracket((char) tokenizer.ttype);

                preOp = false;
                preNum = false;
                preOpenbracket = false;
                preClosebracket = true;
                Bracket2++;
                break;
            case StreamTokenizer.TT_WORD:
                // If the token is a "word", throw an expression error
                throw new ExpressionError("Unrecognized token: "
                        + tokenizer.sval);
            default:
                // If the token is any other type or value, throw an
                // expression error
                throw new ExpressionError("Unrecognized token: "
                        + String.valueOf((char) tokenizer.ttype));
        }
        count++;

        // Read the next token, again converting any potential IO 
exception
        try {
            tokenizer.nextToken();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // Almost done now, but we may have to process remaining operators 
  in
    // the operators stack
    processRemainingOperators();

    if (Bracket1 != Bracket2) {
        throw new ExpressionError("\nNot the same number of bracket");
    }

    // Return the result of the evaluation - 
    return operandStack.pop();
}


void processOperand(double operand) {
//push operand
    operandStack.push(operand);
}


void processOperator(char operator) {
    // Precedence order: ^*/ level 2, +- level 1, ( and [ has lowest 
level 0
    while (!operatorStack.isEmpty() && hasPrecedence(operator, 
operatorStack.peek())) {

        // perform step 1a,1b,1c,1d
        operandStack.push(applyOp(operatorStack.pop(), 
operandStack.pop(), operandStack.pop()));
    }
    // Step 2: thisOp has more precedence than one on top of 
operatorStack, push it
    operatorStack.push(operator);
}

// Returns true if 'op2' has higher or same precedence as 'op1',
// otherwise returns false.
public static boolean hasPrecedence(char op1, char op2)
{
    if (op2 == '(' || op2 == ')' || op2 == '[' || op2 == ']')
        return false;
    if ((op1 == '*' || op1 == '/' || op1 == '^') && (op2 == '+' || op2 
== '-'))
        return false;
    else
        return true;
}

void processOpenBracket(char openBracket) {
    operatorStack.push(openBracket);
}


void processCloseBracket(char closeBracket) {
    //Declare variables
    char operator='0';
    double a=0, b=0, c=0;
    boolean correct = true;

    //check for error before loop
    if (operatorStack.isEmpty()) {
        throw new ExpressionError("Brackets/parenthasis are uneven");
    } 
    if (operatorStack.peek()== '(' || operatorStack.peek()=='[') {
        throw new ExpressionError("There was an empty set of brackets 
 or unneeded use of brackets");
    }
    if (operandStack.isEmpty()) {
        throw new ExpressionError("Too many operators");
    }

    //loop through stacks and pop off operators and operands
    while (correct) {
        operator = operatorStack.pop();
        b = operandStack.pop();
        a = operandStack.pop();

        //check  to see if next one is bracket
        if (operatorStack.peek() == '(' || operatorStack.peek() == '[') 
 { 
            correct = false;
        }
    } 

    //check for errors
    if (closeBracket == ')' && !operatorStack.isEmpty() && 
operatorStack.peek() != '(') {
        throw new ExpressionError("Parenthesis do not match");
    }
    if (closeBracket == ']' && !operatorStack.isEmpty() && 
operatorStack.peek() != '[') {
        throw new ExpressionError("Brackets do not match");
    }

    //calculate result and push it onto the stack, pop off bracket
    c = applyOp(operator, b, a);
    operandStack.push(c);
    operatorStack.pop();
}

public static double applyOp(char op, double b, double a)
{
    switch (op) {
        case '+':
            return a + b;
        case '-':
            return a - b;
        case '*':
            return a * b;
        case '^':
            return pow(a,b);
        case '/':
        //check for division by zero
        if (b == 0)
            throw new ExpressionError("No division by zero");
        return a / b;
    }
    return 0;
 }

 /**
 * This method is called when the evaluator encounters the end of an
 * expression. It manipulates operatorStack and/or operandStack to 
 process
 * the operators that remain on the stack, according to the Infix-to-
 Postfix
 * and Postfix-evaluation algorithms.
 */
void processRemainingOperators() {
    //error check
    double a;
    if (!operatorStack.isEmpty()) {
        if (operatorStack.peek()=='(' || operatorStack.peek()=='[') {
            throw new ExpressionError("Uneven number of parenthesis");
        }

        //check for expression ending with operator
        a=operandStack.pop();
        if (operandStack.isEmpty()) {
            throw new ExpressionError("You can not end with an 
operator");
        }
        operandStack.push(a);

    }

    //process the remaining operators and answer is placed in the stack 
alone
    while (!operatorStack.isEmpty()) {
        operandStack.push(applyOp(operatorStack.pop(), 
operandStack.pop(), operandStack.pop()));
    }
}


/**
 * Creates an InfixExpressionEvaluator object to read from System.in, 
then
 * evaluates its input and prints the result.
 * @param args not used
 */
public static void main(String[] args) {
    System.out.println("\nInfix expression:");
    InfixExpressionEvaluator evaluator =
                    new InfixExpressionEvaluator(System.in);
    Double value = null;
    try {
        value = evaluator.evaluate();
    } catch (ExpressionError e) {
        System.out.println("ExpressionError: " + e.getMessage());
    }
    if (value != null) {
        System.out.println(value);
    } else {
        System.out.println("Evaluator returned null");
    }
}

}

因此,对于这个程序,我们应该使用工具两个堆栈来进行简单的算术运算。如果输入正确,程序可以正常工作,但是当我尝试执行错误捕获时,它无法正常工作。我尝试使用计数器变量来计算括号数,括号,但它没有用。以下是一些不起作用的案例:

2^(2+3*4)

2*14.5+6/5-(5*8-5/9)

10000 * [1+.20/12]^(12*4)

(4+3*2    (error catch here. program should report error because there 
is no closed parenthesis)

以及更多......任何想法?

0 个答案:

没有答案