]>
Commit | Line | Data |
---|---|---|
a945c346 | 1 | (* Copyright (C) 2015-2024 Free Software Foundation, Inc. |
1eee94d3 GM |
2 | This file is part of GNU Modula-2. |
3 | ||
4 | GNU Modula-2 is free software; you can redistribute it and/or modify it under | |
5 | the terms of the GNU General Public License as published by the Free | |
6 | Software Foundation; either version 3, or (at your option) any later | |
7 | version. | |
8 | ||
9 | GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY | |
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 | for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License along | |
15 | with gm2; see the file COPYING. If not, write to the Free Software | |
16 | Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) | |
17 | ||
18 | IMPLEMENTATION MODULE mcComp ; | |
19 | ||
20 | ||
21 | FROM FIO IMPORT StdErr ; | |
22 | FROM libc IMPORT exit ; | |
23 | ||
24 | FROM decl IMPORT node, isNodeF, isDef, isImp, isModule, isMainModule, | |
25 | setMainModule, setCurrentModule, getSource, isImpOrModule, | |
26 | lookupDef, lookupModule, lookupImp, setSource, getSymName, | |
27 | foreachDefModuleDo, foreachModModuleDo, | |
28 | getMainModule, out, hasHidden, | |
29 | setVisited, unsetVisited, isVisited ; | |
30 | ||
31 | FROM symbolKey IMPORT performOperation ; | |
32 | ||
33 | FROM SYSTEM IMPORT ADDRESS ; | |
34 | FROM mcReserved IMPORT toktype ; | |
35 | FROM mcSearch IMPORT findSourceDefFile, findSourceModFile ; | |
36 | FROM mcLexBuf IMPORT openSource, closeSource, currenttoken, getToken, reInitialize, currentstring ; | |
37 | FROM mcFileName IMPORT calculateFileName ; | |
38 | FROM mcPreprocess IMPORT preprocessModule ; | |
39 | ||
40 | FROM FormatStrings IMPORT Sprintf1 ; | |
41 | ||
42 | IMPORT mcflex ; | |
43 | IMPORT mcp1 ; | |
44 | IMPORT mcp2 ; | |
45 | IMPORT mcp3 ; | |
46 | IMPORT mcp4 ; | |
47 | IMPORT mcp5 ; | |
48 | IMPORT mcComment ; | |
49 | ||
50 | ||
51 | FROM mcError IMPORT writeFormat0, flushErrors, flushWarnings ; | |
52 | FROM nameKey IMPORT Name, NulName, getKey, keyToCharStar, makekey ; | |
53 | FROM mcPrintf IMPORT fprintf1 ; | |
54 | FROM mcQuiet IMPORT qprintf0, qprintf1, qprintf2 ; | |
55 | FROM DynamicStrings IMPORT String, InitString, KillString, InitStringCharStar, Dup, Mark, string ; | |
56 | FROM mcOptions IMPORT getExtendedOpaque ; | |
57 | ||
58 | CONST | |
59 | Debugging = FALSE ; | |
60 | ||
61 | TYPE | |
62 | parserFunction = PROCEDURE () : BOOLEAN ; | |
63 | openFunction = PROCEDURE (node, BOOLEAN) : BOOLEAN ; | |
64 | ||
65 | VAR | |
66 | currentPass: CARDINAL ; | |
67 | ||
68 | ||
69 | (* | |
70 | doCompile - translate file, s, using a 6 pass technique. | |
71 | *) | |
72 | ||
73 | PROCEDURE doCompile (s: String) ; | |
74 | VAR | |
75 | n: node ; | |
76 | BEGIN | |
77 | n := initParser (s) ; | |
78 | doPass (TRUE, TRUE, 1, p1, 'lexical analysis, modules, root decls and C preprocessor') ; | |
79 | doPass (TRUE, TRUE, 2, p2, '[all modules] type equivalence and enumeration types') ; | |
80 | doPass (TRUE, TRUE, 3, p3, '[all modules] import lists, types, variables and procedure declarations') ; | |
81 | doPass (TRUE, TRUE, 4, p4, '[all modules] constant expressions') ; | |
82 | ||
83 | IF NOT isDef (n) | |
84 | THEN | |
85 | IF isImp (n) | |
86 | THEN | |
87 | qprintf0 ('Parse implementation module\n') ; | |
88 | doPass (FALSE, TRUE, 5, p5, '[implementation module] build code tree for all procedures and module initializations') | |
89 | ELSE | |
90 | qprintf0 ('Parse program module\n') ; | |
91 | doPass (FALSE, TRUE, 5, p5, '[program module] build code tree for all procedures and module initializations') | |
92 | END ; | |
93 | END ; | |
94 | ||
95 | qprintf0 ('walk tree converting it to C/C++\n') ; | |
96 | out | |
97 | END doCompile ; | |
98 | ||
99 | ||
100 | (* | |
101 | compile - check, s, is non NIL before calling doCompile. | |
102 | *) | |
103 | ||
104 | PROCEDURE compile (s: String) ; | |
105 | BEGIN | |
106 | IF s#NIL | |
107 | THEN | |
108 | doCompile (s) | |
109 | END | |
110 | END compile ; | |
111 | ||
112 | ||
113 | (* | |
114 | examineCompilationUnit - opens the source file to obtain the module name and kind of module. | |
115 | *) | |
116 | ||
117 | PROCEDURE examineCompilationUnit () : node ; | |
118 | BEGIN | |
119 | (* stop if we see eof, ';' or '[' *) | |
120 | WHILE (currenttoken#eoftok) AND (currenttoken#semicolontok) AND (currenttoken#lsbratok) DO | |
121 | IF currenttoken=definitiontok | |
122 | THEN | |
123 | getToken ; | |
124 | IF currenttoken=moduletok | |
125 | THEN | |
126 | getToken ; | |
127 | IF currenttoken=fortok | |
128 | THEN | |
129 | getToken ; | |
130 | IF currenttoken=stringtok | |
131 | THEN | |
132 | getToken | |
133 | ELSE | |
134 | mcflex.mcError (string (InitString ('expecting language string after FOR keyword'))) ; | |
135 | exit (1) | |
136 | END | |
137 | END ; | |
138 | IF currenttoken=identtok | |
139 | THEN | |
140 | RETURN lookupDef (makekey (currentstring)) | |
141 | END | |
142 | ELSE | |
143 | mcflex.mcError (string (InitString ('MODULE missing after DEFINITION keyword'))) | |
144 | END | |
145 | ELSIF currenttoken=implementationtok | |
146 | THEN | |
147 | getToken ; | |
148 | IF currenttoken=moduletok | |
149 | THEN | |
150 | getToken ; | |
151 | IF currenttoken=identtok | |
152 | THEN | |
153 | RETURN lookupImp (makekey (currentstring)) | |
154 | END | |
155 | ELSE | |
156 | mcflex.mcError (string (InitString ('MODULE missing after IMPLEMENTATION keyword'))) | |
157 | END | |
158 | ELSIF currenttoken=moduletok | |
159 | THEN | |
160 | getToken ; | |
161 | IF currenttoken=identtok | |
162 | THEN | |
163 | RETURN lookupModule (makekey (currentstring)) | |
164 | END | |
165 | END ; | |
166 | getToken | |
167 | END ; | |
168 | mcflex.mcError (string (InitString ('failed to find module name'))) ; | |
169 | exit (1) | |
170 | END examineCompilationUnit ; | |
171 | ||
172 | ||
173 | (* | |
174 | peepInto - peeps into source, s, and initializes a definition/implementation or | |
175 | program module accordingly. | |
176 | *) | |
177 | ||
178 | PROCEDURE peepInto (s: String) : node ; | |
179 | VAR | |
180 | n : node ; | |
181 | fileName: String ; | |
182 | BEGIN | |
183 | fileName := preprocessModule (s) ; | |
184 | IF openSource (fileName) | |
185 | THEN | |
186 | n := examineCompilationUnit () ; | |
187 | setSource (n, makekey (string (fileName))) ; | |
188 | setMainModule (n) ; | |
189 | closeSource ; | |
190 | reInitialize ; | |
191 | RETURN n | |
192 | ELSE | |
193 | fprintf1 (StdErr, 'failed to open %s\n', s) ; | |
194 | exit (1) | |
195 | END | |
196 | END peepInto ; | |
197 | ||
198 | ||
199 | (* | |
200 | initParser - returns the node of the module found in the source file. | |
201 | *) | |
202 | ||
203 | PROCEDURE initParser (s: String) : node ; | |
204 | BEGIN | |
205 | qprintf1 ('Compiling: %s\n', s) ; | |
206 | RETURN peepInto (s) | |
207 | END initParser ; | |
208 | ||
209 | ||
210 | (* | |
211 | p1 - wrap the pass procedure with the correct parameter values. | |
212 | *) | |
213 | ||
214 | PROCEDURE p1 (n: node) ; | |
215 | BEGIN | |
216 | IF isDef (n) | |
217 | THEN | |
218 | pass (1, n, mcp1.CompilationUnit, isDef, openDef) ; | |
219 | IF hasHidden (n) AND getExtendedOpaque () | |
220 | THEN | |
221 | pass (1, lookupImp (getSymName (n)), mcp1.CompilationUnit, isImp, openMod) | |
222 | END | |
223 | ELSE | |
224 | pass (1, n, mcp1.CompilationUnit, isImpOrModule, openMod) | |
225 | END | |
226 | END p1 ; | |
227 | ||
228 | ||
229 | (* | |
230 | p2 - wrap the pass procedure with the correct parameter values. | |
231 | *) | |
232 | ||
233 | PROCEDURE p2 (n: node) ; | |
234 | BEGIN | |
235 | IF isDef (n) | |
236 | THEN | |
237 | pass (2, n, mcp2.CompilationUnit, isDef, openDef) ; | |
238 | IF hasHidden (n) AND getExtendedOpaque () | |
239 | THEN | |
240 | pass (2, lookupImp (getSymName (n)), mcp2.CompilationUnit, isImp, openMod) | |
241 | END | |
242 | ELSE | |
243 | pass (2, n, mcp2.CompilationUnit, isImpOrModule, openMod) | |
244 | END | |
245 | END p2 ; | |
246 | ||
247 | ||
248 | (* | |
249 | p3 - wrap the pass procedure with the correct parameter values. | |
250 | *) | |
251 | ||
252 | PROCEDURE p3 (n: node) ; | |
253 | BEGIN | |
254 | IF isDef (n) | |
255 | THEN | |
256 | pass (3, n, mcp3.CompilationUnit, isDef, openDef) ; | |
257 | IF hasHidden (n) AND getExtendedOpaque () | |
258 | THEN | |
259 | pass (3, lookupImp (getSymName (n)), mcp3.CompilationUnit, isImp, openMod) | |
260 | END | |
261 | ELSE | |
262 | pass (3, n, mcp3.CompilationUnit, isImpOrModule, openMod) | |
263 | END | |
264 | END p3 ; | |
265 | ||
266 | ||
267 | (* | |
268 | p4 - wrap the pass procedure with the correct parameter values. | |
269 | *) | |
270 | ||
271 | PROCEDURE p4 (n: node) ; | |
272 | BEGIN | |
273 | IF isDef (n) | |
274 | THEN | |
275 | pass (4, n, mcp4.CompilationUnit, isDef, openDef) ; | |
276 | IF hasHidden (n) AND getExtendedOpaque () | |
277 | THEN | |
278 | pass (4, lookupImp (getSymName (n)), mcp4.CompilationUnit, isImp, openMod) | |
279 | END | |
280 | ELSE | |
281 | pass (4, n, mcp4.CompilationUnit, isImpOrModule, openMod) | |
282 | END | |
283 | END p4 ; | |
284 | ||
285 | ||
286 | (* | |
287 | p5 - wrap the pass procedure with the correct parameter values. | |
288 | *) | |
289 | ||
290 | PROCEDURE p5 (n: node) ; | |
291 | BEGIN | |
292 | pass (5, n, mcp5.CompilationUnit, isImpOrModule, openMod) | |
293 | END p5 ; | |
294 | ||
295 | ||
296 | (* | |
297 | doOpen - | |
298 | *) | |
299 | ||
300 | PROCEDURE doOpen (n: node; symName, fileName: String; exitOnFailure: BOOLEAN) : BOOLEAN ; | |
301 | VAR | |
302 | postProcessed: String ; | |
303 | BEGIN | |
304 | qprintf2(' Module %-20s : %s\n', symName, fileName) ; | |
305 | postProcessed := preprocessModule (fileName) ; | |
306 | setSource (n, makekey (string (postProcessed))) ; | |
307 | setCurrentModule (n) ; | |
308 | IF openSource (postProcessed) | |
309 | THEN | |
310 | RETURN TRUE | |
311 | END ; | |
312 | fprintf1 (StdErr, 'failed to open %s\n', fileName) ; | |
313 | IF exitOnFailure | |
314 | THEN | |
315 | exit (1) | |
316 | END ; | |
317 | RETURN FALSE | |
318 | END doOpen ; | |
319 | ||
320 | ||
321 | (* | |
322 | openDef - try and open the definition module source file. | |
323 | Returns true/false if successful/unsuccessful or | |
324 | exitOnFailure. | |
325 | *) | |
326 | ||
327 | PROCEDURE openDef (n: node; exitOnFailure: BOOLEAN) : BOOLEAN ; | |
328 | VAR | |
329 | sourceName: Name ; | |
330 | symName, | |
331 | fileName : String ; | |
332 | BEGIN | |
333 | sourceName := getSource (n) ; | |
334 | symName := InitStringCharStar (keyToCharStar (getSymName (n))) ; | |
335 | IF sourceName=NulName | |
336 | THEN | |
337 | IF NOT findSourceDefFile (symName, fileName) | |
338 | THEN | |
339 | fprintf1 (StdErr, 'failed to find definition module %s.def\n', symName) ; | |
340 | IF exitOnFailure | |
341 | THEN | |
342 | exit (1) | |
343 | END | |
344 | END | |
345 | ELSE | |
346 | fileName := InitStringCharStar (keyToCharStar (sourceName)) | |
347 | END ; | |
348 | RETURN doOpen (n, symName, fileName, exitOnFailure) | |
349 | END openDef ; | |
350 | ||
351 | ||
352 | (* | |
353 | openMod - try and open the implementation/program module source file. | |
354 | Returns true/false if successful/unsuccessful or | |
355 | exitOnFailure. | |
356 | *) | |
357 | ||
358 | PROCEDURE openMod (n: node; exitOnFailure: BOOLEAN) : BOOLEAN ; | |
359 | VAR | |
360 | sourceName: Name ; | |
361 | symName, | |
362 | fileName : String ; | |
363 | BEGIN | |
364 | sourceName := getSource (n) ; | |
365 | symName := InitStringCharStar (keyToCharStar (getSymName (n))) ; | |
366 | IF sourceName=NulName | |
367 | THEN | |
368 | IF NOT findSourceModFile (symName, fileName) | |
369 | THEN | |
370 | IF isImp (n) | |
371 | THEN | |
372 | fprintf1 (StdErr, 'failed to find implementation module %s.mod\n', symName) | |
373 | ELSE | |
374 | fprintf1 (StdErr, 'failed to find program module %s.mod\n', symName) | |
375 | END ; | |
376 | IF exitOnFailure | |
377 | THEN | |
378 | exit (1) | |
379 | END | |
380 | END | |
381 | ELSE | |
382 | fileName := InitStringCharStar (keyToCharStar (sourceName)) | |
383 | END ; | |
384 | RETURN doOpen (n, symName, fileName, exitOnFailure) | |
385 | END openMod ; | |
386 | ||
387 | ||
388 | (* | |
389 | pass - | |
390 | *) | |
391 | ||
392 | PROCEDURE pass (no: CARDINAL; n: node; f: parserFunction; | |
393 | isnode: isNodeF; open: openFunction) ; | |
394 | BEGIN | |
395 | IF isnode (n) AND (NOT isVisited (n)) | |
396 | THEN | |
397 | setVisited (n) ; | |
398 | IF open (n, TRUE) | |
399 | THEN | |
400 | IF NOT f () | |
401 | THEN | |
402 | writeFormat0 ('compilation failed') ; | |
403 | closeSource ; | |
404 | RETURN | |
405 | END ; | |
406 | closeSource | |
407 | END | |
408 | END | |
409 | END pass ; | |
410 | ||
411 | ||
412 | (* | |
413 | doPass - | |
414 | *) | |
415 | ||
416 | PROCEDURE doPass (parseDefs, parseMain: BOOLEAN; | |
417 | no: CARDINAL; p: performOperation; desc: ARRAY OF CHAR) ; | |
418 | VAR | |
419 | descs: String ; | |
420 | BEGIN | |
421 | setToPassNo (no) ; | |
422 | descs := InitString (desc) ; | |
423 | qprintf2 ('Pass %d: %s\n', no, descs) ; | |
424 | foreachDefModuleDo (unsetVisited) ; | |
425 | foreachModModuleDo (unsetVisited) ; | |
426 | IF parseMain | |
427 | THEN | |
428 | unsetVisited (getMainModule ()) ; | |
429 | IF parseDefs AND isImp (getMainModule ()) | |
430 | THEN | |
431 | (* we need to parse the definition module of a corresponding implementation module. *) | |
432 | p (lookupDef (getSymName (getMainModule ()))) | |
433 | END ; | |
434 | p (getMainModule ()) | |
435 | END ; | |
436 | IF parseDefs | |
437 | THEN | |
438 | foreachDefModuleDo (p) | |
439 | END ; | |
440 | flushWarnings ; flushErrors ; | |
441 | setToPassNo (0) | |
442 | END doPass ; | |
443 | ||
444 | ||
445 | (* | |
446 | setToPassNo - | |
447 | *) | |
448 | ||
449 | PROCEDURE setToPassNo (n: CARDINAL) ; | |
450 | BEGIN | |
451 | currentPass := n | |
452 | END setToPassNo ; | |
453 | ||
454 | ||
455 | (* | |
456 | getPassNo - return the pass no. | |
457 | *) | |
458 | ||
459 | PROCEDURE getPassNo () : CARDINAL ; | |
460 | BEGIN | |
461 | RETURN currentPass | |
462 | END getPassNo ; | |
463 | ||
464 | ||
465 | (* | |
466 | init - initialise data structures for this module. | |
467 | *) | |
468 | ||
469 | PROCEDURE init ; | |
470 | BEGIN | |
471 | setToPassNo (0) | |
472 | END init ; | |
473 | ||
474 | ||
475 | BEGIN | |
476 | init | |
477 | END mcComp. |