320287b3c0c5fef909acd4f0355a26c5fd3cff3e
[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.40                                                     */
7 /*   copyright (c) Graham Nelson 1993 - 2022                                 */
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> |                                              */
258 /*                            | = <value>                                    */
259 /*                            | <array specification>                        */
260 /*                                                                           */
261 /*      Array <arrayname> [static] <array specification>                     */
262 /*                                                                           */
263 /*   where an array specification is:                                        */
264 /*                                                                           */
265 /*      | ->       |  <number-of-entries>                                    */
266 /*      | -->      |  <entry-1> ... <entry-n>                                */
267 /*      | string   |  [ <entry-1> [;] <entry-2> ... <entry-n> ];             */
268 /*      | table                                                              */
269 /*      | buffer                                                             */
270 /*                                                                           */
271 /*   The "static" keyword (arrays only) places the array in static memory.   */
272 /*                                                                           */
273 /* ------------------------------------------------------------------------- */
274
275 extern void set_variable_value(int i, int32 v)
276 {
277     /* This can be called during module-load to create a new global,
278        so we call ensure. */
279     ensure_memory_list_available(&global_initial_value_memlist, i+1);
280     global_initial_value[i]=v;
281 }
282
283 /*  There are four ways to initialise arrays:                                */
284
285 #define UNSPECIFIED_AI  -1
286 #define NULLS_AI        0
287 #define DATA_AI         1
288 #define ASCII_AI        2
289 #define BRACKET_AI      3
290
291 extern void make_global(int array_flag, int name_only)
292 {
293     /*  array_flag is TRUE for an Array directive, FALSE for a Global;
294         name_only is only TRUE for parsing an imported variable name, so
295         array_flag is always FALSE in that case.                             */
296
297     int32 i;
298     int name_length;
299     int array_type, data_type;
300     int is_static = FALSE;
301     assembly_operand AO;
302     
303     int extraspace;
304
305     int32 global_symbol;
306     debug_location_beginning beginning_debug_location =
307         get_token_location_beginning();
308
309     directive_keywords.enabled = FALSE;
310     get_next_token();
311     i = token_value;
312     global_symbol = i;
313     
314     name_length = strlen(token_text) + 1;
315     ensure_memory_list_available(&current_array_name, name_length);
316     strncpy(current_array_name.data, token_text, name_length);
317
318     if (!glulx_mode) {
319         if ((token_type==SYMBOL_TT) && (symbols[i].type==GLOBAL_VARIABLE_T)
320             && (symbols[i].value >= LOWEST_SYSTEM_VAR_NUMBER))
321             goto RedefinitionOfSystemVar;
322     }
323     else {
324         if ((token_type==SYMBOL_TT) && (symbols[i].type==GLOBAL_VARIABLE_T))
325             goto RedefinitionOfSystemVar;
326     }
327
328     if (token_type != SYMBOL_TT)
329     {   discard_token_location(beginning_debug_location);
330         if (array_flag)
331             ebf_error("new array name", token_text);
332         else ebf_error("new global variable name", token_text);
333         panic_mode_error_recovery(); return;
334     }
335
336     if (!(symbols[i].flags & UNKNOWN_SFLAG))
337     {   discard_token_location(beginning_debug_location);
338         if (array_flag)
339             ebf_symbol_error("new array name", token_text, typename(symbols[i].type), symbols[i].line);
340         else ebf_symbol_error("new global variable name", token_text, typename(symbols[i].type), symbols[i].line);
341         panic_mode_error_recovery(); return;
342     }
343
344     if ((!array_flag) && (symbols[i].flags & USED_SFLAG))
345         error_named("Variable must be defined before use:", token_text);
346
347     directive_keywords.enabled = TRUE;
348     get_next_token();
349     directive_keywords.enabled = FALSE;
350     if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) {
351         if (array_flag) {
352             is_static = TRUE;
353         }
354         else {
355             error("Global variables cannot be static");
356         }
357     }
358     else {
359         put_token_back();
360     }
361     
362     if (array_flag)
363     {   if (!is_static) {
364             assign_symbol(i, dynamic_array_area_size, ARRAY_T);
365         }
366         else {
367             assign_symbol(i, static_array_area_size, STATIC_ARRAY_T);
368         }
369         ensure_memory_list_available(&arrays_memlist, no_arrays+1);
370         arrays[no_arrays].symbol = i;
371     }
372     else
373     {   if (!glulx_mode && no_globals==233)
374         {   discard_token_location(beginning_debug_location);
375             error("All 233 global variables already declared");
376             panic_mode_error_recovery();
377             return;
378         }
379         
380         ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES+no_globals+1);
381         variables[MAX_LOCAL_VARIABLES+no_globals].token = i;
382         variables[MAX_LOCAL_VARIABLES+no_globals].usage = FALSE;
383         assign_symbol(i, MAX_LOCAL_VARIABLES+no_globals, GLOBAL_VARIABLE_T);
384
385         if (name_only) {
386             import_symbol(i);
387         }
388         else {
389             ensure_memory_list_available(&global_initial_value_memlist, no_globals+1);
390             global_initial_value[no_globals++]=0;
391         }
392     }
393
394     directive_keywords.enabled = TRUE;
395
396     RedefinitionOfSystemVar:
397
398     if (name_only)
399     {   discard_token_location(beginning_debug_location);
400         return;
401     }
402
403     get_next_token();
404
405     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
406     {   if (array_flag)
407         {   discard_token_location(beginning_debug_location);
408             ebf_error("array definition", token_text);
409         }
410         put_token_back();
411         if (debugfile_switch && !array_flag)
412         {
413             char *global_name = current_array_name.data;
414             debug_file_printf("<global-variable>");
415             debug_file_printf("<identifier>%s</identifier>", global_name);
416             debug_file_printf("<address>");
417             write_debug_global_backpatch(symbols[global_symbol].value);
418             debug_file_printf("</address>");
419             write_debug_locations
420                 (get_token_location_end(beginning_debug_location));
421             debug_file_printf("</global-variable>");
422         }
423         return;
424     }
425
426     if (!array_flag)
427     {
428         /* is_static is always false in this case */
429         if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
430         {   AO = parse_expression(CONSTANT_CONTEXT);
431             if (!glulx_mode) {
432                 if (AO.marker != 0)
433                     backpatch_zmachine(AO.marker, DYNAMIC_ARRAY_ZA,
434                         2*(no_globals-1));
435             }
436             else {
437             if (AO.marker != 0)
438                 backpatch_zmachine(AO.marker, GLOBALVAR_ZA,
439                 4*(no_globals-1));
440             }
441             global_initial_value[no_globals-1] = AO.value;
442             if (debugfile_switch)
443             {
444                 char *global_name = current_array_name.data;
445                 debug_file_printf("<global-variable>");
446                 debug_file_printf("<identifier>%s</identifier>", global_name);
447                 debug_file_printf("<address>");
448                 write_debug_global_backpatch(symbols[global_symbol].value);
449                 debug_file_printf("</address>");
450                 write_debug_locations
451                     (get_token_location_end(beginning_debug_location));
452                 debug_file_printf("</global-variable>");
453             }
454             return;
455         }
456
457         obsolete_warning("more modern to use 'Array', not 'Global'");
458
459         if (!glulx_mode) {
460             backpatch_zmachine(ARRAY_MV, DYNAMIC_ARRAY_ZA, 2*(no_globals-1));
461             global_initial_value[no_globals-1]
462                 = dynamic_array_area_size+variables_offset;
463         }
464         else {
465             backpatch_zmachine(ARRAY_MV, GLOBALVAR_ZA, 4*(no_globals-1));
466             global_initial_value[no_globals-1]
467                 = dynamic_array_area_size;
468         }
469     }
470
471     array_type = BYTE_ARRAY; data_type = UNSPECIFIED_AI;
472
473          if ((!array_flag) &&
474              ((token_type==DIR_KEYWORD_TT)&&(token_value==DATA_DK)))
475                  data_type=NULLS_AI;
476     else if ((!array_flag) &&
477              ((token_type==DIR_KEYWORD_TT)&&(token_value==INITIAL_DK)))
478                  data_type=DATA_AI;
479     else if ((!array_flag) &&
480              ((token_type==DIR_KEYWORD_TT)&&(token_value==INITSTR_DK)))
481                  data_type=ASCII_AI;
482
483     else if ((token_type==SEP_TT)&&(token_value==ARROW_SEP))
484              array_type = BYTE_ARRAY;
485     else if ((token_type==SEP_TT)&&(token_value==DARROW_SEP))
486              array_type = WORD_ARRAY;
487     else if ((token_type==DIR_KEYWORD_TT)&&(token_value==STRING_DK))
488              array_type = STRING_ARRAY;
489     else if ((token_type==DIR_KEYWORD_TT)&&(token_value==TABLE_DK))
490              array_type = TABLE_ARRAY;
491     else if ((token_type==DIR_KEYWORD_TT)&&(token_value==BUFFER_DK))
492              array_type = BUFFER_ARRAY;
493     else
494     {   discard_token_location(beginning_debug_location);
495         if (array_flag)
496             ebf_error
497               ("'->', '-->', 'string', 'table' or 'buffer'", token_text);
498         else
499             ebf_error
500               ("'=', '->', '-->', 'string', 'table' or 'buffer'", token_text);
501         panic_mode_error_recovery();
502         return;
503     }
504
505     array_entry_size=1;
506     if ((array_type==WORD_ARRAY) || (array_type==TABLE_ARRAY))
507         array_entry_size=WORDSIZE;
508
509     get_next_token();
510     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
511     {   discard_token_location(beginning_debug_location);
512         error("No array size or initial values given");
513         put_token_back();
514         return;
515     }
516
517     switch(data_type)
518     {   case UNSPECIFIED_AI:
519             if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
520                 data_type = BRACKET_AI;
521             else
522             {   data_type = NULLS_AI;
523                 if (token_type == DQ_TT) data_type = ASCII_AI;
524                 get_next_token();
525                 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
526                     data_type = DATA_AI;
527                 put_token_back();
528                 put_token_back();
529             }
530             break;
531         case NULLS_AI: obsolete_warning("use '->' instead of 'data'"); break;
532         case DATA_AI:  obsolete_warning("use '->' instead of 'initial'"); break;
533         case ASCII_AI: obsolete_warning("use '->' instead of 'initstr'"); break;
534     }
535
536     /*  Leave room to write the array size in later, if string/table array   */
537     
538     extraspace = 0;
539     if ((array_type==STRING_ARRAY) || (array_type==TABLE_ARRAY))
540         extraspace += array_entry_size;
541     if (array_type==BUFFER_ARRAY)
542         extraspace += WORDSIZE;
543     
544     if (!is_static) {
545         array_base = dynamic_array_area_size;
546         dynamic_array_area_size += extraspace;
547     }
548     else {
549         array_base = static_array_area_size;
550         static_array_area_size += extraspace;
551     }
552
553     arrays[no_arrays].type = array_type;
554     arrays[no_arrays].loc = is_static;
555
556     /* Note that, from this point, we must continue through finish_array().
557        Exiting this routine on error causes problems. */
558     
559     switch(data_type)
560     {
561         case NULLS_AI:
562
563             AO = parse_expression(CONSTANT_CONTEXT);
564
565             CalculatedArraySize:
566
567             if (AO.marker != 0)
568             {   error("Array sizes must be known now, not defined later");
569                 break;
570             }
571
572             if (!glulx_mode) {
573                 if ((AO.value <= 0) || (AO.value >= 32768))
574                 {   error("An array must have between 1 and 32767 entries");
575                     AO.value = 1;
576                 }
577             }
578             else {
579                 if (AO.value <= 0 || (AO.value & 0x80000000))
580                 {   error("An array may not have 0 or fewer entries");
581                     AO.value = 1;
582                 }
583             }
584
585             {   for (i=0; i<AO.value; i++) array_entry(i, is_static, zero_operand);
586             }
587             break;
588
589         case DATA_AI:
590
591             /*  In this case the array is initialised to the sequence of
592                 constant values supplied on the same line                    */
593
594             i=0;
595             do
596             {
597                 /* This isn't the start of a statement, but it's safe to
598                    release token texts anyway. Expressions in an array
599                    list are independent of each other. */
600                 release_token_texts();
601                 get_next_token();
602                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
603                     break;
604
605                 if ((token_type == SEP_TT)
606                     && ((token_value == OPEN_SQUARE_SEP)
607                         || (token_value == CLOSE_SQUARE_SEP)))
608                 {   discard_token_location(beginning_debug_location);
609                     error("Missing ';' to end the initial array values "
610                           "before \"[\" or \"]\"");
611                 }
612                 put_token_back();
613
614                 AO = parse_expression(ARRAY_CONTEXT);
615
616                 if (i == 0)
617                 {   get_next_token();
618                     put_token_back();
619                     if ((token_type == SEP_TT)
620                         && (token_value == SEMICOLON_SEP))
621                     {   data_type = NULLS_AI;
622                         goto CalculatedArraySize;
623                     }
624                 }
625
626                 array_entry(i, is_static, AO);
627                 i++;
628             } while (TRUE);
629             put_token_back();
630             break;
631
632         case ASCII_AI:
633
634             /*  In this case the array is initialised to the ASCII values of
635                 the characters of a given "quoted string"                    */
636
637             get_next_token();
638             if (token_type != DQ_TT)
639             {   ebf_error("literal text in double-quotes", token_text);
640                 token_text = "error";
641             }
642
643             {   assembly_operand chars;
644
645                 int j;
646                 INITAO(&chars);
647                 for (i=0,j=0; token_text[j]!=0; i++,j+=textual_form_length)
648                 {
649                     int32 unicode; int zscii;
650                     unicode = text_to_unicode(token_text+j);
651                     if (glulx_mode)
652                     {
653                         if (array_entry_size == 1 && (unicode < 0 || unicode >= 256))
654                         {
655                             error("Unicode characters beyond Latin-1 cannot be used in a byte array");
656                         }
657                         else
658                         {
659                             chars.value = unicode;
660                         }
661                     }
662                     else  /* Z-code */
663                     {                          
664                         zscii = unicode_to_zscii(unicode);
665                         if ((zscii != 5) && (zscii < 0x100)) chars.value = zscii;
666                         else
667                         {   unicode_char_error("Character can only be used if declared in \
668 advance as part of 'Zcharacter table':", unicode);
669                             chars.value = '?';
670                         }
671                     }
672                     chars.marker = 0;
673                     set_constant_ot(&chars);
674                     array_entry(i, is_static, chars);
675                 }
676             }
677             break;
678
679         case BRACKET_AI:
680
681             /*  In this case the array is initialised to the sequence of
682                 constant values given over a whole range of compiler-lines,
683                 between square brackets [ and ]                              */
684
685             i = 0;
686             while (TRUE)
687             {
688                 /* This isn't the start of a statement, but it's safe to
689                    release token texts anyway. Expressions in an array
690                    list are independent of each other. */
691                 release_token_texts();
692                 get_next_token();
693                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
694                     continue;
695                 if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP))
696                     break;
697                 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
698                 {   /*  Minimal error recovery: we assume that a ] has
699                         been missed, and the programmer is now starting
700                         a new routine                                        */
701
702                     ebf_error("']'", token_text);
703                     put_token_back(); break;
704                 }
705                 put_token_back();
706                 array_entry(i, is_static, parse_expression(ARRAY_CONTEXT));
707                 i++;
708             }
709     }
710
711     finish_array(i, is_static);
712
713     if (debugfile_switch)
714     {
715         int32 new_area_size;
716         char *global_name = current_array_name.data;
717         debug_file_printf("<array>");
718         debug_file_printf("<identifier>%s</identifier>", global_name);
719         debug_file_printf("<value>");
720         write_debug_array_backpatch(symbols[global_symbol].value);
721         debug_file_printf("</value>");
722         new_area_size = (!is_static ? dynamic_array_area_size : static_array_area_size);
723         debug_file_printf
724             ("<byte-count>%d</byte-count>",
725              new_area_size - array_base);
726         debug_file_printf
727             ("<bytes-per-element>%d</bytes-per-element>",
728              array_entry_size);
729         debug_file_printf
730             ("<zeroth-element-holds-length>%s</zeroth-element-holds-length>",
731              (array_type == STRING_ARRAY || array_type == TABLE_ARRAY) ?
732                  "true" : "false");
733         get_next_token();
734         write_debug_locations(get_token_location_end(beginning_debug_location));
735         put_token_back();
736         debug_file_printf("</array>");
737     }
738
739     if ((array_type==BYTE_ARRAY) || (array_type==WORD_ARRAY)) i--;
740     if (array_type==BUFFER_ARRAY) i+=WORDSIZE-1;
741     arrays[no_arrays++].size = i;
742 }
743
744 extern int32 begin_table_array(void)
745 {
746     /*  The "box" statement needs to be able to construct table
747         arrays of strings like this. (Static data, but we create a dynamic
748         array for maximum backwards compatibility.) */
749
750     array_base = dynamic_array_area_size;
751     array_entry_size = WORDSIZE;
752
753     /*  Leave room to write the array size in later                          */
754
755     dynamic_array_area_size += array_entry_size;
756
757     return array_base;
758 }
759
760 extern int32 begin_word_array(void)
761 {
762     /*  The "random(a, b, ...)" function needs to be able to construct
763         word arrays like this. (Static data, but we create a dynamic
764         array for maximum backwards compatibility.) */
765
766     array_base = dynamic_array_area_size;
767     array_entry_size = WORDSIZE;
768
769     return array_base;
770 }
771
772 /* ========================================================================= */
773 /*   Data structure management routines                                      */
774 /* ------------------------------------------------------------------------- */
775
776 extern void init_arrays_vars(void)
777 {   dynamic_array_area = NULL;
778     static_array_area = NULL;
779     arrays = NULL;
780     global_initial_value = NULL;
781     variables = NULL;
782 }
783
784 extern void arrays_begin_pass(void)
785 {
786     int ix, totalvar;
787     
788     no_arrays = 0; 
789     if (!glulx_mode) {
790         no_globals = 0;
791         /* The compiler-defined globals start at 239 and go down, so
792            we need to initialize the entire list from the start. */
793         totalvar = MAX_ZCODE_GLOBAL_VARS;
794     }
795     else {
796         /* The compiler-defined globals run from 0 to 10. */
797         no_globals = 11;
798         totalvar = no_globals;
799     }
800     
801     ensure_memory_list_available(&global_initial_value_memlist, totalvar);
802     for (ix=0; ix<totalvar; ix++) {
803         global_initial_value[ix] = 0;
804     }
805     
806     ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES+totalvar);
807     for (ix=0; ix<MAX_LOCAL_VARIABLES+totalvar; ix++) {
808         variables[ix].token = 0;
809         variables[ix].usage = FALSE;
810     }
811     
812     dynamic_array_area_size = 0;
813
814     if (!glulx_mode) {
815         int ix;
816         /* This initial segment of dynamic_array_area is never used. It's
817            notionally space for the global variables, but that data is
818            kept in the global_initial_value array. Nonetheless, all the
819            Z-compiler math is set up with the idea that arrays start at
820            WORDSIZE * MAX_ZCODE_GLOBAL_VARS, so we need the blank segment.
821         */
822         dynamic_array_area_size = WORDSIZE * MAX_ZCODE_GLOBAL_VARS;
823         ensure_memory_list_available(&dynamic_array_area_memlist, dynamic_array_area_size);
824         for (ix=0; ix<WORDSIZE * MAX_ZCODE_GLOBAL_VARS; ix++)
825             dynamic_array_area[ix] = 0;
826     }
827     
828     static_array_area_size = 0;
829 }
830
831 extern void arrays_allocate_arrays(void)
832 {
833     initialise_memory_list(&dynamic_array_area_memlist,
834         sizeof(uchar), 10000, (void**)&dynamic_array_area,
835         "dynamic array data");
836     initialise_memory_list(&static_array_area_memlist,
837         sizeof(uchar), 0, (void**)&static_array_area,
838         "static array data");
839     initialise_memory_list(&arrays_memlist,
840         sizeof(arrayinfo), 64, (void**)&arrays,
841         "array info");
842     initialise_memory_list(&global_initial_value_memlist,
843         sizeof(int32), 200, (void**)&global_initial_value,
844         "global variable values");
845
846     initialise_memory_list(&current_array_name,
847         sizeof(char), MAX_IDENTIFIER_LENGTH+1, NULL,
848         "array name currently being defined");
849 }
850
851 extern void arrays_free_arrays(void)
852 {
853     deallocate_memory_list(&dynamic_array_area_memlist);
854     deallocate_memory_list(&static_array_area_memlist);
855     deallocate_memory_list(&arrays_memlist);
856     deallocate_memory_list(&global_initial_value_memlist);
857     deallocate_memory_list(&current_array_name);
858 }
859
860 /* ========================================================================= */