import java.io.*; import java.util.*; public class Parser { TTtable tablelist; TAtable attrlist; RRtable relationlist; TT TTcurr; TA TAcurr; Database TheSchema; int parseState; LineNumberReader schemaFile; final int NULL_STATE = 0; final int EXPECTING_TABLE_STATE = 1; final int EXPECTING_OPENING_STATE = 2; final int EXPECTING_ATTR_STATE = 3; String linebuffer; StringTokenizer tokens; String currToken; int keysize = 8; int abbrsize = 2; Parser(TTtable tables, TAtable attrs, RRtable relations) { tablelist = tables; attrlist = attrs; relationlist = relations; } Parser(Database schema) { TheSchema = schema; tablelist = TheSchema.TTtab; attrlist = TheSchema.TAtab; relationlist = TheSchema.RRtab; } void Parse(String filename) { parseState = NULL_STATE; try { schemaFile = new LineNumberReader( new FileReader(filename) ); parseState = EXPECTING_TABLE_STATE; while((linebuffer = schemaFile.readLine()) != null) { // NOTE : This must be reinstantiated each time, because // the delimiter is changed to account for comments // in each row and table!!! tokens = new StringTokenizer(linebuffer); if( !tokens.hasMoreTokens() ) { // Blank line continue; } if( (currToken = tokens.nextToken()).startsWith("/*") ) // Whole line comment continue; switch( parseState ) { case NULL_STATE: break; case EXPECTING_TABLE_STATE: ParseTable(); break; case EXPECTING_OPENING_STATE: ParseOpening(); break; case EXPECTING_ATTR_STATE: ParseAttr(); break; default: System.err.println("Unknown state " + parseState); System.exit(-1); } } } catch ( FileNotFoundException fnfe ) { System.out.println( filename + ": " + fnfe ); System.exit(-1); } catch ( IOException ioe ) { System.out.println( filename + ": " + ioe ); System.exit(-1); } } void ParseTable() { TTcurr = new TT(); if( currToken.charAt(0) == '{' ) { System.err.println("GENJAVA-F-MISSINGTBLLINE, line " + schemaFile.getLineNumber() + ": " + "found '{' when expecting the start of a new table" ); System.exit(-1); } if( currToken.charAt(0) == '}' ) { System.err.println("GENJAVA-F-EXTRAEND, line " + schemaFile.getLineNumber() + ": " + "found '}' when expecting the start of a new table" ); System.exit(-1); } if( !Character.isLetter(currToken.charAt(0)) ) { System.err.println("GENJAVA-F-BADTBLNAME, line " + schemaFile.getLineNumber() + ": " + "invalid table name " + currToken + " - must start with an alphabetic character"); System.exit(-1); } if( !tokens.hasMoreTokens() ) { System.err.println("GENJAVA-F-NOABBR, line " + schemaFile.getLineNumber() + ": " + "Abbreviation missing"); System.exit(-1); } TTcurr.setTTname(currToken); currToken = tokens.nextToken(); if( currToken.length() != abbrsize ) { System.err.println("GENJAVA-F-ABBRTOOLONG, line " + schemaFile.getLineNumber() + ": table abbreviation " + currToken + " for table " + TTcurr.getTTname() + " must be " + abbrsize + " characters long"); System.exit(-1); } TTcurr.setTTabb(currToken); if( !tokens.hasMoreTokens() || !((currToken = tokens.nextToken("\r\n\f").trim()).startsWith("/*"))) { System.err.println("GENJAVA-W-MISSINGCOMMENT, line " + schemaFile.getLineNumber() + ": " + "table " + TTcurr.getTTname() + " does not have a comment"); } else { TTcurr.setDescr(currToken); } TTcurr.setSchema(TheSchema); TTcurr.setTable(tablelist); TTcurr.setSVid("SV010001"); TTcurr.addRow(); parseState = EXPECTING_OPENING_STATE; } void ParseOpening() { if( currToken.charAt(0) != '{' ) { System.err.println("GENJAVA-F-MISSINGBEGIN, line " + schemaFile.getLineNumber() + ": " + "missing '{' for table " + TTcurr.getTTname()); System.exit(-1); } parseState = EXPECTING_ATTR_STATE; } void ParseAttr() { TAcurr = new TA(); if ( currToken.charAt(0) == '}') { parseState = EXPECTING_TABLE_STATE; return; } if ( currToken.charAt(0) == '{') { System.err.println("GENJAVA-F-EXTRABEGIN, line " + schemaFile.getLineNumber() + ": " + "missing '{' for table " + TTcurr.getTTname()); System.exit(-1); } if( !Character.isLetter(currToken.charAt(0)) ) { System.err.println("GENJAVA-F-BADFIELDNAME, line " + schemaFile.getLineNumber() + ": " + "invalid field name " + currToken + " - must start with an alphabetic character"); System.exit(-1); } TAcurr.setFname(currToken); currToken = tokens.nextToken(); TAcurr.setAltFname(currToken); currToken = tokens.nextToken(); switch(currToken.charAt(0)) { case 'i': if((currToken.charAt(1) != '2') && (currToken.charAt(1) != '4')) { System.err.println("GENJAVA-F-BADINTTYPE, line " + schemaFile.getLineNumber() + ": " + "integer data-type " + currToken + " for field " + TAcurr.getFname() + " in table " + TTcurr.getTTname() + " is invalid, value types are i2 and i4"); System.exit(-1); } break; case 'f': if((currToken.charAt(1) != '4') && (currToken.charAt(1) != '8')) { System.err.println("GENJAVA-F-BADFLOATTYPE, line " + schemaFile.getLineNumber() + ": " + "float data-type " + currToken + " for field " + TAcurr.getFname() + " in table " + TTcurr.getTTname() + " is invalid, value types are f4 and f8"); System.exit(-1); } break; case 'd': if( currToken.compareTo("date") != 0 ) { System.err.println("GENJAVA-F-BADDATETYPE, line " + schemaFile.getLineNumber() + ": " + "date data-type " + currToken + " for field " + TAcurr.getFname() + " in table " + TTcurr.getTTname() + " is invalid"); System.exit(-1); } break; case 'c': case 't': try { Integer.parseInt(currToken.substring(1)); } catch ( NumberFormatException e ) { System.err.println("GENJAVA-F-CHARTEXT, line " + schemaFile.getLineNumber() + ": " + "invalid length for data-type " + currToken + " for field " + TAcurr.getFname() + " in table " + TTcurr.getTTname()); System.err.println(e); System.exit(-1); } break; case 'b': if( currToken.compareTo("b") != 0 ) { System.err.println("GENJAVA-F-BADBOOLTYPE, line " + schemaFile.getLineNumber() + ": " + "boolean data-type " + currToken + " for field " + TAcurr.getFname() + " in table " + TTcurr.getTTname() + " is invalid"); System.exit(-1); } break; default: System.err.println("GENJAVA-F-BADTYPE, line " + schemaFile.getLineNumber() + ": " + "unsupported data-type " + currToken + " for field " + TAcurr.getFname() + " in table " + TTcurr.getTTname()); System.exit(-1); } TAcurr.setFtype(currToken); currToken = tokens.nextToken(); if ((currToken.compareTo("0") != 0) && (currToken.compareTo("1") != 0) && (currToken.compareTo("s") != 0) && (currToken.compareTo("1") != 0)) { System.err.println("GENJAVA-F-BADISKEY, line " + schemaFile.getLineNumber() + ": " + "'is-key' field " + currToken + " for field " + TAcurr.getFname() + " in table " + TTcurr.getTTname() + " must be 0, 1, -1, or s"); System.exit(-1); } TAcurr.setIsKey( currToken ); if( !tokens.hasMoreTokens() || !((currToken = tokens.nextToken("\r\n\f").trim()).startsWith("/*"))) { System.err.println("GENJAVA-W-MISSINGCOMMENT, line " + schemaFile.getLineNumber() + ": " + "for field " + TAcurr.getFname() + "for table " + TTcurr.getTTname() + " does not have a comment"); } else { TAcurr.setDescr(currToken); } if ( TAcurr.getIsKey().compareTo("0") != 0 && TAcurr.getFtype().compareTo("c8") != 0) { if ( TTcurr.TAid_fcp == null ) { System.err.println("GENJAVA-F-KEYMUSTBEC8, line " + schemaFile.getLineNumber() + ": " + "primary key field " + TAcurr.getFname() + " for table " + TTcurr.getTTname() + " must be of type c8"); } else { System.err.println("GENJAVA-F-KEYMUSTBEC8, line " + schemaFile.getLineNumber() + ": " + "foreign key field " + TAcurr.getFname() + " for table " + TTcurr.getTTname() + " must be of type c8"); } System.exit(-1); } if ( TTcurr.TAid_fcp == null ) { if (TAcurr.getIsKey().compareTo("1") != 0) { System.err.println("GENJAVA-F-FIRSTMUSTBEKEY, line " + schemaFile.getLineNumber() + ": " + "first field " + TAcurr.getFname() + " for table " + TTcurr.getTTname() + " must have an 'is-key' value of 1"); System.exit(-1); } if ( TAcurr.getFname().substring(0,abbrsize).compareTo(TTcurr.getTTabb()) != 0 ) { System.err.println("GENJAVA-F-PKEYABBREVNOMATCH, line " + schemaFile.getLineNumber() + ": " + "first " + abbrsize + " characters of primary key field " + TAcurr.getFname() + " for table " + TTcurr.getTTname() + " must equal the table abbreviation " + TTcurr.getTTabb()); System.exit(-1); } } else if (TAcurr.getIsKey().compareTo("0") != 0) { // TODO: add parent child (rrtable) code here AddPcTableEntries( TAcurr.getFname(), TTcurr.TAid_fcp.getFname(), TAcurr.getIsKey() ); } TAcurr.setSchema(TheSchema); TAcurr.setTable(attrlist); TAcurr.setTTid(TTcurr.getPkid()); TAcurr.addRow(); } void AddPcTableEntries( String parent, String child, String isKey ) { String tempParent; String tempChild; int i; boolean foundnum = false; RR newRelation; tempParent = parent; tempChild = child; for( i = 0; i < parent.length(); i++ ) { if( Character.isDigit( parent.charAt(i) ) ) { foundnum = true; break; } } if( foundnum ) { String dorkstring = tempParent.substring(i); tempChild += tempParent.substring(i); } newRelation = new RR(); newRelation.setFirstid( tempParent ); newRelation.setSecondid( tempChild ); newRelation.setHasbp( isKey.compareTo("1") == 0 || isKey.compareTo("s") == 0 ); newRelation.setSingleton( isKey.compareTo("s") == 0 ); newRelation.setSchema(TheSchema); newRelation.setTable(relationlist); newRelation.addRow(); } public static void main( String[] args ) { Database theSchema; Parser theParser; theSchema = new Database(); theParser = new Parser(theSchema); System.out.println( "Parsing file " + args[0] + "..." ); theParser.Parse( args[0] ); System.out.println( "Done Parsing\n\n" ); try { TT TTcurr; RC TAcurr; RR RRcurr; BufferedWriter output; if( args.length == 1 ) { output = new BufferedWriter ( new OutputStreamWriter(System.out) ); } else { output = new BufferedWriter ( new FileWriter(args[1]) ); } // Table loop through TT for( TTcurr = theParser.tablelist.getFirstRow(); TTcurr != null; TTcurr = theParser.tablelist.getNextRow(TTcurr) ) { output.write("======================================================="); output.newLine(); output.flush(); output.write( "Table name: "+ TTcurr.getTTname() ); output.newLine(); output.flush(); output.write( "Table abbrev: "+ TTcurr.getTTabb() ); output.newLine(); output.flush(); output.write( "Table comment: "+ TTcurr.getDescr() ); output.newLine(); output.newLine(); output.newLine(); output.newLine(); output.flush(); // Loop over each TA child of this TT TAcurr = TTcurr.TAid_fcp; while( TAcurr != null && TAcurr != TTcurr ) { output.write("\tField name = " + ((TA)TAcurr).getFname() ); output.newLine(); output.flush(); output.write("\tAlternate name = " + ((TA)TAcurr).getAltFname() ); output.newLine(); output.flush(); output.write("\tType = " + ((TA)TAcurr).getFtype() ); output.newLine(); output.flush(); output.write("\tIsKey = " + ((TA)TAcurr).getIsKey() ); output.newLine(); output.flush(); output.write("\tComment = " + ((TA)TAcurr).getDescr() ); output.newLine(); output.newLine(); output.flush(); TAcurr = ((TA)TAcurr).TTid_fpp; } } output.newLine(); output.write("======================================================="); output.newLine(); output.flush(); output.write("* Relationships"); output.newLine(); output.flush(); output.write("======================================================="); output.newLine(); output.flush(); // Table loop through RR for( RRcurr = theParser.relationlist.getFirstRow(); RRcurr != null; RRcurr = theParser.relationlist.getNextRow(RRcurr) ) { output.write("\tField generated in Child : " + RRcurr.getFirstid()); output.newLine(); output.flush(); output.write("\tField generated in Parent : " + RRcurr.getSecondid()); output.newLine(); output.newLine(); output.flush(); } output.newLine(); output.write("======================================================="); output.newLine(); output.flush(); output.write("* Metadata Tables TT, TA, RR"); output.newLine(); output.flush(); output.write("======================================================="); output.newLine(); output.flush(); // Dump all schema tables theSchema.TTtab.dumpTable(output); theSchema.TAtab.dumpTable(output); theSchema.RRtab.dumpTable(output); } catch ( IOException e ) { System.out.println(e); } } }