CMSC--202 , Section Computer Science II for Majors
Fall 1997 27 October 1997 Homework 6

The purpose of this assignment is to give you some experience with stacks and to expose you to an important stack application. In this assignment, you will write a C program to test the ``balance'' of certain features of C programs. This is a task that is done by C compilers. The technique you will use is similar to the technique used by a typical C compiler.

There are many features in C programs that must be ``balanced'' to be syntactically correct. For example, every ( must be balanced by a corresponding ). Similarly for {} and []. There are other (somewhat more complex) situations requiring balance.

There are some balanced C programs you need not test. For example, some balanced C programs contain character constants such as '\'' or '\"'. These are inherently unbalanced and would require a bit more work to catch. You need not worry about such problems for this homework (unless you like the modest challenge).

The Basic Algorithm

The basic algorithm is contained in the ``Stacks and Queues'' handout. As noted in the handout, simply counting the number of characters will not work. For example, the expression }abc{ has the correct number of balancing braces (one opening brace and one closing brace), but it is not valid C code. A stack provides the mechanism needed for the algorithm. Basically, whenever a closing symbol (such as }) is seen, it must match the nearest opening symbol of the same type (such as {). The algorithm given in the handout provides a skeleton for your homework. It is not useable as is; you must modify it in a number of ways. One important point: do not write a large main file. Your main file should simply get a file name, call a function to print the file with line numbers, and then call a balance-checking function.

Your Program

Your program prompts the user for the name of the C source file to test. If unable to open the file, the program issues an appropriate ``file not found'' error message, and exits. Before beginning the check, your program prints the file with line numbers. Every time your program pops the stack (to check for balance), it issues a message such as

    pair matching [  and  ]

As soon as a balance-error condition is found, the program issues a message such as

    unmatched { symbol at line 16
and exits.

Hints

  1. You can read a file character-by-character using the fgetc method from stdio.h.
  2. A file that you have read all the way to the end can be read again by first doing rewind on it.
  3. When you read the / character, it may be the opening of a comment (as in /*), or it may be the division operator. You will have to read the character after it to decide. If it's not the opening comment, you may want to put back the following character. You can use ungetc to do this.
  4. When you read the * character, it may be the closing of a comment (as in */), or it may be the multiplication operator or a pointer operation. Once again, you may want to use ungetc.
  5. The opening-comment ``symbol'' /* and the closing-comment ``symbol'' */ are composed of two characters. One choice for a single character to push for a comment symbol might be an otherwise unused symbol character (for example, the character c).
  6. You may find it useful to define a lot of utility functions such as the following:
    BOOL isOpeningBrace(int c)
    returns TRUE if c is an opening brace, parenthesis, or bracket, FALSE otherwise.
    BOOL opensComment(FILE * fp, int c)
    returns TRUE if c and the character following it in fp form the opening of a comment (i.e., slash-star). If so, the character following the slash (i.e., *) is eaten. Returns FALSE otherwise and puts the character following the slash back on fp.
    int ignoreQuote(FILE * fp, int c, int * line)
    reads fp until a character matching c is found (this will be a matching quote character). Returns BADMATCH if no match found, GOODMATCH otherwise. A side effect is that all characters in fp between the quotes are eaten. line is updated to keep track of the line number in fp.

Submit

Submit your work in the usual way, using the submit command. For example, to submit the file foo.c, do:

Submit all the files required to successfully compile your homework using your submitted makefile. The only constraints on file names are that the executable must be named hw6 and the makefile must be named Makefile or makefile. Otherwise, you may name your files as you wish.

Sample Runs

Here are some samples of the output generated by the hw6 program. Notice that the C-source code does not have to be legal C, it just has to meet balance conditions. The program begins by printing the file to be tested with line numbers. It then checks the balance and reports on the outcome.

A Balanced Test Case

>>  hw6
Please enter filename for C code: good_balance.c
  1 /*
  2   good_balance.c
  3   Test data for HW-6, CMSC-202, Fall 1997
  4   Thomas Anastasio
  5   Created: 24 October 1997
  6   Current: 24 October 1997
  7   */
  8 
  9 #define FOO   '"* /* */ foo'
 10 #define BAR   " /* ' "
 11 
 12 int main(int argc, char * argv[])
 13 {
 14   char c = {'a';}
 15   y = 3;
 16   z = 4; 
 17   x = y * z;
 18   y = x / z;
 19   printf("Hello world\n");
 20 }
 21 
pair matching /* and */
pair matching ' and '
pair matching " and "
pair matching [ and ]
pair matching ( and )
pair matching ' and '
pair matching { and }
pair matching " and "
pair matching ( and )
pair matching { and }
Balance is ok

An Unbalanced Test Case

>> hw6
Please enter filename for C code: bad_balance.c
  1 /*
  2   bad_balance.c
  3   Test data for HW-6, CMSC-202, Fall 1997
  4   This program has bad balance conditions.
  5   Thomas Anastasio
  6   Created: 24 October 1997
  7   Current: 24 October 1997
  8   */
  9 
 10 #define FOO   '"* /* */ foo'
 11 #define BAR   " /* ' "
 12 
 13 int main(int argc, char * argv[])
 14 {
 15   char c = {'a';}
 16   y = 3;
 17   z = 4; 
 18   x = y * z;
 19   y = x / z;
 20   {
 21     printf("Hello world\n");
 22   }
 23 
pair matching /* and */
pair matching ' and '
pair matching " and "
pair matching [ and ]
pair matching ( and )
pair matching ' and '
pair matching { and }
pair matching " and "
pair matching ( and )
pair matching { and }
unbalanced { symbol on line 14

Another Unbalanced Test Case

>>  hw6
Please enter filename for C code: bad_balance2.c
  1 /*
  2   bad_balance2.c
  3   Test data for HW-6, CMSC-202, Fall 1997
  4   This program has bad balance conditions.
  5   Thomas Anastasio
  6   Created: 24 October 1997
  7   Current: 24 October 1997
  8   */
  9 
 10 #define FOO   '"* /* */ foo'
 11 #define BAR   " /* ' "
 12 
 13 int main(int argc, char * argv[])
 14 {
 15   char c = {'a';}
 16   y = 3; '
 17   z = 4; 
 18   x = y * z;
 19   y = x / z;
 20   {
 21     printf("Hello world\n");
 22   }
 23 }
 24 
pair matching /* and */
pair matching ' and '
pair matching " and "
pair matching [ and ]
pair matching ( and )
pair matching ' and '
pair matching { and }
unbalanced quote ' on line 16


Thomas A. Anastasio
Mon Oct 27 14:29:04 EST 1997