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 ;
}