/* Each of these classes should be in their own file. See the zip for all classes and files. */ /* Balance.java */ import java.io.FileReader; import java.io.BufferedReader; import java.io.IOException; import java.util.Stack; /** * Checks a file for whether the delimiters () {} and [] are balanced. * Includes check for proper nesting. * Ignores any other delimiter found within quotes: '' or "", * and assumes that \' or \" is NOT a closing quote. * Reads the file name from command line argument. * Reports on line and column of mismatch found. * * @author Zach Tomaszewski, expanded from a code sample by Dan Suthers * @version 1.0 * @date 21 Oct 2001 */ public class Balance { public static void main(String args[]) { if (args.length == 0) { System.out.println("Usage: java Balance "); }else { try { BufferedReader fileIn = new BufferedReader( new FileReader(args[0])); int lineNumber = 0; int columnIndex; // will be set when each line is read String line; Stack delimiterStack = new Stack(); char lastChar, nextChar = ' '; DelimiterData delimiter; boolean fail = false; boolean singleQuoting = false; //both needed for nested quotes boolean doubleQuoting = false; // read new line and process while ((line = fileIn.readLine()) != null) { lineNumber++; // now it is the actual line number columnIndex = 0; // for string indexing; add 1 to indicate actual column int length = line.length(); // read new character and process while (columnIndex < length && fail == false) { lastChar = nextChar; nextChar = line.charAt(columnIndex++); switch (nextChar){ case '\\': //backslash if (lastChar == '\\') { //this is an escaped backslash nextChar = ' '; } break; case '\'': //quotes if (lastChar == '\\' || doubleQuoting) { //do nothing }else{ singleQuoting = (singleQuoting) ? false : true; } break; case '"': if (lastChar == '\\' || singleQuoting) { //do nothing }else{ doubleQuoting = (doubleQuoting) ? false : true; } break; case '{': case '[': case '(': if (singleQuoting || doubleQuoting) {break;} delimiter = new DelimiterData(nextChar, lineNumber, columnIndex); delimiterStack.push(delimiter); break; case '}': case ']': case ')': if (singleQuoting || doubleQuoting) {break;} if (!delimiterStack.isEmpty()) { delimiter = (DelimiterData)delimiterStack.peek(); }else{ System.out.println("Closing " + nextChar + " at line " + lineNumber + ", column " + columnIndex + " never opened..."); fail = true; break; } if ( (delimiter.getChar() == '{' && nextChar == '}') || (delimiter.getChar() == '[' && nextChar == ']') || (delimiter.getChar() == '(' && nextChar == ')')) { delimiterStack.pop(); }else { System.out.println("Opening " + delimiter.getChar() + " at line " + delimiter.getLine() + ", column " + delimiter.getColumn() + " does not match closing " + nextChar + " at line " + lineNumber + ", column " + columnIndex); fail = true; break; } }//end switch } } //run thru whole file, now see if stack is empty if (delimiterStack.isEmpty() && !fail) { System.out.println("All delimiters match: file syntax CORRECT."); }else if (!fail) { while (!delimiterStack.isEmpty()) { delimiter = (DelimiterData)delimiterStack.pop(); System.out.println("Opening " + delimiter.getChar() + " at line " + delimiter.getLine() + ", column " + delimiter.getColumn() + " never closed..."); } } }catch (IOException e){ System.out.println(e); } } }//end main }//end class /* DelimiterData.java */ /** * A utility class to hold delimiters such as []{} or () * as well as their position in a file. * * @author Zach Tomaszewski * @date 20 Oct 2001 */ class DelimiterData { private char delimiter; //character to hold private int line, column; //position of character protected DelimiterData(char delimiter, int line, int column){ this.delimiter = delimiter; this.line = line; this.column = column; } /** * returns the character held by this object */ protected char getChar(){ return this.delimiter; } /** * returns the line of the delimter held by this object */ protected int getLine(){ return this.line; } /** * returns the column of the delimiter held by this object */ protected int getColumn(){ return this.column; } }//end class