xref: /openbsd-src/usr.bin/dc/bcode.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: bcode.c,v 1.63 2023/03/08 04:43:10 guenther Exp $	*/
2a6ce4a44Sotto 
3a6ce4a44Sotto /*
4a6ce4a44Sotto  * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
5a6ce4a44Sotto  *
6a6ce4a44Sotto  * Permission to use, copy, modify, and distribute this software for any
7a6ce4a44Sotto  * purpose with or without fee is hereby granted, provided that the above
8a6ce4a44Sotto  * copyright notice and this permission notice appear in all copies.
9a6ce4a44Sotto  *
10a6ce4a44Sotto  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a6ce4a44Sotto  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a6ce4a44Sotto  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a6ce4a44Sotto  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a6ce4a44Sotto  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a6ce4a44Sotto  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a6ce4a44Sotto  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a6ce4a44Sotto  */
18a6ce4a44Sotto 
19a6ce4a44Sotto #include <err.h>
20a6ce4a44Sotto #include <limits.h>
21bc24e4f8Sotto #include <signal.h>
22a6ce4a44Sotto #include <stdio.h>
23a6ce4a44Sotto #include <stdlib.h>
24a6ce4a44Sotto #include <string.h>
25a6ce4a44Sotto 
26a6ce4a44Sotto #include "extern.h"
27a6ce4a44Sotto 
28e4ba5352Sotto /* #define	DEBUGGING */
29a6ce4a44Sotto 
30a6ce4a44Sotto #define MAX_ARRAY_INDEX		2048
3122ab46f0Sotto #define READSTACK_SIZE		8
32a6ce4a44Sotto 
33708987f6Sotto #define NO_ELSE			-2	/* -1 is EOF */
3477f3d9ddSotto #define REG_ARRAY_SIZE_SMALL	(UCHAR_MAX + 1)
3577f3d9ddSotto #define REG_ARRAY_SIZE_BIG	(UCHAR_MAX + 1 + USHRT_MAX + 1)
36708987f6Sotto 
37a6ce4a44Sotto struct bmachine {
38a6ce4a44Sotto 	struct stack		stack;
39a6ce4a44Sotto 	u_int			scale;
40a6ce4a44Sotto 	u_int			obase;
41a6ce4a44Sotto 	u_int			ibase;
4222ab46f0Sotto 	size_t			readsp;
4377f3d9ddSotto 	bool			extended_regs;
4477f3d9ddSotto 	size_t			reg_array_size;
4577f3d9ddSotto 	struct stack		*reg;
461495cd0fSotto 	volatile sig_atomic_t	interrupted;
4722ab46f0Sotto 	struct source		*readstack;
4822ab46f0Sotto 	size_t			readstack_sz;
495d69525dSotto 	BN_CTX			*ctx;
50a6ce4a44Sotto };
51a6ce4a44Sotto 
52a6ce4a44Sotto static struct bmachine	bmachine;
53bc24e4f8Sotto static void sighandler(int);
54a6ce4a44Sotto 
55a6ce4a44Sotto static __inline int	readch(void);
56a1a9dfc3Sotto static __inline void	unreadch(void);
57a6ce4a44Sotto static __inline char	*readline(void);
58a6ce4a44Sotto static __inline void	src_free(void);
59a6ce4a44Sotto 
60a6ce4a44Sotto static __inline u_int	max(u_int, u_int);
61a6ce4a44Sotto static u_long		get_ulong(struct number *);
62a6ce4a44Sotto 
63a6ce4a44Sotto static __inline void	push_number(struct number *);
64a6ce4a44Sotto static __inline void	push_string(char *);
65a6ce4a44Sotto static __inline void	push(struct value *);
66a6ce4a44Sotto static __inline struct value *tos(void);
67a6ce4a44Sotto static __inline struct number	*pop_number(void);
68a6ce4a44Sotto static __inline char	*pop_string(void);
6902ce9935Sotto static void		clear_stack(void);
7002ce9935Sotto static void		print_tos(void);
711b843d51Sotto static void		print_err(void);
723c65cd63Sotto static void		pop_print(void);
733c65cd63Sotto static void		pop_printn(void);
7402ce9935Sotto static void		print_stack(void);
7502ce9935Sotto static void		dup(void);
764e2c9909Sotto static void		swap(void);
77d072a150Sotto static void		drop(void);
78a6ce4a44Sotto 
79a6ce4a44Sotto static void		get_scale(void);
80a6ce4a44Sotto static void		set_scale(void);
81a6ce4a44Sotto static void		get_obase(void);
82a6ce4a44Sotto static void		set_obase(void);
83a6ce4a44Sotto static void		get_ibase(void);
84a6ce4a44Sotto static void		set_ibase(void);
85a6ce4a44Sotto static void		stackdepth(void);
86a6ce4a44Sotto static void		push_scale(void);
87a6ce4a44Sotto static u_int		count_digits(const struct number *);
88a6ce4a44Sotto static void		num_digits(void);
893c65cd63Sotto static void		to_ascii(void);
90a6ce4a44Sotto static void		push_line(void);
913c65cd63Sotto static void		comment(void);
92a6ce4a44Sotto static void		badd(void);
93a6ce4a44Sotto static void		bsub(void);
94a6ce4a44Sotto static void		bmul(void);
95a6ce4a44Sotto static void		bdiv(void);
96a6ce4a44Sotto static void		bmod(void);
97b952a0e0Sotto static void		bdivmod(void);
98a6ce4a44Sotto static void		bexp(void);
99a6ce4a44Sotto static void		bsqrt(void);
1009f2b90aaSotto static void		not(void);
1019f2b90aaSotto static void		equal_numbers(void);
1029f2b90aaSotto static void		less_numbers(void);
1039f2b90aaSotto static void		lesseq_numbers(void);
104a6ce4a44Sotto static void		equal(void);
105a6ce4a44Sotto static void		less(void);
106a6ce4a44Sotto static void		greater(void);
107a6ce4a44Sotto static void		not_compare(void);
1089f2b90aaSotto static bool		compare_numbers(enum bcode_compare, struct number *,
1099f2b90aaSotto 			    struct number *);
110a6ce4a44Sotto static void		compare(enum bcode_compare);
11177f3d9ddSotto static int		readreg(void);
112a6ce4a44Sotto static void		load(void);
113a6ce4a44Sotto static void		store(void);
114a6ce4a44Sotto static void		load_stack(void);
115a6ce4a44Sotto static void		store_stack(void);
116a6ce4a44Sotto static void		load_array(void);
117a6ce4a44Sotto static void		store_array(void);
118a6ce4a44Sotto static void		nop(void);
119a6ce4a44Sotto static void		quit(void);
120a6ce4a44Sotto static void		quitN(void);
121e4ba5352Sotto static void		skipN(void);
122e4ba5352Sotto static void		skip_until_mark(void);
123a6ce4a44Sotto static void		parse_number(void);
124a6ce4a44Sotto static void		unknown(void);
125a6ce4a44Sotto static void		eval_string(char *);
126a6ce4a44Sotto static void		eval_line(void);
127a6ce4a44Sotto static void		eval_tos(void);
128a6ce4a44Sotto 
129a6ce4a44Sotto 
130a6ce4a44Sotto typedef void		(*opcode_function)(void);
131a6ce4a44Sotto 
132a6ce4a44Sotto struct jump_entry {
133a6ce4a44Sotto 	u_char		ch;
134a6ce4a44Sotto 	opcode_function	f;
135a6ce4a44Sotto };
136a6ce4a44Sotto 
1375d69525dSotto 
138a1e1a89cStom static opcode_function jump_table[UCHAR_MAX + 1];
139a6ce4a44Sotto 
140a6ce4a44Sotto static const struct jump_entry jump_table_data[] = {
1413c65cd63Sotto 	{ ' ',	nop		},
1423c65cd63Sotto 	{ '!',	not_compare	},
1433c65cd63Sotto 	{ '#',	comment		},
1443c65cd63Sotto 	{ '%',	bmod		},
1459f2b90aaSotto 	{ '(',	less_numbers	},
1463c65cd63Sotto 	{ '*',	bmul		},
1473c65cd63Sotto 	{ '+',	badd		},
1483c65cd63Sotto 	{ '-',	bsub		},
1493c65cd63Sotto 	{ '.',	parse_number	},
1503c65cd63Sotto 	{ '/',	bdiv		},
151a6ce4a44Sotto 	{ '0',	parse_number	},
152a6ce4a44Sotto 	{ '1',	parse_number	},
153a6ce4a44Sotto 	{ '2',	parse_number	},
154a6ce4a44Sotto 	{ '3',	parse_number	},
155a6ce4a44Sotto 	{ '4',	parse_number	},
156a6ce4a44Sotto 	{ '5',	parse_number	},
157a6ce4a44Sotto 	{ '6',	parse_number	},
158a6ce4a44Sotto 	{ '7',	parse_number	},
159a6ce4a44Sotto 	{ '8',	parse_number	},
160a6ce4a44Sotto 	{ '9',	parse_number	},
1613c65cd63Sotto 	{ ':',	store_array	},
1623c65cd63Sotto 	{ ';',	load_array	},
1633c65cd63Sotto 	{ '<',	less		},
1643c65cd63Sotto 	{ '=',	equal		},
1653c65cd63Sotto 	{ '>',	greater		},
1663c65cd63Sotto 	{ '?',	eval_line	},
167a6ce4a44Sotto 	{ 'A',	parse_number	},
168a6ce4a44Sotto 	{ 'B',	parse_number	},
169a6ce4a44Sotto 	{ 'C',	parse_number	},
170a6ce4a44Sotto 	{ 'D',	parse_number	},
171a6ce4a44Sotto 	{ 'E',	parse_number	},
172a6ce4a44Sotto 	{ 'F',	parse_number	},
1739f2b90aaSotto 	{ 'G',	equal_numbers	},
1743c65cd63Sotto 	{ 'I',	get_ibase	},
1753c65cd63Sotto 	{ 'J',	skipN		},
1763c65cd63Sotto 	{ 'K',	get_scale	},
177a6ce4a44Sotto 	{ 'L',	load_stack	},
1783c65cd63Sotto 	{ 'M',	nop		},
1799f2b90aaSotto 	{ 'N',	not		},
1803c65cd63Sotto 	{ 'O',	get_obase	},
181a6ce4a44Sotto 	{ 'P',	pop_print	},
182a6ce4a44Sotto 	{ 'Q',	quitN		},
183d072a150Sotto 	{ 'R',	drop		},
1843c65cd63Sotto 	{ 'S',	store_stack	},
1853c65cd63Sotto 	{ 'X',	push_scale	},
186a6ce4a44Sotto 	{ 'Z',	num_digits	},
1873c65cd63Sotto 	{ '[',	push_line	},
188a6ce4a44Sotto 	{ '\f',	nop		},
1893c65cd63Sotto 	{ '\n',	nop		},
1903c65cd63Sotto 	{ '\r',	nop		},
1913c65cd63Sotto 	{ '\t',	nop		},
1923c65cd63Sotto 	{ '^',	bexp		},
1933c65cd63Sotto 	{ '_',	parse_number	},
1943c65cd63Sotto 	{ 'a',	to_ascii	},
1953c65cd63Sotto 	{ 'c',	clear_stack	},
1963c65cd63Sotto 	{ 'd',	dup		},
1971b843d51Sotto 	{ 'e',	print_err	},
1983c65cd63Sotto 	{ 'f',	print_stack	},
1993c65cd63Sotto 	{ 'i',	set_ibase	},
2003c65cd63Sotto 	{ 'k',	set_scale	},
2013c65cd63Sotto 	{ 'l',	load		},
2023c65cd63Sotto 	{ 'n',	pop_printn	},
2033c65cd63Sotto 	{ 'o',	set_obase	},
2043c65cd63Sotto 	{ 'p',	print_tos	},
2053c65cd63Sotto 	{ 'q',	quit		},
2069f2b90aaSotto 	{ 'r',	swap		},
2073c65cd63Sotto 	{ 's',	store		},
2083c65cd63Sotto 	{ 'v',	bsqrt		},
2093c65cd63Sotto 	{ 'x',	eval_tos	},
2103c65cd63Sotto 	{ 'z',	stackdepth	},
2119f2b90aaSotto 	{ '{',	lesseq_numbers	},
2123c65cd63Sotto 	{ '~',	bdivmod		}
213a6ce4a44Sotto };
214a6ce4a44Sotto 
215a1e1a89cStom #ifndef nitems
216a1e1a89cStom #define nitems(a)	(sizeof((a)) / sizeof((a)[0]))
217a1e1a89cStom #endif
218a6ce4a44Sotto 
219bc24e4f8Sotto static void
sighandler(int ignored)220bc24e4f8Sotto sighandler(int ignored)
221bc24e4f8Sotto {
222bc24e4f8Sotto 	bmachine.interrupted = true;
223bc24e4f8Sotto }
224bc24e4f8Sotto 
225a6ce4a44Sotto void
init_bmachine(bool extended_registers)22677f3d9ddSotto init_bmachine(bool extended_registers)
227a6ce4a44Sotto {
228a6ce4a44Sotto 	int i;
229a6ce4a44Sotto 
2305d69525dSotto 	bmachine.ctx = BN_CTX_new();
2315d69525dSotto 	bn_checkp(bmachine.ctx);
2325d69525dSotto 
23377f3d9ddSotto 	bmachine.extended_regs = extended_registers;
23477f3d9ddSotto 	bmachine.reg_array_size = bmachine.extended_regs ?
23577f3d9ddSotto 	    REG_ARRAY_SIZE_BIG : REG_ARRAY_SIZE_SMALL;
23677f3d9ddSotto 
237bfdaf066Sderaadt 	bmachine.reg = calloc(bmachine.reg_array_size,
23877f3d9ddSotto 	    sizeof(bmachine.reg[0]));
23977f3d9ddSotto 	if (bmachine.reg == NULL)
24077f3d9ddSotto 		err(1, NULL);
24177f3d9ddSotto 
242a1e1a89cStom 	for (i = 0; i < nitems(jump_table); i++)
243a6ce4a44Sotto 		jump_table[i] = unknown;
244a1e1a89cStom 
245a1e1a89cStom 	for (i = 0; i < nitems(jump_table_data); i++) {
246a1e1a89cStom 		if ((unsigned int)jump_table_data[i].ch >= nitems(jump_table))
247a1e1a89cStom 			errx(1, "opcode '%c' overflows jump table",
248a1e1a89cStom 			    jump_table_data[i].ch);
249a1e1a89cStom 		if (jump_table[jump_table_data[i].ch] != unknown)
250a1e1a89cStom 			errx(1, "opcode '%c' already assigned",
251a1e1a89cStom 			    jump_table_data[i].ch);
252a6ce4a44Sotto 		jump_table[jump_table_data[i].ch] = jump_table_data[i].f;
253a1e1a89cStom 	}
254a6ce4a44Sotto 
255a6ce4a44Sotto 	stack_init(&bmachine.stack);
256a6ce4a44Sotto 
25777f3d9ddSotto 	for (i = 0; i < bmachine.reg_array_size; i++)
258a6ce4a44Sotto 		stack_init(&bmachine.reg[i]);
259a6ce4a44Sotto 
26022ab46f0Sotto 	bmachine.readstack_sz = READSTACK_SIZE;
261bfdaf066Sderaadt 	bmachine.readstack = calloc(sizeof(struct source),
26222ab46f0Sotto 	    bmachine.readstack_sz);
26322ab46f0Sotto 	if (bmachine.readstack == NULL)
26422ab46f0Sotto 		err(1, NULL);
265a6ce4a44Sotto 	bmachine.obase = bmachine.ibase = 10;
266a1a9dfc3Sotto 	(void)signal(SIGINT, sighandler);
267a6ce4a44Sotto }
268a6ce4a44Sotto 
2698b19764bSotto u_int
bmachine_scale(void)2708b19764bSotto bmachine_scale(void)
2718b19764bSotto {
2728b19764bSotto 	return bmachine.scale;
2738b19764bSotto }
2748b19764bSotto 
275a6ce4a44Sotto /* Reset the things needed before processing a (new) file */
276a6ce4a44Sotto void
reset_bmachine(struct source * src)277a6ce4a44Sotto reset_bmachine(struct source *src)
278a6ce4a44Sotto {
279a6ce4a44Sotto 	bmachine.readsp = 0;
280a6ce4a44Sotto 	bmachine.readstack[0] = *src;
281a6ce4a44Sotto }
282a6ce4a44Sotto 
283a6ce4a44Sotto static __inline int
readch(void)284a6ce4a44Sotto readch(void)
285a6ce4a44Sotto {
286a6ce4a44Sotto 	struct source *src = &bmachine.readstack[bmachine.readsp];
287a6ce4a44Sotto 
288a6ce4a44Sotto 	return src->vtable->readchar(src);
289a6ce4a44Sotto }
290a6ce4a44Sotto 
291a1a9dfc3Sotto static __inline void
unreadch(void)292a6ce4a44Sotto unreadch(void)
293a6ce4a44Sotto {
294a6ce4a44Sotto 	struct source *src = &bmachine.readstack[bmachine.readsp];
295a6ce4a44Sotto 
296a1a9dfc3Sotto 	src->vtable->unreadchar(src);
297a6ce4a44Sotto }
298a6ce4a44Sotto 
299a6ce4a44Sotto static __inline char *
readline(void)300a6ce4a44Sotto readline(void)
301a6ce4a44Sotto {
302a6ce4a44Sotto 	struct source *src = &bmachine.readstack[bmachine.readsp];
303a6ce4a44Sotto 
304a6ce4a44Sotto 	return src->vtable->readline(src);
305a6ce4a44Sotto }
306a6ce4a44Sotto 
307a6ce4a44Sotto static __inline void
src_free(void)308a6ce4a44Sotto src_free(void)
309a6ce4a44Sotto {
310a6ce4a44Sotto 	struct source *src = &bmachine.readstack[bmachine.readsp];
311a6ce4a44Sotto 
312a6ce4a44Sotto 	src->vtable->free(src);
313a6ce4a44Sotto }
314a6ce4a44Sotto 
315ca957bd1Sotto #ifdef DEBUGGING
316a6ce4a44Sotto void
pn(const char * str,const struct number * n)317a6ce4a44Sotto pn(const char *str, const struct number *n)
318a6ce4a44Sotto {
319a6ce4a44Sotto 	char *p = BN_bn2dec(n->number);
320a6ce4a44Sotto 	if (p == NULL)
321a6ce4a44Sotto 		err(1, "BN_bn2dec failed");
322a1a9dfc3Sotto 	(void)fputs(str, stderr);
323a1a9dfc3Sotto 	(void)fprintf(stderr, " %s (%u)\n" , p, n->scale);
324a6ce4a44Sotto 	OPENSSL_free(p);
325a6ce4a44Sotto }
326a6ce4a44Sotto 
327a6ce4a44Sotto void
pbn(const char * str,const BIGNUM * n)328a6ce4a44Sotto pbn(const char *str, const BIGNUM *n)
329a6ce4a44Sotto {
330a6ce4a44Sotto 	char *p = BN_bn2dec(n);
331a6ce4a44Sotto 	if (p == NULL)
332a6ce4a44Sotto 		err(1, "BN_bn2dec failed");
333a1a9dfc3Sotto 	(void)fputs(str, stderr);
334a1a9dfc3Sotto 	(void)fprintf(stderr, " %s\n", p);
335a6ce4a44Sotto 	OPENSSL_free(p);
336a6ce4a44Sotto }
337a6ce4a44Sotto 
338a6ce4a44Sotto #endif
339a6ce4a44Sotto 
340a6ce4a44Sotto static __inline u_int
max(u_int a,u_int b)341a6ce4a44Sotto max(u_int a, u_int b)
342a6ce4a44Sotto {
343a6ce4a44Sotto 	return a > b ? a : b;
344a6ce4a44Sotto }
345a6ce4a44Sotto 
346a6ce4a44Sotto static unsigned long factors[] = {
347a6ce4a44Sotto 	0, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
348a6ce4a44Sotto 	100000000, 1000000000
349a6ce4a44Sotto };
350a6ce4a44Sotto 
351a6ce4a44Sotto void
scale_number(BIGNUM * n,int s)352a6ce4a44Sotto scale_number(BIGNUM *n, int s)
353a6ce4a44Sotto {
354a6ce4a44Sotto 	int abs_scale;
355a6ce4a44Sotto 
356a6ce4a44Sotto 	if (s == 0)
357a6ce4a44Sotto 		return;
358a6ce4a44Sotto 
359a6ce4a44Sotto 	abs_scale = s > 0 ? s : -s;
360a6ce4a44Sotto 
3613090f0a3Sotto 	if (abs_scale < nitems(factors)) {
362a6ce4a44Sotto 		if (s > 0)
363a6ce4a44Sotto 			bn_check(BN_mul_word(n, factors[abs_scale]));
364a6ce4a44Sotto 		else
365a1a9dfc3Sotto 			(void)BN_div_word(n, factors[abs_scale]);
366a6ce4a44Sotto 	} else {
367a6ce4a44Sotto 		BIGNUM *a, *p;
368a6ce4a44Sotto 
369a6ce4a44Sotto 		a = BN_new();
370a6ce4a44Sotto 		bn_checkp(a);
371a6ce4a44Sotto 		p = BN_new();
372a6ce4a44Sotto 		bn_checkp(p);
373a6ce4a44Sotto 
374a6ce4a44Sotto 		bn_check(BN_set_word(a, 10));
375a6ce4a44Sotto 		bn_check(BN_set_word(p, abs_scale));
3765d69525dSotto 		bn_check(BN_exp(a, a, p, bmachine.ctx));
377a6ce4a44Sotto 		if (s > 0)
3785d69525dSotto 			bn_check(BN_mul(n, n, a, bmachine.ctx));
379a6ce4a44Sotto 		else
3805d69525dSotto 			bn_check(BN_div(n, NULL, n, a, bmachine.ctx));
381a6ce4a44Sotto 		BN_free(a);
382a6ce4a44Sotto 		BN_free(p);
383a6ce4a44Sotto 	}
384a6ce4a44Sotto }
385a6ce4a44Sotto 
386a6ce4a44Sotto void
split_number(const struct number * n,BIGNUM * i,BIGNUM * f)387a6ce4a44Sotto split_number(const struct number *n, BIGNUM *i, BIGNUM *f)
388a6ce4a44Sotto {
389a6ce4a44Sotto 	u_long rem;
390a6ce4a44Sotto 
391a6ce4a44Sotto 	bn_checkp(BN_copy(i, n->number));
392a6ce4a44Sotto 
3933090f0a3Sotto 	if (n->scale == 0) {
3943090f0a3Sotto 		if (f != NULL)
395c935c058Sotto 			bn_check(BN_set_word(f, 0));
3963090f0a3Sotto 	} else if (n->scale < nitems(factors)) {
397a6ce4a44Sotto 		rem = BN_div_word(i, factors[n->scale]);
398a6ce4a44Sotto 		if (f != NULL)
399a1a9dfc3Sotto 			bn_check(BN_set_word(f, rem));
400a6ce4a44Sotto 	} else {
401a6ce4a44Sotto 		BIGNUM *a, *p;
402a6ce4a44Sotto 
403a6ce4a44Sotto 		a = BN_new();
404a6ce4a44Sotto 		bn_checkp(a);
405a6ce4a44Sotto 		p = BN_new();
406a6ce4a44Sotto 		bn_checkp(p);
407a6ce4a44Sotto 
408a6ce4a44Sotto 		bn_check(BN_set_word(a, 10));
409a6ce4a44Sotto 		bn_check(BN_set_word(p, n->scale));
4105d69525dSotto 		bn_check(BN_exp(a, a, p, bmachine.ctx));
4115d69525dSotto 		bn_check(BN_div(i, f, n->number, a, bmachine.ctx));
412a6ce4a44Sotto 		BN_free(a);
413a6ce4a44Sotto 		BN_free(p);
414a6ce4a44Sotto 	}
415a6ce4a44Sotto }
416a6ce4a44Sotto 
4173f2eefc8Sotto void
normalize(struct number * n,u_int s)418a6ce4a44Sotto normalize(struct number *n, u_int s)
419a6ce4a44Sotto {
420a6ce4a44Sotto 	scale_number(n->number, s - n->scale);
421a6ce4a44Sotto 	n->scale = s;
422a6ce4a44Sotto }
423a6ce4a44Sotto 
424a6ce4a44Sotto static u_long
get_ulong(struct number * n)425a6ce4a44Sotto get_ulong(struct number *n)
426a6ce4a44Sotto {
427a6ce4a44Sotto 	normalize(n, 0);
428a6ce4a44Sotto 	return BN_get_word(n->number);
429a6ce4a44Sotto }
430a6ce4a44Sotto 
431a6ce4a44Sotto void
negate(struct number * n)432a6ce4a44Sotto negate(struct number *n)
433a6ce4a44Sotto {
4348e9b8cc7Sotto 	BN_set_negative(n->number, !BN_is_negative(n->number));
435a6ce4a44Sotto }
436a6ce4a44Sotto 
437a6ce4a44Sotto static __inline void
push_number(struct number * n)438a6ce4a44Sotto push_number(struct number *n)
439a6ce4a44Sotto {
440a6ce4a44Sotto 	stack_pushnumber(&bmachine.stack, n);
441a6ce4a44Sotto }
442a6ce4a44Sotto 
443a6ce4a44Sotto static __inline void
push_string(char * string)444a6ce4a44Sotto push_string(char *string)
445a6ce4a44Sotto {
446a6ce4a44Sotto 	stack_pushstring(&bmachine.stack, string);
447a6ce4a44Sotto }
448a6ce4a44Sotto 
449a6ce4a44Sotto static __inline void
push(struct value * v)450a6ce4a44Sotto push(struct value *v)
451a6ce4a44Sotto {
452a6ce4a44Sotto 	stack_push(&bmachine.stack, v);
453a6ce4a44Sotto }
454a6ce4a44Sotto 
455a6ce4a44Sotto static __inline struct value *
tos(void)456a6ce4a44Sotto tos(void)
457a6ce4a44Sotto {
458a6ce4a44Sotto 	return stack_tos(&bmachine.stack);
459a6ce4a44Sotto }
460a6ce4a44Sotto 
461a6ce4a44Sotto static __inline struct value *
pop(void)462a6ce4a44Sotto pop(void)
463a6ce4a44Sotto {
464a6ce4a44Sotto 	return stack_pop(&bmachine.stack);
465a6ce4a44Sotto }
466a6ce4a44Sotto 
467a6ce4a44Sotto static __inline struct number *
pop_number(void)468a6ce4a44Sotto pop_number(void)
469a6ce4a44Sotto {
470a6ce4a44Sotto 	return stack_popnumber(&bmachine.stack);
471a6ce4a44Sotto }
472a6ce4a44Sotto 
473a6ce4a44Sotto static __inline char *
pop_string(void)474a6ce4a44Sotto pop_string(void)
475a6ce4a44Sotto {
476a6ce4a44Sotto 	return stack_popstring(&bmachine.stack);
477a6ce4a44Sotto }
478a6ce4a44Sotto 
47902ce9935Sotto static void
clear_stack(void)480a6ce4a44Sotto clear_stack(void)
481a6ce4a44Sotto {
482a6ce4a44Sotto 	stack_clear(&bmachine.stack);
483a6ce4a44Sotto }
484a6ce4a44Sotto 
48502ce9935Sotto static void
print_stack(void)486a6ce4a44Sotto print_stack(void)
487a6ce4a44Sotto {
488a6ce4a44Sotto 	stack_print(stdout, &bmachine.stack, "", bmachine.obase);
489a6ce4a44Sotto }
490a6ce4a44Sotto 
49102ce9935Sotto static void
print_tos(void)492a6ce4a44Sotto print_tos(void)
493a6ce4a44Sotto {
494a6ce4a44Sotto 	struct value *value = tos();
495a6ce4a44Sotto 	if (value != NULL) {
496a6ce4a44Sotto 		print_value(stdout, value, "", bmachine.obase);
497a1a9dfc3Sotto 		(void)putchar('\n');
49802ce9935Sotto 	} else
499a6ce4a44Sotto 		warnx("stack empty");
500a6ce4a44Sotto }
501a6ce4a44Sotto 
5023c65cd63Sotto static void
print_err(void)5031b843d51Sotto print_err(void)
5041b843d51Sotto {
5051b843d51Sotto 	struct value *value = tos();
5061b843d51Sotto 	if (value != NULL) {
5071b843d51Sotto 		print_value(stderr, value, "", bmachine.obase);
5081b843d51Sotto 		(void)putc('\n', stderr);
50902ce9935Sotto 	} else
5101b843d51Sotto 		warnx("stack empty");
5111b843d51Sotto }
5121b843d51Sotto 
5131b843d51Sotto static void
pop_print(void)514a6ce4a44Sotto pop_print(void)
515a6ce4a44Sotto {
516a6ce4a44Sotto 	struct value *value = pop();
5173c65cd63Sotto 
518a6ce4a44Sotto 	if (value != NULL) {
519a6ce4a44Sotto 		switch (value->type) {
520a6ce4a44Sotto 		case BCODE_NONE:
521a6ce4a44Sotto 			break;
522a6ce4a44Sotto 		case BCODE_NUMBER:
523a6ce4a44Sotto 			normalize(value->u.num, 0);
524a6ce4a44Sotto 			print_ascii(stdout, value->u.num);
525a1a9dfc3Sotto 			(void)fflush(stdout);
526a6ce4a44Sotto 			break;
527a6ce4a44Sotto 		case BCODE_STRING:
528a1a9dfc3Sotto 			(void)fputs(value->u.string, stdout);
529a1a9dfc3Sotto 			(void)fflush(stdout);
530a6ce4a44Sotto 			break;
531a6ce4a44Sotto 		}
532a6ce4a44Sotto 		stack_free_value(value);
533a6ce4a44Sotto 	}
534a6ce4a44Sotto }
535a6ce4a44Sotto 
5363c65cd63Sotto static void
pop_printn(void)5373c65cd63Sotto pop_printn(void)
5383c65cd63Sotto {
5393c65cd63Sotto 	struct value *value = pop();
5403c65cd63Sotto 
5413c65cd63Sotto 	if (value != NULL) {
5423c65cd63Sotto 		print_value(stdout, value, "", bmachine.obase);
543a1a9dfc3Sotto 		(void)fflush(stdout);
5443c65cd63Sotto 		stack_free_value(value);
5453c65cd63Sotto 	}
5463c65cd63Sotto }
5473c65cd63Sotto 
54802ce9935Sotto static void
dup(void)549a6ce4a44Sotto dup(void)
550a6ce4a44Sotto {
551a6ce4a44Sotto 	stack_dup(&bmachine.stack);
552a6ce4a44Sotto }
553a6ce4a44Sotto 
554a6ce4a44Sotto static void
swap(void)5554e2c9909Sotto swap(void)
5564e2c9909Sotto {
5574e2c9909Sotto 	stack_swap(&bmachine.stack);
5584e2c9909Sotto }
5594e2c9909Sotto 
5604e2c9909Sotto static void
drop(void)561d072a150Sotto drop(void)
562d072a150Sotto {
563d072a150Sotto 	struct value *v = pop();
564d072a150Sotto 	if (v != NULL)
565d072a150Sotto 		stack_free_value(v);
566d072a150Sotto }
567d072a150Sotto 
568d072a150Sotto static void
get_scale(void)569a6ce4a44Sotto get_scale(void)
570a6ce4a44Sotto {
571a6ce4a44Sotto 	struct number	*n;
572a6ce4a44Sotto 
573a6ce4a44Sotto 	n = new_number();
574a6ce4a44Sotto 	bn_check(BN_set_word(n->number, bmachine.scale));
575a6ce4a44Sotto 	push_number(n);
576a6ce4a44Sotto }
577a6ce4a44Sotto 
578a6ce4a44Sotto static void
set_scale(void)579a6ce4a44Sotto set_scale(void)
580a6ce4a44Sotto {
581a6ce4a44Sotto 	struct number	*n;
582a6ce4a44Sotto 	u_long		scale;
583a6ce4a44Sotto 
584a6ce4a44Sotto 	n = pop_number();
585a6ce4a44Sotto 	if (n != NULL) {
5868e9b8cc7Sotto 		if (BN_is_negative(n->number))
587a6ce4a44Sotto 			warnx("scale must be a nonnegative number");
588a6ce4a44Sotto 		else {
589a6ce4a44Sotto 			scale = get_ulong(n);
590b0ce59faSotto 			if (scale != BN_MASK2 && scale <= UINT_MAX)
591b0ce59faSotto 				bmachine.scale = (u_int)scale;
592a6ce4a44Sotto 			else
593a6ce4a44Sotto 				warnx("scale too large");
594a6ce4a44Sotto 		}
595a6ce4a44Sotto 		free_number(n);
596a6ce4a44Sotto 	}
597a6ce4a44Sotto }
598a6ce4a44Sotto 
599a6ce4a44Sotto static void
get_obase(void)600a6ce4a44Sotto get_obase(void)
601a6ce4a44Sotto {
602a6ce4a44Sotto 	struct number	*n;
603a6ce4a44Sotto 
604a6ce4a44Sotto 	n = new_number();
605a6ce4a44Sotto 	bn_check(BN_set_word(n->number, bmachine.obase));
606a6ce4a44Sotto 	push_number(n);
607a6ce4a44Sotto }
608a6ce4a44Sotto 
609a6ce4a44Sotto static void
set_obase(void)610a6ce4a44Sotto set_obase(void)
611a6ce4a44Sotto {
612a6ce4a44Sotto 	struct number	*n;
613a6ce4a44Sotto 	u_long		base;
614a6ce4a44Sotto 
615a6ce4a44Sotto 	n = pop_number();
616a6ce4a44Sotto 	if (n != NULL) {
617a6ce4a44Sotto 		base = get_ulong(n);
618b0ce59faSotto 		if (base != BN_MASK2 && base > 1 && base <= UINT_MAX)
619b0ce59faSotto 			bmachine.obase = (u_int)base;
620a6ce4a44Sotto 		else
621a6ce4a44Sotto 			warnx("output base must be a number greater than 1");
622a6ce4a44Sotto 		free_number(n);
623a6ce4a44Sotto 	}
624a6ce4a44Sotto }
625a6ce4a44Sotto 
626a6ce4a44Sotto static void
get_ibase(void)627a6ce4a44Sotto get_ibase(void)
628a6ce4a44Sotto {
629a6ce4a44Sotto 	struct number *n;
630a6ce4a44Sotto 
631a6ce4a44Sotto 	n = new_number();
632a6ce4a44Sotto 	bn_check(BN_set_word(n->number, bmachine.ibase));
633a6ce4a44Sotto 	push_number(n);
634a6ce4a44Sotto }
635a6ce4a44Sotto 
636a6ce4a44Sotto static void
set_ibase(void)637a6ce4a44Sotto set_ibase(void)
638a6ce4a44Sotto {
639a6ce4a44Sotto 	struct number	*n;
640a6ce4a44Sotto 	u_long		base;
641a6ce4a44Sotto 
642a6ce4a44Sotto 	n = pop_number();
643a6ce4a44Sotto 	if (n != NULL) {
644a6ce4a44Sotto 		base = get_ulong(n);
645a6ce4a44Sotto 		if (base != BN_MASK2 && 2 <= base && base <= 16)
646b0ce59faSotto 			bmachine.ibase = (u_int)base;
647a6ce4a44Sotto 		else
648a6ce4a44Sotto 			warnx("input base must be a number between 2 and 16 "
649a6ce4a44Sotto 			    "(inclusive)");
650a6ce4a44Sotto 		free_number(n);
651a6ce4a44Sotto 	}
652a6ce4a44Sotto }
653a6ce4a44Sotto 
654a6ce4a44Sotto static void
stackdepth(void)655a6ce4a44Sotto stackdepth(void)
656a6ce4a44Sotto {
657c982bb45Sotto 	size_t i;
658a6ce4a44Sotto 	struct number *n;
659a6ce4a44Sotto 
660a6ce4a44Sotto 	i = stack_size(&bmachine.stack);
661a6ce4a44Sotto 	n = new_number();
662a6ce4a44Sotto 	bn_check(BN_set_word(n->number, i));
663a6ce4a44Sotto 	push_number(n);
664a6ce4a44Sotto }
665a6ce4a44Sotto 
666a6ce4a44Sotto static void
push_scale(void)667a6ce4a44Sotto push_scale(void)
668a6ce4a44Sotto {
669a6ce4a44Sotto 	struct value	*value;
670a6ce4a44Sotto 	u_int		scale = 0;
671a6ce4a44Sotto 	struct number	*n;
672a6ce4a44Sotto 
673a6ce4a44Sotto 	value = pop();
674a6ce4a44Sotto 	if (value != NULL) {
675a6ce4a44Sotto 		switch (value->type) {
676a6ce4a44Sotto 		case BCODE_NONE:
677a6ce4a44Sotto 			return;
678a6ce4a44Sotto 		case BCODE_NUMBER:
679a6ce4a44Sotto 			scale = value->u.num->scale;
680a6ce4a44Sotto 			break;
681a6ce4a44Sotto 		case BCODE_STRING:
682a6ce4a44Sotto 			break;
683a6ce4a44Sotto 		}
684a6ce4a44Sotto 		stack_free_value(value);
685a6ce4a44Sotto 		n = new_number();
686a6ce4a44Sotto 		bn_check(BN_set_word(n->number, scale));
687a6ce4a44Sotto 		push_number(n);
688a6ce4a44Sotto 	}
689a6ce4a44Sotto }
690a6ce4a44Sotto 
691a6ce4a44Sotto static u_int
count_digits(const struct number * n)692a6ce4a44Sotto count_digits(const struct number *n)
693a6ce4a44Sotto {
6943090f0a3Sotto 	BIGNUM		*int_part, *a, *p;
6953090f0a3Sotto 	uint		d;
6963090f0a3Sotto 	const uint64_t	c = 1292913986; /* floor(2^32 * log_10(2)) */
6973090f0a3Sotto 	int		bits;
698a6ce4a44Sotto 
699a6ce4a44Sotto 	if (BN_is_zero(n->number))
70091a57a7eSotto 		return n->scale;
701a6ce4a44Sotto 
7023090f0a3Sotto 	int_part = BN_new();
7033090f0a3Sotto 	bn_checkp(int_part);
704a6ce4a44Sotto 
7053090f0a3Sotto 	split_number(n, int_part, NULL);
7063090f0a3Sotto 	bits = BN_num_bits(int_part);
7073090f0a3Sotto 
7083090f0a3Sotto 	if (bits == 0)
7093090f0a3Sotto 		d = 0;
7103090f0a3Sotto 	else {
7113090f0a3Sotto 		/*
7123090f0a3Sotto 		 * Estimate number of decimal digits based on number of bits.
7133090f0a3Sotto 		 * Divide 2^32 factor out by shifting
7143090f0a3Sotto 		 */
7153090f0a3Sotto 		d = (c * bits) >> 32;
7163090f0a3Sotto 
7173090f0a3Sotto 		/* If close to a possible rounding error fix if needed */
7183090f0a3Sotto 		if (d != (c * (bits - 1)) >> 32) {
7193090f0a3Sotto 			a = BN_new();
7203090f0a3Sotto 			bn_checkp(a);
7213090f0a3Sotto 			p = BN_new();
7223090f0a3Sotto 			bn_checkp(p);
7233090f0a3Sotto 
7243090f0a3Sotto 			bn_check(BN_set_word(a, 10));
7253090f0a3Sotto 			bn_check(BN_set_word(p, d));
7265d69525dSotto 			bn_check(BN_exp(a, a, p, bmachine.ctx));
7273090f0a3Sotto 
7283090f0a3Sotto 			if (BN_ucmp(int_part, a) >= 0)
7293090f0a3Sotto 				d++;
7303090f0a3Sotto 
7313090f0a3Sotto 			BN_free(a);
7323090f0a3Sotto 			BN_free(p);
7333090f0a3Sotto 		} else
7343090f0a3Sotto 			d++;
735a6ce4a44Sotto 	}
7363090f0a3Sotto 
7373090f0a3Sotto 	BN_free(int_part);
7383090f0a3Sotto 
7393090f0a3Sotto 	return d + n->scale;
740a6ce4a44Sotto }
741a6ce4a44Sotto 
742a6ce4a44Sotto static void
num_digits(void)743a6ce4a44Sotto num_digits(void)
744a6ce4a44Sotto {
745a6ce4a44Sotto 	struct value	*value;
746b0ce59faSotto 	size_t		digits;
7473c65cd63Sotto 	struct number	*n = NULL;
748a6ce4a44Sotto 
749a6ce4a44Sotto 	value = pop();
750a6ce4a44Sotto 	if (value != NULL) {
751a6ce4a44Sotto 		switch (value->type) {
752a6ce4a44Sotto 		case BCODE_NONE:
7533c65cd63Sotto 			return;
754a6ce4a44Sotto 		case BCODE_NUMBER:
755a6ce4a44Sotto 			digits = count_digits(value->u.num);
756a6ce4a44Sotto 			n = new_number();
757a6ce4a44Sotto 			bn_check(BN_set_word(n->number, digits));
758a6ce4a44Sotto 			break;
759a6ce4a44Sotto 		case BCODE_STRING:
760a6ce4a44Sotto 			digits = strlen(value->u.string);
761a6ce4a44Sotto 			n = new_number();
762a6ce4a44Sotto 			bn_check(BN_set_word(n->number, digits));
763a6ce4a44Sotto 			break;
764a6ce4a44Sotto 		}
7653c65cd63Sotto 		stack_free_value(value);
7663c65cd63Sotto 		push_number(n);
7673c65cd63Sotto 	}
7683c65cd63Sotto }
7693c65cd63Sotto 
7703c65cd63Sotto static void
to_ascii(void)7713c65cd63Sotto to_ascii(void)
7723c65cd63Sotto {
7733c65cd63Sotto 	char		str[2];
7743c65cd63Sotto 	struct value	*value;
7753c65cd63Sotto 	struct number	*n;
7763c65cd63Sotto 
7773c65cd63Sotto 	value = pop();
7783c65cd63Sotto 	if (value != NULL) {
7793c65cd63Sotto 		str[1] = '\0';
7803c65cd63Sotto 		switch (value->type) {
7813c65cd63Sotto 		case BCODE_NONE:
7823c65cd63Sotto 			return;
7833c65cd63Sotto 		case BCODE_NUMBER:
7843c65cd63Sotto 			n = value->u.num;
7853c65cd63Sotto 			normalize(n, 0);
7863c65cd63Sotto 			if (BN_num_bits(n->number) > 8)
7873c65cd63Sotto 				bn_check(BN_mask_bits(n->number, 8));
788c982bb45Sotto 			str[0] = (char)BN_get_word(n->number);
7893c65cd63Sotto 			break;
7903c65cd63Sotto 		case BCODE_STRING:
7913c65cd63Sotto 			str[0] = value->u.string[0];
7923c65cd63Sotto 			break;
7933c65cd63Sotto 		}
7943c65cd63Sotto 		stack_free_value(value);
7953c65cd63Sotto 		push_string(bstrdup(str));
796a6ce4a44Sotto 	}
797a6ce4a44Sotto }
798a6ce4a44Sotto 
79977f3d9ddSotto static int
readreg(void)80077f3d9ddSotto readreg(void)
80177f3d9ddSotto {
802c807b455Sotto 	int idx, ch1, ch2;
80377f3d9ddSotto 
804c807b455Sotto 	idx = readch();
805c807b455Sotto 	if (idx == 0xff && bmachine.extended_regs) {
80677f3d9ddSotto 		ch1 = readch();
80777f3d9ddSotto 		ch2 = readch();
80877f3d9ddSotto 		if (ch1 == EOF || ch2 == EOF) {
80977f3d9ddSotto 			warnx("unexpected eof");
810c807b455Sotto 			idx = -1;
81177f3d9ddSotto 		} else
812c807b455Sotto 			idx = (ch1 << 8) + ch2 + UCHAR_MAX + 1;
81377f3d9ddSotto 	}
814c807b455Sotto 	if (idx < 0 || idx >= bmachine.reg_array_size) {
815c807b455Sotto 		warnx("internal error: reg num = %d", idx);
816c807b455Sotto 		idx = -1;
81777f3d9ddSotto 	}
818c807b455Sotto 	return idx;
81977f3d9ddSotto }
82077f3d9ddSotto 
821a6ce4a44Sotto static void
load(void)822a6ce4a44Sotto load(void)
823a6ce4a44Sotto {
824c807b455Sotto 	int		idx;
825a6ce4a44Sotto 	struct value	*v, copy;
8265a2dab25Sotto 	struct number	*n;
827a6ce4a44Sotto 
828c807b455Sotto 	idx = readreg();
829c807b455Sotto 	if (idx >= 0) {
830c807b455Sotto 		v = stack_tos(&bmachine.reg[idx]);
8315a2dab25Sotto 		if (v == NULL) {
8325a2dab25Sotto 			n = new_number();
833c935c058Sotto 			bn_check(BN_set_word(n->number, 0));
8345a2dab25Sotto 			push_number(n);
8355a2dab25Sotto 		} else
836a6ce4a44Sotto 			push(stack_dup_value(v, &copy));
83777f3d9ddSotto 	}
838a6ce4a44Sotto }
839a6ce4a44Sotto 
840a6ce4a44Sotto static void
store(void)841a6ce4a44Sotto store(void)
842a6ce4a44Sotto {
843c807b455Sotto 	int		idx;
844a6ce4a44Sotto 	struct value	*val;
845a6ce4a44Sotto 
846c807b455Sotto 	idx = readreg();
847c807b455Sotto 	if (idx >= 0) {
848a6ce4a44Sotto 		val = pop();
849a6ce4a44Sotto 		if (val == NULL) {
850a6ce4a44Sotto 			return;
851a6ce4a44Sotto 		}
852c807b455Sotto 		stack_set_tos(&bmachine.reg[idx], val);
85377f3d9ddSotto 	}
854a6ce4a44Sotto }
855a6ce4a44Sotto 
856a6ce4a44Sotto static void
load_stack(void)857a6ce4a44Sotto load_stack(void)
858a6ce4a44Sotto {
859c807b455Sotto 	int		idx;
860a6ce4a44Sotto 	struct stack	*stack;
8617444001dSotto 	struct value	*value;
862a6ce4a44Sotto 
863c807b455Sotto 	idx = readreg();
864c807b455Sotto 	if (idx >= 0) {
865c807b455Sotto 		stack = &bmachine.reg[idx];
866a6ce4a44Sotto 		value = NULL;
867a6ce4a44Sotto 		if (stack_size(stack) > 0) {
868a6ce4a44Sotto 			value = stack_pop(stack);
869a6ce4a44Sotto 		}
870a6ce4a44Sotto 		if (value != NULL)
8717444001dSotto 			push(value);
872a6ce4a44Sotto 		else
873a6ce4a44Sotto 			warnx("stack register '%c' (0%o) is empty",
874c807b455Sotto 			    idx, idx);
87577f3d9ddSotto 	}
876a6ce4a44Sotto }
877a6ce4a44Sotto 
878a6ce4a44Sotto static void
store_stack(void)879a6ce4a44Sotto store_stack(void)
880a6ce4a44Sotto {
881c807b455Sotto 	int		idx;
882a6ce4a44Sotto 	struct value	*value;
883a6ce4a44Sotto 
884c807b455Sotto 	idx = readreg();
885c807b455Sotto 	if (idx >= 0) {
886a6ce4a44Sotto 		value = pop();
887a6ce4a44Sotto 		if (value == NULL)
888a6ce4a44Sotto 			return;
889c807b455Sotto 		stack_push(&bmachine.reg[idx], value);
89077f3d9ddSotto 	}
891a6ce4a44Sotto }
892a6ce4a44Sotto 
893a6ce4a44Sotto static void
load_array(void)894a6ce4a44Sotto load_array(void)
895a6ce4a44Sotto {
896a6ce4a44Sotto 	int			reg;
897a6ce4a44Sotto 	struct number		*inumber, *n;
898c807b455Sotto 	u_long			idx;
899a6ce4a44Sotto 	struct stack		*stack;
900a6ce4a44Sotto 	struct value		*v, copy;
901a6ce4a44Sotto 
90277f3d9ddSotto 	reg = readreg();
90377f3d9ddSotto 	if (reg >= 0) {
904a6ce4a44Sotto 		inumber = pop_number();
905a6ce4a44Sotto 		if (inumber == NULL)
906a6ce4a44Sotto 			return;
907c807b455Sotto 		idx = get_ulong(inumber);
9088e9b8cc7Sotto 		if (BN_is_negative(inumber->number))
909c807b455Sotto 			warnx("negative idx");
910c807b455Sotto 		else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX)
911c807b455Sotto 			warnx("idx too big");
912a6ce4a44Sotto 		else {
913a6ce4a44Sotto 			stack = &bmachine.reg[reg];
914c807b455Sotto 			v = frame_retrieve(stack, idx);
9150b63aad3Sotto 			if (v == NULL || v->type == BCODE_NONE) {
916a6ce4a44Sotto 				n = new_number();
917c935c058Sotto 				bn_check(BN_set_word(n->number, 0));
918a6ce4a44Sotto 				push_number(n);
91902ce9935Sotto 			} else
920a6ce4a44Sotto 				push(stack_dup_value(v, &copy));
921a6ce4a44Sotto 		}
922a6ce4a44Sotto 		free_number(inumber);
92377f3d9ddSotto 	}
924a6ce4a44Sotto }
925a6ce4a44Sotto 
926a6ce4a44Sotto static void
store_array(void)927a6ce4a44Sotto store_array(void)
928a6ce4a44Sotto {
929a6ce4a44Sotto 	int			reg;
930a6ce4a44Sotto 	struct number		*inumber;
931c807b455Sotto 	u_long			idx;
932a6ce4a44Sotto 	struct value		*value;
933a6ce4a44Sotto 	struct stack		*stack;
934a6ce4a44Sotto 
93577f3d9ddSotto 	reg = readreg();
93677f3d9ddSotto 	if (reg >= 0) {
937a6ce4a44Sotto 		inumber = pop_number();
9382990b50fSotto 		if (inumber == NULL)
9392990b50fSotto 			return;
940a6ce4a44Sotto 		value = pop();
9412990b50fSotto 		if (value == NULL) {
9422990b50fSotto 			free_number(inumber);
943a6ce4a44Sotto 			return;
944a6ce4a44Sotto 		}
945c807b455Sotto 		idx = get_ulong(inumber);
9468e9b8cc7Sotto 		if (BN_is_negative(inumber->number)) {
947c807b455Sotto 			warnx("negative idx");
948a6ce4a44Sotto 			stack_free_value(value);
949c807b455Sotto 		} else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX) {
950c807b455Sotto 			warnx("idx too big");
951a6ce4a44Sotto 			stack_free_value(value);
952a6ce4a44Sotto 		} else {
953a6ce4a44Sotto 			stack = &bmachine.reg[reg];
954c807b455Sotto 			frame_assign(stack, idx, value);
955a6ce4a44Sotto 		}
956a6ce4a44Sotto 		free_number(inumber);
95777f3d9ddSotto 	}
958a6ce4a44Sotto }
959a6ce4a44Sotto 
960a6ce4a44Sotto static void
push_line(void)961a6ce4a44Sotto push_line(void)
962a6ce4a44Sotto {
963a6ce4a44Sotto 	push_string(read_string(&bmachine.readstack[bmachine.readsp]));
964a6ce4a44Sotto }
965a6ce4a44Sotto 
966a6ce4a44Sotto static void
comment(void)9673c65cd63Sotto comment(void)
9683c65cd63Sotto {
9693c65cd63Sotto 	free(readline());
9703c65cd63Sotto }
9713c65cd63Sotto 
9723c65cd63Sotto static void
badd(void)973a6ce4a44Sotto badd(void)
974a6ce4a44Sotto {
975a6ce4a44Sotto 	struct number	*a, *b;
976a6ce4a44Sotto 
977a6ce4a44Sotto 	a = pop_number();
978e952d73dSotto 	if (a == NULL)
979a6ce4a44Sotto 		return;
980a6ce4a44Sotto 	b = pop_number();
981a6ce4a44Sotto 	if (b == NULL) {
982a6ce4a44Sotto 		push_number(a);
983a6ce4a44Sotto 		return;
984a6ce4a44Sotto 	}
985a6ce4a44Sotto 
986e9875b0cSotto 	if (b->scale > a->scale)
987e9875b0cSotto 		normalize(a, b->scale);
988e9875b0cSotto 	else if (a->scale > b->scale)
989e9875b0cSotto 		normalize(b, a->scale);
990e9875b0cSotto 	bn_check(BN_add(b->number, a->number, b->number));
991a6ce4a44Sotto 	free_number(a);
992e9875b0cSotto 	push_number(b);
993a6ce4a44Sotto }
994a6ce4a44Sotto 
995a6ce4a44Sotto static void
bsub(void)996a6ce4a44Sotto bsub(void)
997a6ce4a44Sotto {
998a6ce4a44Sotto 	struct number	*a, *b;
999a6ce4a44Sotto 
1000a6ce4a44Sotto 	a = pop_number();
1001e952d73dSotto 	if (a == NULL)
1002a6ce4a44Sotto 		return;
1003a6ce4a44Sotto 	b = pop_number();
1004a6ce4a44Sotto 	if (b == NULL) {
1005a6ce4a44Sotto 		push_number(a);
1006a6ce4a44Sotto 		return;
1007a6ce4a44Sotto 	}
1008a6ce4a44Sotto 
1009e9875b0cSotto 	if (b->scale > a->scale)
1010e9875b0cSotto 		normalize(a, b->scale);
1011e9875b0cSotto 	else if (a->scale > b->scale)
1012e9875b0cSotto 		normalize(b, a->scale);
1013e9875b0cSotto 	bn_check(BN_sub(b->number, b->number, a->number));
1014a6ce4a44Sotto 	free_number(a);
1015e9875b0cSotto 	push_number(b);
1016a6ce4a44Sotto }
1017a6ce4a44Sotto 
1018a6ce4a44Sotto void
bmul_number(struct number * r,struct number * a,struct number * b,u_int scale)10198b19764bSotto bmul_number(struct number *r, struct number *a, struct number *b, u_int scale)
1020a6ce4a44Sotto {
1021a6ce4a44Sotto 	/* Create copies of the scales, since r might be equal to a or b */
1022a6ce4a44Sotto 	u_int ascale = a->scale;
1023a6ce4a44Sotto 	u_int bscale = b->scale;
1024a6ce4a44Sotto 	u_int rscale = ascale + bscale;
1025a6ce4a44Sotto 
10265d69525dSotto 	bn_check(BN_mul(r->number, a->number, b->number, bmachine.ctx));
1027a6ce4a44Sotto 
1028a6ce4a44Sotto 	r->scale = rscale;
10298b19764bSotto 	if (rscale > bmachine.scale && rscale > ascale && rscale > bscale)
10308b19764bSotto 		normalize(r, max(scale, max(ascale, bscale)));
1031a6ce4a44Sotto }
1032a6ce4a44Sotto 
1033a6ce4a44Sotto static void
bmul(void)1034a6ce4a44Sotto bmul(void)
1035a6ce4a44Sotto {
1036a6ce4a44Sotto 	struct number	*a, *b;
1037a6ce4a44Sotto 
1038a6ce4a44Sotto 	a = pop_number();
1039e952d73dSotto 	if (a == NULL)
1040a6ce4a44Sotto 		return;
1041a6ce4a44Sotto 	b = pop_number();
1042a6ce4a44Sotto 	if (b == NULL) {
1043a6ce4a44Sotto 		push_number(a);
1044a6ce4a44Sotto 		return;
1045a6ce4a44Sotto 	}
1046a6ce4a44Sotto 
1047e9875b0cSotto 	bmul_number(b, a, b, bmachine.scale);
1048a6ce4a44Sotto 	free_number(a);
1049e9875b0cSotto 	push_number(b);
1050a6ce4a44Sotto }
1051a6ce4a44Sotto 
1052a6ce4a44Sotto static void
bdiv(void)1053a6ce4a44Sotto bdiv(void)
1054a6ce4a44Sotto {
1055a6ce4a44Sotto 	struct number	*a, *b;
1056a6ce4a44Sotto 	struct number	*r;
1057a6ce4a44Sotto 	u_int		scale;
1058a6ce4a44Sotto 
1059a6ce4a44Sotto 	a = pop_number();
1060e952d73dSotto 	if (a == NULL)
1061a6ce4a44Sotto 		return;
1062a6ce4a44Sotto 	b = pop_number();
1063a6ce4a44Sotto 	if (b == NULL) {
1064a6ce4a44Sotto 		push_number(a);
1065a6ce4a44Sotto 		return;
1066a6ce4a44Sotto 	}
1067a6ce4a44Sotto 
1068a6ce4a44Sotto 	r = new_number();
1069a6ce4a44Sotto 	r->scale = bmachine.scale;
1070a6ce4a44Sotto 	scale = max(a->scale, b->scale);
1071a6ce4a44Sotto 
1072a6ce4a44Sotto 	if (BN_is_zero(a->number))
1073a6ce4a44Sotto 		warnx("divide by zero");
1074a6ce4a44Sotto 	else {
1075a6ce4a44Sotto 		normalize(a, scale);
1076a6ce4a44Sotto 		normalize(b, scale + r->scale);
1077a6ce4a44Sotto 
10785d69525dSotto 		bn_check(BN_div(r->number, NULL, b->number, a->number, bmachine.ctx));
1079a6ce4a44Sotto 	}
1080a6ce4a44Sotto 	push_number(r);
1081a6ce4a44Sotto 	free_number(a);
1082a6ce4a44Sotto 	free_number(b);
1083a6ce4a44Sotto }
1084a6ce4a44Sotto 
1085a6ce4a44Sotto static void
bmod(void)1086a6ce4a44Sotto bmod(void)
1087a6ce4a44Sotto {
1088a6ce4a44Sotto 	struct number	*a, *b;
1089a6ce4a44Sotto 	struct number	*r;
1090a6ce4a44Sotto 	u_int		scale;
1091a6ce4a44Sotto 
1092a6ce4a44Sotto 	a = pop_number();
1093e952d73dSotto 	if (a == NULL)
1094a6ce4a44Sotto 		return;
1095a6ce4a44Sotto 	b = pop_number();
1096a6ce4a44Sotto 	if (b == NULL) {
1097a6ce4a44Sotto 		push_number(a);
1098a6ce4a44Sotto 		return;
1099a6ce4a44Sotto 	}
1100a6ce4a44Sotto 
1101a6ce4a44Sotto 	r = new_number();
1102a6ce4a44Sotto 	scale = max(a->scale, b->scale);
1103a6ce4a44Sotto 	r->scale = max(b->scale, a->scale + bmachine.scale);
1104a6ce4a44Sotto 
1105a6ce4a44Sotto 	if (BN_is_zero(a->number))
1106a6ce4a44Sotto 		warnx("remainder by zero");
1107a6ce4a44Sotto 	else {
1108a6ce4a44Sotto 		normalize(a, scale);
1109a6ce4a44Sotto 		normalize(b, scale + bmachine.scale);
1110a6ce4a44Sotto 
11115d69525dSotto 		bn_check(BN_mod(r->number, b->number, a->number, bmachine.ctx));
1112a6ce4a44Sotto 	}
1113a6ce4a44Sotto 	push_number(r);
1114a6ce4a44Sotto 	free_number(a);
1115a6ce4a44Sotto 	free_number(b);
1116a6ce4a44Sotto }
1117a6ce4a44Sotto 
1118a6ce4a44Sotto static void
bdivmod(void)1119b952a0e0Sotto bdivmod(void)
1120b952a0e0Sotto {
1121b952a0e0Sotto 	struct number	*a, *b;
1122b952a0e0Sotto 	struct number	*rdiv, *rmod;
1123b952a0e0Sotto 	u_int		scale;
1124b952a0e0Sotto 
1125b952a0e0Sotto 	a = pop_number();
1126e952d73dSotto 	if (a == NULL)
1127b952a0e0Sotto 		return;
1128b952a0e0Sotto 	b = pop_number();
1129b952a0e0Sotto 	if (b == NULL) {
1130b952a0e0Sotto 		push_number(a);
1131b952a0e0Sotto 		return;
1132b952a0e0Sotto 	}
1133b952a0e0Sotto 
1134b952a0e0Sotto 	rdiv = new_number();
1135b952a0e0Sotto 	rmod = new_number();
1136b952a0e0Sotto 	rdiv->scale = bmachine.scale;
1137b952a0e0Sotto 	rmod->scale = max(b->scale, a->scale + bmachine.scale);
1138b952a0e0Sotto 	scale = max(a->scale, b->scale);
1139b952a0e0Sotto 
1140b952a0e0Sotto 	if (BN_is_zero(a->number))
1141b952a0e0Sotto 		warnx("divide by zero");
1142b952a0e0Sotto 	else {
1143b952a0e0Sotto 		normalize(a, scale);
1144b952a0e0Sotto 		normalize(b, scale + bmachine.scale);
1145b952a0e0Sotto 
1146b952a0e0Sotto 		bn_check(BN_div(rdiv->number, rmod->number,
11475d69525dSotto 		    b->number, a->number, bmachine.ctx));
1148b952a0e0Sotto 	}
1149b952a0e0Sotto 	push_number(rdiv);
1150b952a0e0Sotto 	push_number(rmod);
1151b952a0e0Sotto 	free_number(a);
1152b952a0e0Sotto 	free_number(b);
1153b952a0e0Sotto }
1154b952a0e0Sotto 
1155b952a0e0Sotto static void
bexp(void)1156a6ce4a44Sotto bexp(void)
1157a6ce4a44Sotto {
1158a6ce4a44Sotto 	struct number	*a, *p;
1159a6ce4a44Sotto 	struct number	*r;
1160a6ce4a44Sotto 	bool		neg;
11618b19764bSotto 	u_int		rscale;
1162a6ce4a44Sotto 
1163a6ce4a44Sotto 	p = pop_number();
1164e952d73dSotto 	if (p == NULL)
1165a6ce4a44Sotto 		return;
1166a6ce4a44Sotto 	a = pop_number();
1167a6ce4a44Sotto 	if (a == NULL) {
1168a6ce4a44Sotto 		push_number(p);
1169a6ce4a44Sotto 		return;
1170a6ce4a44Sotto 	}
1171a6ce4a44Sotto 
117214b056dbSotto 	if (p->scale != 0) {
117314b056dbSotto 		BIGNUM *i, *f;
117414b056dbSotto 		i = BN_new();
117514b056dbSotto 		bn_checkp(i);
117614b056dbSotto 		f = BN_new();
117714b056dbSotto 		bn_checkp(f);
117814b056dbSotto 		split_number(p, i, f);
117914b056dbSotto 		if (!BN_is_zero(f))
118029c15520Sotto 			warnx("Runtime warning: non-zero fractional part "
118129c15520Sotto 			    "in exponent");
118229c15520Sotto 		BN_free(p->number);
118329c15520Sotto 		p->number = i;
118414b056dbSotto 		BN_free(f);
118502ce9935Sotto 	}
1186a6ce4a44Sotto 
118702ce9935Sotto 	neg = BN_is_negative(p->number);
118802ce9935Sotto 	if (neg) {
1189a6ce4a44Sotto 		negate(p);
11908b19764bSotto 		rscale = bmachine.scale;
1191a6ce4a44Sotto 	} else {
1192839c473aSotto 		/* Posix bc says min(a.scale * b, max(a.scale, scale)) */
1193a6ce4a44Sotto 		u_long	b;
1194a6ce4a44Sotto 		u_int	m;
1195a6ce4a44Sotto 
1196a6ce4a44Sotto 		b = BN_get_word(p->number);
1197a6ce4a44Sotto 		m = max(a->scale, bmachine.scale);
11988b19764bSotto 		rscale = a->scale * (u_int)b;
11998b19764bSotto 		if (rscale > m || (a->scale > 0 && (b == BN_MASK2 ||
1200b0ce59faSotto 		    b > UINT_MAX)))
12018b19764bSotto 			rscale = m;
1202a6ce4a44Sotto 	}
1203a6ce4a44Sotto 
1204a6ce4a44Sotto 	if (BN_is_zero(p->number)) {
1205a6ce4a44Sotto 		r = new_number();
1206a6ce4a44Sotto 		bn_check(BN_one(r->number));
12078b19764bSotto 		normalize(r, rscale);
1208a6ce4a44Sotto 	} else {
12098b19764bSotto 		u_int ascale, mscale;
12108b19764bSotto 
12118b19764bSotto 		ascale = a->scale;
1212a6ce4a44Sotto 		while (!BN_is_bit_set(p->number, 0)) {
12138b19764bSotto 			ascale *= 2;
12148b19764bSotto 			bmul_number(a, a, a, ascale);
1215a6ce4a44Sotto 			bn_check(BN_rshift1(p->number, p->number));
1216a6ce4a44Sotto 		}
1217a6ce4a44Sotto 
1218a6ce4a44Sotto 		r = dup_number(a);
1219a6ce4a44Sotto 		bn_check(BN_rshift1(p->number, p->number));
1220a6ce4a44Sotto 
12218b19764bSotto 		mscale = ascale;
1222a6ce4a44Sotto 		while (!BN_is_zero(p->number)) {
12238b19764bSotto 			ascale *= 2;
12248b19764bSotto 			bmul_number(a, a, a, ascale);
12258b19764bSotto 			if (BN_is_bit_set(p->number, 0)) {
12268b19764bSotto 				mscale += ascale;
12278b19764bSotto 				bmul_number(r, r, a, mscale);
12288b19764bSotto 			}
1229a6ce4a44Sotto 			bn_check(BN_rshift1(p->number, p->number));
1230a6ce4a44Sotto 		}
1231a6ce4a44Sotto 
1232a6ce4a44Sotto 		if (neg) {
1233a6ce4a44Sotto 			BIGNUM	*one;
1234a6ce4a44Sotto 
1235a6ce4a44Sotto 			one = BN_new();
1236a6ce4a44Sotto 			bn_checkp(one);
1237a1a9dfc3Sotto 			bn_check(BN_one(one));
12388b19764bSotto 			scale_number(one, r->scale + rscale);
123914b056dbSotto 
124014b056dbSotto 			if (BN_is_zero(r->number))
124114b056dbSotto 				warnx("divide by zero");
124214b056dbSotto 			else
124314b056dbSotto 				bn_check(BN_div(r->number, NULL, one,
12445d69525dSotto 				    r->number, bmachine.ctx));
1245a6ce4a44Sotto 			BN_free(one);
12468b19764bSotto 			r->scale = rscale;
1247201d7a33Sotto 		} else
12488b19764bSotto 			normalize(r, rscale);
1249a6ce4a44Sotto 	}
1250a6ce4a44Sotto 	push_number(r);
1251a6ce4a44Sotto 	free_number(a);
1252a6ce4a44Sotto 	free_number(p);
1253a6ce4a44Sotto }
1254a6ce4a44Sotto 
1255a6ce4a44Sotto static void
bsqrt(void)1256a6ce4a44Sotto bsqrt(void)
1257a6ce4a44Sotto {
1258a6ce4a44Sotto 	struct number	*n;
1259a6ce4a44Sotto 	struct number	*r;
1260726f05dcSotto 	BIGNUM		*x, *y, *t;
12616537d013Sotto 	u_int		scale, onecount;
1262a6ce4a44Sotto 
12636537d013Sotto 	onecount = 0;
1264a6ce4a44Sotto 	n = pop_number();
1265e952d73dSotto 	if (n == NULL)
1266a6ce4a44Sotto 		return;
1267a6ce4a44Sotto 	if (BN_is_zero(n->number)) {
1268a6ce4a44Sotto 		r = new_number();
1269a6ce4a44Sotto 		push_number(r);
12708e9b8cc7Sotto 	} else if (BN_is_negative(n->number))
1271a6ce4a44Sotto 		warnx("square root of negative number");
1272a6ce4a44Sotto 	else {
1273a6ce4a44Sotto 		scale = max(bmachine.scale, n->scale);
1274a6ce4a44Sotto 		normalize(n, 2*scale);
1275a6ce4a44Sotto 		x = BN_dup(n->number);
1276a6ce4a44Sotto 		bn_checkp(x);
1277a6ce4a44Sotto 		bn_check(BN_rshift(x, x, BN_num_bits(x)/2));
1278a6ce4a44Sotto 		y = BN_new();
1279a6ce4a44Sotto 		bn_checkp(y);
1280726f05dcSotto 		do {
12815d69525dSotto 			bn_check(BN_div(y, NULL, n->number, x, bmachine.ctx));
1282726f05dcSotto 			bn_check(BN_add(y, x, y));
1283726f05dcSotto 			bn_check(BN_rshift1(y, y));
1284726f05dcSotto 			bn_check(BN_sub(x, y, x));
1285726f05dcSotto 			t = x;
1286726f05dcSotto 			x = y;
1287726f05dcSotto 			y = t;
1288726f05dcSotto 		} while (!BN_is_zero(y) && (onecount += BN_is_one(y)) < 2);
1289726f05dcSotto 		bn_check(BN_sub(y, x, y));
1290a6ce4a44Sotto 		r = bmalloc(sizeof(*r));
1291a6ce4a44Sotto 		r->scale = scale;
1292a6ce4a44Sotto 		r->number = y;
1293a6ce4a44Sotto 		BN_free(x);
1294a6ce4a44Sotto 		push_number(r);
1295a6ce4a44Sotto 	}
1296a6ce4a44Sotto 
1297a6ce4a44Sotto 	free_number(n);
1298a6ce4a44Sotto }
1299a6ce4a44Sotto 
1300a6ce4a44Sotto static void
not(void)13019f2b90aaSotto not(void)
13029f2b90aaSotto {
13039f2b90aaSotto 	struct number	*a;
13049f2b90aaSotto 
13059f2b90aaSotto 	a = pop_number();
1306e952d73dSotto 	if (a == NULL)
13079f2b90aaSotto 		return;
13089f2b90aaSotto 	a->scale = 0;
13099f2b90aaSotto 	bn_check(BN_set_word(a->number, BN_get_word(a->number) ? 0 : 1));
13109f2b90aaSotto 	push_number(a);
13119f2b90aaSotto }
13129f2b90aaSotto 
13139f2b90aaSotto static void
equal(void)1314a6ce4a44Sotto equal(void)
1315a6ce4a44Sotto {
1316a6ce4a44Sotto 	compare(BCODE_EQUAL);
1317a6ce4a44Sotto }
1318a6ce4a44Sotto 
1319a6ce4a44Sotto static void
equal_numbers(void)13209f2b90aaSotto equal_numbers(void)
13219f2b90aaSotto {
13229f2b90aaSotto 	struct number *a, *b, *r;
13239f2b90aaSotto 
13249f2b90aaSotto 	a = pop_number();
1325e952d73dSotto 	if (a == NULL)
13269f2b90aaSotto 		return;
13279f2b90aaSotto 	b = pop_number();
13289f2b90aaSotto 	if (b == NULL) {
13299f2b90aaSotto 		push_number(a);
13309f2b90aaSotto 		return;
13319f2b90aaSotto 	}
13329f2b90aaSotto 	r = new_number();
13339f2b90aaSotto 	bn_check(BN_set_word(r->number,
13349f2b90aaSotto 	    compare_numbers(BCODE_EQUAL, a, b) ? 1 : 0));
13359f2b90aaSotto 	push_number(r);
13369f2b90aaSotto }
13379f2b90aaSotto 
13389f2b90aaSotto static void
less_numbers(void)13399f2b90aaSotto less_numbers(void)
13409f2b90aaSotto {
13419f2b90aaSotto 	struct number *a, *b, *r;
13429f2b90aaSotto 
13439f2b90aaSotto 	a = pop_number();
1344e952d73dSotto 	if (a == NULL)
13459f2b90aaSotto 		return;
13469f2b90aaSotto 	b = pop_number();
13479f2b90aaSotto 	if (b == NULL) {
13489f2b90aaSotto 		push_number(a);
13499f2b90aaSotto 		return;
13509f2b90aaSotto 	}
13519f2b90aaSotto 	r = new_number();
13529f2b90aaSotto 	bn_check(BN_set_word(r->number,
13539f2b90aaSotto 	    compare_numbers(BCODE_LESS, a, b) ? 1 : 0));
13549f2b90aaSotto 	push_number(r);
13559f2b90aaSotto }
13569f2b90aaSotto 
13579f2b90aaSotto static void
lesseq_numbers(void)13589f2b90aaSotto lesseq_numbers(void)
13599f2b90aaSotto {
13609f2b90aaSotto 	struct number *a, *b, *r;
13619f2b90aaSotto 
13629f2b90aaSotto 	a = pop_number();
1363e952d73dSotto 	if (a == NULL)
13649f2b90aaSotto 		return;
13659f2b90aaSotto 	b = pop_number();
13669f2b90aaSotto 	if (b == NULL) {
13679f2b90aaSotto 		push_number(a);
13689f2b90aaSotto 		return;
13699f2b90aaSotto 	}
13709f2b90aaSotto 	r = new_number();
13719f2b90aaSotto 	bn_check(BN_set_word(r->number,
13729f2b90aaSotto 	    compare_numbers(BCODE_NOT_GREATER, a, b) ? 1 : 0));
13739f2b90aaSotto 	push_number(r);
13749f2b90aaSotto }
13759f2b90aaSotto 
13769f2b90aaSotto static void
less(void)1377a6ce4a44Sotto less(void)
1378a6ce4a44Sotto {
1379a6ce4a44Sotto 	compare(BCODE_LESS);
1380a6ce4a44Sotto }
1381a6ce4a44Sotto 
1382a6ce4a44Sotto static void
not_compare(void)1383a6ce4a44Sotto not_compare(void)
1384a6ce4a44Sotto {
1385a6ce4a44Sotto 	switch (readch()) {
1386a6ce4a44Sotto 	case '<':
1387839c473aSotto 		compare(BCODE_NOT_LESS);
1388a6ce4a44Sotto 		break;
1389a6ce4a44Sotto 	case '>':
1390839c473aSotto 		compare(BCODE_NOT_GREATER);
1391a6ce4a44Sotto 		break;
1392a6ce4a44Sotto 	case '=':
1393839c473aSotto 		compare(BCODE_NOT_EQUAL);
1394a6ce4a44Sotto 		break;
1395a6ce4a44Sotto 	default:
1396a6ce4a44Sotto 		unreadch();
1397f7887aecSotto 		warnx("! command is deprecated");
1398a6ce4a44Sotto 		break;
1399a6ce4a44Sotto 	}
1400a6ce4a44Sotto }
1401a6ce4a44Sotto 
1402a6ce4a44Sotto static void
greater(void)1403a6ce4a44Sotto greater(void)
1404a6ce4a44Sotto {
1405a6ce4a44Sotto 	compare(BCODE_GREATER);
1406a6ce4a44Sotto }
1407a6ce4a44Sotto 
14089f2b90aaSotto static bool
compare_numbers(enum bcode_compare type,struct number * a,struct number * b)14099f2b90aaSotto compare_numbers(enum bcode_compare type, struct number *a, struct number *b)
14109f2b90aaSotto {
14119f2b90aaSotto 	u_int	scale;
14129f2b90aaSotto 	int	cmp;
14139f2b90aaSotto 
14149f2b90aaSotto 	scale = max(a->scale, b->scale);
14159f2b90aaSotto 
14169f2b90aaSotto 	if (scale > a->scale)
14179f2b90aaSotto 		normalize(a, scale);
1418fb19ec81Sotto 	else if (scale > b->scale)
14199f2b90aaSotto 		normalize(b, scale);
14209f2b90aaSotto 
14219f2b90aaSotto 	cmp = BN_cmp(a->number, b->number);
14229f2b90aaSotto 
14239f2b90aaSotto 	free_number(a);
14249f2b90aaSotto 	free_number(b);
14259f2b90aaSotto 
14269f2b90aaSotto 	switch (type) {
14279f2b90aaSotto 	case BCODE_EQUAL:
14289f2b90aaSotto 		return cmp == 0;
14299f2b90aaSotto 	case BCODE_NOT_EQUAL:
14309f2b90aaSotto 		return cmp != 0;
14319f2b90aaSotto 	case BCODE_LESS:
14329f2b90aaSotto 		return cmp < 0;
14339f2b90aaSotto 	case BCODE_NOT_LESS:
14349f2b90aaSotto 		return cmp >= 0;
14359f2b90aaSotto 	case BCODE_GREATER:
14369f2b90aaSotto 		return cmp > 0;
14379f2b90aaSotto 	case BCODE_NOT_GREATER:
14389f2b90aaSotto 		return cmp <= 0;
14399f2b90aaSotto 	}
14409f2b90aaSotto 	return false;
14419f2b90aaSotto }
14429f2b90aaSotto 
1443a6ce4a44Sotto static void
compare(enum bcode_compare type)1444a6ce4a44Sotto compare(enum bcode_compare type)
1445a6ce4a44Sotto {
1446c807b455Sotto 	int		idx, elseidx;
1447a6ce4a44Sotto 	struct number	*a, *b;
1448a6ce4a44Sotto 	bool		ok;
1449a6ce4a44Sotto 	struct value	*v;
1450a6ce4a44Sotto 
1451c807b455Sotto 	elseidx = NO_ELSE;
1452c807b455Sotto 	idx = readreg();
1453708987f6Sotto 	if (readch() == 'e')
1454c807b455Sotto 		elseidx = readreg();
1455708987f6Sotto 	else
1456708987f6Sotto 		unreadch();
1457a6ce4a44Sotto 
1458a6ce4a44Sotto 	a = pop_number();
1459708987f6Sotto 	if (a == NULL)
1460a6ce4a44Sotto 		return;
1461a6ce4a44Sotto 	b = pop_number();
1462a6ce4a44Sotto 	if (b == NULL) {
1463a6ce4a44Sotto 		push_number(a);
1464a6ce4a44Sotto 		return;
1465a6ce4a44Sotto 	}
1466a6ce4a44Sotto 
14679f2b90aaSotto 	ok = compare_numbers(type, a, b);
1468a6ce4a44Sotto 
1469c807b455Sotto 	if (!ok && elseidx != NO_ELSE)
1470c807b455Sotto 		idx = elseidx;
1471708987f6Sotto 
1472c807b455Sotto 	if (idx >= 0 && (ok || (!ok && elseidx != NO_ELSE))) {
1473c807b455Sotto 		v = stack_tos(&bmachine.reg[idx]);
1474a6ce4a44Sotto 		if (v == NULL)
1475c807b455Sotto 			warnx("register '%c' (0%o) is empty", idx, idx);
1476a6ce4a44Sotto 		else {
1477a6ce4a44Sotto 			switch(v->type) {
1478a6ce4a44Sotto 			case BCODE_NONE:
1479c807b455Sotto 				warnx("register '%c' (0%o) is empty", idx, idx);
1480a6ce4a44Sotto 				break;
1481a6ce4a44Sotto 			case BCODE_NUMBER:
1482a6ce4a44Sotto 				warn("eval called with non-string argument");
1483a6ce4a44Sotto 				break;
1484a6ce4a44Sotto 			case BCODE_STRING:
1485a6ce4a44Sotto 				eval_string(bstrdup(v->u.string));
1486a6ce4a44Sotto 				break;
1487a6ce4a44Sotto 			}
1488a6ce4a44Sotto 		}
1489a6ce4a44Sotto 	}
1490a6ce4a44Sotto }
1491a6ce4a44Sotto 
1492a6ce4a44Sotto static void
nop(void)1493a6ce4a44Sotto nop(void)
1494a6ce4a44Sotto {
1495a6ce4a44Sotto }
1496a6ce4a44Sotto 
1497a6ce4a44Sotto static void
quit(void)1498a6ce4a44Sotto quit(void)
1499a6ce4a44Sotto {
1500a6ce4a44Sotto 	if (bmachine.readsp < 2)
1501a6ce4a44Sotto 		exit(0);
1502a6ce4a44Sotto 	src_free();
1503a6ce4a44Sotto 	bmachine.readsp--;
1504a6ce4a44Sotto 	src_free();
1505a6ce4a44Sotto 	bmachine.readsp--;
1506a6ce4a44Sotto }
1507a6ce4a44Sotto 
1508a6ce4a44Sotto static void
quitN(void)1509a6ce4a44Sotto quitN(void)
1510a6ce4a44Sotto {
1511a6ce4a44Sotto 	struct number	*n;
1512a6ce4a44Sotto 	u_long		i;
1513a6ce4a44Sotto 
1514a6ce4a44Sotto 	n = pop_number();
1515a6ce4a44Sotto 	if (n == NULL)
1516a6ce4a44Sotto 		return;
1517a6ce4a44Sotto 	i = get_ulong(n);
15187444001dSotto 	free_number(n);
1519a6ce4a44Sotto 	if (i == BN_MASK2 || i == 0)
1520a6ce4a44Sotto 		warnx("Q command requires a number >= 1");
1521a6ce4a44Sotto 	else if (bmachine.readsp < i)
1522a6ce4a44Sotto 		warnx("Q command argument exceeded string execution depth");
1523a6ce4a44Sotto 	else {
1524a6ce4a44Sotto 		while (i-- > 0) {
1525a6ce4a44Sotto 			src_free();
1526a6ce4a44Sotto 			bmachine.readsp--;
1527a6ce4a44Sotto 		}
1528a6ce4a44Sotto 	}
1529a6ce4a44Sotto }
1530a6ce4a44Sotto 
1531a6ce4a44Sotto static void
skipN(void)1532e4ba5352Sotto skipN(void)
1533e4ba5352Sotto {
1534e4ba5352Sotto 	struct number	*n;
1535e4ba5352Sotto 	u_long		i;
1536e4ba5352Sotto 
1537e4ba5352Sotto 	n = pop_number();
1538e4ba5352Sotto 	if (n == NULL)
1539e4ba5352Sotto 		return;
1540e4ba5352Sotto 	i = get_ulong(n);
1541e4ba5352Sotto 	if (i == BN_MASK2)
1542e4ba5352Sotto 		warnx("J command requires a number >= 0");
1543e4ba5352Sotto 	else if (i > 0 && bmachine.readsp < i)
1544e4ba5352Sotto 		warnx("J command argument exceeded string execution depth");
1545e4ba5352Sotto 	else {
1546e4ba5352Sotto 		while (i-- > 0) {
1547e4ba5352Sotto 			src_free();
1548e4ba5352Sotto 			bmachine.readsp--;
1549e4ba5352Sotto 		}
1550e4ba5352Sotto 		skip_until_mark();
1551e4ba5352Sotto 	}
1552e4ba5352Sotto }
1553e4ba5352Sotto 
1554e4ba5352Sotto static void
skip_until_mark(void)1555e4ba5352Sotto skip_until_mark(void)
1556e4ba5352Sotto {
1557e4ba5352Sotto 	for (;;) {
15581afaa581Sotto 		switch (readch()) {
1559e4ba5352Sotto 		case 'M':
1560e4ba5352Sotto 			return;
1561e4ba5352Sotto 		case EOF:
1562e4ba5352Sotto 			errx(1, "mark not found");
1563e4ba5352Sotto 			return;
1564e4ba5352Sotto 		case 'l':
1565e4ba5352Sotto 		case 'L':
1566e4ba5352Sotto 		case 's':
1567e4ba5352Sotto 		case 'S':
1568e4ba5352Sotto 		case ':':
1569e4ba5352Sotto 		case ';':
1570e4ba5352Sotto 		case '<':
1571e4ba5352Sotto 		case '>':
1572e4ba5352Sotto 		case '=':
1573a1a9dfc3Sotto 			(void)readreg();
1574c06e4020Sotto 			if (readch() == 'e')
1575a1a9dfc3Sotto 				(void)readreg();
1576c06e4020Sotto 			else
1577c06e4020Sotto 				unreadch();
1578e4ba5352Sotto 			break;
1579e4ba5352Sotto 		case '[':
1580e4ba5352Sotto 			free(read_string(&bmachine.readstack[bmachine.readsp]));
1581e4ba5352Sotto 			break;
1582e4ba5352Sotto 		case '!':
15831afaa581Sotto 			switch (readch()) {
1584e4ba5352Sotto 				case '<':
1585e4ba5352Sotto 				case '>':
1586e4ba5352Sotto 				case '=':
1587a1a9dfc3Sotto 					(void)readreg();
1588c06e4020Sotto 					if (readch() == 'e')
1589a1a9dfc3Sotto 						(void)readreg();
1590c06e4020Sotto 					else
1591c06e4020Sotto 						unreadch();
1592e4ba5352Sotto 					break;
1593e4ba5352Sotto 				default:
1594e4ba5352Sotto 					free(readline());
1595e4ba5352Sotto 					break;
1596e4ba5352Sotto 			}
1597e4ba5352Sotto 			break;
1598e4ba5352Sotto 		default:
1599e4ba5352Sotto 			break;
1600e4ba5352Sotto 		}
1601e4ba5352Sotto 	}
1602e4ba5352Sotto }
1603e4ba5352Sotto 
1604e4ba5352Sotto static void
parse_number(void)1605a6ce4a44Sotto parse_number(void)
1606a6ce4a44Sotto {
1607a6ce4a44Sotto 	unreadch();
1608a6ce4a44Sotto 	push_number(readnumber(&bmachine.readstack[bmachine.readsp],
1609a6ce4a44Sotto 	    bmachine.ibase));
1610a6ce4a44Sotto }
1611a6ce4a44Sotto 
1612a6ce4a44Sotto static void
unknown(void)1613a6ce4a44Sotto unknown(void)
1614a6ce4a44Sotto {
1615a6ce4a44Sotto 	int ch = bmachine.readstack[bmachine.readsp].lastchar;
1616a6ce4a44Sotto 	warnx("%c (0%o) is unimplemented", ch, ch);
1617a6ce4a44Sotto }
1618a6ce4a44Sotto 
1619a6ce4a44Sotto static void
eval_string(char * p)1620a6ce4a44Sotto eval_string(char *p)
1621a6ce4a44Sotto {
1622a6ce4a44Sotto 	int ch;
1623a6ce4a44Sotto 
1624a6ce4a44Sotto 	if (bmachine.readsp > 0) {
1625a6ce4a44Sotto 		/* Check for tail call. Do not recurse in that case. */
1626a6ce4a44Sotto 		ch = readch();
1627a6ce4a44Sotto 		if (ch == EOF) {
1628a6ce4a44Sotto 			src_free();
1629a6ce4a44Sotto 			src_setstring(&bmachine.readstack[bmachine.readsp], p);
1630a6ce4a44Sotto 			return;
1631a6ce4a44Sotto 		} else
1632a6ce4a44Sotto 			unreadch();
1633a6ce4a44Sotto 	}
163422ab46f0Sotto 	if (bmachine.readsp == bmachine.readstack_sz - 1) {
163522ab46f0Sotto 		size_t newsz = bmachine.readstack_sz * 2;
163622ab46f0Sotto 		struct source *stack;
163732919be8Sdoug 		stack = reallocarray(bmachine.readstack, newsz,
163822ab46f0Sotto 		    sizeof(struct source));
163922ab46f0Sotto 		if (stack == NULL)
164022ab46f0Sotto 			err(1, "recursion too deep");
164122ab46f0Sotto 		bmachine.readstack_sz = newsz;
164222ab46f0Sotto 		bmachine.readstack = stack;
164322ab46f0Sotto 	}
1644a6ce4a44Sotto 	src_setstring(&bmachine.readstack[++bmachine.readsp], p);
1645a6ce4a44Sotto }
1646a6ce4a44Sotto 
1647a6ce4a44Sotto static void
eval_line(void)1648a6ce4a44Sotto eval_line(void)
1649a6ce4a44Sotto {
1650a6ce4a44Sotto 	/* Always read from stdin */
1651a6ce4a44Sotto 	struct source	in;
1652a6ce4a44Sotto 	char		*p;
1653a6ce4a44Sotto 
16548ed24c87Sotto 	clearerr(stdin);
1655a6ce4a44Sotto 	src_setstream(&in, stdin);
1656a6ce4a44Sotto 	p = (*in.vtable->readline)(&in);
1657a6ce4a44Sotto 	eval_string(p);
1658a6ce4a44Sotto }
1659a6ce4a44Sotto 
1660a6ce4a44Sotto static void
eval_tos(void)1661a6ce4a44Sotto eval_tos(void)
1662a6ce4a44Sotto {
1663a6ce4a44Sotto 	char *p;
1664a6ce4a44Sotto 
1665a6ce4a44Sotto 	p = pop_string();
1666e952d73dSotto 	if (p != NULL)
1667a6ce4a44Sotto 		eval_string(p);
1668a6ce4a44Sotto }
1669a6ce4a44Sotto 
1670a6ce4a44Sotto void
eval(void)1671a6ce4a44Sotto eval(void)
1672a6ce4a44Sotto {
1673a6ce4a44Sotto 	int	ch;
1674a6ce4a44Sotto 
1675a6ce4a44Sotto 	for (;;) {
1676a6ce4a44Sotto 		ch = readch();
1677a6ce4a44Sotto 		if (ch == EOF) {
1678a6ce4a44Sotto 			if (bmachine.readsp == 0)
16795db19890Sotto 				return;
1680a6ce4a44Sotto 			src_free();
1681a6ce4a44Sotto 			bmachine.readsp--;
1682a6ce4a44Sotto 			continue;
1683a6ce4a44Sotto 		}
1684bc24e4f8Sotto 		if (bmachine.interrupted) {
1685bc24e4f8Sotto 			if (bmachine.readsp > 0) {
1686bc24e4f8Sotto 				src_free();
1687bc24e4f8Sotto 				bmachine.readsp--;
1688bc24e4f8Sotto 				continue;
16895affd461Sotto 			} else
1690bc24e4f8Sotto 				bmachine.interrupted = false;
1691bc24e4f8Sotto 		}
1692e4ba5352Sotto #ifdef DEBUGGING
1693a1a9dfc3Sotto 		(void)fprintf(stderr, "# %c\n", ch);
1694a6ce4a44Sotto 		stack_print(stderr, &bmachine.stack, "* ",
1695a6ce4a44Sotto 		    bmachine.obase);
169644774577Sotto 		(void)fprintf(stderr, "%zd =>\n", bmachine.readsp);
1697e4ba5352Sotto #endif
1698a6ce4a44Sotto 
1699a1e1a89cStom 		if (0 <= ch && ch < nitems(jump_table))
1700a6ce4a44Sotto 			(*jump_table[ch])();
1701a6ce4a44Sotto 		else
1702a1e1a89cStom 			unknown();
1703a6ce4a44Sotto 
1704e4ba5352Sotto #ifdef DEBUGGING
1705a6ce4a44Sotto 		stack_print(stderr, &bmachine.stack, "* ",
1706a6ce4a44Sotto 		    bmachine.obase);
170744774577Sotto 		(void)fprintf(stderr, "%zd ==\n", bmachine.readsp);
1708e4ba5352Sotto #endif
1709a6ce4a44Sotto 	}
1710a6ce4a44Sotto }
1711