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-2025 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! 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 A68G_TRUE;
68 } else {
69 return A68G_FALSE;
70 }
71 }
72
73 //! @brief Handle format error event.
74
75 void format_error (NODE_T * p, A68G_REF ref_file, char *diag)
76 {
77 A68G_FILE *f = FILE_DEREF (&ref_file);
78 on_event_handler (p, FORMAT_ERROR_MENDED (f), ref_file);
79 A68G_BOOL z;
80 POP_OBJECT (p, &z, A68G_BOOL);
81 if (VALUE (&z) == A68G_FALSE) {
82 diagnostic (A68G_RUNTIME_ERROR, p, diag);
83 exit_genie (p, A68G_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 A68G_COLLITEM *z = (A68G_COLLITEM *) FRAME_LOCAL (A68G_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, A68G_REF ref_file, A68G_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 A68G_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 A68G_FORMAT *save = (A68G_FORMAT *) FRAME_LOCAL (A68G_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, A68G_REF ref_file)
133 {
134 // Format-items return immediately to the embedding format text. The outermost
135 //format text calls "on format end".
136 A68G_FILE *file = FILE_DEREF (&ref_file);
137 NODE_T *dollar = SUB (BODY (&FORMAT (file)));
138 A68G_FORMAT *save = (A68G_FORMAT *) FRAME_LOCAL (A68G_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 A68G_BOOL z;
143 POP_OBJECT (p, &z, A68G_BOOL);
144 if (VALUE (&z) == A68G_FALSE) {
145 // Restart format.
146 A68G_FP = FRAME_POINTER (file);
147 A68G_SP = STACK_POINTER (file);
148 open_format_frame (p, ref_file, &FORMAT (file), NOT_EMBEDDED_FORMAT, A68G_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 A68G_INT u;
166 if (genie_string_to_value_internal (p, M_INT, NSYMBOL (p), (BYTE_T *) & u) == A68G_FALSE) {
167 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, M_INT);
168 exit_genie (p, A68G_RUNTIME_ERROR);
169 }
170 z = VALUE (&u);
171 } else if (IS (p, DYNAMIC_REPLICATOR)) {
172 A68G_INT u;
173 GENIE_UNIT (NEXT_SUB (p));
174 POP_OBJECT (p, &u, A68G_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 (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_INVALID_REPLICATOR);
182 // exit_genie (p, A68G_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, A68G_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 A68G_COLLITEM *collitem = (A68G_COLLITEM *) FRAME_LOCAL (A68G_FP, OFFSET (TAX (p)));
204 if (COUNT (collitem) != 0) {
205 if (IS (picture, A68G_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 A68G_FORMAT z;
213 A68G_FILE *file = FILE_DEREF (&ref_file);
214 GENIE_UNIT (NEXT_SUB (picture));
215 POP_OBJECT (p, &z, A68G_FORMAT);
216 open_format_frame (p, ref_file, &z, EMBEDDED_FORMAT, A68G_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 A68G_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 (A68G_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 = A68G_TRUE;
236 NODE_T *a68g_select = NO_NODE;
237 if (COUNT (collitem) == ITEM_NOT_USED) {
238 if (IS (picture, REPLICATOR)) {
239 COUNT (collitem) = get_replicator_value (SUB (p), A68G_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 a68g_select = scan_format_pattern (NEXT_SUB (picture), ref_file);
253 if (a68g_select != NO_NODE) {
254 return a68g_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, A68G_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 A68G_FILE *file = FILE_DEREF (&ref_file);
277 if (BODY (&FORMAT (file)) == NO_NODE) {
278 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_EXHAUSTED);
279 exit_genie (p, A68G_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 (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_EXHAUSTED);
292 exit_genie (p, A68G_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 (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_CANNOT_TRANSPUT, mode, att);
305 exit_genie (p, A68G_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 = A68G_SP;
313 PUSH_UNION (p, mode);
314 PUSH (p, item, (int) SIZE (mode));
315 A68G_SP = pop_sp + SIZE (M_NUMBER);
316 }
317
318 //! @brief Write a group of insertions.
319
320 void write_insertion (NODE_T * p, A68G_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, A68G_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 size_t k = strlen (NSYMBOL (p));
341 for (size_t 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), A68G_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, A68G_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), A68G_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 = A68G_TRUE;
404 FORWARD (p);
405 } else {
406 *right_align = A68G_FALSE;
407 }
408 if (IS (p, FORMAT_ITEM_PLUS)) {
409 *sign = A68G_TRUE;
410 FORWARD (p);
411 } else {
412 *sign = A68G_FALSE;
413 }
414 if (IS (p, REPLICATOR)) {
415 *width = get_replicator_value (SUB (p), A68G_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), A68G_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, A68G_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, A68G_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 A68G_REF row;
459 POP_REF (p, &row);
460 A68G_ARRAY *arr; A68G_TUPLE *tup;
461 GET_DESCRIPTOR (arr, tup, &row);
462 size_t 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 ((A68G_INT *) & (base_address[addr]));
468 PUSH_VALUE (p, arg, A68G_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 (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_INTS_REQUIRED, M_INT);
488 exit_genie (p, A68G_RUNTIME_ERROR);
489 break;
490 }
491 }
492 } else if (mod == FORMAT_ITEM_H) {
493 A68G_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 = A68G_EXP_WIDTH + 1;
506 } else if (mode == M_LONG_REAL || mode == M_LONG_INT) {
507 def_expo = A68G_LONG_EXP_WIDTH + 1;
508 } else if (mode == M_LONG_LONG_REAL || mode == M_LONG_LONG_INT) {
509 def_expo = A68G_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, A68G_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, A68G_INT);
523 POP_OBJECT (p, &a_after, A68G_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, A68G_INT);
530 POP_OBJECT (p, &a_after, A68G_INT);
531 POP_OBJECT (p, &a_width, A68G_INT);
532 VALUE (&a_expo) = def_expo;
533 break;
534 }
535 case 4: {
536 POP_OBJECT (p, &a_mult, A68G_INT);
537 POP_OBJECT (p, &a_expo, A68G_INT);
538 POP_OBJECT (p, &a_after, A68G_INT);
539 POP_OBJECT (p, &a_width, A68G_INT);
540 break;
541 }
542 default: {
543 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FORMAT_INTS_REQUIRED, M_INT);
544 exit_genie (p, A68G_RUNTIME_ERROR);
545 break;
546 }
547 }
548 PUSH_VALUE (p, VALUE (&a_width), A68G_INT);
549 PUSH_VALUE (p, VALUE (&a_after), A68G_INT);
550 PUSH_VALUE (p, VALUE (&a_expo), A68G_INT);
551 PUSH_VALUE (p, VALUE (&a_mult), A68G_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, A68G_REF ref_file)
560 {
561 ADDR_T pop_sp = A68G_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 A68G_CHAR *z = (A68G_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), A68G_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 = A68G_REAL_WIDTH + A68G_EXP_WIDTH + 4;
589 after = A68G_REAL_WIDTH - 1;
590 expo = A68G_EXP_WIDTH + 1;
591 } else if (mode == M_LONG_REAL || mode == M_LONG_INT) {
592 width = A68G_LONG_REAL_WIDTH + A68G_LONG_EXP_WIDTH + 4;
593 after = A68G_LONG_REAL_WIDTH - 1;
594 expo = A68G_LONG_EXP_WIDTH + 1;
595 } else if (mode == M_LONG_LONG_REAL || mode == M_LONG_LONG_INT) {
596 width = A68G_LONG_LONG_REAL_WIDTH + A68G_LONG_LONG_EXP_WIDTH + 4;
597 after = A68G_LONG_LONG_REAL_WIDTH - 1;
598 expo = A68G_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), A68G_INT);
608 PUSH_VALUE (p, after, A68G_INT);
609 PUSH_VALUE (p, expo, A68G_INT);
610 PUSH_VALUE (p, 1, A68G_INT);
611 str = real (p);
612 A68G_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_REF, 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 = A68G_REAL_WIDTH + 2;
624 after = A68G_REAL_WIDTH - 1;
625 } else if (mode == M_LONG_REAL || mode == M_LONG_INT) {
626 width = A68G_LONG_REAL_WIDTH + 2;
627 after = A68G_LONG_REAL_WIDTH - 1;
628 } else if (mode == M_LONG_LONG_REAL || mode == M_LONG_LONG_INT) {
629 width = A68G_LONG_LONG_REAL_WIDTH + 2;
630 after = A68G_LONG_LONG_REAL_WIDTH - 1;
631 }
632 scan_c_pattern (SUB (p), &right_align, &sign, &digits, &after, &letter);
633 if (digits == 0) {
634 width = 0;
635 } else if (digits > 0) {
636 width = digits + after + 2;
637 }
638 unite_to_number (p, mode, item);
639 PUSH_VALUE (p, (sign ? width : -width), A68G_INT);
640 PUSH_VALUE (p, after, A68G_INT);
641 str = fixed (p);
642 A68G_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) A68G_BITS_WIDTH / (REAL_T) nibble);
661 } else if (mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
662 #if (A68G_LEVEL <= 2)
663 width = (int) ceil ((REAL_T) get_mp_bits_width (mode) / (REAL_T) nibble);
664 #else
665 width = (int) ceil ((REAL_T) A68G_LONG_BITS_WIDTH / (REAL_T) nibble);
666 #endif
667 }
668 }
669 if (mode == M_BITS) {
670 A68G_BITS *z = (A68G_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 (A68G_LEVEL >= 3)
679 A68G_LONG_BITS *z = (A68G_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 (A68G_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 = A68G_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 == A68G_TRUE) {
728 while (str[0] == BLANK_CHAR) {
729 str++;
730 }
731 int blanks = width - 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 - 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, A68G_REF ref_file)
763 {
764 A68G_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, A68G_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, A68G_REF ref_file)
786 {
787 ADDR_T pop_sp = A68G_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 == A68G_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 A68G_FILE *file = FILE_DEREF (&ref_file);
858 int ch;
859 ASSERT (a68g_bufprt (str, (size_t) TRANSPUT_BUFFER_SIZE, "%dr", radix) >= 0);
860 set_transput_buffer_index (INPUT_BUFFER, 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 (a68g_bufprt (str, (size_t) TRANSPUT_BUFFER_SIZE, "%dr", radix) >= 0);
876 set_transput_buffer_index (INPUT_BUFFER, 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 A68G_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), A68G_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), A68G_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, A68G_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, 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 //! @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, A68G_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 = A68G_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 int digits = DIGITS (M_LONG_LONG_INT);
1082 MP_T *z = nil_mp (p, digits);
1083 if (mode == M_INT) {
1084 int_to_mp (p, z, VALUE ((A68G_INT *) item), digits);
1085 } else if (mode == M_LONG_INT) {
1086 #if (A68G_LEVEL >= 3)
1087 DOUBLE_NUM_T w = VALUE ((A68G_LONG_INT *) item);
1088 double_int_to_mp (p, z, w, digits);
1089 #else
1090 (void) lengthen_mp (p, z, digits, (MP_T *) item, DIGITS (M_LONG_INT));
1091 #endif
1092 } else if (mode == M_LONG_LONG_INT) {
1093 (void) move_mp (z, (MP_T *) item, digits);
1094 }
1095 sign = MP_SIGN (z);
1096 MP_DIGIT (z, 1) = ABS (MP_DIGIT (z, 1));
1097 str = sub_whole_mp (p, z, digits, width);
1098 // Edit string and output.
1099 if (strchr (str, ERROR_CHAR) != NO_TEXT) {
1100 value_error (p, root, ref_file);
1101 }
1102 if (IS (p, SIGN_MOULD)) {
1103 put_sign_to_integral (p, sign);
1104 } else if (sign < 0) {
1105 value_sign_error (p, root, ref_file);
1106 }
1107 put_zeroes_to_integral (p, width - strlen (str));
1108 add_string_transput_buffer (p, EDIT_BUFFER, str);
1109 str = get_transput_buffer (EDIT_BUFFER);
1110 mood = (MOOD_T) (DIGIT_BLANK | INSERTION_NORMAL);
1111 if (IS (p, SIGN_MOULD)) {
1112 if (str[0] == '+' || str[0] == '-') {
1113 shift_sign (SUB (p), &str);
1114 }
1115 str = get_transput_buffer (EDIT_BUFFER);
1116 write_mould (SUB (p), ref_file, SIGN_MOULD, &str, &mood);
1117 FORWARD (p);
1118 }
1119 if (IS (p, INTEGRAL_MOULD)) { // This *should* be the case
1120 write_mould (SUB (p), ref_file, INTEGRAL_MOULD, &str, &mood);
1121 }
1122 A68G_SP = pop_sp;
1123 }
1124 }
1125
1126 //! @brief Write REAL value using real pattern.
1127
1128 void write_real_pattern (NODE_T * p, MOID_T * mode, MOID_T * root, BYTE_T * item, A68G_REF ref_file)
1129 {
1130 errno = 0;
1131 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)) {
1132 pattern_error (p, root, ATTRIBUTE (p));
1133 } else {
1134 ADDR_T pop_sp = A68G_SP;
1135 int stag_digits = 0, frac_digits = 0, expo_digits = 0;
1136 int mant_length, sign = 0, exp_value;
1137 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;
1138 char *str = NO_TEXT, *stag_str = NO_TEXT, *frac_str = NO_TEXT;
1139 MOOD_T mood;
1140 // Dive into pattern.
1141 q = ((IS (p, REAL_PATTERN)) ? SUB (p) : p);
1142 // Dissect pattern and establish widths.
1143 if (q != NO_NODE && IS (q, SIGN_MOULD)) {
1144 sign_mould = q;
1145 count_zd_frames (SUB (sign_mould), &stag_digits);
1146 FORWARD (q);
1147 }
1148 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
1149 stag_mould = q;
1150 count_zd_frames (SUB (stag_mould), &stag_digits);
1151 FORWARD (q);
1152 }
1153 if (q != NO_NODE && IS (q, FORMAT_POINT_FRAME)) {
1154 point_frame = q;
1155 FORWARD (q);
1156 }
1157 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
1158 frac_mould = q;
1159 count_zd_frames (SUB (frac_mould), &frac_digits);
1160 FORWARD (q);
1161 }
1162 if (q != NO_NODE && IS (q, EXPONENT_FRAME)) {
1163 e_frame = SUB (q);
1164 expo_mould = NEXT_SUB (q);
1165 q = expo_mould;
1166 if (IS (q, SIGN_MOULD)) {
1167 count_zd_frames (SUB (q), &expo_digits);
1168 FORWARD (q);
1169 }
1170 if (IS (q, INTEGRAL_MOULD)) {
1171 count_zd_frames (SUB (q), &expo_digits);
1172 }
1173 }
1174 // Make string representation.
1175 if (point_frame == NO_NODE) {
1176 mant_length = stag_digits;
1177 } else {
1178 mant_length = 1 + stag_digits + frac_digits;
1179 }
1180 //
1181 ADDR_T pop_sp2 = A68G_SP;
1182 int digits = DIGITS (M_LONG_LONG_REAL);
1183 MP_T *z = nil_mp (p, digits);
1184 if (mode == M_INT) {
1185 INT_T x = VALUE ((A68G_INT *) item);
1186 (void) int_to_mp (p, z, x, digits);
1187 } else if (mode == M_REAL) {
1188 REAL_T x = VALUE ((A68G_REAL *) item);
1189 CHECK_REAL (p, x);
1190 #if (A68G_LEVEL >= 3)
1191 (void) double_to_mp (p, z, (DOUBLE_T) x, A68G_REAL_DIG, A68G_TRUE, digits);
1192 #else
1193 (void) real_to_mp (p, z, x, digits);
1194 #endif
1195 } else if (mode == M_LONG_INT) {
1196 #if (A68G_LEVEL >= 3)
1197 DOUBLE_NUM_T x = VALUE ((A68G_DOUBLE *) item);
1198 (void) double_int_to_mp (p, z, x, digits);
1199 #else
1200 (void) lengthen_mp (p, z, digits, (MP_T *) item, DIGITS (M_LONG_INT));
1201 #endif
1202 } else if (mode == M_LONG_REAL) {
1203 #if (A68G_LEVEL >= 3)
1204 DOUBLE_T x = VALUE ((A68G_DOUBLE *) item).f;
1205 CHECK_DOUBLE_REAL (p, x);
1206 (void) double_to_mp (p, z, x, A68G_REAL_DIG, A68G_TRUE, digits);
1207 #else
1208 (void) lengthen_mp (p, z, digits, (MP_T *) item, DIGITS (M_LONG_REAL));
1209 #endif
1210 } else if (mode == M_LONG_LONG_REAL || mode == M_LONG_LONG_INT) {
1211 (void) move_mp (z, (MP_T *) item, digits);
1212 }
1213 exp_value = 0;
1214 sign = SIGN (z[2]);
1215 if (sign_mould != NO_NODE) {
1216 put_sign_to_integral (sign_mould, sign);
1217 }
1218 z[2] = ABS (z[2]);
1219 if (expo_mould != NO_NODE) {
1220 standardize_mp (p, z, digits, stag_digits, frac_digits, &exp_value);
1221 }
1222 str = sub_fixed_mp (p, z, digits, mant_length, frac_digits);
1223 A68G_SP = pop_sp2;
1224 // Edit and output the string.
1225 if (strchr (str, ERROR_CHAR) != NO_TEXT) {
1226 value_error (p, root, ref_file);
1227 }
1228 reset_transput_buffer (STRING_BUFFER);
1229 add_string_transput_buffer (p, STRING_BUFFER, str);
1230 stag_str = get_transput_buffer (STRING_BUFFER);
1231 if (strchr (stag_str, ERROR_CHAR) != NO_TEXT) {
1232 value_error (p, root, ref_file);
1233 }
1234 str = strchr (stag_str, POINT_CHAR);
1235 if (str != NO_TEXT) {
1236 frac_str = &str[1];
1237 str[0] = NULL_CHAR;
1238 } else {
1239 frac_str = NO_TEXT;
1240 }
1241 // Stagnant part.
1242 reset_transput_buffer (EDIT_BUFFER);
1243 if (sign_mould != NO_NODE) {
1244 put_sign_to_integral (sign_mould, sign);
1245 } else if (sign < 0) {
1246 value_sign_error (sign_mould, root, ref_file);
1247 }
1248 put_zeroes_to_integral (p, stag_digits - strlen (stag_str));
1249 add_string_transput_buffer (p, EDIT_BUFFER, stag_str);
1250 stag_str = get_transput_buffer (EDIT_BUFFER);
1251 mood = (MOOD_T) (DIGIT_BLANK | INSERTION_NORMAL);
1252 if (sign_mould != NO_NODE) {
1253 if (stag_str[0] == '+' || stag_str[0] == '-') {
1254 shift_sign (SUB (p), &stag_str);
1255 }
1256 stag_str = get_transput_buffer (EDIT_BUFFER);
1257 write_mould (SUB (sign_mould), ref_file, SIGN_MOULD, &stag_str, &mood);
1258 }
1259 if (stag_mould != NO_NODE) {
1260 write_mould (SUB (stag_mould), ref_file, INTEGRAL_MOULD, &stag_str, &mood);
1261 }
1262 // Point frame.
1263 if (point_frame != NO_NODE) {
1264 write_pie_frame (point_frame, ref_file, FORMAT_POINT_FRAME, FORMAT_ITEM_POINT);
1265 }
1266 // Fraction.
1267 if (frac_mould != NO_NODE) {
1268 reset_transput_buffer (EDIT_BUFFER);
1269 add_string_transput_buffer (p, EDIT_BUFFER, frac_str);
1270 frac_str = get_transput_buffer (EDIT_BUFFER);
1271 mood = (MOOD_T) (DIGIT_NORMAL | INSERTION_NORMAL);
1272 write_mould (SUB (frac_mould), ref_file, INTEGRAL_MOULD, &frac_str, &mood);
1273 }
1274 // Exponent.
1275 if (expo_mould != NO_NODE) {
1276 A68G_INT k;
1277 STATUS (&k) = INIT_MASK;
1278 VALUE (&k) = exp_value;
1279 if (e_frame != NO_NODE) {
1280 write_pie_frame (e_frame, ref_file, FORMAT_E_FRAME, FORMAT_ITEM_E);
1281 }
1282 write_integral_pattern (expo_mould, M_INT, root, (BYTE_T *) & k, ref_file);
1283 }
1284 A68G_SP = pop_sp;
1285 }
1286 }
1287
1288 //! @brief Write COMPLEX value using complex pattern.
1289
1290 void write_complex_pattern (NODE_T * p, MOID_T * comp, MOID_T * root, BYTE_T * re, BYTE_T * im, A68G_REF ref_file)
1291 {
1292 errno = 0;
1293 // Dissect pattern.
1294 NODE_T *reel = SUB (p);
1295 NODE_T *plus_i_times = NEXT (reel);
1296 NODE_T *imag = NEXT (plus_i_times);
1297 // Write pattern.
1298 write_real_pattern (reel, comp, root, re, ref_file);
1299 write_pie_frame (plus_i_times, ref_file, FORMAT_I_FRAME, FORMAT_ITEM_I);
1300 write_real_pattern (imag, comp, root, im, ref_file);
1301 }
1302
1303 //! @brief Write BITS value using bits pattern.
1304
1305 void write_bits_pattern (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
1306 {
1307 ADDR_T pop_sp = A68G_SP;
1308 int width = 0, radix;
1309 char *str;
1310 if (mode == M_BITS) {
1311 A68G_BITS *z = (A68G_BITS *) item;
1312 // Establish width and radix.
1313 count_zd_frames (SUB (p), &width);
1314 radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
1315 if (radix < 2 || radix > 16) {
1316 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
1317 exit_genie (p, A68G_RUNTIME_ERROR);
1318 }
1319 // Generate string of correct width.
1320 reset_transput_buffer (EDIT_BUFFER);
1321 if (!convert_radix (p, VALUE (z), radix, width)) {
1322 errno = EDOM;
1323 value_error (p, mode, ref_file);
1324 }
1325 } else if (mode == M_LONG_BITS) {
1326 #if (A68G_LEVEL >= 3)
1327 A68G_LONG_BITS *z = (A68G_LONG_BITS *) item;
1328 // Establish width and radix.
1329 count_zd_frames (SUB (p), &width);
1330 radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
1331 if (radix < 2 || radix > 16) {
1332 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
1333 exit_genie (p, A68G_RUNTIME_ERROR);
1334 }
1335 // Generate string of correct width.
1336 reset_transput_buffer (EDIT_BUFFER);
1337 if (!convert_radix_double (p, VALUE (z), radix, width)) {
1338 errno = EDOM;
1339 value_error (p, mode, ref_file);
1340 }
1341 #else
1342 int digits = DIGITS (mode);
1343 MP_T *u = (MP_T *) item;
1344 MP_T *v = nil_mp (p, digits);
1345 MP_T *w = nil_mp (p, digits);
1346 // Establish width and radix.
1347 count_zd_frames (SUB (p), &width);
1348 radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
1349 if (radix < 2 || radix > 16) {
1350 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
1351 exit_genie (p, A68G_RUNTIME_ERROR);
1352 }
1353 // Generate string of correct width.
1354 reset_transput_buffer (EDIT_BUFFER);
1355 if (!convert_radix_mp (p, u, radix, width, mode, v, w)) {
1356 errno = EDOM;
1357 value_error (p, mode, ref_file);
1358 }
1359 #endif
1360 } else if (mode == M_LONG_LONG_BITS) {
1361 #if (A68G_LEVEL <= 2)
1362 int digits = DIGITS (mode);
1363 MP_T *u = (MP_T *) item;
1364 MP_T *v = nil_mp (p, digits);
1365 MP_T *w = nil_mp (p, digits);
1366 // Establish width and radix.
1367 count_zd_frames (SUB (p), &width);
1368 radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
1369 if (radix < 2 || radix > 16) {
1370 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
1371 exit_genie (p, A68G_RUNTIME_ERROR);
1372 }
1373 // Generate string of correct width.
1374 reset_transput_buffer (EDIT_BUFFER);
1375 if (!convert_radix_mp (p, u, radix, width, mode, v, w)) {
1376 errno = EDOM;
1377 value_error (p, mode, ref_file);
1378 }
1379 #endif
1380 }
1381 // Output the edited string.
1382 MOOD_T mood = (MOOD_T) (DIGIT_BLANK | INSERTION_NORMAL);
1383 str = get_transput_buffer (EDIT_BUFFER);
1384 write_mould (NEXT_SUB (p), ref_file, INTEGRAL_MOULD, &str, &mood);
1385 A68G_SP = pop_sp;
1386 }
1387
1388 //! @brief Write value to file.
1389
1390 void genie_write_real_format (NODE_T * p, BYTE_T * item, A68G_REF ref_file)
1391 {
1392 if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) == NO_NODE) {
1393 genie_value_to_string (p, M_REAL, item, ATTRIBUTE (SUB (p)));
1394 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1395 } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
1396 write_number_generic (p, M_REAL, item, ATTRIBUTE (SUB (p)));
1397 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
1398 write_c_pattern (p, M_REAL, item, ref_file);
1399 } else if (IS (p, REAL_PATTERN)) {
1400 write_real_pattern (p, M_REAL, M_REAL, item, ref_file);
1401 } else if (IS (p, COMPLEX_PATTERN)) {
1402 A68G_REAL im;
1403 STATUS (&im) = INIT_MASK;
1404 VALUE (&im) = 0.0;
1405 write_complex_pattern (p, M_REAL, M_COMPLEX, (BYTE_T *) item, (BYTE_T *) & im, ref_file);
1406 } else {
1407 pattern_error (p, M_REAL, ATTRIBUTE (p));
1408 }
1409 }
1410
1411 //! @brief Write value to file.
1412
1413 void genie_write_long_real_format (NODE_T * p, BYTE_T * item, A68G_REF ref_file)
1414 {
1415 if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) == NO_NODE) {
1416 genie_value_to_string (p, M_LONG_REAL, item, ATTRIBUTE (SUB (p)));
1417 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1418 } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
1419 write_number_generic (p, M_LONG_REAL, item, ATTRIBUTE (SUB (p)));
1420 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
1421 write_c_pattern (p, M_LONG_REAL, item, ref_file);
1422 } else if (IS (p, REAL_PATTERN)) {
1423 write_real_pattern (p, M_LONG_REAL, M_LONG_REAL, item, ref_file);
1424 } else if (IS (p, COMPLEX_PATTERN)) {
1425 #if (A68G_LEVEL >= 3)
1426 ADDR_T pop_sp = A68G_SP;
1427 A68G_LONG_REAL *z = (A68G_LONG_REAL *) STACK_TOP;
1428 DOUBLE_NUM_T im;
1429 im.f = 0.0q;
1430 PUSH_VALUE (p, im, A68G_LONG_REAL);
1431 write_complex_pattern (p, M_LONG_REAL, M_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1432 A68G_SP = pop_sp;
1433 #else
1434 ADDR_T pop_sp = A68G_SP;
1435 MP_T *z = nil_mp (p, DIGITS (M_LONG_REAL));
1436 z[0] = (MP_T) INIT_MASK;
1437 write_complex_pattern (p, M_LONG_REAL, M_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1438 A68G_SP = pop_sp;
1439 #endif
1440 } else {
1441 pattern_error (p, M_LONG_REAL, ATTRIBUTE (p));
1442 }
1443 }
1444
1445 //! @brief Write value to file.
1446
1447 void genie_write_long_mp_real_format (NODE_T * p, BYTE_T * item, A68G_REF ref_file)
1448 {
1449 if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) == NO_NODE) {
1450 genie_value_to_string (p, M_LONG_LONG_REAL, item, ATTRIBUTE (SUB (p)));
1451 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1452 } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
1453 write_number_generic (p, M_LONG_LONG_REAL, item, ATTRIBUTE (SUB (p)));
1454 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
1455 write_c_pattern (p, M_LONG_LONG_REAL, item, ref_file);
1456 } else if (IS (p, REAL_PATTERN)) {
1457 write_real_pattern (p, M_LONG_LONG_REAL, M_LONG_LONG_REAL, item, ref_file);
1458 } else if (IS (p, COMPLEX_PATTERN)) {
1459 ADDR_T pop_sp = A68G_SP;
1460 MP_T *z = nil_mp (p, DIGITS (M_LONG_LONG_REAL));
1461 z[0] = (MP_T) INIT_MASK;
1462 write_complex_pattern (p, M_LONG_LONG_REAL, M_LONG_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1463 A68G_SP = pop_sp;
1464 } else {
1465 pattern_error (p, M_LONG_LONG_REAL, ATTRIBUTE (p));
1466 }
1467 }
1468
1469 //! @brief At end of write purge all insertions.
1470
1471 void purge_format_write (NODE_T * p, A68G_REF ref_file)
1472 {
1473 // Problem here is shutting down embedded formats.
1474 BOOL_T siga;
1475 do {
1476 A68G_FILE *file;
1477 NODE_T *dollar, *pat;
1478 A68G_FORMAT *old_fmt;
1479 while ((pat = get_next_format_pattern (p, ref_file, SKIP_PATTERN)) != NO_NODE) {
1480 format_error (p, ref_file, ERROR_FORMAT_PICTURES);
1481 }
1482 file = FILE_DEREF (&ref_file);
1483 dollar = SUB (BODY (&FORMAT (file)));
1484 old_fmt = (A68G_FORMAT *) FRAME_LOCAL (A68G_FP, OFFSET (TAX (dollar)));
1485 siga = (BOOL_T) ! IS_NIL_FORMAT (old_fmt);
1486 if (siga) {
1487 // Pop embedded format and proceed.
1488 (void) end_of_format (p, ref_file);
1489 }
1490 } while (siga);
1491 }
1492
1493 //! @brief Write value to file.
1494
1495 void genie_write_standard_format (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file, int *formats)
1496 {
1497 errno = 0;
1498 ABEND (mode == NO_MOID, ERROR_INTERNAL_CONSISTENCY, __func__);
1499 if (mode == M_FORMAT) {
1500 A68G_FILE *file;
1501 CHECK_REF (p, ref_file, M_REF_FILE);
1502 file = FILE_DEREF (&ref_file);
1503 // Forget about eventual active formats and set up new one.
1504 if (*formats > 0) {
1505 purge_format_write (p, ref_file);
1506 }
1507 (*formats)++;
1508 A68G_FP = FRAME_POINTER (file);
1509 A68G_SP = STACK_POINTER (file);
1510 open_format_frame (p, ref_file, (A68G_FORMAT *) item, NOT_EMBEDDED_FORMAT, A68G_TRUE);
1511 } else if (mode == M_PROC_REF_FILE_VOID) {
1512 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_PROC_REF_FILE_VOID);
1513 exit_genie (p, A68G_RUNTIME_ERROR);
1514 } else if (mode == M_SOUND) {
1515 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_SOUND);
1516 exit_genie (p, A68G_RUNTIME_ERROR);
1517 } else if (mode == M_INT) {
1518 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1519 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1520 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (pat)));
1521 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1522 } else if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) != NO_NODE) {
1523 write_number_generic (pat, M_INT, item, ATTRIBUTE (SUB (pat)));
1524 } else if (IS (pat, INTEGRAL_C_PATTERN) || IS (pat, FIXED_C_PATTERN) || IS (pat, FLOAT_C_PATTERN) || IS (pat, GENERAL_C_PATTERN)) {
1525 write_c_pattern (pat, M_INT, item, ref_file);
1526 } else if (IS (pat, INTEGRAL_PATTERN)) {
1527 write_integral_pattern (pat, M_INT, M_INT, item, ref_file);
1528 } else if (IS (pat, REAL_PATTERN)) {
1529 write_real_pattern (pat, M_INT, M_INT, item, ref_file);
1530 } else if (IS (pat, COMPLEX_PATTERN)) {
1531 A68G_REAL re, im;
1532 STATUS (&re) = INIT_MASK;
1533 VALUE (&re) = (REAL_T) VALUE ((A68G_INT *) item);
1534 STATUS (&im) = INIT_MASK;
1535 VALUE (&im) = 0.0;
1536 write_complex_pattern (pat, M_REAL, M_COMPLEX, (BYTE_T *) & re, (BYTE_T *) & im, ref_file);
1537 } else if (IS (pat, CHOICE_PATTERN)) {
1538 int k = VALUE ((A68G_INT *) item);
1539 write_choice_pattern (NEXT_SUB (pat), ref_file, &k);
1540 } else {
1541 pattern_error (p, mode, ATTRIBUTE (pat));
1542 }
1543 } else if (mode == M_LONG_INT) {
1544 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1545 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1546 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (pat)));
1547 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1548 } else if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) != NO_NODE) {
1549 write_number_generic (pat, M_LONG_INT, item, ATTRIBUTE (SUB (pat)));
1550 } else if (IS (pat, INTEGRAL_C_PATTERN) || IS (pat, FIXED_C_PATTERN) || IS (pat, FLOAT_C_PATTERN) || IS (pat, GENERAL_C_PATTERN)) {
1551 write_c_pattern (pat, M_LONG_INT, item, ref_file);
1552 } else if (IS (pat, INTEGRAL_PATTERN)) {
1553 write_integral_pattern (pat, M_LONG_INT, M_LONG_INT, item, ref_file);
1554 } else if (IS (pat, REAL_PATTERN)) {
1555 write_real_pattern (pat, M_LONG_INT, M_LONG_INT, item, ref_file);
1556 } else if (IS (pat, COMPLEX_PATTERN)) {
1557 #if (A68G_LEVEL >= 3)
1558 ADDR_T pop_sp = A68G_SP;
1559 A68G_LONG_REAL *z = (A68G_LONG_REAL *) STACK_TOP;
1560 DOUBLE_NUM_T im;
1561 im.f = 0.0q;
1562 PUSH_VALUE (p, im, A68G_LONG_REAL);
1563 write_complex_pattern (p, M_LONG_REAL, M_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1564 A68G_SP = pop_sp;
1565 #else
1566 ADDR_T pop_sp = A68G_SP;
1567 MP_T *z = nil_mp (p, DIGITS (mode));
1568 z[0] = (MP_T) INIT_MASK;
1569 write_complex_pattern (pat, M_LONG_REAL, M_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1570 A68G_SP = pop_sp;
1571 #endif
1572 } else if (IS (pat, CHOICE_PATTERN)) {
1573 INT_T k = mp_to_int (p, (MP_T *) item, DIGITS (mode));
1574 int sk;
1575 CHECK_INT_SHORTEN (p, k);
1576 sk = (int) k;
1577 write_choice_pattern (NEXT_SUB (pat), ref_file, &sk);
1578 } else {
1579 pattern_error (p, mode, ATTRIBUTE (pat));
1580 }
1581 } else if (mode == M_LONG_LONG_INT) {
1582 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1583 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1584 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (pat)));
1585 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1586 } else if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) != NO_NODE) {
1587 write_number_generic (pat, M_LONG_LONG_INT, item, ATTRIBUTE (SUB (pat)));
1588 } else if (IS (pat, INTEGRAL_C_PATTERN) || IS (pat, FIXED_C_PATTERN) || IS (pat, FLOAT_C_PATTERN) || IS (pat, GENERAL_C_PATTERN)) {
1589 write_c_pattern (pat, M_LONG_LONG_INT, item, ref_file);
1590 } else if (IS (pat, INTEGRAL_PATTERN)) {
1591 write_integral_pattern (pat, M_LONG_LONG_INT, M_LONG_LONG_INT, item, ref_file);
1592 } else if (IS (pat, REAL_PATTERN)) {
1593 write_real_pattern (pat, M_INT, M_INT, item, ref_file);
1594 } else if (IS (pat, REAL_PATTERN)) {
1595 write_real_pattern (pat, M_LONG_LONG_INT, M_LONG_LONG_INT, item, ref_file);
1596 } else if (IS (pat, COMPLEX_PATTERN)) {
1597 ADDR_T pop_sp = A68G_SP;
1598 MP_T *z = nil_mp (p, DIGITS (M_LONG_LONG_REAL));
1599 z[0] = (MP_T) INIT_MASK;
1600 write_complex_pattern (pat, M_LONG_LONG_REAL, M_LONG_LONG_COMPLEX, item, (BYTE_T *) z, ref_file);
1601 A68G_SP = pop_sp;
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_REAL) {
1612 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1613 genie_write_real_format (pat, item, ref_file);
1614 } else if (mode == M_LONG_REAL) {
1615 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1616 genie_write_long_real_format (pat, item, ref_file);
1617 } else if (mode == M_LONG_LONG_REAL) {
1618 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1619 genie_write_long_mp_real_format (pat, item, ref_file);
1620 } else if (mode == M_COMPLEX) {
1621 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1622 if (IS (pat, COMPLEX_PATTERN)) {
1623 write_complex_pattern (pat, M_REAL, M_COMPLEX, &item[0], &item[SIZE (M_REAL)], ref_file);
1624 } else {
1625 // Try writing as two REAL values.
1626 genie_write_real_format (pat, item, ref_file);
1627 genie_write_standard_format (p, M_REAL, &item[SIZE (M_REAL)], ref_file, formats);
1628 }
1629 } else if (mode == M_LONG_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_LONG_REAL, M_LONG_COMPLEX, &item[0], &item[SIZE (M_LONG_REAL)], ref_file);
1633 } else {
1634 // Try writing as two LONG REAL values.
1635 genie_write_long_real_format (pat, item, ref_file);
1636 genie_write_standard_format (p, M_LONG_REAL, &item[SIZE (M_LONG_REAL)], ref_file, formats);
1637 }
1638 } else if (mode == M_LONG_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_LONG_REAL, M_LONG_LONG_COMPLEX, &item[0], &item[SIZE (M_LONG_LONG_REAL)], ref_file);
1642 } else {
1643 // Try writing as two LONG LONG REAL values.
1644 genie_write_long_mp_real_format (pat, item, ref_file);
1645 genie_write_standard_format (p, M_LONG_LONG_REAL, &item[SIZE (M_LONG_LONG_REAL)], ref_file, formats);
1646 }
1647 } else if (mode == M_BOOL) {
1648 A68G_BOOL *z = (A68G_BOOL *) item;
1649 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1650 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1651 plusab_transput_buffer (p, FORMATTED_BUFFER, (char) (VALUE (z) == A68G_TRUE ? FLIP_CHAR : FLOP_CHAR));
1652 } else if (IS (pat, BOOLEAN_PATTERN)) {
1653 if (NEXT_SUB (pat) == NO_NODE) {
1654 plusab_transput_buffer (p, FORMATTED_BUFFER, (char) (VALUE (z) == A68G_TRUE ? FLIP_CHAR : FLOP_CHAR));
1655 } else {
1656 write_boolean_pattern (pat, ref_file, (BOOL_T) (VALUE (z) == A68G_TRUE));
1657 }
1658 } else {
1659 pattern_error (p, mode, ATTRIBUTE (pat));
1660 }
1661 } else if (mode == M_BITS) {
1662 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1663 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1664 char *str = (char *) STACK_TOP;
1665 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (p)));
1666 add_string_transput_buffer (p, FORMATTED_BUFFER, str);
1667 } else if (IS (pat, BITS_PATTERN)) {
1668 write_bits_pattern (pat, M_BITS, item, ref_file);
1669 } else if (IS (pat, BITS_C_PATTERN)) {
1670 write_c_pattern (pat, M_BITS, item, ref_file);
1671 } else {
1672 pattern_error (p, mode, ATTRIBUTE (pat));
1673 }
1674 } else if (mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
1675 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1676 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1677 char *str = (char *) STACK_TOP;
1678 genie_value_to_string (p, mode, item, ATTRIBUTE (SUB (p)));
1679 add_string_transput_buffer (p, FORMATTED_BUFFER, str);
1680 } else if (IS (pat, BITS_PATTERN)) {
1681 write_bits_pattern (pat, mode, item, ref_file);
1682 } else if (IS (pat, BITS_C_PATTERN)) {
1683 write_c_pattern (pat, mode, item, ref_file);
1684 } else {
1685 pattern_error (p, mode, ATTRIBUTE (pat));
1686 }
1687 } else if (mode == M_CHAR) {
1688 A68G_CHAR *z = (A68G_CHAR *) item;
1689 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1690 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1691 plusab_transput_buffer (p, FORMATTED_BUFFER, (char) VALUE (z));
1692 } else if (IS (pat, STRING_PATTERN)) {
1693 char *q = get_transput_buffer (EDIT_BUFFER);
1694 reset_transput_buffer (EDIT_BUFFER);
1695 plusab_transput_buffer (p, EDIT_BUFFER, (char) VALUE (z));
1696 write_string_pattern (pat, mode, ref_file, &q);
1697 if (q[0] != NULL_CHAR) {
1698 value_error (p, mode, ref_file);
1699 }
1700 } else if (IS (pat, STRING_C_PATTERN)) {
1701 char zz[2];
1702 zz[0] = VALUE (z);
1703 zz[1] = '\0';
1704 (void) c_to_a_string (pat, zz, 1);
1705 write_c_pattern (pat, mode, (BYTE_T *) zz, ref_file);
1706 } else {
1707 pattern_error (p, mode, ATTRIBUTE (pat));
1708 }
1709 } else if (mode == M_ROW_CHAR || mode == M_STRING) {
1710 // Handle these separately instead of printing [] CHAR.
1711 A68G_REF row = *(A68G_REF *) item;
1712 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
1713 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
1714 PUSH_REF (p, row);
1715 add_string_from_stack_transput_buffer (p, FORMATTED_BUFFER);
1716 } else if (IS (pat, STRING_PATTERN)) {
1717 char *q;
1718 PUSH_REF (p, row);
1719 reset_transput_buffer (EDIT_BUFFER);
1720 add_string_from_stack_transput_buffer (p, EDIT_BUFFER);
1721 q = get_transput_buffer (EDIT_BUFFER);
1722 write_string_pattern (pat, mode, ref_file, &q);
1723 if (q[0] != NULL_CHAR) {
1724 value_error (p, mode, ref_file);
1725 }
1726 } else if (IS (pat, STRING_C_PATTERN)) {
1727 char *q;
1728 PUSH_REF (p, row);
1729 reset_transput_buffer (EDIT_BUFFER);
1730 add_string_from_stack_transput_buffer (p, EDIT_BUFFER);
1731 q = get_transput_buffer (EDIT_BUFFER);
1732 write_c_pattern (pat, mode, (BYTE_T *) q, ref_file);
1733 } else {
1734 pattern_error (p, mode, ATTRIBUTE (pat));
1735 }
1736 } else if (IS_UNION (mode)) {
1737 A68G_UNION *z = (A68G_UNION *) item;
1738 MOID_T *um = (MOID_T *) (VALUE (z));
1739 BYTE_T *ui = &item[A68G_UNION_SIZE];
1740 if (um == NO_MOID) {
1741 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_EMPTY_VALUE, mode);
1742 exit_genie (p, A68G_RUNTIME_ERROR);
1743 }
1744 genie_write_standard_format (p, um, ui, ref_file, formats);
1745 } else if (IS_STRUCT (mode)) {
1746 for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
1747 BYTE_T *elem = &item[OFFSET (q)];
1748 genie_check_initialisation (p, elem, MOID (q));
1749 genie_write_standard_format (p, MOID (q), elem, ref_file, formats);
1750 }
1751 } else if (IS_ROW (mode) || IS_FLEX (mode)) {
1752 MOID_T *deflexed = DEFLEX (mode);
1753 CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
1754 A68G_ARRAY *arr; A68G_TUPLE *tup;
1755 GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
1756 if (get_row_size (tup, DIM (arr)) > 0) {
1757 BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
1758 BOOL_T done = A68G_FALSE;
1759 initialise_internal_index (tup, DIM (arr));
1760 while (!done) {
1761 ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
1762 ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
1763 BYTE_T *elem = &base_addr[elem_addr];
1764 genie_check_initialisation (p, elem, SUB (deflexed));
1765 genie_write_standard_format (p, SUB (deflexed), elem, ref_file, formats);
1766 done = increment_internal_index (tup, DIM (arr));
1767 }
1768 }
1769 }
1770 if (errno != 0) {
1771 transput_error (p, ref_file, mode);
1772 }
1773 }
1774
1775 //! @brief PROC ([] SIMPLOUT) VOID print f, write f
1776
1777 void genie_write_format (NODE_T * p)
1778 {
1779 A68G_REF row;
1780 POP_REF (p, &row);
1781 genie_stand_out (p);
1782 PUSH_REF (p, row);
1783 genie_write_file_format (p);
1784 }
1785
1786 //! @brief PROC (REF FILE, [] SIMPLOUT) VOID put f
1787
1788 void genie_write_file_format (NODE_T * p)
1789 {
1790 A68G_REF row;
1791 POP_REF (p, &row);
1792 CHECK_REF (p, row, M_ROW_SIMPLOUT);
1793 A68G_ARRAY *arr; A68G_TUPLE *tup;
1794 GET_DESCRIPTOR (arr, tup, &row);
1795 int elems = ROW_SIZE (tup);
1796 A68G_REF ref_file;
1797 POP_REF (p, &ref_file);
1798 CHECK_REF (p, ref_file, M_REF_FILE);
1799 A68G_FILE *file = FILE_DEREF (&ref_file);
1800 CHECK_INIT (p, INITIALISED (file), M_FILE);
1801 if (!OPENED (file)) {
1802 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
1803 exit_genie (p, A68G_RUNTIME_ERROR);
1804 }
1805 if (DRAW_MOOD (file)) {
1806 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
1807 exit_genie (p, A68G_RUNTIME_ERROR);
1808 }
1809 if (READ_MOOD (file)) {
1810 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "read");
1811 exit_genie (p, A68G_RUNTIME_ERROR);
1812 }
1813 if (!PUT (&CHANNEL (file))) {
1814 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "putting");
1815 exit_genie (p, A68G_RUNTIME_ERROR);
1816 }
1817 if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
1818 if (IS_NIL (STRING (file))) {
1819 if ((FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS, A68G_PROTECTION)) == A68G_NO_FILE) {
1820 open_error (p, ref_file, "putting");
1821 }
1822 } else {
1823 FD (file) = open_physical_file (p, ref_file, A68G_WRITE_ACCESS, 0);
1824 }
1825 DRAW_MOOD (file) = A68G_FALSE;
1826 READ_MOOD (file) = A68G_FALSE;
1827 WRITE_MOOD (file) = A68G_TRUE;
1828 CHAR_MOOD (file) = A68G_TRUE;
1829 }
1830 if (!CHAR_MOOD (file)) {
1831 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "binary");
1832 exit_genie (p, A68G_RUNTIME_ERROR);
1833 }
1834 // Save stack state since formats have frames.
1835 ADDR_T pop_fp = FRAME_POINTER (file), pop_sp = STACK_POINTER (file);
1836 FRAME_POINTER (file) = A68G_FP;
1837 STACK_POINTER (file) = A68G_SP;
1838 // Process [] SIMPLOUT.
1839 if (BODY (&FORMAT (file)) != NO_NODE) {
1840 open_format_frame (p, ref_file, &FORMAT (file), NOT_EMBEDDED_FORMAT, A68G_FALSE);
1841 }
1842 if (elems <= 0) {
1843 return;
1844 }
1845 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
1846 int elem_index = 0, formats = 0;
1847 for (int k = 0; k < elems; k++) {
1848 A68G_UNION *z = (A68G_UNION *) & (base_address[elem_index]);
1849 MOID_T *mode = (MOID_T *) (VALUE (z));
1850 BYTE_T *item = &(base_address[elem_index + A68G_UNION_SIZE]);
1851 genie_write_standard_format (p, mode, item, ref_file, &formats);
1852 elem_index += SIZE (M_SIMPLOUT);
1853 }
1854 // Empty the format to purge insertions.
1855 purge_format_write (p, ref_file);
1856 BODY (&FORMAT (file)) = NO_NODE;
1857 // Dump the buffer.
1858 write_purge_buffer (p, ref_file, FORMATTED_BUFFER);
1859 // Forget about active formats.
1860 A68G_FP = FRAME_POINTER (file);
1861 A68G_SP = STACK_POINTER (file);
1862 FRAME_POINTER (file) = pop_fp;
1863 STACK_POINTER (file) = pop_sp;
1864 }
1865
1866 //! @brief Give a value error in case a character is not among expected ones.
1867
1868 BOOL_T expect (NODE_T * p, MOID_T * m, A68G_REF ref_file, const char *items, char ch)
1869 {
1870 if (strchr ((char *) items, ch) == NO_TEXT) {
1871 value_error (p, m, ref_file);
1872 return A68G_FALSE;
1873 } else {
1874 return A68G_TRUE;
1875 }
1876 }
1877
1878 //! @brief Read a group of insertions.
1879
1880 void read_insertion (NODE_T * p, A68G_REF ref_file)
1881 {
1882
1883 // Algol68G does not check whether the insertions are textually there. It just
1884 // skips them. This because we blank literals in sign moulds before the sign is
1885 // put, which is non-standard Algol68, but convenient.
1886
1887 A68G_FILE *file = FILE_DEREF (&ref_file);
1888 for (; p != NO_NODE; FORWARD (p)) {
1889 read_insertion (SUB (p), ref_file);
1890 if (IS (p, FORMAT_ITEM_L)) {
1891 BOOL_T siga = (BOOL_T) ! END_OF_FILE (file);
1892 while (siga) {
1893 int ch = read_single_char (p, ref_file);
1894 siga = (BOOL_T) ((ch != NEWLINE_CHAR) && (ch != EOF_CHAR) && !END_OF_FILE (file));
1895 }
1896 } else if (IS (p, FORMAT_ITEM_P)) {
1897 BOOL_T siga = (BOOL_T) ! END_OF_FILE (file);
1898 while (siga) {
1899 int ch = read_single_char (p, ref_file);
1900 siga = (BOOL_T) ((ch != FORMFEED_CHAR) && (ch != EOF_CHAR) && !END_OF_FILE (file));
1901 }
1902 } else if (IS (p, FORMAT_ITEM_X) || IS (p, FORMAT_ITEM_Q)) {
1903 if (!END_OF_FILE (file)) {
1904 (void) read_single_char (p, ref_file);
1905 }
1906 } else if (IS (p, FORMAT_ITEM_Y)) {
1907 PUSH_REF (p, ref_file);
1908 PUSH_VALUE (p, -1, A68G_INT);
1909 genie_set (p);
1910 } else if (IS (p, LITERAL)) {
1911 // Skip characters, but don't check the literal.
1912 size_t len = strlen (NSYMBOL (p));
1913 while (len-- && !END_OF_FILE (file)) {
1914 (void) read_single_char (p, ref_file);
1915 }
1916 } else if (IS (p, REPLICATOR)) {
1917 int k = get_replicator_value (SUB (p), A68G_TRUE);
1918 if (ATTRIBUTE (SUB_NEXT (p)) != FORMAT_ITEM_K) {
1919 for (int j = 1; j <= k; j++) {
1920 read_insertion (NEXT (p), ref_file);
1921 }
1922 } else {
1923 int pos = get_transput_buffer_index (INPUT_BUFFER);
1924 for (int j = 1; j < (k - pos); j++) {
1925 if (!END_OF_FILE (file)) {
1926 (void) read_single_char (p, ref_file);
1927 }
1928 }
1929 }
1930 return; // From REPLICATOR, don't delete this!
1931 }
1932 }
1933 }
1934
1935 //! @brief Read string from file according current format.
1936
1937 void read_string_pattern (NODE_T * p, MOID_T * m, A68G_REF ref_file)
1938 {
1939 for (; p != NO_NODE; FORWARD (p)) {
1940 if (IS (p, INSERTION)) {
1941 read_insertion (SUB (p), ref_file);
1942 } else if (IS (p, FORMAT_ITEM_A)) {
1943 scan_n_chars (p, 1, m, ref_file);
1944 } else if (IS (p, FORMAT_ITEM_S)) {
1945 plusab_transput_buffer (p, INPUT_BUFFER, BLANK_CHAR);
1946 return;
1947 } else if (IS (p, REPLICATOR)) {
1948 int k = get_replicator_value (SUB (p), A68G_TRUE);
1949 for (int j = 1; j <= k; j++) {
1950 read_string_pattern (NEXT (p), m, ref_file);
1951 }
1952 return;
1953 } else {
1954 read_string_pattern (SUB (p), m, ref_file);
1955 }
1956 }
1957 }
1958
1959 //! @brief Traverse choice pattern.
1960
1961 void traverse_choice_pattern (NODE_T * p, char *str, int len, int *count, int *matches, int *first_match, BOOL_T * full_match)
1962 {
1963 for (; p != NO_NODE; FORWARD (p)) {
1964 traverse_choice_pattern (SUB (p), str, len, count, matches, first_match, full_match);
1965 if (IS (p, LITERAL)) {
1966 (*count)++;
1967 if (strncmp (NSYMBOL (p), str, (size_t) len) == 0) {
1968 (*matches)++;
1969 (*full_match) = (BOOL_T) ((*full_match) | (strcmp (NSYMBOL (p), str) == 0));
1970 if (*first_match == 0 && *full_match) {
1971 *first_match = *count;
1972 }
1973 }
1974 }
1975 }
1976 }
1977
1978 //! @brief Read appropriate insertion from a choice pattern.
1979
1980 int read_choice_pattern (NODE_T * p, A68G_REF ref_file)
1981 {
1982
1983 // This implementation does not have the RR peculiarity that longest
1984 // matching literal must be first, in case of non-unique first chars.
1985
1986 A68G_FILE *file = FILE_DEREF (&ref_file);
1987 BOOL_T cont = A68G_TRUE;
1988 int longest_match = 0, longest_match_len = 0;
1989 while (cont) {
1990 int ch = char_scanner (file);
1991 if (!END_OF_FILE (file)) {
1992 int len, count = 0, matches = 0, first_match = 0;
1993 BOOL_T full_match = A68G_FALSE;
1994 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
1995 len = get_transput_buffer_index (INPUT_BUFFER);
1996 traverse_choice_pattern (p, get_transput_buffer (INPUT_BUFFER), len, &count, &matches, &first_match, &full_match);
1997 if (full_match && matches == 1 && first_match > 0) {
1998 return first_match;
1999 } else if (full_match && matches > 1 && first_match > 0) {
2000 longest_match = first_match;
2001 longest_match_len = len;
2002 } else if (matches == 0) {
2003 cont = A68G_FALSE;
2004 }
2005 } else {
2006 cont = A68G_FALSE;
2007 }
2008 }
2009 if (longest_match > 0) {
2010 // Push back look-ahead chars.
2011 if (get_transput_buffer_index (INPUT_BUFFER) > 0) {
2012 char *z = get_transput_buffer (INPUT_BUFFER);
2013 END_OF_FILE (file) = A68G_FALSE;
2014 add_string_transput_buffer (p, TRANSPUT_BUFFER (file), &z[longest_match_len]);
2015 }
2016 return longest_match;
2017 } else {
2018 value_error (p, M_INT, ref_file);
2019 return 0;
2020 }
2021 }
2022
2023 //! @brief Read value according to a general-pattern.
2024
2025 void read_number_generic (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
2026 {
2027 GENIE_UNIT (NEXT_SUB (p));
2028 // RR says to ignore parameters just calculated, so we will.
2029 A68G_REF row;
2030 POP_REF (p, &row);
2031 genie_read_standard (p, mode, item, ref_file);
2032 }
2033
2034 // INTEGRAL, REAL, COMPLEX and BITS patterns.
2035
2036 //! @brief Read sign-mould according current format.
2037
2038 void read_sign_mould (NODE_T * p, MOID_T * m, A68G_REF ref_file, int *sign)
2039 {
2040 for (; p != NO_NODE; FORWARD (p)) {
2041 if (IS (p, INSERTION)) {
2042 read_insertion (SUB (p), ref_file);
2043 } else if (IS (p, REPLICATOR)) {
2044 int k = get_replicator_value (SUB (p), A68G_TRUE);
2045 for (int j = 1; j <= k; j++) {
2046 read_sign_mould (NEXT (p), m, ref_file, sign);
2047 }
2048 return; // Leave this!
2049 } else {
2050 switch (ATTRIBUTE (p)) {
2051 case FORMAT_ITEM_Z:
2052 case FORMAT_ITEM_D:
2053 case FORMAT_ITEM_S:
2054 case FORMAT_ITEM_PLUS:
2055 case FORMAT_ITEM_MINUS: {
2056 int ch = read_single_char (p, ref_file);
2057 // When a sign has been read, digits are expected.
2058 if (*sign != 0) {
2059 if (expect (p, m, ref_file, INT_DIGITS, (char) ch)) {
2060 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
2061 } else {
2062 plusab_transput_buffer (p, INPUT_BUFFER, '0');
2063 }
2064 // When a sign has not been read, a sign is expected. If there is a digit
2065 // in stead of a sign, the digit is accepted and '+' is assumed; RR demands a
2066 // space to preceed the digit, Algol68G does not.
2067 } else {
2068 if (strchr (SIGN_DIGITS, ch) != NO_TEXT) {
2069 if (ch == '+') {
2070 *sign = 1;
2071 } else if (ch == '-') {
2072 *sign = -1;
2073 } else if (ch == BLANK_CHAR) {
2074 ;
2075 }
2076 } else if (expect (p, m, ref_file, INT_DIGITS, (char) ch)) {
2077 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
2078 *sign = 1;
2079 }
2080 }
2081 break;
2082 }
2083 default: {
2084 read_sign_mould (SUB (p), m, ref_file, sign);
2085 break;
2086 }
2087 }
2088 }
2089 }
2090 }
2091
2092 //! @brief Read mould according current format.
2093
2094 void read_integral_mould (NODE_T * p, MOID_T * m, A68G_REF ref_file)
2095 {
2096 for (; p != NO_NODE; FORWARD (p)) {
2097 if (IS (p, INSERTION)) {
2098 read_insertion (SUB (p), ref_file);
2099 } else if (IS (p, REPLICATOR)) {
2100 int k = get_replicator_value (SUB (p), A68G_TRUE);
2101 for (int j = 1; j <= k; j++) {
2102 read_integral_mould (NEXT (p), m, ref_file);
2103 }
2104 return; // Leave this!
2105 } else if (IS (p, FORMAT_ITEM_Z)) {
2106 int ch = read_single_char (p, ref_file);
2107 const char *digits = (m == M_BITS || m == M_LONG_BITS || m == M_LONG_LONG_BITS) ? BITS_DIGITS_BLANK : INT_DIGITS_BLANK;
2108 if (expect (p, m, ref_file, digits, (char) ch)) {
2109 plusab_transput_buffer (p, INPUT_BUFFER, (char) ((ch == BLANK_CHAR) ? '0' : ch));
2110 } else {
2111 plusab_transput_buffer (p, INPUT_BUFFER, '0');
2112 }
2113 } else if (IS (p, FORMAT_ITEM_D)) {
2114 int ch = read_single_char (p, ref_file);
2115 const char *digits = (m == M_BITS || m == M_LONG_BITS || m == M_LONG_LONG_BITS) ? BITS_DIGITS : INT_DIGITS;
2116 if (expect (p, m, ref_file, digits, (char) ch)) {
2117 plusab_transput_buffer (p, INPUT_BUFFER, (char) ch);
2118 } else {
2119 plusab_transput_buffer (p, INPUT_BUFFER, '0');
2120 }
2121 } else if (IS (p, FORMAT_ITEM_S)) {
2122 plusab_transput_buffer (p, INPUT_BUFFER, '0');
2123 } else {
2124 read_integral_mould (SUB (p), m, ref_file);
2125 }
2126 }
2127 }
2128
2129 //! @brief Read mould according current format.
2130
2131 void read_integral_pattern (NODE_T * p, MOID_T * m, BYTE_T * item, A68G_REF ref_file)
2132 {
2133 NODE_T *q = SUB (p);
2134 if (q != NO_NODE && IS (q, SIGN_MOULD)) {
2135 int sign = 0;
2136 char *z;
2137 plusab_transput_buffer (p, INPUT_BUFFER, BLANK_CHAR);
2138 read_sign_mould (SUB (q), m, ref_file, &sign);
2139 z = get_transput_buffer (INPUT_BUFFER);
2140 z[0] = (char) ((sign == -1) ? '-' : '+');
2141 FORWARD (q);
2142 }
2143 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
2144 read_integral_mould (SUB (q), m, ref_file);
2145 }
2146 genie_string_to_value (p, m, item, ref_file);
2147 }
2148
2149 //! @brief Read point, exponent or i-frame.
2150
2151 void read_pie_frame (NODE_T * p, MOID_T * m, A68G_REF ref_file, int att, int item, char ch)
2152 {
2153 // Widen ch to a stringlet.
2154 char sym[3];
2155 sym[0] = ch;
2156 sym[1] = (char) TO_LOWER (ch);
2157 sym[2] = NULL_CHAR;
2158 // Now read the frame.
2159 for (; p != NO_NODE; FORWARD (p)) {
2160 if (IS (p, INSERTION)) {
2161 read_insertion (p, ref_file);
2162 } else if (IS (p, att)) {
2163 read_pie_frame (SUB (p), m, ref_file, att, item, ch);
2164 return;
2165 } else if (IS (p, FORMAT_ITEM_S)) {
2166 plusab_transput_buffer (p, INPUT_BUFFER, sym[0]);
2167 return;
2168 } else if (IS (p, item)) {
2169 int ch0 = read_single_char (p, ref_file);
2170 if (expect (p, m, ref_file, sym, (char) ch0)) {
2171 plusab_transput_buffer (p, INPUT_BUFFER, sym[0]);
2172 } else {
2173 plusab_transput_buffer (p, INPUT_BUFFER, sym[0]);
2174 }
2175 }
2176 }
2177 }
2178
2179 //! @brief Read REAL value using real pattern.
2180
2181 void read_real_pattern (NODE_T * p, MOID_T * m, BYTE_T * item, A68G_REF ref_file)
2182 {
2183 // Dive into pattern.
2184 NODE_T *q = (IS (p, REAL_PATTERN)) ? SUB (p) : p;
2185 // Dissect pattern.
2186 if (q != NO_NODE && IS (q, SIGN_MOULD)) {
2187 int sign = 0;
2188 char *z;
2189 plusab_transput_buffer (p, INPUT_BUFFER, BLANK_CHAR);
2190 read_sign_mould (SUB (q), m, ref_file, &sign);
2191 z = get_transput_buffer (INPUT_BUFFER);
2192 z[0] = (char) ((sign == -1) ? '-' : '+');
2193 FORWARD (q);
2194 }
2195 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
2196 read_integral_mould (SUB (q), m, ref_file);
2197 FORWARD (q);
2198 }
2199 if (q != NO_NODE && IS (q, FORMAT_POINT_FRAME)) {
2200 read_pie_frame (SUB (q), m, ref_file, FORMAT_POINT_FRAME, FORMAT_ITEM_POINT, POINT_CHAR);
2201 FORWARD (q);
2202 }
2203 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
2204 read_integral_mould (SUB (q), m, ref_file);
2205 FORWARD (q);
2206 }
2207 if (q != NO_NODE && IS (q, EXPONENT_FRAME)) {
2208 read_pie_frame (SUB (q), m, ref_file, FORMAT_E_FRAME, FORMAT_ITEM_E, EXPONENT_CHAR);
2209 q = NEXT_SUB (q);
2210 if (q != NO_NODE && IS (q, SIGN_MOULD)) {
2211 int k, sign = 0;
2212 char *z;
2213 plusab_transput_buffer (p, INPUT_BUFFER, BLANK_CHAR);
2214 k = get_transput_buffer_index (INPUT_BUFFER);
2215 read_sign_mould (SUB (q), m, ref_file, &sign);
2216 z = get_transput_buffer (INPUT_BUFFER);
2217 z[k - 1] = (char) ((sign == -1) ? '-' : '+');
2218 FORWARD (q);
2219 }
2220 if (q != NO_NODE && IS (q, INTEGRAL_MOULD)) {
2221 read_integral_mould (SUB (q), m, ref_file);
2222 FORWARD (q);
2223 }
2224 }
2225 genie_string_to_value (p, m, item, ref_file);
2226 }
2227
2228 //! @brief Read COMPLEX value using complex pattern.
2229
2230 void read_complex_pattern (NODE_T * p, MOID_T * comp, MOID_T * m, BYTE_T * re, BYTE_T * im, A68G_REF ref_file)
2231 {
2232 // Dissect pattern.
2233 NODE_T *reel = SUB (p);
2234 NODE_T *plus_i_times = NEXT (reel);
2235 NODE_T *imag = NEXT (plus_i_times);
2236 // Read pattern.
2237 read_real_pattern (reel, m, re, ref_file);
2238 reset_transput_buffer (INPUT_BUFFER);
2239 read_pie_frame (plus_i_times, comp, ref_file, FORMAT_I_FRAME, FORMAT_ITEM_I, 'I');
2240 reset_transput_buffer (INPUT_BUFFER);
2241 read_real_pattern (imag, m, im, ref_file);
2242 }
2243
2244 //! @brief Read BITS value according pattern.
2245
2246 void read_bits_pattern (NODE_T * p, MOID_T * m, BYTE_T * item, A68G_REF ref_file)
2247 {
2248 int radix = get_replicator_value (SUB_SUB (p), A68G_TRUE);
2249 if (radix < 2 || radix > 16) {
2250 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, radix);
2251 exit_genie (p, A68G_RUNTIME_ERROR);
2252 }
2253 char *z = get_transput_buffer (INPUT_BUFFER);
2254 ASSERT (a68g_bufprt (z, (size_t) TRANSPUT_BUFFER_SIZE, "%dr", radix) >= 0);
2255 set_transput_buffer_index (INPUT_BUFFER, strlen (z));
2256 read_integral_mould (NEXT_SUB (p), m, ref_file);
2257 genie_string_to_value (p, m, item, ref_file);
2258 }
2259
2260 //! @brief Read object with from file and store.
2261
2262 void genie_read_real_format (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file)
2263 {
2264 if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) == NO_NODE) {
2265 genie_read_standard (p, mode, item, ref_file);
2266 } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
2267 read_number_generic (p, mode, item, ref_file);
2268 } else if (IS (p, FIXED_C_PATTERN) || IS (p, FLOAT_C_PATTERN) || IS (p, GENERAL_C_PATTERN)) {
2269 read_c_pattern (p, mode, item, ref_file);
2270 } else if (IS (p, REAL_PATTERN)) {
2271 read_real_pattern (p, mode, item, ref_file);
2272 } else {
2273 pattern_error (p, mode, ATTRIBUTE (p));
2274 }
2275 }
2276
2277 //! @brief At end of read purge all insertions.
2278
2279 void purge_format_read (NODE_T * p, A68G_REF ref_file)
2280 {
2281 BOOL_T siga;
2282 do {
2283 NODE_T *pat;
2284 while ((pat = get_next_format_pattern (p, ref_file, SKIP_PATTERN)) != NO_NODE) {
2285 format_error (p, ref_file, ERROR_FORMAT_PICTURES);
2286 }
2287 A68G_FILE *file = FILE_DEREF (&ref_file);
2288 NODE_T *dollar = SUB (BODY (&FORMAT (file)));
2289 A68G_FORMAT *old_fmt = (A68G_FORMAT *) FRAME_LOCAL (A68G_FP, OFFSET (TAX (dollar)));
2290 siga = (BOOL_T) ! IS_NIL_FORMAT (old_fmt);
2291 if (siga) {
2292 // Pop embedded format and proceed.
2293 (void) end_of_format (p, ref_file);
2294 }
2295 } while (siga);
2296 }
2297
2298 //! @brief Read object with from file and store.
2299
2300 void genie_read_standard_format (NODE_T * p, MOID_T * mode, BYTE_T * item, A68G_REF ref_file, int *formats)
2301 {
2302 errno = 0;
2303 reset_transput_buffer (INPUT_BUFFER);
2304 if (mode == M_FORMAT) {
2305 CHECK_REF (p, ref_file, M_REF_FILE);
2306 A68G_FILE *file = FILE_DEREF (&ref_file);
2307 // Forget about eventual active formats and set up new one.
2308 if (*formats > 0) {
2309 purge_format_read (p, ref_file);
2310 }
2311 (*formats)++;
2312 A68G_FP = FRAME_POINTER (file);
2313 A68G_SP = STACK_POINTER (file);
2314 open_format_frame (p, ref_file, (A68G_FORMAT *) item, NOT_EMBEDDED_FORMAT, A68G_TRUE);
2315 } else if (mode == M_PROC_REF_FILE_VOID) {
2316 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_PROC_REF_FILE_VOID);
2317 exit_genie (p, A68G_RUNTIME_ERROR);
2318 } else if (mode == M_REF_SOUND) {
2319 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_UNDEFINED_TRANSPUT, M_REF_SOUND);
2320 exit_genie (p, A68G_RUNTIME_ERROR);
2321 } else if (IS_REF (mode)) {
2322 CHECK_REF (p, *(A68G_REF *) item, mode);
2323 genie_read_standard_format (p, SUB (mode), ADDRESS ((A68G_REF *) item), ref_file, formats);
2324 } else if (mode == M_INT || mode == M_LONG_INT || mode == M_LONG_LONG_INT) {
2325 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2326 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2327 genie_read_standard (pat, mode, item, ref_file);
2328 } else if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) != NO_NODE) {
2329 read_number_generic (pat, mode, item, ref_file);
2330 } else if (IS (pat, INTEGRAL_C_PATTERN)) {
2331 read_c_pattern (pat, mode, item, ref_file);
2332 } else if (IS (pat, INTEGRAL_PATTERN)) {
2333 read_integral_pattern (pat, mode, item, ref_file);
2334 } else if (IS (pat, CHOICE_PATTERN)) {
2335 int k = read_choice_pattern (pat, ref_file);
2336 if (mode == M_INT) {
2337 A68G_INT *z = (A68G_INT *) item;
2338 VALUE (z) = k;
2339 STATUS (z) = (STATUS_MASK_T) ((VALUE (z) > 0) ? INIT_MASK : NULL_MASK);
2340 } else {
2341 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_DEPRECATED, mode);
2342 exit_genie (p, A68G_RUNTIME_ERROR);
2343 }
2344 } else {
2345 pattern_error (p, mode, ATTRIBUTE (pat));
2346 }
2347 } else if (mode == M_REAL || mode == M_LONG_REAL || mode == M_LONG_LONG_REAL) {
2348 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2349 genie_read_real_format (pat, mode, item, ref_file);
2350 } else if (mode == M_COMPLEX) {
2351 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2352 if (IS (pat, COMPLEX_PATTERN)) {
2353 read_complex_pattern (pat, mode, M_REAL, item, &item[SIZE (M_REAL)], ref_file);
2354 } else {
2355 // Try reading as two REAL values.
2356 genie_read_real_format (pat, M_REAL, item, ref_file);
2357 genie_read_standard_format (p, M_REAL, &item[SIZE (M_REAL)], ref_file, formats);
2358 }
2359 } else if (mode == M_LONG_COMPLEX) {
2360 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2361 if (IS (pat, COMPLEX_PATTERN)) {
2362 read_complex_pattern (pat, mode, M_LONG_REAL, item, &item[SIZE (M_LONG_REAL)], ref_file);
2363 } else {
2364 // Try reading as two LONG REAL values.
2365 genie_read_real_format (pat, M_LONG_REAL, item, ref_file);
2366 genie_read_standard_format (p, M_LONG_REAL, &item[SIZE (M_LONG_REAL)], ref_file, formats);
2367 }
2368 } else if (mode == M_LONG_LONG_COMPLEX) {
2369 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2370 if (IS (pat, COMPLEX_PATTERN)) {
2371 read_complex_pattern (pat, mode, M_LONG_LONG_REAL, item, &item[SIZE (M_LONG_LONG_REAL)], ref_file);
2372 } else {
2373 // Try reading as two LONG LONG REAL values.
2374 genie_read_real_format (pat, M_LONG_LONG_REAL, item, ref_file);
2375 genie_read_standard_format (p, M_LONG_LONG_REAL, &item[SIZE (M_LONG_LONG_REAL)], ref_file, formats);
2376 }
2377 } else if (mode == M_BOOL) {
2378 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2379 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2380 genie_read_standard (p, mode, item, ref_file);
2381 } else if (IS (pat, BOOLEAN_PATTERN)) {
2382 if (NEXT_SUB (pat) == NO_NODE) {
2383 genie_read_standard (p, mode, item, ref_file);
2384 } else {
2385 A68G_BOOL *z = (A68G_BOOL *) item;
2386 int k = read_choice_pattern (pat, ref_file);
2387 if (k == 1 || k == 2) {
2388 VALUE (z) = (BOOL_T) ((k == 1) ? A68G_TRUE : A68G_FALSE);
2389 STATUS (z) = INIT_MASK;
2390 } else {
2391 STATUS (z) = NULL_MASK;
2392 }
2393 }
2394 } else {
2395 pattern_error (p, mode, ATTRIBUTE (pat));
2396 }
2397 } else if (mode == M_BITS || mode == M_LONG_BITS || mode == M_LONG_LONG_BITS) {
2398 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2399 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2400 genie_read_standard (p, mode, item, ref_file);
2401 } else if (IS (pat, BITS_PATTERN)) {
2402 read_bits_pattern (pat, mode, item, ref_file);
2403 } else if (IS (pat, BITS_C_PATTERN)) {
2404 read_c_pattern (pat, mode, item, ref_file);
2405 } else {
2406 pattern_error (p, mode, ATTRIBUTE (pat));
2407 }
2408 } else if (mode == M_CHAR) {
2409 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2410 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2411 genie_read_standard (p, mode, item, ref_file);
2412 } else if (IS (pat, STRING_PATTERN)) {
2413 read_string_pattern (pat, M_CHAR, ref_file);
2414 genie_string_to_value (p, mode, item, ref_file);
2415 } else if (IS (pat, CHAR_C_PATTERN)) {
2416 read_c_pattern (pat, mode, item, ref_file);
2417 } else {
2418 pattern_error (p, mode, ATTRIBUTE (pat));
2419 }
2420 } else if (mode == M_ROW_CHAR || mode == M_STRING) {
2421 // Handle these separately instead of reading [] CHAR.
2422 NODE_T *pat = get_next_format_pattern (p, ref_file, WANT_PATTERN);
2423 if (IS (pat, GENERAL_PATTERN) && NEXT_SUB (pat) == NO_NODE) {
2424 genie_read_standard (p, mode, item, ref_file);
2425 } else if (IS (pat, STRING_PATTERN)) {
2426 read_string_pattern (pat, mode, ref_file);
2427 genie_string_to_value (p, mode, item, ref_file);
2428 } else if (IS (pat, STRING_C_PATTERN)) {
2429 read_c_pattern (pat, mode, item, ref_file);
2430 } else {
2431 pattern_error (p, mode, ATTRIBUTE (pat));
2432 }
2433 } else if (IS_UNION (mode)) {
2434 A68G_UNION *z = (A68G_UNION *) item;
2435 genie_read_standard_format (p, (MOID_T *) (VALUE (z)), &item[A68G_UNION_SIZE], ref_file, formats);
2436 } else if (IS_STRUCT (mode)) {
2437 for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
2438 BYTE_T *elem = &item[OFFSET (q)];
2439 genie_read_standard_format (p, MOID (q), elem, ref_file, formats);
2440 }
2441 } else if (IS_ROW (mode) || IS_FLEX (mode)) {
2442 MOID_T *deflexed = DEFLEX (mode);
2443 A68G_ARRAY *arr;
2444 A68G_TUPLE *tup;
2445 CHECK_INIT (p, INITIALISED ((A68G_REF *) item), M_ROWS);
2446 GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
2447 if (get_row_size (tup, DIM (arr)) > 0) {
2448 BYTE_T *base_addr = DEREF (BYTE_T, &ARRAY (arr));
2449 BOOL_T done = A68G_FALSE;
2450 initialise_internal_index (tup, DIM (arr));
2451 while (!done) {
2452 ADDR_T a68g_index = calculate_internal_index (tup, DIM (arr));
2453 ADDR_T elem_addr = ROW_ELEMENT (arr, a68g_index);
2454 BYTE_T *elem = &base_addr[elem_addr];
2455 genie_read_standard_format (p, SUB (deflexed), elem, ref_file, formats);
2456 done = increment_internal_index (tup, DIM (arr));
2457 }
2458 }
2459 }
2460 if (errno != 0) {
2461 transput_error (p, ref_file, mode);
2462 }
2463 }
2464
2465 //! @brief PROC ([] SIMPLIN) VOID read f
2466
2467 void genie_read_format (NODE_T * p)
2468 {
2469 A68G_REF row;
2470 POP_REF (p, &row);
2471 genie_stand_in (p);
2472 PUSH_REF (p, row);
2473 genie_read_file_format (p);
2474 }
2475
2476 //! @brief PROC (REF FILE, [] SIMPLIN) VOID get f
2477
2478 void genie_read_file_format (NODE_T * p)
2479 {
2480 A68G_REF row;
2481 POP_REF (p, &row);
2482 CHECK_REF (p, row, M_ROW_SIMPLIN);
2483 A68G_ARRAY *arr; A68G_TUPLE *tup;
2484 GET_DESCRIPTOR (arr, tup, &row);
2485 int elems = ROW_SIZE (tup);
2486 A68G_REF ref_file;
2487 POP_REF (p, &ref_file);
2488 CHECK_REF (p, ref_file, M_REF_FILE);
2489 A68G_FILE *file = FILE_DEREF (&ref_file);
2490 CHECK_INIT (p, INITIALISED (file), M_FILE);
2491 if (!OPENED (file)) {
2492 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_NOT_OPEN);
2493 exit_genie (p, A68G_RUNTIME_ERROR);
2494 }
2495 if (DRAW_MOOD (file)) {
2496 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "draw");
2497 exit_genie (p, A68G_RUNTIME_ERROR);
2498 }
2499 if (WRITE_MOOD (file)) {
2500 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "write");
2501 exit_genie (p, A68G_RUNTIME_ERROR);
2502 }
2503 if (!GET (&CHANNEL (file))) {
2504 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_CHANNEL_DOES_NOT_ALLOW, "getting");
2505 exit_genie (p, A68G_RUNTIME_ERROR);
2506 }
2507 if (!READ_MOOD (file) && !WRITE_MOOD (file)) {
2508 if (IS_NIL (STRING (file))) {
2509 if ((FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS, 0)) == A68G_NO_FILE) {
2510 open_error (p, ref_file, "getting");
2511 }
2512 } else {
2513 FD (file) = open_physical_file (p, ref_file, A68G_READ_ACCESS, 0);
2514 }
2515 DRAW_MOOD (file) = A68G_FALSE;
2516 READ_MOOD (file) = A68G_TRUE;
2517 WRITE_MOOD (file) = A68G_FALSE;
2518 CHAR_MOOD (file) = A68G_TRUE;
2519 }
2520 if (!CHAR_MOOD (file)) {
2521 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_WRONG_MOOD, "binary");
2522 exit_genie (p, A68G_RUNTIME_ERROR);
2523 }
2524 // Save stack state since formats have frames.
2525 ADDR_T pop_fp = FRAME_POINTER (file), pop_sp = STACK_POINTER (file);
2526 FRAME_POINTER (file) = A68G_FP;
2527 STACK_POINTER (file) = A68G_SP;
2528 // Process [] SIMPLIN.
2529 if (BODY (&FORMAT (file)) != NO_NODE) {
2530 open_format_frame (p, ref_file, &FORMAT (file), NOT_EMBEDDED_FORMAT, A68G_FALSE);
2531 }
2532 if (elems <= 0) {
2533 return;
2534 }
2535 int elem_index = 0, formats = 0;
2536 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr));
2537 for (int k = 0; k < elems; k++) {
2538 A68G_UNION *z = (A68G_UNION *) & (base_address[elem_index]);
2539 MOID_T *mode = (MOID_T *) (VALUE (z));
2540 BYTE_T *item = (BYTE_T *) & (base_address[elem_index + A68G_UNION_SIZE]);
2541 genie_read_standard_format (p, mode, item, ref_file, &formats);
2542 elem_index += SIZE (M_SIMPLIN);
2543 }
2544 // Empty the format to purge insertions.
2545 purge_format_read (p, ref_file);
2546 BODY (&FORMAT (file)) = NO_NODE;
2547 // Forget about active formats.
2548 A68G_FP = FRAME_POINTER (file);
2549 A68G_SP = STACK_POINTER (file);
2550 FRAME_POINTER (file) = pop_fp;
2551 STACK_POINTER (file) = pop_sp;
2552 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|