300 likes | 442 Views
CSS342: Stacks and Compilers. Professor: Munehiro Fukuda. Topics. Basic concepts of stacks Stack implementation Applying to language processing Example 1: Balance-symbol checker Example 2: Algebraic expressions Calculator design (lab/home work). Basic Concepts. abcc ddde ef.
E N D
CSS342: Stacks and Compilers Professor: Munehiro Fukuda CSS342: Stacks and Compilers
Topics • Basic concepts of stacks • Stack implementation • Applying to language processing • Example 1: Balance-symbol checker • Example 2: Algebraic expressions • Calculator design (lab/home work) CSS342: Stacks and Compilers
Basic Concepts abcc ddde ef Concepts of Stack push pop • Stack of cafeteria dishes • Inherently unfair in day-by-day situations • Useful problem-solving techniques in Computer Science • Using a backspace key to correct typos • Checking for balanced braces push push push push a b c c pop a b c c push push push push a b c d d d e pop pop pop a b c d d d e push push a b c d e f CSS342: Stacks and Compilers
Basic Concepts Stack Specification template<class Object> class stack { public: stack(); bool empty() const; void push( const Object&newItem ); void pop( ); void pop( Object &stackTop ); // not in STL const Object top( ) const; } push to the top pop (): remove from the top a pop(stacktop): remove and get the top item c retrieve the top item but do not remove it c b a Axiom: (aStack.push(newItem)).pop() is equal to aStack CSS342: Stacks and Compilers
Basic Concepts STL Class stack CSS342: Stacks and Compilers
Basic Concepts STL Class stackExample #include <stack> #include <iostream> using namespace std; int main( ) { stack<int> aStack; int item; for ( int j = 0; j < 5; j++ ) aStack.push( j ); while ( !aStack.empty( ) ) { cout << aStack.top( ) << endl; aStack.pop( ); } } Results: 4 3 2 1 0 CSS342: Stacks and Compilers
Implementation Stack Implementation • Array-based implementation • Pointer-based implementation • Linked list reuse • Data member • Inheritance CSS342: Stacks and Compilers
Implementation An Array-Based Implementation k a b c ….. g ….. top 0 1 2 k (MAX_STACK-1) template <class Object> class stack { public: stack(); bool isEmpty( ) const; void push( const Object&newItem ); void pop( ); void pop( const Object &stackTop ); const Object top( ) const; private: vector<Object> theArray; //Object theArray[MAX_STACK–1]; in an ordinary array int top; } CSS342: Stacks and Compilers
Implementation k a b c ….. g ….. top 0 1 2 k theArray.Size( ) - 1 An Array-Based Implementation Stack( ) : top( -1), theArray( 1 ) { } push(const Object &newItem) pop(Object &topItem) if (top < 0) throw “empty stack”; else { topItem= theArray[top]; --top; } if (top == theArray.size( ) - 1) theArray.resize( theArray.size( ) * 2 + 1 ); item[++top] = newItem; CSS342: Stacks and Compilers
Implementation topPtr ……… NULL a b c g A Pointer-Based Implementation #include<iostream> template<class Object> class Stack { public: Stack( ) : topPtr( NULL ) { }; Stack( const Stack &rhs ); ~Stack( ) { flush( ); }; bool isEmpty( ) const; void push( const Object &newItem ); const Object top( ) const; void pop( ); void pop( Object &stackTop ); void flush( ); const Stack &operator=( const Stack &rhs ); private: struct StackNode { Object item; StackNode *next; }; StackNode *topPtr; }; #include "stackPointer.cpp" CSS342: Stacks and Compilers
Implementation topPtr ……… NULL a b c g A Pointer-Based Implementation Stack( ) : topPtr( NULL ) { }; template<class Object> void Stack<Object>::push( const Object &newItem ) { StackNode *newPtr = new StackNode; if ( newPtr == NULL ) throw "out of memory"; else { newPtr->item = newItem; newPtr->next = topPtr; topPtr = newPtr; } } template<class Object> bool Stack<Object>::isEmpty( ) const { return topPtr == NULL; } template<class Object> void Stack<Object>::flush( ) { while ( !isEmpty( ) ) pop( ); } template<class Object> const Object Stack<Object>::top( ) const { if ( isEmpty( ) ) throw "empty stack"; return topPtr->item; } template<class Object> void Stack<Object>::pop( ) { if ( isEmpty( ) ) throw "empty stack"; StackNode *oldTop = topPtr; topPtr = topPtr->next; delete oldTop; } template<class Object> void Stack<Object>::pop( Object &stackTop ) { stackTop = top( ); pop( ); } CSS342: Stacks and Compilers
Implementation stackTop stackTop 20 45 51 45 20 76 76 20 45 51 76 51 Copy Constructor • Stack( const Stack<Object>& rhs ) • Implicit calledupon passing, returning, and assigning an object. • Shallow copy: C++ copies an object’s data members. • Deep copy: Java copies all traversable pointer variables. NULL rhs. stackTop NULL Rhs. stackTop NULL CSS342: Stacks and Compilers
Implementation Deep Copy template<class Object> // copy constructor Stack<Object>::Stack( const Stack<Object> &rhs ) { topPtr = NULL; *this = rhs; } template<class Object> // operator = (deep copy) const Stack<Object> &Stack<Object>::operator=( const Stack<Object> &rhs ) { if ( this != &rhs ) { // why 1 flush( ); // why 2 if ( rhs.isEmpty( ) ) return *this; StackNode rptr = rhs.topPtr; StackNode ptr = new StackNode; ptr->item = rptr->item; topPtr = ptr; for ( StackNode rptr = rptr->next; rPtr != NULL; rPtr = rPtr->next ) { ptr->next = new StackNode; ptr->next->element = rptr->element; ptr = ptr->next; } return *this; } } rhs. topPtr 20 45 51 topPtr 20 45 Repeat! CSS342: Stacks and Compilers
Implementation Implementation by List Reuse • Why not reuse the Linked List class we studied? • Contain a linked list instance in our stack implementation stack.h stack.cpp #include <iostream> #include "llist.h“ template<class Object> class Stack { public: // the same as previous private: LList<Object> list; }; template<class Object> bool Stack<Object>::isEmpty( ) const { return list.isEmpty( ); } template<class Object> void Stack<Object>::push( const Object &newItem ) { list.insert( newItem, 0 ); // insert after 0th dummy } template<class Object> const Object Stack<Object>::top( ) const { return list.retrieve( 1 ); // retrieve 1st list item } CSS342: Stacks and Compilers
Implementation Implementation by List Reuse(code continued) template<class Object> void Stack<Object>::pop( ) { if ( list.size( ) > 0 ) list.remove( list.retrieve( 1 ) ); // remove the 1st item } template<class Object> void Stack<Object>::pop( Object &stackTop ) { if ( list.size( ) > 0 ) list.remove( ( stackTop = list.retrieve( 1 ) ) ); } template<class Object> void Stack<Object>::flush( ) { return list.clear( ); } template<class Object> const Stack<Object>& Stack<Object>::operator=( const Stack &rhs ) { list = rhs.list; // just reuse list’s operator=! } CSS342: Stacks and Compilers
Implementation Comparing Implementations • The Array-Based Stack • Pros. Easy implementation • Cons. • Fixed size (if we use a fixed array) • Capacity or stack duplication overhead (if we use a dynamic array like vector) • Good for small objects • The Pointer-Based Stack. • Pros. Dynamic size (not wasting space) • Cons.Necessity to take care of pointers • Good for large objects • Reuse of Linked List. • Pros. • Easy Implementation • All advantages inherent to pointer-based stack. • Cons. May be a bit slower. So which is the best? CSS342: Stacks and Compilers
Example 1 Example 1: Balanced-Symbol Checker abc{defg(ijk)(l[mn])op}qr abc{def})(ghij[kl]m) 1.push 2.push 3.pop 1.push 2.pop • Check if stack is empty in prior to a pop • Check if stack is empty at the end of string 4.push 3.pop 5.push 6.pop 7.pop 8.pop 1. { 2. {( 3. { 4. {( 5. {([ 6. {( 7. { 1. { 2. 3. empty!! abc{(def) ghijklm 1.push 3.pop 2.push 1. { 2. {( 3. { Stack is not empty!! CSS342: Stacks and Compilers
Example 1 Balanced-Symbol Checker Simplified code of textbook p411 - 419 It does not care about comments nor prints out detailed error messages. char getNextSymbol( ) {// gets the next ( ) [ ] { and } char ch; do { if ( !cin.get( ch ) ) return '\0'; // EOF } while ( ch != '(' && ch != ')' && ch != '[' && ch != ']' && ch != '{' && ch != '}' ); return ch; } bool checkMatch( const char &openSym, const char &closeSym ) { // check if openSym nad closeSym matches each other if ( openSym == '(' && closeSym != ')' || openSym == '[' && closeSym != ']' || openSym == '{' && closeSym != '}' ) { cout << "Found " << closeSym << "; does not match " << openSym << endl; return false; } return true; } CSS342: Stacks and Compilers
Example 1 Balanced-Symbol Checker(code continued) bool checkBalance( ) { char ch, match; int errors = 0; stack<char> pendingTokens;// a stack while( ( ch = getNextSymbol( ) ) != '\0' ) {// keep reading a new symbol till EOF switch( ch ) { case '(': case '[': case '{':// push an open symbol into the stack pendingTokens.push( ch ); break; case ')': case ']': case '}':// has encountered a close symbol if ( pendingTokens.empty( ) ) {// check if the stack is empty cout << "Extraneous " << ch << endl; return false; } else { match = pendingTokens.top( );// get the top (i.e., the last symbol) pendingTokens.pop( );// on the stack if ( ! checkMatch( match, ch ) )// check this pair of open and close return false;// symbol } } } while ( !pendingTokens.empty( ) ) {// if the stack still has symbols match = pendingTokens.top( );// flush out all. pendingTokens.pop( ); cout << "Unmatched " << match << endl; errors++; } return ( errors > 0 ) ? false : true; } CSS342: Stacks and Compilers
Infix expressions: Every binary operator appears between its operands. a + b a + b * c, if you want to compute a + b first, then (a + b) * c Prefix expressions: Every binary operator appears before its operands. No parentheses needed a + b => + a b (a + b) * c => * + a b c Postfix expressions Every binary operator appears after its operands. No parentheses need a + b => a b + (a + b) * c => a b + c * Easy to evaluate using a stack Example 2 Example 2: Algebraic Expressions CSS342: Stacks and Compilers
Example 2 How to Evaluate a Postfix Expression Assumptions: syntactically correct, no unary operations, and single digit operands 2 3 4 + * for ( (c = cin.get( )) != ‘\n’) { if ( c >= ‘0’ && c <= ‘9’ ) aStack.push(atoi(c)); else { aStack.pop(op2); aStack.pop(op1); switch (c) { case ‘+’: aStack.push(op1 + op2); break; case ‘-’; aStack.push(op1 – op2); break; ….; default: cerr << “panic!”; break; } } } Operations Stack push 2: 2 push 3: 2 3 push 4: 2 3 4 pop 2 3 pop 2 Sum of 3&4 push 7 2 7 Pop Pop Mult of 2&7 Push 14 CSS342: Stacks and Compilers
Converting Infix to Equivalent Postfix Example 2 Infix: a + b Postfix: a b + the same order Abstract code: for ( (c = cin.get( )) != ‘\n’) { siwtch(c) { case operand: postfixExp += c; // Order of operands in both infix and postfix is the same break; case ‘(‘: aStack.push(‘(‘); // Simply push ‘(‘ for matching ‘)’ later break; case operator: while(!aStack.isEmpty() && ch of aStack.getTop(ch) !=‘(‘ && precedence(c) <= precedence(ch)) { posfixExp += ch; aStack.pop( ); } aStack.push(c); (1) Infix: a - b + c Postfix: a Stack: (2) Infix: a - b + c Postfix: a Stack: - (3) Infix: a - b + c Postfix: a b Stack: - (4) Infix: a - b + c Postfix: a b - Stack: + CSS342: Stacks and Compilers
Example 2 Converting Infix to Equivalent Postfix Abstract code (Continued): for ( (c = cin.get( )) != ‘\n’) { switch(c) { …… // See the previous slide case ‘)’: while (ch of aStack.getTop(ch) != ‘(‘) { postfixExp += ch; aStack.pop( ); } aStack.pop( ) break; } } While (!aStack.isEmpty( )) { aStack.pop(ch); postfixExp += ch; } (1) Infix: x - (a - b + c) Postfix: x a b - c Stack: - ( + (2) Infix: x - (a - b + c) Postfix: x a b c - + Stack: - “-” is put on the stack, It is added to Postfix upon encountering “+”, “+”is put on the stack. Upon a “)”, all operators before “(“ are put on Postfix (3) Infix: x - (a - b + c) Postfix: x a b c - + - Stack: CSS342: Stacks and Compilers
Example 2 Converting Infix to Equivalent Postfix int precedence( char op ) { switch( op ) { case '+': return 0; case '-': return 0; case '*': return 1; case '/': return 1; default: return 1; } } string convert( const string& infix ) { stack<char> opStack; char stackTop; string postfixExp; for ( int i = 0; i < infix.size( ); i++ ) { char c = infix[i]; switch( c ) { case '(': opStack.push( c ); break; case '+': case '-': case '*': case '/': if ( !opStack.empty( ) ) { stackTop = opStack.top( ); if ( stackTop != '(' && precedence( c ) <= precedence( stackTop ) ) { postfixExp += stackTop; opStack.pop( ); } } opStack.push( c ); break; case ')': while ( !opStack.empty( ) ) { stackTop = opStack.top( ); if ( stackTop != '(' ) { postfixExp += stackTop; opStack.pop( ); continue; } break; } opStack.pop( ); break; default: // operand postfixExp += c; break; } } while ( !opStack.empty( ) ) { stackTop = opStack.top( ); opStack.pop( ); postfixExp += stackTop; } return postfixExp; } CSS342: Stacks and Compilers
Example 2 Converting Infix to Equivalent Postfix A – (B + C * D) / E CSS342: Stacks and Compilers
Example 2 Ch Stack postFixExp Remark A A Postfix += A * * A Push * B AB Postfix += B A B* Pop *, Postfix += * + + A B* Push + C + A B * C Postfix += C A B * C + Pop +, Postfix += + - - Push - D - A B * C + D Postfix += D / -/ A B * C + D Push / where pr(/) > pr(-) ( -/( A B * C + D Push ( E -/( A B * C + D E Postfix += E + -/(+ A B * C + D E Push + where top( ) = ( F -/(+ A B * C + D E F Postfix += F ) -/( A B * C + D E F+ Pop +, Postfix += + ) -/ A B * C + D E F+ Pop ( - A B * C + D E F+/ Pop /, Postfix += / A B * C + D E F+/- Pop -, Postfix += - Exercise A*B+C-D/(E+F) First try to solve it without looking at the answer. CSS342: Stacks and Compilers
Calculator Design Calculator Design • The code is located at: • http://courses.washington.edu/css342/fukuda/code/stack/evaluator/ • Three main components (in a typical language processor format) • Lexical analyzer token.h tokenizer.h, and tokenizer.cpp.h Read a line of characters and return tokens. • Syntax analyzer evaluator.h’s PREC_TABLE[] and evaluator.cpp.h’s processToken( ) In general, analyze a structure of an arithmetic expression. Convert an infix expression to postfix as checking the syntax. • Evaluator evaluator.cpp’s binaryOp( ) Interprets an analyzed (or postfix) expression. CSS342: Stacks and Compilers
Calculator Design Lexical Analyzer http://dinosaur.compilertools.net/lex/index.html 1. Text Example 2. Lab/Home Work 3. LEX DIGIT [0-9] ID [a-z][a-z0-9] %% {DIGIT}+ { printf( “int = %d\n”, atoi( yytex ) ); {DIGIT}+”.”{DIGIT}* { printf( “float = %g\n”, atof( yytex ) ); } {ID} { printf( “identifier = %s”, yytext ); if|else|while|for|case { printf( “keyword = %s”, yytext ); } From Unix shell: [fukuda@home] Lex pascal.tex [fukuda@home] ls lex.yy.c pascal.lex [fukuda@home] gcc lex.yy.c i i getc( ) == ‘*’ getc( ) == ‘*’ getc( ) == ‘0’ ~’9’ getc( ) == ‘0’ ~’9’ ‘–’ ‘>’ MULT * – ( val * – ( > val MULT MINUS OPAREN MINUS OPAREN GT VALUE VALUE – >= >> UN_MINUS GE SHIFT_R CSS342: Stacks and Compilers
Calculator Design Syntax Analyzer A – (B + C * D) / E • Text example and lab/home work • Infix to prefix algorithm • In general • Syntactic tree • Postfix:Traversing a tree from left to right, as printing the left, the right, and the parent of each node from bottom to root. • Prefix:Traversing a tree from left to right, as printing the parent, the left, and the right of each node from top to bottom – A / + E B * C D CSS342: Stacks and Compilers
Calculator Design Syntax Analyze expression : primary | unary_expr | binary_expr ; primary : ID { $$=(int)maketree( ID, id, NULL ); } : VALUE { $$=(int)maketree( VALUE, value, NULL ); } ; unary_expr : MINUS expression { $$=(int)maketree( UN_MINUS, (TREE)$2, NULL ); } ; Binary_expr : expression STAR expression { $$=(int)maketree( MULT, (TREE)$1, (TREE)$3 ); } | expression SLASH expression { $$=(int)maketree( DIV, (TREE)$1, (TREE)$3 ); } ; • Need • yylex( ) provided by LEX • All grammar definition in parse.y( ) • Then how can you make such a tree? • YACC http://dinosaur.compilertools.net/yacc/index.html CSS342: Stacks and Compilers