modules.c
1 //! @file modules.c
2 //! @author J. Marcel van der Veer
3 //
4 //! @section Copyright
5 //
6 // This file is part of VIF - vintage FORTRAN compiler.
7 // Copyright 2020-2025 J. Marcel van der Veer <algol68g@xs4all.nl>.
8 //
9 //! @section License
10 //
11 // This program is free software; you can redistribute it and/or modify it
12 // under the terms of the GNU General Public License as published by the
13 // Free Software Foundation; either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful, but
17 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 // more details. You should have received a copy of the GNU General Public
20 // License along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 //! @section Synopsis
23 //!
24 //! Compile BLOCK DATA, FUNCTION, PROGRAM and SUBROUTINE.
25
26 #include <vif.h>
27
28 #define ALLOW_ANON (nprocs >= 0)
29
30 int_4 aborted;
31 int_4 nmodules = 0;
32 char *modules[MAX_MODULES];
33
34 void common_errors (int_4 *nest)
35 {
36 RECORD str;
37 _srecordf (str, "%s %s", prelex, curlex);
38 if (TOKEN ("(")) {
39 (*nest)++;
40 } else if (TOKEN (")")) {
41 (*nest)--;
42 } else if (strlen (curlex) == 1 && strchr ("{}[];\\?~`@#$%", curlex[0]) != NO_TEXT) {
43 SYNTAX (2301, "stray symbol");
44 } else if (preret == WORD && curret == WORD) {
45 if (!reserved (prelex)) {
46 ADJACENT (2302, str);
47 }
48 } else if (IS_NUMBER (preret) && IS_NUMBER (curret)) {
49 ADJACENT (2303, str);
50 }
51 }
52
53 void skip_to_end (void)
54 {
55 int_4 rc, go_on = TRUE;
56 while (go_on && (rc = scan (EXPECT_NONE)) != END_OF_MODULE) {
57 if (TOKEN ("end")) {
58 go_on = FALSE;
59 } else {
60 rc = scan (EXPECT_NONE);
61 while (WITHIN) {
62 rc = scan (EXPECT_NONE);
63 }
64 }
65 }
66 aborted = TRUE;
67 }
68
69 void prescan (void)
70 {
71 SAVE_POS;
72 int_4 rc, go_on = TRUE;
73 while (go_on && (rc = scan (EXPECT_NONE)) != END_OF_MODULE) {
74 LBL *statlbl = NO_LABEL;
75 if (curlex[0] == '\0') {
76 continue;
77 }
78 if (rc == LABEL) {
79 sscanf (curlex, "%d", &CUR_LIN.label);
80 if (nlabels >= MAX_LABELS) {
81 ERROR (2304, "too many labels", NO_TEXT);
82 }
83 statlbl = &labels[nlabels];
84 statlbl->index = nlabels;
85 statlbl->num = CUR_LIN.label;
86 statlbl->line = curlin;
87 statlbl->nonexe = FALSE;
88 statlbl->data = FALSE;
89 statlbl->format = FALSE;
90 statlbl->jumped = FALSE;
91 nlabels++;
92 rc = scan (EXPECT_NONE);
93 }
94 if (TOKEN ("end")) {
95 go_on = FALSE;
96 } else if (TOKEN ("data")) {
97 if (statlbl != NO_LABEL) {
98 statlbl->nonexe = TRUE;
99 statlbl->data = TRUE;
100 }
101 skip_card (FALSE);
102 } else if (TOKEN ("format")) {
103 if (statlbl == NO_LABEL) {
104 ERROR (2305, "format statement needs a label", NO_TEXT);
105 }
106 statlbl->nonexe = TRUE;
107 statlbl->format = TRUE;
108 skip_card (FALSE);
109 } else {
110 int_4 nest = 0;
111 rc = scan (EXPECT_NONE);
112 while (WITHIN) {
113 common_errors (&nest);
114 rc = scan (EXPECT_NONE);
115 }
116 if (nest != 0) {
117 SYNTAX (2306, "unbalanced parentheses");
118 }
119 }
120 }
121 RESTORE_POS;
122 }
123
124 void code_args (int_4 proc, int_4 phase)
125 {
126 int_4 rc;
127 code (proc, phase, procnam);
128 code (proc, phase, " ");
129 rc = scan (EXPECT_NONE);
130 if (TOKEN ("(")) {
131 rc = scan (EXPECT_NONE);
132 if (TOKEN (")")) {
133 code (proc, phase, "(void)");
134 } else if (rc == WORD) {
135 int_4 go_on;
136 code (proc, phase, "(");
137 do {
138 int_4 apatch = code (proc, phase, NO_TEXT);
139 if (rc == WORD) {
140 add_local (curlex, NOTYPE, NOLEN, UNIQ, apatch, ARG, LOCAL, SOURCE);
141 } else {
142 EXPECT (2307, "variable");
143 }
144 rc = scan (EXPECT_NONE);
145 if (TOKEN (",")) {
146 go_on = TRUE;
147 code (proc, phase, ", ");
148 rc = scan (EXPECT_NONE);
149 } else if (TOKEN (")")) {
150 go_on = FALSE;
151 code (proc, phase, ")");
152 } else {
153 go_on = FALSE;
154 EXPECT (2308, ", or )");
155 }
156 } while (go_on);
157 }
158 } else {
159 code (proc, phase, "(void)");
160 }
161 (void) rc;
162 skip_card (FALSE);
163 }
164
165 void gen_code (void)
166 {
167 // Generate code for one module.
168 code (nprocs, TITLE, newpage (modnam, "generated-code"));
169 code (nprocs, PARAMETERS, newpage (modnam, "parameters"));
170 code (nprocs, MESSAGES, newpage (modnam, "diagnostics"));
171 merrors = 0;
172 prescan ();
173 //
174 if (merrors == 0) {
175 SAVE_POS;
176 get_impl ();
177 RESTORE_POS;
178 get_decls ();
179 RESTORE_POS;
180 decl_autosave ();
181 RESTORE_POS;
182 decl_equiv ();
183 merge_commons ();
184 RESTORE_POS;
185 decl_data ();
186 }
187 idfs_unused ();
188 if (merrors == 0) {
189 decl_macros ();
190 } else {
191 skip_to_end ();
192 return;
193 }
194 if (merrors == 0) {
195 gen_statements (NO_LABEL, 0);
196 code_idfs (locals, nlocals, LOCAL, nprocs, DECL);
197 code_exts (locals, nlocals, LOCAL, nprocs, DECL);
198 } else {
199 skip_to_end ();
200 return;
201 }
202 if (merrors == 0) {
203 patch_args ();
204 }
205 }
206
207 void gen_program (void)
208 {
209 int_4 rc;
210 // PROGRAM
211 nprocs++;
212 code (0, PROTOTYPE, "\n");
213 code (0, PROTOTYPE, "prototype int_4 ");
214 code (nprocs, PRE, "int_4 ");
215 SAVE_POS;
216 rc = scan (EXPECT_NONE);
217 if (rc != WORD) {
218 ERROR (2309, "missing name for ", "program");
219 strcpy (modnam, "program");
220 } else {
221 strcpy (modnam, curlex);
222 }
223 _srecordf (procnam, "%s", edit_f (modnam));
224 strcpy (retnam, "");
225 if (strlen (program) == 0) {
226 strcpy (program, procnam);
227 } else {
228 ERROR (2310, "redefinition", "program");
229 }
230 code_args (0, PROTOTYPE);
231 code (0, PROTOTYPE, ";");
232 RESTORE_POS;
233 rc = scan (EXPECT_NONE);
234 code_args (nprocs, PRE);
235 code (nprocs, PRE, "\n");
236 code (nprocs, PRE, "{\n");
237 cpp_direct (nprocs, prelin, PRE);
238 gen_code ();
239 code (nprocs, POST, "}");
240 }
241
242 void gen_anon_program (void)
243 {
244 if (! ALLOW_ANON) {
245 EXPECT (2311, "valid subprogram");
246 return;
247 }
248 if (nprocs == 0) {
249 curlin = 1;
250 }
251 curcol = START_OF_LINE;
252 nprocs++;
253 strcpy (modnam, "anonymous");
254 _srecordf (procnam, "%s", edit_f (modnam));
255 strcpy (retnam, "");
256 if (strlen (program) == 0) {
257 strcpy (program, procnam);
258 } else {
259 ERROR (2312, "redefinition", "program");
260 }
261 code (0, PROTOTYPE, "\n");
262 code (0, PROTOTYPE, "prototype int_4 ");
263 code (0, PROTOTYPE, procnam);
264 code (0, PROTOTYPE, " (void);");
265 code (nprocs, PRE, "int_4 ");
266 code (nprocs, PRE, procnam);
267 code (nprocs, PRE, " (void)");
268 code (nprocs, PRE, "\n");
269 code (nprocs, PRE, "{\n");
270 cpp_direct (nprocs, prelin, PRE);
271 gen_code ();
272 code (nprocs, POST, "}");
273 }
274
275 void gen_subroutine (void)
276 {
277 // SUBROUTINE
278 int_4 rc;
279 nprocs++;
280 code (0, PROTOTYPE, "\n");
281 if (compile_only || optimise < 3) {
282 code (0, PROTOTYPE, "prototype int_4 ");
283 code (nprocs, PRE, "int_4 ");
284 } else {
285 code (0, PROTOTYPE, "prototype static inline int_4 ");
286 code (nprocs, PRE, "static inline int_4 ");
287 }
288 SAVE_POS;
289 rc = scan (EXPECT_NONE);
290 if (rc != WORD) {
291 ERROR (2313, "missing name for ", "subroutine");
292 strcpy (modnam, "routine");
293 } else {
294 strcpy (modnam, curlex);
295 }
296 _srecordf (procnam, "%s", edit_f (modnam));
297 strcpy (retnam, "");
298 code_args (0, PROTOTYPE);
299 code (0, PROTOTYPE, ";");
300 RESTORE_POS;
301 rc = scan (EXPECT_NONE);
302 code_args (nprocs, PRE);
303 code (nprocs, PRE, "\n");
304 code (nprocs, PRE, "{\n");
305 cpp_direct (nprocs, prelin, PRE);
306 gen_code ();
307 code (nprocs, POST, "}");
308 }
309
310 void gen_block_data (void)
311 {
312 // BLOCK DATA
313 RECORD str;
314 int_4 rc = scan (EXPECT_NONE);
315 nprocs++;
316 if (!TOKEN ("data")) {
317 EXPECT (2314, "block data");
318 }
319 rc = scan (EXPECT_NONE);
320 if (prelin == curlin) {
321 strcpy (modnam, curlex);
322 rc = scan (EXPECT_NONE);
323 } else {
324 strcpy (modnam, "block_data");
325 }
326 strcpy (retnam, "");
327 _srecordf (block, "%s", edit_f (modnam));
328 if (compile_only || optimise < 3) {
329 _srecordf (str, "int_4 %s (void)", block);
330 } else {
331 _srecordf (str, "static inline int_4 %s (void)", block);
332 }
333 code (0, PROTOTYPE, "\n");
334 code (0, PROTOTYPE, "prototype ");
335 code (0, PROTOTYPE, str);
336 code (0, PROTOTYPE, ";");
337 code (nprocs, PRE, str);
338 code (nprocs, PRE, "{\n");
339 cpp_direct (nprocs, prelin, PRE);
340 gen_code ();
341 code (nprocs, POST, "}");
342 (void) rc;
343 }
344
345 void gen_function (void)
346 {
347 int_4 rc;
348 // FUNCTION with implicit type.
349 int_4 patchp, patchf;
350 SAVE_POS;
351 IDENT *ret;
352 RECORD str;
353 nprocs++;
354 func = TRUE;
355 code (0, PROTOTYPE, "\n");
356 code (0, PROTOTYPE, "prototype ");
357 if (compile_only == FALSE || optimise >= 3) {
358 code (0, PROTOTYPE, "static inline ");
359 }
360 patchp = code (0, PROTOTYPE, NO_TEXT);
361 code (0, PROTOTYPE, " ");
362 if (compile_only == FALSE || optimise >= 3) {
363 code (nprocs, PRE, "static inline ");
364 }
365 patchf = code (nprocs, PRE, NO_TEXT);
366 code (nprocs, PRE, " ");
367 rc = scan (EXPECT_NONE);
368 if (rc != WORD) {
369 ERROR (2315, "missing name for ", "function");
370 strcpy (modnam, "function");
371 } else {
372 strcpy (modnam, curlex);
373 }
374 _srecordf (procnam, "%s", edit_f (modnam));
375 // if (is_intrins (modnam)) {
376 // ERROR (2316, "redefining intrinsic function", modnam);
377 // }
378 ret = add_local (modnam, NOTYPE, NOLEN, UNIQ, NOPATCH, NOARG, LOCAL, SOURCE);
379 ret->mode.fun = TRUE;
380 ret->mode.save = AUTOMATIC;
381 _srecordf (retnam, "%s", C_NAME (ret));
382 code_args (0, PROTOTYPE);
383 code (0, PROTOTYPE, ";");
384 RESTORE_POS;
385 rc = scan (EXPECT_NONE);
386 code_args (nprocs, PRE);
387 code (nprocs, PRE, "\n");
388 code (nprocs, PRE, "{\n");
389 cpp_direct (nprocs, prelin, PRE);
390 gen_code ();
391 code (nprocs, POST, "}\n");
392 _srecordf (str, "%s", wtype (&ret->mode, NOARG, FUN));
393 patch (patchp, str);
394 patch (patchf, str);
395 }
396
397 MODE gen_type_function (void)
398 {
399 int_4 rc;
400 // TYPE FUNCTION
401 MODE mode;
402 f2c_type (curlex, &mode, NOARG, NOFUN);
403 rc = scan (EXPECT_NONE);
404 if (!TOKEN ("function")) {
405 if (nprocs > 0) {
406 EXPECT (2317, "function");
407 } else {
408 mode.type = NOTYPE;
409 mode.len = 0;
410 }
411 return mode;
412 } else {
413 SAVE_POS;
414 IDENT *ret;
415 nprocs++;
416 func = TRUE;
417 code (0, PROTOTYPE, "\n");
418 code (0, PROTOTYPE, "prototype ");
419 if (compile_only == FALSE || optimise >= 3) {
420 code (0, PROTOTYPE, "static inline ");
421 }
422 code (0, PROTOTYPE, f2c_type (prelex, NO_MODE, NOARG, FUN));
423 code (0, PROTOTYPE, " ");
424 if (compile_only == FALSE || optimise >= 3) {
425 code (nprocs, PRE, "static inline ");
426 }
427 code (nprocs, PRE, f2c_type (prelex, NO_MODE, NOARG, FUN));
428 code (nprocs, PRE, " ");
429 rc = scan (EXPECT_NONE);
430 if (rc != WORD) {
431 ERROR (2318, "missing name for ", "function");
432 strcpy (modnam, "function");
433 } else {
434 strcpy (modnam, curlex);
435 }
436 _srecordf (procnam, "%s", edit_f (modnam));
437 // if (is_intrins (modnam)) {
438 // ERROR (2319, "redefining intrinsic function", modnam);
439 // }
440 ret = add_local (modnam, mode.type, mode.len, UNIQ, NOPATCH, NOARG, LOCAL, SOURCE);
441 ret->mode.fun = TRUE;
442 ret->mode.save = AUTOMATIC;
443 _srecordf (retnam, "%s", C_NAME (ret));
444 code_args (0, PROTOTYPE);
445 code (0, PROTOTYPE, ";");
446 RESTORE_POS;
447 rc = scan (EXPECT_NONE);
448 code_args (nprocs, PRE);
449 code (nprocs, PRE, "\n");
450 code (nprocs, PRE, "{\n");
451 cpp_direct (nprocs, prelin, PRE);
452 gen_code ();
453 code (nprocs, POST, "}");
454 }
455 return mode;
456 }
457
458 void subprograms (void)
459 {
460 int_4 rc;
461 RECORD type, kind, str, endof;
462 while ((rc = scan (EXPECT_NONE)) != END_OF_MODULE && !abend) {
463 nlocals = 0;
464 type[0] = '\0';
465 // Label '0' is the label for subprogram exit.
466 labels[0].num = 0;
467 labels[0].line = 0;
468 labels[0].jumped = FALSE;
469 nlabels = 1;
470 //
471 lbl = NO_LABEL;
472 nloctmps = 0;
473 func = FALSE;
474 if (rc == END_OF_LINE) {
475 continue;
476 }
477 kind[0] = '\0';
478 end_statements = 0;
479 aborted = FALSE;
480 if (rc == WORD) {
481 if (TOKEN ("program")) {
482 bufcpy (kind, "program", RECLN);
483 gen_program ();
484 } else if (TOKEN ("subroutine")) {
485 bufcpy (kind, "subroutine", RECLN);
486 gen_subroutine ();
487 } else if (TOKEN ("block")) {
488 bufcpy (kind, "block data", RECLN);
489 gen_block_data ();
490 } else if (TOKEN ("function")) {
491 bufcpy (kind, "function", RECLN);
492 gen_function ();
493 } else {
494 if (ALLOW_ANON) {
495 gen_anon_program ();
496 bufcpy (kind, "program", RECLN);
497 }
498 }
499 } else if (rc == DECLAR) {
500 bufcpy (kind, "function", RECLN);
501 MODE ret = gen_type_function ();
502 if (ret.type == NOTYPE && ALLOW_ANON) {
503 gen_anon_program ();
504 bufcpy (kind, "program", RECLN);
505 } else {
506 _srecordf (type, qtype (&ret));
507 }
508 // } else if (rc == LABEL) {
509 // WARNING (2320, "ignored label", curlex);
510 } else {
511 if (ALLOW_ANON) {
512 gen_anon_program ();
513 bufcpy (kind, "program", RECLN);
514 } else {
515 EXPECT (2321, "valid subprogram");
516 }
517 return;
518 }
519 if (!aborted && end_statements == 0) {
520 EXPECT (2322, "end statement");
521 }
522 if (nprocs == 0) {
523 // BUG ("no subprogram found");
524 FATAL (2323, "no subprogram", "check program statement");
525 }
526 // Prune 'sleeping' labels.
527 for (int_4 k = 0; k < nlabels; k++) {
528 LBL *L = &labels[k];
529 if (!L->jumped) {
530 patch (L->patch, NO_TEXT);
531 }
532 }
533 //
534 if (nprocs == pnprocs) {
535 FATAL (2324, "invalid fortran source", modnam);
536 }
537 RECORD sub;
538 _srecordf (endof, "** %-10s ** end of compilation %d", _bufsub (sub, modnam, 1, 10), nprocs);
539 pnprocs = nprocs;
540 code (nprocs, BANNER, newpage (modnam, modnam));
541 if (strlen (type) > 0) {
542 banner (nprocs, BANNER, _strupper (type));
543 code (nprocs, BANNER, "\n");
544 _srecordf (str, " {\"%s\", 0}, // %s %s\n", modnam, type, kind);
545 code (0, FREQ, str);
546 } else {
547 _srecordf (str, " {\"%s\", 0}, // %s\n", modnam, kind);
548 code (0, FREQ, str);
549 }
550 banner (nprocs, BANNER, _strupper (kind));
551 code (nprocs, BANNER, "\n");
552 banner (nprocs, BANNER, _strupper (modnam));
553 code (nprocs, BANNER, "\n");
554 if (!quiet_mode) {
555 diagnostic (nprocs, endof);
556 }
557 proc_listing (nprocs);
558 }
559 }
560
561 int_4 find_module (char *name)
562 {
563 for (int_4 k = 0; k < nmodules; k++) {
564 if (same_name (name, modules[k])) {
565 return TRUE;
566 }
567 }
568 return FALSE;
569 }
570
571 void list_module (void)
572 {
573 int_4 rc = scan (EXPECT_NONE);
574 if (rc == WORD) {
575 if (nmodules >= MAX_MODULES) {
576 FATAL (2325, "too many modules", NO_TEXT);
577 }
578 modules[nmodules++] = f_stralloc (curlex);
579 } else {
580 ERROR (2326, "missing name", "module");
581 }
582 }
583
584 void scan_modules (void)
585 {
586 int_4 rc;
587 while ((rc = scan (EXPECT_NONE)) != END_OF_MODULE && !abend) {
588 if (rc == WORD) {
589 if (TOKEN ("program")) {
590 list_module ();
591 } else if (TOKEN ("subroutine")) {
592 list_module ();
593 } else if (TOKEN ("function")) {
594 list_module ();
595 } else if (rc == DECLAR) {
596 rc = scan (EXPECT_NONE);
597 if (TOKEN ("function")) {
598 list_module ();
599 }
600 } else if (TOKEN ("block")) {
601 rc = scan (EXPECT_NONE);
602 if (TOKEN ("data")) {
603 list_module ();
604 }
605 }
606 }
607 }
608 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|