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
;
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>
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
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
)
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());
57 if (parser
.getErrorCount() == 0) {
58 iCode
= parser
.getICode();
59 symTabStack
= parser
.getSymTabStack();
62 CrossReferencer crossReferencer
= new CrossReferencer();
63 crossReferencer
.print(symTabStack
);
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. *****");
81 private static final String FLAGS
= "[-ix]";
82 private static final String USAGE
=
83 "Usage: Pascal execute|compile " + FLAGS
+ " <source file path>";
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
[])
93 String operation
= args
[0];
96 if (!( operation
.equalsIgnoreCase("compile")
97 || operation
.equalsIgnoreCase("execute"))) {
98 throw new Exception();
105 while ((++i
< args
.length
) && (args
[i
].charAt(0) == '-')) {
106 flags
+= args
[i
].substring(1);
110 if (i
< args
.length
) {
111 String path
= args
[i
];
112 new CMinus(operation
, path
, flags
);
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();
142 int lineNumber
= (Integer
) body
[0];
143 String lineText
= (String
) body
[1];
145 System
.out
.println(String
.format(SOURCE_LINE_FORMAT
,
146 lineNumber
, lineText
));
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();
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
,
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
)
211 System
.out
.println(flagBuffer
.toString());
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();
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
,
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
);