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