format.c
1 //! @file format.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 FORMAT statements.
25
26 #include <vif.h>
27
28 static void format_elem (char *lex, int_4 *elems)
29 {
30 if (lex == NO_TEXT || strlen (lex) == 0) {
31 return;
32 }
33 RECORD rstr, wstr;
34 int_4 width, digits, expwid;
35 if (LEQUAL ("a", lex)) {
36 if (sscanf (&lex[1], "%d", &width) != 1) {
37 _srecordf (rstr, "%%s");
38 _srecordf (wstr, "%%s");
39 } else if (width < 1) {
40 SYNTAX (1601, lex);
41 _srecordf (rstr, "%%s");
42 _srecordf (wstr, "%%s");
43 } else {
44 _srecordf (rstr, "%%%ds", width);
45 _srecordf (wstr, "%%-%ds", width);
46 }
47 code (nprocs, FMT, "FMT_CHAR");
48 (*elems)++;
49 } else if (LEQUAL ("i", lex)) {
50 if (sscanf (&lex[1], "%d", &width) != 1) {
51 EXPECT (1602, "width");
52 _srecordf (rstr, "%%d");
53 _srecordf (wstr, "%%d");
54 } else if (width < 1) {
55 SYNTAX (1603, lex);
56 _srecordf (rstr, "%%d");
57 _srecordf (wstr, "%%d");
58 } else {
59 _srecordf (rstr, "%%%dd", width);
60 _srecordf (wstr, "%%%dd", width);
61 }
62 code (nprocs, FMT, "FMT_INT");
63 (*elems)++;
64 } else if (LEQUAL ("l", lex)) {
65 if (sscanf (&lex[1], "%d", &width) != 1) {
66 EXPECT (1604, "width");
67 _srecordf (rstr, "%%s");
68 _srecordf (wstr, "%%s");
69 } else if (width < 1) {
70 SYNTAX (1605, lex);
71 _srecordf (rstr, "%%s");
72 _srecordf (wstr, "%%s");
73 } else {
74 _srecordf (rstr, "%%%ds", width);
75 _srecordf (wstr, "%%-%ds", width);
76 }
77 code (nprocs, FMT, "FMT_INT");
78 (*elems)++;
79 } else if (LEQUAL ("d", lex) || LEQUAL ("e", lex) || LEQUAL ("g", lex) || LEQUAL ("n", lex)) {
80 width = digits = expwid = 0;
81 if (sscanf (&lex[1], "%d.%d.%d", &width, &digits, &expwid) == 3) {
82 ;
83 } else if (sscanf (&lex[1], "%d.%d", &width, &digits) == 2) {
84 ;
85 } else {
86 EXPECT (1606, "width, decimals, [width]");
87 }
88 if (width < 0 || digits < 0) {
89 SYNTAX (1607, lex);
90 }
91 // Reading a REAL - specify width only!
92 _srecordf (rstr, "%%%de", width);
93 // Writing a REAL - specify all.
94 if (tolower (lex[0]) == 'n') {
95 if (islower (lex[0])) {
96 _srecordf (wstr, "%%%d.%d.%dn", width, digits, expwid);
97 } else {
98 _srecordf (wstr, "%%%d.%d.%dN", width, digits, expwid);
99 }
100 } else {
101 if (islower (lex[0])) {
102 _srecordf (wstr, "%%%d.%d.%de", width, digits, expwid);
103 } else {
104 _srecordf (wstr, "%%%d.%d.%dE", width, digits, expwid);
105 }
106 }
107 code (nprocs, FMT, "FMT_REAL");
108 (*elems)++;
109 } else if (LEQUAL ("f", lex)) {
110 sscanf (&lex[1], "%d.%d", &width, &digits);
111 if (sscanf (&lex[1], "%d.%d", &width, &digits) != 2) {
112 EXPECT (1608, "width, decimals");
113 _srecordf (rstr, "%%f");
114 _srecordf (wstr, "%%f");
115 } else if (width < 1 || digits < 0) {
116 SYNTAX (1609, lex);
117 _srecordf (rstr, "%%f");
118 _srecordf (wstr, "%%f");
119 } else {
120 _srecordf (rstr, "%%%df", width);
121 _srecordf (wstr, "%%%d.%df", width, digits);
122 }
123 code (nprocs, FMT, "FMT_REAL");
124 (*elems)++;
125 } else {
126 SYNTAX (1610, lex);
127 rstr[0] = wstr[0] = '\0';
128 (*elems)++;
129 }
130 RECORD fstr;
131 code (nprocs, FMT, ", ");
132 _srecordf (fstr, "\"%s\"", rstr);
133 code (nprocs, FMT, fstr);
134 code (nprocs, FMT, ",");
135 _srecordf (fstr, "\"%s\"", wstr);
136 code (nprocs, FMT, fstr);
137 code (nprocs, FMT, ",\n");
138 }
139
140 static void format_scale (int_4 N)
141 {
142 code (nprocs, FMT, "FMT_TEXT,");
143 code (nprocs, FMT, "\"\"");
144 code (nprocs, FMT, ",");
145 if (N == 0) {
146 code (nprocs, FMT, "\"0\"");
147 } else if (N == 1) {
148 code (nprocs, FMT, "\"1\"");
149 } else if (N == 2) {
150 code (nprocs, FMT, "\"2\"");
151 } else if (N == 3) {
152 code (nprocs, FMT, "\"3\"");
153 } else {
154 code (nprocs, FMT, "\"1\"");
155 }
156 }
157
158 static void format_x (int_4 N)
159 {
160 RECORD idf, str;
161 str[0] = '\0';
162 bufcat (str, "\"", RECLN);
163 for (int_4 k = 0; k < N && k < RECLN; k ++) {
164 bufcat (str, " ", RECLN);
165 }
166 bufcat (str, "\"", RECLN);
167 _srecordf (idf, "_dc_%d", code_uniq_str (str));
168 code (nprocs, FMT, "FMT_TEXT,");
169 code (nprocs, FMT, idf);
170 code (nprocs, FMT, ",");
171 code (nprocs, FMT, idf);
172 code (nprocs, FMT, ",\n");
173 }
174
175 static void format_nl (int_4 N)
176 {
177 RECORD str;
178 _srecordf (str, "\"\\n\"");
179 for (int_4 k = 0; k < N; k ++) {
180 code (nprocs, FMT, "FMT_TEXT,");
181 code (nprocs, FMT, str);
182 code (nprocs, FMT, ",");
183 code (nprocs, FMT, str);
184 code (nprocs, FMT, ",\n");
185 }
186 }
187
188 static void format_text (int_4 N, char *lex)
189 {
190 RECORD idf;
191 _srecordf (idf, "_dc_%d", code_uniq_str (lex));
192 for (int_4 k = 0; k < N; k ++) {
193 code (nprocs, FMT, "FMT_TEXT, ");
194 code (nprocs, FMT, idf);
195 code (nprocs, FMT, ", ");
196 code (nprocs, FMT, idf);
197 code (nprocs, FMT, ",\n");
198 }
199 }
200
201 void format_list (int_4 *nest, int_4 *elems)
202 {
203 int_4 rc;
204 int_4 crd = curlin, col = curcol;
205 while (WITHIN && (rc = scan_fmt ()) != END_OF_LINE) {
206 if ((*nest) == 0 && (*elems) == 0 && !TOKEN ("(")) {
207 SYNTAX (1611, "symbol outside parentheses");
208 } else if (TOKEN (",")) {
209 ;
210 } else {
211 int_4 k, N;
212 if (rc != INT_NUMBER) {
213 N = 1;
214 } else {
215 sscanf (curlex, "%d", &N);
216 crd = curlin;
217 col = curcol;
218 rc = scan_fmt ();
219 }
220 if (curlex[0] == 'p') {
221 format_scale (N);
222 code (nprocs, FMT, ",\n");
223 (*elems)++;
224 if (_EXPCHAR (curlex[1])) {
225 format_elem (&curlex[1], elems);
226 }
227 } else if (TOKEN ("x")) {
228 format_x (N);
229 (*elems)++;
230 } else if (TOKEN ("/")) {
231 format_nl (N);
232 (*elems)++;
233 } else if (LEQUAL ("\"", curlex)) {
234 format_text (N, curlex);
235 (*elems)++;
236 } else {
237 for (k = 0; k < N; k ++) {
238 if (TOKEN ("(")) {
239 (*nest) ++;
240 format_list (nest, elems);
241 if (k < N - 1) {
242 curlin = crd;
243 curcol = col;
244 rc = scan_fmt ();
245 }
246 } else if (TOKEN (")")) {
247 (*nest) --;
248 return;
249 } else {
250 format_elem (curlex, elems);
251 }
252 }
253 }
254 }
255 crd = curlin; col = curcol;
256 }
257 }
258
259 char *format_str_list (char *fmt, int_4 *nest, int_4 *elems)
260 {
261 #define LETTER(ch) (tolower (fmt[0]) == ch)
262 if (fmt[0] == '(') {
263 fmt++;
264 } else {
265 EXPECT (1612, "(");
266 }
267 while (fmt[0] != ')' && fmt[0] != '\0') {
268 if (fmt[0] == ',') {
269 fmt++;
270 }
271 while (isspace (fmt[0])) {
272 fmt++;
273 }
274 int_4 N;
275 if (!isdigit (fmt[0])) {
276 N = 1;
277 } else {
278 char *end;
279 N = strtol (fmt, &end, 10);
280 fmt = end;
281 }
282 if (LETTER ('p')) {
283 format_scale (N);
284 code (nprocs, FMT, ",\n");
285 (*elems)++;
286 fmt++;
287 if (_EXPCHAR (tolower (fmt[0]))) {
288 format_elem (fmt, elems);
289 }
290 } else if (LETTER ('x')) {
291 format_x (N);
292 (*elems)++;
293 fmt++;
294 } else if (fmt[0] == '/') {
295 format_nl (N);
296 (*elems)++;
297 fmt++;
298 } else if (LETTER ('h')) {
299 fmt++;
300 RECORD str;
301 RECCLR (str);
302 int_4 k = 0;
303 str[k++] = '"';
304 for (int_4 M = 0; M < N && fmt[0] != '\0'; M++) {
305 str[k++] = (fmt++)[0];
306 }
307 str[k++] = '"';
308 format_text (1, str);
309 (*elems)++;
310 } else if (fmt[0] == '\"') {
311 fmt++;
312 RECORD str;
313 RECCLR (str);
314 int_4 k = 0;
315 str[k++] = '"';
316 int_4 go_on = TRUE;
317 while (go_on) {
318 if (fmt[0] == '\0') {
319 go_on = FALSE;
320 } else if (fmt[0] == '"') {
321 if ((++fmt)[0] == '"') {
322 str[k++] = '"';
323 fmt++;
324 } else {
325 go_on = FALSE;
326 }
327 } else {
328 str[k++] = (fmt++)[0];
329 }
330 }
331 str[k++] = '"';
332 format_text (N, str);
333 (*elems)++;
334 } else if (fmt[0] == '\'') {
335 fmt++;
336 RECORD str;
337 RECCLR (str);
338 int_4 k = 0;
339 str[k++] = '"';
340 int_4 go_on = TRUE;
341 while (go_on) {
342 if (fmt[0] == '\0') {
343 go_on = FALSE;
344 } else if (fmt[0] == '\'') {
345 if ((++fmt)[0] == '\'') {
346 str[k++] = '\'';
347 fmt++;
348 } else {
349 go_on = FALSE;
350 }
351 } else {
352 str[k++] = (fmt++)[0];
353 }
354 }
355 str[k++] = '"';
356 format_text (N, str);
357 (*elems)++;
358 } else {
359 for (int_4 k = 0; k < N; k++) {
360 char *sav = fmt, *rtn = NO_TEXT;
361 if (fmt[0] == '(') {
362 (*nest)++;
363 rtn = format_str_list (fmt, nest, elems);
364 } else if (fmt[0] == ')') {
365 break;
366 } else if (strchr ("adefgiln", tolower (fmt[0])) == NO_TEXT) {
367 SYNTAX (1613, fmt++);
368 } else {
369 RECORD lex;
370 RECCLR (lex);
371 char *p = lex;
372 do {
373 (p++)[0] = (fmt++)[0];
374 while (isdigit (fmt[0])) {
375 (p++)[0] = (fmt++)[0];
376 }
377 } while (fmt[0] == '.');
378 format_elem (lex, elems);
379 }
380 if (k < N - 1) {
381 fmt = sav;
382 } else if (rtn != NO_TEXT) {
383 fmt = rtn;
384 }
385 }
386 }
387 }
388 if (fmt[0] != ')') {
389 EXPECT (1614, ")");
390 return fmt;
391 } else if (*nest > 0) {
392 (*nest)--;
393 }
394 return &fmt[1];
395 #undef LETTER
396 }
397
398 void format (LBL *statlbl)
399 {
400 int_4 nest = 0, elems = 0;
401 RECORD str;
402 if (statlbl == NO_LABEL) {
403 SYNTAX (1615, "format without label");
404 }
405 code (nprocs, FMT, "\n");
406 _srecordf (str, "static FORMAT %s[] = {\n", edit_fmt (statlbl->num));
407 code (nprocs, FMT, str);
408 format_list (&nest, &elems);
409 code (nprocs, FMT, "NULL, NULL, NULL\n");
410 code (nprocs, FMT, "};\n");
411 if (nest != 0) {
412 SYNTAX (1616, "unbalanced parentheses");
413 }
414 if (elems == 0) {
415 SYNTAX (1617, "empty format");
416 }
417 skip_card (FALSE);
418 }
419
420 int_4 format_str (char *fmt)
421 {
422 int_4 nest = 0, elems = 0;
423 int_4 lab = CUR_LIN.isn + 100000;
424 RECORD str;
425 if (fmt[0] == '"') {
426 fmt++;
427 }
428 if (fmt[strlen (fmt) - 1] == '"') {
429 fmt[strlen (fmt) - 1] = '\0';
430 }
431 code (nprocs, FMT, "\n");
432 _srecordf (str, "static FORMAT %s[] = {\n", edit_fmt (lab));
433 code (nprocs, FMT, str);
434 (void) format_str_list (fmt, &nest, &elems);
435 code (nprocs, FMT, "NULL, NULL, NULL\n");
436 code (nprocs, FMT, "};\n");
437 if (nest != 0) {
438 SYNTAX (1618, "unbalanced parentheses");
439 }
440 if (elems == 0) {
441 SYNTAX (1619, "empty format");
442 }
443 return lab;
444 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|