fc4f7af2c5e6abb7f1f951920138bf7dbdfd991a
[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 /* Copyright (c) Graham Nelson 1993 - 2020                                   */
7 /*                                                                           */
8 /* This file is part of Inform.                                              */
9 /*                                                                           */
10 /* Inform is free software: you can redistribute it and/or modify            */
11 /* it under the terms of the GNU General Public License as published by      */
12 /* the Free Software Foundation, either version 3 of the License, or         */
13 /* (at your option) any later version.                                       */
14 /*                                                                           */
15 /* Inform is distributed in the hope that it will be useful,                 */
16 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
17 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
18 /* GNU General Public License for more details.                              */
19 /*                                                                           */
20 /* You should have received a copy of the GNU General Public License         */
21 /* along with Inform. If not, see https://gnu.org/licenses/                  */
22 /*                                                                           */
23 /* ------------------------------------------------------------------------- */
24
25 #include "header.h"
26
27 /* ------------------------------------------------------------------------- */
28 /*   Arrays defined below:                                                   */
29 /*                                                                           */
30 /*    int    dynamic_array_area[]         Initial values for the bytes of    */
31 /*                                        the dynamic array area             */
32 /*    int    static_array_area[]          Initial values for the bytes of    */
33 /*                                        the static array area              */
34 /*    int32  global_initial_value[n]      The initialised value of the nth   */
35 /*                                        global variable (counting 0 - 239) */
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.  Owing to a poor choice of name  */
40 /*   some years ago, this is also called the "static data area", which is    */
41 /*   why the memory setting for its maximum extent is "MAX_STATIC_DATA".     */
42 /*                                                                           */
43 /*   In Glulx, that 240 is changed to MAX_GLOBAL_VAR_NUMBER, and we take     */
44 /*   correspondingly more space for the globals. This *really* ought to be   */
45 /*   split into two segments.                                                */
46 /*                                                                           */
47 /*   We can also store arrays (but not globals) into static memory (ROM).    */
48 /*   The storage for these goes, unsurprisingly, into static_array_area --   */
49 /*   a separate allocation of MAX_STATIC_DATA bytes.                         */
50 /* ------------------------------------------------------------------------- */
51 int     *dynamic_array_area;           /* See above                          */
52 int32   *global_initial_value;
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 int dynamic_array_area_size;           /* Size in bytes                      */
62
63 int     *static_array_area;
64 int static_array_area_size;
65
66 int no_arrays;
67 int32   *array_symbols;
68 int     *array_sizes, *array_types, *array_locs;
69 /* array_sizes[N] gives the length of array N; array_types[N] is one of
70    the constants BYTE_ARRAY, WORD_ARRAY, etc; array_locs[N] is true for
71    static arrays, false for dynamic arrays.                                  */
72
73 static int array_entry_size,           /* 1 for byte array, 2 for word array */
74            array_base;                 /* Offset in dynamic array area of the
75                                           array being constructed.  During the
76                                           same time, dynamic_array_area_size
77                                           is the offset of the initial entry
78                                           in the array: so for "table" and
79                                           "string" arrays, these numbers are
80                                           different (by 2 and 1 bytes resp)  */
81
82                                        /* In Glulx, of course, that will be
83                                           4 instead of 2.                    */
84
85 extern void finish_array(int32 i, int is_static)
86 {
87   int *area;
88   int area_size;
89   
90   if (!is_static) {
91       area = dynamic_array_area;
92       area_size = dynamic_array_area_size;
93   }
94   else {
95       area = static_array_area;
96       area_size = static_array_area_size;
97   }
98   
99     /*  Write the array size into the 0th byte/word of the array, if it's
100         a "table" or "string" array                                          */
101   if (!glulx_mode) {
102
103     if (array_base != area_size)
104     {   if (area_size-array_base==2)
105         {   area[array_base]   = i/256;
106             area[array_base+1] = i%256;
107         }
108         else
109         {   if (i>=256)
110                 error("A 'string' array can have at most 256 entries");
111             area[array_base] = i;
112         }
113     }
114
115   }
116   else {
117     if (array_base != area_size)
118     {   if (area_size-array_base==4)
119         {   
120             area[array_base]   = (i >> 24) & 0xFF;
121             area[array_base+1] = (i >> 16) & 0xFF;
122             area[array_base+2] = (i >> 8) & 0xFF;
123             area[array_base+3] = (i) & 0xFF;
124         }
125         else
126         {   if (i>=256)
127                 error("A 'string' array can have at most 256 entries");
128             area[array_base] = i;
129         }
130     }
131     
132   }
133
134   /*  Move on the static/dynamic array size so that it now points to the
135       next available free space                                              */
136
137   if (!is_static) {
138       dynamic_array_area_size += i*array_entry_size;
139   }
140   else {
141       static_array_area_size += i*array_entry_size;
142   }
143
144 }
145
146 extern void array_entry(int32 i, int is_static, assembly_operand VAL)
147 {
148   int *area;
149   int area_size;
150   
151   if (!is_static) {
152       area = dynamic_array_area;
153       area_size = dynamic_array_area_size;
154   }
155   else {
156       area = static_array_area;
157       area_size = static_array_area_size;
158   }
159   
160   if (!glulx_mode) {
161     /*  Array entry i (initial entry has i=0) is set to Z-machine value j    */
162
163     if (area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
164         memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
165
166     if (array_entry_size==1)
167     {   area[area_size+i] = (VAL.value)%256;
168
169         if (VAL.marker != 0)
170            error("Entries in byte arrays and strings must be known constants");
171
172         /*  If the entry is too large for a byte array, issue a warning
173             and truncate the value                                           */
174         else
175         if (VAL.value >= 256)
176             warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
177     }
178     else
179     {
180         int32 addr = area_size + 2*i;
181         area[addr]   = (VAL.value)/256;
182         area[addr+1] = (VAL.value)%256;
183         if (VAL.marker != 0) {
184             if (!is_static) {
185                 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
186                     addr);
187             }
188             else {
189                 backpatch_zmachine(VAL.marker, STATIC_ARRAY_ZA,
190                     addr);
191             }
192         }
193     }
194   }
195   else {
196     /*  Array entry i (initial entry has i=0) is set to value j              */
197
198     if (area_size+(i+1)*array_entry_size > MAX_STATIC_DATA)
199         memoryerror("MAX_STATIC_DATA", MAX_STATIC_DATA);
200
201     if (array_entry_size==1)
202     {   area[area_size+i] = (VAL.value) & 0xFF;
203
204         if (VAL.marker != 0)
205            error("Entries in byte arrays and strings must be known constants");
206
207         /*  If the entry is too large for a byte array, issue a warning
208             and truncate the value                                           */
209         else
210         if (VAL.value >= 256)
211             warning("Entry in '->', 'string' or 'buffer' array not in range 0 to 255");
212     }
213     else if (array_entry_size==4)
214     {
215         int32 addr = area_size + 4*i;
216         area[addr]   = (VAL.value >> 24) & 0xFF;
217         area[addr+1] = (VAL.value >> 16) & 0xFF;
218         area[addr+2] = (VAL.value >> 8) & 0xFF;
219         area[addr+3] = (VAL.value) & 0xFF;
220         if (VAL.marker != 0) {
221             if (!is_static) {
222                 backpatch_zmachine(VAL.marker, DYNAMIC_ARRAY_ZA,
223                     addr - 4*MAX_GLOBAL_VARIABLES);
224             }
225             else {
226                 /* We can't use backpatch_zmachine() because that only applies to RAM. Instead we add an entry to staticarray_backpatch_table.
227                    A backpatch entry is five bytes: *_MV followed by the array offset (in static array area). */
228                 write_byte_to_memory_block(&staticarray_backpatch_table,
229                     staticarray_backpatch_size++,
230                     VAL.marker);
231                 write_byte_to_memory_block(&staticarray_backpatch_table,
232                     staticarray_backpatch_size++, ((addr >> 24) & 0xFF));
233                 write_byte_to_memory_block(&staticarray_backpatch_table,
234                     staticarray_backpatch_size++, ((addr >> 16) & 0xFF));
235                 write_byte_to_memory_block(&staticarray_backpatch_table,
236                     staticarray_backpatch_size++, ((addr >> 8) & 0xFF));
237                 write_byte_to_memory_block(&staticarray_backpatch_table,
238                     staticarray_backpatch_size++, (addr & 0xFF));
239             }
240         }
241     }
242     else
243     {
244         error("Somehow created an array of shorts");
245     }
246   }
247 }
248
249 /* ------------------------------------------------------------------------- */
250 /*   Global and Array directives.                                            */
251 /*                                                                           */
252 /*      Global <variablename> |                                              */
253 /*                            | = <value>                                    */
254 /*                            | <array specification>                        */
255 /*                                                                           */
256 /*      Array <arrayname> [static] <array specification>                     */
257 /*                                                                           */
258 /*   where an array specification is:                                        */
259 /*                                                                           */
260 /*      | ->       |  <number-of-entries>                                    */
261 /*      | -->      |  <entry-1> ... <entry-n>                                */
262 /*      | string   |  [ <entry-1> [,] [;] <entry-2> ... <entry-n> ];         */
263 /*      | table                                                              */
264 /*      | buffer                                                             */
265 /*                                                                           */
266 /*   The "static" keyword (arrays only) places the array in static memory.   */
267 /*                                                                           */
268 /* ------------------------------------------------------------------------- */
269
270 extern void set_variable_value(int i, int32 v)
271 {   global_initial_value[i]=v;
272 }
273
274 /*  There are four ways to initialise arrays:                                */
275
276 #define UNSPECIFIED_AI  -1
277 #define NULLS_AI        0
278 #define DATA_AI         1
279 #define ASCII_AI        2
280 #define BRACKET_AI      3
281
282 extern void make_global(int array_flag, int name_only)
283 {
284     /*  array_flag is TRUE for an Array directive, FALSE for a Global;
285         name_only is only TRUE for parsing an imported variable name, so
286         array_flag is always FALSE in that case.                             */
287
288     int32 i;
289     int array_type, data_type;
290     int is_static = FALSE;
291     assembly_operand AO;
292
293     int32 global_symbol;
294     const char *global_name;
295     debug_location_beginning beginning_debug_location =
296         get_token_location_beginning();
297
298     directive_keywords.enabled = FALSE;
299     get_next_token();
300     i = token_value;
301     global_symbol = i;
302     global_name = token_text;
303
304     if (!glulx_mode) {
305         if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T)
306             && (svals[i] >= LOWEST_SYSTEM_VAR_NUMBER))
307             goto RedefinitionOfSystemVar;
308     }
309     else {
310         if ((token_type==SYMBOL_TT) && (stypes[i]==GLOBAL_VARIABLE_T))
311             goto RedefinitionOfSystemVar;
312     }
313
314     if ((token_type != SYMBOL_TT) || (!(sflags[i] & UNKNOWN_SFLAG)))
315     {   discard_token_location(beginning_debug_location);
316         if (array_flag)
317             ebf_error("new array name", token_text);
318         else ebf_error("new global variable name", token_text);
319         panic_mode_error_recovery(); return;
320     }
321
322     if ((!array_flag) && (sflags[i] & USED_SFLAG))
323         error_named("Variable must be defined before use:", token_text);
324
325     directive_keywords.enabled = TRUE;
326     get_next_token();
327     directive_keywords.enabled = FALSE;
328     if ((token_type==DIR_KEYWORD_TT)&&(token_value==STATIC_DK)) {
329         if (array_flag) {
330             is_static = TRUE;
331         }
332         else {
333             error("Global variables cannot be static");
334         }
335     }
336     else {
337         put_token_back();
338     }
339     
340     if (array_flag)
341     {   if (!is_static) {
342             if (!glulx_mode)
343                 assign_symbol(i, dynamic_array_area_size, ARRAY_T);
344             else
345                 assign_symbol(i, 
346                     dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES, ARRAY_T);
347         }
348         else {
349             assign_symbol(i, static_array_area_size, STATIC_ARRAY_T);
350         }
351         if (no_arrays == MAX_ARRAYS)
352             memoryerror("MAX_ARRAYS", MAX_ARRAYS);
353         array_symbols[no_arrays] = i;
354     }
355     else
356     {   if (!glulx_mode && no_globals==233)
357         {   discard_token_location(beginning_debug_location);
358             error("All 233 global variables already declared");
359             panic_mode_error_recovery();
360             return;
361         }
362         if (glulx_mode && no_globals==MAX_GLOBAL_VARIABLES)
363         {   discard_token_location(beginning_debug_location);
364             memoryerror("MAX_GLOBAL_VARIABLES", MAX_GLOBAL_VARIABLES);
365             panic_mode_error_recovery();
366             return;
367         }
368
369         variable_tokens[MAX_LOCAL_VARIABLES+no_globals] = i;
370         assign_symbol(i, MAX_LOCAL_VARIABLES+no_globals, GLOBAL_VARIABLE_T);
371         variable_tokens[svals[i]] = i;
372
373         if (name_only) import_symbol(i);
374         else global_initial_value[no_globals++]=0;
375     }
376
377     directive_keywords.enabled = TRUE;
378
379     RedefinitionOfSystemVar:
380
381     if (name_only)
382     {   discard_token_location(beginning_debug_location);
383         return;
384     }
385
386     get_next_token();
387
388     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
389     {   if (array_flag)
390         {   discard_token_location(beginning_debug_location);
391             ebf_error("array definition", token_text);
392         }
393         put_token_back();
394         if (debugfile_switch && !array_flag)
395         {   debug_file_printf("<global-variable>");
396             debug_file_printf("<identifier>%s</identifier>", global_name);
397             debug_file_printf("<address>");
398             write_debug_global_backpatch(svals[global_symbol]);
399             debug_file_printf("</address>");
400             write_debug_locations
401                 (get_token_location_end(beginning_debug_location));
402             debug_file_printf("</global-variable>");
403         }
404         return;
405     }
406
407     if (!array_flag)
408     {
409         /* is_static is always false in this case */
410         if ((token_type == SEP_TT) && (token_value == SETEQUALS_SEP))
411         {   AO = parse_expression(CONSTANT_CONTEXT);
412             if (!glulx_mode) {
413                 if (AO.marker != 0)
414                     backpatch_zmachine(AO.marker, DYNAMIC_ARRAY_ZA,
415                         2*(no_globals-1));
416             }
417             else {
418             if (AO.marker != 0)
419                 backpatch_zmachine(AO.marker, GLOBALVAR_ZA,
420                 4*(no_globals-1));
421             }
422             global_initial_value[no_globals-1] = AO.value;
423             if (debugfile_switch)
424             {   debug_file_printf("<global-variable>");
425                 debug_file_printf("<identifier>%s</identifier>", global_name);
426                 debug_file_printf("<address>");
427                 write_debug_global_backpatch(svals[global_symbol]);
428                 debug_file_printf("</address>");
429                 write_debug_locations
430                     (get_token_location_end(beginning_debug_location));
431                 debug_file_printf("</global-variable>");
432             }
433             return;
434         }
435
436         obsolete_warning("more modern to use 'Array', not 'Global'");
437
438         if (!glulx_mode) {
439             backpatch_zmachine(ARRAY_MV, DYNAMIC_ARRAY_ZA, 2*(no_globals-1));
440             global_initial_value[no_globals-1]
441                 = dynamic_array_area_size+variables_offset;
442         }
443         else {
444             backpatch_zmachine(ARRAY_MV, GLOBALVAR_ZA, 4*(no_globals-1));
445             global_initial_value[no_globals-1]
446                 = dynamic_array_area_size - 4*MAX_GLOBAL_VARIABLES;
447         }
448     }
449
450     array_type = BYTE_ARRAY; data_type = UNSPECIFIED_AI;
451
452          if ((!array_flag) &&
453              ((token_type==DIR_KEYWORD_TT)&&(token_value==DATA_DK)))
454                  data_type=NULLS_AI;
455     else if ((!array_flag) &&
456              ((token_type==DIR_KEYWORD_TT)&&(token_value==INITIAL_DK)))
457                  data_type=DATA_AI;
458     else if ((!array_flag) &&
459              ((token_type==DIR_KEYWORD_TT)&&(token_value==INITSTR_DK)))
460                  data_type=ASCII_AI;
461
462     else if ((token_type==SEP_TT)&&(token_value==ARROW_SEP))
463              array_type = BYTE_ARRAY;
464     else if ((token_type==SEP_TT)&&(token_value==DARROW_SEP))
465              array_type = WORD_ARRAY;
466     else if ((token_type==DIR_KEYWORD_TT)&&(token_value==STRING_DK))
467              array_type = STRING_ARRAY;
468     else if ((token_type==DIR_KEYWORD_TT)&&(token_value==TABLE_DK))
469              array_type = TABLE_ARRAY;
470     else if ((token_type==DIR_KEYWORD_TT)&&(token_value==BUFFER_DK))
471              array_type = BUFFER_ARRAY;
472     else
473     {   discard_token_location(beginning_debug_location);
474         if (array_flag)
475             ebf_error
476               ("'->', '-->', 'string', 'table' or 'buffer'", token_text);
477         else
478             ebf_error
479               ("'=', '->', '-->', 'string', 'table' or 'buffer'", token_text);
480         panic_mode_error_recovery();
481         return;
482     }
483
484     array_entry_size=1;
485     if ((array_type==WORD_ARRAY) || (array_type==TABLE_ARRAY))
486         array_entry_size=WORDSIZE;
487
488     get_next_token();
489     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
490     {   discard_token_location(beginning_debug_location);
491         error("No array size or initial values given");
492         put_token_back();
493         return;
494     }
495
496     switch(data_type)
497     {   case UNSPECIFIED_AI:
498             if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
499                 data_type = BRACKET_AI;
500             else
501             {   data_type = NULLS_AI;
502                 if (token_type == DQ_TT) data_type = ASCII_AI;
503                 get_next_token();
504                 if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)))
505                     data_type = DATA_AI;
506                 put_token_back();
507                 put_token_back();
508             }
509             break;
510         case NULLS_AI: obsolete_warning("use '->' instead of 'data'"); break;
511         case DATA_AI:  obsolete_warning("use '->' instead of 'initial'"); break;
512         case ASCII_AI: obsolete_warning("use '->' instead of 'initstr'"); break;
513     }
514
515     /*  Leave room to write the array size in later, if string/table array   */
516     
517     int extraspace = 0;
518     if ((array_type==STRING_ARRAY) || (array_type==TABLE_ARRAY))
519         extraspace += array_entry_size;
520     if (array_type==BUFFER_ARRAY)
521         extraspace += WORDSIZE;
522
523     int orig_area_size;
524     
525     if (!is_static) {
526         orig_area_size = dynamic_array_area_size;
527         array_base = dynamic_array_area_size;
528         dynamic_array_area_size += extraspace;
529     }
530     else {
531         orig_area_size = static_array_area_size;
532         array_base = static_array_area_size;
533         static_array_area_size += extraspace;
534     }
535
536     array_types[no_arrays] = array_type;
537     array_locs[no_arrays] = is_static;
538
539     switch(data_type)
540     {
541         case NULLS_AI:
542
543             AO = parse_expression(CONSTANT_CONTEXT);
544
545             CalculatedArraySize:
546
547             if (module_switch && (AO.marker != 0))
548             {   error("Array sizes must be known now, not externally defined");
549                 break;
550             }
551
552             if (!glulx_mode) {
553                 if ((AO.value <= 0) || (AO.value >= 32768))
554                 {   error("An array must have between 1 and 32767 entries");
555                     AO.value = 1;
556                 }
557             }
558             else {
559                 if (AO.value <= 0 || (AO.value & 0x80000000))
560                 {   error("An array may not have 0 or fewer entries");
561                     AO.value = 1;
562                 }
563             }
564
565             {   for (i=0; i<AO.value; i++) array_entry(i, is_static, zero_operand);
566             }
567             break;
568
569         case DATA_AI:
570
571             /*  In this case the array is initialised to the sequence of
572                 constant values supplied on the same line                    */
573
574             i=0;
575             do
576             {   get_next_token();
577                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
578                     break;
579
580                 if ((token_type == SEP_TT)
581                     && ((token_value == OPEN_SQUARE_SEP)
582                         || (token_value == CLOSE_SQUARE_SEP)))
583                 {   discard_token_location(beginning_debug_location);
584                     error("Missing ';' to end the initial array values "
585                           "before \"[\" or \"]\"");
586                     return;
587                 }
588                 put_token_back();
589
590                 AO = parse_expression(ARRAY_CONTEXT);
591
592                 if (i == 0)
593                 {   get_next_token();
594                     put_token_back();
595                     if ((token_type == SEP_TT)
596                         && (token_value == SEMICOLON_SEP))
597                     {   data_type = NULLS_AI;
598                         goto CalculatedArraySize;
599                     }
600                 }
601
602                 array_entry(i, is_static, AO);
603                 i++;
604             } while (TRUE);
605             put_token_back();
606             break;
607
608         case ASCII_AI:
609
610             /*  In this case the array is initialised to the ASCII values of
611                 the characters of a given "quoted string"                    */
612
613             get_next_token();
614             if (token_type != DQ_TT)
615             {   ebf_error("literal text in double-quotes", token_text);
616                 token_text = "error";
617             }
618
619             {   assembly_operand chars;
620
621                 int j;
622                 INITAO(&chars);
623                 for (i=0,j=0; token_text[j]!=0; i++,j+=textual_form_length)
624                 {
625                     int32 unicode; int zscii;
626                     unicode = text_to_unicode(token_text+j);
627                     if (glulx_mode)
628                     {
629                         if (array_entry_size == 1 && (unicode < 0 || unicode >= 256))
630                         {
631                             error("Unicode characters beyond Latin-1 cannot be used in a byte array");
632                         }
633                         else
634                         {
635                             chars.value = unicode;
636                         }
637                     }
638                     else  /* Z-code */
639                     {                          
640                         zscii = unicode_to_zscii(unicode);
641                         if ((zscii != 5) && (zscii < 0x100)) chars.value = zscii;
642                         else
643                         {   unicode_char_error("Character can only be used if declared in \
644 advance as part of 'Zcharacter table':", unicode);
645                             chars.value = '?';
646                         }
647                     }
648                     chars.marker = 0;
649                     set_constant_ot(&chars);
650                     array_entry(i, is_static, chars);
651                 }
652             }
653             break;
654
655         case BRACKET_AI:
656
657             /*  In this case the array is initialised to the sequence of
658                 constant values given over a whole range of compiler-lines,
659                 between square brackets [ and ]                              */
660
661             i = 0;
662             while (TRUE)
663             {   get_next_token();
664                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
665                     continue;
666                 if ((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP))
667                     break;
668                 if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
669                 {   /*  Minimal error recovery: we assume that a ] has
670                         been missed, and the programmer is now starting
671                         a new routine                                        */
672
673                     ebf_error("']'", token_text);
674                     put_token_back(); break;
675                 }
676                 put_token_back();
677                 array_entry(i, is_static, parse_expression(ARRAY_CONTEXT));
678                 i++;
679             }
680     }
681
682     finish_array(i, is_static);
683
684     if (debugfile_switch)
685     {   debug_file_printf("<array>");
686         debug_file_printf("<identifier>%s</identifier>", global_name);
687         debug_file_printf("<value>");
688         write_debug_array_backpatch(svals[global_symbol]);
689         debug_file_printf("</value>");
690         int32 new_area_size = (!is_static ? dynamic_array_area_size : static_array_area_size);
691         debug_file_printf
692             ("<byte-count>%d</byte-count>",
693              new_area_size - array_base);
694         debug_file_printf
695             ("<bytes-per-element>%d</bytes-per-element>",
696              array_entry_size);
697         debug_file_printf
698             ("<zeroth-element-holds-length>%s</zeroth-element-holds-length>",
699              (array_type == STRING_ARRAY || array_type == TABLE_ARRAY) ?
700                  "true" : "false");
701         get_next_token();
702         write_debug_locations(get_token_location_end(beginning_debug_location));
703         put_token_back();
704         debug_file_printf("</array>");
705     }
706
707     if ((array_type==BYTE_ARRAY) || (array_type==WORD_ARRAY)) i--;
708     if (array_type==BUFFER_ARRAY) i+=WORDSIZE-1;
709     array_sizes[no_arrays++] = i;
710 }
711
712 extern int32 begin_table_array(void)
713 {
714     /*  The "box" statement needs to be able to construct table
715         arrays of strings like this. (Static data, but we create a dynamic
716         array for maximum backwards compatibility.) */
717
718     array_base = dynamic_array_area_size;
719     array_entry_size = WORDSIZE;
720
721     /*  Leave room to write the array size in later                          */
722
723     dynamic_array_area_size += array_entry_size;
724
725     if (!glulx_mode)
726         return array_base;
727     else
728         return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
729 }
730
731 extern int32 begin_word_array(void)
732 {
733     /*  The "random(a, b, ...)" function needs to be able to construct
734         word arrays like this. (Static data, but we create a dynamic
735         array for maximum backwards compatibility.) */
736
737     array_base = dynamic_array_area_size;
738     array_entry_size = WORDSIZE;
739
740     if (!glulx_mode)
741         return array_base;
742     else
743         return array_base - WORDSIZE * MAX_GLOBAL_VARIABLES;
744 }
745
746 /* ========================================================================= */
747 /*   Data structure management routines                                      */
748 /* ------------------------------------------------------------------------- */
749
750 extern void init_arrays_vars(void)
751 {   dynamic_array_area = NULL;
752     static_array_area = NULL;
753     global_initial_value = NULL;
754     array_sizes = NULL; array_symbols = NULL; array_types = NULL;
755 }
756
757 extern void arrays_begin_pass(void)
758 {   no_arrays = 0; 
759     if (!glulx_mode)
760         no_globals=0; 
761     else
762         no_globals=11;
763     dynamic_array_area_size = WORDSIZE * MAX_GLOBAL_VARIABLES;
764     static_array_area_size = 0;
765 }
766
767 extern void arrays_allocate_arrays(void)
768 {   dynamic_array_area = my_calloc(sizeof(int), MAX_STATIC_DATA, 
769         "dynamic array data");
770     static_array_area = my_calloc(sizeof(int), MAX_STATIC_DATA, 
771         "static array data");
772     array_sizes = my_calloc(sizeof(int), MAX_ARRAYS, "array sizes");
773     array_types = my_calloc(sizeof(int), MAX_ARRAYS, "array types");
774     array_locs = my_calloc(sizeof(int), MAX_ARRAYS, "array locations");
775     array_symbols = my_calloc(sizeof(int32), MAX_ARRAYS, "array symbols");
776     global_initial_value = my_calloc(sizeof(int32), MAX_GLOBAL_VARIABLES, 
777         "global values");
778 }
779
780 extern void arrays_free_arrays(void)
781 {   my_free(&dynamic_array_area, "dynamic array data");
782     my_free(&static_array_area, "static array data");
783     my_free(&global_initial_value, "global values");
784     my_free(&array_sizes, "array sizes");
785     my_free(&array_types, "array types");
786     my_free(&array_locs, "array locations");
787     my_free(&array_symbols, "array sizes");
788 }
789
790 /* ========================================================================= */