xref: /dragonfly/usr.bin/dc/bcode.c (revision a977bf87)
1f2d37758SMatthew Dillon /*
2*a977bf87SJoris Giovannangeli  * $OpenBSD: bcode.c,v 1.45 2012/11/07 11:06:14 otto Exp $
3bbd33d1bSSascha Wildner  * $DragonFly: src/usr.bin/dc/bcode.c,v 1.3 2008/09/14 21:08:29 swildner Exp $
4f2d37758SMatthew Dillon  */
5f2d37758SMatthew Dillon 
6f2d37758SMatthew Dillon /*
7f2d37758SMatthew Dillon  * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
8f2d37758SMatthew Dillon  *
9f2d37758SMatthew Dillon  * Permission to use, copy, modify, and distribute this software for any
10f2d37758SMatthew Dillon  * purpose with or without fee is hereby granted, provided that the above
11f2d37758SMatthew Dillon  * copyright notice and this permission notice appear in all copies.
12f2d37758SMatthew Dillon  *
13f2d37758SMatthew Dillon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14f2d37758SMatthew Dillon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15f2d37758SMatthew Dillon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16f2d37758SMatthew Dillon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17f2d37758SMatthew Dillon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18f2d37758SMatthew Dillon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19f2d37758SMatthew Dillon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20f2d37758SMatthew Dillon  */
21f2d37758SMatthew Dillon 
22f2d37758SMatthew Dillon #include <openssl/ssl.h>
23f2d37758SMatthew Dillon #include <err.h>
24f2d37758SMatthew Dillon #include <limits.h>
25f2d37758SMatthew Dillon #include <signal.h>
26f2d37758SMatthew Dillon #include <stdio.h>
27f2d37758SMatthew Dillon #include <stdlib.h>
28f2d37758SMatthew Dillon #include <string.h>
29f2d37758SMatthew Dillon 
30f2d37758SMatthew Dillon #include "extern.h"
31f2d37758SMatthew Dillon 
32f2d37758SMatthew Dillon /* #define	DEBUGGING */
33f2d37758SMatthew Dillon 
34f2d37758SMatthew Dillon #define MAX_ARRAY_INDEX		2048
35abcef8f0SSascha Wildner #define READSTACK_SIZE		8
36f2d37758SMatthew Dillon 
37f2d37758SMatthew Dillon #define NO_ELSE			-2	/* -1 is EOF */
38f2d37758SMatthew Dillon #define REG_ARRAY_SIZE_SMALL	(UCHAR_MAX + 1)
39f2d37758SMatthew Dillon #define REG_ARRAY_SIZE_BIG	(UCHAR_MAX + 1 + USHRT_MAX + 1)
40f2d37758SMatthew Dillon 
41f2d37758SMatthew Dillon struct bmachine {
42f2d37758SMatthew Dillon 	struct stack		stack;
43f2d37758SMatthew Dillon 	u_int			scale;
44f2d37758SMatthew Dillon 	u_int			obase;
45f2d37758SMatthew Dillon 	u_int			ibase;
46abcef8f0SSascha Wildner 	size_t			readsp;
47f2d37758SMatthew Dillon 	bool			extended_regs;
48f2d37758SMatthew Dillon 	size_t			reg_array_size;
49f2d37758SMatthew Dillon 	struct stack		*reg;
50abcef8f0SSascha Wildner 	volatile sig_atomic_t	interrupted;
51abcef8f0SSascha Wildner 	struct source		*readstack;
52abcef8f0SSascha Wildner 	size_t			readstack_sz;
53f2d37758SMatthew Dillon };
54f2d37758SMatthew Dillon 
55f2d37758SMatthew Dillon static struct bmachine	bmachine;
56f2d37758SMatthew Dillon static void sighandler(int);
57f2d37758SMatthew Dillon 
58f2d37758SMatthew Dillon static __inline int	readch(void);
59*a977bf87SJoris Giovannangeli static __inline void	unreadch(void);
60f2d37758SMatthew Dillon static __inline char	*readline(void);
61f2d37758SMatthew Dillon static __inline void	src_free(void);
62f2d37758SMatthew Dillon 
63f2d37758SMatthew Dillon static __inline u_int	max(u_int, u_int);
64f2d37758SMatthew Dillon static u_long		get_ulong(struct number *);
65f2d37758SMatthew Dillon 
66f2d37758SMatthew Dillon static __inline void	push_number(struct number *);
67f2d37758SMatthew Dillon static __inline void	push_string(char *);
68f2d37758SMatthew Dillon static __inline void	push(struct value *);
69f2d37758SMatthew Dillon static __inline struct value *tos(void);
70f2d37758SMatthew Dillon static __inline struct number	*pop_number(void);
71f2d37758SMatthew Dillon static __inline char	*pop_string(void);
72f2d37758SMatthew Dillon static __inline void	clear_stack(void);
73f2d37758SMatthew Dillon static __inline void	print_tos(void);
74f2d37758SMatthew Dillon static void		pop_print(void);
75f2d37758SMatthew Dillon static void		pop_printn(void);
76f2d37758SMatthew Dillon static __inline void	print_stack(void);
77f2d37758SMatthew Dillon static __inline void	dup(void);
78f2d37758SMatthew Dillon static void		swap(void);
79f2d37758SMatthew Dillon static void		drop(void);
80f2d37758SMatthew Dillon 
81f2d37758SMatthew Dillon static void		get_scale(void);
82f2d37758SMatthew Dillon static void		set_scale(void);
83f2d37758SMatthew Dillon static void		get_obase(void);
84f2d37758SMatthew Dillon static void		set_obase(void);
85f2d37758SMatthew Dillon static void		get_ibase(void);
86f2d37758SMatthew Dillon static void		set_ibase(void);
87f2d37758SMatthew Dillon static void		stackdepth(void);
88f2d37758SMatthew Dillon static void		push_scale(void);
89f2d37758SMatthew Dillon static u_int		count_digits(const struct number *);
90f2d37758SMatthew Dillon static void		num_digits(void);
91f2d37758SMatthew Dillon static void		to_ascii(void);
92f2d37758SMatthew Dillon static void		push_line(void);
93f2d37758SMatthew Dillon static void		comment(void);
94f2d37758SMatthew Dillon static void		bexec(char *);
95f2d37758SMatthew Dillon static void		badd(void);
96f2d37758SMatthew Dillon static void		bsub(void);
97f2d37758SMatthew Dillon static void		bmul(void);
98f2d37758SMatthew Dillon static void		bdiv(void);
99f2d37758SMatthew Dillon static void		bmod(void);
100f2d37758SMatthew Dillon static void		bdivmod(void);
101f2d37758SMatthew Dillon static void		bexp(void);
102abcef8f0SSascha Wildner static bool		bsqrt_stop(const BIGNUM *, const BIGNUM *, u_int *);
103f2d37758SMatthew Dillon static void		bsqrt(void);
104f2d37758SMatthew Dillon static void		not(void);
105f2d37758SMatthew Dillon static void		equal_numbers(void);
106f2d37758SMatthew Dillon static void		less_numbers(void);
107f2d37758SMatthew Dillon static void		lesseq_numbers(void);
108f2d37758SMatthew Dillon static void		equal(void);
109f2d37758SMatthew Dillon static void		not_equal(void);
110f2d37758SMatthew Dillon static void		less(void);
111f2d37758SMatthew Dillon static void		not_less(void);
112f2d37758SMatthew Dillon static void		greater(void);
113f2d37758SMatthew Dillon static void		not_greater(void);
114f2d37758SMatthew Dillon static void		not_compare(void);
115f2d37758SMatthew Dillon static bool		compare_numbers(enum bcode_compare, struct number *,
116f2d37758SMatthew Dillon 			    struct number *);
117f2d37758SMatthew Dillon static void		compare(enum bcode_compare);
118f2d37758SMatthew Dillon static int		readreg(void);
119f2d37758SMatthew Dillon static void		load(void);
120f2d37758SMatthew Dillon static void		store(void);
121f2d37758SMatthew Dillon static void		load_stack(void);
122f2d37758SMatthew Dillon static void		store_stack(void);
123f2d37758SMatthew Dillon static void		load_array(void);
124f2d37758SMatthew Dillon static void		store_array(void);
125f2d37758SMatthew Dillon static void		nop(void);
126f2d37758SMatthew Dillon static void		quit(void);
127f2d37758SMatthew Dillon static void		quitN(void);
128f2d37758SMatthew Dillon static void		skipN(void);
129f2d37758SMatthew Dillon static void		skip_until_mark(void);
130f2d37758SMatthew Dillon static void		parse_number(void);
131f2d37758SMatthew Dillon static void		unknown(void);
132f2d37758SMatthew Dillon static void		eval_string(char *);
133f2d37758SMatthew Dillon static void		eval_line(void);
134f2d37758SMatthew Dillon static void		eval_tos(void);
135f2d37758SMatthew Dillon 
136f2d37758SMatthew Dillon 
137f2d37758SMatthew Dillon typedef void		(*opcode_function)(void);
138f2d37758SMatthew Dillon 
139f2d37758SMatthew Dillon struct jump_entry {
140f2d37758SMatthew Dillon 	u_char		ch;
141f2d37758SMatthew Dillon 	opcode_function	f;
142f2d37758SMatthew Dillon };
143f2d37758SMatthew Dillon 
144f2d37758SMatthew Dillon static opcode_function jump_table[UCHAR_MAX];
145f2d37758SMatthew Dillon 
146f2d37758SMatthew Dillon static const struct jump_entry jump_table_data[] = {
147f2d37758SMatthew Dillon 	{ ' ',	nop		},
148f2d37758SMatthew Dillon 	{ '!',	not_compare	},
149f2d37758SMatthew Dillon 	{ '#',	comment		},
150f2d37758SMatthew Dillon 	{ '%',	bmod		},
151f2d37758SMatthew Dillon 	{ '(',	less_numbers	},
152f2d37758SMatthew Dillon 	{ '*',	bmul		},
153f2d37758SMatthew Dillon 	{ '+',	badd		},
154f2d37758SMatthew Dillon 	{ '-',	bsub		},
155f2d37758SMatthew Dillon 	{ '.',	parse_number	},
156f2d37758SMatthew Dillon 	{ '/',	bdiv		},
157f2d37758SMatthew Dillon 	{ '0',	parse_number	},
158f2d37758SMatthew Dillon 	{ '1',	parse_number	},
159f2d37758SMatthew Dillon 	{ '2',	parse_number	},
160f2d37758SMatthew Dillon 	{ '3',	parse_number	},
161f2d37758SMatthew Dillon 	{ '4',	parse_number	},
162f2d37758SMatthew Dillon 	{ '5',	parse_number	},
163f2d37758SMatthew Dillon 	{ '6',	parse_number	},
164f2d37758SMatthew Dillon 	{ '7',	parse_number	},
165f2d37758SMatthew Dillon 	{ '8',	parse_number	},
166f2d37758SMatthew Dillon 	{ '9',	parse_number	},
167f2d37758SMatthew Dillon 	{ ':',	store_array	},
168f2d37758SMatthew Dillon 	{ ';',	load_array	},
169f2d37758SMatthew Dillon 	{ '<',	less		},
170f2d37758SMatthew Dillon 	{ '=',	equal		},
171f2d37758SMatthew Dillon 	{ '>',	greater		},
172f2d37758SMatthew Dillon 	{ '?',	eval_line	},
173f2d37758SMatthew Dillon 	{ 'A',	parse_number	},
174f2d37758SMatthew Dillon 	{ 'B',	parse_number	},
175f2d37758SMatthew Dillon 	{ 'C',	parse_number	},
176f2d37758SMatthew Dillon 	{ 'D',	parse_number	},
177f2d37758SMatthew Dillon 	{ 'E',	parse_number	},
178f2d37758SMatthew Dillon 	{ 'F',	parse_number	},
179f2d37758SMatthew Dillon 	{ 'G',	equal_numbers	},
180f2d37758SMatthew Dillon 	{ 'I',	get_ibase	},
181f2d37758SMatthew Dillon 	{ 'J',	skipN		},
182f2d37758SMatthew Dillon 	{ 'K',	get_scale	},
183f2d37758SMatthew Dillon 	{ 'L',	load_stack	},
184f2d37758SMatthew Dillon 	{ 'M',	nop		},
185f2d37758SMatthew Dillon 	{ 'N',	not		},
186f2d37758SMatthew Dillon 	{ 'O',	get_obase	},
187f2d37758SMatthew Dillon 	{ 'P',	pop_print	},
188f2d37758SMatthew Dillon 	{ 'Q',	quitN		},
189f2d37758SMatthew Dillon 	{ 'R',	drop		},
190f2d37758SMatthew Dillon 	{ 'S',	store_stack	},
191f2d37758SMatthew Dillon 	{ 'X',	push_scale	},
192f2d37758SMatthew Dillon 	{ 'Z',	num_digits	},
193f2d37758SMatthew Dillon 	{ '[',	push_line	},
194f2d37758SMatthew Dillon 	{ '\f',	nop		},
195f2d37758SMatthew Dillon 	{ '\n',	nop		},
196f2d37758SMatthew Dillon 	{ '\r',	nop		},
197f2d37758SMatthew Dillon 	{ '\t',	nop		},
198f2d37758SMatthew Dillon 	{ '^',	bexp		},
199f2d37758SMatthew Dillon 	{ '_',	parse_number	},
200f2d37758SMatthew Dillon 	{ 'a',	to_ascii	},
201f2d37758SMatthew Dillon 	{ 'c',	clear_stack	},
202f2d37758SMatthew Dillon 	{ 'd',	dup		},
203f2d37758SMatthew Dillon 	{ 'f',	print_stack	},
204f2d37758SMatthew Dillon 	{ 'i',	set_ibase	},
205f2d37758SMatthew Dillon 	{ 'k',	set_scale	},
206f2d37758SMatthew Dillon 	{ 'l',	load		},
207f2d37758SMatthew Dillon 	{ 'n',	pop_printn	},
208f2d37758SMatthew Dillon 	{ 'o',	set_obase	},
209f2d37758SMatthew Dillon 	{ 'p',	print_tos	},
210f2d37758SMatthew Dillon 	{ 'q',	quit		},
211f2d37758SMatthew Dillon 	{ 'r',	swap		},
212f2d37758SMatthew Dillon 	{ 's',	store		},
213f2d37758SMatthew Dillon 	{ 'v',	bsqrt		},
214f2d37758SMatthew Dillon 	{ 'x',	eval_tos	},
215f2d37758SMatthew Dillon 	{ 'z',	stackdepth	},
216f2d37758SMatthew Dillon 	{ '{',	lesseq_numbers	},
217f2d37758SMatthew Dillon 	{ '~',	bdivmod		}
218f2d37758SMatthew Dillon };
219f2d37758SMatthew Dillon 
220f2d37758SMatthew Dillon #define JUMP_TABLE_DATA_SIZE \
221f2d37758SMatthew Dillon 	(sizeof(jump_table_data)/sizeof(jump_table_data[0]))
222f2d37758SMatthew Dillon 
223f2d37758SMatthew Dillon static void
sighandler(int ignored __unused)224abcef8f0SSascha Wildner sighandler(int ignored __unused)
225f2d37758SMatthew Dillon {
226f2d37758SMatthew Dillon 	bmachine.interrupted = true;
227f2d37758SMatthew Dillon }
228f2d37758SMatthew Dillon 
229f2d37758SMatthew Dillon void
init_bmachine(bool extended_registers)230f2d37758SMatthew Dillon init_bmachine(bool extended_registers)
231f2d37758SMatthew Dillon {
232f2d37758SMatthew Dillon 	int i;
233f2d37758SMatthew Dillon 
234f2d37758SMatthew Dillon 	bmachine.extended_regs = extended_registers;
235f2d37758SMatthew Dillon 	bmachine.reg_array_size = bmachine.extended_regs ?
236f2d37758SMatthew Dillon 	    REG_ARRAY_SIZE_BIG : REG_ARRAY_SIZE_SMALL;
237f2d37758SMatthew Dillon 
238*a977bf87SJoris Giovannangeli 	bmachine.reg = calloc(bmachine.reg_array_size,
239f2d37758SMatthew Dillon 	    sizeof(bmachine.reg[0]));
240f2d37758SMatthew Dillon 	if (bmachine.reg == NULL)
241f2d37758SMatthew Dillon 		err(1, NULL);
242f2d37758SMatthew Dillon 
243f2d37758SMatthew Dillon 	for (i = 0; i < UCHAR_MAX; i++)
244f2d37758SMatthew Dillon 		jump_table[i] = unknown;
245f2d37758SMatthew Dillon 	for (i = 0; i < JUMP_TABLE_DATA_SIZE; i++)
246f2d37758SMatthew Dillon 		jump_table[jump_table_data[i].ch] = jump_table_data[i].f;
247f2d37758SMatthew Dillon 
248f2d37758SMatthew Dillon 	stack_init(&bmachine.stack);
249f2d37758SMatthew Dillon 
250f2d37758SMatthew Dillon 	for (i = 0; i < bmachine.reg_array_size; i++)
251f2d37758SMatthew Dillon 		stack_init(&bmachine.reg[i]);
252f2d37758SMatthew Dillon 
253abcef8f0SSascha Wildner 	bmachine.readstack_sz = READSTACK_SIZE;
254*a977bf87SJoris Giovannangeli 	bmachine.readstack = calloc(sizeof(struct source),
255abcef8f0SSascha Wildner 	    bmachine.readstack_sz);
256abcef8f0SSascha Wildner 	if (bmachine.readstack == NULL)
257abcef8f0SSascha Wildner 		err(1, NULL);
258f2d37758SMatthew Dillon 	bmachine.obase = bmachine.ibase = 10;
259f2d37758SMatthew Dillon 	signal(SIGINT, sighandler);
260f2d37758SMatthew Dillon }
261f2d37758SMatthew Dillon 
262*a977bf87SJoris Giovannangeli u_int
bmachine_scale(void)263*a977bf87SJoris Giovannangeli bmachine_scale(void)
264*a977bf87SJoris Giovannangeli {
265*a977bf87SJoris Giovannangeli 	return bmachine.scale;
266*a977bf87SJoris Giovannangeli }
267*a977bf87SJoris Giovannangeli 
268f2d37758SMatthew Dillon /* Reset the things needed before processing a (new) file */
269f2d37758SMatthew Dillon void
reset_bmachine(struct source * src)270f2d37758SMatthew Dillon reset_bmachine(struct source *src)
271f2d37758SMatthew Dillon {
272f2d37758SMatthew Dillon 	bmachine.readsp = 0;
273f2d37758SMatthew Dillon 	bmachine.readstack[0] = *src;
274f2d37758SMatthew Dillon }
275f2d37758SMatthew Dillon 
276f2d37758SMatthew Dillon static __inline int
readch(void)277f2d37758SMatthew Dillon readch(void)
278f2d37758SMatthew Dillon {
279f2d37758SMatthew Dillon 	struct source *src = &bmachine.readstack[bmachine.readsp];
280f2d37758SMatthew Dillon 
281f2d37758SMatthew Dillon 	return src->vtable->readchar(src);
282f2d37758SMatthew Dillon }
283f2d37758SMatthew Dillon 
284*a977bf87SJoris Giovannangeli static __inline void
unreadch(void)285f2d37758SMatthew Dillon unreadch(void)
286f2d37758SMatthew Dillon {
287f2d37758SMatthew Dillon 	struct source *src = &bmachine.readstack[bmachine.readsp];
288f2d37758SMatthew Dillon 
289*a977bf87SJoris Giovannangeli 	src->vtable->unreadchar(src);
290f2d37758SMatthew Dillon }
291f2d37758SMatthew Dillon 
292f2d37758SMatthew Dillon static __inline char *
readline(void)293f2d37758SMatthew Dillon readline(void)
294f2d37758SMatthew Dillon {
295f2d37758SMatthew Dillon 	struct source *src = &bmachine.readstack[bmachine.readsp];
296f2d37758SMatthew Dillon 
297f2d37758SMatthew Dillon 	return src->vtable->readline(src);
298f2d37758SMatthew Dillon }
299f2d37758SMatthew Dillon 
300f2d37758SMatthew Dillon static __inline void
src_free(void)301f2d37758SMatthew Dillon src_free(void)
302f2d37758SMatthew Dillon {
303f2d37758SMatthew Dillon 	struct source *src = &bmachine.readstack[bmachine.readsp];
304f2d37758SMatthew Dillon 
305f2d37758SMatthew Dillon 	src->vtable->free(src);
306f2d37758SMatthew Dillon }
307f2d37758SMatthew Dillon 
308f2d37758SMatthew Dillon #ifdef DEBUGGING
309f2d37758SMatthew Dillon void
pn(const char * str,const struct number * n)310f2d37758SMatthew Dillon pn(const char *str, const struct number *n)
311f2d37758SMatthew Dillon {
312f2d37758SMatthew Dillon 	char *p = BN_bn2dec(n->number);
313f2d37758SMatthew Dillon 	if (p == NULL)
314f2d37758SMatthew Dillon 		err(1, "BN_bn2dec failed");
315f2d37758SMatthew Dillon 	fputs(str, stderr);
316f2d37758SMatthew Dillon 	fprintf(stderr, " %s (%u)\n" , p, n->scale);
317f2d37758SMatthew Dillon 	OPENSSL_free(p);
318f2d37758SMatthew Dillon }
319f2d37758SMatthew Dillon 
320f2d37758SMatthew Dillon void
pbn(const char * str,const BIGNUM * n)321f2d37758SMatthew Dillon pbn(const char *str, const BIGNUM *n)
322f2d37758SMatthew Dillon {
323f2d37758SMatthew Dillon 	char *p = BN_bn2dec(n);
324f2d37758SMatthew Dillon 	if (p == NULL)
325f2d37758SMatthew Dillon 		err(1, "BN_bn2dec failed");
326f2d37758SMatthew Dillon 	fputs(str, stderr);
327f2d37758SMatthew Dillon 	fprintf(stderr, " %s\n", p);
328f2d37758SMatthew Dillon 	OPENSSL_free(p);
329f2d37758SMatthew Dillon }
330f2d37758SMatthew Dillon 
331f2d37758SMatthew Dillon #endif
332f2d37758SMatthew Dillon 
333f2d37758SMatthew Dillon static __inline u_int
max(u_int a,u_int b)334f2d37758SMatthew Dillon max(u_int a, u_int b)
335f2d37758SMatthew Dillon {
336f2d37758SMatthew Dillon 	return a > b ? a : b;
337f2d37758SMatthew Dillon }
338f2d37758SMatthew Dillon 
339f2d37758SMatthew Dillon static unsigned long factors[] = {
340f2d37758SMatthew Dillon 	0, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
341f2d37758SMatthew Dillon 	100000000, 1000000000
342f2d37758SMatthew Dillon };
343f2d37758SMatthew Dillon 
344f2d37758SMatthew Dillon void
scale_number(BIGNUM * n,int s)345f2d37758SMatthew Dillon scale_number(BIGNUM *n, int s)
346f2d37758SMatthew Dillon {
347f2d37758SMatthew Dillon 	int abs_scale;
348f2d37758SMatthew Dillon 
349f2d37758SMatthew Dillon 	if (s == 0)
350f2d37758SMatthew Dillon 		return;
351f2d37758SMatthew Dillon 
352f2d37758SMatthew Dillon 	abs_scale = s > 0 ? s : -s;
353f2d37758SMatthew Dillon 
354f2d37758SMatthew Dillon 	if (abs_scale < sizeof(factors)/sizeof(factors[0])) {
355f2d37758SMatthew Dillon 		if (s > 0)
356f2d37758SMatthew Dillon 			bn_check(BN_mul_word(n, factors[abs_scale]));
357f2d37758SMatthew Dillon 		else
358f2d37758SMatthew Dillon 			BN_div_word(n, factors[abs_scale]);
359f2d37758SMatthew Dillon 	} else {
360f2d37758SMatthew Dillon 		BIGNUM *a, *p;
361f2d37758SMatthew Dillon 		BN_CTX *ctx;
362f2d37758SMatthew Dillon 
363f2d37758SMatthew Dillon 		a = BN_new();
364f2d37758SMatthew Dillon 		bn_checkp(a);
365f2d37758SMatthew Dillon 		p = BN_new();
366f2d37758SMatthew Dillon 		bn_checkp(p);
367f2d37758SMatthew Dillon 		ctx = BN_CTX_new();
368f2d37758SMatthew Dillon 		bn_checkp(ctx);
369f2d37758SMatthew Dillon 
370f2d37758SMatthew Dillon 		bn_check(BN_set_word(a, 10));
371f2d37758SMatthew Dillon 		bn_check(BN_set_word(p, abs_scale));
372f2d37758SMatthew Dillon 		bn_check(BN_exp(a, a, p, ctx));
373f2d37758SMatthew Dillon 		if (s > 0)
374f2d37758SMatthew Dillon 			bn_check(BN_mul(n, n, a, ctx));
375f2d37758SMatthew Dillon 		else
376f2d37758SMatthew Dillon 			bn_check(BN_div(n, NULL, n, a, ctx));
377f2d37758SMatthew Dillon 		BN_CTX_free(ctx);
378f2d37758SMatthew Dillon 		BN_free(a);
379f2d37758SMatthew Dillon 		BN_free(p);
380f2d37758SMatthew Dillon 	}
381f2d37758SMatthew Dillon }
382f2d37758SMatthew Dillon 
383f2d37758SMatthew Dillon void
split_number(const struct number * n,BIGNUM * i,BIGNUM * f)384f2d37758SMatthew Dillon split_number(const struct number *n, BIGNUM *i, BIGNUM *f)
385f2d37758SMatthew Dillon {
386f2d37758SMatthew Dillon 	u_long rem;
387f2d37758SMatthew Dillon 
388f2d37758SMatthew Dillon 	bn_checkp(BN_copy(i, n->number));
389f2d37758SMatthew Dillon 
390f2d37758SMatthew Dillon 	if (n->scale == 0 && f != NULL)
391*a977bf87SJoris Giovannangeli 		bn_check(BN_zero(f));
392f2d37758SMatthew Dillon 	else if (n->scale < sizeof(factors)/sizeof(factors[0])) {
393f2d37758SMatthew Dillon 		rem = BN_div_word(i, factors[n->scale]);
394f2d37758SMatthew Dillon 		if (f != NULL)
395*a977bf87SJoris Giovannangeli 			bn_check(BN_set_word(f, rem));
396f2d37758SMatthew Dillon 	} else {
397f2d37758SMatthew Dillon 		BIGNUM *a, *p;
398f2d37758SMatthew Dillon 		BN_CTX *ctx;
399f2d37758SMatthew Dillon 
400f2d37758SMatthew Dillon 		a = BN_new();
401f2d37758SMatthew Dillon 		bn_checkp(a);
402f2d37758SMatthew Dillon 		p = BN_new();
403f2d37758SMatthew Dillon 		bn_checkp(p);
404f2d37758SMatthew Dillon 		ctx = BN_CTX_new();
405f2d37758SMatthew Dillon 		bn_checkp(ctx);
406f2d37758SMatthew Dillon 
407f2d37758SMatthew Dillon 		bn_check(BN_set_word(a, 10));
408f2d37758SMatthew Dillon 		bn_check(BN_set_word(p, n->scale));
409f2d37758SMatthew Dillon 		bn_check(BN_exp(a, a, p, ctx));
410f2d37758SMatthew Dillon 		bn_check(BN_div(i, f, n->number, a, ctx));
411f2d37758SMatthew Dillon 		BN_CTX_free(ctx);
412f2d37758SMatthew Dillon 		BN_free(a);
413f2d37758SMatthew Dillon 		BN_free(p);
414f2d37758SMatthew Dillon 	}
415f2d37758SMatthew Dillon }
416f2d37758SMatthew Dillon 
417f2d37758SMatthew Dillon __inline void
normalize(struct number * n,u_int s)418f2d37758SMatthew Dillon normalize(struct number *n, u_int s)
419f2d37758SMatthew Dillon {
420f2d37758SMatthew Dillon 	scale_number(n->number, s - n->scale);
421f2d37758SMatthew Dillon 	n->scale = s;
422f2d37758SMatthew Dillon }
423f2d37758SMatthew Dillon 
424f2d37758SMatthew Dillon static u_long
get_ulong(struct number * n)425f2d37758SMatthew Dillon get_ulong(struct number *n)
426f2d37758SMatthew Dillon {
427f2d37758SMatthew Dillon 	normalize(n, 0);
428f2d37758SMatthew Dillon 	return BN_get_word(n->number);
429f2d37758SMatthew Dillon }
430f2d37758SMatthew Dillon 
431f2d37758SMatthew Dillon void
negate(struct number * n)432f2d37758SMatthew Dillon negate(struct number *n)
433f2d37758SMatthew Dillon {
434*a977bf87SJoris Giovannangeli 	BN_set_negative(n->number, !BN_is_negative(n->number));
435f2d37758SMatthew Dillon }
436f2d37758SMatthew Dillon 
437f2d37758SMatthew Dillon static __inline void
push_number(struct number * n)438f2d37758SMatthew Dillon push_number(struct number *n)
439f2d37758SMatthew Dillon {
440f2d37758SMatthew Dillon 	stack_pushnumber(&bmachine.stack, n);
441f2d37758SMatthew Dillon }
442f2d37758SMatthew Dillon 
443f2d37758SMatthew Dillon static __inline void
push_string(char * string)444f2d37758SMatthew Dillon push_string(char *string)
445f2d37758SMatthew Dillon {
446f2d37758SMatthew Dillon 	stack_pushstring(&bmachine.stack, string);
447f2d37758SMatthew Dillon }
448f2d37758SMatthew Dillon 
449f2d37758SMatthew Dillon static __inline void
push(struct value * v)450f2d37758SMatthew Dillon push(struct value *v)
451f2d37758SMatthew Dillon {
452f2d37758SMatthew Dillon 	stack_push(&bmachine.stack, v);
453f2d37758SMatthew Dillon }
454f2d37758SMatthew Dillon 
455f2d37758SMatthew Dillon static __inline struct value *
tos(void)456f2d37758SMatthew Dillon tos(void)
457f2d37758SMatthew Dillon {
458f2d37758SMatthew Dillon 	return stack_tos(&bmachine.stack);
459f2d37758SMatthew Dillon }
460f2d37758SMatthew Dillon 
461f2d37758SMatthew Dillon static __inline struct value *
pop(void)462f2d37758SMatthew Dillon pop(void)
463f2d37758SMatthew Dillon {
464f2d37758SMatthew Dillon 	return stack_pop(&bmachine.stack);
465f2d37758SMatthew Dillon }
466f2d37758SMatthew Dillon 
467f2d37758SMatthew Dillon static __inline struct number *
pop_number(void)468f2d37758SMatthew Dillon pop_number(void)
469f2d37758SMatthew Dillon {
470f2d37758SMatthew Dillon 	return stack_popnumber(&bmachine.stack);
471f2d37758SMatthew Dillon }
472f2d37758SMatthew Dillon 
473f2d37758SMatthew Dillon static __inline char *
pop_string(void)474f2d37758SMatthew Dillon pop_string(void)
475f2d37758SMatthew Dillon {
476f2d37758SMatthew Dillon 	return stack_popstring(&bmachine.stack);
477f2d37758SMatthew Dillon }
478f2d37758SMatthew Dillon 
479f2d37758SMatthew Dillon static __inline void
clear_stack(void)480f2d37758SMatthew Dillon clear_stack(void)
481f2d37758SMatthew Dillon {
482f2d37758SMatthew Dillon 	stack_clear(&bmachine.stack);
483f2d37758SMatthew Dillon }
484f2d37758SMatthew Dillon 
485f2d37758SMatthew Dillon static __inline void
print_stack(void)486f2d37758SMatthew Dillon print_stack(void)
487f2d37758SMatthew Dillon {
488f2d37758SMatthew Dillon 	stack_print(stdout, &bmachine.stack, "", bmachine.obase);
489f2d37758SMatthew Dillon }
490f2d37758SMatthew Dillon 
491f2d37758SMatthew Dillon static __inline void
print_tos(void)492f2d37758SMatthew Dillon print_tos(void)
493f2d37758SMatthew Dillon {
494f2d37758SMatthew Dillon 	struct value *value = tos();
495f2d37758SMatthew Dillon 	if (value != NULL) {
496f2d37758SMatthew Dillon 		print_value(stdout, value, "", bmachine.obase);
497f2d37758SMatthew Dillon 		putchar('\n');
498f2d37758SMatthew Dillon 	}
499f2d37758SMatthew Dillon 	else
500f2d37758SMatthew Dillon 		warnx("stack empty");
501f2d37758SMatthew Dillon }
502f2d37758SMatthew Dillon 
503f2d37758SMatthew Dillon static void
pop_print(void)504f2d37758SMatthew Dillon pop_print(void)
505f2d37758SMatthew Dillon {
506f2d37758SMatthew Dillon 	struct value *value = pop();
507f2d37758SMatthew Dillon 
508f2d37758SMatthew Dillon 	if (value != NULL) {
509f2d37758SMatthew Dillon 		switch (value->type) {
510f2d37758SMatthew Dillon 		case BCODE_NONE:
511f2d37758SMatthew Dillon 			break;
512f2d37758SMatthew Dillon 		case BCODE_NUMBER:
513f2d37758SMatthew Dillon 			normalize(value->u.num, 0);
514f2d37758SMatthew Dillon 			print_ascii(stdout, value->u.num);
515f2d37758SMatthew Dillon 			fflush(stdout);
516f2d37758SMatthew Dillon 			break;
517f2d37758SMatthew Dillon 		case BCODE_STRING:
518f2d37758SMatthew Dillon 			fputs(value->u.string, stdout);
519f2d37758SMatthew Dillon 			fflush(stdout);
520f2d37758SMatthew Dillon 			break;
521f2d37758SMatthew Dillon 		}
522f2d37758SMatthew Dillon 		stack_free_value(value);
523f2d37758SMatthew Dillon 	}
524f2d37758SMatthew Dillon }
525f2d37758SMatthew Dillon 
526f2d37758SMatthew Dillon static void
pop_printn(void)527f2d37758SMatthew Dillon pop_printn(void)
528f2d37758SMatthew Dillon {
529f2d37758SMatthew Dillon 	struct value *value = pop();
530f2d37758SMatthew Dillon 
531f2d37758SMatthew Dillon 	if (value != NULL) {
532f2d37758SMatthew Dillon 		print_value(stdout, value, "", bmachine.obase);
533f2d37758SMatthew Dillon 		fflush(stdout);
534f2d37758SMatthew Dillon 		stack_free_value(value);
535f2d37758SMatthew Dillon 	}
536f2d37758SMatthew Dillon }
537f2d37758SMatthew Dillon 
538f2d37758SMatthew Dillon static __inline void
dup(void)539f2d37758SMatthew Dillon dup(void)
540f2d37758SMatthew Dillon {
541f2d37758SMatthew Dillon 	stack_dup(&bmachine.stack);
542f2d37758SMatthew Dillon }
543f2d37758SMatthew Dillon 
544f2d37758SMatthew Dillon static void
swap(void)545f2d37758SMatthew Dillon swap(void)
546f2d37758SMatthew Dillon {
547f2d37758SMatthew Dillon 	stack_swap(&bmachine.stack);
548f2d37758SMatthew Dillon }
549f2d37758SMatthew Dillon 
550f2d37758SMatthew Dillon static void
drop(void)551f2d37758SMatthew Dillon drop(void)
552f2d37758SMatthew Dillon {
553f2d37758SMatthew Dillon 	struct value *v = pop();
554f2d37758SMatthew Dillon 	if (v != NULL)
555f2d37758SMatthew Dillon 		stack_free_value(v);
556f2d37758SMatthew Dillon }
557f2d37758SMatthew Dillon 
558f2d37758SMatthew Dillon static void
get_scale(void)559f2d37758SMatthew Dillon get_scale(void)
560f2d37758SMatthew Dillon {
561f2d37758SMatthew Dillon 	struct number	*n;
562f2d37758SMatthew Dillon 
563f2d37758SMatthew Dillon 	n = new_number();
564f2d37758SMatthew Dillon 	bn_check(BN_set_word(n->number, bmachine.scale));
565f2d37758SMatthew Dillon 	push_number(n);
566f2d37758SMatthew Dillon }
567f2d37758SMatthew Dillon 
568f2d37758SMatthew Dillon static void
set_scale(void)569f2d37758SMatthew Dillon set_scale(void)
570f2d37758SMatthew Dillon {
571f2d37758SMatthew Dillon 	struct number	*n;
572f2d37758SMatthew Dillon 	u_long		scale;
573f2d37758SMatthew Dillon 
574f2d37758SMatthew Dillon 	n = pop_number();
575f2d37758SMatthew Dillon 	if (n != NULL) {
576*a977bf87SJoris Giovannangeli 		if (BN_is_negative(n->number))
577f2d37758SMatthew Dillon 			warnx("scale must be a nonnegative number");
578f2d37758SMatthew Dillon 		else {
579f2d37758SMatthew Dillon 			scale = get_ulong(n);
580*a977bf87SJoris Giovannangeli 			if (scale != BN_MASK2 && scale <= UINT_MAX)
581*a977bf87SJoris Giovannangeli 				bmachine.scale = (u_int)scale;
582f2d37758SMatthew Dillon 			else
583f2d37758SMatthew Dillon 				warnx("scale too large");
584f2d37758SMatthew Dillon 			}
585f2d37758SMatthew Dillon 		free_number(n);
586f2d37758SMatthew Dillon 	}
587f2d37758SMatthew Dillon }
588f2d37758SMatthew Dillon 
589f2d37758SMatthew Dillon static void
get_obase(void)590f2d37758SMatthew Dillon get_obase(void)
591f2d37758SMatthew Dillon {
592f2d37758SMatthew Dillon 	struct number	*n;
593f2d37758SMatthew Dillon 
594f2d37758SMatthew Dillon 	n = new_number();
595f2d37758SMatthew Dillon 	bn_check(BN_set_word(n->number, bmachine.obase));
596f2d37758SMatthew Dillon 	push_number(n);
597f2d37758SMatthew Dillon }
598f2d37758SMatthew Dillon 
599f2d37758SMatthew Dillon static void
set_obase(void)600f2d37758SMatthew Dillon set_obase(void)
601f2d37758SMatthew Dillon {
602f2d37758SMatthew Dillon 	struct number	*n;
603f2d37758SMatthew Dillon 	u_long		base;
604f2d37758SMatthew Dillon 
605f2d37758SMatthew Dillon 	n = pop_number();
606f2d37758SMatthew Dillon 	if (n != NULL) {
607f2d37758SMatthew Dillon 		base = get_ulong(n);
608*a977bf87SJoris Giovannangeli 		if (base != BN_MASK2 && base > 1 && base <= UINT_MAX)
609*a977bf87SJoris Giovannangeli 			bmachine.obase = (u_int)base;
610f2d37758SMatthew Dillon 		else
611f2d37758SMatthew Dillon 			warnx("output base must be a number greater than 1");
612f2d37758SMatthew Dillon 		free_number(n);
613f2d37758SMatthew Dillon 	}
614f2d37758SMatthew Dillon }
615f2d37758SMatthew Dillon 
616f2d37758SMatthew Dillon static void
get_ibase(void)617f2d37758SMatthew Dillon get_ibase(void)
618f2d37758SMatthew Dillon {
619f2d37758SMatthew Dillon 	struct number *n;
620f2d37758SMatthew Dillon 
621f2d37758SMatthew Dillon 	n = new_number();
622f2d37758SMatthew Dillon 	bn_check(BN_set_word(n->number, bmachine.ibase));
623f2d37758SMatthew Dillon 	push_number(n);
624f2d37758SMatthew Dillon }
625f2d37758SMatthew Dillon 
626f2d37758SMatthew Dillon static void
set_ibase(void)627f2d37758SMatthew Dillon set_ibase(void)
628f2d37758SMatthew Dillon {
629f2d37758SMatthew Dillon 	struct number	*n;
630f2d37758SMatthew Dillon 	u_long		base;
631f2d37758SMatthew Dillon 
632f2d37758SMatthew Dillon 	n = pop_number();
633f2d37758SMatthew Dillon 	if (n != NULL) {
634f2d37758SMatthew Dillon 		base = get_ulong(n);
635f2d37758SMatthew Dillon 		if (base != BN_MASK2 && 2 <= base && base <= 16)
636*a977bf87SJoris Giovannangeli 			bmachine.ibase = (u_int)base;
637f2d37758SMatthew Dillon 		else
638f2d37758SMatthew Dillon 			warnx("input base must be a number between 2 and 16 "
639f2d37758SMatthew Dillon 			    "(inclusive)");
640f2d37758SMatthew Dillon 		free_number(n);
641f2d37758SMatthew Dillon 	}
642f2d37758SMatthew Dillon }
643f2d37758SMatthew Dillon 
644f2d37758SMatthew Dillon static void
stackdepth(void)645f2d37758SMatthew Dillon stackdepth(void)
646f2d37758SMatthew Dillon {
647*a977bf87SJoris Giovannangeli 	size_t i;
648f2d37758SMatthew Dillon 	struct number *n;
649f2d37758SMatthew Dillon 
650f2d37758SMatthew Dillon 	i = stack_size(&bmachine.stack);
651f2d37758SMatthew Dillon 	n = new_number();
652f2d37758SMatthew Dillon 	bn_check(BN_set_word(n->number, i));
653f2d37758SMatthew Dillon 	push_number(n);
654f2d37758SMatthew Dillon }
655f2d37758SMatthew Dillon 
656f2d37758SMatthew Dillon static void
push_scale(void)657f2d37758SMatthew Dillon push_scale(void)
658f2d37758SMatthew Dillon {
659f2d37758SMatthew Dillon 	struct value	*value;
660f2d37758SMatthew Dillon 	u_int		scale = 0;
661f2d37758SMatthew Dillon 	struct number	*n;
662f2d37758SMatthew Dillon 
663f2d37758SMatthew Dillon 
664f2d37758SMatthew Dillon 	value = pop();
665f2d37758SMatthew Dillon 	if (value != NULL) {
666f2d37758SMatthew Dillon 		switch (value->type) {
667f2d37758SMatthew Dillon 		case BCODE_NONE:
668f2d37758SMatthew Dillon 			return;
669f2d37758SMatthew Dillon 		case BCODE_NUMBER:
670f2d37758SMatthew Dillon 			scale = value->u.num->scale;
671f2d37758SMatthew Dillon 			break;
672f2d37758SMatthew Dillon 		case BCODE_STRING:
673f2d37758SMatthew Dillon 			break;
674f2d37758SMatthew Dillon 		}
675f2d37758SMatthew Dillon 		stack_free_value(value);
676f2d37758SMatthew Dillon 		n = new_number();
677f2d37758SMatthew Dillon 		bn_check(BN_set_word(n->number, scale));
678f2d37758SMatthew Dillon 		push_number(n);
679f2d37758SMatthew Dillon 	}
680f2d37758SMatthew Dillon }
681f2d37758SMatthew Dillon 
682f2d37758SMatthew Dillon static u_int
count_digits(const struct number * n)683f2d37758SMatthew Dillon count_digits(const struct number *n)
684f2d37758SMatthew Dillon {
685f2d37758SMatthew Dillon 	struct number	*int_part, *fract_part;
686f2d37758SMatthew Dillon 	u_int		i;
687f2d37758SMatthew Dillon 
688f2d37758SMatthew Dillon 	if (BN_is_zero(n->number))
689*a977bf87SJoris Giovannangeli 		return n->scale ? n->scale : 1;
690f2d37758SMatthew Dillon 
691f2d37758SMatthew Dillon 	int_part = new_number();
692f2d37758SMatthew Dillon 	fract_part = new_number();
693f2d37758SMatthew Dillon 	fract_part->scale = n->scale;
694f2d37758SMatthew Dillon 	split_number(n, int_part->number, fract_part->number);
695f2d37758SMatthew Dillon 
696f2d37758SMatthew Dillon 	i = 0;
697f2d37758SMatthew Dillon 	while (!BN_is_zero(int_part->number)) {
698f2d37758SMatthew Dillon 		BN_div_word(int_part->number, 10);
699f2d37758SMatthew Dillon 		i++;
700f2d37758SMatthew Dillon 	}
701f2d37758SMatthew Dillon 	free_number(int_part);
702f2d37758SMatthew Dillon 	free_number(fract_part);
703f2d37758SMatthew Dillon 	return i + n->scale;
704f2d37758SMatthew Dillon }
705f2d37758SMatthew Dillon 
706f2d37758SMatthew Dillon static void
num_digits(void)707f2d37758SMatthew Dillon num_digits(void)
708f2d37758SMatthew Dillon {
709f2d37758SMatthew Dillon 	struct value	*value;
710*a977bf87SJoris Giovannangeli 	size_t		digits;
711f2d37758SMatthew Dillon 	struct number	*n = NULL;
712f2d37758SMatthew Dillon 
713f2d37758SMatthew Dillon 	value = pop();
714f2d37758SMatthew Dillon 	if (value != NULL) {
715f2d37758SMatthew Dillon 		switch (value->type) {
716f2d37758SMatthew Dillon 		case BCODE_NONE:
717f2d37758SMatthew Dillon 			return;
718f2d37758SMatthew Dillon 		case BCODE_NUMBER:
719f2d37758SMatthew Dillon 			digits = count_digits(value->u.num);
720f2d37758SMatthew Dillon 			n = new_number();
721f2d37758SMatthew Dillon 			bn_check(BN_set_word(n->number, digits));
722f2d37758SMatthew Dillon 			break;
723f2d37758SMatthew Dillon 		case BCODE_STRING:
724f2d37758SMatthew Dillon 			digits = strlen(value->u.string);
725f2d37758SMatthew Dillon 			n = new_number();
726f2d37758SMatthew Dillon 			bn_check(BN_set_word(n->number, digits));
727f2d37758SMatthew Dillon 			break;
728f2d37758SMatthew Dillon 		}
729f2d37758SMatthew Dillon 		stack_free_value(value);
730f2d37758SMatthew Dillon 		push_number(n);
731f2d37758SMatthew Dillon 	}
732f2d37758SMatthew Dillon }
733f2d37758SMatthew Dillon 
734f2d37758SMatthew Dillon static void
to_ascii(void)735f2d37758SMatthew Dillon to_ascii(void)
736f2d37758SMatthew Dillon {
737f2d37758SMatthew Dillon 	char		str[2];
738f2d37758SMatthew Dillon 	struct value	*value;
739f2d37758SMatthew Dillon 	struct number	*n;
740f2d37758SMatthew Dillon 
741f2d37758SMatthew Dillon 	value = pop();
742f2d37758SMatthew Dillon 	if (value != NULL) {
743f2d37758SMatthew Dillon 		str[1] = '\0';
744f2d37758SMatthew Dillon 		switch (value->type) {
745f2d37758SMatthew Dillon 		case BCODE_NONE:
746f2d37758SMatthew Dillon 			return;
747f2d37758SMatthew Dillon 		case BCODE_NUMBER:
748f2d37758SMatthew Dillon 			n = value->u.num;
749f2d37758SMatthew Dillon 			normalize(n, 0);
750f2d37758SMatthew Dillon 			if (BN_num_bits(n->number) > 8)
751f2d37758SMatthew Dillon 				bn_check(BN_mask_bits(n->number, 8));
752f2d37758SMatthew Dillon 			str[0] = BN_get_word(n->number);
753f2d37758SMatthew Dillon 			break;
754f2d37758SMatthew Dillon 		case BCODE_STRING:
755f2d37758SMatthew Dillon 			str[0] = value->u.string[0];
756f2d37758SMatthew Dillon 			break;
757f2d37758SMatthew Dillon 		}
758f2d37758SMatthew Dillon 		stack_free_value(value);
759f2d37758SMatthew Dillon 		push_string(bstrdup(str));
760f2d37758SMatthew Dillon 	}
761f2d37758SMatthew Dillon }
762f2d37758SMatthew Dillon 
763f2d37758SMatthew Dillon static int
readreg(void)764f2d37758SMatthew Dillon readreg(void)
765f2d37758SMatthew Dillon {
766f2d37758SMatthew Dillon 	int index, ch1, ch2;
767f2d37758SMatthew Dillon 
768f2d37758SMatthew Dillon 	index = readch();
769f2d37758SMatthew Dillon 	if (index == 0xff && bmachine.extended_regs) {
770f2d37758SMatthew Dillon 		ch1 = readch();
771f2d37758SMatthew Dillon 		ch2 = readch();
772f2d37758SMatthew Dillon 		if (ch1 == EOF || ch2 == EOF) {
773f2d37758SMatthew Dillon 			warnx("unexpected eof");
774f2d37758SMatthew Dillon 			index = -1;
775f2d37758SMatthew Dillon 		} else
776f2d37758SMatthew Dillon 			index = (ch1 << 8) + ch2 + UCHAR_MAX + 1;
777f2d37758SMatthew Dillon 	}
778f2d37758SMatthew Dillon 	if (index < 0 || index >= bmachine.reg_array_size) {
779f2d37758SMatthew Dillon 		warnx("internal error: reg num = %d", index);
780f2d37758SMatthew Dillon 		index = -1;
781f2d37758SMatthew Dillon 	}
782f2d37758SMatthew Dillon 	return index;
783f2d37758SMatthew Dillon }
784f2d37758SMatthew Dillon 
785f2d37758SMatthew Dillon static void
load(void)786f2d37758SMatthew Dillon load(void)
787f2d37758SMatthew Dillon {
788f2d37758SMatthew Dillon 	int		index;
789f2d37758SMatthew Dillon 	struct value	*v, copy;
790f2d37758SMatthew Dillon 	struct number	*n;
791f2d37758SMatthew Dillon 
792f2d37758SMatthew Dillon 	index = readreg();
793f2d37758SMatthew Dillon 	if (index >= 0) {
794f2d37758SMatthew Dillon 		v = stack_tos(&bmachine.reg[index]);
795f2d37758SMatthew Dillon 		if (v == NULL) {
796f2d37758SMatthew Dillon 			n = new_number();
797f2d37758SMatthew Dillon 			bn_check(BN_zero(n->number));
798f2d37758SMatthew Dillon 			push_number(n);
799f2d37758SMatthew Dillon 		} else
800f2d37758SMatthew Dillon 			push(stack_dup_value(v, &copy));
801f2d37758SMatthew Dillon 	}
802f2d37758SMatthew Dillon }
803f2d37758SMatthew Dillon 
804f2d37758SMatthew Dillon static void
store(void)805f2d37758SMatthew Dillon store(void)
806f2d37758SMatthew Dillon {
807f2d37758SMatthew Dillon 	int		index;
808f2d37758SMatthew Dillon 	struct value	*val;
809f2d37758SMatthew Dillon 
810f2d37758SMatthew Dillon 	index = readreg();
811f2d37758SMatthew Dillon 	if (index >= 0) {
812f2d37758SMatthew Dillon 		val = pop();
813f2d37758SMatthew Dillon 		if (val == NULL) {
814f2d37758SMatthew Dillon 			return;
815f2d37758SMatthew Dillon 		}
816f2d37758SMatthew Dillon 		stack_set_tos(&bmachine.reg[index], val);
817f2d37758SMatthew Dillon 	}
818f2d37758SMatthew Dillon }
819f2d37758SMatthew Dillon 
820f2d37758SMatthew Dillon static void
load_stack(void)821f2d37758SMatthew Dillon load_stack(void)
822f2d37758SMatthew Dillon {
823f2d37758SMatthew Dillon 	int		index;
824f2d37758SMatthew Dillon 	struct stack	*stack;
825*a977bf87SJoris Giovannangeli 	struct value	*value;
826f2d37758SMatthew Dillon 
827f2d37758SMatthew Dillon 	index = readreg();
828f2d37758SMatthew Dillon 	if (index >= 0) {
829f2d37758SMatthew Dillon 		stack = &bmachine.reg[index];
830f2d37758SMatthew Dillon 		value = NULL;
831f2d37758SMatthew Dillon 		if (stack_size(stack) > 0) {
832f2d37758SMatthew Dillon 			value = stack_pop(stack);
833f2d37758SMatthew Dillon 		}
834f2d37758SMatthew Dillon 		if (value != NULL)
835*a977bf87SJoris Giovannangeli 			push(value);
836f2d37758SMatthew Dillon 		else
837f2d37758SMatthew Dillon 			warnx("stack register '%c' (0%o) is empty",
838f2d37758SMatthew Dillon 			    index, index);
839f2d37758SMatthew Dillon 	}
840f2d37758SMatthew Dillon }
841f2d37758SMatthew Dillon 
842f2d37758SMatthew Dillon static void
store_stack(void)843f2d37758SMatthew Dillon store_stack(void)
844f2d37758SMatthew Dillon {
845f2d37758SMatthew Dillon 	int		index;
846f2d37758SMatthew Dillon 	struct value	*value;
847f2d37758SMatthew Dillon 
848f2d37758SMatthew Dillon 	index = readreg();
849f2d37758SMatthew Dillon 	if (index >= 0) {
850f2d37758SMatthew Dillon 		value = pop();
851f2d37758SMatthew Dillon 		if (value == NULL)
852f2d37758SMatthew Dillon 			return;
853f2d37758SMatthew Dillon 		stack_push(&bmachine.reg[index], value);
854f2d37758SMatthew Dillon 	}
855f2d37758SMatthew Dillon }
856f2d37758SMatthew Dillon 
857f2d37758SMatthew Dillon static void
load_array(void)858f2d37758SMatthew Dillon load_array(void)
859f2d37758SMatthew Dillon {
860f2d37758SMatthew Dillon 	int			reg;
861f2d37758SMatthew Dillon 	struct number		*inumber, *n;
862f2d37758SMatthew Dillon 	u_long			index;
863f2d37758SMatthew Dillon 	struct stack		*stack;
864f2d37758SMatthew Dillon 	struct value		*v, copy;
865f2d37758SMatthew Dillon 
866f2d37758SMatthew Dillon 	reg = readreg();
867f2d37758SMatthew Dillon 	if (reg >= 0) {
868f2d37758SMatthew Dillon 		inumber = pop_number();
869f2d37758SMatthew Dillon 		if (inumber == NULL)
870f2d37758SMatthew Dillon 			return;
871f2d37758SMatthew Dillon 		index = get_ulong(inumber);
872*a977bf87SJoris Giovannangeli 		if (BN_is_negative(inumber->number))
873f2d37758SMatthew Dillon 			warnx("negative index");
874f2d37758SMatthew Dillon 		else if (index == BN_MASK2 || index > MAX_ARRAY_INDEX)
875f2d37758SMatthew Dillon 			warnx("index too big");
876f2d37758SMatthew Dillon 		else {
877f2d37758SMatthew Dillon 			stack = &bmachine.reg[reg];
878f2d37758SMatthew Dillon 			v = frame_retrieve(stack, index);
879*a977bf87SJoris Giovannangeli 			if (v == NULL || v->type == BCODE_NONE ) {
880f2d37758SMatthew Dillon 				n = new_number();
881f2d37758SMatthew Dillon 				bn_check(BN_zero(n->number));
882f2d37758SMatthew Dillon 				push_number(n);
883f2d37758SMatthew Dillon 			}
884f2d37758SMatthew Dillon 			else
885f2d37758SMatthew Dillon 				push(stack_dup_value(v, &copy));
886f2d37758SMatthew Dillon 		}
887f2d37758SMatthew Dillon 		free_number(inumber);
888f2d37758SMatthew Dillon 	}
889f2d37758SMatthew Dillon }
890f2d37758SMatthew Dillon 
891f2d37758SMatthew Dillon static void
store_array(void)892f2d37758SMatthew Dillon store_array(void)
893f2d37758SMatthew Dillon {
894f2d37758SMatthew Dillon 	int			reg;
895f2d37758SMatthew Dillon 	struct number		*inumber;
896f2d37758SMatthew Dillon 	u_long			index;
897f2d37758SMatthew Dillon 	struct value		*value;
898f2d37758SMatthew Dillon 	struct stack		*stack;
899f2d37758SMatthew Dillon 
900f2d37758SMatthew Dillon 	reg = readreg();
901f2d37758SMatthew Dillon 	if (reg >= 0) {
902f2d37758SMatthew Dillon 		inumber = pop_number();
903f2d37758SMatthew Dillon 		if (inumber == NULL)
904f2d37758SMatthew Dillon 			return;
905f2d37758SMatthew Dillon 		value = pop();
906f2d37758SMatthew Dillon 		if (value == NULL) {
907f2d37758SMatthew Dillon 			free_number(inumber);
908f2d37758SMatthew Dillon 			return;
909f2d37758SMatthew Dillon 		}
910f2d37758SMatthew Dillon 		index = get_ulong(inumber);
911*a977bf87SJoris Giovannangeli 		if (BN_is_negative(inumber->number)) {
912f2d37758SMatthew Dillon 			warnx("negative index");
913f2d37758SMatthew Dillon 			stack_free_value(value);
914f2d37758SMatthew Dillon 		} else if (index == BN_MASK2 || index > MAX_ARRAY_INDEX) {
915f2d37758SMatthew Dillon 			warnx("index too big");
916f2d37758SMatthew Dillon 			stack_free_value(value);
917f2d37758SMatthew Dillon 		} else {
918f2d37758SMatthew Dillon 			stack = &bmachine.reg[reg];
919f2d37758SMatthew Dillon 			frame_assign(stack, index, value);
920f2d37758SMatthew Dillon 		}
921f2d37758SMatthew Dillon 		free_number(inumber);
922f2d37758SMatthew Dillon 	}
923f2d37758SMatthew Dillon }
924f2d37758SMatthew Dillon 
925f2d37758SMatthew Dillon static void
push_line(void)926f2d37758SMatthew Dillon push_line(void)
927f2d37758SMatthew Dillon {
928f2d37758SMatthew Dillon 	push_string(read_string(&bmachine.readstack[bmachine.readsp]));
929f2d37758SMatthew Dillon }
930f2d37758SMatthew Dillon 
931f2d37758SMatthew Dillon static void
comment(void)932f2d37758SMatthew Dillon comment(void)
933f2d37758SMatthew Dillon {
934f2d37758SMatthew Dillon 	free(readline());
935f2d37758SMatthew Dillon }
936f2d37758SMatthew Dillon 
937f2d37758SMatthew Dillon static void
bexec(char * line)938f2d37758SMatthew Dillon bexec(char *line)
939f2d37758SMatthew Dillon {
940f2d37758SMatthew Dillon 	system(line);
941f2d37758SMatthew Dillon 	free(line);
942f2d37758SMatthew Dillon }
943f2d37758SMatthew Dillon 
944f2d37758SMatthew Dillon static void
badd(void)945f2d37758SMatthew Dillon badd(void)
946f2d37758SMatthew Dillon {
947f2d37758SMatthew Dillon 	struct number	*a, *b;
948f2d37758SMatthew Dillon 	struct number	*r;
949f2d37758SMatthew Dillon 
950f2d37758SMatthew Dillon 	a = pop_number();
951f2d37758SMatthew Dillon 	if (a == NULL) {
952f2d37758SMatthew Dillon 		return;
953f2d37758SMatthew Dillon 	}
954f2d37758SMatthew Dillon 	b = pop_number();
955f2d37758SMatthew Dillon 	if (b == NULL) {
956f2d37758SMatthew Dillon 		push_number(a);
957f2d37758SMatthew Dillon 		return;
958f2d37758SMatthew Dillon 	}
959f2d37758SMatthew Dillon 
960f2d37758SMatthew Dillon 	r = new_number();
961f2d37758SMatthew Dillon 	r->scale = max(a->scale, b->scale);
962f2d37758SMatthew Dillon 	if (r->scale > a->scale)
963f2d37758SMatthew Dillon 		normalize(a, r->scale);
964f2d37758SMatthew Dillon 	else if (r->scale > b->scale)
965f2d37758SMatthew Dillon 		normalize(b, r->scale);
966f2d37758SMatthew Dillon 	bn_check(BN_add(r->number, a->number, b->number));
967f2d37758SMatthew Dillon 	push_number(r);
968f2d37758SMatthew Dillon 	free_number(a);
969f2d37758SMatthew Dillon 	free_number(b);
970f2d37758SMatthew Dillon }
971f2d37758SMatthew Dillon 
972f2d37758SMatthew Dillon static void
bsub(void)973f2d37758SMatthew Dillon bsub(void)
974f2d37758SMatthew Dillon {
975f2d37758SMatthew Dillon 	struct number	*a, *b;
976f2d37758SMatthew Dillon 	struct number	*r;
977f2d37758SMatthew Dillon 
978f2d37758SMatthew Dillon 	a = pop_number();
979f2d37758SMatthew Dillon 	if (a == NULL) {
980f2d37758SMatthew Dillon 		return;
981f2d37758SMatthew Dillon 	}
982f2d37758SMatthew Dillon 	b = pop_number();
983f2d37758SMatthew Dillon 	if (b == NULL) {
984f2d37758SMatthew Dillon 		push_number(a);
985f2d37758SMatthew Dillon 		return;
986f2d37758SMatthew Dillon 	}
987f2d37758SMatthew Dillon 
988f2d37758SMatthew Dillon 	r = new_number();
989f2d37758SMatthew Dillon 
990f2d37758SMatthew Dillon 	r->scale = max(a->scale, b->scale);
991f2d37758SMatthew Dillon 	if (r->scale > a->scale)
992f2d37758SMatthew Dillon 		normalize(a, r->scale);
993f2d37758SMatthew Dillon 	else if (r->scale > b->scale)
994f2d37758SMatthew Dillon 		normalize(b, r->scale);
995f2d37758SMatthew Dillon 	bn_check(BN_sub(r->number, b->number, a->number));
996f2d37758SMatthew Dillon 	push_number(r);
997f2d37758SMatthew Dillon 	free_number(a);
998f2d37758SMatthew Dillon 	free_number(b);
999f2d37758SMatthew Dillon }
1000f2d37758SMatthew Dillon 
1001f2d37758SMatthew Dillon void
bmul_number(struct number * r,struct number * a,struct number * b,u_int scale)1002*a977bf87SJoris Giovannangeli bmul_number(struct number *r, struct number *a, struct number *b, u_int scale)
1003f2d37758SMatthew Dillon {
1004f2d37758SMatthew Dillon 	BN_CTX		*ctx;
1005f2d37758SMatthew Dillon 
1006f2d37758SMatthew Dillon 	/* Create copies of the scales, since r might be equal to a or b */
1007f2d37758SMatthew Dillon 	u_int ascale = a->scale;
1008f2d37758SMatthew Dillon 	u_int bscale = b->scale;
1009f2d37758SMatthew Dillon 	u_int rscale = ascale + bscale;
1010f2d37758SMatthew Dillon 
1011f2d37758SMatthew Dillon 	ctx = BN_CTX_new();
1012f2d37758SMatthew Dillon 	bn_checkp(ctx);
1013f2d37758SMatthew Dillon 	bn_check(BN_mul(r->number, a->number, b->number, ctx));
1014f2d37758SMatthew Dillon 	BN_CTX_free(ctx);
1015f2d37758SMatthew Dillon 
1016f2d37758SMatthew Dillon 	r->scale = rscale;
1017*a977bf87SJoris Giovannangeli 	if (rscale > bmachine.scale && rscale > ascale && rscale > bscale)
1018*a977bf87SJoris Giovannangeli 		normalize(r, max(scale, max(ascale, bscale)));
1019f2d37758SMatthew Dillon }
1020f2d37758SMatthew Dillon 
1021f2d37758SMatthew Dillon static void
bmul(void)1022f2d37758SMatthew Dillon bmul(void)
1023f2d37758SMatthew Dillon {
1024f2d37758SMatthew Dillon 	struct number	*a, *b;
1025f2d37758SMatthew Dillon 	struct number	*r;
1026f2d37758SMatthew Dillon 
1027f2d37758SMatthew Dillon 	a = pop_number();
1028f2d37758SMatthew Dillon 	if (a == NULL) {
1029f2d37758SMatthew Dillon 		return;
1030f2d37758SMatthew Dillon 	}
1031f2d37758SMatthew Dillon 	b = pop_number();
1032f2d37758SMatthew Dillon 	if (b == NULL) {
1033f2d37758SMatthew Dillon 		push_number(a);
1034f2d37758SMatthew Dillon 		return;
1035f2d37758SMatthew Dillon 	}
1036f2d37758SMatthew Dillon 
1037f2d37758SMatthew Dillon 	r = new_number();
1038*a977bf87SJoris Giovannangeli 	bmul_number(r, a, b, bmachine.scale);
1039f2d37758SMatthew Dillon 
1040f2d37758SMatthew Dillon 	push_number(r);
1041f2d37758SMatthew Dillon 	free_number(a);
1042f2d37758SMatthew Dillon 	free_number(b);
1043f2d37758SMatthew Dillon }
1044f2d37758SMatthew Dillon 
1045f2d37758SMatthew Dillon static void
bdiv(void)1046f2d37758SMatthew Dillon bdiv(void)
1047f2d37758SMatthew Dillon {
1048f2d37758SMatthew Dillon 	struct number	*a, *b;
1049f2d37758SMatthew Dillon 	struct number	*r;
1050f2d37758SMatthew Dillon 	u_int		scale;
1051f2d37758SMatthew Dillon 	BN_CTX		*ctx;
1052f2d37758SMatthew Dillon 
1053f2d37758SMatthew Dillon 	a = pop_number();
1054f2d37758SMatthew Dillon 	if (a == NULL) {
1055f2d37758SMatthew Dillon 		return;
1056f2d37758SMatthew Dillon 	}
1057f2d37758SMatthew Dillon 	b = pop_number();
1058f2d37758SMatthew Dillon 	if (b == NULL) {
1059f2d37758SMatthew Dillon 		push_number(a);
1060f2d37758SMatthew Dillon 		return;
1061f2d37758SMatthew Dillon 	}
1062f2d37758SMatthew Dillon 
1063f2d37758SMatthew Dillon 	r = new_number();
1064f2d37758SMatthew Dillon 	r->scale = bmachine.scale;
1065f2d37758SMatthew Dillon 	scale = max(a->scale, b->scale);
1066f2d37758SMatthew Dillon 
1067f2d37758SMatthew Dillon 	if (BN_is_zero(a->number))
1068f2d37758SMatthew Dillon 		warnx("divide by zero");
1069f2d37758SMatthew Dillon 	else {
1070f2d37758SMatthew Dillon 		normalize(a, scale);
1071f2d37758SMatthew Dillon 		normalize(b, scale + r->scale);
1072f2d37758SMatthew Dillon 
1073f2d37758SMatthew Dillon 		ctx = BN_CTX_new();
1074f2d37758SMatthew Dillon 		bn_checkp(ctx);
1075f2d37758SMatthew Dillon 		bn_check(BN_div(r->number, NULL, b->number, a->number, ctx));
1076f2d37758SMatthew Dillon 		BN_CTX_free(ctx);
1077f2d37758SMatthew Dillon 	}
1078f2d37758SMatthew Dillon 	push_number(r);
1079f2d37758SMatthew Dillon 	free_number(a);
1080f2d37758SMatthew Dillon 	free_number(b);
1081f2d37758SMatthew Dillon }
1082f2d37758SMatthew Dillon 
1083f2d37758SMatthew Dillon static void
bmod(void)1084f2d37758SMatthew Dillon bmod(void)
1085f2d37758SMatthew Dillon {
1086f2d37758SMatthew Dillon 	struct number	*a, *b;
1087f2d37758SMatthew Dillon 	struct number	*r;
1088f2d37758SMatthew Dillon 	u_int		scale;
1089f2d37758SMatthew Dillon 	BN_CTX		*ctx;
1090f2d37758SMatthew Dillon 
1091f2d37758SMatthew Dillon 	a = pop_number();
1092f2d37758SMatthew Dillon 	if (a == NULL) {
1093f2d37758SMatthew Dillon 		return;
1094f2d37758SMatthew Dillon 	}
1095f2d37758SMatthew Dillon 	b = pop_number();
1096f2d37758SMatthew Dillon 	if (b == NULL) {
1097f2d37758SMatthew Dillon 		push_number(a);
1098f2d37758SMatthew Dillon 		return;
1099f2d37758SMatthew Dillon 	}
1100f2d37758SMatthew Dillon 
1101f2d37758SMatthew Dillon 	r = new_number();
1102f2d37758SMatthew Dillon 	scale = max(a->scale, b->scale);
1103f2d37758SMatthew Dillon 	r->scale = max(b->scale, a->scale + bmachine.scale);
1104f2d37758SMatthew Dillon 
1105f2d37758SMatthew Dillon 	if (BN_is_zero(a->number))
1106f2d37758SMatthew Dillon 		warnx("remainder by zero");
1107f2d37758SMatthew Dillon 	else {
1108f2d37758SMatthew Dillon 		normalize(a, scale);
1109f2d37758SMatthew Dillon 		normalize(b, scale + bmachine.scale);
1110f2d37758SMatthew Dillon 
1111f2d37758SMatthew Dillon 		ctx = BN_CTX_new();
1112f2d37758SMatthew Dillon 		bn_checkp(ctx);
1113f2d37758SMatthew Dillon 		bn_check(BN_mod(r->number, b->number, a->number, ctx));
1114f2d37758SMatthew Dillon 		BN_CTX_free(ctx);
1115f2d37758SMatthew Dillon 	}
1116f2d37758SMatthew Dillon 	push_number(r);
1117f2d37758SMatthew Dillon 	free_number(a);
1118f2d37758SMatthew Dillon 	free_number(b);
1119f2d37758SMatthew Dillon }
1120f2d37758SMatthew Dillon 
1121f2d37758SMatthew Dillon static void
bdivmod(void)1122f2d37758SMatthew Dillon bdivmod(void)
1123f2d37758SMatthew Dillon {
1124f2d37758SMatthew Dillon 	struct number	*a, *b;
1125f2d37758SMatthew Dillon 	struct number	*rdiv, *rmod;
1126f2d37758SMatthew Dillon 	u_int		scale;
1127f2d37758SMatthew Dillon 	BN_CTX		*ctx;
1128f2d37758SMatthew Dillon 
1129f2d37758SMatthew Dillon 	a = pop_number();
1130f2d37758SMatthew Dillon 	if (a == NULL) {
1131f2d37758SMatthew Dillon 		return;
1132f2d37758SMatthew Dillon 	}
1133f2d37758SMatthew Dillon 	b = pop_number();
1134f2d37758SMatthew Dillon 	if (b == NULL) {
1135f2d37758SMatthew Dillon 		push_number(a);
1136f2d37758SMatthew Dillon 		return;
1137f2d37758SMatthew Dillon 	}
1138f2d37758SMatthew Dillon 
1139f2d37758SMatthew Dillon 	rdiv = new_number();
1140f2d37758SMatthew Dillon 	rmod = new_number();
1141f2d37758SMatthew Dillon 	rdiv->scale = bmachine.scale;
1142f2d37758SMatthew Dillon 	rmod->scale = max(b->scale, a->scale + bmachine.scale);
1143f2d37758SMatthew Dillon 	scale = max(a->scale, b->scale);
1144f2d37758SMatthew Dillon 
1145f2d37758SMatthew Dillon 	if (BN_is_zero(a->number))
1146f2d37758SMatthew Dillon 		warnx("divide by zero");
1147f2d37758SMatthew Dillon 	else {
1148f2d37758SMatthew Dillon 		normalize(a, scale);
1149f2d37758SMatthew Dillon 		normalize(b, scale + bmachine.scale);
1150f2d37758SMatthew Dillon 
1151f2d37758SMatthew Dillon 		ctx = BN_CTX_new();
1152f2d37758SMatthew Dillon 		bn_checkp(ctx);
1153f2d37758SMatthew Dillon 		bn_check(BN_div(rdiv->number, rmod->number,
1154f2d37758SMatthew Dillon 		    b->number, a->number, ctx));
1155f2d37758SMatthew Dillon 		BN_CTX_free(ctx);
1156f2d37758SMatthew Dillon 	}
1157f2d37758SMatthew Dillon 	push_number(rdiv);
1158f2d37758SMatthew Dillon 	push_number(rmod);
1159f2d37758SMatthew Dillon 	free_number(a);
1160f2d37758SMatthew Dillon 	free_number(b);
1161f2d37758SMatthew Dillon }
1162f2d37758SMatthew Dillon 
1163f2d37758SMatthew Dillon static void
bexp(void)1164f2d37758SMatthew Dillon bexp(void)
1165f2d37758SMatthew Dillon {
1166f2d37758SMatthew Dillon 	struct number	*a, *p;
1167f2d37758SMatthew Dillon 	struct number	*r;
1168f2d37758SMatthew Dillon 	bool		neg;
1169*a977bf87SJoris Giovannangeli 	u_int		rscale;
1170f2d37758SMatthew Dillon 
1171f2d37758SMatthew Dillon 	p = pop_number();
1172f2d37758SMatthew Dillon 	if (p == NULL) {
1173f2d37758SMatthew Dillon 		return;
1174f2d37758SMatthew Dillon 	}
1175f2d37758SMatthew Dillon 	a = pop_number();
1176f2d37758SMatthew Dillon 	if (a == NULL) {
1177f2d37758SMatthew Dillon 		push_number(p);
1178f2d37758SMatthew Dillon 		return;
1179f2d37758SMatthew Dillon 	}
1180f2d37758SMatthew Dillon 
1181*a977bf87SJoris Giovannangeli 	if (p->scale != 0) {
1182*a977bf87SJoris Giovannangeli 		BIGNUM *i, *f;
1183*a977bf87SJoris Giovannangeli 		i = BN_new();
1184*a977bf87SJoris Giovannangeli 		bn_checkp(i);
1185*a977bf87SJoris Giovannangeli 		f = BN_new();
1186*a977bf87SJoris Giovannangeli 		bn_checkp(f);
1187*a977bf87SJoris Giovannangeli 		split_number(p, i, f);
1188*a977bf87SJoris Giovannangeli 		if (!BN_is_zero(f))
1189*a977bf87SJoris Giovannangeli 			warnx("Runtime warning: non-zero fractional part in exponent");
1190*a977bf87SJoris Giovannangeli 		BN_free(i);
1191*a977bf87SJoris Giovannangeli 		BN_free(f);
1192*a977bf87SJoris Giovannangeli 	}
1193f2d37758SMatthew Dillon 	normalize(p, 0);
1194f2d37758SMatthew Dillon 
1195f2d37758SMatthew Dillon 	neg = false;
1196*a977bf87SJoris Giovannangeli 	if (BN_is_negative(p->number)) {
1197f2d37758SMatthew Dillon 		neg = true;
1198f2d37758SMatthew Dillon 		negate(p);
1199*a977bf87SJoris Giovannangeli 		rscale = bmachine.scale;
1200f2d37758SMatthew Dillon 	} else {
1201f2d37758SMatthew Dillon 		/* Posix bc says min(a.scale * b, max(a.scale, scale) */
1202f2d37758SMatthew Dillon 		u_long	b;
1203f2d37758SMatthew Dillon 		u_int	m;
1204f2d37758SMatthew Dillon 
1205f2d37758SMatthew Dillon 		b = BN_get_word(p->number);
1206f2d37758SMatthew Dillon 		m = max(a->scale, bmachine.scale);
1207*a977bf87SJoris Giovannangeli 		rscale = a->scale * (u_int)b;
1208*a977bf87SJoris Giovannangeli 		if (rscale > m || (a->scale > 0 && (b == BN_MASK2 ||
1209*a977bf87SJoris Giovannangeli 		    b > UINT_MAX)))
1210*a977bf87SJoris Giovannangeli 			rscale = m;
1211f2d37758SMatthew Dillon 	}
1212f2d37758SMatthew Dillon 
1213f2d37758SMatthew Dillon 	if (BN_is_zero(p->number)) {
1214f2d37758SMatthew Dillon 		r = new_number();
1215f2d37758SMatthew Dillon 		bn_check(BN_one(r->number));
1216*a977bf87SJoris Giovannangeli 		normalize(r, rscale);
1217f2d37758SMatthew Dillon 	} else {
1218*a977bf87SJoris Giovannangeli 		u_int ascale, mscale;
1219*a977bf87SJoris Giovannangeli 
1220*a977bf87SJoris Giovannangeli 		ascale = a->scale;
1221f2d37758SMatthew Dillon 		while (!BN_is_bit_set(p->number, 0)) {
1222*a977bf87SJoris Giovannangeli 			ascale *= 2;
1223*a977bf87SJoris Giovannangeli 			bmul_number(a, a, a, ascale);
1224f2d37758SMatthew Dillon 			bn_check(BN_rshift1(p->number, p->number));
1225f2d37758SMatthew Dillon 		}
1226f2d37758SMatthew Dillon 
1227f2d37758SMatthew Dillon 		r = dup_number(a);
1228f2d37758SMatthew Dillon 		bn_check(BN_rshift1(p->number, p->number));
1229f2d37758SMatthew Dillon 
1230*a977bf87SJoris Giovannangeli 		mscale = ascale;
1231f2d37758SMatthew Dillon 		while (!BN_is_zero(p->number)) {
1232*a977bf87SJoris Giovannangeli 			ascale *=2;
1233*a977bf87SJoris Giovannangeli 			bmul_number(a, a, a, ascale);
1234*a977bf87SJoris Giovannangeli 			if (BN_is_bit_set(p->number, 0)) {
1235*a977bf87SJoris Giovannangeli 				mscale += ascale;
1236*a977bf87SJoris Giovannangeli 				bmul_number(r, r, a, mscale);
1237*a977bf87SJoris Giovannangeli 			}
1238f2d37758SMatthew Dillon 			bn_check(BN_rshift1(p->number, p->number));
1239f2d37758SMatthew Dillon 		}
1240f2d37758SMatthew Dillon 
1241f2d37758SMatthew Dillon 		if (neg) {
1242f2d37758SMatthew Dillon 			BN_CTX	*ctx;
1243f2d37758SMatthew Dillon 			BIGNUM	*one;
1244f2d37758SMatthew Dillon 
1245f2d37758SMatthew Dillon 			one = BN_new();
1246f2d37758SMatthew Dillon 			bn_checkp(one);
1247*a977bf87SJoris Giovannangeli 			bn_check(BN_one(one));
1248f2d37758SMatthew Dillon 			ctx = BN_CTX_new();
1249f2d37758SMatthew Dillon 			bn_checkp(ctx);
1250*a977bf87SJoris Giovannangeli 			scale_number(one, r->scale + rscale);
1251*a977bf87SJoris Giovannangeli 
1252*a977bf87SJoris Giovannangeli 			if (BN_is_zero(r->number))
1253*a977bf87SJoris Giovannangeli 				warnx("divide by zero");
1254*a977bf87SJoris Giovannangeli 			else
1255*a977bf87SJoris Giovannangeli 				bn_check(BN_div(r->number, NULL, one,
1256*a977bf87SJoris Giovannangeli 				    r->number, ctx));
1257f2d37758SMatthew Dillon 			BN_free(one);
1258f2d37758SMatthew Dillon 			BN_CTX_free(ctx);
1259*a977bf87SJoris Giovannangeli 			r->scale = rscale;
1260abcef8f0SSascha Wildner 		} else
1261*a977bf87SJoris Giovannangeli 			normalize(r, rscale);
1262f2d37758SMatthew Dillon 	}
1263f2d37758SMatthew Dillon 	push_number(r);
1264f2d37758SMatthew Dillon 	free_number(a);
1265f2d37758SMatthew Dillon 	free_number(p);
1266f2d37758SMatthew Dillon }
1267f2d37758SMatthew Dillon 
1268f2d37758SMatthew Dillon static bool
bsqrt_stop(const BIGNUM * x,const BIGNUM * y,u_int * onecount)1269abcef8f0SSascha Wildner bsqrt_stop(const BIGNUM *x, const BIGNUM *y, u_int *onecount)
1270f2d37758SMatthew Dillon {
1271f2d37758SMatthew Dillon 	BIGNUM *r;
1272f2d37758SMatthew Dillon 	bool ret;
1273f2d37758SMatthew Dillon 
1274f2d37758SMatthew Dillon 	r = BN_new();
1275f2d37758SMatthew Dillon 	bn_checkp(r);
1276f2d37758SMatthew Dillon 	bn_check(BN_sub(r, x, y));
1277abcef8f0SSascha Wildner 	if (BN_is_one(r))
1278abcef8f0SSascha Wildner 		(*onecount)++;
1279abcef8f0SSascha Wildner 	ret = BN_is_zero(r);
1280f2d37758SMatthew Dillon 	BN_free(r);
1281abcef8f0SSascha Wildner 	return ret || *onecount > 1;
1282f2d37758SMatthew Dillon }
1283f2d37758SMatthew Dillon 
1284f2d37758SMatthew Dillon static void
bsqrt(void)1285f2d37758SMatthew Dillon bsqrt(void)
1286f2d37758SMatthew Dillon {
1287f2d37758SMatthew Dillon 	struct number	*n;
1288f2d37758SMatthew Dillon 	struct number	*r;
1289f2d37758SMatthew Dillon 	BIGNUM		*x, *y;
1290abcef8f0SSascha Wildner 	u_int		scale, onecount;
1291f2d37758SMatthew Dillon 	BN_CTX		*ctx;
1292f2d37758SMatthew Dillon 
1293abcef8f0SSascha Wildner 	onecount = 0;
1294f2d37758SMatthew Dillon 	n = pop_number();
1295f2d37758SMatthew Dillon 	if (n == NULL) {
1296f2d37758SMatthew Dillon 		return;
1297f2d37758SMatthew Dillon 	}
1298f2d37758SMatthew Dillon 	if (BN_is_zero(n->number)) {
1299f2d37758SMatthew Dillon 		r = new_number();
1300f2d37758SMatthew Dillon 		push_number(r);
1301*a977bf87SJoris Giovannangeli 	} else if (BN_is_negative(n->number))
1302f2d37758SMatthew Dillon 		warnx("square root of negative number");
1303f2d37758SMatthew Dillon 	else {
1304f2d37758SMatthew Dillon 		scale = max(bmachine.scale, n->scale);
1305f2d37758SMatthew Dillon 		normalize(n, 2*scale);
1306f2d37758SMatthew Dillon 		x = BN_dup(n->number);
1307f2d37758SMatthew Dillon 		bn_checkp(x);
1308f2d37758SMatthew Dillon 		bn_check(BN_rshift(x, x, BN_num_bits(x)/2));
1309f2d37758SMatthew Dillon 		y = BN_new();
1310f2d37758SMatthew Dillon 		bn_checkp(y);
1311f2d37758SMatthew Dillon 		ctx = BN_CTX_new();
1312f2d37758SMatthew Dillon 		bn_checkp(ctx);
1313f2d37758SMatthew Dillon 		for (;;) {
1314f2d37758SMatthew Dillon 			bn_checkp(BN_copy(y, x));
1315f2d37758SMatthew Dillon 			bn_check(BN_div(x, NULL, n->number, x, ctx));
1316f2d37758SMatthew Dillon 			bn_check(BN_add(x, x, y));
1317f2d37758SMatthew Dillon 			bn_check(BN_rshift1(x, x));
1318abcef8f0SSascha Wildner 			if (bsqrt_stop(x, y, &onecount))
1319f2d37758SMatthew Dillon 				break;
1320f2d37758SMatthew Dillon 		}
1321f2d37758SMatthew Dillon 		r = bmalloc(sizeof(*r));
1322f2d37758SMatthew Dillon 		r->scale = scale;
1323f2d37758SMatthew Dillon 		r->number = y;
1324f2d37758SMatthew Dillon 		BN_free(x);
1325f2d37758SMatthew Dillon 		BN_CTX_free(ctx);
1326f2d37758SMatthew Dillon 		push_number(r);
1327f2d37758SMatthew Dillon 	}
1328f2d37758SMatthew Dillon 
1329f2d37758SMatthew Dillon 	free_number(n);
1330f2d37758SMatthew Dillon }
1331f2d37758SMatthew Dillon 
1332f2d37758SMatthew Dillon static void
not(void)1333f2d37758SMatthew Dillon not(void)
1334f2d37758SMatthew Dillon {
1335f2d37758SMatthew Dillon 	struct number	*a;
1336f2d37758SMatthew Dillon 
1337f2d37758SMatthew Dillon 	a = pop_number();
1338f2d37758SMatthew Dillon 	if (a == NULL) {
1339f2d37758SMatthew Dillon 		return;
1340f2d37758SMatthew Dillon 	}
1341f2d37758SMatthew Dillon 	a->scale = 0;
1342f2d37758SMatthew Dillon 	bn_check(BN_set_word(a->number, BN_get_word(a->number) ? 0 : 1));
1343f2d37758SMatthew Dillon 	push_number(a);
1344f2d37758SMatthew Dillon }
1345f2d37758SMatthew Dillon 
1346f2d37758SMatthew Dillon static void
equal(void)1347f2d37758SMatthew Dillon equal(void)
1348f2d37758SMatthew Dillon {
1349f2d37758SMatthew Dillon 	compare(BCODE_EQUAL);
1350f2d37758SMatthew Dillon }
1351f2d37758SMatthew Dillon 
1352f2d37758SMatthew Dillon static void
equal_numbers(void)1353f2d37758SMatthew Dillon equal_numbers(void)
1354f2d37758SMatthew Dillon {
1355f2d37758SMatthew Dillon 	struct number *a, *b, *r;
1356f2d37758SMatthew Dillon 
1357f2d37758SMatthew Dillon 	a = pop_number();
1358f2d37758SMatthew Dillon 	if (a == NULL) {
1359f2d37758SMatthew Dillon 		return;
1360f2d37758SMatthew Dillon 	}
1361f2d37758SMatthew Dillon 	b = pop_number();
1362f2d37758SMatthew Dillon 	if (b == NULL) {
1363f2d37758SMatthew Dillon 		push_number(a);
1364f2d37758SMatthew Dillon 		return;
1365f2d37758SMatthew Dillon 	}
1366f2d37758SMatthew Dillon 	r = new_number();
1367f2d37758SMatthew Dillon 	bn_check(BN_set_word(r->number,
1368f2d37758SMatthew Dillon 	    compare_numbers(BCODE_EQUAL, a, b) ? 1 : 0));
1369f2d37758SMatthew Dillon 	push_number(r);
1370f2d37758SMatthew Dillon }
1371f2d37758SMatthew Dillon 
1372f2d37758SMatthew Dillon static void
less_numbers(void)1373f2d37758SMatthew Dillon less_numbers(void)
1374f2d37758SMatthew Dillon {
1375f2d37758SMatthew Dillon 	struct number *a, *b, *r;
1376f2d37758SMatthew Dillon 
1377f2d37758SMatthew Dillon 	a = pop_number();
1378f2d37758SMatthew Dillon 	if (a == NULL) {
1379f2d37758SMatthew Dillon 		return;
1380f2d37758SMatthew Dillon 	}
1381f2d37758SMatthew Dillon 	b = pop_number();
1382f2d37758SMatthew Dillon 	if (b == NULL) {
1383f2d37758SMatthew Dillon 		push_number(a);
1384f2d37758SMatthew Dillon 		return;
1385f2d37758SMatthew Dillon 	}
1386f2d37758SMatthew Dillon 	r = new_number();
1387f2d37758SMatthew Dillon 	bn_check(BN_set_word(r->number,
1388f2d37758SMatthew Dillon 	    compare_numbers(BCODE_LESS, a, b) ? 1 : 0));
1389f2d37758SMatthew Dillon 	push_number(r);
1390f2d37758SMatthew Dillon }
1391f2d37758SMatthew Dillon 
1392f2d37758SMatthew Dillon static void
lesseq_numbers(void)1393f2d37758SMatthew Dillon lesseq_numbers(void)
1394f2d37758SMatthew Dillon {
1395f2d37758SMatthew Dillon 	struct number *a, *b, *r;
1396f2d37758SMatthew Dillon 
1397f2d37758SMatthew Dillon 	a = pop_number();
1398f2d37758SMatthew Dillon 	if (a == NULL) {
1399f2d37758SMatthew Dillon 		return;
1400f2d37758SMatthew Dillon 	}
1401f2d37758SMatthew Dillon 	b = pop_number();
1402f2d37758SMatthew Dillon 	if (b == NULL) {
1403f2d37758SMatthew Dillon 		push_number(a);
1404f2d37758SMatthew Dillon 		return;
1405f2d37758SMatthew Dillon 	}
1406f2d37758SMatthew Dillon 	r = new_number();
1407f2d37758SMatthew Dillon 	bn_check(BN_set_word(r->number,
1408f2d37758SMatthew Dillon 	    compare_numbers(BCODE_NOT_GREATER, a, b) ? 1 : 0));
1409f2d37758SMatthew Dillon 	push_number(r);
1410f2d37758SMatthew Dillon }
1411f2d37758SMatthew Dillon 
1412f2d37758SMatthew Dillon static void
not_equal(void)1413f2d37758SMatthew Dillon not_equal(void)
1414f2d37758SMatthew Dillon {
1415f2d37758SMatthew Dillon 	compare(BCODE_NOT_EQUAL);
1416f2d37758SMatthew Dillon }
1417f2d37758SMatthew Dillon 
1418f2d37758SMatthew Dillon static void
less(void)1419f2d37758SMatthew Dillon less(void)
1420f2d37758SMatthew Dillon {
1421f2d37758SMatthew Dillon 	compare(BCODE_LESS);
1422f2d37758SMatthew Dillon }
1423f2d37758SMatthew Dillon 
1424f2d37758SMatthew Dillon static void
not_compare(void)1425f2d37758SMatthew Dillon not_compare(void)
1426f2d37758SMatthew Dillon {
1427f2d37758SMatthew Dillon 	switch (readch()) {
1428f2d37758SMatthew Dillon 	case '<':
1429f2d37758SMatthew Dillon 		not_less();
1430f2d37758SMatthew Dillon 		break;
1431f2d37758SMatthew Dillon 	case '>':
1432f2d37758SMatthew Dillon 		not_greater();
1433f2d37758SMatthew Dillon 		break;
1434f2d37758SMatthew Dillon 	case '=':
1435f2d37758SMatthew Dillon 		not_equal();
1436f2d37758SMatthew Dillon 		break;
1437f2d37758SMatthew Dillon 	default:
1438f2d37758SMatthew Dillon 		unreadch();
1439f2d37758SMatthew Dillon 		bexec(readline());
1440f2d37758SMatthew Dillon 		break;
1441f2d37758SMatthew Dillon 	}
1442f2d37758SMatthew Dillon }
1443f2d37758SMatthew Dillon 
1444f2d37758SMatthew Dillon static void
not_less(void)1445f2d37758SMatthew Dillon not_less(void)
1446f2d37758SMatthew Dillon {
1447f2d37758SMatthew Dillon 	compare(BCODE_NOT_LESS);
1448f2d37758SMatthew Dillon }
1449f2d37758SMatthew Dillon 
1450f2d37758SMatthew Dillon static void
greater(void)1451f2d37758SMatthew Dillon greater(void)
1452f2d37758SMatthew Dillon {
1453f2d37758SMatthew Dillon 	compare(BCODE_GREATER);
1454f2d37758SMatthew Dillon }
1455f2d37758SMatthew Dillon 
1456f2d37758SMatthew Dillon static void
not_greater(void)1457f2d37758SMatthew Dillon not_greater(void)
1458f2d37758SMatthew Dillon {
1459f2d37758SMatthew Dillon 	compare(BCODE_NOT_GREATER);
1460f2d37758SMatthew Dillon }
1461f2d37758SMatthew Dillon 
1462f2d37758SMatthew Dillon static bool
compare_numbers(enum bcode_compare type,struct number * a,struct number * b)1463f2d37758SMatthew Dillon compare_numbers(enum bcode_compare type, struct number *a, struct number *b)
1464f2d37758SMatthew Dillon {
1465f2d37758SMatthew Dillon 	u_int	scale;
1466f2d37758SMatthew Dillon 	int	cmp;
1467f2d37758SMatthew Dillon 
1468f2d37758SMatthew Dillon 	scale = max(a->scale, b->scale);
1469f2d37758SMatthew Dillon 
1470f2d37758SMatthew Dillon 	if (scale > a->scale)
1471f2d37758SMatthew Dillon 		normalize(a, scale);
1472bbd33d1bSSascha Wildner 	else if (scale > b->scale)
1473f2d37758SMatthew Dillon 		normalize(b, scale);
1474f2d37758SMatthew Dillon 
1475f2d37758SMatthew Dillon 	cmp = BN_cmp(a->number, b->number);
1476f2d37758SMatthew Dillon 
1477f2d37758SMatthew Dillon 	free_number(a);
1478f2d37758SMatthew Dillon 	free_number(b);
1479f2d37758SMatthew Dillon 
1480f2d37758SMatthew Dillon 	switch (type) {
1481f2d37758SMatthew Dillon 	case BCODE_EQUAL:
1482f2d37758SMatthew Dillon 		return cmp == 0;
1483f2d37758SMatthew Dillon 	case BCODE_NOT_EQUAL:
1484f2d37758SMatthew Dillon 		return cmp != 0;
1485f2d37758SMatthew Dillon 	case BCODE_LESS:
1486f2d37758SMatthew Dillon 		return cmp < 0;
1487f2d37758SMatthew Dillon 	case BCODE_NOT_LESS:
1488f2d37758SMatthew Dillon 		return cmp >= 0;
1489f2d37758SMatthew Dillon 	case BCODE_GREATER:
1490f2d37758SMatthew Dillon 		return cmp > 0;
1491f2d37758SMatthew Dillon 	case BCODE_NOT_GREATER:
1492f2d37758SMatthew Dillon 		return cmp <= 0;
1493f2d37758SMatthew Dillon 	}
1494f2d37758SMatthew Dillon 	return false;
1495f2d37758SMatthew Dillon }
1496f2d37758SMatthew Dillon 
1497f2d37758SMatthew Dillon static void
compare(enum bcode_compare type)1498f2d37758SMatthew Dillon compare(enum bcode_compare type)
1499f2d37758SMatthew Dillon {
1500f2d37758SMatthew Dillon 	int		index, elseindex;
1501f2d37758SMatthew Dillon 	struct number	*a, *b;
1502f2d37758SMatthew Dillon 	bool		ok;
1503f2d37758SMatthew Dillon 	struct value	*v;
1504f2d37758SMatthew Dillon 
1505f2d37758SMatthew Dillon 	elseindex = NO_ELSE;
1506f2d37758SMatthew Dillon 	index = readreg();
1507f2d37758SMatthew Dillon 	if (readch() == 'e')
1508f2d37758SMatthew Dillon 		elseindex = readreg();
1509f2d37758SMatthew Dillon 	else
1510f2d37758SMatthew Dillon 		unreadch();
1511f2d37758SMatthew Dillon 
1512f2d37758SMatthew Dillon 	a = pop_number();
1513f2d37758SMatthew Dillon 	if (a == NULL)
1514f2d37758SMatthew Dillon 		return;
1515f2d37758SMatthew Dillon 	b = pop_number();
1516f2d37758SMatthew Dillon 	if (b == NULL) {
1517f2d37758SMatthew Dillon 		push_number(a);
1518f2d37758SMatthew Dillon 		return;
1519f2d37758SMatthew Dillon 	}
1520f2d37758SMatthew Dillon 
1521f2d37758SMatthew Dillon 	ok = compare_numbers(type, a, b);
1522f2d37758SMatthew Dillon 
1523f2d37758SMatthew Dillon 	if (!ok && elseindex != NO_ELSE)
1524f2d37758SMatthew Dillon 		index = elseindex;
1525f2d37758SMatthew Dillon 
1526f2d37758SMatthew Dillon 	if (index >= 0 && (ok || (!ok && elseindex != NO_ELSE))) {
1527f2d37758SMatthew Dillon 		v = stack_tos(&bmachine.reg[index]);
1528f2d37758SMatthew Dillon 		if (v == NULL)
1529f2d37758SMatthew Dillon 			warnx("register '%c' (0%o) is empty", index, index);
1530f2d37758SMatthew Dillon 		else {
1531f2d37758SMatthew Dillon 			switch(v->type) {
1532f2d37758SMatthew Dillon 			case BCODE_NONE:
1533f2d37758SMatthew Dillon 				warnx("register '%c' (0%o) is empty",
1534f2d37758SMatthew Dillon 				    index, index);
1535f2d37758SMatthew Dillon 				break;
1536f2d37758SMatthew Dillon 			case BCODE_NUMBER:
1537f2d37758SMatthew Dillon 				warn("eval called with non-string argument");
1538f2d37758SMatthew Dillon 				break;
1539f2d37758SMatthew Dillon 			case BCODE_STRING:
1540f2d37758SMatthew Dillon 				eval_string(bstrdup(v->u.string));
1541f2d37758SMatthew Dillon 				break;
1542f2d37758SMatthew Dillon 			}
1543f2d37758SMatthew Dillon 		}
1544f2d37758SMatthew Dillon 	}
1545f2d37758SMatthew Dillon }
1546f2d37758SMatthew Dillon 
1547f2d37758SMatthew Dillon 
1548f2d37758SMatthew Dillon static void
nop(void)1549f2d37758SMatthew Dillon nop(void)
1550f2d37758SMatthew Dillon {
1551f2d37758SMatthew Dillon }
1552f2d37758SMatthew Dillon 
1553f2d37758SMatthew Dillon static void
quit(void)1554f2d37758SMatthew Dillon quit(void)
1555f2d37758SMatthew Dillon {
1556f2d37758SMatthew Dillon 	if (bmachine.readsp < 2)
1557f2d37758SMatthew Dillon 		exit(0);
1558f2d37758SMatthew Dillon 	src_free();
1559f2d37758SMatthew Dillon 	bmachine.readsp--;
1560f2d37758SMatthew Dillon 	src_free();
1561f2d37758SMatthew Dillon 	bmachine.readsp--;
1562f2d37758SMatthew Dillon }
1563f2d37758SMatthew Dillon 
1564f2d37758SMatthew Dillon static void
quitN(void)1565f2d37758SMatthew Dillon quitN(void)
1566f2d37758SMatthew Dillon {
1567f2d37758SMatthew Dillon 	struct number	*n;
1568f2d37758SMatthew Dillon 	u_long		i;
1569f2d37758SMatthew Dillon 
1570f2d37758SMatthew Dillon 	n = pop_number();
1571f2d37758SMatthew Dillon 	if (n == NULL)
1572f2d37758SMatthew Dillon 		return;
1573f2d37758SMatthew Dillon 	i = get_ulong(n);
1574*a977bf87SJoris Giovannangeli 	free_number(n);
1575f2d37758SMatthew Dillon 	if (i == BN_MASK2 || i == 0)
1576f2d37758SMatthew Dillon 		warnx("Q command requires a number >= 1");
1577f2d37758SMatthew Dillon 	else if (bmachine.readsp < i)
1578f2d37758SMatthew Dillon 		warnx("Q command argument exceeded string execution depth");
1579f2d37758SMatthew Dillon 	else {
1580f2d37758SMatthew Dillon 		while (i-- > 0) {
1581f2d37758SMatthew Dillon 			src_free();
1582f2d37758SMatthew Dillon 			bmachine.readsp--;
1583f2d37758SMatthew Dillon 		}
1584f2d37758SMatthew Dillon 	}
1585f2d37758SMatthew Dillon }
1586f2d37758SMatthew Dillon 
1587f2d37758SMatthew Dillon static void
skipN(void)1588f2d37758SMatthew Dillon skipN(void)
1589f2d37758SMatthew Dillon {
1590f2d37758SMatthew Dillon 	struct number	*n;
1591f2d37758SMatthew Dillon 	u_long		i;
1592f2d37758SMatthew Dillon 
1593f2d37758SMatthew Dillon 	n = pop_number();
1594f2d37758SMatthew Dillon 	if (n == NULL)
1595f2d37758SMatthew Dillon 		return;
1596f2d37758SMatthew Dillon 	i = get_ulong(n);
1597f2d37758SMatthew Dillon 	if (i == BN_MASK2)
1598f2d37758SMatthew Dillon 		warnx("J command requires a number >= 0");
1599f2d37758SMatthew Dillon 	else if (i > 0 && bmachine.readsp < i)
1600f2d37758SMatthew Dillon 		warnx("J command argument exceeded string execution depth");
1601f2d37758SMatthew Dillon 	else {
1602f2d37758SMatthew Dillon 		while (i-- > 0) {
1603f2d37758SMatthew Dillon 			src_free();
1604f2d37758SMatthew Dillon 			bmachine.readsp--;
1605f2d37758SMatthew Dillon 		}
1606f2d37758SMatthew Dillon 		skip_until_mark();
1607f2d37758SMatthew Dillon 	}
1608f2d37758SMatthew Dillon }
1609f2d37758SMatthew Dillon 
1610f2d37758SMatthew Dillon static void
skip_until_mark(void)1611f2d37758SMatthew Dillon skip_until_mark(void)
1612f2d37758SMatthew Dillon {
1613f2d37758SMatthew Dillon 	int ch;
1614f2d37758SMatthew Dillon 
1615f2d37758SMatthew Dillon 	for (;;) {
1616f2d37758SMatthew Dillon 		ch = readch();
1617f2d37758SMatthew Dillon 		switch (ch) {
1618f2d37758SMatthew Dillon 		case 'M':
1619f2d37758SMatthew Dillon 			return;
1620f2d37758SMatthew Dillon 		case EOF:
1621f2d37758SMatthew Dillon 			errx(1, "mark not found");
1622f2d37758SMatthew Dillon 			return;
1623f2d37758SMatthew Dillon 		case 'l':
1624f2d37758SMatthew Dillon 		case 'L':
1625f2d37758SMatthew Dillon 		case 's':
1626f2d37758SMatthew Dillon 		case 'S':
1627f2d37758SMatthew Dillon 		case ':':
1628f2d37758SMatthew Dillon 		case ';':
1629f2d37758SMatthew Dillon 		case '<':
1630f2d37758SMatthew Dillon 		case '>':
1631f2d37758SMatthew Dillon 		case '=':
1632f2d37758SMatthew Dillon 			readreg();
1633f2d37758SMatthew Dillon 			if (readch() == 'e')
1634f2d37758SMatthew Dillon 				readreg();
1635f2d37758SMatthew Dillon 			else
1636f2d37758SMatthew Dillon 				unreadch();
1637f2d37758SMatthew Dillon 			break;
1638f2d37758SMatthew Dillon 		case '[':
1639f2d37758SMatthew Dillon 			free(read_string(&bmachine.readstack[bmachine.readsp]));
1640f2d37758SMatthew Dillon 			break;
1641f2d37758SMatthew Dillon 		case '!':
1642f2d37758SMatthew Dillon 			switch (ch = readch()) {
1643f2d37758SMatthew Dillon 				case '<':
1644f2d37758SMatthew Dillon 				case '>':
1645f2d37758SMatthew Dillon 				case '=':
1646f2d37758SMatthew Dillon 					readreg();
1647f2d37758SMatthew Dillon 					if (readch() == 'e')
1648f2d37758SMatthew Dillon 						readreg();
1649f2d37758SMatthew Dillon 					else
1650f2d37758SMatthew Dillon 						unreadch();
1651f2d37758SMatthew Dillon 					break;
1652f2d37758SMatthew Dillon 				default:
1653f2d37758SMatthew Dillon 					free(readline());
1654f2d37758SMatthew Dillon 					break;
1655f2d37758SMatthew Dillon 			}
1656f2d37758SMatthew Dillon 			break;
1657f2d37758SMatthew Dillon 		default:
1658f2d37758SMatthew Dillon 			break;
1659f2d37758SMatthew Dillon 		}
1660f2d37758SMatthew Dillon 	}
1661f2d37758SMatthew Dillon }
1662f2d37758SMatthew Dillon 
1663f2d37758SMatthew Dillon static void
parse_number(void)1664f2d37758SMatthew Dillon parse_number(void)
1665f2d37758SMatthew Dillon {
1666f2d37758SMatthew Dillon 	unreadch();
1667f2d37758SMatthew Dillon 	push_number(readnumber(&bmachine.readstack[bmachine.readsp],
1668f2d37758SMatthew Dillon 	    bmachine.ibase));
1669f2d37758SMatthew Dillon }
1670f2d37758SMatthew Dillon 
1671f2d37758SMatthew Dillon static void
unknown(void)1672f2d37758SMatthew Dillon unknown(void)
1673f2d37758SMatthew Dillon {
1674f2d37758SMatthew Dillon 	int ch = bmachine.readstack[bmachine.readsp].lastchar;
1675f2d37758SMatthew Dillon 	warnx("%c (0%o) is unimplemented", ch, ch);
1676f2d37758SMatthew Dillon }
1677f2d37758SMatthew Dillon 
1678f2d37758SMatthew Dillon static void
eval_string(char * p)1679f2d37758SMatthew Dillon eval_string(char *p)
1680f2d37758SMatthew Dillon {
1681f2d37758SMatthew Dillon 	int ch;
1682f2d37758SMatthew Dillon 
1683f2d37758SMatthew Dillon 	if (bmachine.readsp > 0) {
1684f2d37758SMatthew Dillon 		/* Check for tail call. Do not recurse in that case. */
1685f2d37758SMatthew Dillon 		ch = readch();
1686f2d37758SMatthew Dillon 		if (ch == EOF) {
1687f2d37758SMatthew Dillon 			src_free();
1688f2d37758SMatthew Dillon 			src_setstring(&bmachine.readstack[bmachine.readsp], p);
1689f2d37758SMatthew Dillon 			return;
1690f2d37758SMatthew Dillon 		} else
1691f2d37758SMatthew Dillon 			unreadch();
1692f2d37758SMatthew Dillon 	}
1693abcef8f0SSascha Wildner 	if (bmachine.readsp == bmachine.readstack_sz - 1) {
1694abcef8f0SSascha Wildner 		size_t newsz = bmachine.readstack_sz * 2;
1695abcef8f0SSascha Wildner 		struct source *stack;
1696abcef8f0SSascha Wildner 		stack = realloc(bmachine.readstack, newsz *
1697abcef8f0SSascha Wildner 		    sizeof(struct source));
1698abcef8f0SSascha Wildner 		if (stack == NULL)
1699abcef8f0SSascha Wildner 			err(1, "recursion too deep");
1700abcef8f0SSascha Wildner 		bmachine.readstack_sz = newsz;
1701abcef8f0SSascha Wildner 		bmachine.readstack = stack;
1702abcef8f0SSascha Wildner 	}
1703f2d37758SMatthew Dillon 	src_setstring(&bmachine.readstack[++bmachine.readsp], p);
1704f2d37758SMatthew Dillon }
1705f2d37758SMatthew Dillon 
1706f2d37758SMatthew Dillon static void
eval_line(void)1707f2d37758SMatthew Dillon eval_line(void)
1708f2d37758SMatthew Dillon {
1709f2d37758SMatthew Dillon 	/* Always read from stdin */
1710f2d37758SMatthew Dillon 	struct source	in;
1711f2d37758SMatthew Dillon 	char		*p;
1712f2d37758SMatthew Dillon 
1713*a977bf87SJoris Giovannangeli 	clearerr(stdin);
1714f2d37758SMatthew Dillon 	src_setstream(&in, stdin);
1715f2d37758SMatthew Dillon 	p = (*in.vtable->readline)(&in);
1716f2d37758SMatthew Dillon 	eval_string(p);
1717f2d37758SMatthew Dillon }
1718f2d37758SMatthew Dillon 
1719f2d37758SMatthew Dillon static void
eval_tos(void)1720f2d37758SMatthew Dillon eval_tos(void)
1721f2d37758SMatthew Dillon {
1722f2d37758SMatthew Dillon 	char *p;
1723f2d37758SMatthew Dillon 
1724f2d37758SMatthew Dillon 	p = pop_string();
1725f2d37758SMatthew Dillon 	if (p == NULL)
1726f2d37758SMatthew Dillon 		return;
1727f2d37758SMatthew Dillon 	eval_string(p);
1728f2d37758SMatthew Dillon }
1729f2d37758SMatthew Dillon 
1730f2d37758SMatthew Dillon void
eval(void)1731f2d37758SMatthew Dillon eval(void)
1732f2d37758SMatthew Dillon {
1733f2d37758SMatthew Dillon 	int	ch;
1734f2d37758SMatthew Dillon 
1735f2d37758SMatthew Dillon 	for (;;) {
1736f2d37758SMatthew Dillon 		ch = readch();
1737f2d37758SMatthew Dillon 		if (ch == EOF) {
1738f2d37758SMatthew Dillon 			if (bmachine.readsp == 0)
1739abcef8f0SSascha Wildner 				return;
1740f2d37758SMatthew Dillon 			src_free();
1741f2d37758SMatthew Dillon 			bmachine.readsp--;
1742f2d37758SMatthew Dillon 			continue;
1743f2d37758SMatthew Dillon 		}
1744f2d37758SMatthew Dillon 		if (bmachine.interrupted) {
1745f2d37758SMatthew Dillon 			if (bmachine.readsp > 0) {
1746f2d37758SMatthew Dillon 				src_free();
1747f2d37758SMatthew Dillon 				bmachine.readsp--;
1748f2d37758SMatthew Dillon 				continue;
1749f2d37758SMatthew Dillon 			} else
1750f2d37758SMatthew Dillon 				bmachine.interrupted = false;
1751f2d37758SMatthew Dillon 		}
1752f2d37758SMatthew Dillon #ifdef DEBUGGING
1753f2d37758SMatthew Dillon 		fprintf(stderr, "# %c\n", ch);
1754f2d37758SMatthew Dillon 		stack_print(stderr, &bmachine.stack, "* ",
1755f2d37758SMatthew Dillon 		    bmachine.obase);
1756*a977bf87SJoris Giovannangeli 		fprintf(stderr, "%zd =>\n", bmachine.readsp);
1757f2d37758SMatthew Dillon #endif
1758f2d37758SMatthew Dillon 
1759f2d37758SMatthew Dillon 		if (0 <= ch && ch < UCHAR_MAX)
1760f2d37758SMatthew Dillon 			(*jump_table[ch])();
1761f2d37758SMatthew Dillon 		else
1762f2d37758SMatthew Dillon 			warnx("internal error: opcode %d", ch);
1763f2d37758SMatthew Dillon 
1764f2d37758SMatthew Dillon #ifdef DEBUGGING
1765f2d37758SMatthew Dillon 		stack_print(stderr, &bmachine.stack, "* ",
1766f2d37758SMatthew Dillon 		    bmachine.obase);
1767*a977bf87SJoris Giovannangeli 		fprintf(stderr, "%zd ==\n", bmachine.readsp);
1768f2d37758SMatthew Dillon #endif
1769f2d37758SMatthew Dillon 	}
1770f2d37758SMatthew Dillon }
1771