001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2005-2007 Robert Grimm, Princeton University
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.lang.c4;
020:
021: import java.lang.reflect.Method;
022:
023: import java.io.BufferedReader;
024: import java.io.BufferedWriter;
025: import java.io.File;
026: import java.io.FileNotFoundException;
027: import java.io.FileReader;
028: import java.io.IOException;
029: import java.io.OutputStreamWriter;
030: import java.io.Reader;
031:
032: import xtc.Constants;
033:
034: import xtc.tree.GNode;
035: import xtc.tree.Printer;
036:
037: import xtc.util.Statistics;
038:
039: import xtc.parser.Result;
040: import xtc.parser.SemanticValue;
041: import xtc.parser.ParseError;
042:
043: import xtc.lang.CCounter;
044: import xtc.lang.CPrinter;
045:
046: /**
047: * The driver for C4.
048: *
049: * @author Robert Grimm
050: * @author Marco Yuen
051: * @version $Revision: 1.6 $
052: */
053: public final class C4Driver {
054:
055: /** The number of warm-up runs for collecting statistics. */
056: private static final int WARM_UP_RUNS = 2;
057:
058: /** The total number of runs for collecting statistics. */
059: private static final int TOTAL_RUNS = 22;
060:
061: /** The flag for an erroneous execution. */
062: private static boolean error = false;
063:
064: /** The option for incremental parsing. */
065: private static boolean optionIncremental = true;
066:
067: /** The option for performing GC. */
068: private static boolean optionGC = false;
069:
070: /** The option for printing AST statistics. */
071: private static boolean optionASTStats = false;
072:
073: /** The option for printing the AST in generic form. */
074: private static boolean optionPrintAST = false;
075:
076: /** The option for printing the AST in C source form. */
077: private static boolean optionPrint = false;
078:
079: /** The option for collecting parsing statistics. */
080: private static boolean optionStats = false;
081:
082: /** The option for printing parsing statistics in table form. */
083: private static boolean optionTable = false;
084:
085: /** The option for printing the memoization table. */
086: private static boolean optionPrintTable = false;
087:
088: /** The option for invoking the Aspect Transformer. */
089: private static boolean optionAspectTransformer = false;
090:
091: /** The file sizes (in KB). */
092: private static Statistics fileSizes = null;
093:
094: /** The average latencies (in ms). */
095: private static Statistics latencies = null;
096:
097: /** The average heap utilizations (in KB). */
098: private static Statistics heapSizes = null;
099:
100: /** The method for printing the memoization table. */
101: private static Method dump = null;
102:
103: /** Hide the constructor. */
104: private C4Driver() {
105: }
106:
107: /**
108: * Report a parse error.
109: *
110: * @param err The parse error.
111: * @param parser The C parser.
112: * @throws IOException Signals an exceptional condition while
113: * accessing the parser.
114: */
115: private static void error(ParseError err, C4Parser parser)
116: throws IOException {
117:
118: System.err.println();
119: System.err.print(parser.format(err));
120: error = true;
121: }
122:
123: /**
124: * Process the specified C file.
125: *
126: * @param file The file name.
127: * @throws Exception Signals an exceptional condition.
128: */
129: private static void process(String file) throws Exception {
130: final long fileSize = new File(file).length();
131: Reader in = null;
132:
133: if (Integer.MAX_VALUE < fileSize) {
134: throw new IllegalArgumentException("File too large");
135: }
136:
137: try {
138: // Set up for collecting statistics.
139: Statistics time = null;
140: Statistics memory = null;
141: int iterations = 1;
142:
143: if (optionStats) {
144: time = new Statistics();
145: memory = new Statistics();
146: iterations = TOTAL_RUNS;
147: fileSizes.add((double) fileSize / 1024.0);
148: }
149:
150: for (int i = 0; i < iterations; i++) {
151: // Open file.
152: in = new BufferedReader(new FileReader(file));
153:
154: // Perform GC if requested.
155: if (optionGC) {
156: System.gc();
157: }
158:
159: // Set up the statistics for this run.
160: long startTime = 0;
161: long startMemory = 0;
162:
163: if (optionStats) {
164: startMemory = Runtime.getRuntime().freeMemory();
165: startTime = System.currentTimeMillis();
166: }
167:
168: // Do the actual parsing.
169: C4Parser parser = new C4Parser(in, file, (int) fileSize);
170: GNode root = null;
171:
172: if (optionIncremental) {
173: root = GNode.create("TranslationUnit");
174: boolean first = true;
175:
176: while (!parser.isEOF(0)) {
177: Result result = null;
178:
179: if (first) {
180: result = parser.pPrelude(0);
181: } else {
182: result = parser.pExternalDeclaration(0);
183: }
184:
185: if (!result.hasValue()) {
186: error((ParseError) result, parser);
187: return;
188: }
189:
190: if (first) {
191: first = false;
192: } else {
193: root.add(((SemanticValue) result).value);
194: }
195: parser.resetTo(result.index);
196: }
197:
198: // Grab any trailing annotations.
199: Result result = parser.pAnnotations(0);
200: if (!result.hasValue()) {
201: error((ParseError) result, parser);
202: return;
203: }
204: root.add(((SemanticValue) result).value);
205:
206: } else {
207: Result result = parser.pTranslationUnit(0);
208: if (!result.hasValue()) {
209: error((ParseError) result, parser);
210: return;
211: }
212: root = (GNode) ((SemanticValue) result).value;
213: }
214:
215: // Transform Aspect constructs to C.
216: if (optionAspectTransformer) {
217: System.err
218: .println("Invoking AspectTransformer ...");
219: new AspectTransformer(root).transform();
220: }
221:
222: // Print program statistics.
223: if (optionASTStats) {
224: CCounter counter = new CCounter();
225: counter.dispatch(root);
226: Printer printer = new Printer(new BufferedWriter(
227: new OutputStreamWriter(System.out)));
228: counter.print(printer);
229: printer.flush();
230: }
231:
232: // Print the result.
233: if (optionPrint || optionPrintAST || optionPrintTable) {
234: Printer printer = new Printer(new BufferedWriter(
235: new OutputStreamWriter(System.out)));
236:
237: if (optionPrintAST) {
238: printer.format(root).pln();
239: }
240: if (optionPrint) {
241: new CPrinter(printer).dispatch(root);
242: }
243: if (optionPrintTable) {
244: dump.invoke(parser, new Object[] { printer });
245: }
246:
247: printer.flush();
248: }
249:
250: // Collect the statistics for this run.
251: if (optionStats) {
252: long endTime = System.currentTimeMillis();
253: long endMemory = Runtime.getRuntime().freeMemory();
254:
255: if (i >= WARM_UP_RUNS) {
256: time.add(endTime - startTime);
257: memory.add(startMemory - endMemory);
258: }
259: }
260:
261: // Close the input stream.
262: in.close();
263: }
264:
265: // Print the statistics.
266: if (optionStats) {
267: double latency = time.mean();
268: double heapSize = memory.mean();
269:
270: latencies.add(latency);
271: heapSizes.add(heapSize / 1024.0);
272:
273: if (optionTable) {
274: System.out.println(file + " " + fileSize + " "
275: + Statistics.round(latency) + " "
276: + time.median() + " "
277: + Statistics.round(time.stdev()) + " "
278: + Statistics.round(heapSize) + " "
279: + memory.median() + " "
280: + Statistics.round(memory.stdev()));
281: } else {
282: System.out.println(" file size : " + fileSize);
283: System.out.println(" time mean : "
284: + Statistics.round(latency));
285: System.out.println(" time median : "
286: + time.median());
287: System.out.println(" time stdev : "
288: + Statistics.round(time.stdev()));
289: System.out.println(" memory mean : "
290: + Statistics.round(heapSize));
291: System.out.println(" memory median : "
292: + memory.median());
293: System.out.println(" memory stdev : "
294: + Statistics.round(memory.stdev()));
295: }
296: }
297:
298: } finally {
299: // Clean up.
300: if (null != in) {
301: try {
302: in.close();
303: } catch (Exception x) {
304: }
305: }
306: }
307: }
308:
309: /**
310: * Run the driver with the specified arguments.
311: *
312: * @param args The command line arguments.
313: */
314: public static void main(String[] args) {
315: System.err.print("C4 Parser Driver Version ");
316: System.err.print(Constants.VERSION);
317: System.err.print(" ");
318: System.err.println(Constants.COPY);
319:
320: if ((null == args) || (0 == args.length)) {
321: System.err.println();
322: System.err.println("Usage: <option>* <file-name>+");
323: System.err.println();
324: System.err.println("Options are:");
325: System.err
326: .println(" -noincr Do not parse incrementally.");
327: System.err
328: .println(" -gc Perform GC before parsing a file.");
329: System.err
330: .println(" -aststats Collect and print AST statistics.");
331: System.err
332: .println(" -ast Print the AST in generic form.");
333: System.err
334: .println(" -source Print the AST in C source form.");
335: System.err.println(" -at Transform Aspect to C.");
336: System.err
337: .println(" -stats Collect and print performance "
338: + "statistics.");
339: System.err
340: .println(" -table Print performance statistics as a "
341: + "table.");
342: System.err
343: .println(" -memo Print the memoization table.");
344: System.err.println();
345: System.exit(1);
346: }
347:
348: int start = -1;
349: error = false;
350:
351: // Process options.
352: for (int i = 0; i < args.length; i++) {
353: if (args[i].startsWith("-")) {
354: if ("-noincr".equals(args[i])) {
355: optionIncremental = false;
356:
357: } else if ("-gc".equals(args[i])) {
358: optionGC = true;
359:
360: } else if ("-aststats".equals(args[i])) {
361: optionASTStats = true;
362:
363: } else if ("-ast".equals(args[i])) {
364: optionPrintAST = true;
365:
366: } else if ("-source".equals(args[i])) {
367: optionPrint = true;
368:
369: } else if ("-at".equals(args[i])) {
370: optionAspectTransformer = true;
371:
372: } else if ("-stats".equals(args[i])) {
373: optionStats = true;
374:
375: } else if ("-table".equals(args[i])) {
376: optionTable = true;
377:
378: } else if ("-memo".equals(args[i])) {
379: // Find method for printing the memoization table.
380: try {
381: dump = C4Parser.class.getMethod("dump",
382: new Class[] { Printer.class });
383: } catch (Exception x) {
384: System.err
385: .println("Parser cannot print memoization table."
386: + " Rebuild with dumpTable option.");
387: error = true;
388: }
389:
390: optionPrintTable = true;
391:
392: } else {
393: System.err
394: .println("Unrecognized option " + args[i]);
395: error = true;
396: }
397:
398: } else {
399: start = i;
400: break;
401: }
402: }
403:
404: if (-1 == start) {
405: System.err.println("No file names specified");
406: error = true;
407: }
408:
409: if (error) {
410: System.exit(1);
411: }
412:
413: if (optionStats) {
414: fileSizes = new Statistics();
415: latencies = new Statistics();
416: heapSizes = new Statistics();
417:
418: if (optionTable) {
419: System.out
420: .println("Legend: File, size, time (ave, med, stdev), "
421: + "memory (ave, med, stdev)");
422: System.out.println();
423: }
424: }
425:
426: // Process files.
427: error = false;
428:
429: for (int i = start; i < args.length; i++) {
430: if (!(optionStats && optionTable)) {
431: System.err.println("Processing " + args[i] + " ...");
432: }
433: try {
434: process(args[i]);
435: } catch (Throwable x) {
436: error = true;
437:
438: while (null != x.getCause()) {
439: x = x.getCause();
440: }
441: if (x instanceof FileNotFoundException) {
442: System.err.println(x.getMessage());
443: } else {
444: x.printStackTrace();
445: }
446: }
447: }
448:
449: if (optionStats) {
450: double time = 1000.0 / Statistics.fitSlope(fileSizes,
451: latencies);
452: double memory = Statistics.fitSlope(fileSizes, heapSizes);
453:
454: System.out.println();
455: System.out.println("Overall performance : "
456: + Statistics.round(time) + " KB/s");
457: System.out.println("Overall heap utilization : "
458: + Statistics.round(memory) + ":1");
459: }
460:
461: // Return the right status code.
462: if (error) {
463: System.exit(1);
464: } else {
465: System.exit(0);
466: }
467: }
468:
469: }
|