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