Commit | Line | Data |
---|---|---|
f87489ac WJ |
1 | /* storage.c: Code and data storage manipulations. This includes labels. */ |
2 | ||
3 | /* This file is part of bc written for MINIX. | |
4 | Copyright (C) 1991 Free Software Foundation, Inc. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2 of the License , or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | ||
20 | You may contact the author by: | |
21 | e-mail: phil@cs.wwu.edu | |
22 | us-mail: Philip A. Nelson | |
23 | Computer Science Department, 9062 | |
24 | Western Washington University | |
25 | Bellingham, WA 98226-9062 | |
26 | ||
27 | *************************************************************************/ | |
28 | ||
29 | #include "bcdefs.h" | |
30 | #include "global.h" | |
31 | #include "proto.h" | |
32 | ||
33 | ||
34 | /* Initialize the storage at the beginning of the run. */ | |
35 | ||
36 | void | |
37 | init_storage () | |
38 | { | |
39 | ||
40 | /* Functions: we start with none and ask for more. */ | |
41 | f_count = 0; | |
42 | more_functions (); | |
43 | f_names[0] = "(main)"; | |
44 | ||
45 | /* Variables. */ | |
46 | v_count = 0; | |
47 | more_variables (); | |
48 | ||
49 | /* Arrays. */ | |
50 | a_count = 0; | |
51 | more_arrays (); | |
52 | ||
53 | /* Other things... */ | |
54 | ex_stack = NULL; | |
55 | fn_stack = NULL; | |
56 | i_base = 10; | |
57 | o_base = 10; | |
58 | scale = 0; | |
59 | c_code = FALSE; | |
60 | init_numbers(); | |
61 | } | |
62 | ||
63 | /* Three functions for increasing the number of functions, variables, or | |
64 | arrays that are needed. This adds another 32 of the requested object. */ | |
65 | ||
66 | void | |
67 | more_functions (VOID) | |
68 | { | |
69 | int old_count; | |
70 | int indx1, indx2; | |
71 | bc_function *old_f; | |
72 | bc_function *f; | |
73 | char **old_names; | |
74 | ||
75 | /* Save old information. */ | |
76 | old_count = f_count; | |
77 | old_f = functions; | |
78 | old_names = f_names; | |
79 | ||
80 | /* Add a fixed amount and allocate new space. */ | |
81 | f_count += STORE_INCR; | |
82 | functions = (bc_function *) bc_malloc (f_count*sizeof (bc_function)); | |
83 | f_names = (char **) bc_malloc (f_count*sizeof (char *)); | |
84 | ||
85 | /* Copy old ones. */ | |
86 | for (indx1 = 0; indx1 < old_count; indx1++) | |
87 | { | |
88 | functions[indx1] = old_f[indx1]; | |
89 | f_names[indx1] = old_names[indx1]; | |
90 | } | |
91 | ||
92 | /* Initialize the new ones. */ | |
93 | for (; indx1 < f_count; indx1++) | |
94 | { | |
95 | f = &functions[indx1]; | |
96 | f->f_defined = FALSE; | |
97 | for (indx2 = 0; indx2 < BC_MAX_SEGS; indx2++) | |
98 | f->f_body [indx2] = NULL; | |
99 | f->f_code_size = 0; | |
100 | f->f_label = NULL; | |
101 | f->f_autos = NULL; | |
102 | f->f_params = NULL; | |
103 | } | |
104 | ||
105 | /* Free the old elements. */ | |
106 | if (old_count != 0) | |
107 | { | |
108 | free (old_f); | |
109 | free (old_names); | |
110 | } | |
111 | } | |
112 | ||
113 | void | |
114 | more_variables () | |
115 | { | |
116 | int indx; | |
117 | int old_count; | |
118 | bc_var **old_var; | |
119 | char **old_names; | |
120 | ||
121 | /* Save the old values. */ | |
122 | old_count = v_count; | |
123 | old_var = variables; | |
124 | old_names = v_names; | |
125 | ||
126 | /* Increment by a fixed amount and allocate. */ | |
127 | v_count += STORE_INCR; | |
128 | variables = (bc_var **) bc_malloc (v_count*sizeof(bc_var *)); | |
129 | v_names = (char **) bc_malloc (v_count*sizeof(char *)); | |
130 | ||
131 | /* Copy the old variables. */ | |
132 | for (indx = 3; indx < old_count; indx++) | |
133 | variables[indx] = old_var[indx]; | |
134 | ||
135 | /* Initialize the new elements. */ | |
136 | for (; indx < v_count; indx++) | |
137 | variables[indx] = NULL; | |
138 | ||
139 | /* Free the old elements. */ | |
140 | if (old_count != 0) | |
141 | { | |
142 | free (old_var); | |
143 | free (old_names); | |
144 | } | |
145 | } | |
146 | ||
147 | void | |
148 | more_arrays () | |
149 | { | |
150 | int indx; | |
151 | int old_count; | |
152 | bc_var_array **old_ary; | |
153 | char **old_names; | |
154 | ||
155 | /* Save the old values. */ | |
156 | old_count = a_count; | |
157 | old_ary = arrays; | |
158 | old_names = a_names; | |
159 | ||
160 | /* Increment by a fixed amount and allocate. */ | |
161 | a_count += STORE_INCR; | |
162 | arrays = (bc_var_array **) bc_malloc (a_count*sizeof(bc_var_array *)); | |
163 | a_names = (char **) bc_malloc (a_count*sizeof(char *)); | |
164 | ||
165 | /* Copy the old arrays. */ | |
166 | for (indx = 1; indx < old_count; indx++) | |
167 | arrays[indx] = old_ary[indx]; | |
168 | ||
169 | ||
170 | /* Initialize the new elements. */ | |
171 | for (; indx < v_count; indx++) | |
172 | arrays[indx] = NULL; | |
173 | ||
174 | /* Free the old elements. */ | |
175 | if (old_count != 0) | |
176 | { | |
177 | free (old_ary); | |
178 | free (old_names); | |
179 | } | |
180 | } | |
181 | ||
182 | ||
183 | /* clear_func clears out function FUNC and makes it ready to redefine. */ | |
184 | ||
185 | void | |
186 | clear_func (func) | |
187 | char func; | |
188 | { | |
189 | bc_function *f; | |
190 | int indx; | |
191 | bc_label_group *lg; | |
192 | ||
193 | /* Set the pointer to the function. */ | |
194 | f = &functions[func]; | |
195 | f->f_defined = FALSE; | |
196 | ||
197 | /* Clear the code segments. */ | |
198 | for (indx = 0; indx < BC_MAX_SEGS; indx++) | |
199 | { | |
200 | if (f->f_body[indx] != NULL) | |
201 | { | |
202 | free (f->f_body[indx]); | |
203 | f->f_body[indx] = NULL; | |
204 | } | |
205 | } | |
206 | ||
207 | f->f_code_size = 0; | |
208 | if (f->f_autos != NULL) | |
209 | { | |
210 | free_args (f->f_autos); | |
211 | f->f_autos = NULL; | |
212 | } | |
213 | if (f->f_params != NULL) | |
214 | { | |
215 | free_args (f->f_params); | |
216 | f->f_params = NULL; | |
217 | } | |
218 | while (f->f_label != NULL) | |
219 | { | |
220 | lg = f->f_label->l_next; | |
221 | free (f->f_label); | |
222 | f->f_label = lg; | |
223 | } | |
224 | } | |
225 | ||
226 | ||
227 | /* Pop the function execution stack and return the top. */ | |
228 | ||
229 | int | |
230 | fpop() | |
231 | { | |
232 | fstack_rec *temp; | |
233 | int retval; | |
234 | ||
235 | if (fn_stack != NULL) | |
236 | { | |
237 | temp = fn_stack; | |
238 | fn_stack = temp->s_next; | |
239 | retval = temp->s_val; | |
240 | free (temp); | |
241 | } | |
242 | return (retval); | |
243 | } | |
244 | ||
245 | ||
246 | /* Push VAL on to the function stack. */ | |
247 | ||
248 | void | |
249 | fpush (val) | |
250 | int val; | |
251 | { | |
252 | fstack_rec *temp; | |
253 | ||
254 | temp = (fstack_rec *) bc_malloc (sizeof (fstack_rec)); | |
255 | temp->s_next = fn_stack; | |
256 | temp->s_val = val; | |
257 | fn_stack = temp; | |
258 | } | |
259 | ||
260 | ||
261 | /* Pop and discard the top element of the regular execution stack. */ | |
262 | ||
263 | void | |
264 | pop () | |
265 | { | |
266 | estack_rec *temp; | |
267 | ||
268 | if (ex_stack != NULL) | |
269 | { | |
270 | temp = ex_stack; | |
271 | ex_stack = temp->s_next; | |
272 | free_num (&temp->s_num); | |
273 | free (temp); | |
274 | } | |
275 | } | |
276 | ||
277 | ||
278 | /* Push a copy of NUM on to the regular execution stack. */ | |
279 | ||
280 | void | |
281 | push_copy (num) | |
282 | bc_num num; | |
283 | { | |
284 | estack_rec *temp; | |
285 | ||
286 | temp = (estack_rec *) bc_malloc (sizeof (estack_rec)); | |
287 | temp->s_num = copy_num (num); | |
288 | temp->s_next = ex_stack; | |
289 | ex_stack = temp; | |
290 | } | |
291 | ||
292 | ||
293 | /* Push NUM on to the regular execution stack. Do NOT push a copy. */ | |
294 | ||
295 | void | |
296 | push_num (num) | |
297 | bc_num num; | |
298 | { | |
299 | estack_rec *temp; | |
300 | ||
301 | temp = (estack_rec *) bc_malloc (sizeof (estack_rec)); | |
302 | temp->s_num = num; | |
303 | temp->s_next = ex_stack; | |
304 | ex_stack = temp; | |
305 | } | |
306 | ||
307 | ||
308 | /* Make sure the ex_stack has at least DEPTH elements on it. | |
309 | Return TRUE if it has at least DEPTH elements, otherwise | |
310 | return FALSE. */ | |
311 | ||
312 | char | |
313 | check_stack (depth) | |
314 | int depth; | |
315 | { | |
316 | estack_rec *temp; | |
317 | ||
318 | temp = ex_stack; | |
319 | while ((temp != NULL) && (depth > 0)) | |
320 | { | |
321 | temp = temp->s_next; | |
322 | depth--; | |
323 | } | |
324 | if (depth > 0) | |
325 | { | |
326 | rt_error ("Stack error."); | |
327 | return FALSE; | |
328 | } | |
329 | return TRUE; | |
330 | } | |
331 | ||
332 | ||
333 | /* The following routines manipulate simple variables and | |
334 | array variables. */ | |
335 | ||
336 | /* get_var returns a pointer to the variable VAR_NAME. If one does not | |
337 | exist, one is created. */ | |
338 | ||
339 | bc_var * | |
340 | get_var (var_name) | |
341 | int var_name; | |
342 | { | |
343 | bc_var *var_ptr; | |
344 | ||
345 | var_ptr = variables[var_name]; | |
346 | if (var_ptr == NULL) | |
347 | { | |
348 | var_ptr = variables[var_name] = (bc_var *) bc_malloc (sizeof (bc_var)); | |
349 | init_num (&var_ptr->v_value); | |
350 | } | |
351 | return var_ptr; | |
352 | } | |
353 | ||
354 | ||
355 | /* get_array_num returns the address of the bc_num in the array | |
356 | structure. If more structure is requried to get to the index, | |
357 | this routine does the work to create that structure. VAR_INDEX | |
358 | is a zero based index into the arrays storage array. INDEX is | |
359 | the index into the bc array. */ | |
360 | ||
361 | bc_num * | |
362 | get_array_num (var_index, index) | |
363 | int var_index; | |
364 | long index; | |
365 | { | |
366 | bc_var_array *ary_ptr; | |
367 | bc_array *a_var; | |
368 | bc_array_node *temp; | |
369 | int log, ix, ix1; | |
370 | int sub [NODE_DEPTH]; | |
371 | ||
372 | /* Get the array entry. */ | |
373 | ary_ptr = arrays[var_index]; | |
374 | if (ary_ptr == NULL) | |
375 | { | |
376 | ary_ptr = arrays[var_index] = | |
377 | (bc_var_array *) bc_malloc (sizeof (bc_var_array)); | |
378 | ary_ptr->a_value = NULL; | |
379 | ary_ptr->a_next = NULL; | |
380 | ary_ptr->a_param = FALSE; | |
381 | } | |
382 | ||
383 | a_var = ary_ptr->a_value; | |
384 | if (a_var == NULL) { | |
385 | a_var = ary_ptr->a_value = (bc_array *) bc_malloc (sizeof (bc_array)); | |
386 | a_var->a_tree = NULL; | |
387 | a_var->a_depth = 0; | |
388 | } | |
389 | ||
390 | /* Get the index variable. */ | |
391 | sub[0] = index & NODE_MASK; | |
392 | ix = index >> NODE_SHIFT; | |
393 | log = 1; | |
394 | while (ix > 0 || log < a_var->a_depth) | |
395 | { | |
396 | sub[log] = ix & NODE_MASK; | |
397 | ix >>= NODE_SHIFT; | |
398 | log++; | |
399 | } | |
400 | ||
401 | /* Build any tree that is necessary. */ | |
402 | while (log > a_var->a_depth) | |
403 | { | |
404 | temp = (bc_array_node *) bc_malloc (sizeof(bc_array_node)); | |
405 | if (a_var->a_depth != 0) | |
406 | { | |
407 | temp->n_items.n_down[0] = a_var->a_tree; | |
408 | for (ix=1; ix < NODE_SIZE; ix++) | |
409 | temp->n_items.n_down[ix] = NULL; | |
410 | } | |
411 | else | |
412 | { | |
413 | for (ix=0; ix < NODE_SIZE; ix++) | |
414 | temp->n_items.n_num[ix] = copy_num(_zero_); | |
415 | } | |
416 | a_var->a_tree = temp; | |
417 | a_var->a_depth++; | |
418 | } | |
419 | ||
420 | /* Find the indexed variable. */ | |
421 | temp = a_var->a_tree; | |
422 | while ( log-- > 1) | |
423 | { | |
424 | ix1 = sub[log]; | |
425 | if (temp->n_items.n_down[ix1] == NULL) | |
426 | { | |
427 | temp->n_items.n_down[ix1] = | |
428 | (bc_array_node *) bc_malloc (sizeof(bc_array_node)); | |
429 | temp = temp->n_items.n_down[ix1]; | |
430 | if (log > 1) | |
431 | for (ix=0; ix < NODE_SIZE; ix++) | |
432 | temp->n_items.n_down[ix] = NULL; | |
433 | else | |
434 | for (ix=0; ix < NODE_SIZE; ix++) | |
435 | temp->n_items.n_num[ix] = copy_num(_zero_); | |
436 | } | |
437 | else | |
438 | temp = temp->n_items.n_down[ix1]; | |
439 | } | |
440 | ||
441 | /* Return the address of the indexed variable. */ | |
442 | return &(temp->n_items.n_num[sub[0]]); | |
443 | } | |
444 | ||
445 | ||
446 | /* Store the top of the execution stack into VAR_NAME. | |
447 | This includes the special variables ibase, obase, and scale. */ | |
448 | ||
449 | void | |
450 | store_var (var_name) | |
451 | int var_name; | |
452 | { | |
453 | bc_var *var_ptr; | |
454 | long temp; | |
455 | char toobig; | |
456 | ||
457 | if (var_name > 2) | |
458 | { | |
459 | /* It is a simple variable. */ | |
460 | var_ptr = get_var (var_name); | |
461 | if (var_ptr != NULL) | |
462 | { | |
463 | free_num(&var_ptr->v_value); | |
464 | var_ptr->v_value = copy_num (ex_stack->s_num); | |
465 | } | |
466 | } | |
467 | else | |
468 | { | |
469 | /* It is a special variable... */ | |
470 | toobig = FALSE; | |
471 | if (is_neg (ex_stack->s_num)) | |
472 | { | |
473 | switch (var_name) | |
474 | { | |
475 | case 0: | |
476 | rt_warn ("negative ibase, set to 2"); | |
477 | temp = 2; | |
478 | break; | |
479 | case 1: | |
480 | rt_warn ("negative obase, set to 2"); | |
481 | temp = 2; | |
482 | break; | |
483 | case 2: | |
484 | rt_warn ("negative scale, set to 0"); | |
485 | temp = 0; | |
486 | break; | |
487 | } | |
488 | } | |
489 | else | |
490 | { | |
491 | temp = num2long (ex_stack->s_num); | |
492 | if (!is_zero (ex_stack->s_num) && temp == 0) | |
493 | toobig = TRUE; | |
494 | } | |
495 | switch (var_name) | |
496 | { | |
497 | case 0: | |
498 | if (temp < 2 && !toobig) | |
499 | { | |
500 | i_base = 2; | |
501 | rt_warn ("ibase too small, set to 2"); | |
502 | } | |
503 | else | |
504 | if (temp > 16 || toobig) | |
505 | { | |
506 | i_base = 16; | |
507 | rt_warn ("ibase too large, set to 16"); | |
508 | } | |
509 | else | |
510 | i_base = (int) temp; | |
511 | break; | |
512 | ||
513 | case 1: | |
514 | if (temp < 2 && !toobig) | |
515 | { | |
516 | o_base = 2; | |
517 | rt_warn ("obase too small, set to 2"); | |
518 | } | |
519 | else | |
520 | if (temp > BC_BASE_MAX || toobig) | |
521 | { | |
522 | o_base = BC_BASE_MAX; | |
523 | rt_warn ("obase too large, set to %d", BC_BASE_MAX); | |
524 | } | |
525 | else | |
526 | o_base = (int) temp; | |
527 | break; | |
528 | ||
529 | case 2: | |
530 | /* WARNING: The following if statement may generate a compiler | |
531 | warning if INT_MAX == LONG_MAX. This is NOT a problem. */ | |
532 | if (temp > BC_SCALE_MAX || toobig ) | |
533 | { | |
534 | scale = BC_SCALE_MAX; | |
535 | rt_warn ("scale too large, set to %d", BC_SCALE_MAX); | |
536 | } | |
537 | else | |
538 | scale = (int) temp; | |
539 | } | |
540 | } | |
541 | } | |
542 | ||
543 | ||
544 | /* Store the top of the execution stack into array VAR_NAME. | |
545 | VAR_NAME is the name of an array, and the next to the top | |
546 | of stack for the index into the array. */ | |
547 | ||
548 | void | |
549 | store_array (var_name) | |
550 | int var_name; | |
551 | { | |
552 | bc_num *num_ptr; | |
553 | long index; | |
554 | ||
555 | if (!check_stack(2)) return; | |
556 | index = num2long (ex_stack->s_next->s_num); | |
557 | if (index < 0 || index > BC_DIM_MAX || | |
558 | (index == 0 && !is_zero(ex_stack->s_next->s_num))) | |
559 | rt_error ("Array %s subscript out of bounds.", a_names[var_name]); | |
560 | else | |
561 | { | |
562 | num_ptr = get_array_num (var_name, index); | |
563 | if (num_ptr != NULL) | |
564 | { | |
565 | free_num (num_ptr); | |
566 | *num_ptr = copy_num (ex_stack->s_num); | |
567 | free_num (&ex_stack->s_next->s_num); | |
568 | ex_stack->s_next->s_num = ex_stack->s_num; | |
569 | init_num (&ex_stack->s_num); | |
570 | pop(); | |
571 | } | |
572 | } | |
573 | } | |
574 | ||
575 | ||
576 | /* Load a copy of VAR_NAME on to the execution stack. This includes | |
577 | the special variables ibase, obase and scale. */ | |
578 | ||
579 | void | |
580 | load_var (var_name) | |
581 | int var_name; | |
582 | { | |
583 | bc_var *var_ptr; | |
584 | ||
585 | switch (var_name) | |
586 | { | |
587 | ||
588 | case 0: | |
589 | /* Special variable ibase. */ | |
590 | push_copy (_zero_); | |
591 | int2num (&ex_stack->s_num, i_base); | |
592 | break; | |
593 | ||
594 | case 1: | |
595 | /* Special variable obase. */ | |
596 | push_copy (_zero_); | |
597 | int2num (&ex_stack->s_num, o_base); | |
598 | break; | |
599 | ||
600 | case 2: | |
601 | /* Special variable scale. */ | |
602 | push_copy (_zero_); | |
603 | int2num (&ex_stack->s_num, scale); | |
604 | break; | |
605 | ||
606 | default: | |
607 | /* It is a simple variable. */ | |
608 | var_ptr = variables[var_name]; | |
609 | if (var_ptr != NULL) | |
610 | push_copy (var_ptr->v_value); | |
611 | else | |
612 | push_copy (_zero_); | |
613 | } | |
614 | } | |
615 | ||
616 | ||
617 | /* Load a copy of VAR_NAME on to the execution stack. This includes | |
618 | the special variables ibase, obase and scale. */ | |
619 | ||
620 | void | |
621 | load_array (var_name) | |
622 | int var_name; | |
623 | { | |
624 | bc_num *num_ptr; | |
625 | long index; | |
626 | ||
627 | if (!check_stack(1)) return; | |
628 | index = num2long (ex_stack->s_num); | |
629 | if (index < 0 || index > BC_DIM_MAX || | |
630 | (index == 0 && !is_zero(ex_stack->s_num))) | |
631 | rt_error ("Array %s subscript out of bounds.", a_names[var_name]); | |
632 | else | |
633 | { | |
634 | num_ptr = get_array_num (var_name, index); | |
635 | if (num_ptr != NULL) | |
636 | { | |
637 | pop(); | |
638 | push_copy (*num_ptr); | |
639 | } | |
640 | } | |
641 | } | |
642 | ||
643 | ||
644 | /* Decrement VAR_NAME by one. This includes the special variables | |
645 | ibase, obase, and scale. */ | |
646 | ||
647 | void | |
648 | decr_var (var_name) | |
649 | int var_name; | |
650 | { | |
651 | bc_var *var_ptr; | |
652 | ||
653 | switch (var_name) | |
654 | { | |
655 | ||
656 | case 0: /* ibase */ | |
657 | if (i_base > 2) | |
658 | i_base--; | |
659 | else | |
660 | rt_warn ("ibase too small in --"); | |
661 | break; | |
662 | ||
663 | case 1: /* obase */ | |
664 | if (o_base > 2) | |
665 | o_base--; | |
666 | else | |
667 | rt_warn ("obase too small in --"); | |
668 | break; | |
669 | ||
670 | case 2: /* scale */ | |
671 | if (scale > 0) | |
672 | scale--; | |
673 | else | |
674 | rt_warn ("scale can not be negative in -- "); | |
675 | break; | |
676 | ||
677 | default: /* It is a simple variable. */ | |
678 | var_ptr = get_var (var_name); | |
679 | if (var_ptr != NULL) | |
680 | bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value); | |
681 | } | |
682 | } | |
683 | ||
684 | ||
685 | /* Decrement VAR_NAME by one. VAR_NAME is an array, and the top of | |
686 | the execution stack is the index and it is popped off the stack. */ | |
687 | ||
688 | void | |
689 | decr_array (var_name) | |
690 | char var_name; | |
691 | { | |
692 | bc_num *num_ptr; | |
693 | long index; | |
694 | ||
695 | /* It is an array variable. */ | |
696 | if (!check_stack (1)) return; | |
697 | index = num2long (ex_stack->s_num); | |
698 | if (index < 0 || index > BC_DIM_MAX || | |
699 | (index == 0 && !is_zero (ex_stack->s_num))) | |
700 | rt_error ("Array %s subscript out of bounds.", a_names[var_name]); | |
701 | else | |
702 | { | |
703 | num_ptr = get_array_num (var_name, index); | |
704 | if (num_ptr != NULL) | |
705 | { | |
706 | pop (); | |
707 | bc_sub (*num_ptr, _one_, num_ptr); | |
708 | } | |
709 | } | |
710 | } | |
711 | ||
712 | ||
713 | /* Increment VAR_NAME by one. This includes the special variables | |
714 | ibase, obase, and scale. */ | |
715 | ||
716 | void | |
717 | incr_var (var_name) | |
718 | int var_name; | |
719 | { | |
720 | bc_var *var_ptr; | |
721 | ||
722 | switch (var_name) | |
723 | { | |
724 | ||
725 | case 0: /* ibase */ | |
726 | if (i_base < 16) | |
727 | i_base++; | |
728 | else | |
729 | rt_warn ("ibase too big in ++"); | |
730 | break; | |
731 | ||
732 | case 1: /* obase */ | |
733 | if (o_base < BC_BASE_MAX) | |
734 | o_base++; | |
735 | else | |
736 | rt_warn ("obase too big in ++"); | |
737 | break; | |
738 | ||
739 | case 2: | |
740 | if (scale < BC_SCALE_MAX) | |
741 | scale++; | |
742 | else | |
743 | rt_warn ("Scale too big in ++"); | |
744 | break; | |
745 | ||
746 | default: /* It is a simple variable. */ | |
747 | var_ptr = get_var (var_name); | |
748 | if (var_ptr != NULL) | |
749 | bc_add (var_ptr->v_value, _one_, &var_ptr->v_value); | |
750 | ||
751 | } | |
752 | } | |
753 | ||
754 | ||
755 | /* Increment VAR_NAME by one. VAR_NAME is an array and top of | |
756 | execution stack is the index and is popped off the stack. */ | |
757 | ||
758 | void | |
759 | incr_array (var_name) | |
760 | int var_name; | |
761 | { | |
762 | bc_num *num_ptr; | |
763 | long index; | |
764 | ||
765 | if (!check_stack (1)) return; | |
766 | index = num2long (ex_stack->s_num); | |
767 | if (index < 0 || index > BC_DIM_MAX || | |
768 | (index == 0 && !is_zero (ex_stack->s_num))) | |
769 | rt_error ("Array %s subscript out of bounds.", a_names[var_name]); | |
770 | else | |
771 | { | |
772 | num_ptr = get_array_num (var_name, index); | |
773 | if (num_ptr != NULL) | |
774 | { | |
775 | pop (); | |
776 | bc_add (*num_ptr, _one_, num_ptr); | |
777 | } | |
778 | } | |
779 | } | |
780 | ||
781 | ||
782 | /* Routines for processing autos variables and parameters. */ | |
783 | ||
784 | /* NAME is an auto variable that needs to be pushed on its stack. */ | |
785 | ||
786 | void | |
787 | auto_var (name) | |
788 | int name; | |
789 | { | |
790 | bc_var *v_temp; | |
791 | bc_var_array *a_temp; | |
792 | int ix; | |
793 | ||
794 | if (name > 0) | |
795 | { | |
796 | /* A simple variable. */ | |
797 | ix = name; | |
798 | v_temp = (bc_var *) bc_malloc (sizeof (bc_var)); | |
799 | v_temp->v_next = variables[ix]; | |
800 | init_num (&v_temp->v_value); | |
801 | variables[ix] = v_temp; | |
802 | } | |
803 | else | |
804 | { | |
805 | /* An array variable. */ | |
806 | ix = -name; | |
807 | a_temp = (bc_var_array *) bc_malloc (sizeof (bc_var_array)); | |
808 | a_temp->a_next = arrays[ix]; | |
809 | a_temp->a_value = NULL; | |
810 | a_temp->a_param = FALSE; | |
811 | arrays[ix] = a_temp; | |
812 | } | |
813 | } | |
814 | ||
815 | ||
816 | /* Free_a_tree frees everything associated with an array variable tree. | |
817 | This is used when popping an array variable off its auto stack. */ | |
818 | ||
819 | void | |
820 | free_a_tree ( root, depth ) | |
821 | bc_array_node *root; | |
822 | int depth; | |
823 | { | |
824 | int ix; | |
825 | ||
826 | if (root != NULL) | |
827 | { | |
828 | if (depth > 1) | |
829 | for (ix = 0; ix < NODE_SIZE; ix++) | |
830 | free_a_tree (root->n_items.n_down[ix], depth-1); | |
831 | else | |
832 | for (ix = 0; ix < NODE_SIZE; ix++) | |
833 | free_num ( &(root->n_items.n_num[ix])); | |
834 | free (root); | |
835 | } | |
836 | } | |
837 | ||
838 | ||
839 | /* LIST is an NULL terminated list of varible names that need to be | |
840 | popped off their auto stacks. */ | |
841 | ||
842 | void | |
843 | pop_vars (list) | |
844 | arg_list *list; | |
845 | { | |
846 | bc_var *v_temp; | |
847 | bc_var_array *a_temp; | |
848 | int ix; | |
849 | ||
850 | while (list != NULL) | |
851 | { | |
852 | ix = list->av_name; | |
853 | if (ix > 0) | |
854 | { | |
855 | /* A simple variable. */ | |
856 | v_temp = variables[ix]; | |
857 | if (v_temp != NULL) | |
858 | { | |
859 | variables[ix] = v_temp->v_next; | |
860 | free_num (&v_temp->v_value); | |
861 | free (v_temp); | |
862 | } | |
863 | } | |
864 | else | |
865 | { | |
866 | /* An array variable. */ | |
867 | ix = -ix; | |
868 | a_temp = arrays[ix]; | |
869 | if (a_temp != NULL) | |
870 | { | |
871 | arrays[ix] = a_temp->a_next; | |
872 | if (!a_temp->a_param && a_temp->a_value != NULL) | |
873 | { | |
874 | free_a_tree (a_temp->a_value->a_tree, | |
875 | a_temp->a_value->a_depth); | |
876 | free (a_temp->a_value); | |
877 | } | |
878 | free (a_temp); | |
879 | } | |
880 | } | |
881 | list = list->next; | |
882 | } | |
883 | } | |
884 | ||
885 | ||
886 | /* A call is being made to FUNC. The call types are at PC. Process | |
887 | the parameters by doing an auto on the parameter variable and then | |
888 | store the value at the new variable or put a pointer the the array | |
889 | variable. */ | |
890 | ||
891 | void | |
892 | process_params (pc, func) | |
893 | program_counter *pc; | |
894 | int func; | |
895 | { | |
896 | char ch; | |
897 | arg_list *params; | |
898 | char warned = FALSE; | |
899 | int ix, ix1; | |
900 | bc_var *v_temp; | |
901 | bc_var_array *a_src, *a_dest; | |
902 | bc_num *n_temp; | |
903 | ||
904 | /* Get the parameter names from the function. */ | |
905 | params = functions[func].f_params; | |
906 | ||
907 | while ((ch = byte(pc)) != ':') | |
908 | { | |
909 | if (params != NULL) | |
910 | { | |
911 | if ((ch == '0') && params->av_name > 0) | |
912 | { | |
913 | /* A simple variable. */ | |
914 | ix = params->av_name; | |
915 | v_temp = (bc_var *) bc_malloc (sizeof(bc_var)); | |
916 | v_temp->v_next = variables[ix]; | |
917 | v_temp->v_value = ex_stack->s_num; | |
918 | init_num (&ex_stack->s_num); | |
919 | variables[ix] = v_temp; | |
920 | } | |
921 | else | |
922 | if ((ch == '1') && (params->av_name < 0)) | |
923 | { | |
924 | /* The variables is an array variable. */ | |
925 | ||
926 | /* Compute source index and make sure some structure exists. */ | |
927 | ix = (int) num2long (ex_stack->s_num); | |
928 | n_temp = get_array_num (ix, 0); | |
929 | ||
930 | /* Push a new array and Compute Destination index */ | |
931 | auto_var (params->av_name); | |
932 | ix1 = -params->av_name; | |
933 | ||
934 | /* Set up the correct pointers in the structure. */ | |
935 | if (ix == ix1) | |
936 | a_src = arrays[ix]->a_next; | |
937 | else | |
938 | a_src = arrays[ix]; | |
939 | a_dest = arrays[ix1]; | |
940 | a_dest->a_param = TRUE; | |
941 | a_dest->a_value = a_src->a_value; | |
942 | } | |
943 | else | |
944 | { | |
945 | if (params->av_name < 0) | |
946 | rt_error ("Parameter type mismatch parameter %s.", | |
947 | a_names[-params->av_name]); | |
948 | else | |
949 | rt_error ("Parameter type mismatch, parameter %s.", | |
950 | v_names[params->av_name]); | |
951 | params++; | |
952 | } | |
953 | pop (); | |
954 | } | |
955 | else | |
956 | { | |
957 | if (!warned) | |
958 | { | |
959 | rt_error ("Parameter number mismatch"); | |
960 | warned = TRUE; | |
961 | } | |
962 | } | |
963 | params = params->next; | |
964 | } | |
965 | if (params != NULL) | |
966 | rt_error ("Parameter number mismatch"); | |
967 | } |