|
|
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@algol68genie.nl]. 8 9 //! @section License 10 //! 11 //! This program is free software; you can redistribute it and/or modify it 12 //! under the terms of the GNU General Public License as published by the 13 //! Free Software Foundation; either version 3 of the License, or 14 //! (at your option) any later version. 15 //! 16 //! This program is distributed in the hope that it will be useful, but 17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 //! more details. You should have received a copy of the GNU General Public 20 //! License along with this program. If not, see [http://www.gnu.org/licenses/]. 21 22 //! @section Synopsis 23 //! 24 //! Formatted transput. 25 26 #include "a68g.h" 27 #include "a68g-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_T 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 int formats = 0; 1845 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr)); 1846 INT_T elem_index = 0; 1847 for (INT_T 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_T 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 formats = 0; 2536 BYTE_T *base_address = DEREF (BYTE_T, &ARRAY (arr)); 2537 INT_T elem_index = 0; 2538 for (INT_T k = 0; k < elems; k++) { 2539 A68G_UNION *z = (A68G_UNION *) & (base_address[elem_index]); 2540 MOID_T *mode = (MOID_T *) (VALUE (z)); 2541 BYTE_T *item = (BYTE_T *) & (base_address[elem_index + A68G_UNION_SIZE]); 2542 genie_read_standard_format (p, mode, item, ref_file, &formats); 2543 elem_index += SIZE (M_SIMPLIN); 2544 } 2545 // Empty the format to purge insertions. 2546 purge_format_read (p, ref_file); 2547 BODY (&FORMAT (file)) = NO_NODE; 2548 // Forget about active formats. 2549 A68G_FP = FRAME_POINTER (file); 2550 A68G_SP = STACK_POINTER (file); 2551 FRAME_POINTER (file) = pop_fp; 2552 STACK_POINTER (file) = pop_sp; 2553 }
© 2001-2026 J.M. van der Veer
jmvdveer@algol68genie.nl