Update to commit af5309356bfa197d7a7ea09101c317f94e9b856b
[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.35                                                     */
7 /*   copyright (c) Graham Nelson 1993 - 2021                                 */
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 /*    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) */
35 /*                                                                           */
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".     */
41 /*                                                                           */
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.                                                */
45 /*                                                                           */
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;
52
53 int no_globals;                        /* Number of global variables used
54                                           by the programmer (Inform itself
55                                           uses the top seven -- but these do
56                                           not count)                         */
57                                        /* In Glulx, Inform uses the bottom 
58                                           ten.                               */
59
60 int dynamic_array_area_size;           /* Size in bytes                      */
61
62 int     *static_array_area;
63 int static_array_area_size;
64
65 int no_arrays;
66 int32   *array_symbols;
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.                                  */
71
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)  */
80
81                                        /* In Glulx, of course, that will be
82                                           4 instead of 2.                    */
83
84 extern void finish_array(int32 i, int is_static)
85 {
86   int *area;
87   int area_size;
88   
89   if (!is_static) {
90       area = dynamic_array_area;
91       area_size = dynamic_array_area_size;
92   }
93   else {
94       area = static_array_area;
95       area_size = static_array_area_size;
96   }
97
98   if (i == 0) {
99       error("An array must have at least one entry");
100   }
101   
102     /*  Write the array size into the 0th byte/word of the array, if it's
103         a "table" or "string" array                                          */
104   if (!glulx_mode) {
105
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;
110         }
111         else
112         {   if (i>=256)
113                 error("A 'string' array can have at most 256 entries");
114             area[array_base] = i;
115         }
116     }
117
118   }
119   else {
120     if (array_base != area_size)
121     {   if (area_size-array_base==4)
122         {   
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;
127         }
128         else
129         {   if (i>=256)
130                 error("A 'string' array can have at most 256 entries");
131             area[array_base] = i;
132         }
133     }
134     
135   }
136
137   /*  Move on the static/dynamic array size so that it now points to the
138       next available free space                                              */
139
140   if (!is_static) {
141       dynamic_array_area_size += i*array_entry_size;
142   }
143   else {
144       static_array_area_size += i*array_entry_size;
145   }
146
147 }
148
149 extern void array_entry(int32 i, int is_static, assembly_operand VAL)
150 {
151   int *area;
152   int area_size;
153   
154   if (!is_static) {
155       area = dynamic_array_area;
156       area_size = dynamic_array_area_size;
157   }
158   else {
159       area = static_array_area;
160       area_size = static_array_area_size;
161   }
162   
163   if (!glulx_mode) {
164     /*  Array entry i (initial entry has i=0) is set to Z-machine value j    */
165
166     if (area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
167         memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
168
169     if (array_entry_size==1)
170     {   area[area_size+i] = (VAL.value)%256;
171
172         if (VAL.marker != 0)
173            error("Entries in byte arrays and strings must be known constants");
174
175         /*  If the entry is too large for a byte array, issue a warning
176             and truncate the value                                           */
177         else
178         if (VAL.value >= 256)
179             warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
180     }
181     else
182     {
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) {
187             if (!is_static) {
188                 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
189                     addr);
190             }
191             else {
192                 backpatch_zmachine(VAL.marker, STATIC_ARRAY_ZA,
193                     addr);
194             }
195         }
196     }
197   }
198   else {
199     /*  Array entry i (initial entry has i=0) is set to value j              */
200
201     if (area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
202         memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
203
204     if (array_entry_size==1)
205     {   area[area_size+i] = (VAL.value) & 0xFF;
206
207         if (VAL.marker != 0)
208            error("Entries in byte arrays and strings must be known constants");
209
210         /*  If the entry is too large for a byte array, issue a warning
211             and truncate the value                                           */
212         else
213         if (VAL.value >= 256)
214             warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
215     }
216     else if (array_entry_size==4)
217     {
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) {
224             if (!is_static) {
225                 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
226                     addr - 4*MAX_GLOBAL_VARIABLES);
227             }
228             else {
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++,
233                     VAL.marker);
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));
242             }
243         }
244     }
245     else
246     {
247         error("Somehow created an array of shorts");
248     }
249   }
250 }
251
252 /* ------------------------------------------------------------------------- */
253 /*   Global and Array directives.                                            */
254 /*                                                                           */
255 /*      Global <variablename> |                                              */
256 /*                            | = <value>                                    */
257 /*                            | <array specification>                        */
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 {   global_initial_value[i]=v;
275 }
276
277 /*  There are four ways to initialise arrays:                                */
278
279 #define UNSPECIFIED_AI  -1
280 #define NULLS_AI        0
281 #define DATA_AI         1
282 #define ASCII_AI        2
283 #define BRACKET_AI      3
284
285 extern void make_global(int array_flag, int name_only)
286 {
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.                             */
290
291     int32 i;
292     int array_type, data_type;
293     int is_static = FALSE;
294     assembly_operand AO;
295     
296     int extraspace;
297     int orig_area_size;
298
299     int32 global_symbol;
300     const char *global_name;
301     debug_location_beginning beginning_debug_location =
302         get_token_location_beginning();
303
304     directive_keywords.enabled = FALSE;
305     get_next_token();
306     i = token_value;
307     global_symbol = i;
308     global_name = token_text;
309
310     if (!glulx_mode) {
311         if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T)
312             && (svals[i] >= LOWEST_SYSTEM_VAR_NUMBER))
313             goto RedefinitionOfSystemVar;
314     }
315     else {
316         if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T))
317             goto RedefinitionOfSystemVar;
318     }
319
320     if (token_type != SYMBOL_TT)
321     {   discard_token_location(beginning_debug_location);
322         if (array_flag)
323             ebf_error("new array name", token_text);
324         else ebf_error("new global variable name", token_text);
325         panic_mode_error_recovery(); return;
326     }
327
328     if (!(sflags[i] & UNKNOWN_SFLAG))
329     {   discard_token_location(beginning_debug_location);
330         if (array_flag)
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;
334     }
335
336     if ((!array_flag) && (sflags[i] & USED_SFLAG))
337         error_named("Variable must be defined before use:", token_text);
338
339     directive_keywords.enabled = TRUE;
340     get_next_token();
341     directive_keywords.enabled = FALSE;
342     if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) {
343         if (array_flag) {
344             is_static = TRUE;
345         }
346         else {
347             error("Global variables cannot be static");
348         }
349     }
350     else {
351         put_token_back();
352     }
353     
354     if (array_flag)
355     {   if (!is_static) {
356             if (!glulx_mode)
357                 assign_symbol(i, dynamic_array_area_size, ARRAY_T);
358             else
359                 assign_symbol(i, 
360                     dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES, ARRAY_T);
361         }
362         else {
363             assign_symbol(i, static_array_area_size, STATIC_ARRAY_T);
364         }
365         if (no_arrays == MAX_ARRAYS)
366             memoryerror("MAX_ARRAYS", MAX_ARRAYS);
367         array_symbols[no_arrays] = i;
368     }
369     else
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();
374             return;
375         }
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();
380             return;
381         }
382
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;
386
387         if (name_only) import_symbol(i);
388         else global_initial_value[no_globals++]=0;
389     }
390
391     directive_keywords.enabled = TRUE;
392
393     RedefinitionOfSystemVar:
394
395     if (name_only)
396     {   discard_token_location(beginning_debug_location);
397         return;
398     }
399
400     get_next_token();
401
402     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
403     {   if (array_flag)
404         {   discard_token_location(beginning_debug_location);
405             ebf_error("array definition", token_text);
406         }
407         put_token_back();
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>");
417         }
418         return;
419     }
420
421     if (!array_flag)
422     {
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);
426             if (!glulx_mode) {
427                 if (AO.marker != 0)
428                     backpatch_zmachine(AO.marker, DYNAMIC_ARRAY_ZA,
429                         2*(no_globals-1));
430             }
431             else {
432             if (AO.marker != 0)
433                 backpatch_zmachine(AO.marker, GLOBALVAR_ZA,
434                 4*(no_globals-1));
435             }
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>");
446             }
447             return;
448         }
449
450         obsolete_warning("more modern to use 'Array', not 'Global'");
451
452         if (!glulx_mode) {
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;
456         }
457         else {
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;
461         }
462     }
463
464     array_type = BYTE_ARRAY; data_type = UNSPECIFIED_AI;
465
466          if ((!array_flag) &&
467              ((token_type==DIR_KEYWORD_TT)&&(token_value==DATA_DK)))
468                  data_type=NULLS_AI;
469     else if ((!array_flag) &&
470              ((token_type==DIR_KEYWORD_TT)&&(token_value==INITIAL_DK)))
471                  data_type=DATA_AI;
472     else if ((!array_flag) &&
473              ((token_type==DIR_KEYWORD_TT)&&(token_value==INITSTR_DK)))
474                  data_type=ASCII_AI;
475
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;
486     else
487     {   discard_token_location(beginning_debug_location);
488         if (array_flag)
489             ebf_error
490               ("'->', '-->', 'string', 'table' or 'buffer'", token_text);
491         else
492             ebf_error
493               ("'=', '->', '-->', 'string', 'table' or 'buffer'", token_text);
494         panic_mode_error_recovery();
495         return;
496     }
497
498     array_entry_size=1;
499     if ((array_type==WORD_ARRAY) || (array_type==TABLE_ARRAY))
500         array_entry_size=WORDSIZE;
501
502     get_next_token();
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");
506         put_token_back();
507         return;
508     }
509
510     switch(data_type)
511     {   case UNSPECIFIED_AI:
512             if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
513                 data_type = BRACKET_AI;
514             else
515             {   data_type = NULLS_AI;
516                 if (token_type == DQ_TT) data_type = ASCII_AI;
517                 get_next_token();
518                 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
519                     data_type = DATA_AI;
520                 put_token_back();
521                 put_token_back();
522             }
523             break;
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;
527     }
528
529     /*  Leave room to write the array size in later, if string/table array   */
530     
531     extraspace = 0;
532     if ((array_type==STRING_ARRAY) || (array_type==TABLE_ARRAY))
533         extraspace += array_entry_size;
534     if (array_type==BUFFER_ARRAY)
535         extraspace += WORDSIZE;
536     
537     if (!is_static) {
538         orig_area_size = dynamic_array_area_size;
539         array_base = dynamic_array_area_size;
540         dynamic_array_area_size += extraspace;
541     }
542     else {
543         orig_area_size = static_array_area_size;
544         array_base = static_array_area_size;
545         static_array_area_size += extraspace;
546     }
547
548     array_types[no_arrays] = array_type;
549     array_locs[no_arrays] = is_static;
550
551     switch(data_type)
552     {
553         case NULLS_AI:
554
555             AO = parse_expression(CONSTANT_CONTEXT);
556
557             CalculatedArraySize:
558
559             if (AO.marker != 0)
560             {   error("Array sizes must be known now, not defined later");
561                 break;
562             }
563
564             if (!glulx_mode) {
565                 if ((AO.value <= 0) || (AO.value >= 32768))
566                 {   error("An array must have between 1 and 32767 entries");
567                     AO.value = 1;
568                 }
569             }
570             else {
571                 if (AO.value <= 0 || (AO.value & 0x80000000))
572                 {   error("An array may not have 0 or fewer entries");
573                     AO.value = 1;
574                 }
575             }
576
577             {   for (i=0; i<AO.value; i++) array_entry(i, is_static, zero_operand);
578             }
579             break;
580
581         case DATA_AI:
582
583             /*  In this case the array is initialised to the sequence of
584                 constant values supplied on the same line                    */
585
586             i=0;
587             do
588             {   get_next_token();
589                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
590                     break;
591
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 \"]\"");
598                     return;
599                 }
600                 put_token_back();
601
602                 AO = parse_expression(ARRAY_CONTEXT);
603
604                 if (i == 0)
605                 {   get_next_token();
606                     put_token_back();
607                     if ((token_type == SEP_TT)
608                         && (token_value == SEMICOLON_SEP))
609                     {   data_type = NULLS_AI;
610                         goto CalculatedArraySize;
611                     }
612                 }
613
614                 array_entry(i, is_static, AO);
615                 i++;
616             } while (TRUE);
617             put_token_back();
618             break;
619
620         case ASCII_AI:
621
622             /*  In this case the array is initialised to the ASCII values of
623                 the characters of a given "quoted string"                    */
624
625             get_next_token();
626             if (token_type != DQ_TT)
627             {   ebf_error("literal text in double-quotes", token_text);
628                 token_text = "error";
629             }
630
631             {   assembly_operand chars;
632
633                 int j;
634                 INITAO(&chars);
635                 for (i=0,j=0; token_text[j]!=0; i++,j+=textual_form_length)
636                 {
637                     int32 unicode; int zscii;
638                     unicode = text_to_unicode(token_text+j);
639                     if (glulx_mode)
640                     {
641                         if (array_entry_size == 1 && (unicode < 0 || unicode >= 256))
642                         {
643                             error("Unicode characters beyond Latin-1 cannot be used in a byte array");
644                         }
645                         else
646                         {
647                             chars.value = unicode;
648                         }
649                     }
650                     else  /* Z-code */
651                     {                          
652                         zscii = unicode_to_zscii(unicode);
653                         if ((zscii != 5) && (zscii < 0x100)) chars.value = zscii;
654                         else
655                         {   unicode_char_error("Character can only be used if declared in \
656 advance as part of 'Zcharacter table':", unicode);
657                             chars.value = '?';
658                         }
659                     }
660                     chars.marker = 0;
661                     set_constant_ot(&chars);
662                     array_entry(i, is_static, chars);
663                 }
664             }
665             break;
666
667         case BRACKET_AI:
668
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 ]                              */
672
673             i = 0;
674             while (TRUE)
675             {   get_next_token();
676                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
677                     continue;
678                 if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP))
679                     break;
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
683                         a new routine                                        */
684
685                     ebf_error("']'", token_text);
686                     put_token_back(); break;
687                 }
688                 put_token_back();
689                 array_entry(i, is_static, parse_expression(ARRAY_CONTEXT));
690                 i++;
691             }
692     }
693
694     finish_array(i, is_static);
695
696     if (debugfile_switch)
697     {
698         int32 new_area_size;
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);
705         debug_file_printf
706             ("<byte-count>%d</byte-count>",
707              new_area_size - array_base);
708         debug_file_printf
709             ("<bytes-per-element>%d</bytes-per-element>",
710              array_entry_size);
711         debug_file_printf
712             ("<zeroth-element-holds-length>%s</zeroth-element-holds-length>",
713              (array_type == STRING_ARRAY || array_type == TABLE_ARRAY) ?
714                  "true" : "false");
715         get_next_token();
716         write_debug_locations(get_token_location_end(beginning_debug_location));
717         put_token_back();
718         debug_file_printf("</array>");
719     }
720
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;
724 }
725
726 extern int32 begin_table_array(void)
727 {
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.) */
731
732     array_base = dynamic_array_area_size;
733     array_entry_size = WORDSIZE;
734
735     /*  Leave room to write the array size in later                          */
736
737     dynamic_array_area_size += array_entry_size;
738
739     if (!glulx_mode)
740         return array_base;
741     else
742         return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
743 }
744
745 extern int32 begin_word_array(void)
746 {
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.) */
750
751     array_base = dynamic_array_area_size;
752     array_entry_size = WORDSIZE;
753
754     if (!glulx_mode)
755         return array_base;
756     else
757         return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
758 }
759
760 /* ========================================================================= */
761 /*   Data structure management routines                                      */
762 /* ------------------------------------------------------------------------- */
763
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;
769 }
770
771 extern void arrays_begin_pass(void)
772 {   no_arrays = 0; 
773     if (!glulx_mode)
774         no_globals=0; 
775     else
776         no_globals=11;
777     dynamic_array_area_size = WORDSIZE * MAX_GLOBAL_VARIABLES;
778     static_array_area_size = 0;
779 }
780
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, 
791         "global values");
792 }
793
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");
802 }
803
804 /* ========================================================================= */