Anda di halaman 1dari 23

Infix Expression Evaluation

Postfix expressions are easy to evaluate:


no subexpressions precedence among operators already accounted for

But this is not the case for infix expressions! e.g. 9 + (2 3) * 8 Two approaches to evaluate an infix expression: Use two stacks within one scan. Convert to equivalent postfix expression and then call the infix expression evaluator.

Infix Expression Attributes


Left associative: +, -, /, % Right associative: ^ 2^7^6 + (3 2 * 4) % 5

2^(7^6) + ((3 (2 * 4)) % 5)

Decreasing order of precedence: () > ^ > * = % = / > + =

Rank of Expression
Binary operators only. Evaluates an infix expression based on rank. 1 for any operand -1 for +, -, *, /, %, ^ 0 for (, ) Cumulative rank: sum of the ranks of individual terms.
cumulative 101010010101101 rank: 2^7^6+(3 2*4)%5

Cumulative rank for the entire expression is always 1.


(exactly one more operand than operator) Invalid expression if c.r. 1 (e.g. 2 4 + 3)

Infix-to-Postfix Conversion
During the scan of an expression:
An operand is immediately written to the output string. No need to maintain an operand stack.

Operator stack
Stores operators and left-parenthesis symbols as soon as they appear. Manages the order of precedence and associativity of operators. Handles subexpressions.

Example 1
The stack temporally stores operators awaiting their right-hand-side operand. a+b*c
* has higher priority than + add to the stack Operator Stack:

* + a b c * +

Postfix string:

Example 2
Use the stack to handle operators with same or lower precedence. a*b /c+d
* has the same priority as / pop * and write it to the postfix string before adding / to the stack. / has higher priority than +

Operator Stack:

+ * / a b * c / d +

Postfix string:

Example 3
Use precedence values to handle ^ (right associative). input precedence 4 when ^ is the input. stack precedence 3 when ^ resides on the stack. a^b^c
2nd ^ has precedence 4 but 1st ^ has only 3 2nd ^ goes to operator stack (so it will be popped before 1st ^)

Operator Stack:

^ ^ a b c ^

Postfix string:

