renum.c
1 //! @file renum.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 //! Vintage Fortran statement renumbering tool.
25 //
26 // I wrote a first version in Pascal, in the 1980's.
27 // That explains the unity lower bounds in this code.
28
29 #include <vif.h>
30
31 #define MODLEN 5000 // Max size of a subprogram
32
33 typedef RECORD DECK[MODLEN];
34
35 static RECORD name;
36
37 static int_4 routines, errors;
38 static int_4 old_label[MODLEN];
39
40 static void renum_jcl (RECORD *b, int_4 *flin, int_4 *size)
41 {
42 if (b[*flin - 1][0] == '/' && b[*flin - 1][1] == '*') {
43 return;
44 } else if (b[*flin - 1][0] == '/' && b[*flin - 1][1] == '/') {
45 int_4 k = 0, l = 2, N = 0, fn;
46 // Parse step and snam field.
47 NEW_RECORD (step);
48 NEW_RECORD (snam);
49 NEW_RECORD (oper);
50 NEW_RECORD (parm);
51 while (N <= RECLN && (isalpha (b[*flin - 1][l]) || (strlen (snam) > 0 ? isdigit (b[*flin - 1][l]) : FALSE))) {
52 snam[k++] = tolower (b[*flin - 1][l]);
53 l++;
54 N++;
55 }
56 if (b[*flin - 1][l] == '.') {
57 RECCPY (step, snam);
58 l++;
59 k = 0;
60 N = 0;
61 while (N <= RECLN && (isalpha (b[*flin - 1][l]) || (strlen (snam) > 0 ? isdigit (b[*flin - 1][l]) : FALSE))) {
62 snam[k++] = tolower (b[*flin - 1][l]);
63 l++;
64 N++;
65 }
66 }
67 // Parse operation field.
68 while (isspace (b[*flin - 1][l])) {
69 l++;
70 }
71 k = 0;
72 while (N <= RECLN && (isalpha (b[*flin - 1][l]) || (strlen (oper) > 0 ? isdigit (b[*flin - 1][l]) : FALSE))) {
73 oper[k++] = tolower (b[*flin - 1][l]);
74 l++;
75 N++;
76 }
77 // Parse parameter field.
78 while (isspace (b[*flin - 1][l])) {
79 l++;
80 }
81 k = 0;
82 while (N <= RECLN && b[*flin - 1][l] != '\0' && isprint (b[*flin - 1][l])) {
83 parm[k++] = b[*flin - 1][l];
84 l++;
85 N++;
86 }
87 // Match FT..F001.
88 if (sscanf(snam, "ft%02df001", &fn) == 1 && LEQUAL ("dd", oper)) {
89 if (LEQUAL ("*", parm)) {
90 while (*flin <= *size && !LEQUAL ("/*", b[*flin - 1])) {
91 (*flin)++;
92 }
93 }
94 }
95 }
96 }
97
98 static int_4 P_eof (FILE * f)
99 {
100 if (feof (f)) {
101 return TRUE;
102 }
103 int_4 ch = getc (f);
104 if (ch == EOF || feof (f)) {
105 return TRUE;
106 }
107 ungetc (ch, f);
108 return FALSE;
109 }
110
111 static int_4 P_eoln (FILE *f)
112 {
113 int_4 ch = getc (f);
114 if (ch == EOF) {
115 return TRUE;
116 }
117 ungetc (ch, f);
118 return (ch == '\n');
119 }
120
121 static void write_sym (char *s)
122 {
123 for (int_4 i = 1; i <= RECLN && s[i - 1] != ' '; i++) {
124 putchar (s[i - 1]);
125 }
126 putchar ('\n');
127 }
128
129 static void cram_symbol (char *b, char *s)
130 {
131 RECCLR (s);
132 for (int_4 i = 0, j = 0; i <= RECLN; i++) {
133 if (b[i] != ' ') {
134 s[j++] = b[i];
135 }
136 }
137 }
138
139 static int_4 blank_card (char *a)
140 {
141 int_4 eq = TRUE;
142 for (int_4 i = 0; i <= RECLN; i++) {
143 eq = (eq && a[i] == ' ');
144 }
145 return eq;
146 }
147
148 static void fill_buffer (FILE **f, RECORD *fsrc, int_4 *i)
149 {
150 int_4 j, kontinue = TRUE;
151 NEW_RECORD (current_card);
152 NEW_RECORD (s);
153 *i = 0;
154 while (kontinue) {
155 if (P_eof (*f) || *i >= MODLEN) {
156 break;
157 }
158 memset (current_card, ' ', RECLN);
159 j = 0;
160 while (!P_eoln (*f) && j <= RECLN) {
161 j++;
162 current_card[j - 1] = getc (*f);
163 if (current_card[j - 1] == '\n') {
164 current_card[j - 1] = ' ';
165 }
166 }
167 cram_symbol (current_card, s);
168 kontinue = !EQUAL (s, "end");
169 if (!blank_card (current_card)) {
170 (*i)++;
171 for (j = 0; j <= RECLN; j++) {
172 fsrc[*i - 1][j] = current_card[j];
173 }
174 }
175 (void) fscanf (*f, "%*[^\n]");
176 getc (*f);
177 if (P_eof (*f)) {
178 kontinue = FALSE;
179 }
180 }
181 }
182
183 static void write_buffer (FILE **f, RECORD *fsrc, int_4 size)
184 {
185 int_4 i, j, last;
186
187 if (routines > 1) {
188 putc ('\n', *f);
189 }
190 for (i = 0; i < size; i++) {
191 last = strlen (fsrc[i]);
192 while (last > 0 && fsrc[i][last - 1] == ' ') {
193 last--;
194 }
195 for (j = 0; j < last; j++) {
196 putc (fsrc[i][j], *f);
197 }
198 putc ('\n', *f);
199 }
200 fflush (*f);
201 }
202
203 static int_4 isidchar (char c)
204 {
205 return (isalpha (c) || c == '$');
206 }
207
208 static int_4 isspecial (char c)
209 {
210 return (((!isidchar (c)) & (!isdigit (c))) && c != ' ');
211 }
212
213 static int_4 read_label (RECORD *b, int_4 *flin, int_4 *size)
214 {
215 int_4 signif, labval, column, digit;
216
217 if (IS_JCL ((b[*flin - 1][0]))) {
218 renum_jcl (b, flin, size);
219 return 0;
220 } else if (IS_COMMENT ((b[*flin - 1][0]))) {
221 return 0;
222 } else {
223 signif = 1;
224 column = 5;
225 labval = 0;
226 while (column != 0) {
227 if (isdigit (b[*flin - 1][column - 1])) {
228 digit = b[*flin - 1][column - 1] - '0';
229 labval += signif * digit;
230 signif *= 10;
231 }
232 column--;
233 }
234 return labval;
235 }
236 }
237
238 static void write_label (RECORD *b, int_4 flin, int_4 lab)
239 {
240 int_4 i, digit;
241 int_4 column = 5, labval = lab;
242
243 do {
244 i = labval / 10;
245 digit = labval - i * 10;
246 labval = i;
247 b[flin - 1][column - 1] = (char) (digit + '0');
248 column--;
249 } while (labval != 0);
250 while (column != 0) {
251 b[flin - 1][column - 1] = ' ';
252 column--;
253 }
254 }
255
256 static void replace_label (RECORD *b, int_4 *flin, int_4 *first, int_4 *last, int_4 lab)
257 {
258 int_4 i;
259 int_4 j = 0;
260 int_4 k, digit, labval, FORLIM;
261
262 FORLIM = RECLN - *last;
263 for (i = 1; i <= FORLIM; i++) {
264 b[*flin - 1][*first + i - 1] = b[*flin - 1][*last + i - 2];
265 }
266 *last = *first + 1;
267 labval = lab;
268 do {
269 j++;
270 i = labval / 10;
271 digit = labval - i * 10;
272 labval = i;
273 b[*flin - 1][*first - 1] = (char) (digit + '0');
274 if (labval != 0) {
275 FORLIM = *first;
276 for (k = RECLN - 1; k >= FORLIM; k--) {
277 b[*flin - 1][k] = b[*flin - 1][k - 1];
278 }
279 (*last)++;
280 }
281 } while (labval != 0);
282 }
283
284 static void advance (RECORD *b, int_4 *eol, int_4 *cont, int_4 *flin, int_4 *column, int_4 *size)
285 {
286 if (*column != RECLN) {
287 (*column)++;
288 return;
289 }
290 do {
291 if (*flin == *size) {
292 *cont = FALSE;
293 } else {
294 (*flin)++;
295 }
296 } while (IS_COMMENT ((*b[*flin - 1])) && *cont);
297 if (!*cont) {
298 *column = 1;
299 *eol = TRUE;
300 return;
301 }
302 if (b[*flin - 1][5] != ' ') {
303 *column = 7;
304 return;
305 }
306 *column = 1;
307 *eol = TRUE;
308 *cont = FALSE;
309 }
310
311 static void scan_symbol (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
312 {
313 int_4 i, cont = TRUE;
314 *eol = FALSE;
315 memset (s, ' ', RECLN);
316 while (b[*flin - 1][*column - 1] == ' ' && cont) {
317 advance (b, eol, &cont, flin, column, size);
318 }
319 if (cont && b[*flin - 1][*column - 1] == '\'') {
320 do {
321 advance (b, eol, &cont, flin, column, size);
322 while (cont && b[*flin - 1][*column - 1] != '\'') {
323 advance (b, eol, &cont, flin, column, size);
324 }
325 advance (b, eol, &cont, flin, column, size);
326 } while (cont && b[*flin - 1][*column - 1] == '\'');
327 }
328 *first = *column;
329 i = 0;
330 if (cont & isidchar (b[*flin - 1][*column - 1])) {
331 while ((isidchar (b[*flin - 1][*column - 1]) || isdigit (b[*flin - 1][*column - 1])) && cont) {
332 i++;
333 s[i - 1] = b[*flin - 1][*column - 1];
334 advance (b, eol, &cont, flin, column, size);
335 }
336 // Provision for 'endif' or 'end if' etcetera.
337 if (tolower (s[0]) == 'e' && tolower (s[1]) == 'n' && tolower (s[2]) == 'd') {
338 while (b[*flin - 1][*column - 1] == ' ' && cont) {
339 advance (b, eol, &cont, flin, column, size);
340 }
341 while (isidchar (b[*flin - 1][*column - 1]) && cont) {
342 i++;
343 s[i - 1] = b[*flin - 1][*column - 1];
344 advance (b, eol, &cont, flin, column, size);
345 }
346 }
347 s[i] = '\0';
348 cont = FALSE;
349 }
350 if (cont && isdigit (b[*flin - 1][*column - 1])) {
351 while (isdigit (b[*flin - 1][*column - 1]) && cont) {
352 i++;
353 s[i - 1] = b[*flin - 1][*column - 1];
354 advance (b, eol, &cont, flin, column, size);
355 }
356 s[i] = '\0';
357 cont = FALSE;
358 }
359 if (!(cont & isspecial (b[*flin - 1][*column - 1]))) {
360 return;
361 }
362 s[0] = b[*flin - 1][*column - 1];
363 advance (b, eol, &cont, flin, column, size);
364 s[1] = '\0';
365 cont = FALSE;
366 }
367
368 static int_4 new_label (char *c)
369 {
370 int_4 flin = 1;
371 int_4 labval = atoi (c);
372 while (old_label[flin - 1] != labval && flin < MODLEN) {
373 flin++;
374 }
375 if (flin < MODLEN) {
376 return flin;
377 }
378 message (NO_FTN_LINE, ERR, "error", 0, "undefined label", c);
379 errors++;
380 return 0;
381 }
382
383 static void skip_to_comma (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
384 {
385 int_4 nest = 0;
386 while (! (s[0] == ',' && nest == 0)) {
387 scan_symbol (b, s, eol, flin, column, first, size);
388 if (s[0] == '(') {
389 nest++;
390 } else if (s[0] == ')') {
391 if (nest == 0) {
392 return;
393 } else {
394 nest--;
395 }
396 }
397 }
398 }
399
400 static void relabel_io (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
401 {
402 scan_symbol (b, s, eol, flin, column, first, size);
403 if (s[0] == '*') {
404 // print_4 *, ...
405 ;
406 } else if (isdigit (s[0])) {
407 // print_4 10, ...
408 replace_label (b, flin, first, column, new_label (s));
409 } else if (s[0] == '(') {
410 // print_4 (UNIT [,FMT=n],FILE=expr][,FORM=str][,ACTION=str][,DISP=str][,END=n][,ERR=n])
411 int_4 pos = 0;
412 do {
413 pos++;
414 scan_symbol (b, s, eol, flin, column, first, size);
415 if (s[0] == ',') {
416 ;
417 } else if (EQUAL (s, ")")) {
418 return;
419 } else if (EQUAL (s, "access")) {
420 skip_to_comma (b, s, eol, flin, column, first, size);
421 } else if (EQUAL (s, "action")) {
422 skip_to_comma (b, s, eol, flin, column, first, size);
423 } else if (EQUAL (s, "disp")) {
424 skip_to_comma (b, s, eol, flin, column, first, size);
425 } else if (EQUAL (s, "file")) {
426 skip_to_comma (b, s, eol, flin, column, first, size);
427 } else if (EQUAL (s, "form")) {
428 skip_to_comma (b, s, eol, flin, column, first, size);
429 } else if (EQUAL (s, "fmt") || EQUAL (s, "end") || EQUAL (s, "err")) {
430 scan_symbol (b, s, eol, flin, column, first, size);
431 scan_symbol (b, s, eol, flin, column, first, size);
432 replace_label (b, flin, first, column, new_label (s));
433 scan_symbol (b, s, eol, flin, column, first, size);
434 } else if (isdigit (s[0]) && pos == 2) {
435 replace_label (b, flin, first, column, new_label (s));
436 scan_symbol (b, s, eol, flin, column, first, size);
437 } else {
438 skip_to_comma (b, s, eol, flin, column, first, size);
439 }
440 } while (s[0] == ',');
441 }
442 }
443
444 static void relabel_goto (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
445 {
446 do {
447 scan_symbol (b, s, eol, flin, column, first, size);
448 replace_label (b, flin, first, column, new_label (s));
449 scan_symbol (b, s, eol, flin, column, first, size);
450 } while (s[0] != ')');
451 }
452
453 static logical_4 relabel_statement (RECORD *b, char *s, int_4 *eol, int_4 *flin, int_4 *column, int_4 *first, int_4 *size)
454 {
455 if (EQUAL (s, "do")) {
456 scan_symbol (b, s, eol, flin, column, first, size);
457 if (isdigit (s[0])) {
458 replace_label (b, flin, first, column, new_label (s));
459 }
460 return TRUE;
461 }
462 if (EQUAL (s, "assign")) {
463 scan_symbol (b, s, eol, flin, column, first, size);
464 replace_label (b, flin, first, column, new_label (s));
465 return TRUE;
466 }
467 if (EQUAL (s, "read") || EQUAL (s, "accept")) {
468 relabel_io (b, s, eol, flin, column, first, size);
469 return TRUE;
470 }
471 if (EQUAL (s, "write") || EQUAL (s, "print") || EQUAL (s, "punch")) {
472 relabel_io (b, s, eol, flin, column, first, size);
473 return TRUE;
474 }
475 if (EQUAL (s, "goto") || EQUAL (s, "go")) {
476 if (EQUAL (s, "go")) {
477 scan_symbol (b, s, eol, flin, column, first, size);
478 }
479 scan_symbol (b, s, eol, flin, column, first, size);
480 if (s[0] == '(') {
481 relabel_goto (b, s, eol, flin, column, first, size);
482 } else if (isalpha (s[0])) {
483 scan_symbol (b, s, eol, flin, column, first, size);
484 if (s[0] == ',') {
485 scan_symbol (b, s, eol, flin, column, first, size);
486 }
487 relabel_goto (b, s, eol, flin, column, first, size);
488 } else {
489 replace_label (b, flin, first, column, new_label (s));
490 }
491 return TRUE;
492 }
493 if (EQUAL (s, "if")) {
494 scan_symbol (b, s, eol, flin, column, first, size);
495 int_4 nest = 1;
496 do {
497 scan_symbol (b, s, eol, flin, column, first, size);
498 if (s[0] == '(') {
499 nest++;
500 } else if (s[0] == ')') {
501 nest--;
502 }
503 } while (nest != 0);
504 scan_symbol (b, s, eol, flin, column, first, size);
505 if (isdigit (s[0])) {
506 replace_label (b, flin, first, column, new_label (s));
507 scan_symbol (b, s, eol, flin, column, first, size);
508 scan_symbol (b, s, eol, flin, column, first, size);
509 replace_label (b, flin, first, column, new_label (s));
510 scan_symbol (b, s, eol, flin, column, first, size);
511 if (EQUAL (s, ",")) {
512 scan_symbol (b, s, eol, flin, column, first, size);
513 replace_label (b, flin, first, column, new_label (s));
514 }
515 } else if (EQUAL (s, "goto") | EQUAL (s, "go")) {
516 relabel_statement (b, s, eol, flin, column, first, size);
517 } else if (EQUAL (s, "read") || EQUAL (s, "accept")) {
518 relabel_statement (b, s, eol, flin, column, first, size);
519 } else if (EQUAL (s, "write") || EQUAL (s, "print") || EQUAL (s, "punch")) {
520 relabel_statement (b, s, eol, flin, column, first, size);
521 } else if (EQUAL (s, "assign")) {
522 relabel_statement (b, s, eol, flin, column, first, size);
523 }
524 return TRUE;
525 }
526
527 return FALSE;
528 }
529
530 static void scan_statement (RECORD *b, int_4 size)
531 {
532 NEW_RECORD (s);
533 int_4 eol = FALSE, column, first;
534 int_4 flin = 1;
535 do {
536 column = 1;
537 do {
538 if (flin > size) {
539 eol = TRUE;
540 flin = size;
541 }
542 if (IS_JCL (b[flin -1][0])) {
543 renum_jcl (b, &flin, &size);
544 flin++;
545 } else {
546 scan_symbol (b, s, &eol, &flin, &column, &first, &size);
547 if (relabel_statement (b, s, &eol, &flin, &column, &first, &size)) {
548 /* skip */;
549 }
550 }
551 } while (!eol);
552 } while (flin < size);
553 }
554
555 static void scan_name (RECORD *b, int_4 size, char *n)
556 {
557 NEW_RECORD (s);
558 int_4 eol, column, first, i;
559
560 int_4 flin = 1;
561 memset (n, ' ', RECLN);
562 memcpy (n, "anonymous", 9);
563 do {
564 column = 1;
565 if (IS_COMMENT (*(b[flin - 1]))) {
566 flin++;
567 } else {
568 do {
569 scan_symbol (b, s, &eol, &flin, &column, &first, &size);
570 if (EQUAL (s, "end")) {
571 eol = TRUE;
572 flin = size;
573 } else if (EQUAL (s, "program") || EQUAL (s, "subroutine") || EQUAL (s, "function")) {
574 memset (n, ' ', RECLN);
575 scan_symbol (b, s, &eol, &flin, &column, &first, &size);
576 i = 1;
577 while (i <= RECLN && s[i - 1] != '\0') {
578 n[i - 1] = tolower (s[i - 1]);
579 i++;
580 }
581 }
582 } while (!eol);
583 }
584 } while (flin < size);
585 }
586
587 void relabel (char *fname)
588 {
589 FILE *infile, *outfile;
590 int_4 number;
591 static DECK fsrc;
592 NEW_RECORD (gname);
593 if ((infile = fopen (fname, "r")) == NO_FILE) {
594 FATAL (2701, "cannot open", fname);
595 };
596 RECCPY (gname, fname);
597 for (int_4 k = (int_4) strlen (gname); k >= 0; k--) {
598 if (gname[k] == '.') {
599 gname[k] = '\0';
600 break;
601 }
602 }
603 //
604 strcat (gname, ".f~");
605 if ((outfile = fopen (gname, "w")) == NO_FILE) {
606 FATAL (2702, "cannot open", gname);
607 };
608 //
609 routines = 0;
610 errors = 0;
611 do {
612 int_4 size;
613 fill_buffer (&infile, fsrc, &size);
614 if (size > 0) {
615 for (int_4 i = 1; i <= size; i++) {
616 old_label[i - 1] = 0;
617 }
618 number = 0;
619 int_4 flin = 1;
620 while (flin <= size) {
621 int_4 labval = read_label (fsrc, &flin, &size);
622 if (labval != 0) {
623 number++;
624 write_label (fsrc, flin, number);
625 old_label[number - 1] = labval;
626 }
627 flin++;
628 }
629 if (number == 0) {
630 write_buffer (&outfile, fsrc, size);
631 } else {
632 routines++;
633 scan_name (fsrc, size, name);
634 scan_statement (fsrc, size);
635 write_buffer (&outfile, fsrc, size);
636 printf ("** ");
637 for (int_4 i = 1; i <= 10; i++) {
638 putchar (name[i - 1]);
639 }
640 printf (" ** renumbered subprogram %d\n", routines);
641 }
642 }
643 } while (!P_eof (infile));
644 fclose (infile);
645 fclose (outfile);
646 return;
647 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|