import java.io.Reader; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Stack; // Balance class: check for balanced symbols // // CONSTRUCTION: with a BufferedReader object // ******************PUBLIC OPERATIONS*********************** // int checkBalance( ) --> Print mismatches // return number of errors // ******************ERRORS********************************** // Error checking on comments and quotes is performed // main checks for balanced symbols. /** * Class to perform symbol matching * generation for Java programs. */ public class Balance { /** * Symbol represents what will be placed on the stack. */ private static class Symbol { public char token; public int theLine; public Symbol( char tok, int line ) { token = tok; theLine = line; } } /** * Constructor. * @param inStream the stream containing a program. */ public Balance( Reader inStream ) { errors = 0; tok = new Tokenizer( inStream ); } /** * Print an error message for unbalanced symbols. * @return number of errors detected. */ public int checkBalance( ) { char ch; Symbol match = null; Stack pendingTokens = new Stack( ); while( ( ch = tok.getNextOpenClose( ) ) != '\0' ) { Symbol lastSymbol = new Symbol( ch, tok.getLineNumber( ) ); switch( ch ) { case '(': case '[': case '{': pendingTokens.push( lastSymbol ); break; case ')': case ']': case '}': if( pendingTokens.isEmpty( ) ) { errors++; System.out.println( "Extraneous " + ch + " at line " + tok.getLineNumber( ) ); } else { match = (Symbol) pendingTokens.pop( ); checkMatch( match, lastSymbol ); } break; default: // Cannot happen break; } } while( !pendingTokens.isEmpty( ) ) { match = (Symbol) pendingTokens.pop( ); System.out.println( "Unmatched " + match.token + " at line " + match.theLine ); errors++; } return errors + tok.getErrorCount( );; } private Tokenizer tok; private int errors; /** * Print an error message if clSym does not match opSym. * Update errors. */ private void checkMatch( Symbol opSym, Symbol clSym ) { if( opSym.token == '(' && clSym.token != ')' || opSym.token == '[' && clSym.token != ']' || opSym.token == '{' && clSym.token != '}' ) { System.out.println( "Found " + clSym.token + " on line " + tok.getLineNumber( ) + "; does not match " + opSym.token + " at line " + opSym.theLine ); errors++; } } /** * main routine for balanced symbol checker. * Slightly different from text. * If no command line parameters, standard input is used. * Otherwise, files in command line are used. */ public static void main( String [ ] args ) { Balance p; if( args.length == 0 ) { p = new Balance( new InputStreamReader( System.in ) ); if( p.checkBalance( ) == 0 ) System.out.println( "No errors!" ); return; } for( int i = 0; i < args.length; i++ ) { FileReader f = null; try { f = new FileReader( args[ i ] ); System.out.println( args[ i ] + ": " ); p = new Balance( f ); if( p.checkBalance( ) == 0 ) System.out.println( " ...no errors!" ); } catch( IOException e ) { System.err.println( e + args[ i ] ); } finally { try { if( f != null ) f.close( ); } catch( IOException e ) { } } } } }