1 /* ------------------------------------------------------------------------- */
2 /* "arrays" : Parses array declarations and constructs arrays from them; */
3 /* likewise global variables, which are in some ways a */
4 /* simpler form of the same thing. */
6 /* Part of Inform 6.41 */
7 /* copyright (c) Graham Nelson 1993 - 2022 */
9 /* Inform is free software: you can redistribute it and/or modify */
10 /* it under the terms of the GNU General Public License as published by */
11 /* the Free Software Foundation, either version 3 of the License, or */
12 /* (at your option) any later version. */
14 /* Inform is distributed in the hope that it will be useful, */
15 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
16 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
17 /* GNU General Public License for more details. */
19 /* You should have received a copy of the GNU General Public License */
20 /* along with Inform. If not, see https://gnu.org/licenses/ */
22 /* ------------------------------------------------------------------------- */
26 /* ------------------------------------------------------------------------- */
27 /* Arrays defined below: */
29 /* uchar dynamic_array_area[] Initial values for the bytes of */
30 /* the dynamic array area */
31 /* uchar static_array_area[] Initial values for the bytes of */
32 /* the static array area */
33 /* int32 global_initial_value[n] The initialised value of the nth */
34 /* global variable (counting 0 - 239, */
35 /* or higher for Glulx) */
37 /* The "dynamic array area" is the Z-machine area holding the current */
38 /* values of the global variables (in 240x2 = 480 bytes) followed by any */
39 /* (dynamic) arrays which may be defined. */
41 /* In Glulx, we don't keep the global variables in dynamic_array_area. */
42 /* Array data starts at the start. */
44 /* We can also store arrays (but not globals) into static memory (ROM). */
45 /* The storage for these goes, unsurprisingly, into static_array_area. */
46 /* ------------------------------------------------------------------------- */
47 uchar *dynamic_array_area; /* See above */
48 memory_list dynamic_array_area_memlist;
49 int dynamic_array_area_size; /* Size in bytes */
51 int32 *global_initial_value; /* Allocated to no_globals */
52 static memory_list global_initial_value_memlist;
54 int no_globals; /* Number of global variables used
55 by the programmer (Inform itself
56 uses the top seven -- but these do
58 /* In Glulx, Inform uses the bottom
61 uchar *static_array_area;
62 memory_list static_array_area_memlist;
63 int static_array_area_size;
67 static memory_list arrays_memlist;
69 static int array_entry_size, /* 1 for byte array, 2 for word array */
70 array_base; /* Offset in dynamic array area of the
71 array being constructed. During the
72 same time, dynamic_array_area_size
73 is the offset of the initial entry
74 in the array: so for "table" and
75 "string" arrays, these numbers are
76 different (by 2 and 1 bytes resp) */
78 /* In Glulx, of course, that will be
81 static memory_list current_array_name; /* The name of the global or array
82 currently being compiled. */
84 /* Complete the array. Fill in the size field (if it has one) and
85 advance foo_array_area_size.
87 extern void finish_array(int32 i, int is_static)
93 ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size+array_base+1*array_entry_size);
94 area = dynamic_array_area;
95 area_size = dynamic_array_area_size;
98 ensure_memory_list_available(&static_array_area_memlist, static_array_area_size+array_base+1*array_entry_size);
99 area = static_array_area;
100 area_size = static_array_area_size;
104 error("An array must have at least one entry");
107 /* Write the array size into the 0th byte/word of the array, if it's
108 a "table" or "string" array */
111 if (array_base != area_size)
112 { if (area_size-array_base==2)
113 { area[array_base] = i/256;
114 area[array_base+1] = i%256;
118 error("A 'string' array can have at most 256 entries");
119 area[array_base] = i;
125 if (array_base != area_size)
126 { if (area_size-array_base==4)
128 area[array_base] = (i >> 24) & 0xFF;
129 area[array_base+1] = (i >> 16) & 0xFF;
130 area[array_base+2] = (i >> 8) & 0xFF;
131 area[array_base+3] = (i) & 0xFF;
135 error("A 'string' array can have at most 256 entries");
136 area[array_base] = i;
142 /* Move on the static/dynamic array size so that it now points to the
143 next available free space */
146 dynamic_array_area_size += i*array_entry_size;
149 static_array_area_size += i*array_entry_size;
154 /* Fill in array entry i (in either the static or dynamic area).
155 When this is called, foo_array_area_size is the end of the previous
156 array; we're writing after that.
158 extern void array_entry(int32 i, int is_static, assembly_operand VAL)
164 ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size+(i+1)*array_entry_size);
165 area = dynamic_array_area;
166 area_size = dynamic_array_area_size;
169 ensure_memory_list_available(&static_array_area_memlist, static_array_area_size+(i+1)*array_entry_size);
170 area = static_array_area;
171 area_size = static_array_area_size;
175 /* Array entry i (initial entry has i=0) is set to Z-machine value j */
177 if (array_entry_size==1)
178 { area[area_size+i] = (VAL.value)%256;
181 error("Entries in byte arrays and strings must be known constants");
183 /* If the entry is too large for a byte array, issue a warning
184 and truncate the value */
186 if (VAL.value >= 256)
187 warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
191 int32 addr = area_size + 2*i;
192 area[addr] = (VAL.value)/256;
193 area[addr+1] = (VAL.value)%256;
194 if (VAL.marker != 0) {
196 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
200 backpatch_zmachine(VAL.marker, STATIC_ARRAY_ZA,
207 /* Array entry i (initial entry has i=0) is set to value j */
209 if (array_entry_size==1)
210 { area[area_size+i] = (VAL.value) & 0xFF;
213 error("Entries in byte arrays and strings must be known constants");
215 /* If the entry is too large for a byte array, issue a warning
216 and truncate the value */
218 if (VAL.value >= 256)
219 warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
221 else if (array_entry_size==4)
223 int32 addr = area_size + 4*i;
224 area[addr] = (VAL.value >> 24) & 0xFF;
225 area[addr+1] = (VAL.value >> 16) & 0xFF;
226 area[addr+2] = (VAL.value >> 8) & 0xFF;
227 area[addr+3] = (VAL.value) & 0xFF;
228 if (VAL.marker != 0) {
230 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
234 /* We can't use backpatch_zmachine() because that only applies to RAM. Instead we add an entry to staticarray_backpatch_table.
235 A backpatch entry is five bytes: *_MV followed by the array offset (in static array area). */
236 if (bpatch_trace_setting >= 2)
237 printf("BP added: MV %d staticarray %04x\n", VAL.marker, addr);
238 ensure_memory_list_available(&staticarray_backpatch_table_memlist, staticarray_backpatch_size+5);
239 staticarray_backpatch_table[staticarray_backpatch_size++] = VAL.marker;
240 staticarray_backpatch_table[staticarray_backpatch_size++] = ((addr >> 24) & 0xFF);
241 staticarray_backpatch_table[staticarray_backpatch_size++] = ((addr >> 16) & 0xFF);
242 staticarray_backpatch_table[staticarray_backpatch_size++] = ((addr >> 8) & 0xFF);
243 staticarray_backpatch_table[staticarray_backpatch_size++] = (addr & 0xFF);
249 error("Somehow created an array of shorts");
254 /* ------------------------------------------------------------------------- */
255 /* Global and Array directives. */
257 /* Global <variablename> [ [=] <value> ] */
259 /* Array <arrayname> [static] <array specification> */
261 /* where an array specification is: */
263 /* | -> | <number-of-entries> */
264 /* | --> | <entry-1> ... <entry-n> */
265 /* | string | [ <entry-1> [;] <entry-2> ... <entry-n> ]; */
269 /* The "static" keyword (arrays only) places the array in static memory. */
271 /* ------------------------------------------------------------------------- */
273 extern void set_variable_value(int i, int32 v)
275 /* This isn't currently called to create a new global, but it has
276 been used that way within living memory. So we call ensure. */
277 ensure_memory_list_available(&global_initial_value_memlist, i+1);
278 global_initial_value[i]=v;
281 /* There are four ways to initialise arrays: */
283 #define UNSPECIFIED_AI -1
289 extern void make_global()
297 debug_location_beginning beginning_debug_location =
298 get_token_location_beginning();
300 directive_keywords.enabled = FALSE;
305 name_length = strlen(token_text) + 1;
306 ensure_memory_list_available(¤t_array_name, name_length);
307 strncpy(current_array_name.data, token_text, name_length);
310 if ((token_type==SYMBOL_TT) && (symbols[i].type==GLOBAL_VARIABLE_T)
311 && (symbols[i].value >= LOWEST_SYSTEM_VAR_NUMBER)) {
312 globalnum = symbols[i].value - MAX_LOCAL_VARIABLES;
313 goto RedefinitionOfSystemVar;
317 if ((token_type==SYMBOL_TT) && (symbols[i].type==GLOBAL_VARIABLE_T)) {
318 globalnum = symbols[i].value - MAX_LOCAL_VARIABLES;
319 goto RedefinitionOfSystemVar;
323 if (token_type != SYMBOL_TT)
324 { discard_token_location(beginning_debug_location);
325 ebf_error("new global variable name", token_text);
326 panic_mode_error_recovery(); return;
329 if (!(symbols[i].flags & UNKNOWN_SFLAG))
330 { discard_token_location(beginning_debug_location);
331 ebf_symbol_error("new global variable name", token_text, typename(symbols[i].type), symbols[i].line);
332 panic_mode_error_recovery(); return;
335 if (symbols[i].flags & USED_SFLAG)
336 error_named("Variable must be defined before use:", token_text);
338 directive_keywords.enabled = TRUE;
340 directive_keywords.enabled = FALSE;
341 if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) {
342 error("Global variables cannot be static");
348 if (!glulx_mode && no_globals==233)
349 { discard_token_location(beginning_debug_location);
350 error("All 233 global variables already declared");
351 panic_mode_error_recovery();
355 globalnum = no_globals;
357 ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES+no_globals+1);
358 variables[MAX_LOCAL_VARIABLES+no_globals].token = i;
359 variables[MAX_LOCAL_VARIABLES+no_globals].usage = FALSE;
360 assign_symbol(i, MAX_LOCAL_VARIABLES+no_globals, GLOBAL_VARIABLE_T);
362 ensure_memory_list_available(&global_initial_value_memlist, no_globals+1);
363 global_initial_value[no_globals++]=0;
365 directive_keywords.enabled = TRUE;
367 RedefinitionOfSystemVar:
371 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
373 /* No initial value. */
375 if (debugfile_switch)
377 char *global_name = current_array_name.data;
378 debug_file_printf("<global-variable>");
379 debug_file_printf("<identifier>%s</identifier>", global_name);
380 debug_file_printf("<address>");
381 write_debug_global_backpatch(symbols[global_symbol].value);
382 debug_file_printf("</address>");
383 write_debug_locations
384 (get_token_location_end(beginning_debug_location));
385 debug_file_printf("</global-variable>");
390 if (((token_type==SEP_TT)&&(token_value==ARROW_SEP))
391 || ((token_type==SEP_TT)&&(token_value==DARROW_SEP))
392 || ((token_type==DIR_KEYWORD_TT)&&(token_value==STRING_DK))
393 || ((token_type==DIR_KEYWORD_TT)&&(token_value==TABLE_DK))
394 || ((token_type==DIR_KEYWORD_TT)&&(token_value==BUFFER_DK)))
396 error("use 'Array' to define arrays, not 'Global'");
400 /* Skip "=" if present. */
401 if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
404 AO = parse_expression(CONSTANT_CONTEXT);
407 backpatch_zmachine(AO.marker, DYNAMIC_ARRAY_ZA,
412 backpatch_zmachine(AO.marker, GLOBALVAR_ZA,
416 if (globalnum < 0 || globalnum >= global_initial_value_memlist.count)
417 compiler_error("Globalnum out of range");
418 global_initial_value[globalnum] = AO.value;
420 if (debugfile_switch)
422 char *global_name = current_array_name.data;
423 debug_file_printf("<global-variable>");
424 debug_file_printf("<identifier>%s</identifier>", global_name);
425 debug_file_printf("<address>");
426 write_debug_global_backpatch(symbols[global_symbol].value);
427 debug_file_printf("</address>");
428 write_debug_locations
429 (get_token_location_end(beginning_debug_location));
430 debug_file_printf("</global-variable>");
434 extern void make_array()
438 int array_type, data_type;
439 int is_static = FALSE;
445 debug_location_beginning beginning_debug_location =
446 get_token_location_beginning();
448 directive_keywords.enabled = FALSE;
453 name_length = strlen(token_text) + 1;
454 ensure_memory_list_available(¤t_array_name, name_length);
455 strncpy(current_array_name.data, token_text, name_length);
457 if (token_type != SYMBOL_TT)
458 { discard_token_location(beginning_debug_location);
459 ebf_error("new array name", token_text);
460 panic_mode_error_recovery(); return;
463 if (!(symbols[i].flags & UNKNOWN_SFLAG))
464 { discard_token_location(beginning_debug_location);
465 ebf_symbol_error("new array name", token_text, typename(symbols[i].type), symbols[i].line);
466 panic_mode_error_recovery(); return;
469 directive_keywords.enabled = TRUE;
471 directive_keywords.enabled = FALSE;
472 if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) {
480 assign_symbol(i, dynamic_array_area_size, ARRAY_T);
483 assign_symbol(i, static_array_area_size, STATIC_ARRAY_T);
485 ensure_memory_list_available(&arrays_memlist, no_arrays+1);
486 arrays[no_arrays].symbol = i;
488 directive_keywords.enabled = TRUE;
492 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
494 discard_token_location(beginning_debug_location);
495 ebf_error("array definition", token_text);
500 array_type = BYTE_ARRAY; data_type = UNSPECIFIED_AI;
502 /* The keywords "data", "initial", and "initstr" used to be accepted
503 here -- but only in a Global directive, not Array. The Global directive
504 no longer calls here, so those keywords are now (more) obsolete.
507 if ((token_type==SEP_TT)&&(token_value==ARROW_SEP))
508 array_type = BYTE_ARRAY;
509 else if ((token_type==SEP_TT)&&(token_value==DARROW_SEP))
510 array_type = WORD_ARRAY;
511 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==STRING_DK))
512 array_type = STRING_ARRAY;
513 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==TABLE_DK))
514 array_type = TABLE_ARRAY;
515 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==BUFFER_DK))
516 array_type = BUFFER_ARRAY;
518 { discard_token_location(beginning_debug_location);
520 ("'->', '-->', 'string', 'table' or 'buffer'", token_text);
521 panic_mode_error_recovery();
526 if ((array_type==WORD_ARRAY) || (array_type==TABLE_ARRAY))
527 array_entry_size=WORDSIZE;
530 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
531 { discard_token_location(beginning_debug_location);
532 error("No array size or initial values given");
538 { case UNSPECIFIED_AI:
539 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
540 data_type = BRACKET_AI;
542 { data_type = NULLS_AI;
543 if (token_type == DQ_TT) data_type = ASCII_AI;
545 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
551 case NULLS_AI: obsolete_warning("use '->' instead of 'data'"); break;
552 case DATA_AI: obsolete_warning("use '->' instead of 'initial'"); break;
553 case ASCII_AI: obsolete_warning("use '->' instead of 'initstr'"); break;
556 /* Leave room to write the array size in later, if string/table array */
559 if ((array_type==STRING_ARRAY) || (array_type==TABLE_ARRAY))
560 extraspace += array_entry_size;
561 if (array_type==BUFFER_ARRAY)
562 extraspace += WORDSIZE;
565 array_base = dynamic_array_area_size;
566 dynamic_array_area_size += extraspace;
569 array_base = static_array_area_size;
570 static_array_area_size += extraspace;
573 arrays[no_arrays].type = array_type;
574 arrays[no_arrays].loc = is_static;
576 /* Note that, from this point, we must continue through finish_array().
577 Exiting this routine on error causes problems. */
583 AO = parse_expression(CONSTANT_CONTEXT);
588 { error("Array sizes must be known now, not defined later");
593 if ((AO.value <= 0) || (AO.value >= 32768))
594 { error("An array must have between 1 and 32767 entries");
599 if (AO.value <= 0 || (AO.value & 0x80000000))
600 { error("An array may not have 0 or fewer entries");
605 { for (i=0; i<AO.value; i++) array_entry(i, is_static, zero_operand);
611 /* In this case the array is initialised to the sequence of
612 constant values supplied on the same line */
617 /* This isn't the start of a statement, but it's safe to
618 release token texts anyway. Expressions in an array
619 list are independent of each other. */
620 release_token_texts();
622 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
625 if ((token_type == SEP_TT)
626 && ((token_value == OPEN_SQUARE_SEP)
627 || (token_value == CLOSE_SQUARE_SEP)))
628 { discard_token_location(beginning_debug_location);
629 error("Missing ';' to end the initial array values "
630 "before \"[\" or \"]\"");
634 AO = parse_expression(ARRAY_CONTEXT);
639 if ((token_type == SEP_TT)
640 && (token_value == SEMICOLON_SEP))
641 { data_type = NULLS_AI;
642 goto CalculatedArraySize;
646 array_entry(i, is_static, AO);
654 /* In this case the array is initialised to the ASCII values of
655 the characters of a given "quoted string" */
658 if (token_type != DQ_TT)
659 { ebf_error("literal text in double-quotes", token_text);
660 token_text = "error";
663 { assembly_operand chars;
667 for (i=0,j=0; token_text[j]!=0; i++,j+=textual_form_length)
669 int32 unicode; int zscii;
670 unicode = text_to_unicode(token_text+j);
673 if (array_entry_size == 1 && (unicode < 0 || unicode >= 256))
675 error("Unicode characters beyond Latin-1 cannot be used in a byte array");
679 chars.value = unicode;
684 zscii = unicode_to_zscii(unicode);
685 if ((zscii != 5) && (zscii < 0x100)) chars.value = zscii;
687 { unicode_char_error("Character can only be used if declared in \
688 advance as part of 'Zcharacter table':", unicode);
693 set_constant_ot(&chars);
694 array_entry(i, is_static, chars);
701 /* In this case the array is initialised to the sequence of
702 constant values given over a whole range of compiler-lines,
703 between square brackets [ and ] */
708 /* This isn't the start of a statement, but it's safe to
709 release token texts anyway. Expressions in an array
710 list are independent of each other. */
711 release_token_texts();
713 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
715 if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP))
717 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
718 { /* Minimal error recovery: we assume that a ] has
719 been missed, and the programmer is now starting
722 ebf_error("']'", token_text);
723 put_token_back(); break;
726 array_entry(i, is_static, parse_expression(ARRAY_CONTEXT));
731 finish_array(i, is_static);
733 if (debugfile_switch)
736 char *global_name = current_array_name.data;
737 debug_file_printf("<array>");
738 debug_file_printf("<identifier>%s</identifier>", global_name);
739 debug_file_printf("<value>");
740 write_debug_array_backpatch(symbols[global_symbol].value);
741 debug_file_printf("</value>");
742 new_area_size = (!is_static ? dynamic_array_area_size : static_array_area_size);
744 ("<byte-count>%d</byte-count>",
745 new_area_size - array_base);
747 ("<bytes-per-element>%d</bytes-per-element>",
750 ("<zeroth-element-holds-length>%s</zeroth-element-holds-length>",
751 (array_type == STRING_ARRAY || array_type == TABLE_ARRAY) ?
754 write_debug_locations(get_token_location_end(beginning_debug_location));
756 debug_file_printf("</array>");
759 if ((array_type==BYTE_ARRAY) || (array_type==WORD_ARRAY)) i--;
760 if (array_type==BUFFER_ARRAY) i+=WORDSIZE-1;
761 arrays[no_arrays++].size = i;
764 extern int32 begin_table_array(void)
766 /* The "box" statement needs to be able to construct table
767 arrays of strings like this. (Static data, but we create a dynamic
768 array for maximum backwards compatibility.) */
770 array_base = dynamic_array_area_size;
771 array_entry_size = WORDSIZE;
773 /* Leave room to write the array size in later */
775 dynamic_array_area_size += array_entry_size;
780 extern int32 begin_word_array(void)
782 /* The "random(a, b, ...)" function needs to be able to construct
783 word arrays like this. (Static data, but we create a dynamic
784 array for maximum backwards compatibility.) */
786 array_base = dynamic_array_area_size;
787 array_entry_size = WORDSIZE;
792 /* ========================================================================= */
793 /* Data structure management routines */
794 /* ------------------------------------------------------------------------- */
796 extern void init_arrays_vars(void)
797 { dynamic_array_area = NULL;
798 static_array_area = NULL;
800 global_initial_value = NULL;
804 extern void arrays_begin_pass(void)
811 /* The compiler-defined globals start at 239 and go down, so
812 we need to initialize the entire list from the start. */
813 totalvar = MAX_ZCODE_GLOBAL_VARS;
816 /* The compiler-defined globals run from 0 to 10. */
818 totalvar = no_globals;
821 ensure_memory_list_available(&global_initial_value_memlist, totalvar);
822 for (ix=0; ix<totalvar; ix++) {
823 global_initial_value[ix] = 0;
826 ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES+totalvar);
827 for (ix=0; ix<MAX_LOCAL_VARIABLES+totalvar; ix++) {
828 variables[ix].token = 0;
829 variables[ix].usage = FALSE;
832 dynamic_array_area_size = 0;
836 /* This initial segment of dynamic_array_area is never used. It's
837 notionally space for the global variables, but that data is
838 kept in the global_initial_value array. Nonetheless, all the
839 Z-compiler math is set up with the idea that arrays start at
840 WORDSIZE * MAX_ZCODE_GLOBAL_VARS, so we need the blank segment.
842 dynamic_array_area_size = WORDSIZE * MAX_ZCODE_GLOBAL_VARS;
843 ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size);
844 for (ix=0; ix<WORDSIZE * MAX_ZCODE_GLOBAL_VARS; ix++)
845 dynamic_array_area[ix] = 0;
848 static_array_area_size = 0;
851 extern void arrays_allocate_arrays(void)
853 initialise_memory_list(&dynamic_array_area_memlist,
854 sizeof(uchar), 10000, (void**)&dynamic_array_area,
855 "dynamic array data");
856 initialise_memory_list(&static_array_area_memlist,
857 sizeof(uchar), 0, (void**)&static_array_area,
858 "static array data");
859 initialise_memory_list(&arrays_memlist,
860 sizeof(arrayinfo), 64, (void**)&arrays,
862 initialise_memory_list(&global_initial_value_memlist,
863 sizeof(int32), 200, (void**)&global_initial_value,
864 "global variable values");
866 initialise_memory_list(¤t_array_name,
867 sizeof(char), MAX_IDENTIFIER_LENGTH+1, NULL,
868 "array name currently being defined");
871 extern void arrays_free_arrays(void)
873 deallocate_memory_list(&dynamic_array_area_memlist);
874 deallocate_memory_list(&static_array_area_memlist);
875 deallocate_memory_list(&arrays_memlist);
876 deallocate_memory_list(&global_initial_value_memlist);
877 deallocate_memory_list(¤t_array_name);
880 /* ========================================================================= */