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 NEW_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 (2601, "stray symbol");
44 } else if (preret == WORD && curret == WORD) {
45 if (!reserved (prelex)) {
46 ADJACENT (2602, str);
47 }
48 } else if (IS_NUMBER (preret) && IS_NUMBER (curret)) {
49 ADJACENT (2603, 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") && IS_NOT_ASSIGNMENT) {
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 (1);
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 (2604, "too many labels", NO_TEXT);
82 }
83 for (int_4 k = 1; k < nlabels; k++) {
84 if (labels[k].num == CUR_LIN.label) {
85 ERROR (2605, "duplicate label", curlex);
86 break;
87 }
88 }
89 statlbl = &labels[nlabels];
90 statlbl->index = nlabels;
91 statlbl->num = CUR_LIN.label;
92 statlbl->line = curlin;
93 statlbl->nonexe = FALSE;
94 statlbl->data = FALSE;
95 statlbl->format = FALSE;
96 statlbl->jumped = FALSE;
97 statlbl->renum = nlabels++;
98 rc = scan (EXPECT_NONE);
99 }
100 if (TOKEN ("end") && IS_NOT_ASSIGNMENT) {
101 go_on = FALSE;
102 } else if (TOKEN ("data") && IS_NOT_ASSIGNMENT) {
103 if (statlbl != NO_LABEL) {
104 statlbl->nonexe = TRUE;
105 statlbl->data = TRUE;
106 }
107 skip_card (FALSE);
108 } else if (TOKEN ("format") && IS_NOT_ASSIGNMENT) {
109 if (statlbl == NO_LABEL) {
110 ERROR (2606, "format statement needs a label", NO_TEXT);
111 } else {
112 statlbl->nonexe = TRUE;
113 statlbl->format = TRUE;
114 }
115 skip_card (FALSE);
116 } else {
117 int_4 nest = 0;
118 rc = scan (EXPECT_NONE);
119 while (WITHIN) {
120 common_errors (&nest);
121 rc = scan (EXPECT_NONE);
122 }
123 if (nest != 0) {
124 SYNTAX (2607, "unbalanced parentheses");
125 }
126 }
127 }
128 RESTORE_POS (1);
129 }
130
131 void code_args (int_4 proc, int_4 phase)
132 {
133 int_4 rc;
134 code (proc, phase, procnam);
135 code (proc, phase, " ");
136 rc = scan (EXPECT_NONE);
137 if (TOKEN ("(")) {
138 rc = scan (EXPECT_NONE);
139 if (TOKEN (")")) {
140 code (proc, phase, "(void)");
141 } else if (rc == WORD) {
142 int_4 go_on;
143 code (proc, phase, "(");
144 do {
145 int_4 apatch = code (proc, phase, NO_TEXT);
146 if (rc == WORD) {
147 add_local (curlex, NOTYPE, NOLEN, UNIQ, apatch, ARG, LOCAL, SOURCE);
148 } else {
149 EXPECT (2608, "variable");
150 }
151 rc = scan (EXPECT_NONE);
152 if (TOKEN (",")) {
153 go_on = TRUE;
154 code (proc, phase, ", ");
155 rc = scan (EXPECT_NONE);
156 } else if (TOKEN (")")) {
157 go_on = FALSE;
158 code (proc, phase, ")");
159 } else {
160 go_on = FALSE;
161 EXPECT (2609, ", or )");
162 }
163 } while (go_on);
164 }
165 } else {
166 code (proc, phase, "(void)");
167 }
168 (void) rc;
169 skip_card (FALSE);
170 }
171
172 void gen_code (void)
173 {
174 // Generate code for one module.
175 code (nprocs, TITLE, newpage (modnam, "generated-code"));
176 if (!no_source) {
177 code (nprocs, PARAMETERS, newpage (modnam, "parameters"));
178 }
179 code (nprocs, MESSAGES, newpage (modnam, "diagnostics"));
180 merrors = 0;
181 prescan ();
182 //
183 SAVE_POS (1);
184 if (merrors == 0) {
185 get_impl ();
186 RESTORE_POS (1);
187 get_decls ();
188 RESTORE_POS (1);
189 decl_autosave ();
190 RESTORE_POS (1);
191 decl_equiv ();
192 merge_commons ();
193 RESTORE_POS (1);
194 decl_data ();
195 }
196 if (merrors == 0) {
197 idfs_unused ();
198 RESTORE_POS (1);
199 decl_macros ();
200 } else {
201 skip_to_end ();
202 return;
203 }
204 if (merrors == 0) {
205 gen_statements (NO_LABEL, 0);
206 code_idfs (locals, nlocals, LOCAL, nprocs, DECL);
207 code_exts (locals, nlocals, LOCAL, nprocs, DECL);
208 } else {
209 skip_to_end ();
210 return;
211 }
212 if (merrors == 0) {
213 patch_args ();
214 }
215 }
216
217 void gen_program (void)
218 {
219 int_4 rc;
220 // PROGRAM
221 nprocs++;
222 code (0, PROTOTYPE, "\n");
223 code (0, PROTOTYPE, "prototype int_4 ");
224 code (nprocs, PRE, "int_4 ");
225 SAVE_POS (1);
226 rc = scan (EXPECT_NONE);
227 if (rc != WORD) {
228 ERROR (2610, "missing name for ", "program");
229 RECCPY (modnam, "program");
230 } else {
231 RECCPY (modnam, curlex);
232 }
233 _srecordf (procnam, "%s", edit_f (modnam));
234 RECCPY (retnam, "");
235 if (strlen (program) == 0) {
236 RECCPY (program, procnam);
237 } else {
238 ERROR (2611, "redefinition", "program");
239 }
240 code_args (0, PROTOTYPE);
241 code (0, PROTOTYPE, ";");
242 RESTORE_POS (1);
243 rc = scan (EXPECT_NONE);
244 code_args (nprocs, PRE);
245 code (nprocs, PRE, "\n");
246 code (nprocs, PRE, "{\n");
247 cpp_direct (nprocs, prelin, PRE);
248 gen_code ();
249 code (nprocs, POST, "}");
250 }
251
252 void gen_anon_program (void)
253 {
254 if (! ALLOW_ANON) {
255 EXPECT (2612, "valid subprogram");
256 return;
257 }
258 if (nprocs == 0) {
259 curlin = 1;
260 }
261 curcol = START_OF_LINE;
262 nprocs++;
263 RECCPY (modnam, "anonymous");
264 _srecordf (procnam, "%s", edit_f (modnam));
265 RECCPY (retnam, "");
266 if (strlen (program) == 0) {
267 RECCPY (program, procnam);
268 } else {
269 ERROR (2613, "redefinition", "program");
270 }
271 code (0, PROTOTYPE, "\n");
272 code (0, PROTOTYPE, "prototype int_4 ");
273 code (0, PROTOTYPE, procnam);
274 code (0, PROTOTYPE, " (void);");
275 code (nprocs, PRE, "int_4 ");
276 code (nprocs, PRE, procnam);
277 code (nprocs, PRE, " (void)");
278 code (nprocs, PRE, "\n");
279 code (nprocs, PRE, "{\n");
280 cpp_direct (nprocs, prelin, PRE);
281 gen_code ();
282 code (nprocs, POST, "}");
283 }
284
285 void gen_subroutine (void)
286 {
287 // SUBROUTINE
288 int_4 rc;
289 nprocs++;
290 code (0, PROTOTYPE, "\n");
291 if (compile_only || optimise < 3) {
292 code (0, PROTOTYPE, "prototype int_4 ");
293 code (nprocs, PRE, "int_4 ");
294 } else {
295 code (0, PROTOTYPE, "prototype static inline int_4 ");
296 code (nprocs, PRE, "static inline int_4 ");
297 }
298 SAVE_POS (1);
299 rc = scan (EXPECT_NONE);
300 if (rc != WORD) {
301 ERROR (2614, "missing name for ", "subroutine");
302 RECCPY (modnam, "routine");
303 } else {
304 RECCPY (modnam, curlex);
305 }
306 _srecordf (procnam, "%s", edit_f (modnam));
307 RECCPY (retnam, "");
308 code_args (0, PROTOTYPE);
309 code (0, PROTOTYPE, ";");
310 RESTORE_POS (1);
311 rc = scan (EXPECT_NONE);
312 code_args (nprocs, PRE);
313 code (nprocs, PRE, "\n");
314 code (nprocs, PRE, "{\n");
315 cpp_direct (nprocs, prelin, PRE);
316 gen_code ();
317 code (nprocs, POST, "}");
318 }
319
320 void gen_block_data (void)
321 {
322 // BLOCK DATA
323 NEW_RECORD (str);
324 int_4 rc = scan (EXPECT_NONE);
325 nprocs++;
326 if (!TOKEN ("data")) {
327 EXPECT (2615, "block data");
328 }
329 rc = scan (EXPECT_NONE);
330 if (prelin == curlin) {
331 RECCPY (modnam, curlex);
332 rc = scan (EXPECT_NONE);
333 } else {
334 RECCPY (modnam, "block_data");
335 }
336 RECCPY (retnam, "");
337 _srecordf (block, "%s", edit_f (modnam));
338 if (compile_only || optimise < 3) {
339 _srecordf (str, "int_4 %s (void)", block);
340 } else {
341 _srecordf (str, "static inline int_4 %s (void)", block);
342 }
343 code (0, PROTOTYPE, "\n");
344 code (0, PROTOTYPE, "prototype ");
345 code (0, PROTOTYPE, str);
346 code (0, PROTOTYPE, ";");
347 code (nprocs, PRE, str);
348 code (nprocs, PRE, "{\n");
349 cpp_direct (nprocs, prelin, PRE);
350 gen_code ();
351 code (nprocs, POST, "}");
352 (void) rc;
353 }
354
355 void gen_function (void)
356 {
357 int_4 rc;
358 // FUNCTION with implicit type.
359 int_4 patchp, patchf;
360 SAVE_POS (1);
361 IDENT *ret;
362 NEW_RECORD (str);
363 nprocs++;
364 func = TRUE;
365 code (0, PROTOTYPE, "\n");
366 code (0, PROTOTYPE, "prototype ");
367 if (compile_only == FALSE || optimise >= 3) {
368 code (0, PROTOTYPE, "static inline ");
369 }
370 patchp = code (0, PROTOTYPE, NO_TEXT);
371 code (0, PROTOTYPE, " ");
372 if (compile_only == FALSE || optimise >= 3) {
373 code (nprocs, PRE, "static inline ");
374 }
375 patchf = code (nprocs, PRE, NO_TEXT);
376 code (nprocs, PRE, " ");
377 rc = scan (EXPECT_NONE);
378 if (rc != WORD) {
379 ERROR (2616, "missing name for ", "function");
380 RECCPY (modnam, "function");
381 } else {
382 RECCPY (modnam, curlex);
383 }
384 _srecordf (procnam, "%s", edit_f (modnam));
385 ret = add_local (modnam, NOTYPE, NOLEN, UNIQ, NOPATCH, NOARG, LOCAL, SOURCE);
386 ret->mode.fun = TRUE;
387 ret->mode.save = AUTOMATIC;
388 _srecordf (retnam, "%s", C_NAME (ret));
389 code_args (0, PROTOTYPE);
390 code (0, PROTOTYPE, ";");
391 RESTORE_POS (1);
392 rc = scan (EXPECT_NONE);
393 code_args (nprocs, PRE);
394 code (nprocs, PRE, "\n");
395 code (nprocs, PRE, "{\n");
396 cpp_direct (nprocs, prelin, PRE);
397 gen_code ();
398 code (nprocs, POST, "}\n");
399 _srecordf (str, "%s", wtype (&ret->mode, NOARG, FUN));
400 patch (patchp, str);
401 patch (patchf, str);
402 }
403
404 MODE gen_typed_function (void)
405 {
406 int_4 rc;
407 // TYPE FUNCTION
408 MODE mode;
409 f2c_type (curlex, &mode, NOARG, NOFUN);
410 rc = scan (EXPECT_NONE);
411 if (!TOKEN ("function")) {
412 mode.type = NOTYPE;
413 mode.len = 0;
414 return mode;
415 } else {
416 SAVE_POS (1);
417 IDENT *ret;
418 nprocs++;
419 func = TRUE;
420 code (0, PROTOTYPE, "\n");
421 code (0, PROTOTYPE, "prototype ");
422 if (compile_only == FALSE || optimise >= 3) {
423 code (0, PROTOTYPE, "static inline ");
424 }
425 code (0, PROTOTYPE, f2c_type (prelex, NO_MODE, NOARG, FUN));
426 code (0, PROTOTYPE, " ");
427 if (compile_only == FALSE || optimise >= 3) {
428 code (nprocs, PRE, "static inline ");
429 }
430 code (nprocs, PRE, f2c_type (prelex, NO_MODE, NOARG, FUN));
431 code (nprocs, PRE, " ");
432 rc = scan (EXPECT_NONE);
433 if (rc != WORD) {
434 ERROR (2617, "missing name for ", "function");
435 RECCPY (modnam, "function");
436 } else {
437 RECCPY (modnam, curlex);
438 }
439 _srecordf (procnam, "%s", edit_f (modnam));
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 (1);
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 NEW_RECORD (type);
462 NEW_RECORD (kind);
463 NEW_RECORD (str);
464 NEW_RECORD (endof);
465 while (!abend) {
466 SAVE_POS (1);
467 rc = scan (EXPECT_NONE);
468 if (rc == END_OF_MODULE) {
469 break;
470 }
471 nlocals = 0;
472 type[0] = '\0';
473 // Label '0' is the label for subprogram exit.
474 labels[0].num = 0;
475 labels[0].line = 0;
476 labels[0].jumped = FALSE;
477 nlabels = 1;
478 //
479 lbl = NO_LABEL;
480 nloctmps = 0;
481 func = FALSE;
482 if (rc == END_OF_LINE) {
483 continue;
484 }
485 kind[0] = '\0';
486 end_statements = 0;
487 aborted = FALSE;
488 if (rc == WORD) {
489 if (TOKEN ("program")) {
490 bufcpy (kind, "program", RECLN);
491 gen_program ();
492 } else if (TOKEN ("subroutine")) {
493 bufcpy (kind, "subroutine", RECLN);
494 gen_subroutine ();
495 if (renum && merrors == 0) {
496 RESTORE_POS (1);
497 tidy_source (procnam);
498 }
499 } else if (TOKEN ("block")) {
500 bufcpy (kind, "block data", RECLN);
501 gen_block_data ();
502 if (renum && merrors == 0) {
503 RESTORE_POS (1);
504 tidy_source (procnam);
505 }
506 } else if (TOKEN ("function")) {
507 bufcpy (kind, "function", RECLN);
508 gen_function ();
509 if (renum && merrors == 0) {
510 RESTORE_POS (1);
511 tidy_source (procnam);
512 }
513 } else {
514 if (ALLOW_ANON) {
515 gen_anon_program ();
516 bufcpy (kind, "program", RECLN);
517 if (renum && merrors == 0) {
518 RESTORE_POS (1);
519 tidy_source (procnam);
520 }
521 }
522 }
523 } else if (rc == DECLAR) {
524 bufcpy (kind, "function", RECLN);
525 MODE ret = gen_typed_function ();
526 if (ret.type == NOTYPE && ALLOW_ANON) {
527 gen_anon_program ();
528 bufcpy (kind, "program", RECLN);
529 } else {
530 _srecordf (type, qtype (&ret));
531 }
532 if (renum && merrors == 0) {
533 RESTORE_POS (1);
534 tidy_source (procnam);
535 }
536 // } else if (rc == LABEL) {
537 // WARNING (2618, "ignored label", curlex);
538 } else {
539 if (ALLOW_ANON) {
540 gen_anon_program ();
541 bufcpy (kind, "program", RECLN);
542 if (renum && merrors == 0) {
543 RESTORE_POS (1);
544 tidy_source (procnam);
545 }
546 } else {
547 EXPECT (2619, "valid subprogram");
548 }
549 return;
550 }
551 if (!aborted && end_statements == 0) {
552 EXPECT (2620, "end statement");
553 }
554 if (nprocs == 0) {
555 // BUG ("no subprogram found");
556 FATAL (2621, "no subprogram", "check program statement");
557 }
558 // Prune 'sleeping' labels.
559 for (int_4 k = 0; k < nlabels; k++) {
560 LBL *L = &labels[k];
561 if (!L->jumped) {
562 patch (L->patch, NO_TEXT);
563 }
564 }
565 //
566 if (nprocs == pnprocs) {
567 FATAL (2622, "invalid fortran source", modnam);
568 }
569 NEW_RECORD (sub);
570 _srecordf (endof, "** %-10s ** end of compilation %d", _bufsub (sub, modnam, 1, 10), nprocs);
571 pnprocs = nprocs;
572 code (nprocs, BANNER, newpage (modnam, modnam));
573 if (strlen (type) > 0) {
574 banner (nprocs, BANNER, _strupper (type));
575 code (nprocs, BANNER, "\n");
576 _srecordf (str, " {\"%s\", 0}, // %s %s\n", modnam, type, kind);
577 code (0, FREQ, str);
578 } else {
579 _srecordf (str, " {\"%s\", 0}, // %s\n", modnam, kind);
580 code (0, FREQ, str);
581 }
582 banner (nprocs, BANNER, _strupper (kind));
583 code (nprocs, BANNER, "\n");
584 banner (nprocs, BANNER, _strupper (modnam));
585 code (nprocs, BANNER, "\n");
586 if (!quiet_mode) {
587 diagnostic (nprocs, endof);
588 }
589 proc_listing (nprocs);
590 }
591 }
592
593 logical_4 find_module (char *name)
594 {
595 for (int_4 k = 0; k < nmodules; k++) {
596 if (same_name (name, modules[k])) {
597 return TRUE;
598 }
599 }
600 return FALSE;
601 }
602
603 void list_module (void)
604 {
605 int_4 rc = scan (EXPECT_NONE);
606 if (rc == WORD) {
607 if (nmodules >= MAX_MODULES) {
608 FATAL (2623, "too many modules", NO_TEXT);
609 }
610 modules[nmodules++] = f_stralloc (curlex);
611 } else {
612 ERROR (2624, "missing name", "module");
613 }
614 }
615
616 void scan_modules (void)
617 {
618 int_4 rc;
619 while ((rc = scan (EXPECT_NONE)) != END_OF_MODULE && !abend) {
620 if (rc == WORD) {
621 if (TOKEN ("program")) {
622 list_module ();
623 } else if (TOKEN ("subroutine")) {
624 list_module ();
625 } else if (TOKEN ("function")) {
626 list_module ();
627 } else if (rc == DECLAR) {
628 rc = scan (EXPECT_NONE);
629 if (TOKEN ("function")) {
630 list_module ();
631 }
632 } else if (TOKEN ("block")) {
633 rc = scan (EXPECT_NONE);
634 if (TOKEN ("data")) {
635 list_module ();
636 }
637 }
638 }
639 }
640 }
|
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|