1 import java
.io
.BufferedReader
;
2 import java
.io
.FileReader
;
5 import wci
.intermediate
.*;
10 import static wci
.message
.MessageType
.*;
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>
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
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
)
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());
52 if (parser
.getErrorCount() == 0) {
53 iCode
= parser
.getICode();
54 symTabStack
= parser
.getSymTabStack();
57 CrossReferencer crossReferencer
= new CrossReferencer();
58 crossReferencer
.print(symTabStack
);
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. *****");
76 private static final String FLAGS
= "[-ix]";
77 private static final String USAGE
=
78 "Usage: Pascal execute|compile " + FLAGS
+ " <source file path>";
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
[])
88 String operation
= args
[0];
91 if (!( operation
.equalsIgnoreCase("compile")
92 || operation
.equalsIgnoreCase("execute"))) {
93 throw new Exception();
100 while ((++i
< args
.length
) && (args
[i
].charAt(0) == '-')) {
101 flags
+= args
[i
].substring(1);
105 if (i
< args
.length
) {
106 String path
= args
[i
];
107 new Pascal(operation
, path
, flags
);
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();
137 int lineNumber
= (Integer
) body
[0];
138 String lineText
= (String
) body
[1];
140 System
.out
.println(String
.format(SOURCE_LINE_FORMAT
,
141 lineNumber
, lineText
));
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();
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
,
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
)
206 System
.out
.println(flagBuffer
.toString());
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();
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
,
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
);