In this lab you will design implement a stack on top of a linked list, and solve the so-called parentheses matching problem using it. Make sure that you understand the workings of a linked list. Although it is easy to modify the code in the previous lecture notes to suit the purpose of this lab, we recommend implementing your linked list from scratch.
You may be wondering how the C++ compiler parses your text ( and makes sense of it). In this lab you will get a flavor of this, by solving a much less complicated yet similar problem.
Consider an arithmetic expression (or a C++ program) that contains parentheses, '(' and ')' . Ignoring all other characters in the text, you can still decide if all parentheses are correctly matched. Here are a few examples:
( ) -- correct ( ( ) ) -- correct ( ( ) ) ( ) -- correct ( ( ( ) ) ( ) ) -- correct ( ) ) -- incorrect (closed paren with no open paren) ) ( -- incorrect ( ( ) ) ) ( -- incorrectAs you can see, the number of open and closed parens being equal does not guarantee that the parens are matching.
The situation can be worse if there are two kinds of parens that should be matching in a program, such as '{', '}' and '(', ')'. The situation when these parenthesis are weirdly mismatched in a C++ program must be a familiar one :-) . A few examples:
{ ( ) } -- correct { ( { } ) () } -- correct { ( } ) -- incorrect ( ( { ) } ) -- incorrectClearly, separately matching the kinds of parentheses does not guarantee the correctness of the overall structure - observe that in third example both braces and parens are matched if we ignore the other kind. Also notice that we can put as many matched parens as we like around that example, and that still won't make it correct.
An algorithm that checks whether the matching in a given text is correct is as follows:
0. Create an empty stack S. 1. While( there are characters left ){ 2. Read a character ch. 3. If is ch an opening paren (of any kind), push it onto S 4. Else 5. If ch is a closing paren (of any kind), look at the top of S. 6. If S is empty as this point, report failure. 7. If the top of S is the opening paren that corresponds to c, then pop S and continue to 1, this paren matches OK. 8. Else report failure. 9. If at the end of input the stack S is not empty, return failure. Else return success.The failure reported on line 6 is due to finding a closing paren without any preceding opening paren that might correspond to it. On line 8 it is due to mismatches like { ( } ), and on line 9 it is due to having more opening parens of some kind than closing ones.
main(){ cout << " :-) " ; }
The following program reads a file and counts the number of opening and closing parens '(', ')' in it. As we saw, this is by far not enough to check the matching, so treat the following code is intended to merely refresh your memory of standard libraries.
#include <iostream.h> #include <fstream.h> #include <stdlib.h> // for exit(..) int main(){ ifstream f; f.open( "test1.txt" ); if( ! f ){ cout << "Error opening file. Quitting.\n"; exit(-1); } int open_count = 0; int close_count = 0; int line_count = 0; char ch; while( f.get( ch ) ){ // fills ch with the next char from file, // returns false if the end of file (EOF) // is reached if( ch == '(' ) open_count++; else if( ch == ')' ) close_count++; else if( ch == '\n' ) line_count++; } cout << open_count << " of ) , \n"; cout << close_count << " of ( , \n"; cout << line_count << " lines. \n"; return 0; }