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