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 /* Copyright (c) Graham Nelson 1993 - 2018 */
8 /* This file is part of Inform. */
10 /* Inform is free software: you can redistribute it and/or modify */
11 /* it under the terms of the GNU General Public License as published by */
12 /* the Free Software Foundation, either version 3 of the License, or */
13 /* (at your option) any later version. */
15 /* Inform is distributed in the hope that it will be useful, */
16 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
17 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
18 /* GNU General Public License for more details. */
20 /* You should have received a copy of the GNU General Public License */
21 /* along with Inform. If not, see https://gnu.org/licenses/ */
23 /* ------------------------------------------------------------------------- */
27 /* ------------------------------------------------------------------------- */
28 /* Arrays defined below: */
30 /* int dynamic_array_area[] Initial values for the bytes of */
31 /* the dynamic array area */
32 /* int32 global_initial_value[n] The initialised value of the nth */
33 /* global variable (counting 0 - 239) */
35 /* The "dynamic array area" is the Z-machine area holding the current */
36 /* values of the global variables (in 240x2 = 480 bytes) followed by any */
37 /* (dynamic) arrays which may be defined. Owing to a poor choice of name */
38 /* some years ago, this is also called the "static data area", which is */
39 /* why the memory setting for its maximum extent is "MAX_STATIC_DATA". */
41 /* In Glulx, that 240 is changed to MAX_GLOBAL_VAR_NUMBER, and we take */
42 /* correspondingly more space for the globals. This *really* ought to be */
43 /* split into two segments. */
44 /* ------------------------------------------------------------------------- */
45 int *dynamic_array_area; /* See above */
46 int32 *global_initial_value;
48 int no_globals; /* Number of global variables used
49 by the programmer (Inform itself
50 uses the top seven -- but these do
52 /* In Glulx, Inform uses the bottom
55 int dynamic_array_area_size; /* Size in bytes */
59 int *array_sizes, *array_types;
61 static int array_entry_size, /* 1 for byte array, 2 for word array */
62 array_base; /* Offset in dynamic array area of the
63 array being constructed. During the
64 same time, dynamic_array_area_size
65 is the offset of the initial entry
66 in the array: so for "table" and
67 "string" arrays, these numbers are
68 different (by 2 and 1 bytes resp) */
70 /* In Glulx, of course, that will be
73 extern void finish_array(int32 i)
75 /* Write the array size into the 0th byte/word of the array, if it's
76 a "table" or "string" array */
79 if (array_base!=dynamic_array_area_size)
80 { if (dynamic_array_area_size-array_base==2)
81 { dynamic_array_area[array_base] = i/256;
82 dynamic_array_area[array_base+1] = i%256;
86 error("A 'string' array can have at most 256 entries");
87 dynamic_array_area[array_base] = i;
93 if (array_base!=dynamic_array_area_size)
94 { if (dynamic_array_area_size-array_base==4)
96 dynamic_array_area[array_base] = (i >> 24) & 0xFF;
97 dynamic_array_area[array_base+1] = (i >> 16) & 0xFF;
98 dynamic_array_area[array_base+2] = (i >> 8) & 0xFF;
99 dynamic_array_area[array_base+3] = (i) & 0xFF;
103 error("A 'string' array can have at most 256 entries");
104 dynamic_array_area[array_base] = i;
110 /* Move on the dynamic array size so that it now points to the next
111 available free space */
113 dynamic_array_area_size += i*array_entry_size;
117 extern void array_entry(int32 i, assembly_operand VAL)
120 /* Array entry i (initial entry has i=0) is set to Z-machine value j */
122 if (dynamic_array_area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
123 memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
125 if (array_entry_size==1)
126 { dynamic_array_area[dynamic_array_area_size+i] = (VAL.value)%256;
129 error("Entries in byte arrays and strings must be known constants");
131 /* If the entry is too large for a byte array, issue a warning
132 and truncate the value */
134 if (VAL.value >= 256)
135 warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
138 { dynamic_array_area[dynamic_array_area_size + 2*i] = (VAL.value)/256;
139 dynamic_array_area[dynamic_array_area_size + 2*i+1] = (VAL.value)%256;
141 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
142 dynamic_array_area_size + 2*i);
146 /* Array entry i (initial entry has i=0) is set to value j */
148 if (dynamic_array_area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
149 memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
151 if (array_entry_size==1)
152 { dynamic_array_area[dynamic_array_area_size+i] = (VAL.value) & 0xFF;
155 error("Entries in byte arrays and strings must be known constants");
157 /* If the entry is too large for a byte array, issue a warning
158 and truncate the value */
160 if (VAL.value >= 256)
161 warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
163 else if (array_entry_size==4)
164 { dynamic_array_area[dynamic_array_area_size + 4*i] = (VAL.value >> 24) & 0xFF;
165 dynamic_array_area[dynamic_array_area_size + 4*i+1] = (VAL.value >> 16) & 0xFF;
166 dynamic_array_area[dynamic_array_area_size + 4*i+2] = (VAL.value >> 8) & 0xFF;
167 dynamic_array_area[dynamic_array_area_size + 4*i+3] = (VAL.value) & 0xFF;
169 backpatch_zmachine(VAL.marker, ARRAY_ZA,
170 dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES + 4*i);
174 error("Somehow created an array of shorts");
179 /* ------------------------------------------------------------------------- */
180 /* Global and Array directives. */
182 /* Global <variablename> | */
184 /* | <array specification> */
186 /* Array <arrayname> <array specification> */
188 /* where an array specification is: */
190 /* | -> | <number-of-entries> */
191 /* | --> | <entry-1> ... <entry-n> */
192 /* | string | [ <entry-1> [,] [;] <entry-2> ... <entry-n> ]; */
195 /* ------------------------------------------------------------------------- */
197 extern void set_variable_value(int i, int32 v)
198 { global_initial_value[i]=v;
201 /* There are four ways to initialise arrays: */
203 #define UNSPECIFIED_AI -1
209 extern void make_global(int array_flag, int name_only)
211 /* array_flag is TRUE for an Array directive, FALSE for a Global;
212 name_only is only TRUE for parsing an imported variable name, so
213 array_flag is always FALSE in that case. */
216 int array_type, data_type;
220 const char *global_name;
221 debug_location_beginning beginning_debug_location =
222 get_token_location_beginning();
224 directive_keywords.enabled = FALSE;
228 global_name = token_text;
231 if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T)
232 && (svals[i] >= LOWEST_SYSTEM_VAR_NUMBER))
233 goto RedefinitionOfSystemVar;
236 if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T))
237 goto RedefinitionOfSystemVar;
240 if ((token_type != SYMBOL_TT) || (!(sflags[i] & UNKNOWN_SFLAG)))
241 { discard_token_location(beginning_debug_location);
243 ebf_error("new array name", token_text);
244 else ebf_error("new global variable name", token_text);
245 panic_mode_error_recovery(); return;
248 if ((!array_flag) && (sflags[i] & USED_SFLAG))
249 error_named("Variable must be defined before use:", token_text);
254 assign_symbol(i, dynamic_array_area_size, ARRAY_T);
257 dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES, ARRAY_T);
258 if (no_arrays == MAX_ARRAYS)
259 memoryerror("MAX_ARRAYS", MAX_ARRAYS);
260 array_symbols[no_arrays] = i;
263 { if (!glulx_mode && no_globals==233)
264 { discard_token_location(beginning_debug_location);
265 error("All 233 global variables already declared");
266 panic_mode_error_recovery();
269 if (glulx_mode && no_globals==MAX_GLOBAL_VARIABLES)
270 { discard_token_location(beginning_debug_location);
271 memoryerror("MAX_GLOBAL_VARIABLES", MAX_GLOBAL_VARIABLES);
272 panic_mode_error_recovery();
276 variable_tokens[MAX_LOCAL_VARIABLES+no_globals] = i;
277 assign_symbol(i, MAX_LOCAL_VARIABLES+no_globals, GLOBAL_VARIABLE_T);
278 variable_tokens[svals[i]] = i;
280 if (name_only) import_symbol(i);
281 else global_initial_value[no_globals++]=0;
284 directive_keywords.enabled = TRUE;
286 RedefinitionOfSystemVar:
289 { discard_token_location(beginning_debug_location);
295 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
297 { discard_token_location(beginning_debug_location);
298 ebf_error("array definition", token_text);
301 if (debugfile_switch && !array_flag)
302 { debug_file_printf("<global-variable>");
303 debug_file_printf("<identifier>%s</identifier>", global_name);
304 debug_file_printf("<address>");
305 write_debug_global_backpatch(svals[global_symbol]);
306 debug_file_printf("</address>");
307 write_debug_locations
308 (get_token_location_end(beginning_debug_location));
309 debug_file_printf("</global-variable>");
316 if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
317 { AO = parse_expression(CONSTANT_CONTEXT);
320 backpatch_zmachine(AO.marker, DYNAMIC_ARRAY_ZA,
325 backpatch_zmachine(AO.marker, GLOBALVAR_ZA,
328 global_initial_value[no_globals-1] = AO.value;
329 if (debugfile_switch)
330 { debug_file_printf("<global-variable>");
331 debug_file_printf("<identifier>%s</identifier>", global_name);
332 debug_file_printf("<address>");
333 write_debug_global_backpatch(svals[global_symbol]);
334 debug_file_printf("</address>");
335 write_debug_locations
336 (get_token_location_end(beginning_debug_location));
337 debug_file_printf("</global-variable>");
342 obsolete_warning("more modern to use 'Array', not 'Global'");
345 backpatch_zmachine(ARRAY_MV, DYNAMIC_ARRAY_ZA, 2*(no_globals-1));
346 global_initial_value[no_globals-1]
347 = dynamic_array_area_size+variables_offset;
350 backpatch_zmachine(ARRAY_MV, GLOBALVAR_ZA, 4*(no_globals-1));
351 global_initial_value[no_globals-1]
352 = dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES;
356 array_type = BYTE_ARRAY; data_type = UNSPECIFIED_AI;
359 ((token_type==DIR_KEYWORD_TT)&&(token_value==DATA_DK)))
361 else if ((!array_flag) &&
362 ((token_type==DIR_KEYWORD_TT)&&(token_value==INITIAL_DK)))
364 else if ((!array_flag) &&
365 ((token_type==DIR_KEYWORD_TT)&&(token_value==INITSTR_DK)))
368 else if ((token_type==SEP_TT)&&(token_value==ARROW_SEP))
369 array_type = BYTE_ARRAY;
370 else if ((token_type==SEP_TT)&&(token_value==DARROW_SEP))
371 array_type = WORD_ARRAY;
372 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==STRING_DK))
373 array_type = STRING_ARRAY;
374 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==TABLE_DK))
375 array_type = TABLE_ARRAY;
376 else if ((token_type==DIR_KEYWORD_TT)&&(token_value==BUFFER_DK))
377 array_type = BUFFER_ARRAY;
379 { discard_token_location(beginning_debug_location);
382 ("'->', '-->', 'string', 'table' or 'buffer'", token_text);
385 ("'=', '->', '-->', 'string', 'table' or 'buffer'", token_text);
386 panic_mode_error_recovery();
391 if ((array_type==WORD_ARRAY) || (array_type==TABLE_ARRAY))
392 array_entry_size=WORDSIZE;
395 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
396 { discard_token_location(beginning_debug_location);
397 error("No array size or initial values given");
403 { case UNSPECIFIED_AI:
404 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
405 data_type = BRACKET_AI;
407 { data_type = NULLS_AI;
408 if (token_type == DQ_TT) data_type = ASCII_AI;
410 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
416 case NULLS_AI: obsolete_warning("use '->' instead of 'data'"); break;
417 case DATA_AI: obsolete_warning("use '->' instead of 'initial'"); break;
418 case ASCII_AI: obsolete_warning("use '->' instead of 'initstr'"); break;
421 array_base = dynamic_array_area_size;
423 /* Leave room to write the array size in later, if string/table array */
425 if ((array_type==STRING_ARRAY) || (array_type==TABLE_ARRAY))
426 dynamic_array_area_size += array_entry_size;
427 if (array_type==BUFFER_ARRAY)
428 dynamic_array_area_size += WORDSIZE;
429 array_types[no_arrays] = array_type;
435 AO = parse_expression(CONSTANT_CONTEXT);
439 if (module_switch && (AO.marker != 0))
440 { error("Array sizes must be known now, not externally defined");
445 if ((AO.value <= 0) || (AO.value >= 32768))
446 { error("An array must have between 1 and 32767 entries");
451 if (AO.value <= 0 || (AO.value & 0x80000000))
452 { error("An array may not have 0 or fewer entries");
457 { for (i=0; i<AO.value; i++) array_entry(i, zero_operand);
463 /* In this case the array is initialised to the sequence of
464 constant values supplied on the same line */
469 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
472 if ((token_type == SEP_TT)
473 && ((token_value == OPEN_SQUARE_SEP)
474 || (token_value == CLOSE_SQUARE_SEP)))
475 { discard_token_location(beginning_debug_location);
476 error("Missing ';' to end the initial array values "
477 "before \"[\" or \"]\"");
482 AO = parse_expression(ARRAY_CONTEXT);
487 if ((token_type == SEP_TT)
488 && (token_value == SEMICOLON_SEP))
489 { data_type = NULLS_AI;
490 goto CalculatedArraySize;
502 /* In this case the array is initialised to the ASCII values of
503 the characters of a given "quoted string" */
506 if (token_type != DQ_TT)
507 { ebf_error("literal text in double-quotes", token_text);
508 token_text = "error";
511 { assembly_operand chars;
515 for (i=0,j=0; token_text[j]!=0; i++,j+=textual_form_length)
517 int32 unicode; int zscii;
518 unicode = text_to_unicode(token_text+j);
521 if (array_entry_size == 1 && (unicode < 0 || unicode >= 256))
523 error("Unicode characters beyond Latin-1 cannot be used in a byte array");
527 chars.value = unicode;
532 zscii = unicode_to_zscii(unicode);
533 if ((zscii != 5) && (zscii < 0x100)) chars.value = zscii;
535 { unicode_char_error("Character can only be used if declared in \
536 advance as part of 'Zcharacter table':", unicode);
541 set_constant_ot(&chars);
542 array_entry(i, chars);
549 /* In this case the array is initialised to the sequence of
550 constant values given over a whole range of compiler-lines,
551 between square brackets [ and ] */
556 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
558 if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP))
560 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
561 { /* Minimal error recovery: we assume that a ] has
562 been missed, and the programmer is now starting
565 ebf_error("']'", token_text);
566 put_token_back(); break;
569 array_entry(i, parse_expression(ARRAY_CONTEXT));
576 if (debugfile_switch)
577 { debug_file_printf("<array>");
578 debug_file_printf("<identifier>%s</identifier>", global_name);
579 debug_file_printf("<value>");
580 write_debug_array_backpatch(svals[global_symbol]);
581 debug_file_printf("</value>");
583 ("<byte-count>%d</byte-count>",
584 dynamic_array_area_size - array_base);
586 ("<bytes-per-element>%d</bytes-per-element>",
589 ("<zeroth-element-holds-length>%s</zeroth-element-holds-length>",
590 (array_type == STRING_ARRAY || array_type == TABLE_ARRAY) ?
593 write_debug_locations(get_token_location_end(beginning_debug_location));
595 debug_file_printf("</array>");
598 if ((array_type==BYTE_ARRAY) || (array_type==WORD_ARRAY)) i--;
599 if (array_type==BUFFER_ARRAY) i+=WORDSIZE-1;
600 array_sizes[no_arrays++] = i;
603 extern int32 begin_table_array(void)
605 /* The "box" statement needs to be able to construct (static) table
606 arrays of strings like this */
608 array_base = dynamic_array_area_size;
609 array_entry_size = WORDSIZE;
611 /* Leave room to write the array size in later */
613 dynamic_array_area_size += array_entry_size;
618 return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
621 extern int32 begin_word_array(void)
623 /* The "random(a, b, ...)" function needs to be able to construct
624 (static) word arrays like this */
626 array_base = dynamic_array_area_size;
627 array_entry_size = WORDSIZE;
632 return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
635 /* ========================================================================= */
636 /* Data structure management routines */
637 /* ------------------------------------------------------------------------- */
639 extern void init_arrays_vars(void)
640 { dynamic_array_area = NULL;
641 global_initial_value = NULL;
642 array_sizes = NULL; array_symbols = NULL; array_types = NULL;
645 extern void arrays_begin_pass(void)
651 dynamic_array_area_size = WORDSIZE * MAX_GLOBAL_VARIABLES;
654 extern void arrays_allocate_arrays(void)
655 { dynamic_array_area = my_calloc(sizeof(int), MAX_STATIC_DATA,
657 array_sizes = my_calloc(sizeof(int), MAX_ARRAYS, "array sizes");
658 array_types = my_calloc(sizeof(int), MAX_ARRAYS, "array types");
659 array_symbols = my_calloc(sizeof(int32), MAX_ARRAYS, "array symbols");
660 global_initial_value = my_calloc(sizeof(int32), MAX_GLOBAL_VARIABLES,
664 extern void arrays_free_arrays(void)
665 { my_free(&dynamic_array_area, "static data");
666 my_free(&global_initial_value, "global values");
667 my_free(&array_sizes, "array sizes");
668 my_free(&array_types, "array sizes");
669 my_free(&array_symbols, "array sizes");
672 /* ========================================================================= */