1 /**
2 * .
3 * Copyright � 1999 Erich P G.
4 *
5 */
6
7 package creator.compiler;
8
9 import java.util.Vector;
10 import java.io.InputStream;
11 import java.io.File;
12 import java.io.InputStreamReader;
13 import java.io.FileInputStream;
14 import java.io.EOFException;
15 import org.xml.sax.InputSource;
16 import com.sun.xml.parser.Parser;
17 import com.sun.xml.parser.ValidatingParser;
18 import com.sun.xml.tree.XmlDocument;
19 import com.sun.xml.tree.XmlDocumentBuilder;
20 import org.xml.sax.ErrorHandler;
21
22
23 /**
24 * This is the a base XML compiler. It must be extended by a specific compiler.
25 * Users of an extended class will call the compile() method in this class, which
26 * will first parse the XML then call the abstract method build(). An extended
27 * class must override the build() method and use to to compile from the
28 * xml document tree.
29 *
30 * This will load/cache the DTD by providing a new Resolver that will
31 * return a string reader to the cached DTD.
32 *
33 * WARNING!!! For the compiler to work, the FIRST element of the java
34 * CLASSPATH <b>must</b> be the root for the autohit installation. The compiler
35 * needs to find the XML DTD files in the "./lib" directory.
36 *
37 *
38 * @author Erich P. Gatejen
39 * @version 1.0
40 * <i>Version History</i>
41 * <code>EPG - Initial - 12Jan99</code>
42 *
43 */
44 public abstract class XmlCompiler {
45
46 // --- FINAL FIELDS ------------------------------------------------------
47 private final static String dtdLocation = "/lib/";
48 private final static int BUFFER_SIZE = 1024;
49
50 // --- FIELDS ------------------------------------------------------------
51
52 /**
53 * Handles parse/compile errors and warnings. Also serves as the ErrorHandler
54 * for the XML parser.
55 *
56 * A new one will be/must be created for each compile.
57 *
58 * @see creator.compiler.XmlParseErrorHandler
59 */
60 public XmlParseErrorHandler err;
61
62 /**
63 * The DTD to use when parsing the source text.
64 */
65 private String myDTD;
66
67 /**
68 * The DTD to use when parsing the source text.
69 */
70 private XmlCompilerResolver myResolver;
71
72 /**
73 * The XML builder.
74 */
75 private XmlDocumentBuilder builder;
76
77 /**
78 * The XML parser.
79 */
80 protected Parser parser;
81
82
83 // --- PUBLIC METHODS ----------------------------------------------------
84
85 /**
86 * Constructor. You must use this and NOT the default.
87 * It will make sure that the DTD for the SimLanguage is available.
88 *
89 * If you use the defaulty constructor, the compiler will not know
90 * which DTD to use.
91 *
92 * @param dtdURI URI of the DTD used in the !DOCTYPE * SYSTEM clause in the
93 * compile targets.
94 * @throws Exception any exception invalidates the compiler.
95 */
96 public XmlCompiler(String dtdURI) throws Exception {
97
98 // Try to find the file
99 String raw = System.getProperty("java.class.path");
100
101 String scrubbed = raw.substring(0, raw.indexOf(";"));
102 String scrubbedURI = dtdURI.substring(dtdURI.indexOf(":") + 1);
103 String dtdPath = new String(scrubbed + dtdLocation + scrubbedURI);
104
105 // See if we can open and read it. Allow any exceptions to be
106 // thrown beyond this constructor.
107 File dtdFile = new File(dtdPath);
108 InputStreamReader inFile = new InputStreamReader( new FileInputStream(dtdFile) );
109 StringBuffer tempDTD = new StringBuffer();
110
111 try {
112 char[] buf = new char[BUFFER_SIZE];
113 int len;
114
115 len = inFile.read(buf, 0, BUFFER_SIZE);
116 while (len > 0) {
117 tempDTD.append(buf, 0, len);
118 len = inFile.read(buf, 0, BUFFER_SIZE);
119 }
120
121 } catch (EOFException e) {
122 // Dont do anything. this is A-OK. For some odd reason, java.io
123 // will sometimes throw an EOF instead of just returning a -1.
124 } catch (Exception e) {
125 throw(e);
126 }
127
128 // Set up a resolver from which the XML parser can get our DTD
129 myDTD = tempDTD.toString();
130
131 myResolver = new XmlCompilerResolver(dtdURI, myDTD);
132
133 // Prepare the XML document builder and parser
134 builder = new XmlDocumentBuilder();
135 parser = new ValidatingParser();
136 parser.setDocumentHandler(builder);
137 parser.setEntityResolver(myResolver);
138 }
139
140 /**
141 * Compile a stream into a new Sim object. It will abort on a major error
142 * and return a null instead of a Sim instance. Any compile errors or
143 * warnings can be found in the errors field.
144 *
145 * @param is An input stream to the text that is to be compiled.
146 * @return a reference to the target object.
147 *
148 * @see autohit.Sim
149 */
150 public Object compile(InputStream is) {
151
152 XmlDocument parsedXML;
153
154 Object objectCode = null;
155
156 // Any exception aborts the compile
157 try {
158
159 // Start fresh
160 err = new XmlParseErrorHandler();
161 parser.setErrorHandler(err);
162
163 // Drive the parser and build the document tree.
164 parser.parse(new InputSource(is));
165
166 parsedXML = builder.getDocument();
167
168 // DEBUG
169 //parsedXML.write (System.out);
170
171 objectCode = build(parsedXML);
172
173
174 } catch (Exception e) {
175 objectCode = null; // leave the objectCode as null;
176 }
177
178 return objectCode;
179 }
180
181 /**
182 * Abstract build method. Override with a method that builds the object code
183 * from the XML parse tree.
184 *
185 * @param xd A parsed XML document.
186 *
187 * @return Object reference to the object code.
188 */
189 public abstract Object build(XmlDocument xd);
190
191
192 // --- PRIVATE METHODS ---------------------------------------------------
193
194
195
196 // --- INTERNAL CLASSES ---------------------------------------------------
197
198 }
|