import java.io.File ; import java.io.FileInputStream ; import java.io.FileNotFoundException ; import java.io.InputStream ; import java.io.InputStreamReader ; import java.io.Reader ; import java.io.UnsupportedEncodingException ; import java.lang.reflect.Method ; import java.util.HashMap ; import java.util.Map ; //-----------------------------------------------------------------------// // Parser facade below: //-----------------------------------------------------------------------// /** * Facade for underlying {@link BaliParser} that provides factory methods * named <code>getInstance</code> for obtaining a <em>singleton</em> * instance of the parser. The factory methods should be used instead of * constructors or the {@link BaliParser#ReInit()} methods. * * @layer<kernel> */ final public class Parser { //-----------------------------------------------------------------------// // Static factory methods for instantiation: //-----------------------------------------------------------------------// /** * Return singleton <code>Parser</code> in current state. * * @layer<kernel> */ public static Parser getInstance() { return parser ; } /** * Re-initialize singleton <code>Parser</code> to start parsing from * a given {@link File}, returning the updated <code>Parser</code>. * * @layer<kernel> */ public static Parser getInstance( File inputFile ) throws FileNotFoundException { return getInstance( new FileInputStream( inputFile ) ) ; } /** * Re-initialize singleton <code>Parser</code> to start parsing from * an {@link InputStream}, returning the updated <code>Parser</code>. * * @layer<kernel> */ public static Parser getInstance( InputStream stream ) { try { return getInstance( new InputStreamReader( stream,"ISO-8859-1" ) ); } catch ( UnsupportedEncodingException except ) { return getInstance( new InputStreamReader( stream ) ) ; } } /** * Re-initialize singleton <code>Parser</code> to start parsing from * a {@link Reader} object, returning the updated <code>Parser</code>. * * @layer<kernel> */ public static Parser getInstance( Reader reader ) { if ( parser == null ) parser = new Parser( reader ) ; else parser.reset (reader) ; return parser ; } //-----------------------------------------------------------------------// // Parser instance methods: //-----------------------------------------------------------------------// /** * Returns the result of the last parse, <code>null</code> if none. **/ public AstNode getParse () { return lastParse ; } /** * Parses the input against the specified non-terminal rule. This method * doesn't require that a successful parse must be terminated by an * end-of-file. Instead, any non-matching input is allowed. * * @return an {@link AstNode} with the result of the parse. * @throws ParseException if the parse fails. **/ public AstNode parse (String rule) throws ParseException { try { Method method = (Method) ruleMap.get (rule) ; if (null == method) { Class klass = baliParser.getClass() ; method = klass.getMethod (rule, class0) ; if (! AstNode.class.isAssignableFrom (method.getReturnType())) throw new IllegalArgumentException (rule + " not found") ; ruleMap.put (rule, method) ; } return (AstNode) method.invoke (baliParser, object0) ; } catch (RuntimeException re) { throw re ; } catch (Exception except) { ParseException pe = baliParser.generateParseException() ; pe.initCause (except) ; throw pe ; } } /** * Parses the input against the start rule, then parses an end-of-file. * * @return an {@link AstNode} with the result of the parse. * * @throws ParseException * if input doesn't match the start rule or if it's not terminated by an * end-of-file. **/ public AstNode parseAll () throws ParseException { lastParse = BaliParser.getStartRoot (baliParser) ; return lastParse ; } /** * Parses an end-of-file from the input. * * @throws ParseException if input is not at end of file. **/ public void parseEOF () throws ParseException { baliParser.requireEOF() ; } /** * Resets the parser's input to another {@link Reader}. **/ private void reset (Reader reader) { baliParser.ReInit (reader) ; } //-----------------------------------------------------------------------// /** * Private constructor to create singleton of <code>Parser</code>. * * @layer<kernel> */ private Parser( Reader reader ) { if (null == reader) throw new NullPointerException ("\"reader\" is null") ; this.baliParser = new BaliParser (reader) ; this.lastParse = null ; this.ruleMap = new HashMap() ; } private BaliParser baliParser ; private AstNode lastParse ; private Map ruleMap ; final private static Class[] class0 = new Class [0] ; final private static Object[] object0 = new Object [0] ; private static Parser parser = null ; }