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.35 */
7 /* copyright (c) Graham Nelson 1993 - 2021 */
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 /* int dynamic_array_area[] Initial values for the bytes of */
30 /* the dynamic array area */
31 /* int 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) */
36 /* The "dynamic array area" is the Z-machine area holding the current */
37 /* values of the global variables (in 240x2 = 480 bytes) followed by any */
38 /* (dynamic) arrays which may be defined. Owing to a poor choice of name */
39 /* some years ago, this is also called the "static data area", which is */
40 /* why the memory setting for its maximum extent is "MAX_STATIC_DATA". */
42 /* In Glulx, that 240 is changed to MAX_GLOBAL_VAR_NUMBER, and we take */
43 /* correspondingly more space for the globals. This *really* ought to be */
44 /* split into two segments. */
46 /* We can also store arrays (but not globals) into static memory (ROM). */
47 /* The storage for these goes, unsurprisingly, into static_array_area -- */
48 /* a separate allocation of MAX_STATIC_DATA bytes. */
49 /* ------------------------------------------------------------------------- */
50 int *dynamic_array_area; /* See above */
51 int32 *global_initial_value;
53 int no_globals; /* Number of global variables used
54 by the programmer (Inform itself
55 uses the top seven -- but these do
57 /* In Glulx, Inform uses the bottom
60 int dynamic_array_area_size; /* Size in bytes */
62 int *static_array_area;
63 int static_array_area_size;
67 int *array_sizes, *array_types, *array_locs;
68 /* array_sizes[N] gives the length of array N; array_types[N] is one of
69 the constants BYTE_ARRAY, WORD_ARRAY, etc; array_locs[N] is true for
70 static arrays, false for dynamic arrays. */
72 static int array_entry_size, /* 1 for byte array, 2 for word array */
73 array_base; /* Offset in dynamic array area of the
74 array being constructed. During the
75 same time, dynamic_array_area_size
76 is the offset of the initial entry
77 in the array: so for "table" and
78 "string" arrays, these numbers are
79 different (by 2 and 1 bytes resp) */
81 /* In Glulx, of course, that will be
84 extern void finish_array(int32 i, int is_static)
90 area = dynamic_array_area;
91 area_size = dynamic_array_area_size;
94 area = static_array_area;
95 area_size = static_array_area_size;
99 error("An array must have at least one entry");
102 /* Write the array size into the 0th byte/word of the array, if it's
103 a "table" or "string" array */
106 if (array_base != area_size)
107 { if (area_size-array_base==2)
108 { area[array_base] = i/256;
109 area[array_base+1] = i%256;
113 error("A 'string' array can have at most 256 entries");
114 area[array_base] = i;
120 if (array_base != area_size)
121 { if (area_size-array_base==4)
123 area[array_base] = (i >> 24) & 0xFF;
124 area[array_base+1] = (i >> 16) & 0xFF;
125 area[array_base+2] = (i >> 8) & 0xFF;
126 area[array_base+3] = (i) & 0xFF;
130 error("A 'string' array can have at most 256 entries");
131 area[array_base] = i;
137 /* Move on the static/dynamic array size so that it now points to the
138 next available free space */
141 dynamic_array_area_size += i*array_entry_size;
144 static_array_area_size += i*array_entry_size;
149 extern void array_entry(int32 i, int is_static, assembly_operand VAL)
155 area = dynamic_array_area;
156 area_size = dynamic_array_area_size;
159 area = static_array_area;
160 area_size = static_array_area_size;
164 /* Array entry i (initial entry has i=0) is set to Z-machine value j */
166 if (area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
167 memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
169 if (array_entry_size==1)
170 { area[area_size+i] = (VAL.value)%256;
173 error("Entries in byte arrays and strings must be known constants");
175 /* If the entry is too large for a byte array, issue a warning
176 and truncate the value */
178 if (VAL.value >= 256)
179 warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
183 int32 addr = area_size + 2*i;
184 area[addr] = (VAL.value)/256;
185 area[addr+1] = (VAL.value)%256;
186 if (VAL.marker != 0) {
188 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
192 backpatch_zmachine(VAL.marker, STATIC_ARRAY_ZA,
199 /* Array entry i (initial entry has i=0) is set to value j */
201 if (area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
202 memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
204 if (array_entry_size==1)
205 { area[area_size+i] = (VAL.value) & 0xFF;
208 error("Entries in byte arrays and strings must be known constants");
210 /* If the entry is too large for a byte array, issue a warning
211 and truncate the value */
213 if (VAL.value >= 256)
214 warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
216 else if (array_entry_size==4)
218 int32 addr = area_size + 4*i;
219 area[addr] = (VAL.value >> 24) & 0xFF;
220 area[addr+1] = (VAL.value >> 16) & 0xFF;
221 area[addr+2] = (VAL.value >> 8) & 0xFF;
222 area[addr+3] = (VAL.value) & 0xFF;
223 if (VAL.marker != 0) {
225 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
226 addr - 4*MAX_GLOBAL_VARIABLES);
229 /* We can't use backpatch_zmachine() because that only applies to RAM. Instead we add an entry to staticarray_backpatch_table.
230 A backpatch entry is five bytes: *_MV followed by the array offset (in static array area). */
231 write_byte_to_memory_block(&staticarray_backpatch_table,
232 staticarray_backpatch_size++,
234 write_byte_to_memory_block(&staticarray_backpatch_table,
235 staticarray_backpatch_size++, ((addr >> 24) & 0xFF));
236 write_byte_to_memory_block(&staticarray_backpatch_table,
237 staticarray_backpatch_size++, ((addr >> 16) & 0xFF));
238 write_byte_to_memory_block(&staticarray_backpatch_table,
239 staticarray_backpatch_size++, ((addr >> 8) & 0xFF));
240 write_byte_to_memory_block(&staticarray_backpatch_table,
241 staticarray_backpatch_size++, (addr & 0xFF));
247 error("Somehow created an array of shorts");
252 /* ------------------------------------------------------------------------- */
253 /* Global and Array directives. */
255 /* Global <variablename> | */
257 /* | <array specification> */
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)
274 { global_initial_value[i]=v;
277 /* There are four ways to initialise arrays: */
279 #define UNSPECIFIED_AI -1
285 extern void make_global(int array_flag, int name_only)
287 /* array_flag is TRUE for an Array directive, FALSE for a Global;
288 name_only is only TRUE for parsing an imported variable name, so
289 array_flag is always FALSE in that case. */
292 int array_type, data_type;
293 int is_static = FALSE;
300 const char *global_name;
301 debug_location_beginning beginning_debug_location =
302 get_token_location_beginning();
304 directive_keywords.enabled = FALSE;
308 global_name = token_text;
311 if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T)
312 && (svals[i] >= LOWEST_SYSTEM_VAR_NUMBER))
313 goto RedefinitionOfSystemVar;
316 if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T))
317 goto RedefinitionOfSystemVar;
320 if (token_type != SYMBOL_TT)
321 { discard_token_location(beginning_debug_location);
323 ebf_error("new array name", token_text);
324 else ebf_error("new global variable name", token_text);
325 panic_mode_error_recovery(); return;
328 if (!(sflags[i] & UNKNOWN_SFLAG))
329 { discard_token_location(beginning_debug_location);
331 ebf_symbol_error("new array name", token_text, typename(stypes[i]), slines[i]);
332 else ebf_symbol_error("new global variable name", token_text, typename(stypes[i]), slines[i]);
333 panic_mode_error_recovery(); return;
336 if ((!array_flag) && (sflags[i] & USED_SFLAG))
337 error_named("Variable must be defined before use:", token_text);
339 directive_keywords.enabled = TRUE;
341 directive_keywords.enabled = FALSE;
342 if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) {
347 error("Global variables cannot be static");
357 assign_symbol(i, dynamic_array_area_size, ARRAY_T);
360 dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES, ARRAY_T);
363 assign_symbol(i, static_array_area_size, STATIC_ARRAY_T);
365 if (no_arrays == MAX_ARRAYS)
366 memoryerror("MAX_ARRAYS", MAX_ARRAYS);
367 array_symbols[no_arrays] = i;
370 { if (!glulx_mode && no_globals==233)
371 { discard_token_location(beginning_debug_location);
372 error("All 233 global variables already declared");
373 panic_mode_error_recovery();
376 if (glulx_mode && no_globals==MAX_GLOBAL_VARIABLES)
377 { discard_token_location(beginning_debug_location);
378 memoryerror("MAX_GLOBAL_VARIABLES", MAX_GLOBAL_VARIABLES);
379 panic_mode_error_recovery();
383 variable_tokens[MAX_LOCAL_VARIABLES+no_globals] = i;
384 assign_symbol(i, MAX_LOCAL_VARIABLES+no_globals, GLOBAL_VARIABLE_T);
385 variable_tokens[svals[i]] = i;
387 if (name_only) import_symbol(i);
388 else global_initial_value[no_globals++]=0;
391 directive_keywords.enabled = TRUE;
393 RedefinitionOfSystemVar:
396 { discard_token_location(beginning_debug_location);
402 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
404 { discard_token_location(beginning_debug_location);
405 ebf_error("array definition", token_text);
408 if (debugfile_switch && !array_flag)
409 { debug_file_printf("<global-variable>");
410 debug_file_printf("<identifier>%s</identifier>", global_name);
411 debug_file_printf("<address>");
412 write_debug_global_backpatch(svals[global_symbol]);
413 debug_file_printf("</address>");
414 write_debug_locations
415 (get_token_location_end(beginning_debug_location));
416 debug_file_printf("</global-variable>");
423 /* is_static is always false in this case */
424 if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
425 { AO = parse_expression(CONSTANT_CONTEXT);
428 backpatch_zmachine(AO.marker, DYNAMIC_ARRAY_ZA,
433 backpatch_zmachine(AO.marker, GLOBALVAR_ZA,
436 global_initial_value[no_globals-1] = AO.value;
437 if (debugfile_switch)
438 { debug_file_printf("<global-variable>");
439 debug_file_printf("<identifier>%s</identifier>", global_name);
440 debug_file_printf("<address>");
441 write_debug_global_backpatch(svals[global_symbol]);
442 debug_file_printf("</address>");
443 write_debug_locations
444 (get_token_location_end(beginning_debug_location));
445 debug_file_printf("</global-variable>");
450 obsolete_warning("more modern to use 'Array', not 'Global'");
453 backpatch_zmachine(ARRAY_MV, DYNAMIC_ARRAY_ZA, 2*(no_globals-1));
454 global_initial_value[no_globals-1]
455 = dynamic_array_area_size+variables_offset;
458 backpatch_zmachine(ARRAY_MV, GLOBALVAR_ZA, 4*(no_globals-1));
459 global_initial_value[no_globals-1]
460 = dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES;
464 array_type = BYTE_ARRAY; data_type = UNSPECIFIED_AI;
467 ((token_type==DIR_KEYWORD_TT)&&(token_value==DATA_DK)))
469 else if ((!array_flag) &&
470 ((token_type==DIR_KEYWORD_TT)&&(token_value==INITIAL_DK)))
472 else if ((!array_flag) &&
473 ((token_type==DIR_KEYWORD_TT)&&(token_value==INITSTR_DK)))
476 else if ((token_type==SEP_TT)&&(token_value==ARROW_SEP))
477 array_type = BYTE_ARRAY;
478 else if ((token_type==SEP_TT)&&(token_value==DARROW_SEP))
479 array_type = WORD_ARRAY;
480 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==STRING_DK))
481 array_type = STRING_ARRAY;
482 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==TABLE_DK))
483 array_type = TABLE_ARRAY;
484 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==BUFFER_DK))
485 array_type = BUFFER_ARRAY;
487 { discard_token_location(beginning_debug_location);
490 ("'->', '-->', 'string', 'table' or 'buffer'", token_text);
493 ("'=', '->', '-->', 'string', 'table' or 'buffer'", token_text);
494 panic_mode_error_recovery();
499 if ((array_type==WORD_ARRAY) || (array_type==TABLE_ARRAY))
500 array_entry_size=WORDSIZE;
503 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
504 { discard_token_location(beginning_debug_location);
505 error("No array size or initial values given");
511 { case UNSPECIFIED_AI:
512 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
513 data_type = BRACKET_AI;
515 { data_type = NULLS_AI;
516 if (token_type == DQ_TT) data_type = ASCII_AI;
518 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
524 case NULLS_AI: obsolete_warning("use '->' instead of 'data'"); break;
525 case DATA_AI: obsolete_warning("use '->' instead of 'initial'"); break;
526 case ASCII_AI: obsolete_warning("use '->' instead of 'initstr'"); break;
529 /* Leave room to write the array size in later, if string/table array */
532 if ((array_type==STRING_ARRAY) || (array_type==TABLE_ARRAY))
533 extraspace += array_entry_size;
534 if (array_type==BUFFER_ARRAY)
535 extraspace += WORDSIZE;
538 orig_area_size = dynamic_array_area_size;
539 array_base = dynamic_array_area_size;
540 dynamic_array_area_size += extraspace;
543 orig_area_size = static_array_area_size;
544 array_base = static_array_area_size;
545 static_array_area_size += extraspace;
548 array_types[no_arrays] = array_type;
549 array_locs[no_arrays] = is_static;
555 AO = parse_expression(CONSTANT_CONTEXT);
560 { error("Array sizes must be known now, not defined later");
565 if ((AO.value <= 0) || (AO.value >= 32768))
566 { error("An array must have between 1 and 32767 entries");
571 if (AO.value <= 0 || (AO.value & 0x80000000))
572 { error("An array may not have 0 or fewer entries");
577 { for (i=0; i<AO.value; i++) array_entry(i, is_static, zero_operand);
583 /* In this case the array is initialised to the sequence of
584 constant values supplied on the same line */
589 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
592 if ((token_type == SEP_TT)
593 && ((token_value == OPEN_SQUARE_SEP)
594 || (token_value == CLOSE_SQUARE_SEP)))
595 { discard_token_location(beginning_debug_location);
596 error("Missing ';' to end the initial array values "
597 "before \"[\" or \"]\"");
602 AO = parse_expression(ARRAY_CONTEXT);
607 if ((token_type == SEP_TT)
608 && (token_value == SEMICOLON_SEP))
609 { data_type = NULLS_AI;
610 goto CalculatedArraySize;
614 array_entry(i, is_static, AO);
622 /* In this case the array is initialised to the ASCII values of
623 the characters of a given "quoted string" */
626 if (token_type != DQ_TT)
627 { ebf_error("literal text in double-quotes", token_text);
628 token_text = "error";
631 { assembly_operand chars;
635 for (i=0,j=0; token_text[j]!=0; i++,j+=textual_form_length)
637 int32 unicode; int zscii;
638 unicode = text_to_unicode(token_text+j);
641 if (array_entry_size == 1 && (unicode < 0 || unicode >= 256))
643 error("Unicode characters beyond Latin-1 cannot be used in a byte array");
647 chars.value = unicode;
652 zscii = unicode_to_zscii(unicode);
653 if ((zscii != 5) && (zscii < 0x100)) chars.value = zscii;
655 { unicode_char_error("Character can only be used if declared in \
656 advance as part of 'Zcharacter table':", unicode);
661 set_constant_ot(&chars);
662 array_entry(i, is_static, chars);
669 /* In this case the array is initialised to the sequence of
670 constant values given over a whole range of compiler-lines,
671 between square brackets [ and ] */
676 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
678 if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP))
680 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
681 { /* Minimal error recovery: we assume that a ] has
682 been missed, and the programmer is now starting
685 ebf_error("']'", token_text);
686 put_token_back(); break;
689 array_entry(i, is_static, parse_expression(ARRAY_CONTEXT));
694 finish_array(i, is_static);
696 if (debugfile_switch)
699 debug_file_printf("<array>");
700 debug_file_printf("<identifier>%s</identifier>", global_name);
701 debug_file_printf("<value>");
702 write_debug_array_backpatch(svals[global_symbol]);
703 debug_file_printf("</value>");
704 new_area_size = (!is_static ? dynamic_array_area_size : static_array_area_size);
706 ("<byte-count>%d</byte-count>",
707 new_area_size - array_base);
709 ("<bytes-per-element>%d</bytes-per-element>",
712 ("<zeroth-element-holds-length>%s</zeroth-element-holds-length>",
713 (array_type == STRING_ARRAY || array_type == TABLE_ARRAY) ?
716 write_debug_locations(get_token_location_end(beginning_debug_location));
718 debug_file_printf("</array>");
721 if ((array_type==BYTE_ARRAY) || (array_type==WORD_ARRAY)) i--;
722 if (array_type==BUFFER_ARRAY) i+=WORDSIZE-1;
723 array_sizes[no_arrays++] = i;
726 extern int32 begin_table_array(void)
728 /* The "box" statement needs to be able to construct table
729 arrays of strings like this. (Static data, but we create a dynamic
730 array for maximum backwards compatibility.) */
732 array_base = dynamic_array_area_size;
733 array_entry_size = WORDSIZE;
735 /* Leave room to write the array size in later */
737 dynamic_array_area_size += array_entry_size;
742 return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
745 extern int32 begin_word_array(void)
747 /* The "random(a, b, ...)" function needs to be able to construct
748 word arrays like this. (Static data, but we create a dynamic
749 array for maximum backwards compatibility.) */
751 array_base = dynamic_array_area_size;
752 array_entry_size = WORDSIZE;
757 return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
760 /* ========================================================================= */
761 /* Data structure management routines */
762 /* ------------------------------------------------------------------------- */
764 extern void init_arrays_vars(void)
765 { dynamic_array_area = NULL;
766 static_array_area = NULL;
767 global_initial_value = NULL;
768 array_sizes = NULL; array_symbols = NULL; array_types = NULL;
771 extern void arrays_begin_pass(void)
777 dynamic_array_area_size = WORDSIZE * MAX_GLOBAL_VARIABLES;
778 static_array_area_size = 0;
781 extern void arrays_allocate_arrays(void)
782 { dynamic_array_area = my_calloc(sizeof(int), MAX_STATIC_DATA,
783 "dynamic array data");
784 static_array_area = my_calloc(sizeof(int), MAX_STATIC_DATA,
785 "static array data");
786 array_sizes = my_calloc(sizeof(int), MAX_ARRAYS, "array sizes");
787 array_types = my_calloc(sizeof(int), MAX_ARRAYS, "array types");
788 array_locs = my_calloc(sizeof(int), MAX_ARRAYS, "array locations");
789 array_symbols = my_calloc(sizeof(int32), MAX_ARRAYS, "array symbols");
790 global_initial_value = my_calloc(sizeof(int32), MAX_GLOBAL_VARIABLES,
794 extern void arrays_free_arrays(void)
795 { my_free(&dynamic_array_area, "dynamic array data");
796 my_free(&static_array_area, "static array data");
797 my_free(&global_initial_value, "global values");
798 my_free(&array_sizes, "array sizes");
799 my_free(&array_types, "array types");
800 my_free(&array_locs, "array locations");
801 my_free(&array_symbols, "array sizes");
804 /* ========================================================================= */