transput-formatted.c
1 //! @file transput-formatted.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2026 J. Marcel van der Veer [algol68g@algol68genie.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 //! Formatted transput.
25
26 #include "a68g.h"
27 #include "a68g-conversion.h"
28 #include "a68g-genie.h"
29 #include "a68g-frames.h"
30 #include "a68g-prelude.h"
31 #include "a68g-mp.h"
32 #include "a68g-double.h"
33 #include "a68g-transput.h"
34
35 // Transput - Formatted transput.
36 // In Algol68G, a value of mode FORMAT looks like a routine text. The value
37 // comprises a pointer to its environment in the stack, and a pointer where the
38 // format text is at in the syntax tree.
39
40 #define INT_DIGITS "0123456789"
41 #define BITS_DIGITS "0123456789abcdefABCDEF"
42 #define INT_DIGITS_BLANK " 0123456789"
43 #define BITS_DIGITS_BLANK " 0123456789abcdefABCDEF"
44 #define SIGN_DIGITS " +-"
45
46
47 //! @brief Handle format error event.
48
49 void format_error (NODE_T * p, A68G_REF ref_file, char *diag)
50 {
51 A68G_FILE *f = FILE_DEREF (&ref_file);
52 on_event_handler (p, FORMAT_ERROR_MENDED (f), ref_file);
53 A68G_BOOL z;
54 POP_OBJECT (p, &z, A68G_BOOL);
55 if (VALUE (&z) == A68G_FALSE) {
56 diagnostic (A68G_RUNTIME_ERROR, p, diag);
57 exit_genie (p, A68G_RUNTIME_ERROR);
58 }
59 }
60
61
62 //! @brief Initialise processing of pictures.
63
64 void initialise_collitems (NODE_T * p)
65 {
66 // Every picture has a counter that says whether it has not been used OR the number
67 // of times it can still be used.
68 for (; p != NO_NODE; FORWARD (p)) {
69 if (IS (p, PICTURE)) {
70 A68G_COLLITEM *z = (A68G_COLLITEM *) FRAME_LOCAL (A68G_FP, OFFSET (TAX (p)));
71 STATUS (z) = INIT_MASK;
72 COUNT (z) = ITEM_NOT_USED;
73 }
74 // Don't dive into f, g, n frames and collections.
75 if (!(IS (p, ENCLOSED_CLAUSE) || IS (p, COLLECTION))) {
76 initialise_collitems (SUB (p));
77 }
78 }
79 }
80
81
82 //! @brief Initialise processing of format text.
83
84 void open_format_frame (NODE_T * p, A68G_REF ref_file, A68G_FORMAT * fmt, BOOL_T embedded, BOOL_T init)
85 {
86 // Open a new frame for the format text and save for return to embedding one.
87 A68G_FILE *file = FILE_DEREF (&ref_file);
88 // Integrity check.
89 if ((STATUS (fmt) & SKIP_FORMAT_MASK) || (BODY (fmt) == NO_NODE)) {
90 format_error (p, ref_file, ERROR_FORMAT_UNDEFINED);
91 }
92 // Ok, seems usable.
93 NODE_T *dollar = SUB (BODY (fmt));
94 OPEN_PROC_FRAME (dollar, ENVIRON (fmt));
95 INIT_STATIC_FRAME (dollar);
96 // Save old format.
97 A68G_FORMAT *save = (A68G_FORMAT *) FRAME_LOCAL (A68G_FP, OFFSET (TAX (dollar)));
98 *save = (embedded == EMBEDDED_FORMAT ? FORMAT (file) : nil_format);
99 FORMAT (file) = *fmt;
100 // Reset all collitems.
101 if (init) {
102 initialise_collitems (dollar);
103 }
104 }
105
106
107 //! @brief Handle end-of-format event.
108
109 int end_of_format (NODE_T * p, A68G_REF ref_file)
110 {
111 // Format-items return immediately to the embedding format text. The outermost
112 //format text calls "on format end".
113 A68G_FILE *file = FILE_DEREF (&ref_file);
114 NODE_T *dollar = SUB (BODY (&FORMAT (file)));
115 A68G_FORMAT *save = (A68G_FORMAT *) FRAME_LOCAL (A68G_FP, OFFSET (TAX (dollar)));
116 if (IS_NIL_FORMAT (save)) {
117 // Not embedded, outermost format: execute event routine.
118 on_event_handler (p, FORMAT_END_MENDED (FILE_DEREF (&ref_file)), ref_file);
119 A68G_BOOL z;
120 POP_OBJECT (p, &z, A68G_BOOL);
121 if (VALUE (&z) == A68G_FALSE) {
122 // Restart format.
123 A68G_FP = FRAME_POINTER (file);
124 A68G_SP = STACK_POINTER (file);
125 open_format_frame (p, ref_file, &FORMAT (file), NOT_EMBEDDED_FORMAT, A68G_TRUE);
126 }
127 return NOT_EMBEDDED_FORMAT;
128 } else {
129 // Embedded format, return to embedding format, cf. RR.
130 CLOSE_FRAME;
131 FORMAT (file) = *save;
132 return EMBEDDED_FORMAT;
133 }
134 }
135
136
137 //! @brief Return integral value of replicator.
138
139 int get_replicator_value (NODE_T * p, BOOL_T check)
140 {
141 int z = 0;
142 if (IS (p, STATIC_REPLICATOR)) {
143 A68G_INT u;
144 if (genie_string_to_value_internal (p, M_INT, NSYMBOL (p), (BYTE_T *) & u) == A68G_FALSE) {
145 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, M_INT);
146 exit_genie (p, A68G_RUNTIME_ERROR);
147 }
148 z = VALUE (&u);
149 } else if (IS (p, DYNAMIC_REPLICATOR)) {
150 A68G_INT u;
151 GENIE_UNIT (NEXT_SUB (p));
152 POP_OBJECT (p, &u, A68G_INT);
153 z = VALUE (&u);
154 } else if (IS (p, REPLICATOR)) {
155 z = get_replicator_value (SUB (p), check);
156 }
157 // Not conform RR as Andrew Herbert rightfully pointed out.
158 // if (check && z < 0) {
159 // diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_INVALID_REPLICATOR);
160 // exit_genie (p, A68G_RUNTIME_ERROR);
161 // }
162 if (z < 0) {
163 z = 0;
164 }
165 return z;
166 }
167
168
169 //! @brief Return first available pattern.
170
171 NODE_T *scan_format_pattern (NODE_T * p, A68G_REF ref_file)
172 {
173 for (; p != NO_NODE; FORWARD (p)) {
174 if (IS (p, PICTURE_LIST)) {
175 NODE_T *prio = scan_format_pattern (SUB (p), ref_file);
176 if (prio != NO_NODE) {
177 return prio;
178 }
179 }
180 if (IS (p, PICTURE)) {
181 NODE_T *picture = SUB (p);
182 A68G_COLLITEM *collitem = (A68G_COLLITEM *) FRAME_LOCAL (A68G_FP, OFFSET (TAX (p)));
183 if (COUNT (collitem) != 0) {
184 if (IS (picture, A68G_PATTERN)) {
185 COUNT (collitem) = 0; // This pattern is now done
186 picture = SUB (picture);
187 if (ATTRIBUTE (picture) != FORMAT_PATTERN) {
188 return picture;
189 } else {
190 NODE_T *pat;
191 A68G_FORMAT z;
192 A68G_FILE *file = FILE_DEREF (&ref_file);
193 GENIE_UNIT (NEXT_SUB (picture));
194 POP_OBJECT (p, &z, A68G_FORMAT);
195 open_format_frame (p, ref_file, &z, EMBEDDED_FORMAT, A68G_TRUE);
196 pat = scan_format_pattern (SUB (BODY (&FORMAT (file))), ref_file);
197 if (pat != NO_NODE) {
198 return pat;
199 } else {
200 (void) end_of_format (p, ref_file);
201 }
202 }
203 } else if (IS (picture, INSERTION)) {
204 A68G_FILE *file = FILE_DEREF (&ref_file);
205 if (READ_MOOD (file)) {
206 read_insertion (picture, ref_file);
207 } else if (WRITE_MOOD (file)) {
208 write_insertion (picture, ref_file, INSERTION_NORMAL);
209 } else {
210 ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
211 }
212 COUNT (collitem) = 0; // This insertion is now done
213 } else if (IS (picture, REPLICATOR) || IS (picture, COLLECTION)) {
214 BOOL_T siga = A68G_TRUE;
215 NODE_T *a68g_select = NO_NODE;
216 if (COUNT (collitem) == ITEM_NOT_USED) {
217 if (IS (picture, REPLICATOR)) {
218 COUNT (collitem) = get_replicator_value (SUB (p), A68G_TRUE);
219 siga = (BOOL_T) (COUNT (collitem) > 0);
220 FORWARD (picture);
221 } else {
222 COUNT (collitem) = 1;
223 }
224 initialise_collitems (NEXT_SUB (picture));
225 } else if (IS (picture, REPLICATOR)) {
226 FORWARD (picture);
227 }
228 while (siga) {
229 // Get format item from collection. If collection is done, but repitition is not,
230 // then re-initialise the collection and repeat.
231 a68g_select = scan_format_pattern (NEXT_SUB (picture), ref_file);
232 if (a68g_select != NO_NODE) {
233 return a68g_select;
234 } else {
235 COUNT (collitem)--;
236 siga = (BOOL_T) (COUNT (collitem) > 0);
237 if (siga) {
238 initialise_collitems (NEXT_SUB (picture));
239 }
240 }
241 }
242 }
243 }
244 }
245 }
246 return NO_NODE;
247 }
248
249
250 //! @brief Return first available pattern.
251
252 NODE_T *get_next_format_pattern (NODE_T * p, A68G_REF ref_file, BOOL_T mood)
253 {
254 // "mood" can be WANT_PATTERN: pattern needed by caller, so perform end-of-format
255 // if needed or SKIP_PATTERN: just emptying current pattern/collection/format.
256 A68G_FILE *file = FILE_DEREF (&ref_file);
257 if (BODY (&FORMAT (file)) == NO_NODE) {
258 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_EXHAUSTED);
259 exit_genie (p, A68G_RUNTIME_ERROR);
260 return NO_NODE;
261 } else {
262 NODE_T *pat = scan_format_pattern (SUB (BODY (&FORMAT (file))), ref_file);
263 if (pat == NO_NODE) {
264 if (mood == WANT_PATTERN) {
265 int z;
266 do {
267 z = end_of_format (p, ref_file);
268 pat = scan_format_pattern (SUB (BODY (&FORMAT (file))), ref_file);
269 } while (z == EMBEDDED_FORMAT && pat == NO_NODE);
270 if (pat == NO_NODE) {
271 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_EXHAUSTED);
272 exit_genie (p, A68G_RUNTIME_ERROR);
273 }
274 }
275 }
276 return pat;
277 }
278 }
279
280
281 //! @brief Diagnostic_node in case mode does not match picture.
282
283 void pattern_error (NODE_T * p, MOID_T * mode, int att)
284 {
285 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_CANNOT_TRANSPUT, mode, att);
286 exit_genie (p, A68G_RUNTIME_ERROR);
287 }
288
289
290 //! @brief Unite value at top of stack to NUMBER.
291
292 void unite_to_number (NODE_T * p, MOID_T * mode, BYTE_T * item)
293 {
294 ADDR_T pop_sp = A68G_SP;
295 PUSH_UNION (p, mode);
296 PUSH (p, item, (int) SIZE (mode));
297 A68G_SP = pop_sp + SIZE (M_NUMBER);
298 }
299
300
301 //! @brief Write a group of insertions.
302
303 void write_insertion (NODE_T * p, A68G_REF ref_file, MOOD_T mood)
304 {
305 for (; p != NO_NODE; FORWARD (p)) {
306 write_insertion (SUB (p), ref_file, mood);
307 if (IS (p, FORMAT_ITEM_L)) {
308 plusab_transput_buffer (p, FORMATTED_BUFFER, NEWLINE_CHAR);
309 write_purge_buffer (p, ref_file, FORMATTED_BUFFER);
310 } else if (IS (p, FORMAT_ITEM_P)) {
311 plusab_transput_buffer (p, FORMATTED_BUFFER, FORMFEED_CHAR);
312 write_purge_buffer (p, ref_file, FORMATTED_BUFFER);
313 } else if (IS (p, FORMAT_ITEM_X) || IS (p, FORMAT_ITEM_Q)) {
314 plusab_transput_buffer (p, FORMATTED_BUFFER, BLANK_CHAR);
315 } else if (IS (p, FORMAT_ITEM_Y)) {
316 PUSH_REF (p, ref_file);
317 PUSH_VALUE (p, -1, A68G_INT);
318 genie_set (p);
319 } else if (IS (p, LITERAL)) {
320 if (mood & INSERTION_NORMAL) {
321 add_string_transput_buffer (p, FORMATTED_BUFFER, NSYMBOL (p));
322 } else if (mood & INSERTION_BLANK) {
323 size_t k = strlen (NSYMBOL (p));
324 for (size_t j = 1; j <= k; j++) {
325 plusab_transput_buffer (p, FORMATTED_BUFFER, BLANK_CHAR);
326 }
327 }
328 } else if (IS (p, REPLICATOR)) {
329 int k = get_replicator_value (SUB (p), A68G_TRUE);
330 if (ATTRIBUTE (SUB_NEXT (p)) != FORMAT_ITEM_K) {
331 for (int j = 1; j <= k; j++) {
332 write_insertion (NEXT (p), ref_file, mood);
333 }
334 } else {
335 int pos = get_transput_buffer_index (FORMATTED_BUFFER);
336 for (int j = 1; j < (k - pos); j++) {
337 plusab_transput_buffer (p, FORMATTED_BUFFER, BLANK_CHAR);
338 }
339 }
340 return;
341 }
342 }
343 }
344
345
346 //! @brief Write string to file following current format.
347
348 void write_string_pattern (NODE_T * p, MOID_T * mode, A68G_REF ref_file, char **str)
349 {
350 for (; p != NO_NODE; FORWARD (p)) {
351 if (IS (p, INSERTION)) {
352 write_insertion (SUB (p), ref_file, INSERTION_NORMAL);
353 } else if (IS (p, FORMAT_ITEM_A)) {
354 if ((*str)[0] != NULL_CHAR) {
355 plusab_transput_buffer (p, FORMATTED_BUFFER, (*str)[0]);
356 (*str)++;
357 } else {
358 value_error (p, mode, ref_file);
359 }
360 } else if (IS (p, FORMAT_ITEM_S)) {
361 if ((*str)[0] != NULL_CHAR) {
362 (*str)++;
363 } else {
364 value_error (p, mode, ref_file);
365 }
366 return;
367 } else if (IS (p, REPLICATOR)) {
368 int k = get_replicator_value (SUB (p), A68G_TRUE);
369 for (int j = 1; j <= k; j++) {
370 write_string_pattern (NEXT (p), mode, ref_file, str);
371 }
372 return;
373 } else {
374 write_string_pattern (SUB (p), mode, ref_file, str);
375 }
376 }
377 }
378
379
380 //! @brief Scan c_pattern.
381
382 void scan_c_pattern (NODE_T * p, BOOL_T * right_align, BOOL_T * sign, int *width, int *after, int *letter)
383 {
384 if (IS (p, FORMAT_ITEM_ESCAPE)) {
385 FORWARD (p);
386 }
387 if (IS (p, FORMAT_ITEM_MINUS)) {
388 *right_align = A68G_TRUE;
389 FORWARD (p);
390 } else {
391 *right_align = A68G_FALSE;
392 }
393 if (IS (p, FORMAT_ITEM_PLUS)) {
394 *sign = A68G_TRUE;
395 FORWARD (p);
396 } else {
397 *sign = A68G_FALSE;
398 }
399 if (IS (p, REPLICATOR)) {
400 *width = get_replicator_value (SUB (p), A68G_TRUE);
401 FORWARD (p);
402 }
403 if (IS (p, FORMAT_ITEM_POINT)) {
404 FORWARD (p);
405 }
406 if (IS (p, REPLICATOR)) {
407 *after = get_replicator_value (SUB (p), A68G_TRUE);
408 FORWARD (p);
409 }
410 *letter = ATTRIBUTE (p);
411 }
412
413
414 //! @brief Write appropriate insertion from a choice pattern.
415
416 void write_choice_pattern (NODE_T * p, A68G_REF ref_file, int *count)
417 {
418 for (; p != NO_NODE; FORWARD (p)) {
419 write_choice_pattern (SUB (p), ref_file, count);
420 if (IS (p, PICTURE)) {
421 (*count)--;
422 if (*count == 0) {
423 write_insertion (SUB (p), ref_file, INSERTION_NORMAL);
424 }
425 }
426 }
427 }
428
429
430 //! @brief Write appropriate insertion from a boolean pattern.
431
432 void write_boolean_pattern (NODE_T * p, A68G_REF ref_file, BOOL_T z)
433 {
434 int k = (z ? 1 : 2);
435 write_choice_pattern (p, ref_file, &k);
436 }
437
438
439 //! @brief Write value according to a general pattern.
440
441 void write_number_generic (NODE_T * p, MOID_T * mode, BYTE_T * item, int mod)
442 {
443 // Push arguments.
444 unite_to_number (p, mode, item);
445 GENIE_UNIT (NEXT_SUB (p));
446 A68G_REF row;
447 POP_REF (p, &row);
448 A68G_ARRAY *arr; A68G_TUPLE *tup;
449 GET_DESCRIPTOR (arr, tup, &row);
450 size_t size = ROW_SIZE (tup);
451 if (size > 0) {
452 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
453 for (int i = LWB (tup); i <= UPB (tup); i++) {
454 int addr = INDEX_1_DIM (arr, tup, i);
455 int arg = VALUE ((A68G_INT *) & (base_address[addr]));
456 PUSH_VALUE (p, arg, A68G_INT);
457 }
458 }
459 // Make a string.
460 if (mod == FORMAT_ITEM_G) {
461 switch (size) {
462 case 1: {
463 genie_whole (p);
464 break;
465 }
466 case 2: {
467 genie_fixed (p);
468 break;
469 }
470 case 3: {
471 genie_float (p);
472 break;
473 }
474 default: {
475 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_INTS_REQUIRED, M_INT);
476 exit_genie (p, A68G_RUNTIME_ERROR);
477 break;
478 }
479 }
480 } else if (mod == FORMAT_ITEM_H) {
481 A68G_INT a_width, a_after, a_expo, a_mult;
482 STATUS (&a_width) = INIT_MASK;
483 VALUE (&a_width) = 0;
484 STATUS (&a_after) = INIT_MASK;
485 VALUE (&a_after) = 0;
486 STATUS (&a_expo) = INIT_MASK;
487 VALUE (&a_expo) = 0;
488 STATUS (&a_mult) = INIT_MASK;
489 VALUE (&a_mult) = 0;
490 // Set default values
491 int def_expo = 0, def_mult = 3;
492 if (mode == M_REAL || mode == M_INT) {
493 def_expo = A68G_EXP_WIDTH + 1;
494 } else if (mode == M_LONG_REAL || mode == M_LONG_INT) {
495 def_expo = A68G_LONG_EXP_WIDTH + 1;
496 } else if (mode == M_LONG_LONG_REAL || mode == M_LONG_LONG_INT) {
497 def_expo = A68G_LONG_LONG_EXP_WIDTH + 1;
498 }
499 // Pop user values
500 switch (size) {
501 case 1: {
502 POP_OBJECT (p, &a_after, A68G_INT);
503 VALUE (&a_width) = VALUE (&a_after) + def_expo + 4;
504 VALUE (&a_expo) = def_expo;
505 VALUE (&a_mult) = def_mult;
506 break;
507 }
508 case 2: {
509 POP_OBJECT (p, &a_mult, A68G_INT);
510 POP_OBJECT (p, &a_after, A68G_INT);
511 VALUE (&a_width) = VALUE (&a_after) + def_expo + 4;
512 VALUE (&a_expo) = def_expo;
513 break;
514 }
515 case 3: {
516 POP_OBJECT (p, &a_mult, A68G_INT);
517 POP_OBJECT (p, &a_after, A68G_INT);
518 POP_OBJECT (p, &a_width, A68G_INT);
519 VALUE (&a_expo) = def_expo;
520 break;
521 }
522 case 4: {
523 POP_OBJECT (p, &a_mult, A68G_INT);
524 POP_OBJECT (p, &a_expo, A68G_INT);
525 POP_OBJECT (p, &a_after, A68G_INT);
526 POP_OBJECT (p, &a_width, A68G_INT);
527 break;
528 }
529 default: {
530 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_INTS_REQUIRED, M_INT);
531 exit_genie (p, A68G_RUNTIME_ERROR);
532 break;
533 }
534 }
535 PUSH_VALUE (p, VALUE (&a_width), A68G_INT);
536 PUSH_VALUE (p, VALUE (&a_after), A68G_INT);
537 PUSH_VALUE (p, VALUE (&a_expo), A68G_INT);
538 PUSH_VALUE (p, VALUE (&a_mult), A68G_INT);
539 genie_real (p);
540 }
541 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
542 }
543
544
545 //! @brief Write %[-][+][w][.][d]s/d/i/f/e/b/o/x formats.
546
547 void write_c_pattern (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
548 {
549 ADDR_T pop_sp = A68G_SP;
550 BOOL_T right_align, sign, invalid;
551 int width = 0, after = 0, letter;
552 char *str = NO_TEXT;
553 char tmp[2]; // In same scope as str!
554 if (IS (p, CHAR_C_PATTERN)) {
555 A68G_CHAR *z = (A68G_CHAR *) item;
556 tmp[0] = (char) VALUE (z);
557 tmp[1] = NULL_CHAR;
558 str = (char *) &tmp;
559 width = (int) strlen (str);
560 scan_c_pattern (SUB (p), &right_align, &sign, &width, &after, &letter);
561 } else if (IS (p, STRING_C_PATTERN)) {
562 str = (char *) item;
563 width = (int) strlen (str);
564 scan_c_pattern (SUB (p), &right_align, &sign, &width, &after, &letter);
565 } else if (IS (p, INTEGRAL_C_PATTERN)) {
566 width = 0;
567 scan_c_pattern (SUB (p), &right_align, &sign, &width, &after, &letter);
568 unite_to_number (p, mode, item);
569 PUSH_VALUE (p, (sign ? width : -width), A68G_INT);
570 str = whole (p);
571 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
572 int att = ATTRIBUTE (p), expval = 0, expo = 0;
573 if (att == FLOAT_C_PATTERN || att == GENERAL_C_PATTERN) {
574 int digits = 0;
575 if (mode == M_REAL || mode == M_INT) {
576 width = A68G_REAL_WIDTH + A68G_EXP_WIDTH + 4;
577 after = A68G_REAL_WIDTH - 1;
578 expo = A68G_EXP_WIDTH + 1;
579 } else if (mode == M_LONG_REAL || mode == M_LONG_INT) {
580 width = A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4;
581 after = A68G_LONG_REAL_WIDTH - 1;
582 expo = A68G_LONG_EXP_WIDTH + 1;
583 } else if (mode == M_LONG_LONG_REAL || mode == M_LONG_LONG_INT) {
584 width = A68G_LONG_LONG_REAL_WIDTH + A68G_LONG_LONG_EXP_WIDTH + 4;
585 after = A68G_LONG_LONG_REAL_WIDTH - 1;
586 expo = A68G_LONG_LONG_EXP_WIDTH + 1;
587 }
588 scan_c_pattern (SUB (p), &right_align, &sign, &digits, &after, &letter);
589 if (digits == 0 && after > 0) {
590 width = after + expo + 4;
591 } else if (digits > 0) {
592 width = digits;
593 }
594 unite_to_number (p, mode, item);
595 PUSH_VALUE (p, (sign ? width : -width), A68G_INT);
596 PUSH_VALUE (p, after, A68G_INT);
597 PUSH_VALUE (p, expo, A68G_INT);
598 PUSH_VALUE (p, 1, A68G_INT);
599 str = real (p);
600 A68G_SP = pop_sp;
601 }
602 if (att == GENERAL_C_PATTERN) {
603 char *expch = strchr (str, EXPONENT_CHAR);
604 if (expch != NO_TEXT) {
605 expval = (int) strtol (&(expch[1]), NO_REF, 10);
606 }
607 }
608 if ((att == FIXED_C_PATTERN) || (att == GENERAL_C_PATTERN && (expval > -4 && expval <= after))) {
609 int digits = 0;
610 if (mode == M_REAL || mode == M_INT) {
611 width = A68G_REAL_WIDTH + 2;
612 after = A68G_REAL_WIDTH - 1;
613 } else if (mode == M_LONG_REAL || mode == M_LONG_INT) {
614 width = A68G_LONG_REAL_WIDTH + 2;
615 after = A68G_LONG_REAL_WIDTH - 1;
616 } else if (mode == M_LONG_LONG_REAL || mode == M_LONG_LONG_INT) {
617 width = A68G_LONG_LONG_REAL_WIDTH + 2;
618 after = A68G_LONG_LONG_REAL_WIDTH - 1;
619 }
620 scan_c_pattern (SUB (p), &right_align, &sign, &digits, &after, &letter);
621 if (digits == 0) {
622 width = 0;
623 } else if (digits > 0) {
624 width = digits + after + 2;
625 }
626 unite_to_number (p, mode, item);
627 PUSH_VALUE (p, (sign ? width : -width), A68G_INT);
628 PUSH_VALUE (p, after, A68G_INT);
629 str = fixed (p);
630 A68G_SP = pop_sp;
631 }
632 } else if (IS (p, BITS_C_PATTERN)) {
633 int radix = 10, nibble = 1;
634 width = 0;
635 scan_c_pattern (SUB (p), &right_align, &sign, &width, &after, &letter);
636 if (letter == FORMAT_ITEM_B) {
637 radix = 2;
638 nibble = 1;
639 } else if (letter == FORMAT_ITEM_O) {
640 radix = 8;
641 nibble = 3;
642 } else if (letter == FORMAT_ITEM_X) {
643 radix = 16;
644 nibble = 4;
645 }
646 if (width == 0) {
647 if (mode == M_BITS) {
648 width = (int) ceil ((REAL_T) A68G_BITS_WIDTH / (REAL_T) nibble);
649 } else if (mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
650 #if (A68G_LEVEL <= 2)
651 width = (int) ceil ((REAL_T) get_mp_bits_width (mode) / (REAL_T) nibble);
652 #else
653 width = (int) ceil ((REAL_T) A68G_LONG_BITS_WIDTH / (REAL_T) nibble);
654 #endif
655 }
656 }
657 if (mode == M_BITS) {
658 A68G_BITS *z = (A68G_BITS *) item;
659 reset_transput_buffer (EDIT_BUFFER);
660 if (!convert_radix (p, VALUE (z), radix, width)) {
661 errno = EDOM;
662 value_error (p, mode, ref_file);
663 }
664 str = get_transput_buffer (EDIT_BUFFER);
665 } else if (mode == M_LONG_BITS) {
666 #if (A68G_LEVEL >= 3)
667 A68G_LONG_BITS *z = (A68G_LONG_BITS *) item;
668 reset_transput_buffer (EDIT_BUFFER);
669 if (!convert_radix_double (p, VALUE (z), radix, width)) {
670 errno = EDOM;
671 value_error (p, mode, ref_file);
672 }
673 str = get_transput_buffer (EDIT_BUFFER);
674 #else
675 int digits = DIGITS (mode);
676 MP_T *u = (MP_T *) item;
677 MP_T *v = nil_mp (p, digits);
678 MP_T *w = nil_mp (p, digits);
679 reset_transput_buffer (EDIT_BUFFER);
680 if (!convert_radix_mp (p, u, radix, width, mode, v, w)) {
681 errno = EDOM;
682 value_error (p, mode, ref_file);
683 }
684 str = get_transput_buffer (EDIT_BUFFER);
685 #endif
686 } else if (mode == M_LONG_LONG_BITS) {
687 #if (A68G_LEVEL <= 2)
688 int digits = DIGITS (mode);
689 MP_T *u = (MP_T *) item;
690 MP_T *v = nil_mp (p, digits);
691 MP_T *w = nil_mp (p, digits);
692 reset_transput_buffer (EDIT_BUFFER);
693 if (!convert_radix_mp (p, u, radix, width, mode, v, w)) {
694 errno = EDOM;
695 value_error (p, mode, ref_file);
696 }
697 str = get_transput_buffer (EDIT_BUFFER);
698 #endif
699 }
700 }
701 // Did the conversion succeed?.
702 if (IS (p, CHAR_C_PATTERN) || IS (p, STRING_C_PATTERN)) {
703 invalid = A68G_FALSE;
704 } else {
705 invalid = (strchr (str, ERROR_CHAR) != NO_TEXT);
706 }
707 if (invalid) {
708 value_error (p, mode, ref_file);
709 (void) error_chars (get_transput_buffer (FORMATTED_BUFFER), width);
710 } else {
711 // Align and output.
712 if (width == 0) {
713 add_string_transput_buffer (p, FORMATTED_BUFFER, str);
714 } else {
715 if (right_align == A68G_TRUE) {
716 while (str[0] == BLANK_CHAR) {
717 str++;
718 }
719 int blanks = width - strlen (str);
720 if (blanks >= 0) {
721 add_string_transput_buffer (p, FORMATTED_BUFFER, str);
722 while (blanks--) {
723 plusab_transput_buffer (p, FORMATTED_BUFFER, BLANK_CHAR);
724 }
725 } else {
726 value_error (p, mode, ref_file);
727 (void) error_chars (get_transput_buffer (FORMATTED_BUFFER), width);
728 }
729 } else {
730 while (str[0] == BLANK_CHAR) {
731 str++;
732 }
733 int blanks = width - strlen (str);
734 if (blanks >= 0) {
735 while (blanks--) {
736 plusab_transput_buffer (p, FORMATTED_BUFFER, BLANK_CHAR);
737 }
738 add_string_transput_buffer (p, FORMATTED_BUFFER, str);
739 } else {
740 value_error (p, mode, ref_file);
741 (void) error_chars (get_transput_buffer (FORMATTED_BUFFER), width);
742 }
743 }
744 }
745 }
746 }
747
748
749 //! @brief Read one char from file.
750
751 char read_single_char (NODE_T * p, A68G_REF ref_file)
752 {
753 A68G_FILE *file = FILE_DEREF (&ref_file);
754 int ch = char_scanner (file);
755 if (ch == EOF_CHAR) {
756 end_of_file_error (p, ref_file);
757 }
758 return (char) ch;
759 }
760
761
762 //! @brief Scan n chars from file to input buffer.
763
764 void scan_n_chars (NODE_T * p, int n, MOID_T * m, A68G_REF ref_file)
765 {
766 (void) m;
767 for (int k = 0; k < n; k++) {
768 int ch = read_single_char (p, ref_file);
769 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
770 }
771 }
772
773
774 //! @brief Read %[-][+][w][.][d]s/d/i/f/e/b/o/x formats.
775
776 void read_c_pattern (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
777 {
778 ADDR_T pop_sp = A68G_SP;
779 BOOL_T right_align, sign;
780 int width, after, letter;
781 reset_transput_buffer (INPUT_BUFFER);
782 if (IS (p, CHAR_C_PATTERN)) {
783 width = 0;
784 scan_c_pattern (SUB (p), &right_align, &sign, &width, &after, &letter);
785 if (width == 0) {
786 genie_read_standard (p, mode, item, ref_file);
787 } else {
788 scan_n_chars (p, width, mode, ref_file);
789 if (width > 1 && right_align == A68G_FALSE) {
790 for (; width > 1; width--) {
791 (void) pop_char_transput_buffer (INPUT_BUFFER);
792 }
793 }
794 genie_string_to_value (p, mode, item, ref_file);
795 }
796 } else if (IS (p, STRING_C_PATTERN)) {
797 width = 0;
798 scan_c_pattern (SUB (p), &right_align, &sign, &width, &after, &letter);
799 if (width == 0) {
800 genie_read_standard (p, mode, item, ref_file);
801 } else {
802 scan_n_chars (p, width, mode, ref_file);
803 genie_string_to_value (p, mode, item, ref_file);
804 }
805 } else if (IS (p, INTEGRAL_C_PATTERN)) {
806 if (mode != M_INT && mode != M_LONG_INT && mode != M_LONG_LONG_INT) {
807 pattern_error (p, mode, ATTRIBUTE (p));
808 } else {
809 width = 0;
810 scan_c_pattern (SUB (p), &right_align, &sign, &width, &after, &letter);
811 if (width == 0) {
812 genie_read_standard (p, mode, item, ref_file);
813 } else {
814 scan_n_chars (p, (sign != 0) ? width + 1 : width, mode, ref_file);
815 genie_string_to_value (p, mode, item, ref_file);
816 }
817 }
818 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
819 if (mode != M_REAL && mode != M_LONG_REAL && mode != M_LONG_LONG_REAL) {
820 pattern_error (p, mode, ATTRIBUTE (p));
821 } else {
822 width = 0;
823 scan_c_pattern (SUB (p), &right_align, &sign, &width, &after, &letter);
824 if (width == 0) {
825 genie_read_standard (p, mode, item, ref_file);
826 } else {
827 scan_n_chars (p, (sign != 0) ? width + 1 : width, mode, ref_file);
828 genie_string_to_value (p, mode, item, ref_file);
829 }
830 }
831 } else if (IS (p, BITS_C_PATTERN)) {
832 if (mode != M_BITS && mode != M_LONG_BITS && mode != M_LONG_LONG_BITS) {
833 pattern_error (p, mode, ATTRIBUTE (p));
834 } else {
835 int radix = 10;
836 char *str;
837 width = 0;
838 scan_c_pattern (SUB (p), &right_align, &sign, &width, &after, &letter);
839 if (letter == FORMAT_ITEM_B) {
840 radix = 2;
841 } else if (letter == FORMAT_ITEM_O) {
842 radix = 8;
843 } else if (letter == FORMAT_ITEM_X) {
844 radix = 16;
845 }
846 str = get_transput_buffer (INPUT_BUFFER);
847 if (width == 0) {
848 A68G_FILE *file = FILE_DEREF (&ref_file);
849 int ch;
850 ASSERT (a68g_bufprt (str, (size_t) TRANSPUT_BUFFER_SIZE, "%dr", radix) >= 0);
851 set_transput_buffer_index (INPUT_BUFFER, strlen (str));
852 ch = char_scanner (file);
853 while (ch != EOF_CHAR && (IS_SPACE (ch) || IS_NL_FF (ch))) {
854 if (IS_NL_FF (ch)) {
855 skip_nl_ff (p, &ch, ref_file);
856 } else {
857 ch = char_scanner (file);
858 }
859 }
860 while (ch != EOF_CHAR && IS_XDIGIT (ch)) {
861 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
862 ch = char_scanner (file);
863 }
864 unchar_scanner (p, file, (char) ch);
865 } else {
866 ASSERT (a68g_bufprt (str, (size_t) TRANSPUT_BUFFER_SIZE, "%dr", radix) >= 0);
867 set_transput_buffer_index (INPUT_BUFFER, strlen (str));
868 scan_n_chars (p, width, mode, ref_file);
869 }
870 genie_string_to_value (p, mode, item, ref_file);
871 }
872 }
873 A68G_SP = pop_sp;
874 }
875
876 // INTEGRAL, REAL, COMPLEX and BITS patterns.
877
878
879 //! @brief Count Z and D frames in a mould.
880
881 void count_zd_frames (NODE_T * p, int *z)
882 {
883 for (; p != NO_NODE; FORWARD (p)) {
884 if (IS (p, FORMAT_ITEM_D) || IS (p, FORMAT_ITEM_Z)) {
885 (*z)++;
886 } else if (IS (p, REPLICATOR)) {
887 int k = get_replicator_value (SUB (p), A68G_TRUE);
888 for (int j = 1; j <= k; j++) {
889 count_zd_frames (NEXT (p), z);
890 }
891 return;
892 } else {
893 count_zd_frames (SUB (p), z);
894 }
895 }
896 }
897
898
899 //! @brief Get sign from sign mould.
900
901 NODE_T *get_sign (NODE_T * p)
902 {
903 for (; p != NO_NODE; FORWARD (p)) {
904 NODE_T *q = get_sign (SUB (p));
905 if (q != NO_NODE) {
906 return q;
907 } else if (IS (p, FORMAT_ITEM_PLUS) || IS (p, FORMAT_ITEM_MINUS)) {
908 return p;
909 }
910 }
911 return NO_NODE;
912 }
913
914
915 //! @brief Shift sign through Z frames until non-zero digit or D frame.
916
917 void shift_sign (NODE_T * p, char **q)
918 {
919 for (; p != NO_NODE && (*q) != NO_TEXT; FORWARD (p)) {
920 shift_sign (SUB (p), q);
921 if (IS (p, FORMAT_ITEM_Z)) {
922 if (((*q)[0] == '+' || (*q)[0] == '-') && (*q)[1] == '0') {
923 char ch = (*q)[0];
924 (*q)[0] = (*q)[1];
925 (*q)[1] = ch;
926 (*q)++;
927 }
928 } else if (IS (p, FORMAT_ITEM_D)) {
929 (*q) = NO_TEXT;
930 } else if (IS (p, REPLICATOR)) {
931 int k = get_replicator_value (SUB (p), A68G_TRUE);
932 for (int j = 1; j <= k; j++) {
933 shift_sign (NEXT (p), q);
934 }
935 return;
936 }
937 }
938 }
939
940
941 //! @brief Pad trailing blanks to integral until desired width.
942
943 void put_zeroes_to_integral (NODE_T * p, int n)
944 {
945 for (; n > 0; n--) {
946 plusab_transput_buffer (p, EDIT_BUFFER, '0');
947 }
948 }
949
950
951 //! @brief Pad a sign to integral representation.
952
953 void put_sign_to_integral (NODE_T * p, int sign)
954 {
955 NODE_T *sign_node = get_sign (SUB (p));
956 if (IS (sign_node, FORMAT_ITEM_PLUS)) {
957 plusab_transput_buffer (p, EDIT_BUFFER, (char) (sign >= 0 ? '+' : '-'));
958 } else {
959 plusab_transput_buffer (p, EDIT_BUFFER, (char) (sign >= 0 ? BLANK_CHAR : '-'));
960 }
961 }
962
963
964 //! @brief Write point, exponent or plus-i-times symbol.
965
966 void write_pie_frame (NODE_T * p, A68G_REF ref_file, int att, int sym)
967 {
968 for (; p != NO_NODE; FORWARD (p)) {
969 if (IS (p, INSERTION)) {
970 write_insertion (p, ref_file, INSERTION_NORMAL);
971 } else if (IS (p, att)) {
972 write_pie_frame (SUB (p), ref_file, att, sym);
973 return;
974 } else if (IS (p, sym)) {
975 add_string_transput_buffer (p, FORMATTED_BUFFER, NSYMBOL (p));
976 } else if (IS (p, FORMAT_ITEM_S)) {
977 return;
978 }
979 }
980 }
981
982
983 //! @brief Write sign when appropriate.
984
985 void write_mould_put_sign (NODE_T * p, char **q)
986 {
987 if ((*q)[0] == '+' || (*q)[0] == '-' || (*q)[0] == BLANK_CHAR) {
988 plusab_transput_buffer (p, FORMATTED_BUFFER, (*q)[0]);
989 (*q)++;
990 }
991 }
992
993
994 //! @brief Write character according to a mould.
995
996 void add_char_mould (NODE_T * p, char ch, char **q)
997 {
998 if (ch != NULL_CHAR) {
999 plusab_transput_buffer (p, FORMATTED_BUFFER, ch);
1000 (*q)++;
1001 }
1002 }
1003
1004
1005 //! @brief Write string according to a mould.
1006
1007 void write_mould (NODE_T * p, A68G_REF ref_file, int type, char **q, MOOD_T * mood)
1008 {
1009 for (; p != NO_NODE; FORWARD (p)) {
1010 // Insertions are inserted straight away. Note that we can suppress them using "mood", which is not standard A68.
1011 if (IS (p, INSERTION)) {
1012 write_insertion (SUB (p), ref_file, *mood);
1013 } else {
1014 write_mould (SUB (p), ref_file, type, q, mood);
1015 // Z frames print blanks until first non-zero digits comes.
1016 if (IS (p, FORMAT_ITEM_Z)) {
1017 write_mould_put_sign (p, q);
1018 if ((*q)[0] == '0') {
1019 if (*mood & DIGIT_BLANK) {
1020 add_char_mould (p, BLANK_CHAR, q);
1021 *mood = (*mood & ~INSERTION_NORMAL) | INSERTION_BLANK;
1022 } else if (*mood & DIGIT_NORMAL) {
1023 add_char_mould (p, '0', q);
1024 *mood = (MOOD_T) (DIGIT_NORMAL | INSERTION_NORMAL);
1025 }
1026 } else {
1027 add_char_mould (p, (*q)[0], q);
1028 *mood = (MOOD_T) (DIGIT_NORMAL | INSERTION_NORMAL);
1029 }
1030 }
1031 // D frames print a digit.
1032 else if (IS (p, FORMAT_ITEM_D)) {
1033 write_mould_put_sign (p, q);
1034 add_char_mould (p, (*q)[0], q);
1035 *mood = (MOOD_T) (DIGIT_NORMAL | INSERTION_NORMAL);
1036 }
1037 // Suppressible frames.
1038 else if (IS (p, FORMAT_ITEM_S)) {
1039 // Suppressible frames are ignored in a sign-mould.
1040 if (type == SIGN_MOULD) {
1041 write_mould (NEXT (p), ref_file, type, q, mood);
1042 } else if (type == INTEGRAL_MOULD) {
1043 if ((*q)[0] != NULL_CHAR) {
1044 (*q)++;
1045 }
1046 }
1047 return;
1048 }
1049 // Replicator.
1050 else if (IS (p, REPLICATOR)) {
1051 int k = get_replicator_value (SUB (p), A68G_TRUE);
1052 for (int j = 1; j <= k; j++) {
1053 write_mould (NEXT (p), ref_file, type, q, mood);
1054 }
1055 return;
1056 }
1057 }
1058 }
1059 }
1060
1061
1062 //! @brief Write INT value using int pattern.
1063
1064 void write_integral_pattern (NODE_T * p, MOID_T * mode, MOID_T * root, BYTE_T * item, A68G_REF ref_file)
1065 {
1066 errno = 0;
1067 if (!(mode == M_INT || mode == M_LONG_INT || mode == M_LONG_LONG_INT)) {
1068 pattern_error (p, root, ATTRIBUTE (p));
1069 } else {
1070 ADDR_T pop_sp = A68G_SP;
1071 char *str = "*";
1072 int width = 0, sign = 0;
1073 MOOD_T mood;
1074 // Dive into the pattern if needed.
1075 if (IS (p, INTEGRAL_PATTERN)) {
1076 p = SUB (p);
1077 }
1078 // Find width.
1079 count_zd_frames (p, &width);
1080 // Make string.
1081 reset_transput_buffer (EDIT_BUFFER);
1082 int digits = DIGITS (M_LONG_LONG_INT);
1083 MP_T *z = nil_mp (p, digits);
1084 if (mode == M_INT) {
1085 int_to_mp (p, z, VALUE ((A68G_INT *) item), digits);
1086 } else if (mode == M_LONG_INT) {
1087 #if (A68G_LEVEL >= 3)
1088 DOUBLE_NUM_T w = VALUE ((A68G_LONG_INT *) item);
1089 double_int_to_mp (p, z, w, digits);
1090 #else
1091 (void) lengthen_mp (p, z, digits, (MP_T *) item, DIGITS (M_LONG_INT));
1092 #endif
1093 } else if (mode == M_LONG_LONG_INT) {
1094 (void) move_mp (z, (MP_T *) item, digits);
1095 }
1096 sign = MP_SIGN (z);
1097 MP_DIGIT (z, 1) = ABS (MP_DIGIT (z, 1));
1098 str = sub_whole_mp (p, z, digits, width);
1099 // Edit string and output.
1100 if (strchr (str, ERROR_CHAR) != NO_TEXT) {
1101 value_error (p, root, ref_file);
1102 }
1103 if (IS (p, SIGN_MOULD)) {
1104 put_sign_to_integral (p, sign);
1105 } else if (sign < 0) {
1106 value_sign_error (p, root, ref_file);
1107 }
1108 put_zeroes_to_integral (p, width - strlen (str));
1109 add_string_transput_buffer (p, EDIT_BUFFER, str);
1110 str = get_transput_buffer (EDIT_BUFFER);
1111 mood = (MOOD_T) (DIGIT_BLANK | INSERTION_NORMAL);
1112 if (IS (p, SIGN_MOULD)) {
1113 if (str[0] == '+' || str[0] == '-') {
1114 shift_sign (SUB (p), &str);
1115 }
1116 str = get_transput_buffer (EDIT_BUFFER);
1117 write_mould (SUB (p), ref_file, SIGN_MOULD, &str, &mood);
1118 FORWARD (p);
1119 }
1120 if (IS (p, INTEGRAL_MOULD)) { // This *should* be the case
1121 write_mould (SUB (p), ref_file, INTEGRAL_MOULD, &str, &mood);
1122 }
1123 A68G_SP = pop_sp;
1124 }
1125 }
1126
1127
1128 //! @brief Write REAL value using real pattern.
1129
1130 void write_real_pattern (NODE_T * p, MOID_T * mode, MOID_T * root, BYTE_T * item, A68G_REF ref_file)
1131 {
1132 errno = 0;
1133 if (!(mode == M_REAL || mode == M_LONG_REAL || mode == M_LONG_LONG_REAL || mode == M_INT || mode == M_LONG_INT || mode == M_LONG_LONG_INT)) {
1134 pattern_error (p, root, ATTRIBUTE (p));
1135 } else {
1136 ADDR_T pop_sp = A68G_SP;
1137 int stag_digits = 0, frac_digits = 0, expo_digits = 0;
1138 int mant_length, sign = 0, exp_value;
1139 NODE_T *q, *sign_mould = NO_NODE, *stag_mould = NO_NODE, *point_frame = NO_NODE, *frac_mould = NO_NODE, *e_frame = NO_NODE, *expo_mould = NO_NODE;
1140 char *str = NO_TEXT, *stag_str = NO_TEXT, *frac_str = NO_TEXT;
1141 MOOD_T mood;
1142 // Dive into pattern.
1143 q = ((IS (p, REAL_PATTERN)) ? SUB (p) : p);
1144 // Dissect pattern and establish widths.
1145 if (q != NO_NODE && IS (q, SIGN_MOULD)) {
1146 sign_mould = q;
1147 count_zd_frames (SUB (sign_mould), &stag_digits);
1148 FORWARD (q);
1149 }
1150 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
1151 stag_mould = q;
1152 count_zd_frames (SUB (stag_mould), &stag_digits);
1153 FORWARD (q);
1154 }
1155 if (q != NO_NODE && IS (q, FORMAT_POINT_FRAME)) {
1156 point_frame = q;
1157 FORWARD (q);
1158 }
1159 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
1160 frac_mould = q;
1161 count_zd_frames (SUB (frac_mould), &frac_digits);
1162 FORWARD (q);
1163 }
1164 if (q != NO_NODE && IS (q, EXPONENT_FRAME)) {
1165 e_frame = SUB (q);
1166 expo_mould = NEXT_SUB (q);
1167 q = expo_mould;
1168 if (IS (q, SIGN_MOULD)) {
1169 count_zd_frames (SUB (q), &expo_digits);
1170 FORWARD (q);
1171 }
1172 if (IS (q, INTEGRAL_MOULD)) {
1173 count_zd_frames (SUB (q), &expo_digits);
1174 }
1175 }
1176 // Make string representation.
1177 if (point_frame == NO_NODE) {
1178 mant_length = stag_digits;
1179 } else {
1180 mant_length = 1 + stag_digits + frac_digits;
1181 }
1182 //
1183 ADDR_T pop_sp2 = A68G_SP;
1184 int digits = DIGITS (M_LONG_LONG_REAL);
1185 MP_T *z = nil_mp (p, digits);
1186 if (mode == M_INT) {
1187 INT_T x = VALUE ((A68G_INT *) item);
1188 (void) int_to_mp (p, z, x, digits);
1189 } else if (mode == M_REAL) {
1190 REAL_T x = VALUE ((A68G_REAL *) item);
1191 CHECK_REAL (p, x, M_REAL);
1192 #if (A68G_LEVEL >= 3)
1193 (void) double_to_mp (p, z, (DOUBLE_T) x, digits);
1194 #else
1195 (void) real_to_mp (p, z, x, digits);
1196 #endif
1197 } else if (mode == M_LONG_INT) {
1198 #if (A68G_LEVEL >= 3)
1199 DOUBLE_NUM_T x = VALUE ((A68G_DOUBLE *) item);
1200 (void) double_int_to_mp (p, z, x, digits);
1201 #else
1202 (void) lengthen_mp (p, z, digits, (MP_T *) item, DIGITS (M_LONG_INT));
1203 #endif
1204 } else if (mode == M_LONG_REAL) {
1205 #if (A68G_LEVEL >= 3)
1206 DOUBLE_T x = VALUE ((A68G_DOUBLE *) item).f;
1207 CHECK_DOUBLE_REAL (p, x, M_LONG_REAL);
1208 (void) double_to_mp (p, z, x, digits);
1209 #else
1210 (void) lengthen_mp (p, z, digits, (MP_T *) item, DIGITS (M_LONG_REAL));
1211 #endif
1212 } else if (mode == M_LONG_LONG_REAL || mode == M_LONG_LONG_INT) {
1213 (void) move_mp (z, (MP_T *) item, digits);
1214 }
1215 exp_value = 0;
1216 sign = SIGN (z[2]);
1217 if (sign_mould != NO_NODE) {
1218 put_sign_to_integral (sign_mould, sign);
1219 }
1220 z[2] = ABS (z[2]);
1221 if (expo_mould != NO_NODE) {
1222 standardize_mp (p, z, digits, stag_digits, frac_digits, &exp_value);
1223 }
1224 str = sub_fixed_mp (p, z, digits, mant_length, frac_digits);
1225 A68G_SP = pop_sp2;
1226 // Edit and output the string.
1227 if (strchr (str, ERROR_CHAR) != NO_TEXT) {
1228 value_error (p, root, ref_file);
1229 }
1230 reset_transput_buffer (STRING_BUFFER);
1231 add_string_transput_buffer (p, STRING_BUFFER, str);
1232 stag_str = get_transput_buffer (STRING_BUFFER);
1233 if (strchr (stag_str, ERROR_CHAR) != NO_TEXT) {
1234 value_error (p, root, ref_file);
1235 }
1236 str = strchr (stag_str, POINT_CHAR);
1237 if (str != NO_TEXT) {
1238 frac_str = &str[1];
1239 str[0] = NULL_CHAR;
1240 } else {
1241 frac_str = NO_TEXT;
1242 }
1243 // Stagnant part.
1244 reset_transput_buffer (EDIT_BUFFER);
1245 if (sign_mould != NO_NODE) {
1246 put_sign_to_integral (sign_mould, sign);
1247 } else if (sign < 0) {
1248 value_sign_error (sign_mould, root, ref_file);
1249 }
1250 put_zeroes_to_integral (p, stag_digits - strlen (stag_str));
1251 add_string_transput_buffer (p, EDIT_BUFFER, stag_str);
1252 stag_str = get_transput_buffer (EDIT_BUFFER);
1253 mood = (MOOD_T) (DIGIT_BLANK | INSERTION_NORMAL);
1254 if (sign_mould != NO_NODE) {
1255 if (stag_str[0] == '+' || stag_str[0] == '-') {
1256 shift_sign (SUB (p), &stag_str);
1257 }
1258 stag_str = get_transput_buffer (EDIT_BUFFER);
1259 write_mould (SUB (sign_mould), ref_file, SIGN_MOULD, &stag_str, &mood);
1260 }
1261 if (stag_mould != NO_NODE) {
1262 write_mould (SUB (stag_mould), ref_file, INTEGRAL_MOULD, &stag_str, &mood);
1263 }
1264 // Point frame.
1265 if (point_frame != NO_NODE) {
1266 write_pie_frame (point_frame, ref_file, FORMAT_POINT_FRAME, FORMAT_ITEM_POINT);
1267 }
1268 // Fraction.
1269 if (frac_mould != NO_NODE) {
1270 reset_transput_buffer (EDIT_BUFFER);
1271 add_string_transput_buffer (p, EDIT_BUFFER, frac_str);
1272 frac_str = get_transput_buffer (EDIT_BUFFER);
1273 mood = (MOOD_T) (DIGIT_NORMAL | INSERTION_NORMAL);
1274 write_mould (SUB (frac_mould), ref_file, INTEGRAL_MOULD, &frac_str, &mood);
1275 }
1276 // Exponent.
1277 if (expo_mould != NO_NODE) {
1278 A68G_INT k;
1279 STATUS (&k) = INIT_MASK;
1280 VALUE (&k) = exp_value;
1281 if (e_frame != NO_NODE) {
1282 write_pie_frame (e_frame, ref_file, FORMAT_E_FRAME, FORMAT_ITEM_E);
1283 }
1284 write_integral_pattern (expo_mould, M_INT, root, (BYTE_T *) & k, ref_file);
1285 }
1286 A68G_SP = pop_sp;
1287 }
1288 }
1289
1290
1291 //! @brief Write COMPLEX value using complex pattern.
1292
1293 void write_complex_pattern (NODE_T * p, MOID_T * comp, MOID_T * root, BYTE_T * re, BYTE_T * im, A68G_REF ref_file)
1294 {
1295 errno = 0;
1296 // Dissect pattern.
1297 NODE_T *reel = SUB (p);
1298 NODE_T *plus_i_times = NEXT (reel);
1299 NODE_T *imag = NEXT (plus_i_times);
1300 // Write pattern.
1301 write_real_pattern (reel, comp, root, re, ref_file);
1302 write_pie_frame (plus_i_times, ref_file, FORMAT_I_FRAME, FORMAT_ITEM_I);
1303 write_real_pattern (imag, comp, root, im, ref_file);
1304 }
1305
1306
1307 //! @brief Write BITS value using bits pattern.
1308
1309 void write_bits_pattern (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
1310 {
1311 ADDR_T pop_sp = A68G_SP;
1312 int width = 0, radix;
1313 char *str;
1314 if (mode == M_BITS) {
1315 A68G_BITS *z = (A68G_BITS *) item;
1316 // Establish width and radix.
1317 count_zd_frames (SUB (p), &width);
1318 radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
1319 if (radix < 2 || radix > 16) {
1320 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
1321 exit_genie (p, A68G_RUNTIME_ERROR);
1322 }
1323 // Generate string of correct width.
1324 reset_transput_buffer (EDIT_BUFFER);
1325 if (!convert_radix (p, VALUE (z), radix, width)) {
1326 errno = EDOM;
1327 value_error (p, mode, ref_file);
1328 }
1329 } else if (mode == M_LONG_BITS) {
1330 #if (A68G_LEVEL >= 3)
1331 A68G_LONG_BITS *z = (A68G_LONG_BITS *) item;
1332 // Establish width and radix.
1333 count_zd_frames (SUB (p), &width);
1334 radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
1335 if (radix < 2 || radix > 16) {
1336 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
1337 exit_genie (p, A68G_RUNTIME_ERROR);
1338 }
1339 // Generate string of correct width.
1340 reset_transput_buffer (EDIT_BUFFER);
1341 if (!convert_radix_double (p, VALUE (z), radix, width)) {
1342 errno = EDOM;
1343 value_error (p, mode, ref_file);
1344 }
1345 #else
1346 int digits = DIGITS (mode);
1347 MP_T *u = (MP_T *) item;
1348 MP_T *v = nil_mp (p, digits);
1349 MP_T *w = nil_mp (p, digits);
1350 // Establish width and radix.
1351 count_zd_frames (SUB (p), &width);
1352 radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
1353 if (radix < 2 || radix > 16) {
1354 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
1355 exit_genie (p, A68G_RUNTIME_ERROR);
1356 }
1357 // Generate string of correct width.
1358 reset_transput_buffer (EDIT_BUFFER);
1359 if (!convert_radix_mp (p, u, radix, width, mode, v, w)) {
1360 errno = EDOM;
1361 value_error (p, mode, ref_file);
1362 }
1363 #endif
1364 } else if (mode == M_LONG_LONG_BITS) {
1365 #if (A68G_LEVEL <= 2)
1366 int digits = DIGITS (mode);
1367 MP_T *u = (MP_T *) item;
1368 MP_T *v = nil_mp (p, digits);
1369 MP_T *w = nil_mp (p, digits);
1370 // Establish width and radix.
1371 count_zd_frames (SUB (p), &width);
1372 radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
1373 if (radix < 2 || radix > 16) {
1374 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
1375 exit_genie (p, A68G_RUNTIME_ERROR);
1376 }
1377 // Generate string of correct width.
1378 reset_transput_buffer (EDIT_BUFFER);
1379 if (!convert_radix_mp (p, u, radix, width, mode, v, w)) {
1380 errno = EDOM;
1381 value_error (p, mode, ref_file);
1382 }
1383 #endif
1384 }
1385 // Output the edited string.
1386 MOOD_T mood = (MOOD_T) (DIGIT_BLANK | INSERTION_NORMAL);
1387 str = get_transput_buffer (EDIT_BUFFER);
1388 write_mould (NEXT_SUB (p), ref_file, INTEGRAL_MOULD, &str, &mood);
1389 A68G_SP = pop_sp;
1390 }
1391
1392
1393 //! @brief Write value to file.
1394
1395 void genie_write_real_format (NODE_T * p, BYTE_T * item, A68G_REF ref_file)
1396 {
1397 if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) == NO_NODE) {
1398 genie_value_to_string (p, M_REAL, item, ATTRIBUTE (SUB (p)));
1399 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1400 } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
1401 write_number_generic (p, M_REAL, item, ATTRIBUTE (SUB (p)));
1402 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
1403 write_c_pattern (p, M_REAL, item, ref_file);
1404 } else if (IS (p, REAL_PATTERN)) {
1405 write_real_pattern (p, M_REAL, M_REAL, item, ref_file);
1406 } else if (IS (p, COMPLEX_PATTERN)) {
1407 A68G_REAL im;
1408 STATUS (&im) = INIT_MASK;
1409 VALUE (&im) = 0.0;
1410 write_complex_pattern (p, M_REAL, M_COMPLEX, (BYTE_T *) item, (BYTE_T *) & im, ref_file);
1411 } else {
1412 pattern_error (p, M_REAL, ATTRIBUTE (p));
1413 }
1414 }
1415
1416
1417 //! @brief Write value to file.
1418
1419 void genie_write_long_real_format (NODE_T * p, BYTE_T * item, A68G_REF ref_file)
1420 {
1421 if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) == NO_NODE) {
1422 genie_value_to_string (p, M_LONG_REAL, item, ATTRIBUTE (SUB (p)));
1423 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1424 } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
1425 write_number_generic (p, M_LONG_REAL, item, ATTRIBUTE (SUB (p)));
1426 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
1427 write_c_pattern (p, M_LONG_REAL, item, ref_file);
1428 } else if (IS (p, REAL_PATTERN)) {
1429 write_real_pattern (p, M_LONG_REAL, M_LONG_REAL, item, ref_file);
1430 } else if (IS (p, COMPLEX_PATTERN)) {
1431 #if (A68G_LEVEL >= 3)
1432 ADDR_T pop_sp = A68G_SP;
1433 A68G_LONG_REAL *z = (A68G_LONG_REAL *) STACK_TOP;
1434 DOUBLE_NUM_T im;
1435 im.f = 0.0q;
1436 PUSH_VALUE (p, im, A68G_LONG_REAL);
1437 write_complex_pattern (p, M_LONG_REAL, M_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1438 A68G_SP = pop_sp;
1439 #else
1440 ADDR_T pop_sp = A68G_SP;
1441 MP_T *z = nil_mp (p, DIGITS (M_LONG_REAL));
1442 z[0] = (MP_T) INIT_MASK;
1443 write_complex_pattern (p, M_LONG_REAL, M_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1444 A68G_SP = pop_sp;
1445 #endif
1446 } else {
1447 pattern_error (p, M_LONG_REAL, ATTRIBUTE (p));
1448 }
1449 }
1450
1451
1452 //! @brief Write value to file.
1453
1454 void genie_write_long_mp_real_format (NODE_T * p, BYTE_T * item, A68G_REF ref_file)
1455 {
1456 if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) == NO_NODE) {
1457 genie_value_to_string (p, M_LONG_LONG_REAL, item, ATTRIBUTE (SUB (p)));
1458 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1459 } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
1460 write_number_generic (p, M_LONG_LONG_REAL, item, ATTRIBUTE (SUB (p)));
1461 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
1462 write_c_pattern (p, M_LONG_LONG_REAL, item, ref_file);
1463 } else if (IS (p, REAL_PATTERN)) {
1464 write_real_pattern (p, M_LONG_LONG_REAL, M_LONG_LONG_REAL, item, ref_file);
1465 } else if (IS (p, COMPLEX_PATTERN)) {
1466 ADDR_T pop_sp = A68G_SP;
1467 MP_T *z = nil_mp (p, DIGITS (M_LONG_LONG_REAL));
1468 z[0] = (MP_T) INIT_MASK;
1469 write_complex_pattern (p, M_LONG_LONG_REAL, M_LONG_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1470 A68G_SP = pop_sp;
1471 } else {
1472 pattern_error (p, M_LONG_LONG_REAL, ATTRIBUTE (p));
1473 }
1474 }
1475
1476
1477 //! @brief At end of write purge all insertions.
1478
1479 void purge_format_write (NODE_T * p, A68G_REF ref_file)
1480 {
1481 // Problem here is shutting down embedded formats.
1482 BOOL_T siga;
1483 do {
1484 A68G_FILE *file;
1485 NODE_T *dollar, *pat;
1486 A68G_FORMAT *old_fmt;
1487 while ((pat = get_next_format_pattern (p, ref_file, SKIP_PATTERN)) != NO_NODE) {
1488 format_error (p, ref_file, ERROR_FORMAT_PICTURES);
1489 }
1490 file = FILE_DEREF (&ref_file);
1491 dollar = SUB (BODY (&FORMAT (file)));
1492 old_fmt = (A68G_FORMAT *) FRAME_LOCAL (A68G_FP, OFFSET (TAX (dollar)));
1493 siga = (BOOL_T) ! IS_NIL_FORMAT (old_fmt);
1494 if (siga) {
1495 // Pop embedded format and proceed.
1496 (void) end_of_format (p, ref_file);
1497 }
1498 } while (siga);
1499 }
1500
1501
1502 //! @brief Write value to file.
1503
1504 void genie_write_standard_format (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file, int *formats)
1505 {
1506 errno = 0;
1507 ABEND (mode == NO_MOID, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
1508 if (mode == M_FORMAT) {
1509 A68G_FILE *file;
1510 CHECK_REF (p, ref_file, M_REF_FILE);
1511 file = FILE_DEREF (&ref_file);
1512 // Forget about eventual active formats and set up new one.
1513 if (*formats > 0) {
1514 purge_format_write (p, ref_file);
1515 }
1516 (*formats)++;
1517 A68G_FP = FRAME_POINTER (file);
1518 A68G_SP = STACK_POINTER (file);
1519 open_format_frame (p, ref_file, (A68G_FORMAT *) item, NOT_EMBEDDED_FORMAT, A68G_TRUE);
1520 } else if (mode == M_PROC_REF_FILE_VOID) {
1521 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_PROC_REF_FILE_VOID);
1522 exit_genie (p, A68G_RUNTIME_ERROR);
1523 } else if (mode == M_SOUND) {
1524 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_SOUND);
1525 exit_genie (p, A68G_RUNTIME_ERROR);
1526 } else if (mode == M_INT) {
1527 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1528 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1529 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (pat)));
1530 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1531 } else if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) != NO_NODE) {
1532 write_number_generic (pat, M_INT, item, ATTRIBUTE (SUB (pat)));
1533 } else if (IS (pat, INTEGRAL_C_PATTERN) || IS (pat, FIXED_C_PATTERN) || IS (pat, FLOAT_C_PATTERN) || IS (pat, GENERAL_C_PATTERN)) {
1534 write_c_pattern (pat, M_INT, item, ref_file);
1535 } else if (IS (pat, INTEGRAL_PATTERN)) {
1536 write_integral_pattern (pat, M_INT, M_INT, item, ref_file);
1537 } else if (IS (pat, REAL_PATTERN)) {
1538 write_real_pattern (pat, M_INT, M_INT, item, ref_file);
1539 } else if (IS (pat, COMPLEX_PATTERN)) {
1540 A68G_REAL re, im;
1541 STATUS (&re) = INIT_MASK;
1542 VALUE (&re) = (REAL_T) VALUE ((A68G_INT *) item);
1543 STATUS (&im) = INIT_MASK;
1544 VALUE (&im) = 0.0;
1545 write_complex_pattern (pat, M_REAL, M_COMPLEX, (BYTE_T *) & re, (BYTE_T *) & im, ref_file);
1546 } else if (IS (pat, CHOICE_PATTERN)) {
1547 int k = VALUE ((A68G_INT *) item);
1548 write_choice_pattern (NEXT_SUB (pat), ref_file, &k);
1549 } else {
1550 pattern_error (p, mode, ATTRIBUTE (pat));
1551 }
1552 } else if (mode == M_LONG_INT) {
1553 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1554 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1555 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (pat)));
1556 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1557 } else if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) != NO_NODE) {
1558 write_number_generic (pat, M_LONG_INT, item, ATTRIBUTE (SUB (pat)));
1559 } else if (IS (pat, INTEGRAL_C_PATTERN) || IS (pat, FIXED_C_PATTERN) || IS (pat, FLOAT_C_PATTERN) || IS (pat, GENERAL_C_PATTERN)) {
1560 write_c_pattern (pat, M_LONG_INT, item, ref_file);
1561 } else if (IS (pat, INTEGRAL_PATTERN)) {
1562 write_integral_pattern (pat, M_LONG_INT, M_LONG_INT, item, ref_file);
1563 } else if (IS (pat, REAL_PATTERN)) {
1564 write_real_pattern (pat, M_LONG_INT, M_LONG_INT, item, ref_file);
1565 } else if (IS (pat, COMPLEX_PATTERN)) {
1566 #if (A68G_LEVEL >= 3)
1567 ADDR_T pop_sp = A68G_SP;
1568 A68G_LONG_REAL *z = (A68G_LONG_REAL *) STACK_TOP;
1569 DOUBLE_NUM_T im;
1570 im.f = 0.0q;
1571 PUSH_VALUE (p, im, A68G_LONG_REAL);
1572 write_complex_pattern (p, M_LONG_REAL, M_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1573 A68G_SP = pop_sp;
1574 #else
1575 ADDR_T pop_sp = A68G_SP;
1576 MP_T *z = nil_mp (p, DIGITS (mode));
1577 z[0] = (MP_T) INIT_MASK;
1578 write_complex_pattern (pat, M_LONG_REAL, M_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1579 A68G_SP = pop_sp;
1580 #endif
1581 } else if (IS (pat, CHOICE_PATTERN)) {
1582 INT_T k = mp_to_int (p, (MP_T *) item, DIGITS (mode));
1583 int sk;
1584 CHECK_INT_SHORTEN (p, k);
1585 sk = (int) k;
1586 write_choice_pattern (NEXT_SUB (pat), ref_file, &sk);
1587 } else {
1588 pattern_error (p, mode, ATTRIBUTE (pat));
1589 }
1590 } else if (mode == M_LONG_LONG_INT) {
1591 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1592 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1593 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (pat)));
1594 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1595 } else if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) != NO_NODE) {
1596 write_number_generic (pat, M_LONG_LONG_INT, item, ATTRIBUTE (SUB (pat)));
1597 } else if (IS (pat, INTEGRAL_C_PATTERN) || IS (pat, FIXED_C_PATTERN) || IS (pat, FLOAT_C_PATTERN) || IS (pat, GENERAL_C_PATTERN)) {
1598 write_c_pattern (pat, M_LONG_LONG_INT, item, ref_file);
1599 } else if (IS (pat, INTEGRAL_PATTERN)) {
1600 write_integral_pattern (pat, M_LONG_LONG_INT, M_LONG_LONG_INT, item, ref_file);
1601 } else if (IS (pat, REAL_PATTERN)) {
1602 write_real_pattern (pat, M_INT, M_INT, item, ref_file);
1603 } else if (IS (pat, REAL_PATTERN)) {
1604 write_real_pattern (pat, M_LONG_LONG_INT, M_LONG_LONG_INT, item, ref_file);
1605 } else if (IS (pat, COMPLEX_PATTERN)) {
1606 ADDR_T pop_sp = A68G_SP;
1607 MP_T *z = nil_mp (p, DIGITS (M_LONG_LONG_REAL));
1608 z[0] = (MP_T) INIT_MASK;
1609 write_complex_pattern (pat, M_LONG_LONG_REAL, M_LONG_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1610 A68G_SP = pop_sp;
1611 } else if (IS (pat, CHOICE_PATTERN)) {
1612 INT_T k = mp_to_int (p, (MP_T *) item, DIGITS (mode));
1613 int sk;
1614 CHECK_INT_SHORTEN (p, k);
1615 sk = (int) k;
1616 write_choice_pattern (NEXT_SUB (pat), ref_file, &sk);
1617 } else {
1618 pattern_error (p, mode, ATTRIBUTE (pat));
1619 }
1620 } else if (mode == M_REAL) {
1621 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1622 genie_write_real_format (pat, item, ref_file);
1623 } else if (mode == M_LONG_REAL) {
1624 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1625 genie_write_long_real_format (pat, item, ref_file);
1626 } else if (mode == M_LONG_LONG_REAL) {
1627 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1628 genie_write_long_mp_real_format (pat, item, ref_file);
1629 } else if (mode == M_COMPLEX) {
1630 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1631 if (IS (pat, COMPLEX_PATTERN)) {
1632 write_complex_pattern (pat, M_REAL, M_COMPLEX, &item[0], &item[SIZE (M_REAL)], ref_file);
1633 } else {
1634 // Try writing as two REAL values.
1635 genie_write_real_format (pat, item, ref_file);
1636 genie_write_standard_format (p, M_REAL, &item[SIZE (M_REAL)], ref_file, formats);
1637 }
1638 } else if (mode == M_LONG_COMPLEX) {
1639 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1640 if (IS (pat, COMPLEX_PATTERN)) {
1641 write_complex_pattern (pat, M_LONG_REAL, M_LONG_COMPLEX, &item[0], &item[SIZE (M_LONG_REAL)], ref_file);
1642 } else {
1643 // Try writing as two LONG REAL values.
1644 genie_write_long_real_format (pat, item, ref_file);
1645 genie_write_standard_format (p, M_LONG_REAL, &item[SIZE (M_LONG_REAL)], ref_file, formats);
1646 }
1647 } else if (mode == M_LONG_LONG_COMPLEX) {
1648 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1649 if (IS (pat, COMPLEX_PATTERN)) {
1650 write_complex_pattern (pat, M_LONG_LONG_REAL, M_LONG_LONG_COMPLEX, &item[0], &item[SIZE (M_LONG_LONG_REAL)], ref_file);
1651 } else {
1652 // Try writing as two LONG LONG REAL values.
1653 genie_write_long_mp_real_format (pat, item, ref_file);
1654 genie_write_standard_format (p, M_LONG_LONG_REAL, &item[SIZE (M_LONG_LONG_REAL)], ref_file, formats);
1655 }
1656 } else if (mode == M_BOOL) {
1657 A68G_BOOL *z = (A68G_BOOL *) item;
1658 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1659 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1660 plusab_transput_buffer (p, FORMATTED_BUFFER, (char) (VALUE (z) == A68G_TRUE ? FLIP_CHAR : FLOP_CHAR));
1661 } else if (IS (pat, BOOLEAN_PATTERN)) {
1662 if (NEXT_SUB (pat) == NO_NODE) {
1663 plusab_transput_buffer (p, FORMATTED_BUFFER, (char) (VALUE (z) == A68G_TRUE ? FLIP_CHAR : FLOP_CHAR));
1664 } else {
1665 write_boolean_pattern (pat, ref_file, (BOOL_T) (VALUE (z) == A68G_TRUE));
1666 }
1667 } else {
1668 pattern_error (p, mode, ATTRIBUTE (pat));
1669 }
1670 } else if (mode == M_BITS) {
1671 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1672 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1673 char *str = (char *) STACK_TOP;
1674 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (p)));
1675 add_string_transput_buffer (p, FORMATTED_BUFFER, str);
1676 } else if (IS (pat, BITS_PATTERN)) {
1677 write_bits_pattern (pat, M_BITS, item, ref_file);
1678 } else if (IS (pat, BITS_C_PATTERN)) {
1679 write_c_pattern (pat, M_BITS, item, ref_file);
1680 } else {
1681 pattern_error (p, mode, ATTRIBUTE (pat));
1682 }
1683 } else if (mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
1684 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1685 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1686 char *str = (char *) STACK_TOP;
1687 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (p)));
1688 add_string_transput_buffer (p, FORMATTED_BUFFER, str);
1689 } else if (IS (pat, BITS_PATTERN)) {
1690 write_bits_pattern (pat, mode, item, ref_file);
1691 } else if (IS (pat, BITS_C_PATTERN)) {
1692 write_c_pattern (pat, mode, item, ref_file);
1693 } else {
1694 pattern_error (p, mode, ATTRIBUTE (pat));
1695 }
1696 } else if (mode == M_CHAR) {
1697 A68G_CHAR *z = (A68G_CHAR *) item;
1698 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1699 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1700 plusab_transput_buffer (p, FORMATTED_BUFFER, (char) VALUE (z));
1701 } else if (IS (pat, STRING_PATTERN)) {
1702 char *q = get_transput_buffer (EDIT_BUFFER);
1703 reset_transput_buffer (EDIT_BUFFER);
1704 plusab_transput_buffer (p, EDIT_BUFFER, (char) VALUE (z));
1705 write_string_pattern (pat, mode, ref_file, &q);
1706 if (q[0] != NULL_CHAR) {
1707 value_error (p, mode, ref_file);
1708 }
1709 } else if (IS (pat, STRING_C_PATTERN)) {
1710 char zz[2];
1711 zz[0] = VALUE (z);
1712 zz[1] = '\0';
1713 (void) c_to_a_string (pat, zz, 1);
1714 write_c_pattern (pat, mode, (BYTE_T *) zz, ref_file);
1715 } else {
1716 pattern_error (p, mode, ATTRIBUTE (pat));
1717 }
1718 } else if (mode == M_ROW_CHAR || mode == M_STRING) {
1719 // Handle these separately instead of printing [] CHAR.
1720 A68G_REF row = *(A68G_REF *) item;
1721 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1722 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1723 PUSH_REF (p, row);
1724 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1725 } else if (IS (pat, STRING_PATTERN)) {
1726 char *q;
1727 PUSH_REF (p, row);
1728 reset_transput_buffer (EDIT_BUFFER);
1729 add_string_from_stack_transput_buffer (p, EDIT_BUFFER);
1730 q = get_transput_buffer (EDIT_BUFFER);
1731 write_string_pattern (pat, mode, ref_file, &q);
1732 if (q[0] != NULL_CHAR) {
1733 value_error (p, mode, ref_file);
1734 }
1735 } else if (IS (pat, STRING_C_PATTERN)) {
1736 char *q;
1737 PUSH_REF (p, row);
1738 reset_transput_buffer (EDIT_BUFFER);
1739 add_string_from_stack_transput_buffer (p, EDIT_BUFFER);
1740 q = get_transput_buffer (EDIT_BUFFER);
1741 write_c_pattern (pat, mode, (BYTE_T *) q, ref_file);
1742 } else {
1743 pattern_error (p, mode, ATTRIBUTE (pat));
1744 }
1745 } else if (IS_UNION (mode)) {
1746 A68G_UNION *z = (A68G_UNION *) item;
1747 MOID_T *um = (MOID_T *) (VALUE (z));
1748 BYTE_T *ui = &item[A68G_UNION_SIZE];
1749 if (um == NO_MOID) {
1750 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE, mode);
1751 exit_genie (p, A68G_RUNTIME_ERROR);
1752 }
1753 genie_write_standard_format (p, um, ui, ref_file, formats);
1754 } else if (IS_STRUCT (mode)) {
1755 for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
1756 BYTE_T *elem = &item[OFFSET (q)];
1757 genie_check_initialisation (p, elem, MOID (q));
1758 genie_write_standard_format (p, MOID (q), elem, ref_file, formats);
1759 }
1760 } else if (IS_ROW (mode) || IS_FLEX (mode)) {
1761 MOID_T *deflexed = DEFLEX (mode);
1762 CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
1763 A68G_ARRAY *arr; A68G_TUPLE *tup;
1764 GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
1765 if (get_row_size (tup, DIM (arr)) > 0) {
1766 BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
1767 BOOL_T done = A68G_FALSE;
1768 initialise_internal_index (tup, DIM (arr));
1769 while (!done) {
1770 ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
1771 ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
1772 BYTE_T *elem = &base_addr[elem_addr];
1773 genie_check_initialisation (p, elem, SUB (deflexed));
1774 genie_write_standard_format (p, SUB (deflexed), elem, ref_file, formats);
1775 done = increment_internal_index (tup, DIM (arr));
1776 }
1777 }
1778 }
1779 if (errno != 0) {
1780 transput_error (p, ref_file, mode);
1781 }
1782 }
1783
1784
1785 //! @brief PROC ([] SIMPLOUT) VOID print f, write f
1786
1787 void genie_write_format (NODE_T * p)
1788 {
1789 A68G_REF row;
1790 POP_REF (p, &row);
1791 genie_stand_out (p);
1792 PUSH_REF (p, row);
1793 genie_write_file_format (p);
1794 }
1795
1796
1797 //! @brief PROC (REF FILE, [] SIMPLOUT) VOID put f
1798
1799 void genie_write_file_format (NODE_T * p)
1800 {
1801 A68G_REF row;
1802 POP_REF (p, &row);
1803 CHECK_REF (p, row, M_ROW_SIMPLOUT);
1804 A68G_ARRAY *arr; A68G_TUPLE *tup;
1805 GET_DESCRIPTOR (arr, tup, &row);
1806 INT_T elems = ROW_SIZE (tup);
1807 A68G_REF ref_file;
1808 POP_REF (p, &ref_file);
1809 CHECK_REF (p, ref_file, M_REF_FILE);
1810 A68G_FILE *file = FILE_DEREF (&ref_file);
1811 CHECK_INIT (p, INITIALISED (file), M_FILE);
1812 if (!OPENED (file)) {
1813 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1814 exit_genie (p, A68G_RUNTIME_ERROR);
1815 }
1816 if (DRAW_MOOD (file)) {
1817 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1818 exit_genie (p, A68G_RUNTIME_ERROR);
1819 }
1820 if (READ_MOOD (file)) {
1821 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "read");
1822 exit_genie (p, A68G_RUNTIME_ERROR);
1823 }
1824 if (!PUT (&CHANNEL (file))) {
1825 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "putting");
1826 exit_genie (p, A68G_RUNTIME_ERROR);
1827 }
1828 if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
1829 if (IS_NIL (STRING (file))) {
1830 if ((FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS, A68G_PROTECTION)) == A68G_NO_FILE) {
1831 open_error (p, ref_file, "putting");
1832 }
1833 } else {
1834 FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS, 0);
1835 }
1836 DRAW_MOOD (file) = A68G_FALSE;
1837 READ_MOOD (file) = A68G_FALSE;
1838 WRITE_MOOD (file) = A68G_TRUE;
1839 CHAR_MOOD (file) = A68G_TRUE;
1840 }
1841 if (!CHAR_MOOD (file)) {
1842 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "binary");
1843 exit_genie (p, A68G_RUNTIME_ERROR);
1844 }
1845 // Save stack state since formats have frames.
1846 ADDR_T pop_fp = FRAME_POINTER (file), pop_sp = STACK_POINTER (file);
1847 FRAME_POINTER (file) = A68G_FP;
1848 STACK_POINTER (file) = A68G_SP;
1849 // Process [] SIMPLOUT.
1850 if (BODY (&FORMAT (file)) != NO_NODE) {
1851 open_format_frame (p, ref_file, &FORMAT (file), NOT_EMBEDDED_FORMAT, A68G_FALSE);
1852 }
1853 if (elems <= 0) {
1854 return;
1855 }
1856 int formats = 0;
1857 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
1858 INT_T elem_index = 0;
1859 for (INT_T k = 0; k < elems; k++) {
1860 A68G_UNION *z = (A68G_UNION *) & (base_address[elem_index]);
1861 MOID_T *mode = (MOID_T *) (VALUE (z));
1862 BYTE_T *item = &(base_address[elem_index + A68G_UNION_SIZE]);
1863 genie_write_standard_format (p, mode, item, ref_file, &formats);
1864 elem_index += SIZE (M_SIMPLOUT);
1865 }
1866 // Empty the format to purge insertions.
1867 purge_format_write (p, ref_file);
1868 BODY (&FORMAT (file)) = NO_NODE;
1869 // Dump the buffer.
1870 write_purge_buffer (p, ref_file, FORMATTED_BUFFER);
1871 // Forget about active formats.
1872 A68G_FP = FRAME_POINTER (file);
1873 A68G_SP = STACK_POINTER (file);
1874 FRAME_POINTER (file) = pop_fp;
1875 STACK_POINTER (file) = pop_sp;
1876 }
1877
1878
1879 //! @brief Give a value error in case a character is not among expected ones.
1880
1881 BOOL_T expect (NODE_T * p, MOID_T * m, A68G_REF ref_file, const char *items, char ch)
1882 {
1883 if (strchr ((char *) items, ch) == NO_TEXT) {
1884 value_error (p, m, ref_file);
1885 return A68G_FALSE;
1886 } else {
1887 return A68G_TRUE;
1888 }
1889 }
1890
1891
1892 //! @brief Read a group of insertions.
1893
1894 void read_insertion (NODE_T * p, A68G_REF ref_file)
1895 {
1896
1897 // Algol68G does not check whether the insertions are textually there. It just
1898 // skips them. This because we blank literals in sign moulds before the sign is
1899 // put, which is non-standard Algol68, but convenient.
1900
1901 A68G_FILE *file = FILE_DEREF (&ref_file);
1902 for (; p != NO_NODE; FORWARD (p)) {
1903 read_insertion (SUB (p), ref_file);
1904 if (IS (p, FORMAT_ITEM_L)) {
1905 BOOL_T siga = (BOOL_T) ! END_OF_FILE (file);
1906 while (siga) {
1907 int ch = read_single_char (p, ref_file);
1908 siga = (BOOL_T) ((ch != NEWLINE_CHAR) && (ch != EOF_CHAR) && !END_OF_FILE (file));
1909 }
1910 } else if (IS (p, FORMAT_ITEM_P)) {
1911 BOOL_T siga = (BOOL_T) ! END_OF_FILE (file);
1912 while (siga) {
1913 int ch = read_single_char (p, ref_file);
1914 siga = (BOOL_T) ((ch != FORMFEED_CHAR) && (ch != EOF_CHAR) && !END_OF_FILE (file));
1915 }
1916 } else if (IS (p, FORMAT_ITEM_X) || IS (p, FORMAT_ITEM_Q)) {
1917 if (!END_OF_FILE (file)) {
1918 (void) read_single_char (p, ref_file);
1919 }
1920 } else if (IS (p, FORMAT_ITEM_Y)) {
1921 PUSH_REF (p, ref_file);
1922 PUSH_VALUE (p, -1, A68G_INT);
1923 genie_set (p);
1924 } else if (IS (p, LITERAL)) {
1925 // Skip characters, but don't check the literal.
1926 size_t len = strlen (NSYMBOL (p));
1927 while (len-- && !END_OF_FILE (file)) {
1928 (void) read_single_char (p, ref_file);
1929 }
1930 } else if (IS (p, REPLICATOR)) {
1931 int k = get_replicator_value (SUB (p), A68G_TRUE);
1932 if (ATTRIBUTE (SUB_NEXT (p)) != FORMAT_ITEM_K) {
1933 for (int j = 1; j <= k; j++) {
1934 read_insertion (NEXT (p), ref_file);
1935 }
1936 } else {
1937 int pos = get_transput_buffer_index (INPUT_BUFFER);
1938 for (int j = 1; j < (k - pos); j++) {
1939 if (!END_OF_FILE (file)) {
1940 (void) read_single_char (p, ref_file);
1941 }
1942 }
1943 }
1944 return; // From REPLICATOR, don't delete this!
1945 }
1946 }
1947 }
1948
1949
1950 //! @brief Read string from file according current format.
1951
1952 void read_string_pattern (NODE_T * p, MOID_T * m, A68G_REF ref_file)
1953 {
1954 for (; p != NO_NODE; FORWARD (p)) {
1955 if (IS (p, INSERTION)) {
1956 read_insertion (SUB (p), ref_file);
1957 } else if (IS (p, FORMAT_ITEM_A)) {
1958 scan_n_chars (p, 1, m, ref_file);
1959 } else if (IS (p, FORMAT_ITEM_S)) {
1960 plusab_transput_buffer (p, INPUT_BUFFER, BLANK_CHAR);
1961 return;
1962 } else if (IS (p, REPLICATOR)) {
1963 int k = get_replicator_value (SUB (p), A68G_TRUE);
1964 for (int j = 1; j <= k; j++) {
1965 read_string_pattern (NEXT (p), m, ref_file);
1966 }
1967 return;
1968 } else {
1969 read_string_pattern (SUB (p), m, ref_file);
1970 }
1971 }
1972 }
1973
1974
1975 //! @brief Traverse choice pattern.
1976
1977 void traverse_choice_pattern (NODE_T * p, char *str, int len, int *count, int *matches, int *first_match, BOOL_T * full_match)
1978 {
1979 for (; p != NO_NODE; FORWARD (p)) {
1980 traverse_choice_pattern (SUB (p), str, len, count, matches, first_match, full_match);
1981 if (IS (p, LITERAL)) {
1982 (*count)++;
1983 if (strncmp (NSYMBOL (p), str, (size_t) len) == 0) {
1984 (*matches)++;
1985 (*full_match) = (BOOL_T) ((*full_match) | (strcmp (NSYMBOL (p), str) == 0));
1986 if (*first_match == 0 && *full_match) {
1987 *first_match = *count;
1988 }
1989 }
1990 }
1991 }
1992 }
1993
1994
1995 //! @brief Read appropriate insertion from a choice pattern.
1996
1997 int read_choice_pattern (NODE_T * p, A68G_REF ref_file)
1998 {
1999
2000 // This implementation does not have the RR peculiarity that longest
2001 // matching literal must be first, in case of non-unique first chars.
2002
2003 A68G_FILE *file = FILE_DEREF (&ref_file);
2004 BOOL_T cont = A68G_TRUE;
2005 int longest_match = 0, longest_match_len = 0;
2006 while (cont) {
2007 int ch = char_scanner (file);
2008 if (!END_OF_FILE (file)) {
2009 int len, count = 0, matches = 0, first_match = 0;
2010 BOOL_T full_match = A68G_FALSE;
2011 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
2012 len = get_transput_buffer_index (INPUT_BUFFER);
2013 traverse_choice_pattern (p, get_transput_buffer (INPUT_BUFFER), len, &count, &matches, &first_match, &full_match);
2014 if (full_match && matches == 1 && first_match > 0) {
2015 return first_match;
2016 } else if (full_match && matches > 1 && first_match > 0) {
2017 longest_match = first_match;
2018 longest_match_len = len;
2019 } else if (matches == 0) {
2020 cont = A68G_FALSE;
2021 }
2022 } else {
2023 cont = A68G_FALSE;
2024 }
2025 }
2026 if (longest_match > 0) {
2027 // Push back look-ahead chars.
2028 if (get_transput_buffer_index (INPUT_BUFFER) > 0) {
2029 char *z = get_transput_buffer (INPUT_BUFFER);
2030 END_OF_FILE (file) = A68G_FALSE;
2031 add_string_transput_buffer (p, TRANSPUT_BUFFER (file), &z[longest_match_len]);
2032 }
2033 return longest_match;
2034 } else {
2035 value_error (p, M_INT, ref_file);
2036 return 0;
2037 }
2038 }
2039
2040
2041 //! @brief Read value according to a general-pattern.
2042
2043 void read_number_generic (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
2044 {
2045 GENIE_UNIT (NEXT_SUB (p));
2046 // RR says to ignore parameters just calculated, so we will.
2047 A68G_REF row;
2048 POP_REF (p, &row);
2049 genie_read_standard (p, mode, item, ref_file);
2050 }
2051
2052 // INTEGRAL, REAL, COMPLEX and BITS patterns.
2053
2054
2055 //! @brief Read sign-mould according current format.
2056
2057 void read_sign_mould (NODE_T * p, MOID_T * m, A68G_REF ref_file, int *sign)
2058 {
2059 for (; p != NO_NODE; FORWARD (p)) {
2060 if (IS (p, INSERTION)) {
2061 read_insertion (SUB (p), ref_file);
2062 } else if (IS (p, REPLICATOR)) {
2063 int k = get_replicator_value (SUB (p), A68G_TRUE);
2064 for (int j = 1; j <= k; j++) {
2065 read_sign_mould (NEXT (p), m, ref_file, sign);
2066 }
2067 return; // Leave this!
2068 } else {
2069 switch (ATTRIBUTE (p)) {
2070 case FORMAT_ITEM_Z:
2071 case FORMAT_ITEM_D:
2072 case FORMAT_ITEM_S:
2073 case FORMAT_ITEM_PLUS:
2074 case FORMAT_ITEM_MINUS: {
2075 int ch = read_single_char (p, ref_file);
2076 // When a sign has been read, digits are expected.
2077 if (*sign != 0) {
2078 if (expect (p, m, ref_file, INT_DIGITS, (char) ch)) {
2079 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
2080 } else {
2081 plusab_transput_buffer (p, INPUT_BUFFER, '0');
2082 }
2083 // When a sign has not been read, a sign is expected. If there is a digit
2084 // in stead of a sign, the digit is accepted and '+' is assumed; RR demands a
2085 // space to preceed the digit, Algol68G does not.
2086 } else {
2087 if (strchr (SIGN_DIGITS, ch) != NO_TEXT) {
2088 if (ch == '+') {
2089 *sign = 1;
2090 } else if (ch == '-') {
2091 *sign = -1;
2092 } else if (ch == BLANK_CHAR) {
2093 ;
2094 }
2095 } else if (expect (p, m, ref_file, INT_DIGITS, (char) ch)) {
2096 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
2097 *sign = 1;
2098 }
2099 }
2100 break;
2101 }
2102 default: {
2103 read_sign_mould (SUB (p), m, ref_file, sign);
2104 break;
2105 }
2106 }
2107 }
2108 }
2109 }
2110
2111
2112 //! @brief Read mould according current format.
2113
2114 void read_integral_mould (NODE_T * p, MOID_T * m, A68G_REF ref_file)
2115 {
2116 for (; p != NO_NODE; FORWARD (p)) {
2117 if (IS (p, INSERTION)) {
2118 read_insertion (SUB (p), ref_file);
2119 } else if (IS (p, REPLICATOR)) {
2120 int k = get_replicator_value (SUB (p), A68G_TRUE);
2121 for (int j = 1; j <= k; j++) {
2122 read_integral_mould (NEXT (p), m, ref_file);
2123 }
2124 return; // Leave this!
2125 } else if (IS (p, FORMAT_ITEM_Z)) {
2126 int ch = read_single_char (p, ref_file);
2127 const char *digits = (m == M_BITS || m == M_LONG_BITS || m == M_LONG_LONG_BITS) ? BITS_DIGITS_BLANK : INT_DIGITS_BLANK;
2128 if (expect (p, m, ref_file, digits, (char) ch)) {
2129 plusab_transput_buffer (p, INPUT_BUFFER, (char) ((ch == BLANK_CHAR) ? '0' : ch));
2130 } else {
2131 plusab_transput_buffer (p, INPUT_BUFFER, '0');
2132 }
2133 } else if (IS (p, FORMAT_ITEM_D)) {
2134 int ch = read_single_char (p, ref_file);
2135 const char *digits = (m == M_BITS || m == M_LONG_BITS || m == M_LONG_LONG_BITS) ? BITS_DIGITS : INT_DIGITS;
2136 if (expect (p, m, ref_file, digits, (char) ch)) {
2137 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
2138 } else {
2139 plusab_transput_buffer (p, INPUT_BUFFER, '0');
2140 }
2141 } else if (IS (p, FORMAT_ITEM_S)) {
2142 plusab_transput_buffer (p, INPUT_BUFFER, '0');
2143 } else {
2144 read_integral_mould (SUB (p), m, ref_file);
2145 }
2146 }
2147 }
2148
2149
2150 //! @brief Read mould according current format.
2151
2152 void read_integral_pattern (NODE_T * p, MOID_T * m, BYTE_T * item, A68G_REF ref_file)
2153 {
2154 NODE_T *q = SUB (p);
2155 if (q != NO_NODE && IS (q, SIGN_MOULD)) {
2156 int sign = 0;
2157 char *z;
2158 plusab_transput_buffer (p, INPUT_BUFFER, BLANK_CHAR);
2159 read_sign_mould (SUB (q), m, ref_file, &sign);
2160 z = get_transput_buffer (INPUT_BUFFER);
2161 z[0] = (char) ((sign == -1) ? '-' : '+');
2162 FORWARD (q);
2163 }
2164 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
2165 read_integral_mould (SUB (q), m, ref_file);
2166 }
2167 genie_string_to_value (p, m, item, ref_file);
2168 }
2169
2170
2171 //! @brief Read point, exponent or i-frame.
2172
2173 void read_pie_frame (NODE_T * p, MOID_T * m, A68G_REF ref_file, int att, int item, char ch)
2174 {
2175 // Widen ch to a stringlet.
2176 char sym[3];
2177 sym[0] = ch;
2178 sym[1] = (char) TO_LOWER (ch);
2179 sym[2] = NULL_CHAR;
2180 // Now read the frame.
2181 for (; p != NO_NODE; FORWARD (p)) {
2182 if (IS (p, INSERTION)) {
2183 read_insertion (p, ref_file);
2184 } else if (IS (p, att)) {
2185 read_pie_frame (SUB (p), m, ref_file, att, item, ch);
2186 return;
2187 } else if (IS (p, FORMAT_ITEM_S)) {
2188 plusab_transput_buffer (p, INPUT_BUFFER, sym[0]);
2189 return;
2190 } else if (IS (p, item)) {
2191 int ch0 = read_single_char (p, ref_file);
2192 if (expect (p, m, ref_file, sym, (char) ch0)) {
2193 plusab_transput_buffer (p, INPUT_BUFFER, sym[0]);
2194 } else {
2195 plusab_transput_buffer (p, INPUT_BUFFER, sym[0]);
2196 }
2197 }
2198 }
2199 }
2200
2201
2202 //! @brief Read REAL value using real pattern.
2203
2204 void read_real_pattern (NODE_T * p, MOID_T * m, BYTE_T * item, A68G_REF ref_file)
2205 {
2206 // Dive into pattern.
2207 NODE_T *q = (IS (p, REAL_PATTERN)) ? SUB (p) : p;
2208 // Dissect pattern.
2209 if (q != NO_NODE && IS (q, SIGN_MOULD)) {
2210 int sign = 0;
2211 char *z;
2212 plusab_transput_buffer (p, INPUT_BUFFER, BLANK_CHAR);
2213 read_sign_mould (SUB (q), m, ref_file, &sign);
2214 z = get_transput_buffer (INPUT_BUFFER);
2215 z[0] = (char) ((sign == -1) ? '-' : '+');
2216 FORWARD (q);
2217 }
2218 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
2219 read_integral_mould (SUB (q), m, ref_file);
2220 FORWARD (q);
2221 }
2222 if (q != NO_NODE && IS (q, FORMAT_POINT_FRAME)) {
2223 read_pie_frame (SUB (q), m, ref_file, FORMAT_POINT_FRAME, FORMAT_ITEM_POINT, POINT_CHAR);
2224 FORWARD (q);
2225 }
2226 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
2227 read_integral_mould (SUB (q), m, ref_file);
2228 FORWARD (q);
2229 }
2230 if (q != NO_NODE && IS (q, EXPONENT_FRAME)) {
2231 read_pie_frame (SUB (q), m, ref_file, FORMAT_E_FRAME, FORMAT_ITEM_E, EXPONENT_CHAR);
2232 q = NEXT_SUB (q);
2233 if (q != NO_NODE && IS (q, SIGN_MOULD)) {
2234 int k, sign = 0;
2235 char *z;
2236 plusab_transput_buffer (p, INPUT_BUFFER, BLANK_CHAR);
2237 k = get_transput_buffer_index (INPUT_BUFFER);
2238 read_sign_mould (SUB (q), m, ref_file, &sign);
2239 z = get_transput_buffer (INPUT_BUFFER);
2240 z[k - 1] = (char) ((sign == -1) ? '-' : '+');
2241 FORWARD (q);
2242 }
2243 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
2244 read_integral_mould (SUB (q), m, ref_file);
2245 FORWARD (q);
2246 }
2247 }
2248 genie_string_to_value (p, m, item, ref_file);
2249 }
2250
2251
2252 //! @brief Read COMPLEX value using complex pattern.
2253
2254 void read_complex_pattern (NODE_T * p, MOID_T * comp, MOID_T * m, BYTE_T * re, BYTE_T * im, A68G_REF ref_file)
2255 {
2256 // Dissect pattern.
2257 NODE_T *reel = SUB (p);
2258 NODE_T *plus_i_times = NEXT (reel);
2259 NODE_T *imag = NEXT (plus_i_times);
2260 // Read pattern.
2261 read_real_pattern (reel, m, re, ref_file);
2262 reset_transput_buffer (INPUT_BUFFER);
2263 read_pie_frame (plus_i_times, comp, ref_file, FORMAT_I_FRAME, FORMAT_ITEM_I, 'I');
2264 reset_transput_buffer (INPUT_BUFFER);
2265 read_real_pattern (imag, m, im, ref_file);
2266 }
2267
2268
2269 //! @brief Read BITS value according pattern.
2270
2271 void read_bits_pattern (NODE_T * p, MOID_T * m, BYTE_T * item, A68G_REF ref_file)
2272 {
2273 int radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
2274 if (radix < 2 || radix > 16) {
2275 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
2276 exit_genie (p, A68G_RUNTIME_ERROR);
2277 }
2278 char *z = get_transput_buffer (INPUT_BUFFER);
2279 ASSERT (a68g_bufprt (z, (size_t) TRANSPUT_BUFFER_SIZE, "%dr", radix) >= 0);
2280 set_transput_buffer_index (INPUT_BUFFER, strlen (z));
2281 read_integral_mould (NEXT_SUB (p), m, ref_file);
2282 genie_string_to_value (p, m, item, ref_file);
2283 }
2284
2285
2286 //! @brief Read object with from file and store.
2287
2288 void genie_read_real_format (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
2289 {
2290 if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) == NO_NODE) {
2291 genie_read_standard (p, mode, item, ref_file);
2292 } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
2293 read_number_generic (p, mode, item, ref_file);
2294 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
2295 read_c_pattern (p, mode, item, ref_file);
2296 } else if (IS (p, REAL_PATTERN)) {
2297 read_real_pattern (p, mode, item, ref_file);
2298 } else {
2299 pattern_error (p, mode, ATTRIBUTE (p));
2300 }
2301 }
2302
2303
2304 //! @brief At end of read purge all insertions.
2305
2306 void purge_format_read (NODE_T * p, A68G_REF ref_file)
2307 {
2308 BOOL_T siga;
2309 do {
2310 NODE_T *pat;
2311 while ((pat = get_next_format_pattern (p, ref_file, SKIP_PATTERN)) != NO_NODE) {
2312 format_error (p, ref_file, ERROR_FORMAT_PICTURES);
2313 }
2314 A68G_FILE *file = FILE_DEREF (&ref_file);
2315 NODE_T *dollar = SUB (BODY (&FORMAT (file)));
2316 A68G_FORMAT *old_fmt = (A68G_FORMAT *) FRAME_LOCAL (A68G_FP, OFFSET (TAX (dollar)));
2317 siga = (BOOL_T) ! IS_NIL_FORMAT (old_fmt);
2318 if (siga) {
2319 // Pop embedded format and proceed.
2320 (void) end_of_format (p, ref_file);
2321 }
2322 } while (siga);
2323 }
2324
2325
2326 //! @brief Read object with from file and store.
2327
2328 void genie_read_standard_format (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file, int *formats)
2329 {
2330 errno = 0;
2331 reset_transput_buffer (INPUT_BUFFER);
2332 if (mode == M_FORMAT) {
2333 CHECK_REF (p, ref_file, M_REF_FILE);
2334 A68G_FILE *file = FILE_DEREF (&ref_file);
2335 // Forget about eventual active formats and set up new one.
2336 if (*formats > 0) {
2337 purge_format_read (p, ref_file);
2338 }
2339 (*formats)++;
2340 A68G_FP = FRAME_POINTER (file);
2341 A68G_SP = STACK_POINTER (file);
2342 open_format_frame (p, ref_file, (A68G_FORMAT *) item, NOT_EMBEDDED_FORMAT, A68G_TRUE);
2343 } else if (mode == M_PROC_REF_FILE_VOID) {
2344 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_PROC_REF_FILE_VOID);
2345 exit_genie (p, A68G_RUNTIME_ERROR);
2346 } else if (mode == M_REF_SOUND) {
2347 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_REF_SOUND);
2348 exit_genie (p, A68G_RUNTIME_ERROR);
2349 } else if (IS_REF (mode)) {
2350 CHECK_REF (p, *(A68G_REF *) item, mode);
2351 genie_read_standard_format (p, SUB (mode), ADDRESS ((A68G_REF *) item), ref_file, formats);
2352 } else if (mode == M_INT || mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
2353 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2354 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2355 genie_read_standard (pat, mode, item, ref_file);
2356 } else if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) != NO_NODE) {
2357 read_number_generic (pat, mode, item, ref_file);
2358 } else if (IS (pat, INTEGRAL_C_PATTERN)) {
2359 read_c_pattern (pat, mode, item, ref_file);
2360 } else if (IS (pat, INTEGRAL_PATTERN)) {
2361 read_integral_pattern (pat, mode, item, ref_file);
2362 } else if (IS (pat, CHOICE_PATTERN)) {
2363 int k = read_choice_pattern (pat, ref_file);
2364 if (mode == M_INT) {
2365 A68G_INT *z = (A68G_INT *) item;
2366 VALUE (z) = k;
2367 STATUS (z) = (STATUS_MASK_T) ((VALUE (z) > 0) ? INIT_MASK : NULL_MASK);
2368 } else {
2369 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_DEPRECATED, mode);
2370 exit_genie (p, A68G_RUNTIME_ERROR);
2371 }
2372 } else {
2373 pattern_error (p, mode, ATTRIBUTE (pat));
2374 }
2375 } else if (mode == M_REAL || mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
2376 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2377 genie_read_real_format (pat, mode, item, ref_file);
2378 } else if (mode == M_COMPLEX) {
2379 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2380 if (IS (pat, COMPLEX_PATTERN)) {
2381 read_complex_pattern (pat, mode, M_REAL, item, &item[SIZE (M_REAL)], ref_file);
2382 } else {
2383 // Try reading as two REAL values.
2384 genie_read_real_format (pat, M_REAL, item, ref_file);
2385 genie_read_standard_format (p, M_REAL, &item[SIZE (M_REAL)], ref_file, formats);
2386 }
2387 } else if (mode == M_LONG_COMPLEX) {
2388 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2389 if (IS (pat, COMPLEX_PATTERN)) {
2390 read_complex_pattern (pat, mode, M_LONG_REAL, item, &item[SIZE (M_LONG_REAL)], ref_file);
2391 } else {
2392 // Try reading as two LONG REAL values.
2393 genie_read_real_format (pat, M_LONG_REAL, item, ref_file);
2394 genie_read_standard_format (p, M_LONG_REAL, &item[SIZE (M_LONG_REAL)], ref_file, formats);
2395 }
2396 } else if (mode == M_LONG_LONG_COMPLEX) {
2397 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2398 if (IS (pat, COMPLEX_PATTERN)) {
2399 read_complex_pattern (pat, mode, M_LONG_LONG_REAL, item, &item[SIZE (M_LONG_LONG_REAL)], ref_file);
2400 } else {
2401 // Try reading as two LONG LONG REAL values.
2402 genie_read_real_format (pat, M_LONG_LONG_REAL, item, ref_file);
2403 genie_read_standard_format (p, M_LONG_LONG_REAL, &item[SIZE (M_LONG_LONG_REAL)], ref_file, formats);
2404 }
2405 } else if (mode == M_BOOL) {
2406 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2407 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2408 genie_read_standard (p, mode, item, ref_file);
2409 } else if (IS (pat, BOOLEAN_PATTERN)) {
2410 if (NEXT_SUB (pat) == NO_NODE) {
2411 genie_read_standard (p, mode, item, ref_file);
2412 } else {
2413 A68G_BOOL *z = (A68G_BOOL *) item;
2414 int k = read_choice_pattern (pat, ref_file);
2415 if (k == 1 || k == 2) {
2416 VALUE (z) = (BOOL_T) ((k == 1) ? A68G_TRUE : A68G_FALSE);
2417 STATUS (z) = INIT_MASK;
2418 } else {
2419 STATUS (z) = NULL_MASK;
2420 }
2421 }
2422 } else {
2423 pattern_error (p, mode, ATTRIBUTE (pat));
2424 }
2425 } else if (mode == M_BITS || mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
2426 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2427 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2428 genie_read_standard (p, mode, item, ref_file);
2429 } else if (IS (pat, BITS_PATTERN)) {
2430 read_bits_pattern (pat, mode, item, ref_file);
2431 } else if (IS (pat, BITS_C_PATTERN)) {
2432 read_c_pattern (pat, mode, item, ref_file);
2433 } else {
2434 pattern_error (p, mode, ATTRIBUTE (pat));
2435 }
2436 } else if (mode == M_CHAR) {
2437 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2438 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2439 genie_read_standard (p, mode, item, ref_file);
2440 } else if (IS (pat, STRING_PATTERN)) {
2441 read_string_pattern (pat, M_CHAR, ref_file);
2442 genie_string_to_value (p, mode, item, ref_file);
2443 } else if (IS (pat, CHAR_C_PATTERN)) {
2444 read_c_pattern (pat, mode, item, ref_file);
2445 } else {
2446 pattern_error (p, mode, ATTRIBUTE (pat));
2447 }
2448 } else if (mode == M_ROW_CHAR || mode == M_STRING) {
2449 // Handle these separately instead of reading [] CHAR.
2450 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2451 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2452 genie_read_standard (p, mode, item, ref_file);
2453 } else if (IS (pat, STRING_PATTERN)) {
2454 read_string_pattern (pat, mode, ref_file);
2455 genie_string_to_value (p, mode, item, ref_file);
2456 } else if (IS (pat, STRING_C_PATTERN)) {
2457 read_c_pattern (pat, mode, item, ref_file);
2458 } else {
2459 pattern_error (p, mode, ATTRIBUTE (pat));
2460 }
2461 } else if (IS_UNION (mode)) {
2462 A68G_UNION *z = (A68G_UNION *) item;
2463 genie_read_standard_format (p, (MOID_T *) (VALUE (z)), &item[A68G_UNION_SIZE], ref_file, formats);
2464 } else if (IS_STRUCT (mode)) {
2465 for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
2466 BYTE_T *elem = &item[OFFSET (q)];
2467 genie_read_standard_format (p, MOID (q), elem, ref_file, formats);
2468 }
2469 } else if (IS_ROW (mode) || IS_FLEX (mode)) {
2470 MOID_T *deflexed = DEFLEX (mode);
2471 A68G_ARRAY *arr;
2472 A68G_TUPLE *tup;
2473 CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
2474 GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
2475 if (get_row_size (tup, DIM (arr)) > 0) {
2476 BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
2477 BOOL_T done = A68G_FALSE;
2478 initialise_internal_index (tup, DIM (arr));
2479 while (!done) {
2480 ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
2481 ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
2482 BYTE_T *elem = &base_addr[elem_addr];
2483 genie_read_standard_format (p, SUB (deflexed), elem, ref_file, formats);
2484 done = increment_internal_index (tup, DIM (arr));
2485 }
2486 }
2487 }
2488 if (errno != 0) {
2489 transput_error (p, ref_file, mode);
2490 }
2491 }
2492
2493
2494 //! @brief PROC ([] SIMPLIN) VOID read f
2495
2496 void genie_read_format (NODE_T * p)
2497 {
2498 A68G_REF row;
2499 POP_REF (p, &row);
2500 genie_stand_in (p);
2501 PUSH_REF (p, row);
2502 genie_read_file_format (p);
2503 }
2504
2505
2506 //! @brief PROC (REF FILE, [] SIMPLIN) VOID get f
2507
2508 void genie_read_file_format (NODE_T * p)
2509 {
2510 A68G_REF row;
2511 POP_REF (p, &row);
2512 CHECK_REF (p, row, M_ROW_SIMPLIN);
2513 A68G_ARRAY *arr; A68G_TUPLE *tup;
2514 GET_DESCRIPTOR (arr, tup, &row);
2515 INT_T elems = ROW_SIZE (tup);
2516 A68G_REF ref_file;
2517 POP_REF (p, &ref_file);
2518 CHECK_REF (p, ref_file, M_REF_FILE);
2519 A68G_FILE *file = FILE_DEREF (&ref_file);
2520 CHECK_INIT (p, INITIALISED (file), M_FILE);
2521 if (!OPENED (file)) {
2522 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
2523 exit_genie (p, A68G_RUNTIME_ERROR);
2524 }
2525 if (DRAW_MOOD (file)) {
2526 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
2527 exit_genie (p, A68G_RUNTIME_ERROR);
2528 }
2529 if (WRITE_MOOD (file)) {
2530 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
2531 exit_genie (p, A68G_RUNTIME_ERROR);
2532 }
2533 if (!GET (&CHANNEL (file))) {
2534 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "getting");
2535 exit_genie (p, A68G_RUNTIME_ERROR);
2536 }
2537 if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
2538 if (IS_NIL (STRING (file))) {
2539 if ((FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS, 0)) == A68G_NO_FILE) {
2540 open_error (p, ref_file, "getting");
2541 }
2542 } else {
2543 FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS, 0);
2544 }
2545 DRAW_MOOD (file) = A68G_FALSE;
2546 READ_MOOD (file) = A68G_TRUE;
2547 WRITE_MOOD (file) = A68G_FALSE;
2548 CHAR_MOOD (file) = A68G_TRUE;
2549 }
2550 if (!CHAR_MOOD (file)) {
2551 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "binary");
2552 exit_genie (p, A68G_RUNTIME_ERROR);
2553 }
2554 // Save stack state since formats have frames.
2555 ADDR_T pop_fp = FRAME_POINTER (file), pop_sp = STACK_POINTER (file);
2556 FRAME_POINTER (file) = A68G_FP;
2557 STACK_POINTER (file) = A68G_SP;
2558 // Process [] SIMPLIN.
2559 if (BODY (&FORMAT (file)) != NO_NODE) {
2560 open_format_frame (p, ref_file, &FORMAT (file), NOT_EMBEDDED_FORMAT, A68G_FALSE);
2561 }
2562 if (elems <= 0) {
2563 return;
2564 }
2565 int formats = 0;
2566 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
2567 INT_T elem_index = 0;
2568 for (INT_T k = 0; k < elems; k++) {
2569 A68G_UNION *z = (A68G_UNION *) & (base_address[elem_index]);
2570 MOID_T *mode = (MOID_T *) (VALUE (z));
2571 BYTE_T *item = (BYTE_T *) & (base_address[elem_index + A68G_UNION_SIZE]);
2572 genie_read_standard_format (p, mode, item, ref_file, &formats);
2573 elem_index += SIZE (M_SIMPLIN);
2574 }
2575 // Empty the format to purge insertions.
2576 purge_format_read (p, ref_file);
2577 BODY (&FORMAT (file)) = NO_NODE;
2578 // Forget about active formats.
2579 A68G_FP = FRAME_POINTER (file);
2580 A68G_SP = STACK_POINTER (file);
2581 FRAME_POINTER (file) = pop_fp;
2582 STACK_POINTER (file) = pop_sp;
2583 }
© J.M. van der Veer • jmvdveer@algol68genie.nl