import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.logging.Level; //-----------------------------------------------------------------------// // Main class: //-----------------------------------------------------------------------// /** * Provides a <code>driver</code> to compose a sequence of Bali * source files into a single Bali output file. * * @layer<composer> */ public class Main { /** * Handles argument parsing, source parsing, parse-tree collections, * and code generation. * * @return {@link $TEqn.Collector} * with collected data from parse trees. * * @layer<composer> */ public Object driver( String[] args ) throws Throwable { setVersion( "v2003.02.17" ) ; try { parseArguments( Arrays.asList( args ) ) ; } catch ( Exception exception ) { usage( exception.getMessage() ) ; throw exception ; } Collector collector = collectSources( inpFiles ) ; generateObject( collector, writer ) ; writer.close() ; Main.DEBUG.exiting( "composer.Main", "driver", "collector" ) ; return collector ; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /** * Given an {@link Object}, returns a {@link String} containing the * normalized {@link Class} name for the object. * * @layer<composer> */ private static String className( Object object ) { return ( object != null ) ? object.getClass().getName() : "null" ; } /** * Processes a {@link List} of input {@link File} objects, each with * Bali source code, by parsing each into a parse tree, then running * a {@link $TEqn.Collector} over the trees to gather all necessary * data for later code generation. * * @return {@link $TEqn.Collector} with collected data from parse trees. * * @layer<composer> */ private Collector collectSources( List inpFiles ) throws IOException { Main.DEBUG.entering( "composer.Main", "collectSources", inpFiles ) ; Collector collector = new Collector() ; for ( Iterator p = inpFiles.iterator() ; p.hasNext() ; ) { File inputFile = ( File ) p.next() ; Reader reader = new BufferedReader( new InputStreamReader( new FileInputStream( inputFile ), "ISO-8859-1" ) ) ; BaliParse tree = null ; try { Parser parser = Parser.getInstance( reader ) ; tree = (BaliParse) parser.parseAll () ; } catch ( ParseException thrown ) { IllegalStateException except = new IllegalStateException( "parse error in file " + inputFile ) ; except.initCause( thrown ) ; throw except ; } finally { reader.close() ; } collector.dispatch( tree ) ; } Main.DEBUG.exiting( "composer.Main", "collectSources", collector ) ; return collector ; } /** * Generates a single Bali file representing the data collected in the * {@link $TEqn.Collector} argument. * * @layer<composer> */ public void generateObject( Collector collector, Writer writer ) throws IOException { Main.DEBUG.entering( "composer.Main", "generateObject", writer ) ; writer.write( "// Automatically generated Bali code. Edit at your own risk!" + Main.LINE_SEPARATOR + "// Generated by \"balicomposer\" " + Main.getVersion() + '.' + Main.LINE_SEPARATOR + Main.LINE_SEPARATOR + collector + Main.LINE_SEPARATOR ) ; writer.flush() ; Main.DEBUG.exiting( "composer.Main", "generateObject" ) ; } /** * Processes a {@link List} of {@link String} arguments that specify * the input files and output file. * * @see #usage() * * @layer<composer> */ private void parseArguments( List args ) throws IOException { Level debugLevel = Level.OFF ; inpFiles = new ArrayList() ; for ( ListIterator p = args.listIterator() ; p.hasNext() ; ) { String arg = ( String ) p.next() ; if ( arg.equals( "-debug" ) ) { debugLevel = Level.INFO ; if ( p.hasNext() ) { String peek = ( String ) p.next() ; if ( peek.charAt( 0 ) != '-' ) debugLevel = Level.parse( peek.toUpperCase() ) ; else p.previous() ; } continue ; } if ( arg.equals( "-output" ) && p.hasNext() ) writer = parseWriter( ( String ) p.next() ) ; else if ( arg.equals( "-o" ) && p.hasNext() ) writer = parseWriter( ( String ) p.next() ) ; else if ( arg.charAt( 0 ) == '-' ) throw new IllegalArgumentException( "invalid: " + arg ) ; else inpFiles.add( parseInputFile( arg ) ) ; } Main.DEBUG.setLevel( debugLevel ) ; if ( inpFiles.size() < 1 ) throw new IllegalArgumentException( "no input files" ) ; if ( writer == null ) writer = new PrintWriter( System.out, true ) ; return ; } private File parseInputFile( String fileName ) { File file = new File( fileName ) ; if ( ! file.exists() ) throw new IllegalArgumentException( "file doesn't exist: " + fileName ) ; if ( ! file.canRead() ) throw new IllegalArgumentException( "file can't be read: " + fileName ) ; return file ; } private BufferedWriter parseWriter( String fileName ) throws IOException { return new BufferedWriter( new OutputStreamWriter( new FileOutputStream( fileName ), "ISO-8859-1" ) ) ; } private void usage( String message ) { String program = className( this ) ; if ( message != null ) System.err.println( program + ": " + message ) ; System.err.println( "Usage: java " + program + " <Bali-source-file> ..." + " -output <output-file>" ) ; } private List inpFiles = null ; private Writer writer = null ; }