xref: /netbsd-src/external/bsd/bc/dist/storage.c (revision ed857e95db3fec367bb6764523110eb0ac99cb49)
1 /*	$NetBSD: storage.c,v 1.1 2017/04/10 02:28:23 phil Exp $ */
2 
3 /*
4  * Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
5  * Copyright (C) 2016-2017 Philip A. Nelson.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The names Philip A. Nelson and Free Software Foundation may not be
18  *    used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY PHILIP A. NELSON ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL PHILIP A. NELSON OR THE FREE SOFTWARE FOUNDATION BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /* storage.c:  Code and data storage manipulations.  This includes labels. */
35 
36 #include "bcdefs.h"
37 #include "proto.h"
38 
39 /* Local prototypes */
40 static bc_array_node *copy_tree (bc_array_node *ary_node, int depth);
41 static bc_array *copy_array (bc_array *ary);
42 
43 
44 /* Initialize the storage at the beginning of the run. */
45 
46 void
init_storage(void)47 init_storage (void)
48 {
49 
50   /* Functions: we start with none and ask for more. */
51   f_count = 0;
52   more_functions ();
53   f_names[0] = strdup("(main)");
54 
55   /* Variables. */
56   v_count = 0;
57   more_variables ();
58 
59   /* Arrays. */
60   a_count = 0;
61   more_arrays ();
62 
63   /* Other things... */
64   ex_stack = NULL;
65   fn_stack = NULL;
66   i_base = 10;
67   o_base = 10;
68   scale  = 0;
69 #if defined(READLINE) || defined(LIBEDIT)
70   n_history = -1;
71 #endif
72   c_code = FALSE;
73   bc_init_numbers();
74 }
75 
76 /* Three functions for increasing the number of functions, variables, or
77    arrays that are needed.  This adds another 32 of the requested object. */
78 
79 void
more_functions(void)80 more_functions (void)
81 {
82   int old_count;
83   int indx;
84   bc_function *old_f;
85   bc_function *f;
86   char **old_names;
87 
88   /* Save old information. */
89   old_count = f_count;
90   old_f = functions;
91   old_names = f_names;
92 
93   /* Add a fixed amount and allocate new space. */
94   f_count += STORE_INCR;
95   functions = bc_malloc (f_count*sizeof (bc_function));
96   f_names = bc_malloc (f_count*sizeof (char *));
97 
98   /* Copy old ones. */
99   for (indx = 0; indx < old_count; indx++)
100     {
101       functions[indx] = old_f[indx];
102       f_names[indx] = old_names[indx];
103     }
104 
105   /* Initialize the new ones. */
106   for (; indx < f_count; indx++)
107     {
108       f = &functions[indx];
109       f->f_defined = FALSE;
110       f->f_void = FALSE;
111       f->f_body = bc_malloc (BC_START_SIZE);
112       f->f_body_size = BC_START_SIZE;
113       f->f_code_size = 0;
114       f->f_label = NULL;
115       f->f_autos = NULL;
116       f->f_params = NULL;
117     }
118 
119   /* Free the old elements. */
120   if (old_count != 0)
121     {
122       free (old_f);
123       free (old_names);
124     }
125 }
126 
127 void
more_variables(void)128 more_variables (void)
129 {
130   int indx;
131   int old_count;
132   bc_var **old_var;
133   char **old_names;
134 
135   /* Save the old values. */
136   old_count = v_count;
137   old_var = variables;
138   old_names = v_names;
139 
140   /* Increment by a fixed amount and allocate. */
141   v_count += STORE_INCR;
142   variables = bc_malloc (v_count*sizeof(bc_var *));
143   v_names = bc_malloc (v_count*sizeof(char *));
144 
145   /* Copy the old variables. */
146   for (indx = 3; indx < old_count; indx++)
147     {
148       variables[indx] = old_var[indx];
149       v_names[indx] = old_names[indx];
150     }
151 
152   /* Initialize the new elements. */
153   for (; indx < v_count; indx++)
154     variables[indx] = NULL;
155 
156   /* Free the old elements. */
157   if (old_count != 0)
158     {
159       free (old_var);
160       free (old_names);
161     }
162 }
163 
164 void
more_arrays(void)165 more_arrays (void)
166 {
167   int indx;
168   int old_count;
169   bc_var_array **old_ary;
170   char **old_names;
171 
172   /* Save the old values. */
173   old_count = a_count;
174   old_ary = arrays;
175   old_names = a_names;
176 
177   /* Increment by a fixed amount and allocate. */
178   a_count += STORE_INCR;
179   arrays = bc_malloc (a_count*sizeof(bc_var_array *));
180   a_names = bc_malloc (a_count*sizeof(char *));
181 
182   /* Copy the old arrays. */
183   for (indx = 1; indx < old_count; indx++)
184     {
185       arrays[indx] = old_ary[indx];
186       a_names[indx] = old_names[indx];
187     }
188 
189 
190   /* Initialize the new elements. */
191   for (; indx < a_count; indx++)
192     arrays[indx] = NULL;
193 
194   /* Free the old elements. */
195   if (old_count != 0)
196     {
197       free (old_ary);
198       free (old_names);
199     }
200 }
201 
202 
203 /* clear_func clears out function FUNC and makes it ready to redefine. */
204 
205 void
clear_func(int func)206 clear_func (int func)
207 {
208   bc_function *f;
209   bc_label_group *lg;
210 
211   /* Set the pointer to the function. */
212   f = &functions[func];
213   f->f_defined = FALSE;
214   /* XXX restore f_body to initial size??? */
215   f->f_code_size = 0;
216   if (f->f_autos != NULL)
217     {
218       free_args (f->f_autos);
219       f->f_autos = NULL;
220     }
221   if (f->f_params != NULL)
222     {
223       free_args (f->f_params);
224       f->f_params = NULL;
225     }
226   while (f->f_label != NULL)
227     {
228       lg = f->f_label->l_next;
229       free (f->f_label);
230       f->f_label = lg;
231     }
232 }
233 
234 
235 /*  Pop the function execution stack and return the top. */
236 
237 int
fpop(void)238 fpop(void)
239 {
240   fstack_rec *temp;
241   int retval;
242 
243   if (fn_stack != NULL)
244     {
245       temp = fn_stack;
246       fn_stack = temp->s_next;
247       retval = temp->s_val;
248       free (temp);
249     }
250   else
251     {
252       retval = 0;
253       rt_error ("function stack underflow, contact maintainer.");
254     }
255   return (retval);
256 }
257 
258 
259 /* Push VAL on to the function stack. */
260 
261 void
fpush(int val)262 fpush (int val)
263 {
264   fstack_rec *temp;
265 
266   temp = bc_malloc (sizeof (fstack_rec));
267   temp->s_next = fn_stack;
268   temp->s_val = val;
269   fn_stack = temp;
270 }
271 
272 
273 /* Pop and discard the top element of the regular execution stack. */
274 
275 void
pop(void)276 pop (void)
277 {
278   estack_rec *temp;
279 
280   if (ex_stack != NULL)
281     {
282       temp = ex_stack;
283       ex_stack = temp->s_next;
284       bc_free_num (&temp->s_num);
285       free (temp);
286     }
287 }
288 
289 
290 /* Push a copy of NUM on to the regular execution stack. */
291 
292 void
push_copy(bc_num num)293 push_copy (bc_num num)
294 {
295   estack_rec *temp;
296 
297   temp = bc_malloc (sizeof (estack_rec));
298   temp->s_num = bc_copy_num (num);
299   temp->s_next = ex_stack;
300   ex_stack = temp;
301 }
302 
303 
304 /* Push NUM on to the regular execution stack.  Do NOT push a copy. */
305 
306 void
push_num(bc_num num)307 push_num (bc_num num)
308 {
309   estack_rec *temp;
310 
311   temp = bc_malloc (sizeof (estack_rec));
312   temp->s_num = num;
313   temp->s_next = ex_stack;
314   ex_stack = temp;
315 }
316 
317 
318 /* Make sure the ex_stack has at least DEPTH elements on it.
319    Return TRUE if it has at least DEPTH elements, otherwise
320    return FALSE. */
321 
322 char
check_stack(int depth)323 check_stack (int depth)
324 {
325   estack_rec *temp;
326 
327   temp = ex_stack;
328   while ((temp != NULL) && (depth > 0))
329     {
330       temp = temp->s_next;
331       depth--;
332     }
333   if (depth > 0)
334     {
335       rt_error ("Stack error.");
336       return FALSE;
337     }
338   return TRUE;
339 }
340 
341 
342 /* The following routines manipulate simple variables and
343    array variables. */
344 
345 /* get_var returns a pointer to the variable VAR_NAME.  If one does not
346    exist, one is created. */
347 
348 bc_var *
get_var(int var_name)349 get_var (int var_name)
350 {
351   bc_var *var_ptr;
352 
353   var_ptr = variables[var_name];
354   if (var_ptr == NULL)
355     {
356       var_ptr = variables[var_name] = bc_malloc (sizeof (bc_var));
357       bc_init_num (&var_ptr->v_value);
358     }
359   return var_ptr;
360 }
361 
362 
363 /* get_array_num returns the address of the bc_num in the array
364    structure.  If more structure is requried to get to the index,
365    this routine does the work to create that structure. VAR_INDEX
366    is a zero based index into the arrays storage array. INDEX is
367    the index into the bc array. */
368 
369 bc_num *
get_array_num(int var_index,unsigned long idx)370 get_array_num (int var_index, unsigned long idx)
371 {
372   bc_var_array *ary_ptr;
373   bc_array *a_var;
374   bc_array_node *temp;
375   int log;
376   unsigned int ix, ix1;
377   int sub [NODE_DEPTH];
378 
379   /* Get the array entry. */
380   ary_ptr = arrays[var_index];
381   if (ary_ptr == NULL)
382     {
383       ary_ptr = arrays[var_index] = bc_malloc (sizeof (bc_var_array));
384       ary_ptr->a_value = NULL;
385       ary_ptr->a_next = NULL;
386       ary_ptr->a_param = FALSE;
387     }
388 
389   a_var = ary_ptr->a_value;
390   if (a_var == NULL) {
391     a_var = ary_ptr->a_value = bc_malloc (sizeof (bc_array));
392     a_var->a_tree = NULL;
393     a_var->a_depth = 0;
394   }
395 
396   /* Get the index variable. */
397   sub[0] = idx & NODE_MASK;
398   ix = idx >> NODE_SHIFT;
399   log = 1;
400   while (ix > 0 || log < a_var->a_depth)
401     {
402       sub[log] = ix & NODE_MASK;
403       ix >>= NODE_SHIFT;
404       log++;
405     }
406 
407   /* Build any tree that is necessary. */
408   while (log > a_var->a_depth)
409     {
410       temp = bc_malloc (sizeof(bc_array_node));
411       if (a_var->a_depth != 0)
412 	{
413 	  temp->n_items.n_down[0] = a_var->a_tree;
414 	  for (ix=1; ix < NODE_SIZE; ix++)
415 	    temp->n_items.n_down[ix] = NULL;
416 	}
417       else
418 	{
419 	  for (ix=0; ix < NODE_SIZE; ix++)
420 	    temp->n_items.n_num[ix] = bc_copy_num(_zero_);
421 	}
422       a_var->a_tree = temp;
423       a_var->a_depth++;
424     }
425 
426   /* Find the indexed variable. */
427   temp = a_var->a_tree;
428   while ( log-- > 1)
429     {
430       ix1 = sub[log];
431       if (temp->n_items.n_down[ix1] == NULL)
432 	{
433 	  temp->n_items.n_down[ix1] = bc_malloc (sizeof(bc_array_node));
434 	  temp = temp->n_items.n_down[ix1];
435 	  if (log > 1)
436 	    for (ix=0; ix < NODE_SIZE; ix++)
437 	      temp->n_items.n_down[ix] = NULL;
438 	  else
439 	    for (ix=0; ix < NODE_SIZE; ix++)
440 	      temp->n_items.n_num[ix] = bc_copy_num(_zero_);
441 	}
442       else
443 	temp = temp->n_items.n_down[ix1];
444     }
445 
446   /* Return the address of the indexed variable. */
447   return &(temp->n_items.n_num[sub[0]]);
448 }
449 
450 
451 /* Store the top of the execution stack into VAR_NAME.
452    This includes the special variables ibase, obase, and scale. */
453 
454 void
store_var(int var_name)455 store_var (int var_name)
456 {
457   bc_var *var_ptr;
458   long temp;
459   char toobig;
460 
461   if (var_name > 3)
462     {
463       /* It is a simple variable. */
464       var_ptr = get_var (var_name);
465       if (var_ptr != NULL)
466 	{
467 	  bc_free_num(&var_ptr->v_value);
468 	  var_ptr->v_value = bc_copy_num (ex_stack->s_num);
469 	}
470     }
471   else
472     {
473       /* It is a special variable... */
474       toobig = FALSE;
475       temp = 0;
476       if (bc_is_neg (ex_stack->s_num))
477 	{
478 	  switch (var_name)
479 	    {
480 	    case 0:
481 	      rt_warn ("negative ibase, set to 2");
482 	      temp = 2;
483 	      break;
484 	    case 1:
485 	      rt_warn ("negative obase, set to 2");
486 	      temp = 2;
487 	      break;
488 	    case 2:
489 	      rt_warn ("negative scale, set to 0");
490 	      temp = 0;
491 	      break;
492 #if defined(READLINE) || defined(LIBEDIT)
493 	    case 3:
494 	      temp = -1;
495 	      break;
496 #endif
497 	    }
498 	}
499       else
500 	{
501 	  temp = bc_num2long (ex_stack->s_num);
502 	  if (!bc_is_zero (ex_stack->s_num) && temp == 0)
503 	    toobig = TRUE;
504 	}
505       switch (var_name)
506 	{
507 	case 0:
508 	  if (temp < 2 && !toobig)
509 	    {
510 	      i_base = 2;
511 	      rt_warn ("ibase too small, set to 2");
512 	    }
513 	  else
514 	    if (temp > 16 || toobig)
515 	      {
516 	        if (std_only)
517                   {
518 		    i_base = 16;
519 		    rt_warn ("ibase too large, set to 16");
520                   }
521                 else if (temp > 36 || toobig)
522                   {
523 		    i_base = 36;
524 		    rt_warn ("ibase too large, set to 36");
525                   }
526                 else
527                   {
528                      if (temp >= 16 && warn_not_std)
529                        rt_warn ("ibase larger than 16 is non-standard");
530 		     i_base = temp;
531                   }
532 	      }
533 	    else
534 	      i_base = (int) temp;
535 	  break;
536 
537 	case 1:
538 	  if (temp < 2 && !toobig)
539 	    {
540 	      o_base = 2;
541 	      rt_warn ("obase too small, set to 2");
542 	    }
543 	  else
544 	    if (temp > BC_BASE_MAX || toobig)
545 	      {
546 		o_base = BC_BASE_MAX;
547 		rt_warn ("obase too large, set to %d", BC_BASE_MAX);
548 	      }
549 	    else
550 	      o_base = (int) temp;
551 	  break;
552 
553 	case 2:
554 	  /*  WARNING:  The following if statement may generate a compiler
555 	      warning if INT_MAX == LONG_MAX.  This is NOT a problem. */
556 	  if (temp > BC_SCALE_MAX || toobig )
557 	    {
558 	      scale = BC_SCALE_MAX;
559 	      rt_warn ("scale too large, set to %d", BC_SCALE_MAX);
560 	    }
561 	  else
562 	    scale = (int) temp;
563 	  break;
564 
565 #if defined(READLINE) || defined(LIBEDIT)
566 	case 3:
567 	  if (toobig)
568 	    {
569 	      temp = -1;
570 	      rt_warn ("history too large, set to unlimited");
571 	      UNLIMIT_HISTORY;
572 	    }
573 	  else
574 	    {
575 	      n_history = temp;
576 	      if (temp < 0)
577 		UNLIMIT_HISTORY;
578 	      else
579 		HISTORY_SIZE(n_history);
580 	    }
581 #endif
582 	}
583     }
584 }
585 
586 
587 /* Store the top of the execution stack into array VAR_NAME.
588    VAR_NAME is the name of an array, and the next to the top
589    of stack for the index into the array. */
590 
591 void
store_array(int var_name)592 store_array (int var_name)
593 {
594   bc_num *num_ptr;
595   long idx;
596 
597   if (!check_stack(2)) return;
598   idx = bc_num2long (ex_stack->s_next->s_num);
599   if (idx < 0 || idx > BC_DIM_MAX ||
600       (idx == 0 && !bc_is_zero(ex_stack->s_next->s_num)))
601     rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
602   else
603     {
604       num_ptr = get_array_num (var_name, idx);
605       if (num_ptr != NULL)
606 	{
607 	  bc_free_num (num_ptr);
608 	  *num_ptr = bc_copy_num (ex_stack->s_num);
609 	  bc_free_num (&ex_stack->s_next->s_num);
610 	  ex_stack->s_next->s_num = ex_stack->s_num;
611 	  bc_init_num (&ex_stack->s_num);
612 	  pop();
613 	}
614     }
615 }
616 
617 
618 /*  Load a copy of VAR_NAME on to the execution stack.  This includes
619     the special variables ibase, obase and scale.  */
620 
621 void
load_var(int var_name)622 load_var (int var_name)
623 {
624   bc_var *var_ptr;
625 
626   switch (var_name)
627     {
628 
629     case 0:
630       /* Special variable ibase. */
631       push_copy (_zero_);
632       bc_int2num (&ex_stack->s_num, i_base);
633       break;
634 
635     case 1:
636       /* Special variable obase. */
637       push_copy (_zero_);
638       bc_int2num (&ex_stack->s_num, o_base);
639       break;
640 
641     case 2:
642       /* Special variable scale. */
643       push_copy (_zero_);
644       bc_int2num (&ex_stack->s_num, scale);
645       break;
646 
647 #if defined(READLINE) || defined(LIBEDIT)
648     case 3:
649       /* Special variable history. */
650       push_copy (_zero_);
651       bc_int2num (&ex_stack->s_num, n_history);
652       break;
653 #endif
654 
655     default:
656       /* It is a simple variable. */
657       var_ptr = variables[var_name];
658       if (var_ptr != NULL)
659 	push_copy (var_ptr->v_value);
660       else
661 	push_copy (_zero_);
662     }
663 }
664 
665 
666 /*  Load a copy of VAR_NAME on to the execution stack.  This includes
667     the special variables ibase, obase and scale.  */
668 
669 void
load_array(int var_name)670 load_array (int var_name)
671 {
672   bc_num *num_ptr;
673   long   idx;
674 
675   if (!check_stack(1)) return;
676   idx = bc_num2long (ex_stack->s_num);
677   if (idx < 0 || idx > BC_DIM_MAX ||
678      (idx == 0 && !bc_is_zero(ex_stack->s_num)))
679     rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
680   else
681     {
682       num_ptr = get_array_num (var_name, idx);
683       if (num_ptr != NULL)
684 	{
685 	  pop();
686 	  push_copy (*num_ptr);
687 	}
688     }
689 }
690 
691 
692 /* Decrement VAR_NAME by one.  This includes the special variables
693    ibase, obase, and scale. */
694 
695 void
decr_var(int var_name)696 decr_var (int var_name)
697 {
698   bc_var *var_ptr;
699 
700   switch (var_name)
701     {
702 
703     case 0: /* ibase */
704       if (i_base > 2)
705 	i_base--;
706       else
707 	rt_warn ("ibase too small in --");
708       break;
709 
710     case 1: /* obase */
711       if (o_base > 2)
712 	o_base--;
713       else
714 	rt_warn ("obase too small in --");
715       break;
716 
717     case 2: /* scale */
718       if (scale > 0)
719 	scale--;
720       else
721 	rt_warn ("scale can not be negative in -- ");
722       break;
723 
724 #if defined(READLINE) || defined(LIBEDIT)
725     case 3: /* history */
726       n_history--;
727       if (n_history >= 0)
728 	HISTORY_SIZE(n_history);
729       else
730 	{
731 	  n_history = -1;
732 	  rt_warn ("history is negative, set to unlimited");
733 	  UNLIMIT_HISTORY;
734 	}
735       break;
736 #endif
737 
738     default: /* It is a simple variable. */
739       var_ptr = get_var (var_name);
740       if (var_ptr != NULL)
741 	bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value, 0);
742     }
743 }
744 
745 
746 /* Decrement VAR_NAME by one.  VAR_NAME is an array, and the top of
747    the execution stack is the index and it is popped off the stack. */
748 
749 void
decr_array(int var_name)750 decr_array (int var_name)
751 {
752   bc_num *num_ptr;
753   long   idx;
754 
755   /* It is an array variable. */
756   if (!check_stack (1)) return;
757   idx = bc_num2long (ex_stack->s_num);
758   if (idx < 0 || idx > BC_DIM_MAX ||
759      (idx == 0 && !bc_is_zero (ex_stack->s_num)))
760     rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
761   else
762     {
763       num_ptr = get_array_num (var_name, idx);
764       if (num_ptr != NULL)
765 	{
766 	  pop ();
767 	  bc_sub (*num_ptr, _one_, num_ptr, 0);
768 	}
769     }
770 }
771 
772 
773 /* Increment VAR_NAME by one.  This includes the special variables
774    ibase, obase, and scale. */
775 
776 void
incr_var(int var_name)777 incr_var (int var_name)
778 {
779   bc_var *var_ptr;
780 
781   switch (var_name)
782     {
783 
784     case 0: /* ibase */
785       if (i_base < 16)
786 	i_base++;
787       else
788 	rt_warn ("ibase too big in ++");
789       break;
790 
791     case 1: /* obase */
792       if (o_base < BC_BASE_MAX)
793 	o_base++;
794       else
795 	rt_warn ("obase too big in ++");
796       break;
797 
798     case 2:
799       if (scale < BC_SCALE_MAX)
800 	scale++;
801       else
802 	rt_warn ("Scale too big in ++");
803       break;
804 
805 #if defined(READLINE) || defined(LIBEDIT)
806     case 3: /* history */
807       n_history++;
808       if (n_history > 0)
809 	HISTORY_SIZE(n_history);
810       else
811 	{
812 	  n_history = -1;
813 	  rt_warn ("history set to unlimited");
814 	  UNLIMIT_HISTORY;
815 	}
816       break;
817 #endif
818 
819     default:  /* It is a simple variable. */
820       var_ptr = get_var (var_name);
821       if (var_ptr != NULL)
822 	bc_add (var_ptr->v_value, _one_, &var_ptr->v_value, 0);
823 
824     }
825 }
826 
827 
828 /* Increment VAR_NAME by one.  VAR_NAME is an array and top of
829    execution stack is the index and is popped off the stack. */
830 
831 void
incr_array(int var_name)832 incr_array (int var_name)
833 {
834   bc_num *num_ptr;
835   long   idx;
836 
837   if (!check_stack (1)) return;
838   idx = bc_num2long (ex_stack->s_num);
839   if (idx < 0 || idx > BC_DIM_MAX ||
840       (idx == 0 && !bc_is_zero (ex_stack->s_num)))
841     rt_error ("Array %s subscript out of bounds.", a_names[var_name]);
842   else
843     {
844       num_ptr = get_array_num (var_name, idx);
845       if (num_ptr != NULL)
846 	{
847 	  pop ();
848 	  bc_add (*num_ptr, _one_, num_ptr, 0);
849 	}
850     }
851 }
852 
853 
854 /* Routines for processing autos variables and parameters. */
855 
856 /* NAME is an auto variable that needs to be pushed on its stack. */
857 
858 void
auto_var(int name)859 auto_var (int name)
860 {
861   bc_var *v_temp;
862   bc_var_array *a_temp;
863   int ix;
864 
865   if (name > 0)
866     {
867       /* A simple variable. */
868       ix = name;
869       v_temp = bc_malloc (sizeof (bc_var));
870       v_temp->v_next = variables[ix];
871       bc_init_num (&v_temp->v_value);
872       variables[ix] = v_temp;
873     }
874   else
875     {
876       /* An array variable. */
877       ix = -name;
878       a_temp = bc_malloc (sizeof (bc_var_array));
879       a_temp->a_next = arrays[ix];
880       a_temp->a_value = NULL;
881       a_temp->a_param = FALSE;
882       arrays[ix] = a_temp;
883     }
884 }
885 
886 
887 /* Free_a_tree frees everything associated with an array variable tree.
888    This is used when popping an array variable off its auto stack.  */
889 
890 void
free_a_tree(bc_array_node * root,int depth)891 free_a_tree (bc_array_node *root, int depth)
892 {
893   int ix;
894 
895   if (root != NULL)
896     {
897       if (depth > 1)
898 	for (ix = 0; ix < NODE_SIZE; ix++)
899 	  free_a_tree (root->n_items.n_down[ix], depth-1);
900       else
901 	for (ix = 0; ix < NODE_SIZE; ix++)
902 	  bc_free_num ( &(root->n_items.n_num[ix]));
903       free (root);
904     }
905 }
906 
907 
908 /* LIST is an NULL terminated list of varible names that need to be
909    popped off their auto stacks. */
910 
911 void
pop_vars(arg_list * list)912 pop_vars (arg_list *list)
913 {
914   bc_var *v_temp;
915   bc_var_array *a_temp;
916   int    ix;
917 
918   while (list != NULL)
919     {
920       ix = list->av_name;
921       if (ix > 0)
922 	{
923 	  /* A simple variable. */
924 	  v_temp = variables[ix];
925 	  if (v_temp != NULL)
926 	    {
927 	      variables[ix] = v_temp->v_next;
928 	      bc_free_num (&v_temp->v_value);
929 	      free (v_temp);
930 	    }
931 	}
932       else
933 	{
934 	  /* An array variable. */
935 	  ix = -ix;
936 	  a_temp = arrays[ix];
937 	  if (a_temp != NULL)
938 	    {
939 	      arrays[ix] = a_temp->a_next;
940 	      if (!a_temp->a_param && a_temp->a_value != NULL)
941 		{
942 		  free_a_tree (a_temp->a_value->a_tree,
943 			       a_temp->a_value->a_depth);
944 		  free (a_temp->a_value);
945 		}
946 	      free (a_temp);
947 	    }
948 	}
949       list = list->next;
950     }
951 }
952 
953 /* COPY_NODE: Copies an array node for a call by value parameter. */
954 static bc_array_node *
copy_tree(bc_array_node * ary_node,int depth)955 copy_tree (bc_array_node *ary_node, int depth)
956 {
957   bc_array_node *res = bc_malloc (sizeof(bc_array_node));
958   int i;
959 
960   if (depth > 1)
961     for (i=0; i<NODE_SIZE; i++)
962       if (ary_node->n_items.n_down[i] != NULL)
963 	res->n_items.n_down[i] =
964 	  copy_tree (ary_node->n_items.n_down[i], depth - 1);
965       else
966 	res->n_items.n_down[i] = NULL;
967   else
968     for (i=0; i<NODE_SIZE; i++)
969       if (ary_node->n_items.n_num[i] != NULL)
970 	res->n_items.n_num[i] = bc_copy_num (ary_node->n_items.n_num[i]);
971       else
972 	res->n_items.n_num[i] = NULL;
973   return res;
974 }
975 
976 /* COPY_ARRAY: Copies an array for a call by value array parameter.
977    ARY is the pointer to the bc_array structure. */
978 
979 static bc_array *
copy_array(bc_array * ary)980 copy_array (bc_array *ary)
981 {
982   bc_array *res = bc_malloc (sizeof(bc_array));
983   res->a_depth = ary->a_depth;
984   res->a_tree = copy_tree (ary->a_tree, ary->a_depth);
985   return (res);
986 }
987 
988 
989 /* A call is being made to FUNC.  The call types are at PC.  Process
990    the parameters by doing an auto on the parameter variable and then
991    store the value at the new variable or put a pointer the the array
992    variable. */
993 
994 void
process_params(program_counter * progctr,int func)995 process_params (program_counter *progctr, int func)
996 {
997   char ch;
998   arg_list *params;
999   int ix, ix1;
1000   bc_var *v_temp;
1001   bc_var_array *a_src, *a_dest;
1002 
1003   /* Get the parameter names from the function. */
1004   params = functions[func].f_params;
1005 
1006   while ((ch = byte(progctr)) != ':')
1007     {
1008       if (params != NULL)
1009 	{
1010 	  if ((ch == '0') && params->av_name > 0)
1011 	    {
1012 	      /* A simple variable. */
1013 	      ix = params->av_name;
1014 	      v_temp = bc_malloc (sizeof(bc_var));
1015 	      v_temp->v_next = variables[ix];
1016 	      v_temp->v_value = ex_stack->s_num;
1017 	      bc_init_num (&ex_stack->s_num);
1018 	      variables[ix] = v_temp;
1019 	    }
1020 	  else
1021 	    if ((ch == '1') && (params->av_name < 0))
1022 	      {
1023 		/* The variables is an array variable. */
1024 
1025 		/* Compute source index and make sure some structure exists. */
1026 		ix = (int) bc_num2long (ex_stack->s_num);
1027 		(void) get_array_num (ix, 0);
1028 
1029 		/* Push a new array and Compute Destination index */
1030 		auto_var (params->av_name);
1031 		ix1 = -params->av_name;
1032 
1033 		/* Set up the correct pointers in the structure. */
1034 		if (ix == ix1)
1035 		  a_src = arrays[ix]->a_next;
1036 		else
1037 		  a_src = arrays[ix];
1038 		a_dest = arrays[ix1];
1039 		if (params->arg_is_var)
1040 		  {
1041 		    a_dest->a_param = TRUE;
1042 		    a_dest->a_value = a_src->a_value;
1043 		  }
1044 		else
1045 		  {
1046 		    a_dest->a_param = FALSE;
1047 		    a_dest->a_value = copy_array (a_src->a_value);
1048 		  }
1049 	      }
1050 	    else
1051 	      {
1052 		if (params->av_name < 0)
1053 		  rt_error ("Parameter type mismatch parameter %s.",
1054 			    a_names[-params->av_name]);
1055 		else
1056 		  rt_error ("Parameter type mismatch, parameter %s.",
1057 			    v_names[params->av_name]);
1058 		params++;
1059 	      }
1060 	  pop ();
1061 	}
1062       else
1063 	{
1064 	    rt_error ("Parameter number mismatch");
1065 	    return;
1066 	}
1067       params = params->next;
1068     }
1069   if (params != NULL)
1070     rt_error ("Parameter number mismatch");
1071 }
1072