finished 19 (not fully tested...)
[williamcminus.git] / assign3 / src / CMinus.java
blobecadd28c4ac79e3e51afb812f29eb31ade59d409
1 import wci.backend.Backend;
2 import wci.backend.BackendFactory;
3 import wci.frontend.FrontendFactory;
4 import wci.frontend.Parser;
5 import wci.frontend.Source;
6 import wci.intermediate.ICode;
7 import wci.intermediate.SymTabStack;
8 import wci.message.Message;
9 import wci.message.MessageListener;
10 import wci.message.MessageType;
11 import wci.util.CrossReferencer;
12 import wci.util.ParseTreePrinter;
14 import java.io.BufferedReader;
15 import java.io.FileReader;
17 /**
18 * <h1>Pascal</h1>
20 * <p>Compile or interpret a Pascal source program.</p>
22 * <p>Copyright (c) 2009 by Ronald Mak</p>
23 * <p>For instructional purposes only. No warranties.</p>
25 public class CMinus
27 private Parser parser; // language-independent parser
28 private Source source; // language-independent scanner
29 private ICode iCode; // generated intermediate code
30 private SymTabStack symTabStack; // symbol table stack
31 private Backend backend; // backend
33 /**
34 * Compile or interpret a Pascal source program.
35 * @param operation either "compile" or "execute".
36 * @param filePath the source file path.
37 * @param flags the command line flags.
39 public CMinus(String operation, String filePath, String flags)
41 try {
42 boolean intermediate = flags.indexOf('i') > -1;
43 boolean xref = flags.indexOf('x') > -1;
45 source = new Source(new BufferedReader(new FileReader(filePath)));
46 source.addMessageListener(new SourceMessageListener());
48 parser = FrontendFactory.createParser("CMinus", "top-down", source);
49 parser.addMessageListener(new ParserMessageListener());
51 backend = BackendFactory.createBackend(operation);
52 backend.addMessageListener(new BackendMessageListener());
54 parser.parse();
55 source.close();
57 if (parser.getErrorCount() == 0) {
58 iCode = parser.getICode();
59 symTabStack = parser.getSymTabStack();
61 if (xref) {
62 CrossReferencer crossReferencer = new CrossReferencer();
63 crossReferencer.print(symTabStack);
66 if (intermediate) {
67 ParseTreePrinter treePrinter =
68 new ParseTreePrinter(System.out);
69 treePrinter.print(iCode);
72 backend.process(iCode, symTabStack);
75 catch (Exception ex) {
76 System.out.println("***** Internal translator error. *****");
77 ex.printStackTrace();
81 private static final String FLAGS = "[-ix]";
82 private static final String USAGE =
83 "Usage: Pascal execute|compile " + FLAGS + " <source file path>";
85 /**
86 * The main method.
87 * @param args command-line arguments: "compile" or "execute" followed by
88 * optional flags followed by the source file path.
90 public static void main(String args[])
92 try {
93 String operation = args[0];
95 // Operation.
96 if (!( operation.equalsIgnoreCase("compile")
97 || operation.equalsIgnoreCase("execute"))) {
98 throw new Exception();
101 int i = 0;
102 String flags = "";
104 // Flags.
105 while ((++i < args.length) && (args[i].charAt(0) == '-')) {
106 flags += args[i].substring(1);
109 // Source path.
110 if (i < args.length) {
111 String path = args[i];
112 new CMinus(operation, path, flags);
114 else {
115 throw new Exception();
118 catch (Exception ex) {
119 System.out.println(USAGE);
123 private static final String SOURCE_LINE_FORMAT = "%03d %s";
126 * Listener for source messages.
128 private class SourceMessageListener implements MessageListener
131 * Called by the source whenever it produces a message.
132 * @param message the message.
134 public void messageReceived(Message message)
136 MessageType type = message.getType();
137 Object body[] = (Object []) message.getBody();
139 switch (type) {
141 case SOURCE_LINE: {
142 int lineNumber = (Integer) body[0];
143 String lineText = (String) body[1];
145 System.out.println(String.format(SOURCE_LINE_FORMAT,
146 lineNumber, lineText));
147 break;
153 private static final String PARSER_SUMMARY_FORMAT =
154 "\n%,20d source lines." +
155 "\n%,20d syntax errors." +
156 "\n%,20.2f seconds total parsing time.\n";
158 private static final int PREFIX_WIDTH = 5;
161 * Listener for parser messages.
163 private class ParserMessageListener implements MessageListener
166 * Called by the parser whenever it produces a message.
167 * @param message the message.
169 public void messageReceived(Message message)
171 MessageType type = message.getType();
173 switch (type) {
175 case PARSER_SUMMARY: {
176 Number body[] = (Number[]) message.getBody();
177 int statementCount = (Integer) body[0];
178 int syntaxErrors = (Integer) body[1];
179 float elapsedTime = (Float) body[2];
181 System.out.printf(PARSER_SUMMARY_FORMAT,
182 statementCount, syntaxErrors,
183 elapsedTime);
184 break;
187 case SYNTAX_ERROR: {
188 Object body[] = (Object []) message.getBody();
189 int lineNumber = (Integer) body[0];
190 int position = (Integer) body[1];
191 String tokenText = (String) body[2];
192 String errorMessage = (String) body[3];
194 int spaceCount = PREFIX_WIDTH + position;
195 StringBuilder flagBuffer = new StringBuilder();
197 // Spaces up to the error position.
198 for (int i = 1; i < spaceCount; ++i) {
199 flagBuffer.append(' ');
202 // A pointer to the error followed by the error message.
203 flagBuffer.append("^\n*** ").append(errorMessage);
205 // Text, if any, of the bad token.
206 if (tokenText != null) {
207 flagBuffer.append(" [at \"").append(tokenText)
208 .append("\"]");
211 System.out.println(flagBuffer.toString());
212 break;
218 private static final String INTERPRETER_SUMMARY_FORMAT =
219 "\n%,20d statements executed." +
220 "\n%,20d runtime errors." +
221 "\n%,20.2f seconds total execution time.\n";
223 private static final String COMPILER_SUMMARY_FORMAT =
224 "\n%,20d instructions generated." +
225 "\n%,20.2f seconds total code generation time.\n";
228 * Listener for back end messages.
230 private class BackendMessageListener implements MessageListener
233 * Called by the back end whenever it produces a message.
234 * @param message the message.
236 public void messageReceived(Message message)
238 MessageType type = message.getType();
240 switch (type) {
242 case INTERPRETER_SUMMARY: {
243 Number body[] = (Number[]) message.getBody();
244 int executionCount = (Integer) body[0];
245 int runtimeErrors = (Integer) body[1];
246 float elapsedTime = (Float) body[2];
248 System.out.printf(INTERPRETER_SUMMARY_FORMAT,
249 executionCount, runtimeErrors,
250 elapsedTime);
251 break;
254 case COMPILER_SUMMARY: {
255 Number body[] = (Number[]) message.getBody();
256 int instructionCount = (Integer) body[0];
257 float elapsedTime = (Float) body[1];
259 System.out.printf(COMPILER_SUMMARY_FORMAT,
260 instructionCount, elapsedTime);
261 break;