Update to Inform v6.42
[inform.git] / src / arrays.c
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.                             */
5 /*                                                                           */
6 /*   Part of Inform 6.42                                                     */
7 /*   copyright (c) Graham Nelson 1993 - 2024                                 */
8 /*                                                                           */
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.                                       */
13 /*                                                                           */
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.                              */
18 /*                                                                           */
19 /* You should have received a copy of the GNU General Public License         */
20 /* along with Inform. If not, see https://gnu.org/licenses/                  */
21 /*                                                                           */
22 /* ------------------------------------------------------------------------- */
23
24 #include "header.h"
25
26 /* ------------------------------------------------------------------------- */
27 /*   Arrays defined below:                                                   */
28 /*                                                                           */
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)               */
36 /*                                                                           */
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.                                  */
40 /*                                                                           */
41 /*   In Glulx, we don't keep the global variables in dynamic_array_area.     */
42 /*   Array data starts at the start.                                         */
43 /*                                                                           */
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                      */
50
51 int32   *global_initial_value;         /* Allocated to no_globals            */
52 static memory_list global_initial_value_memlist;
53
54 int no_globals;                        /* Number of global variables used
55                                           by the programmer (Inform itself
56                                           uses the top seven -- but these do
57                                           not count)                         */
58                                        /* In Glulx, Inform uses the bottom 
59                                           ten.                               */
60
61 uchar   *static_array_area;
62 memory_list static_array_area_memlist;
63 int static_array_area_size;
64
65 int no_arrays;
66 arrayinfo *arrays;
67 static memory_list arrays_memlist;
68
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)  */
77
78                                        /* In Glulx, of course, that will be
79                                           4 instead of 2.                    */
80
81 static memory_list current_array_name; /* The name of the global or array
82                                           currently being compiled.          */
83
84 /* Complete the array. Fill in the size field (if it has one) and 
85    advance foo_array_area_size.
86 */
87 extern void finish_array(int32 i, int is_static)
88 {
89   uchar *area;
90   int area_size;
91   
92   if (!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;
96   }
97   else {
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;
101   }
102
103   if (i == 0) {
104       error("An array must have at least one entry");
105   }
106   
107     /*  Write the array size into the 0th byte/word of the array, if it's
108         a "table" or "string" array                                          */
109   if (!glulx_mode) {
110
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;
115         }
116         else
117         {   if (i>=256)
118                 error("A 'string' array can have at most 256 entries");
119             area[array_base] = i;
120         }
121     }
122
123   }
124   else {
125     if (array_base != area_size)
126     {   if (area_size-array_base==4)
127         {   
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;
132         }
133         else
134         {   if (i>=256)
135                 error("A 'string' array can have at most 256 entries");
136             area[array_base] = i;
137         }
138     }
139     
140   }
141
142   /*  Move on the static/dynamic array size so that it now points to the
143       next available free space                                              */
144
145   if (!is_static) {
146       dynamic_array_area_size += i*array_entry_size;
147   }
148   else {
149       static_array_area_size += i*array_entry_size;
150   }
151
152 }
153
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.
157 */
158 extern void array_entry(int32 i, int is_static, assembly_operand VAL)
159 {
160   uchar *area;
161   int area_size;
162   
163   if (!is_static) {
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;
167   }
168   else {
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;
172   }
173   
174   if (!glulx_mode) {
175     /*  Array entry i (initial entry has i=0) is set to Z-machine value j    */
176
177     if (array_entry_size==1)
178     {   area[area_size+i] = (VAL.value)%256;
179
180         if (VAL.marker != 0)
181            error("Entries in byte arrays and strings must be known constants");
182
183         /*  If the entry is too large for a byte array, issue a warning
184             and truncate the value                                           */
185         else
186         if (VAL.value >= 256)
187             warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
188     }
189     else
190     {
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) {
195             if (!is_static) {
196                 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
197                     addr);
198             }
199             else {
200                 backpatch_zmachine(VAL.marker, STATIC_ARRAY_ZA,
201                     addr);
202             }
203         }
204     }
205   }
206   else {
207     /*  Array entry i (initial entry has i=0) is set to value j              */
208
209     if (array_entry_size==1)
210     {   area[area_size+i] = (VAL.value) & 0xFF;
211
212         if (VAL.marker != 0)
213            error("Entries in byte arrays and strings must be known constants");
214
215         /*  If the entry is too large for a byte array, issue a warning
216             and truncate the value                                           */
217         else
218         if (VAL.value >= 256)
219             warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
220     }
221     else if (array_entry_size==4)
222     {
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) {
229             if (!is_static) {
230                 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
231                     addr);
232             }
233             else {
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);
244             }
245         }
246     }
247     else
248     {
249         error("Somehow created an array of shorts");
250     }
251   }
252 }
253
254 /* ------------------------------------------------------------------------- */
255 /*   Global and Array directives.                                            */
256 /*                                                                           */
257 /*      Global <variablename> [ [=] <value> ]                                */
258 /*                                                                           */
259 /*      Array <arrayname> [static] <array specification>                     */
260 /*                                                                           */
261 /*   where an array specification is:                                        */
262 /*                                                                           */
263 /*      | ->       |  <number-of-entries>                                    */
264 /*      | -->      |  <entry-1> ... <entry-n>                                */
265 /*      | string   |  [ <entry-1> [;] <entry-2> ... <entry-n> ];             */
266 /*      | table                                                              */
267 /*      | buffer                                                             */
268 /*                                                                           */
269 /*   The "static" keyword (arrays only) places the array in static memory.   */
270 /*                                                                           */
271 /* ------------------------------------------------------------------------- */
272
273 extern void set_variable_value(int i, int32 v)
274 {
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;
279 }
280
281 /*  There are four ways to initialise arrays:                                */
282
283 #define UNSPECIFIED_AI  -1
284 #define NULLS_AI        0
285 #define DATA_AI         1
286 #define ASCII_AI        2
287 #define BRACKET_AI      3
288
289 extern void make_global()
290 {
291     int32 i;
292     int name_length;
293     assembly_operand AO;
294
295     uint32 globalnum;
296     int32 global_symbol;
297     debug_location_beginning beginning_debug_location =
298         get_token_location_beginning();
299
300     directive_keywords.enabled = FALSE;
301     get_next_token();
302     i = token_value;
303     global_symbol = i;
304     
305     name_length = strlen(token_text) + 1;
306     ensure_memory_list_available(&current_array_name, name_length);
307     strncpy(current_array_name.data, token_text, name_length);
308
309     if (!glulx_mode) {
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;
314         }
315     }
316     else {
317         if ((token_type==SYMBOL_TT) && (symbols[i].type==GLOBAL_VARIABLE_T)) {
318             globalnum = symbols[i].value - MAX_LOCAL_VARIABLES;
319             goto RedefinitionOfSystemVar;
320         }
321     }
322
323     if (token_type != SYMBOL_TT)
324     {   discard_token_location(beginning_debug_location);
325         ebf_curtoken_error("new global variable name");
326         panic_mode_error_recovery(); return;
327     }
328
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;
333     }
334
335     if (symbols[i].flags & USED_SFLAG)
336         error_named("Variable must be defined before use:", token_text);
337
338     directive_keywords.enabled = TRUE;
339     get_next_token();
340     directive_keywords.enabled = FALSE;
341     if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) {
342         error("Global variables cannot be static");
343     }
344     else {
345         put_token_back();
346     }
347     
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();
352         return;
353     }
354
355     globalnum = no_globals;
356     
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);
361
362     ensure_memory_list_available(&global_initial_value_memlist, no_globals+1);
363     global_initial_value[no_globals++]=0;
364
365     directive_keywords.enabled = TRUE;
366
367     RedefinitionOfSystemVar:
368
369     get_next_token();
370
371     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
372     {
373         /* No initial value. */
374         put_token_back();
375         if (debugfile_switch)
376         {
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>");
386         }
387         return;
388     }
389
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)))
395     {
396         error("use 'Array' to define arrays, not 'Global'");
397         return;
398     }
399
400     /* Skip "=" if present. */
401     if (!((token_type == SEP_TT) && (token_value == SETEQUALS_SEP)))
402         put_token_back();
403
404     AO = parse_expression(CONSTANT_CONTEXT);
405     if (!glulx_mode) {
406         if (AO.marker != 0)
407             backpatch_zmachine(AO.marker, DYNAMIC_ARRAY_ZA,
408                 2*globalnum);
409     }
410     else {
411         if (AO.marker != 0)
412             backpatch_zmachine(AO.marker, GLOBALVAR_ZA,
413                 4*globalnum);
414     }
415     
416     if (globalnum >= global_initial_value_memlist.count)
417         compiler_error("Globalnum out of range");
418     global_initial_value[globalnum] = AO.value;
419     
420     if (debugfile_switch)
421     {
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>");
431     }
432 }
433
434 extern void make_array()
435 {
436     int32 i;
437     int name_length;
438     int array_type, data_type;
439     int is_static = FALSE;
440     assembly_operand AO;
441     
442     int extraspace;
443
444     int32 global_symbol;
445     debug_location_beginning beginning_debug_location =
446         get_token_location_beginning();
447
448     directive_keywords.enabled = FALSE;
449     get_next_token();
450     i = token_value;
451     global_symbol = i;
452     
453     name_length = strlen(token_text) + 1;
454     ensure_memory_list_available(&current_array_name, name_length);
455     strncpy(current_array_name.data, token_text, name_length);
456
457     if (token_type != SYMBOL_TT)
458     {   discard_token_location(beginning_debug_location);
459         ebf_curtoken_error("new array name");
460         panic_mode_error_recovery(); return;
461     }
462
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;
467     }
468
469     directive_keywords.enabled = TRUE;
470     get_next_token();
471     directive_keywords.enabled = FALSE;
472     if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) {
473         is_static = TRUE;
474     }
475     else {
476         put_token_back();
477     }
478     
479     if (!is_static) {
480         assign_symbol(i, dynamic_array_area_size, ARRAY_T);
481     }
482     else {
483         assign_symbol(i, static_array_area_size, STATIC_ARRAY_T);
484     }
485     ensure_memory_list_available(&arrays_memlist, no_arrays+1);
486     arrays[no_arrays].symbol = i;
487
488     directive_keywords.enabled = TRUE;
489
490     get_next_token();
491
492     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
493     {
494         discard_token_location(beginning_debug_location);
495         ebf_curtoken_error("array definition");
496         put_token_back();
497         return;
498     }
499
500     array_type = BYTE_ARRAY; data_type = UNSPECIFIED_AI;
501
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.
505     */
506
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;
517     else
518     {   discard_token_location(beginning_debug_location);
519         ebf_curtoken_error("'->', '-->', 'string', 'table' or 'buffer'");
520         panic_mode_error_recovery();
521         return;
522     }
523
524     array_entry_size=1;
525     if ((array_type==WORD_ARRAY) || (array_type==TABLE_ARRAY))
526         array_entry_size=WORDSIZE;
527
528     get_next_token();
529     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
530     {   discard_token_location(beginning_debug_location);
531         error("No array size or initial values given");
532         put_token_back();
533         return;
534     }
535
536     switch(data_type)
537     {   case UNSPECIFIED_AI:
538             if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
539                 data_type = BRACKET_AI;
540             else
541             {   data_type = NULLS_AI;
542                 if (token_type == DQ_TT) data_type = ASCII_AI;
543                 get_next_token();
544                 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
545                     data_type = DATA_AI;
546                 put_token_back();
547                 put_token_back();
548             }
549             break;
550         case NULLS_AI: obsolete_warning("use '->' instead of 'data'"); break;
551         case DATA_AI:  obsolete_warning("use '->' instead of 'initial'"); break;
552         case ASCII_AI: obsolete_warning("use '->' instead of 'initstr'"); break;
553     }
554
555     /*  Leave room to write the array size in later, if string/table array   */
556     
557     extraspace = 0;
558     if ((array_type==STRING_ARRAY) || (array_type==TABLE_ARRAY))
559         extraspace += array_entry_size;
560     if (array_type==BUFFER_ARRAY)
561         extraspace += WORDSIZE;
562     
563     if (!is_static) {
564         array_base = dynamic_array_area_size;
565         dynamic_array_area_size += extraspace;
566     }
567     else {
568         array_base = static_array_area_size;
569         static_array_area_size += extraspace;
570     }
571
572     arrays[no_arrays].type = array_type;
573     arrays[no_arrays].loc = is_static;
574
575     /* Note that, from this point, we must continue through finish_array().
576        Exiting this routine on error causes problems. */
577     
578     switch(data_type)
579     {
580         case NULLS_AI:
581
582             AO = parse_expression(CONSTANT_CONTEXT);
583
584             CalculatedArraySize:
585
586             if (AO.marker != 0)
587             {   error("Array sizes must be known now, not defined later");
588                 break;
589             }
590
591             if (!glulx_mode) {
592                 if ((AO.value <= 0) || (AO.value >= 32768))
593                 {   error("An array must have between 1 and 32767 entries");
594                     AO.value = 1;
595                 }
596             }
597             else {
598                 if (AO.value <= 0 || (AO.value & 0x80000000))
599                 {   error("An array may not have 0 or fewer entries");
600                     AO.value = 1;
601                 }
602             }
603
604             {   for (i=0; i<AO.value; i++) array_entry(i, is_static, zero_operand);
605             }
606             break;
607
608         case DATA_AI:
609
610             /*  In this case the array is initialised to the sequence of
611                 constant values supplied on the same line                    */
612
613             i=0;
614             do
615             {
616                 /* This isn't the start of a statement, but it's safe to
617                    release token texts anyway. Expressions in an array
618                    list are independent of each other. */
619                 release_token_texts();
620                 get_next_token();
621                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
622                     break;
623
624                 if ((token_type == SEP_TT)
625                     && ((token_value == OPEN_SQUARE_SEP)
626                         || (token_value == CLOSE_SQUARE_SEP)))
627                 {   discard_token_location(beginning_debug_location);
628                     error("Missing ';' to end the initial array values "
629                           "before \"[\" or \"]\"");
630                 }
631                 put_token_back();
632
633                 AO = parse_expression(ARRAY_CONTEXT);
634                 if (AO.marker == ERROR_MV)
635                     break;
636
637                 if (i == 0)
638                 {   get_next_token();
639                     put_token_back();
640                     if ((token_type == SEP_TT)
641                         && (token_value == SEMICOLON_SEP))
642                     {   data_type = NULLS_AI;
643                         goto CalculatedArraySize;
644                     }
645                 }
646
647                 array_entry(i, is_static, AO);
648                 i++;
649             } while (TRUE);
650             put_token_back();
651             break;
652
653         case ASCII_AI:
654
655             /*  In this case the array is initialised to the ASCII values of
656                 the characters of a given "quoted string"                    */
657
658             get_next_token();
659             if (token_type != DQ_TT)
660             {   ebf_curtoken_error("literal text in double-quotes");
661                 token_text = "error";
662             }
663
664             {   assembly_operand chars;
665
666                 int j;
667                 INITAO(&chars);
668                 for (i=0,j=0; token_text[j]!=0; i++,j+=textual_form_length)
669                 {
670                     int32 unicode; int zscii;
671                     unicode = text_to_unicode(token_text+j);
672                     if (glulx_mode)
673                     {
674                         if (array_entry_size == 1 && (unicode < 0 || unicode >= 256))
675                         {
676                             error("Unicode characters beyond Latin-1 cannot be used in a byte array");
677                         }
678                         else
679                         {
680                             chars.value = unicode;
681                         }
682                     }
683                     else  /* Z-code */
684                     {                          
685                         zscii = unicode_to_zscii(unicode);
686                         if ((zscii != 5) && (zscii < 0x100)) chars.value = zscii;
687                         else
688                         {   unicode_char_error("Character can only be used if declared in \
689 advance as part of 'Zcharacter table':", unicode);
690                             chars.value = '?';
691                         }
692                     }
693                     chars.marker = 0;
694                     set_constant_ot(&chars);
695                     array_entry(i, is_static, chars);
696                 }
697             }
698             break;
699
700         case BRACKET_AI:
701
702             /*  In this case the array is initialised to the sequence of
703                 constant values given over a whole range of compiler-lines,
704                 between square brackets [ and ]                              */
705
706             i = 0;
707             while (TRUE)
708             {
709                 assembly_operand AO;
710                 /* This isn't the start of a statement, but it's safe to
711                    release token texts anyway. Expressions in an array
712                    list are independent of each other. */
713                 release_token_texts();
714                 get_next_token();
715                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
716                     continue;
717                 if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP))
718                     break;
719                 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
720                 {   /*  Minimal error recovery: we assume that a ] has
721                         been missed, and the programmer is now starting
722                         a new routine                                        */
723
724                     ebf_curtoken_error("']'");
725                     put_token_back(); break;
726                 }
727                 put_token_back();
728                 AO = parse_expression(ARRAY_CONTEXT);
729                 if (AO.marker == ERROR_MV)
730                     break;
731                 array_entry(i, is_static, AO);
732                 i++;
733             }
734     }
735
736     finish_array(i, is_static);
737
738     if (debugfile_switch)
739     {
740         int32 new_area_size;
741         char *global_name = current_array_name.data;
742         debug_file_printf("<array>");
743         debug_file_printf("<identifier>%s</identifier>", global_name);
744         debug_file_printf("<value>");
745         write_debug_array_backpatch(symbols[global_symbol].value);
746         debug_file_printf("</value>");
747         new_area_size = (!is_static ? dynamic_array_area_size : static_array_area_size);
748         debug_file_printf
749             ("<byte-count>%d</byte-count>",
750              new_area_size - array_base);
751         debug_file_printf
752             ("<bytes-per-element>%d</bytes-per-element>",
753              array_entry_size);
754         debug_file_printf
755             ("<zeroth-element-holds-length>%s</zeroth-element-holds-length>",
756              (array_type == STRING_ARRAY || array_type == TABLE_ARRAY) ?
757                  "true" : "false");
758         get_next_token();
759         write_debug_locations(get_token_location_end(beginning_debug_location));
760         put_token_back();
761         debug_file_printf("</array>");
762     }
763
764     if ((array_type==BYTE_ARRAY) || (array_type==WORD_ARRAY)) i--;
765     if (array_type==BUFFER_ARRAY) i+=WORDSIZE-1;
766     arrays[no_arrays++].size = i;
767 }
768
769 extern int32 begin_table_array(void)
770 {
771     /*  The "box" statement needs to be able to construct table
772         arrays of strings like this. (Static data, but we create a dynamic
773         array for maximum backwards compatibility.) */
774
775     array_base = dynamic_array_area_size;
776     array_entry_size = WORDSIZE;
777
778     /*  Leave room to write the array size in later                          */
779
780     dynamic_array_area_size += array_entry_size;
781
782     return array_base;
783 }
784
785 extern int32 begin_word_array(void)
786 {
787     /*  The "random(a, b, ...)" function needs to be able to construct
788         word arrays like this. (Static data, but we create a dynamic
789         array for maximum backwards compatibility.) */
790
791     array_base = dynamic_array_area_size;
792     array_entry_size = WORDSIZE;
793
794     return array_base;
795 }
796
797 /* ========================================================================= */
798 /*   Data structure management routines                                      */
799 /* ------------------------------------------------------------------------- */
800
801 extern void init_arrays_vars(void)
802 {   dynamic_array_area = NULL;
803     static_array_area = NULL;
804     arrays = NULL;
805     global_initial_value = NULL;
806     variables = NULL;
807 }
808
809 extern void arrays_begin_pass(void)
810 {
811     int ix, totalvar;
812     
813     no_arrays = 0; 
814     if (!glulx_mode) {
815         no_globals = 0;
816         /* The compiler-defined globals start at 239 and go down, so
817            we need to initialize the entire list from the start. */
818         totalvar = MAX_ZCODE_GLOBAL_VARS;
819     }
820     else {
821         /* The compiler-defined globals run from 0 to 10. */
822         no_globals = 11;
823         totalvar = no_globals;
824     }
825     
826     ensure_memory_list_available(&global_initial_value_memlist, totalvar);
827     for (ix=0; ix<totalvar; ix++) {
828         global_initial_value[ix] = 0;
829     }
830     
831     ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES+totalvar);
832     for (ix=0; ix<MAX_LOCAL_VARIABLES+totalvar; ix++) {
833         variables[ix].token = 0;
834         variables[ix].usage = FALSE;
835     }
836     
837     dynamic_array_area_size = 0;
838
839     if (!glulx_mode) {
840         int ix;
841         /* This initial segment of dynamic_array_area is never used. It's
842            notionally space for the global variables, but that data is
843            kept in the global_initial_value array. Nonetheless, all the
844            Z-compiler math is set up with the idea that arrays start at
845            WORDSIZE * MAX_ZCODE_GLOBAL_VARS, so we need the blank segment.
846         */
847         dynamic_array_area_size = WORDSIZE * MAX_ZCODE_GLOBAL_VARS;
848         ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size);
849         for (ix=0; ix<WORDSIZE * MAX_ZCODE_GLOBAL_VARS; ix++)
850             dynamic_array_area[ix] = 0;
851     }
852     
853     static_array_area_size = 0;
854 }
855
856 extern void arrays_allocate_arrays(void)
857 {
858     initialise_memory_list(&dynamic_array_area_memlist,
859         sizeof(uchar), 10000, (void**)&dynamic_array_area,
860         "dynamic array data");
861     initialise_memory_list(&static_array_area_memlist,
862         sizeof(uchar), 0, (void**)&static_array_area,
863         "static array data");
864     initialise_memory_list(&arrays_memlist,
865         sizeof(arrayinfo), 64, (void**)&arrays,
866         "array info");
867     initialise_memory_list(&global_initial_value_memlist,
868         sizeof(int32), 200, (void**)&global_initial_value,
869         "global variable values");
870
871     initialise_memory_list(&current_array_name,
872         sizeof(char), 32, NULL,
873         "array name currently being defined");
874 }
875
876 extern void arrays_free_arrays(void)
877 {
878     deallocate_memory_list(&dynamic_array_area_memlist);
879     deallocate_memory_list(&static_array_area_memlist);
880     deallocate_memory_list(&arrays_memlist);
881     deallocate_memory_list(&global_initial_value_memlist);
882     deallocate_memory_list(&current_array_name);
883 }
884
885 /* ========================================================================= */