xref: /netbsd-src/external/bsd/bc/dist/execute.c (revision 341df6449e0758ecbc5c5009a483a1f5c365efea)
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