finished 19 (not fully tested...)
[williamcminus.git] / assign3 / src / Pascal.java
blobe811efb2617d166d40abefe205ec0f4f74529cb7
1 import java.io.BufferedReader;
2 import java.io.FileReader;
4 import wci.frontend.*;
5 import wci.intermediate.*;
6 import wci.backend.*;
7 import wci.message.*;
8 import wci.util.*;
10 import static wci.message.MessageType.*;
12 /**
13 * <h1>Pascal</h1>
15 * <p>Compile or interpret a Pascal source program.</p>
17 * <p>Copyright (c) 2009 by Ronald Mak</p>
18 * <p>For instructional purposes only. No warranties.</p>
20 public class Pascal
22 private Parser parser; // language-independent parser
23 private Source source; // language-independent scanner
24 private ICode iCode; // generated intermediate code
25 private SymTabStack symTabStack; // symbol table stack
26 private Backend backend; // backend
28 /**
29 * Compile or interpret a Pascal source program.
30 * @param operation either "compile" or "execute".
31 * @param filePath the source file path.
32 * @param flags the command line flags.
34 public Pascal(String operation, String filePath, String flags)
36 try {
37 boolean intermediate = flags.indexOf('i') > -1;
38 boolean xref = flags.indexOf('x') > -1;
40 source = new Source(new BufferedReader(new FileReader(filePath)));
41 source.addMessageListener(new SourceMessageListener());
43 parser = FrontendFactory.createParser("Pascal", "top-down", source);
44 parser.addMessageListener(new ParserMessageListener());
46 backend = BackendFactory.createBackend(operation);
47 backend.addMessageListener(new BackendMessageListener());
49 parser.parse();
50 source.close();
52 if (parser.getErrorCount() == 0) {
53 iCode = parser.getICode();
54 symTabStack = parser.getSymTabStack();
56 if (xref) {
57 CrossReferencer crossReferencer = new CrossReferencer();
58 crossReferencer.print(symTabStack);
61 if (intermediate) {
62 ParseTreePrinter treePrinter =
63 new ParseTreePrinter(System.out);
64 treePrinter.print(iCode);
67 backend.process(iCode, symTabStack);
70 catch (Exception ex) {
71 System.out.println("***** Internal translator error. *****");
72 ex.printStackTrace();
76 private static final String FLAGS = "[-ix]";
77 private static final String USAGE =
78 "Usage: Pascal execute|compile " + FLAGS + " <source file path>";
80 /**
81 * The main method.
82 * @param args command-line arguments: "compile" or "execute" followed by
83 * optional flags followed by the source file path.
85 public static void main(String args[])
87 try {
88 String operation = args[0];
90 // Operation.
91 if (!( operation.equalsIgnoreCase("compile")
92 || operation.equalsIgnoreCase("execute"))) {
93 throw new Exception();
96 int i = 0;
97 String flags = "";
99 // Flags.
100 while ((++i < args.length) && (args[i].charAt(0) == '-')) {
101 flags += args[i].substring(1);
104 // Source path.
105 if (i < args.length) {
106 String path = args[i];
107 new Pascal(operation, path, flags);
109 else {
110 throw new Exception();
113 catch (Exception ex) {
114 System.out.println(USAGE);
118 private static final String SOURCE_LINE_FORMAT = "%03d %s";
121 * Listener for source messages.
123 private class SourceMessageListener implements MessageListener
126 * Called by the source whenever it produces a message.
127 * @param message the message.
129 public void messageReceived(Message message)
131 MessageType type = message.getType();
132 Object body[] = (Object []) message.getBody();
134 switch (type) {
136 case SOURCE_LINE: {
137 int lineNumber = (Integer) body[0];
138 String lineText = (String) body[1];
140 System.out.println(String.format(SOURCE_LINE_FORMAT,
141 lineNumber, lineText));
142 break;
148 private static final String PARSER_SUMMARY_FORMAT =
149 "\n%,20d source lines." +
150 "\n%,20d syntax errors." +
151 "\n%,20.2f seconds total parsing time.\n";
153 private static final int PREFIX_WIDTH = 5;
156 * Listener for parser messages.
158 private class ParserMessageListener implements MessageListener
161 * Called by the parser whenever it produces a message.
162 * @param message the message.
164 public void messageReceived(Message message)
166 MessageType type = message.getType();
168 switch (type) {
170 case PARSER_SUMMARY: {
171 Number body[] = (Number[]) message.getBody();
172 int statementCount = (Integer) body[0];
173 int syntaxErrors = (Integer) body[1];
174 float elapsedTime = (Float) body[2];
176 System.out.printf(PARSER_SUMMARY_FORMAT,
177 statementCount, syntaxErrors,
178 elapsedTime);
179 break;
182 case SYNTAX_ERROR: {
183 Object body[] = (Object []) message.getBody();
184 int lineNumber = (Integer) body[0];
185 int position = (Integer) body[1];
186 String tokenText = (String) body[2];
187 String errorMessage = (String) body[3];
189 int spaceCount = PREFIX_WIDTH + position;
190 StringBuilder flagBuffer = new StringBuilder();
192 // Spaces up to the error position.
193 for (int i = 1; i < spaceCount; ++i) {
194 flagBuffer.append(' ');
197 // A pointer to the error followed by the error message.
198 flagBuffer.append("^\n*** ").append(errorMessage);
200 // Text, if any, of the bad token.
201 if (tokenText != null) {
202 flagBuffer.append(" [at \"").append(tokenText)
203 .append("\"]");
206 System.out.println(flagBuffer.toString());
207 break;
213 private static final String INTERPRETER_SUMMARY_FORMAT =
214 "\n%,20d statements executed." +
215 "\n%,20d runtime errors." +
216 "\n%,20.2f seconds total execution time.\n";
218 private static final String COMPILER_SUMMARY_FORMAT =
219 "\n%,20d instructions generated." +
220 "\n%,20.2f seconds total code generation time.\n";
223 * Listener for back end messages.
225 private class BackendMessageListener implements MessageListener
228 * Called by the back end whenever it produces a message.
229 * @param message the message.
231 public void messageReceived(Message message)
233 MessageType type = message.getType();
235 switch (type) {
237 case INTERPRETER_SUMMARY: {
238 Number body[] = (Number[]) message.getBody();
239 int executionCount = (Integer) body[0];
240 int runtimeErrors = (Integer) body[1];
241 float elapsedTime = (Float) body[2];
243 System.out.printf(INTERPRETER_SUMMARY_FORMAT,
244 executionCount, runtimeErrors,
245 elapsedTime);
246 break;
249 case COMPILER_SUMMARY: {
250 Number body[] = (Number[]) message.getBody();
251 int instructionCount = (Integer) body[0];
252 float elapsedTime = (Float) body[1];
254 System.out.printf(COMPILER_SUMMARY_FORMAT,
255 instructionCount, elapsedTime);
256 break;