Commit | Line | Data |
---|---|---|
f87489ac WJ |
1 | /* execute.c - run a bc program. */ |
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 <signal.h> | |
31 | #include <setjmp.h> | |
32 | #include "global.h" | |
33 | #include "proto.h" | |
34 | ||
35 | /* Local variable for SIGINT interrupt of an execution. */ | |
36 | static jmp_buf env; | |
37 | ||
38 | ||
39 | /* The SIGINT interrupt handling routine. */ | |
40 | ||
41 | void | |
42 | stop_execution (sig) | |
43 | int sig; | |
44 | { | |
45 | printf ("\n"); | |
46 | rt_error ("interrupted execution"); | |
47 | longjmp (env, 1); /* Jump to the main code. */ | |
48 | } | |
49 | ||
50 | ||
51 | /* Get the current byte and advance the PC counter. */ | |
52 | ||
53 | unsigned char | |
54 | byte (pc) | |
55 | program_counter *pc; | |
56 | { | |
57 | int seg, offset; | |
58 | ||
59 | seg = pc->pc_addr >> BC_SEG_LOG; | |
60 | offset = pc->pc_addr++ % BC_SEG_SIZE; | |
61 | return (functions[pc->pc_func].f_body[seg][offset]); | |
62 | } | |
63 | ||
64 | ||
65 | /* The routine that actually runs the machine. */ | |
66 | ||
67 | void | |
68 | execute () | |
69 | { | |
70 | int label_num, l_gp, l_off; | |
71 | bc_label_group *gp; | |
72 | ||
73 | char inst, ch; | |
74 | int new_func; | |
75 | int var_name; | |
76 | ||
77 | int const_base; | |
78 | ||
79 | bc_num temp_num; | |
80 | arg_list *auto_list; | |
81 | ||
82 | /* Initialize this run... */ | |
83 | pc.pc_func = 0; | |
84 | pc.pc_addr = 0; | |
85 | runtime_error = FALSE; | |
86 | init_num (&temp_num); | |
87 | ||
88 | /* Set up the interrupt mechanism for an interactive session. */ | |
89 | if (interactive) | |
90 | if (setjmp (env) == 0) | |
91 | signal (SIGINT, stop_execution); | |
92 | ||
93 | while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error) | |
94 | { | |
95 | inst = byte(&pc); | |
96 | ||
97 | #if DEBUG > 3 | |
98 | { /* Print out address and the stack before each instruction.*/ | |
99 | int depth; estack_rec *temp = ex_stack; | |
100 | ||
101 | printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst); | |
102 | if (temp == NULL) printf ("empty stack.\n", inst); | |
103 | else | |
104 | { | |
105 | depth = 1; | |
106 | while (temp != NULL) | |
107 | { | |
108 | printf (" %d = ", depth); | |
109 | out_num (temp->s_num, 10, out_char); | |
110 | depth++; | |
111 | temp = temp->s_next; | |
112 | } | |
113 | } | |
114 | } | |
115 | #endif | |
116 | ||
117 | switch ( inst ) | |
118 | { | |
119 | ||
120 | case 'A' : /* increment array variable (Add one). */ | |
121 | var_name = byte(&pc); | |
122 | if ((var_name & 0x80) != 0) | |
123 | var_name = ((var_name << 8) & 0x7f) + byte(&pc); | |
124 | incr_array (var_name); | |
125 | break; | |
126 | ||
127 | case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */ | |
128 | case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */ | |
129 | c_code = !is_zero (ex_stack->s_num); | |
130 | pop (); | |
131 | case 'J' : /* Jump to a label. */ | |
132 | label_num = byte(&pc); /* Low order bits first. */ | |
133 | label_num += byte(&pc) << 8; | |
134 | if (inst == 'J' || (inst == 'B' && c_code) | |
135 | || (inst == 'Z' && !c_code)) { | |
136 | gp = functions[pc.pc_func].f_label; | |
137 | l_gp = label_num >> BC_LABEL_LOG; | |
138 | l_off = label_num % BC_LABEL_GROUP; | |
139 | while (l_gp-- > 0) gp = gp->l_next; | |
140 | pc.pc_addr = gp->l_adrs[l_off]; | |
141 | } | |
142 | break; | |
143 | ||
144 | case 'C' : /* Call a function. */ | |
145 | /* Get the function number. */ | |
146 | new_func = byte(&pc); | |
147 | if ((new_func & 0x80) != 0) | |
148 | new_func = ((new_func << 8) & 0x7f) + byte(&pc); | |
149 | ||
150 | /* Check to make sure it is defined. */ | |
151 | if (!functions[new_func].f_defined) | |
152 | { | |
153 | rt_error ("Function %s not defined.", f_names[new_func]); | |
154 | break; | |
155 | } | |
156 | ||
157 | /* Check and push parameters. */ | |
158 | process_params (&pc, new_func); | |
159 | ||
160 | /* Push auto variables. */ | |
161 | for (auto_list = functions[new_func].f_autos; | |
162 | auto_list != NULL; | |
163 | auto_list = auto_list->next) | |
164 | auto_var (auto_list->av_name); | |
165 | ||
166 | /* Push pc and ibase. */ | |
167 | fpush (pc.pc_func); | |
168 | fpush (pc.pc_addr); | |
169 | fpush (i_base); | |
170 | ||
171 | /* Reset pc to start of function. */ | |
172 | pc.pc_func = new_func; | |
173 | pc.pc_addr = 0; | |
174 | break; | |
175 | ||
176 | case 'D' : /* Duplicate top of stack */ | |
177 | push_copy (ex_stack->s_num); | |
178 | break; | |
179 | ||
180 | case 'K' : /* Push a constant */ | |
181 | /* Get the input base and convert it to a bc number. */ | |
182 | if (pc.pc_func == 0) | |
183 | const_base = i_base; | |
184 | else | |
185 | const_base = fn_stack->s_val; | |
186 | if (const_base == 10) | |
187 | push_b10_const (&pc); | |
188 | else | |
189 | push_constant (prog_char, const_base); | |
190 | break; | |
191 | ||
192 | case 'L' : /* load array variable */ | |
193 | var_name = byte(&pc); | |
194 | if ((var_name & 0x80) != 0) | |
195 | var_name = ((var_name << 8) & 0x7f) + byte(&pc); | |
196 | load_array (var_name); | |
197 | break; | |
198 | ||
199 | case 'M' : /* decrement array variable (Minus!) */ | |
200 | var_name = byte(&pc); | |
201 | if ((var_name & 0x80) != 0) | |
202 | var_name = ((var_name << 8) & 0x7f) + byte(&pc); | |
203 | decr_array (var_name); | |
204 | break; | |
205 | ||
206 | case 'O' : /* Write a string to the output with processing. */ | |
207 | while ((ch = byte(&pc)) != '"') | |
208 | if (ch != '\\') | |
209 | out_char (ch); | |
210 | else | |
211 | { | |
212 | ch = byte(&pc); | |
213 | if (ch == '"') break; | |
214 | switch (ch) | |
215 | { | |
216 | case 'n': out_char ('\n'); break; | |
217 | case 't': out_char ('\t'); break; | |
218 | case 'r': out_char ('\r'); break; | |
219 | case 'b': out_char (007); break; | |
220 | case 'f': out_char ('\f'); break; | |
221 | case '\\': out_char ('\\'); break; | |
222 | default: break; | |
223 | } | |
224 | } | |
225 | if (interactive) fflush (stdout); | |
226 | break; | |
227 | ||
228 | case 'R' : /* Return from function */ | |
229 | if (pc.pc_func != 0) | |
230 | { | |
231 | /* "Pop" autos and parameters. */ | |
232 | pop_vars(functions[pc.pc_func].f_autos); | |
233 | pop_vars(functions[pc.pc_func].f_params); | |
234 | /* reset the pc. */ | |
235 | fpop (); | |
236 | pc.pc_addr = fpop (); | |
237 | pc.pc_func = fpop (); | |
238 | } | |
239 | else | |
240 | rt_error ("Return from main program."); | |
241 | break; | |
242 | ||
243 | case 'S' : /* store array variable */ | |
244 | var_name = byte(&pc); | |
245 | if ((var_name & 0x80) != 0) | |
246 | var_name = ((var_name << 8) & 0x7f) + byte(&pc); | |
247 | store_array (var_name); | |
248 | break; | |
249 | ||
250 | case 'T' : /* Test tos for zero */ | |
251 | c_code = is_zero (ex_stack->s_num); | |
252 | assign (c_code); | |
253 | break; | |
254 | ||
255 | case 'W' : /* Write the value on the top of the stack. */ | |
256 | case 'P' : /* Write the value on the top of the stack. No newline. */ | |
257 | out_num (ex_stack->s_num, o_base, out_char); | |
258 | if (inst == 'W') out_char ('\n'); | |
259 | store_var (3); /* Special variable "last". */ | |
260 | if (interactive) fflush (stdout); | |
261 | break; | |
262 | ||
263 | case 'c' : /* Call special function. */ | |
264 | new_func = byte(&pc); | |
265 | ||
266 | switch (new_func) | |
267 | { | |
268 | case 'L': /* Length function. */ | |
269 | /* For the number 0.xxxx, 0 is not significant. */ | |
270 | if (ex_stack->s_num->n_len == 1 && | |
271 | ex_stack->s_num->n_scale != 0 && | |
272 | ex_stack->s_num->n_value[0] == 0 ) | |
273 | int2num (&ex_stack->s_num, ex_stack->s_num->n_scale); | |
274 | else | |
275 | int2num (&ex_stack->s_num, ex_stack->s_num->n_len | |
276 | + ex_stack->s_num->n_scale); | |
277 | break; | |
278 | ||
279 | case 'S': /* Scale function. */ | |
280 | int2num (&ex_stack->s_num, ex_stack->s_num->n_scale); | |
281 | break; | |
282 | ||
283 | case 'R': /* Square Root function. */ | |
284 | if (!bc_sqrt (&ex_stack->s_num, scale)) | |
285 | rt_error ("Square root of a negative number"); | |
286 | break; | |
287 | ||
288 | case 'I': /* Read function. */ | |
289 | push_constant (input_char, i_base); | |
290 | break; | |
291 | } | |
292 | break; | |
293 | ||
294 | case 'd' : /* Decrement number */ | |
295 | var_name = byte(&pc); | |
296 | if ((var_name & 0x80) != 0) | |
297 | var_name = ((var_name << 8) & 0x7f) + byte(&pc); | |
298 | decr_var (var_name); | |
299 | break; | |
300 | ||
301 | case 'h' : /* Halt the machine. */ | |
302 | exit (0); | |
303 | ||
304 | case 'i' : /* increment number */ | |
305 | var_name = byte(&pc); | |
306 | if ((var_name & 0x80) != 0) | |
307 | var_name = ((var_name << 8) & 0x7f) + byte(&pc); | |
308 | incr_var (var_name); | |
309 | break; | |
310 | ||
311 | case 'l' : /* load variable */ | |
312 | var_name = byte(&pc); | |
313 | if ((var_name & 0x80) != 0) | |
314 | var_name = ((var_name << 8) & 0x7f) + byte(&pc); | |
315 | load_var (var_name); | |
316 | break; | |
317 | ||
318 | case 'n' : /* Negate top of stack. */ | |
319 | bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num); | |
320 | break; | |
321 | ||
322 | case 'p' : /* Pop the execution stack. */ | |
323 | pop (); | |
324 | break; | |
325 | ||
326 | case 's' : /* store variable */ | |
327 | var_name = byte(&pc); | |
328 | if ((var_name & 0x80) != 0) | |
329 | var_name = ((var_name << 8) & 0x7f) + byte(&pc); | |
330 | store_var (var_name); | |
331 | break; | |
332 | ||
333 | case 'w' : /* Write a string to the output. */ | |
334 | while ((ch = byte(&pc)) != '"') out_char (ch); | |
335 | if (interactive) fflush (stdout); | |
336 | break; | |
337 | ||
338 | case 'x' : /* Exchange Top of Stack with the one under the tos. */ | |
339 | if (check_stack(2)) { | |
340 | bc_num temp = ex_stack->s_num; | |
341 | ex_stack->s_num = ex_stack->s_next->s_num; | |
342 | ex_stack->s_next->s_num = temp; | |
343 | } | |
344 | break; | |
345 | ||
346 | case '0' : /* Load Constant 0. */ | |
347 | push_copy (_zero_); | |
348 | break; | |
349 | ||
350 | case '1' : /* Load Constant 0. */ | |
351 | push_copy (_one_); | |
352 | break; | |
353 | ||
354 | case '!' : /* Negate the boolean value on top of the stack. */ | |
355 | c_code = is_zero (ex_stack->s_num); | |
356 | assign (c_code); | |
357 | break; | |
358 | ||
359 | case '&' : /* compare greater than */ | |
360 | if (check_stack(2)) | |
361 | { | |
362 | c_code = !is_zero (ex_stack->s_next->s_num) | |
363 | && !is_zero (ex_stack->s_num); | |
364 | pop (); | |
365 | assign (c_code); | |
366 | } | |
367 | break; | |
368 | ||
369 | case '|' : /* compare greater than */ | |
370 | if (check_stack(2)) | |
371 | { | |
372 | c_code = !is_zero (ex_stack->s_next->s_num) | |
373 | || !is_zero (ex_stack->s_num); | |
374 | pop (); | |
375 | assign (c_code); | |
376 | } | |
377 | break; | |
378 | ||
379 | case '+' : /* add */ | |
380 | if (check_stack(2)) | |
381 | { | |
382 | bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num); | |
383 | pop(); | |
384 | pop(); | |
385 | push_num (temp_num); | |
386 | init_num (&temp_num); | |
387 | } | |
388 | break; | |
389 | ||
390 | case '-' : /* subtract */ | |
391 | if (check_stack(2)) | |
392 | { | |
393 | bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num); | |
394 | pop(); | |
395 | pop(); | |
396 | push_num (temp_num); | |
397 | init_num (&temp_num); | |
398 | } | |
399 | break; | |
400 | ||
401 | case '*' : /* multiply */ | |
402 | if (check_stack(2)) | |
403 | { | |
404 | bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num, | |
405 | &temp_num, scale); | |
406 | pop(); | |
407 | pop(); | |
408 | push_num (temp_num); | |
409 | init_num (&temp_num); | |
410 | } | |
411 | break; | |
412 | ||
413 | case '/' : /* divide */ | |
414 | if (check_stack(2)) | |
415 | { | |
416 | if (bc_divide (ex_stack->s_next->s_num, | |
417 | ex_stack->s_num, &temp_num, scale) == 0) | |
418 | { | |
419 | pop(); | |
420 | pop(); | |
421 | push_num (temp_num); | |
422 | init_num (&temp_num); | |
423 | } | |
424 | else | |
425 | rt_error ("Divide by zero"); | |
426 | } | |
427 | break; | |
428 | ||
429 | case '%' : /* remainder */ | |
430 | if (check_stack(2)) | |
431 | { | |
432 | if (is_zero (ex_stack->s_num)) | |
433 | rt_error ("Modulo by zero"); | |
434 | else | |
435 | { | |
436 | bc_modulo (ex_stack->s_next->s_num, | |
437 | ex_stack->s_num, &temp_num, scale); | |
438 | pop(); | |
439 | pop(); | |
440 | push_num (temp_num); | |
441 | init_num (&temp_num); | |
442 | } | |
443 | } | |
444 | break; | |
445 | ||
446 | case '^' : /* raise */ | |
447 | if (check_stack(2)) | |
448 | { | |
449 | bc_raise (ex_stack->s_next->s_num, | |
450 | ex_stack->s_num, &temp_num, scale); | |
451 | if (is_zero (ex_stack->s_next->s_num) && is_neg (ex_stack->s_num)) | |
452 | rt_error ("divide by zero"); | |
453 | pop(); | |
454 | pop(); | |
455 | push_num (temp_num); | |
456 | init_num (&temp_num); | |
457 | } | |
458 | break; | |
459 | ||
460 | case '=' : /* compare equal */ | |
461 | if (check_stack(2)) | |
462 | { | |
463 | c_code = bc_compare (ex_stack->s_next->s_num, | |
464 | ex_stack->s_num) == 0; | |
465 | pop (); | |
466 | assign (c_code); | |
467 | } | |
468 | break; | |
469 | ||
470 | case '#' : /* compare not equal */ | |
471 | if (check_stack(2)) | |
472 | { | |
473 | c_code = bc_compare (ex_stack->s_next->s_num, | |
474 | ex_stack->s_num) != 0; | |
475 | pop (); | |
476 | assign (c_code); | |
477 | } | |
478 | break; | |
479 | ||
480 | case '<' : /* compare less than */ | |
481 | if (check_stack(2)) | |
482 | { | |
483 | c_code = bc_compare (ex_stack->s_next->s_num, | |
484 | ex_stack->s_num) == -1; | |
485 | pop (); | |
486 | assign (c_code); | |
487 | } | |
488 | break; | |
489 | ||
490 | case '{' : /* compare less than or equal */ | |
491 | if (check_stack(2)) | |
492 | { | |
493 | c_code = bc_compare (ex_stack->s_next->s_num, | |
494 | ex_stack->s_num) <= 0; | |
495 | pop (); | |
496 | assign (c_code); | |
497 | } | |
498 | break; | |
499 | ||
500 | case '>' : /* compare greater than */ | |
501 | if (check_stack(2)) | |
502 | { | |
503 | c_code = bc_compare (ex_stack->s_next->s_num, | |
504 | ex_stack->s_num) == 1; | |
505 | pop (); | |
506 | assign (c_code); | |
507 | } | |
508 | break; | |
509 | ||
510 | case '}' : /* compare greater than or equal */ | |
511 | if (check_stack(2)) | |
512 | { | |
513 | c_code = bc_compare (ex_stack->s_next->s_num, | |
514 | ex_stack->s_num) >= 0; | |
515 | pop (); | |
516 | assign (c_code); | |
517 | } | |
518 | break; | |
519 | ||
520 | default : /* error! */ | |
521 | rt_error ("bad instruction: inst=%c", inst); | |
522 | } | |
523 | } | |
524 | ||
525 | /* Clean up the interrupt stuff. */ | |
526 | if (interactive) | |
527 | signal (SIGINT, use_quit); | |
528 | ||
529 | /* Clean up the function stack and pop all autos/parameters. */ | |
530 | while (pc.pc_func != 0) | |
531 | { | |
532 | pop_vars(functions[pc.pc_func].f_autos); | |
533 | pop_vars(functions[pc.pc_func].f_params); | |
534 | fpop (); | |
535 | pc.pc_addr = fpop (); | |
536 | pc.pc_func = fpop (); | |
537 | } | |
538 | ||
539 | /* Clean up the execution stack. */ | |
540 | while (ex_stack != NULL) pop(); | |
541 | ||
542 | } | |
543 | ||
544 | ||
545 | /* Prog_char gets another byte from the program. It is used for | |
546 | conversion of text constants in the code to numbers. */ | |
547 | ||
548 | char | |
549 | prog_char () | |
550 | { | |
551 | return byte(&pc); | |
552 | } | |
553 | ||
554 | ||
555 | /* Read a character from the standard input. This function is used | |
556 | by the "read" function. */ | |
557 | ||
558 | char | |
559 | input_char () | |
560 | { | |
561 | char in_ch; | |
562 | ||
563 | /* Get a character from the standard input for the read function. */ | |
564 | in_ch = getchar(); | |
565 | ||
566 | /* Check for a \ quoted newline. */ | |
567 | if (in_ch == '\\') | |
568 | { | |
569 | in_ch = getchar(); | |
570 | if (in_ch == '\n') | |
571 | in_ch = getchar(); | |
572 | } | |
573 | ||
574 | /* Classify and preprocess the input character. */ | |
575 | if (isdigit(in_ch)) | |
576 | return (in_ch - '0'); | |
577 | if (in_ch >= 'A' && in_ch <= 'F') | |
578 | return (in_ch + 10 - 'A'); | |
579 | if (in_ch >= 'a' && in_ch <= 'f') | |
580 | return (in_ch + 10 - 'a'); | |
581 | if (in_ch == '.' || in_ch == '+' || in_ch == '-') | |
582 | return (in_ch); | |
583 | if (in_ch <= ' ') | |
584 | return (' '); | |
585 | ||
586 | return (':'); | |
587 | } | |
588 | ||
589 | ||
590 | /* Push_constant converts a sequence of input characters as returned | |
591 | by IN_CHAR into a number. The number is pushed onto the execution | |
592 | stack. The number is converted as a number in base CONV_BASE. */ | |
593 | ||
594 | void | |
595 | push_constant (in_char, conv_base) | |
596 | char (*in_char)(VOID); | |
597 | int conv_base; | |
598 | { | |
599 | int digits; | |
600 | bc_num build, temp, result, mult, divisor; | |
601 | char in_ch, first_ch; | |
602 | char negative; | |
603 | ||
604 | /* Initialize all bc numbers */ | |
605 | init_num (&temp); | |
606 | init_num (&result); | |
607 | init_num (&mult); | |
608 | build = copy_num (_zero_); | |
609 | negative = FALSE; | |
610 | ||
611 | /* The conversion base. */ | |
612 | int2num (&mult, conv_base); | |
613 | ||
614 | /* Get things ready. */ | |
615 | in_ch = in_char(); | |
616 | while (in_ch == ' ') | |
617 | in_ch = in_char(); | |
618 | ||
619 | if (in_ch == '+') | |
620 | in_ch = in_char(); | |
621 | else | |
622 | if (in_ch == '-') | |
623 | { | |
624 | negative = TRUE; | |
625 | in_ch = in_char(); | |
626 | } | |
627 | ||
628 | /* Check for the special case of a single digit. */ | |
629 | if (in_ch < 16) | |
630 | { | |
631 | first_ch = in_ch; | |
632 | in_ch = in_char(); | |
633 | if (in_ch < 16 && first_ch >= conv_base) | |
634 | first_ch = conv_base - 1; | |
635 | int2num (&build, (int) first_ch); | |
636 | } | |
637 | ||
638 | /* Convert the integer part. */ | |
639 | while (in_ch < 16) | |
640 | { | |
641 | if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1; | |
642 | bc_multiply (build, mult, &result, 0); | |
643 | int2num (&temp, (int) in_ch); | |
644 | bc_add (result, temp, &build); | |
645 | in_ch = in_char(); | |
646 | } | |
647 | if (in_ch == '.') | |
648 | { | |
649 | in_ch = in_char(); | |
650 | if (in_ch >= conv_base) in_ch = conv_base-1; | |
651 | free_num (&result); | |
652 | free_num (&temp); | |
653 | divisor = copy_num (_one_); | |
654 | result = copy_num (_zero_); | |
655 | digits = 0; | |
656 | while (in_ch < 16) | |
657 | { | |
658 | bc_multiply (result, mult, &result, 0); | |
659 | int2num (&temp, (int) in_ch); | |
660 | bc_add (result, temp, &result); | |
661 | bc_multiply (divisor, mult, &divisor, 0); | |
662 | digits++; | |
663 | in_ch = in_char(); | |
664 | if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1; | |
665 | } | |
666 | bc_divide (result, divisor, &result, digits); | |
667 | bc_add (build, result, &build); | |
668 | } | |
669 | ||
670 | /* Final work. */ | |
671 | if (negative) | |
672 | bc_sub (_zero_, build, &build); | |
673 | ||
674 | push_num (build); | |
675 | free_num (&temp); | |
676 | free_num (&result); | |
677 | free_num (&mult); | |
678 | } | |
679 | ||
680 | ||
681 | /* When converting base 10 constants from the program, we use this | |
682 | more efficient way to convert them to numbers. PC tells where | |
683 | the constant starts and is expected to be advanced to after | |
684 | the constant. */ | |
685 | ||
686 | void | |
687 | push_b10_const (pc) | |
688 | program_counter *pc; | |
689 | { | |
690 | bc_num build; | |
691 | program_counter look_pc; | |
692 | int kdigits, kscale; | |
693 | char inchar; | |
694 | char *ptr; | |
695 | ||
696 | /* Count the digits and get things ready. */ | |
697 | look_pc = *pc; | |
698 | kdigits = 0; | |
699 | kscale = 0; | |
700 | inchar = byte (&look_pc); | |
701 | while (inchar != '.' && inchar != ':') | |
702 | { | |
703 | kdigits++; | |
704 | inchar = byte(&look_pc); | |
705 | } | |
706 | if (inchar == '.' ) | |
707 | { | |
708 | inchar = byte(&look_pc); | |
709 | while (inchar != ':') | |
710 | { | |
711 | kscale++; | |
712 | inchar = byte(&look_pc); | |
713 | } | |
714 | } | |
715 | ||
716 | /* Get the first character again and move the pc. */ | |
717 | inchar = byte(pc); | |
718 | ||
719 | /* Secial cases of 0, 1, and A-F single inputs. */ | |
720 | if (kdigits == 1 && kscale == 0) | |
721 | { | |
722 | if (inchar == 0) | |
723 | { | |
724 | push_copy (_zero_); | |
725 | inchar = byte(pc); | |
726 | return; | |
727 | } | |
728 | if (inchar == 1) { | |
729 | push_copy (_one_); | |
730 | inchar = byte(pc); | |
731 | return; | |
732 | } | |
733 | if (inchar > 9) | |
734 | { | |
735 | init_num (&build); | |
736 | int2num (&build, inchar); | |
737 | push_num (build); | |
738 | inchar = byte(pc); | |
739 | return; | |
740 | } | |
741 | } | |
742 | ||
743 | /* Build the new number. */ | |
744 | if (kdigits == 0) | |
745 | { | |
746 | build = new_num (1,kscale); | |
747 | ptr = build->n_value; | |
748 | *ptr++ = 0; | |
749 | } | |
750 | else | |
751 | { | |
752 | build = new_num (kdigits,kscale); | |
753 | ptr = build->n_value; | |
754 | } | |
755 | ||
756 | while (inchar != ':') | |
757 | { | |
758 | if (inchar != '.') | |
759 | if (inchar > 9) | |
760 | *ptr++ = 9; | |
761 | else | |
762 | *ptr++ = inchar; | |
763 | inchar = byte(pc); | |
764 | } | |
765 | push_num (build); | |
766 | } | |
767 | ||
768 | ||
769 | /* Put the correct value on the stack for C_CODE. Frees TOS num. */ | |
770 | ||
771 | void | |
772 | assign (c_code) | |
773 | char c_code; | |
774 | { | |
775 | free_num (&ex_stack->s_num); | |
776 | if (c_code) | |
777 | ex_stack->s_num = copy_num (_one_); | |
778 | else | |
779 | ex_stack->s_num = copy_num (_zero_); | |
780 | } |