Example 4
Two precedence values for left parenthese ( : input precedence 5 which is higher than that of any operator.
(all operators on the stack must remain because a new subexpression begins.)

stack precedence

-1 which is lower than that of any opeartor.


( has precedence 5 it goes to the operator stack. ( now has precedence -1 it stays on the operator stack.

(no operator in the subexpression may remove ( until ) shows up.)

a*(b+c)

Operator Stack: Postfix string:

+ ( * a b c +

Input and Stack Precedence


Symbol Input Precedence Stack Precedence Rank

+ * / % ^ ( )

1 2 4 5 0

1 2 3 -1 0

-1 -1 -1 0 0

Rules for Evaluation


Check the cumulative rank after each symbol (must be in the range from 0 to 1). Write the input to the postfix string if it is an operand. Upon input of an operator or a (, compare its precedence with the stack precedence of the top operator on the stack. Pop the top if the stack precedence is higher or equal, and write it to the postfix string. Repeat until the top operator has a lower rank, push the input onto the stack. If the input is ), pop all operators from the stack until ( and write them to the postfix string. Pop (. At the end of the infix expression, pop all remaining operators from the stack and write them to the postfix string.

An Example
3 * (4 2 ^ 5) + 6
Operator stack postfix

* [2] 3 3 ^ [3] - [1] ( [-1] * [2] 342

( [-1] * [2] 3 ^ [3] - [1] ( [-1] * [2] 3425

( [-1] * [2] 34

- [1] ( [-1] * [2] 34

- [1] ( [-1] * [2] 342

( [-1] * [2] 3425^-

contd
Pop ( * [2] 3425^3 * (4 2 ^ 5) + 6 + [1] 3425^-* + [1] 3425^-*6

3425^-*6+

Class for the Symbols


Encapsulate each symbol along with the associated input and output precedence. class expressionSymbol
{ public: expressionSymbol(); // default constructor expressionSymbol(char ch); // initializes the object for operator ch friend bool operator>= (const expressionSymbol& left, const expressionSymbol& right); // return true if stackPrecedence of left is // >= inputPrecedence of right. determines whether // operator left on the stack should be output before // pushing operator right on the stack char getOp() const; // return operator private: char op; // operator int inputPrecedence; // input precedence of op int stackPrecedence; // stack precedence of op };

Class for Conversion


The infix2Postfix class uses a stack to store expressionSymbol objects that correspond to operators.
const char lParen = '(', rParen = ')'; class infix2Postfix { public: infix2Postfix(); // default constructor. infix expression is NULL string infix2Postfix(const string& infixExp); // initialize the infix expression void setInfixExp(const string& infixExp); // change the infix expression string postfix(); // return a string that contains the equivalent postfix // expression. the function throws expressionError if an // error occurs during conversion

infix2Postfix contd
private: string infixExpression; // the infix expression to convert string postfixExpression; // built to contain the postfix equivalent of infixExpression stack<expressionSymbol> operatorStack; // stack of expressionSymbol objects void outputHigherOrEqual(const expressionSymbol& op); // the expressionSymbol object op holds the current // symbol. pop the stack and output as long as the symbol // on the top of the stack has a precedence >= that of // the current operator bool isOperator(char ch) const; // is ch one of '+','-','*','/','%','^' };

Output Stack Symbols


Pop symbols on the stack with stack precedence input precendence of the new symbol.

void infix2Postfix::outputHigherOrEqual(const expressionSymbol& op) { expressionSymbol op2; while(!operatorStack.empty() && (op2 = operatorStack.top()) >= op) { operatorStack.pop(); postfixExpression += op2.getOp(); postfixExpression += ' '; } }

Function for Infix-to-Postfix Conversion


postfix() does the following:
Skips a whitespace character. Writes an operand to the postfix string. Calls outputHigherOrEqual() with an operator. Also calls outputHigherOrEqual() when the input is ). Terminates at the end of the expression or if an error occurs. Declarations:
expressionSymbol op; // maintain rank for error checking int rank = 0, i; char ch;

Processing an Operand
// process until end of the expression for (i=0; i < infixExpression.length(); i++) { ch = infixExpression[i]; // ******** process an operand ******** // an operand is a single digit non-negative integer if (isdigit(ch)) { // just add operand to output expression, followed by // a blank postfixExpression += ch; postfixExpression += ' '; // rank of an operand is 1, accumulated rank // must be 1 rank++; if (rank > 1) throw expressionError("infix2Postfix: Operator expected"); }

Processing an Operator
// ********* process an operator or '(' ********** else if (isOperator(ch) || ch == '(') { // rank of an operator is -1. rank of '(' is 0. // accumulated rank should be 0 if (ch != '(') rank--; if (rank < 0) throw expressionError("infix2Postfix: Operand expected"); else { // output the operators on the stack with higher // or equal precedence. push the current operator // on the stack op = expressionSymbol(ch); outputHigherOrEqual(op); operatorStack.push(op); } }

Processing a Right Parenthesis


else if (ch == rParen) { // build an expressionSymbol object holding ')', which // has precedence lower than the stack precedence // of any operator except '('. pop the operator stack // and output operators from the subexpression until // '(' surfaces or the stack is empty. if the stack is // empty, a '(' is missing; otherwise, pop off '('. op = expressionSymbol(ch); outputHigherOrEqual(op); if (operatorStack.empty()) throw expressionError("infix2Postfix: Missing '('"); else operatorStack.pop(); // get rid of '(' } // ********* make sure ch is whitespace ********** else if (!isspace(ch)) throw expressionError("infix2Postfix: Invalid input"); }

Finish Processing
// outside the for loop if (rank != 1) throw expressionError("infix2Postfix: Operand expected"); else { // flush operator stack and complete expression evaluation. // if find left parenthesis, a right parenthesis is missing while (!operatorStack.empty()) { op = operatorStack.top(); operatorStack.pop(); if (op.getOp() == lParen) throw expressionError("infix2Postfix: Missing ')'"); else { postfixExpression += op.getOp(); postfixExpression += ' '; } } } return postfixExpression; }

Evaluating an Infix Expression


void main() { // use iexp for infix to postfix conversion infix2Postfix iexp; // infix expression input and postfix expression output string infixExp, postfixExp; // use pexp to evaluate postfix expressions postfixEval pexp; // input and evaluate infix expressions until the // user enters an empty string // get the first expression cout << "Enter an infix expression: "; getline(cin, infixExp); while (infixExp != "") { // an exception may occur. enclose the conversion // to postfix and the output of the expression // value in a try block

try { // convert to postfix iexp.setInfixExp(infixExp); postfixExp = iexp.postfix(); // output the postfix expression cout << "The postfix form is " << postfixExp << endl; // use pexp to evaluate the postfix expression pexp.setPostfixExp(postfixExp); cout << "Value of the expression = " << pexp.evaluate() << endl << endl; } // catch an exception and output the error catch (const expressionError& ee) { cout << ee.what() << endl << endl; } // input another expression cout << "Enter an infix expression: "; getline(cin, infixExp); } }

Anda mungkin juga menyukai