xref: /netbsd-src/usr.bin/dc/bcode.c (revision 3c7417b277438229f55d127ebb8f205edf97b121)
1*3c7417b2Smartin /*	$NetBSD: bcode.c,v 1.4 2023/06/26 17:47:04 martin Exp $	*/
27d0b3229Schristos /*	$OpenBSD: bcode.c,v 1.51 2017/02/26 11:29:55 otto Exp $	*/
37d0b3229Schristos 
47d0b3229Schristos /*
57d0b3229Schristos  * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
67d0b3229Schristos  *
77d0b3229Schristos  * Permission to use, copy, modify, and distribute this software for any
87d0b3229Schristos  * purpose with or without fee is hereby granted, provided that the above
97d0b3229Schristos  * copyright notice and this permission notice appear in all copies.
107d0b3229Schristos  *
117d0b3229Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
127d0b3229Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
137d0b3229Schristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
147d0b3229Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
157d0b3229Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
167d0b3229Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
177d0b3229Schristos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
187d0b3229Schristos  */
19fc8ee2f5Schristos #include <sys/cdefs.h>
20*3c7417b2Smartin __RCSID("$NetBSD: bcode.c,v 1.4 2023/06/26 17:47:04 martin Exp $");
217d0b3229Schristos 
227d0b3229Schristos #include <err.h>
237d0b3229Schristos #include <limits.h>
247d0b3229Schristos #include <signal.h>
257d0b3229Schristos #include <stdio.h>
267d0b3229Schristos #include <stdlib.h>
277d0b3229Schristos #include <string.h>
287d0b3229Schristos 
297d0b3229Schristos #include "extern.h"
307d0b3229Schristos 
317d0b3229Schristos /* #define	DEBUGGING */
327d0b3229Schristos 
337d0b3229Schristos #define MAX_ARRAY_INDEX		2048
347d0b3229Schristos #define READSTACK_SIZE		8
35fa34604aSchristos #define	NO_NUMBER		(~0UL)
367d0b3229Schristos 
377d0b3229Schristos #define NO_ELSE			-2	/* -1 is EOF */
387d0b3229Schristos #define REG_ARRAY_SIZE_SMALL	(UCHAR_MAX + 1)
397d0b3229Schristos #define REG_ARRAY_SIZE_BIG	(UCHAR_MAX + 1 + USHRT_MAX + 1)
407d0b3229Schristos 
417d0b3229Schristos struct bmachine {
427d0b3229Schristos 	struct stack		stack;
437d0b3229Schristos 	u_int			scale;
447d0b3229Schristos 	u_int			obase;
457d0b3229Schristos 	u_int			ibase;
467d0b3229Schristos 	size_t			readsp;
477d0b3229Schristos 	bool			extended_regs;
487d0b3229Schristos 	size_t			reg_array_size;
497d0b3229Schristos 	struct stack		*reg;
507d0b3229Schristos 	volatile sig_atomic_t	interrupted;
517d0b3229Schristos 	struct source		*readstack;
527d0b3229Schristos 	size_t			readstack_sz;
537d0b3229Schristos };
547d0b3229Schristos 
557d0b3229Schristos static struct bmachine	bmachine;
567d0b3229Schristos static void sighandler(int);
577d0b3229Schristos 
587d0b3229Schristos static __inline int	readch(void);
597d0b3229Schristos static __inline void	unreadch(void);
607d0b3229Schristos static __inline char	*readline(void);
617d0b3229Schristos static __inline void	src_free(void);
627d0b3229Schristos 
637d0b3229Schristos static __inline u_int	max(u_int, u_int);
647d0b3229Schristos static u_long		get_ulong(struct number *);
657d0b3229Schristos 
667d0b3229Schristos static __inline void	push_number(struct number *);
677d0b3229Schristos static __inline void	push_string(char *);
687d0b3229Schristos static __inline void	push(struct value *);
697d0b3229Schristos static __inline struct value *tos(void);
707d0b3229Schristos static __inline struct number	*pop_number(void);
717d0b3229Schristos static __inline char	*pop_string(void);
727d0b3229Schristos static __inline void	clear_stack(void);
737d0b3229Schristos static __inline void	print_tos(void);
747d0b3229Schristos static void		print_err(void);
757d0b3229Schristos static void		pop_print(void);
767d0b3229Schristos static void		pop_printn(void);
777d0b3229Schristos static __inline void	print_stack(void);
787d0b3229Schristos static __inline void	dup(void);
797d0b3229Schristos static void		swap(void);
807d0b3229Schristos static void		drop(void);
817d0b3229Schristos 
827d0b3229Schristos static void		get_scale(void);
837d0b3229Schristos static void		set_scale(void);
847d0b3229Schristos static void		get_obase(void);
857d0b3229Schristos static void		set_obase(void);
867d0b3229Schristos static void		get_ibase(void);
877d0b3229Schristos static void		set_ibase(void);
887d0b3229Schristos static void		stackdepth(void);
897d0b3229Schristos static void		push_scale(void);
907d0b3229Schristos static u_int		count_digits(const struct number *);
917d0b3229Schristos static void		num_digits(void);
927d0b3229Schristos static void		to_ascii(void);
937d0b3229Schristos static void		push_line(void);
947d0b3229Schristos static void		comment(void);
957d0b3229Schristos static void		badd(void);
967d0b3229Schristos static void		bsub(void);
977d0b3229Schristos static void		bmul(void);
987d0b3229Schristos static void		bdiv(void);
997d0b3229Schristos static void		bmod(void);
1007d0b3229Schristos static void		bdivmod(void);
1017d0b3229Schristos static void		bexp(void);
1027d0b3229Schristos static bool		bsqrt_stop(const BIGNUM *, const BIGNUM *, u_int *);
1037d0b3229Schristos static void		bsqrt(void);
1047d0b3229Schristos static void		not(void);
1057d0b3229Schristos static void		equal_numbers(void);
1067d0b3229Schristos static void		less_numbers(void);
1077d0b3229Schristos static void		lesseq_numbers(void);
1087d0b3229Schristos static void		equal(void);
1097d0b3229Schristos static void		not_equal(void);
1107d0b3229Schristos static void		less(void);
1117d0b3229Schristos static void		not_less(void);
1127d0b3229Schristos static void		greater(void);
1137d0b3229Schristos static void		not_greater(void);
1147d0b3229Schristos static void		not_compare(void);
1157d0b3229Schristos static bool		compare_numbers(enum bcode_compare, struct number *,
1167d0b3229Schristos 			    struct number *);
1177d0b3229Schristos static void		compare(enum bcode_compare);
1187d0b3229Schristos static int		readreg(void);
1197d0b3229Schristos static void		load(void);
1207d0b3229Schristos static void		store(void);
1217d0b3229Schristos static void		load_stack(void);
1227d0b3229Schristos static void		store_stack(void);
1237d0b3229Schristos static void		load_array(void);
1247d0b3229Schristos static void		store_array(void);
1257d0b3229Schristos static void		nop(void);
1267d0b3229Schristos static void		quit(void);
1277d0b3229Schristos static void		quitN(void);
1287d0b3229Schristos static void		skipN(void);
1297d0b3229Schristos static void		skip_until_mark(void);
1307d0b3229Schristos static void		parse_number(void);
1317d0b3229Schristos static void		unknown(void);
1327d0b3229Schristos static void		eval_string(char *);
1337d0b3229Schristos static void		eval_line(void);
1347d0b3229Schristos static void		eval_tos(void);
1357d0b3229Schristos 
1367d0b3229Schristos 
1377d0b3229Schristos typedef void		(*opcode_function)(void);
1387d0b3229Schristos 
1397d0b3229Schristos struct jump_entry {
1407d0b3229Schristos 	u_char		ch;
1417d0b3229Schristos 	opcode_function	f;
1427d0b3229Schristos };
1437d0b3229Schristos 
1447d0b3229Schristos static opcode_function jump_table[UCHAR_MAX];
1457d0b3229Schristos 
1467d0b3229Schristos static const struct jump_entry jump_table_data[] = {
1477d0b3229Schristos 	{ ' ',	nop		},
1487d0b3229Schristos 	{ '!',	not_compare	},
1497d0b3229Schristos 	{ '#',	comment		},
1507d0b3229Schristos 	{ '%',	bmod		},
1517d0b3229Schristos 	{ '(',	less_numbers	},
1527d0b3229Schristos 	{ '*',	bmul		},
1537d0b3229Schristos 	{ '+',	badd		},
1547d0b3229Schristos 	{ '-',	bsub		},
1557d0b3229Schristos 	{ '.',	parse_number	},
1567d0b3229Schristos 	{ '/',	bdiv		},
1577d0b3229Schristos 	{ '0',	parse_number	},
1587d0b3229Schristos 	{ '1',	parse_number	},
1597d0b3229Schristos 	{ '2',	parse_number	},
1607d0b3229Schristos 	{ '3',	parse_number	},
1617d0b3229Schristos 	{ '4',	parse_number	},
1627d0b3229Schristos 	{ '5',	parse_number	},
1637d0b3229Schristos 	{ '6',	parse_number	},
1647d0b3229Schristos 	{ '7',	parse_number	},
1657d0b3229Schristos 	{ '8',	parse_number	},
1667d0b3229Schristos 	{ '9',	parse_number	},
1677d0b3229Schristos 	{ ':',	store_array	},
1687d0b3229Schristos 	{ ';',	load_array	},
1697d0b3229Schristos 	{ '<',	less		},
1707d0b3229Schristos 	{ '=',	equal		},
1717d0b3229Schristos 	{ '>',	greater		},
1727d0b3229Schristos 	{ '?',	eval_line	},
1737d0b3229Schristos 	{ 'A',	parse_number	},
1747d0b3229Schristos 	{ 'B',	parse_number	},
1757d0b3229Schristos 	{ 'C',	parse_number	},
1767d0b3229Schristos 	{ 'D',	parse_number	},
1777d0b3229Schristos 	{ 'E',	parse_number	},
1787d0b3229Schristos 	{ 'F',	parse_number	},
1797d0b3229Schristos 	{ 'G',	equal_numbers	},
1807d0b3229Schristos 	{ 'I',	get_ibase	},
1817d0b3229Schristos 	{ 'J',	skipN		},
1827d0b3229Schristos 	{ 'K',	get_scale	},
1837d0b3229Schristos 	{ 'L',	load_stack	},
1847d0b3229Schristos 	{ 'M',	nop		},
1857d0b3229Schristos 	{ 'N',	not		},
1867d0b3229Schristos 	{ 'O',	get_obase	},
1877d0b3229Schristos 	{ 'P',	pop_print	},
1887d0b3229Schristos 	{ 'Q',	quitN		},
1897d0b3229Schristos 	{ 'R',	drop		},
1907d0b3229Schristos 	{ 'S',	store_stack	},
1917d0b3229Schristos 	{ 'X',	push_scale	},
1927d0b3229Schristos 	{ 'Z',	num_digits	},
1937d0b3229Schristos 	{ '[',	push_line	},
1947d0b3229Schristos 	{ '\f',	nop		},
1957d0b3229Schristos 	{ '\n',	nop		},
1967d0b3229Schristos 	{ '\r',	nop		},
1977d0b3229Schristos 	{ '\t',	nop		},
1987d0b3229Schristos 	{ '^',	bexp		},
1997d0b3229Schristos 	{ '_',	parse_number	},
2007d0b3229Schristos 	{ 'a',	to_ascii	},
2017d0b3229Schristos 	{ 'c',	clear_stack	},
2027d0b3229Schristos 	{ 'd',	dup		},
2037d0b3229Schristos 	{ 'e',	print_err	},
2047d0b3229Schristos 	{ 'f',	print_stack	},
2057d0b3229Schristos 	{ 'i',	set_ibase	},
2067d0b3229Schristos 	{ 'k',	set_scale	},
2077d0b3229Schristos 	{ 'l',	load		},
2087d0b3229Schristos 	{ 'n',	pop_printn	},
2097d0b3229Schristos 	{ 'o',	set_obase	},
2107d0b3229Schristos 	{ 'p',	print_tos	},
2117d0b3229Schristos 	{ 'q',	quit		},
2127d0b3229Schristos 	{ 'r',	swap		},
2137d0b3229Schristos 	{ 's',	store		},
2147d0b3229Schristos 	{ 'v',	bsqrt		},
2157d0b3229Schristos 	{ 'x',	eval_tos	},
2167d0b3229Schristos 	{ 'z',	stackdepth	},
2177d0b3229Schristos 	{ '{',	lesseq_numbers	},
2187d0b3229Schristos 	{ '~',	bdivmod		}
2197d0b3229Schristos };
2207d0b3229Schristos 
2217d0b3229Schristos #define JUMP_TABLE_DATA_SIZE \
2227d0b3229Schristos 	(sizeof(jump_table_data)/sizeof(jump_table_data[0]))
2237d0b3229Schristos 
2247d0b3229Schristos /* ARGSUSED */
2257d0b3229Schristos static void
sighandler(int ignored)2267d0b3229Schristos sighandler(int ignored)
2277d0b3229Schristos {
2287d0b3229Schristos 	bmachine.interrupted = true;
2297d0b3229Schristos }
2307d0b3229Schristos 
2317d0b3229Schristos void
init_bmachine(bool extended_registers)2327d0b3229Schristos init_bmachine(bool extended_registers)
2337d0b3229Schristos {
234fc8ee2f5Schristos 	size_t i;
2357d0b3229Schristos 
2367d0b3229Schristos 	bmachine.extended_regs = extended_registers;
2377d0b3229Schristos 	bmachine.reg_array_size = bmachine.extended_regs ?
2387d0b3229Schristos 	    REG_ARRAY_SIZE_BIG : REG_ARRAY_SIZE_SMALL;
2397d0b3229Schristos 
2407d0b3229Schristos 	bmachine.reg = calloc(bmachine.reg_array_size,
2417d0b3229Schristos 	    sizeof(bmachine.reg[0]));
2427d0b3229Schristos 	if (bmachine.reg == NULL)
2437d0b3229Schristos 		err(1, NULL);
2447d0b3229Schristos 
2457d0b3229Schristos 	for (i = 0; i < UCHAR_MAX; i++)
2467d0b3229Schristos 		jump_table[i] = unknown;
2477d0b3229Schristos 	for (i = 0; i < JUMP_TABLE_DATA_SIZE; i++)
2487d0b3229Schristos 		jump_table[jump_table_data[i].ch] = jump_table_data[i].f;
2497d0b3229Schristos 
2507d0b3229Schristos 	stack_init(&bmachine.stack);
2517d0b3229Schristos 
2527d0b3229Schristos 	for (i = 0; i < bmachine.reg_array_size; i++)
2537d0b3229Schristos 		stack_init(&bmachine.reg[i]);
2547d0b3229Schristos 
2557d0b3229Schristos 	bmachine.readstack_sz = READSTACK_SIZE;
2567d0b3229Schristos 	bmachine.readstack = calloc(sizeof(struct source),
2577d0b3229Schristos 	    bmachine.readstack_sz);
2587d0b3229Schristos 	if (bmachine.readstack == NULL)
2597d0b3229Schristos 		err(1, NULL);
2607d0b3229Schristos 	bmachine.obase = bmachine.ibase = 10;
2617d0b3229Schristos 	(void)signal(SIGINT, sighandler);
2627d0b3229Schristos }
2637d0b3229Schristos 
2647d0b3229Schristos u_int
bmachine_scale(void)2657d0b3229Schristos bmachine_scale(void)
2667d0b3229Schristos {
2677d0b3229Schristos 	return bmachine.scale;
2687d0b3229Schristos }
2697d0b3229Schristos 
2707d0b3229Schristos /* Reset the things needed before processing a (new) file */
2717d0b3229Schristos void
reset_bmachine(struct source * src)2727d0b3229Schristos reset_bmachine(struct source *src)
2737d0b3229Schristos {
2747d0b3229Schristos 	bmachine.readsp = 0;
2757d0b3229Schristos 	bmachine.readstack[0] = *src;
2767d0b3229Schristos }
2777d0b3229Schristos 
2787d0b3229Schristos static __inline int
readch(void)2797d0b3229Schristos readch(void)
2807d0b3229Schristos {
2817d0b3229Schristos 	struct source *src = &bmachine.readstack[bmachine.readsp];
2827d0b3229Schristos 
2837d0b3229Schristos 	return src->vtable->readchar(src);
2847d0b3229Schristos }
2857d0b3229Schristos 
2867d0b3229Schristos static __inline void
unreadch(void)2877d0b3229Schristos unreadch(void)
2887d0b3229Schristos {
2897d0b3229Schristos 	struct source *src = &bmachine.readstack[bmachine.readsp];
2907d0b3229Schristos 
2917d0b3229Schristos 	src->vtable->unreadchar(src);
2927d0b3229Schristos }
2937d0b3229Schristos 
2947d0b3229Schristos static __inline char *
readline(void)2957d0b3229Schristos readline(void)
2967d0b3229Schristos {
2977d0b3229Schristos 	struct source *src = &bmachine.readstack[bmachine.readsp];
2987d0b3229Schristos 
2997d0b3229Schristos 	return src->vtable->readline(src);
3007d0b3229Schristos }
3017d0b3229Schristos 
3027d0b3229Schristos static __inline void
src_free(void)3037d0b3229Schristos src_free(void)
3047d0b3229Schristos {
3057d0b3229Schristos 	struct source *src = &bmachine.readstack[bmachine.readsp];
3067d0b3229Schristos 
3077d0b3229Schristos 	src->vtable->free(src);
3087d0b3229Schristos }
3097d0b3229Schristos 
3107d0b3229Schristos #ifdef DEBUGGING
3117d0b3229Schristos void
pn(const char * str,const struct number * n)3127d0b3229Schristos pn(const char *str, const struct number *n)
3137d0b3229Schristos {
3147d0b3229Schristos 	char *p = BN_bn2dec(n->number);
3157d0b3229Schristos 	if (p == NULL)
3167d0b3229Schristos 		err(1, "BN_bn2dec failed");
3177d0b3229Schristos 	(void)fputs(str, stderr);
3187d0b3229Schristos 	(void)fprintf(stderr, " %s (%u)\n" , p, n->scale);
3197d0b3229Schristos 	OPENSSL_free(p);
3207d0b3229Schristos }
3217d0b3229Schristos 
3227d0b3229Schristos void
pbn(const char * str,const BIGNUM * n)3237d0b3229Schristos pbn(const char *str, const BIGNUM *n)
3247d0b3229Schristos {
3257d0b3229Schristos 	char *p = BN_bn2dec(n);
3267d0b3229Schristos 	if (p == NULL)
3277d0b3229Schristos 		err(1, "BN_bn2dec failed");
3287d0b3229Schristos 	(void)fputs(str, stderr);
3297d0b3229Schristos 	(void)fprintf(stderr, " %s\n", p);
3307d0b3229Schristos 	OPENSSL_free(p);
3317d0b3229Schristos }
3327d0b3229Schristos 
3337d0b3229Schristos #endif
3347d0b3229Schristos 
3357d0b3229Schristos static __inline u_int
max(u_int a,u_int b)3367d0b3229Schristos max(u_int a, u_int b)
3377d0b3229Schristos {
3387d0b3229Schristos 	return a > b ? a : b;
3397d0b3229Schristos }
3407d0b3229Schristos 
341*3c7417b2Smartin static BN_ULONG factors[] = {
3427d0b3229Schristos 	0, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
3437d0b3229Schristos 	100000000, 1000000000
3447d0b3229Schristos };
3457d0b3229Schristos 
3467d0b3229Schristos void
scale_number(BIGNUM * n,int s)3477d0b3229Schristos scale_number(BIGNUM *n, int s)
3487d0b3229Schristos {
349fc8ee2f5Schristos 	size_t abs_scale;
3507d0b3229Schristos 
3517d0b3229Schristos 	if (s == 0)
3527d0b3229Schristos 		return;
3537d0b3229Schristos 
354fc8ee2f5Schristos 	abs_scale = (size_t)(s > 0 ? s : -s);
3557d0b3229Schristos 
3567d0b3229Schristos 	if (abs_scale < sizeof(factors)/sizeof(factors[0])) {
3577d0b3229Schristos 		if (s > 0)
3587d0b3229Schristos 			bn_check(BN_mul_word(n, factors[abs_scale]));
3597d0b3229Schristos 		else
3607d0b3229Schristos 			(void)BN_div_word(n, factors[abs_scale]);
3617d0b3229Schristos 	} else {
3627d0b3229Schristos 		BIGNUM *a, *p;
3637d0b3229Schristos 		BN_CTX *ctx;
3647d0b3229Schristos 
3657d0b3229Schristos 		a = BN_new();
3667d0b3229Schristos 		bn_checkp(a);
3677d0b3229Schristos 		p = BN_new();
3687d0b3229Schristos 		bn_checkp(p);
3697d0b3229Schristos 		ctx = BN_CTX_new();
3707d0b3229Schristos 		bn_checkp(ctx);
3717d0b3229Schristos 
3727d0b3229Schristos 		bn_check(BN_set_word(a, 10));
373*3c7417b2Smartin 		bn_check(BN_set_word(p, (BN_ULONG)abs_scale));
3747d0b3229Schristos 		bn_check(BN_exp(a, a, p, ctx));
3757d0b3229Schristos 		if (s > 0)
3767d0b3229Schristos 			bn_check(BN_mul(n, n, a, ctx));
3777d0b3229Schristos 		else
3787d0b3229Schristos 			bn_check(BN_div(n, NULL, n, a, ctx));
3797d0b3229Schristos 		BN_CTX_free(ctx);
3807d0b3229Schristos 		BN_free(a);
3817d0b3229Schristos 		BN_free(p);
3827d0b3229Schristos 	}
3837d0b3229Schristos }
3847d0b3229Schristos 
3857d0b3229Schristos void
split_number(const struct number * n,BIGNUM * i,BIGNUM * f)3867d0b3229Schristos split_number(const struct number *n, BIGNUM *i, BIGNUM *f)
3877d0b3229Schristos {
3887d0b3229Schristos 	u_long rem;
3897d0b3229Schristos 
3907d0b3229Schristos 	bn_checkp(BN_copy(i, n->number));
3917d0b3229Schristos 
3927d0b3229Schristos 	if (n->scale == 0 && f != NULL)
3937d0b3229Schristos 		bn_check(BN_set_word(f, 0));
3947d0b3229Schristos 	else if (n->scale < sizeof(factors)/sizeof(factors[0])) {
3957d0b3229Schristos 		rem = BN_div_word(i, factors[n->scale]);
3967d0b3229Schristos 		if (f != NULL)
397*3c7417b2Smartin 			bn_check(BN_set_word(f, (BN_ULONG)rem));
3987d0b3229Schristos 	} else {
3997d0b3229Schristos 		BIGNUM *a, *p;
4007d0b3229Schristos 		BN_CTX *ctx;
4017d0b3229Schristos 
4027d0b3229Schristos 		a = BN_new();
4037d0b3229Schristos 		bn_checkp(a);
4047d0b3229Schristos 		p = BN_new();
4057d0b3229Schristos 		bn_checkp(p);
4067d0b3229Schristos 		ctx = BN_CTX_new();
4077d0b3229Schristos 		bn_checkp(ctx);
4087d0b3229Schristos 
4097d0b3229Schristos 		bn_check(BN_set_word(a, 10));
4107d0b3229Schristos 		bn_check(BN_set_word(p, n->scale));
4117d0b3229Schristos 		bn_check(BN_exp(a, a, p, ctx));
4127d0b3229Schristos 		bn_check(BN_div(i, f, n->number, a, ctx));
4137d0b3229Schristos 		BN_CTX_free(ctx);
4147d0b3229Schristos 		BN_free(a);
4157d0b3229Schristos 		BN_free(p);
4167d0b3229Schristos 	}
4177d0b3229Schristos }
4187d0b3229Schristos 
4197d0b3229Schristos void
normalize(struct number * n,u_int s)4207d0b3229Schristos normalize(struct number *n, u_int s)
4217d0b3229Schristos {
422fc8ee2f5Schristos 	scale_number(n->number, (int)(s - n->scale));
4237d0b3229Schristos 	n->scale = s;
4247d0b3229Schristos }
4257d0b3229Schristos 
4267d0b3229Schristos static u_long
get_ulong(struct number * n)4277d0b3229Schristos get_ulong(struct number *n)
4287d0b3229Schristos {
4297d0b3229Schristos 	normalize(n, 0);
4307d0b3229Schristos 	return BN_get_word(n->number);
4317d0b3229Schristos }
4327d0b3229Schristos 
4337d0b3229Schristos void
negate(struct number * n)4347d0b3229Schristos negate(struct number *n)
4357d0b3229Schristos {
4367d0b3229Schristos 	BN_set_negative(n->number, !BN_is_negative(n->number));
4377d0b3229Schristos }
4387d0b3229Schristos 
4397d0b3229Schristos static __inline void
push_number(struct number * n)4407d0b3229Schristos push_number(struct number *n)
4417d0b3229Schristos {
4427d0b3229Schristos 	stack_pushnumber(&bmachine.stack, n);
4437d0b3229Schristos }
4447d0b3229Schristos 
4457d0b3229Schristos static __inline void
push_string(char * string)4467d0b3229Schristos push_string(char *string)
4477d0b3229Schristos {
4487d0b3229Schristos 	stack_pushstring(&bmachine.stack, string);
4497d0b3229Schristos }
4507d0b3229Schristos 
4517d0b3229Schristos static __inline void
push(struct value * v)4527d0b3229Schristos push(struct value *v)
4537d0b3229Schristos {
4547d0b3229Schristos 	stack_push(&bmachine.stack, v);
4557d0b3229Schristos }
4567d0b3229Schristos 
4577d0b3229Schristos static __inline struct value *
tos(void)4587d0b3229Schristos tos(void)
4597d0b3229Schristos {
4607d0b3229Schristos 	return stack_tos(&bmachine.stack);
4617d0b3229Schristos }
4627d0b3229Schristos 
4637d0b3229Schristos static __inline struct value *
pop(void)4647d0b3229Schristos pop(void)
4657d0b3229Schristos {
4667d0b3229Schristos 	return stack_pop(&bmachine.stack);
4677d0b3229Schristos }
4687d0b3229Schristos 
4697d0b3229Schristos static __inline struct number *
pop_number(void)4707d0b3229Schristos pop_number(void)
4717d0b3229Schristos {
4727d0b3229Schristos 	return stack_popnumber(&bmachine.stack);
4737d0b3229Schristos }
4747d0b3229Schristos 
4757d0b3229Schristos static __inline char *
pop_string(void)4767d0b3229Schristos pop_string(void)
4777d0b3229Schristos {
4787d0b3229Schristos 	return stack_popstring(&bmachine.stack);
4797d0b3229Schristos }
4807d0b3229Schristos 
4817d0b3229Schristos static __inline void
clear_stack(void)4827d0b3229Schristos clear_stack(void)
4837d0b3229Schristos {
4847d0b3229Schristos 	stack_clear(&bmachine.stack);
4857d0b3229Schristos }
4867d0b3229Schristos 
4877d0b3229Schristos static __inline void
print_stack(void)4887d0b3229Schristos print_stack(void)
4897d0b3229Schristos {
4907d0b3229Schristos 	stack_print(stdout, &bmachine.stack, "", bmachine.obase);
4917d0b3229Schristos }
4927d0b3229Schristos 
4937d0b3229Schristos static __inline void
print_tos(void)4947d0b3229Schristos print_tos(void)
4957d0b3229Schristos {
4967d0b3229Schristos 	struct value *value = tos();
4977d0b3229Schristos 	if (value != NULL) {
4987d0b3229Schristos 		print_value(stdout, value, "", bmachine.obase);
4997d0b3229Schristos 		(void)putchar('\n');
5007d0b3229Schristos 	}
5017d0b3229Schristos 	else
5027d0b3229Schristos 		warnx("stack empty");
5037d0b3229Schristos }
5047d0b3229Schristos 
5057d0b3229Schristos static void
print_err(void)5067d0b3229Schristos print_err(void)
5077d0b3229Schristos {
5087d0b3229Schristos 	struct value *value = tos();
5097d0b3229Schristos 	if (value != NULL) {
5107d0b3229Schristos 		print_value(stderr, value, "", bmachine.obase);
5117d0b3229Schristos 		(void)putc('\n', stderr);
5127d0b3229Schristos 	}
5137d0b3229Schristos 	else
5147d0b3229Schristos 		warnx("stack empty");
5157d0b3229Schristos }
5167d0b3229Schristos 
5177d0b3229Schristos static void
pop_print(void)5187d0b3229Schristos pop_print(void)
5197d0b3229Schristos {
5207d0b3229Schristos 	struct value *value = pop();
5217d0b3229Schristos 
5227d0b3229Schristos 	if (value != NULL) {
5237d0b3229Schristos 		switch (value->type) {
5247d0b3229Schristos 		case BCODE_NONE:
5257d0b3229Schristos 			break;
5267d0b3229Schristos 		case BCODE_NUMBER:
5277d0b3229Schristos 			normalize(value->u.num, 0);
5287d0b3229Schristos 			print_ascii(stdout, value->u.num);
5297d0b3229Schristos 			(void)fflush(stdout);
5307d0b3229Schristos 			break;
5317d0b3229Schristos 		case BCODE_STRING:
5327d0b3229Schristos 			(void)fputs(value->u.string, stdout);
5337d0b3229Schristos 			(void)fflush(stdout);
5347d0b3229Schristos 			break;
5357d0b3229Schristos 		}
5367d0b3229Schristos 		stack_free_value(value);
5377d0b3229Schristos 	}
5387d0b3229Schristos }
5397d0b3229Schristos 
5407d0b3229Schristos static void
pop_printn(void)5417d0b3229Schristos pop_printn(void)
5427d0b3229Schristos {
5437d0b3229Schristos 	struct value *value = pop();
5447d0b3229Schristos 
5457d0b3229Schristos 	if (value != NULL) {
5467d0b3229Schristos 		print_value(stdout, value, "", bmachine.obase);
5477d0b3229Schristos 		(void)fflush(stdout);
5487d0b3229Schristos 		stack_free_value(value);
5497d0b3229Schristos 	}
5507d0b3229Schristos }
5517d0b3229Schristos 
5527d0b3229Schristos static __inline void
dup(void)5537d0b3229Schristos dup(void)
5547d0b3229Schristos {
5557d0b3229Schristos 	stack_dup(&bmachine.stack);
5567d0b3229Schristos }
5577d0b3229Schristos 
5587d0b3229Schristos static void
swap(void)5597d0b3229Schristos swap(void)
5607d0b3229Schristos {
5617d0b3229Schristos 	stack_swap(&bmachine.stack);
5627d0b3229Schristos }
5637d0b3229Schristos 
5647d0b3229Schristos static void
drop(void)5657d0b3229Schristos drop(void)
5667d0b3229Schristos {
5677d0b3229Schristos 	struct value *v = pop();
5687d0b3229Schristos 	if (v != NULL)
5697d0b3229Schristos 		stack_free_value(v);
5707d0b3229Schristos }
5717d0b3229Schristos 
5727d0b3229Schristos static void
get_scale(void)5737d0b3229Schristos get_scale(void)
5747d0b3229Schristos {
5757d0b3229Schristos 	struct number	*n;
5767d0b3229Schristos 
5777d0b3229Schristos 	n = new_number();
5787d0b3229Schristos 	bn_check(BN_set_word(n->number, bmachine.scale));
5797d0b3229Schristos 	push_number(n);
5807d0b3229Schristos }
5817d0b3229Schristos 
5827d0b3229Schristos static void
set_scale(void)5837d0b3229Schristos set_scale(void)
5847d0b3229Schristos {
5857d0b3229Schristos 	struct number	*n;
5867d0b3229Schristos 	u_long		scale;
5877d0b3229Schristos 
5887d0b3229Schristos 	n = pop_number();
5897d0b3229Schristos 	if (n != NULL) {
5907d0b3229Schristos 		if (BN_is_negative(n->number))
5917d0b3229Schristos 			warnx("scale must be a nonnegative number");
5927d0b3229Schristos 		else {
5937d0b3229Schristos 			scale = get_ulong(n);
594fa34604aSchristos 			if (scale != NO_NUMBER && scale <= UINT_MAX)
5957d0b3229Schristos 				bmachine.scale = (u_int)scale;
5967d0b3229Schristos 			else
5977d0b3229Schristos 				warnx("scale too large");
5987d0b3229Schristos 			}
5997d0b3229Schristos 		free_number(n);
6007d0b3229Schristos 	}
6017d0b3229Schristos }
6027d0b3229Schristos 
6037d0b3229Schristos static void
get_obase(void)6047d0b3229Schristos get_obase(void)
6057d0b3229Schristos {
6067d0b3229Schristos 	struct number	*n;
6077d0b3229Schristos 
6087d0b3229Schristos 	n = new_number();
6097d0b3229Schristos 	bn_check(BN_set_word(n->number, bmachine.obase));
6107d0b3229Schristos 	push_number(n);
6117d0b3229Schristos }
6127d0b3229Schristos 
6137d0b3229Schristos static void
set_obase(void)6147d0b3229Schristos set_obase(void)
6157d0b3229Schristos {
6167d0b3229Schristos 	struct number	*n;
6177d0b3229Schristos 	u_long		base;
6187d0b3229Schristos 
6197d0b3229Schristos 	n = pop_number();
6207d0b3229Schristos 	if (n != NULL) {
6217d0b3229Schristos 		base = get_ulong(n);
622fa34604aSchristos 		if (base != NO_NUMBER && base > 1 && base <= UINT_MAX)
6237d0b3229Schristos 			bmachine.obase = (u_int)base;
6247d0b3229Schristos 		else
6257d0b3229Schristos 			warnx("output base must be a number greater than 1");
6267d0b3229Schristos 		free_number(n);
6277d0b3229Schristos 	}
6287d0b3229Schristos }
6297d0b3229Schristos 
6307d0b3229Schristos static void
get_ibase(void)6317d0b3229Schristos get_ibase(void)
6327d0b3229Schristos {
6337d0b3229Schristos 	struct number *n;
6347d0b3229Schristos 
6357d0b3229Schristos 	n = new_number();
6367d0b3229Schristos 	bn_check(BN_set_word(n->number, bmachine.ibase));
6377d0b3229Schristos 	push_number(n);
6387d0b3229Schristos }
6397d0b3229Schristos 
6407d0b3229Schristos static void
set_ibase(void)6417d0b3229Schristos set_ibase(void)
6427d0b3229Schristos {
6437d0b3229Schristos 	struct number	*n;
6447d0b3229Schristos 	u_long		base;
6457d0b3229Schristos 
6467d0b3229Schristos 	n = pop_number();
6477d0b3229Schristos 	if (n != NULL) {
6487d0b3229Schristos 		base = get_ulong(n);
649fa34604aSchristos 		if (base != NO_NUMBER && 2 <= base && base <= 16)
6507d0b3229Schristos 			bmachine.ibase = (u_int)base;
6517d0b3229Schristos 		else
6527d0b3229Schristos 			warnx("input base must be a number between 2 and 16 "
6537d0b3229Schristos 			    "(inclusive)");
6547d0b3229Schristos 		free_number(n);
6557d0b3229Schristos 	}
6567d0b3229Schristos }
6577d0b3229Schristos 
6587d0b3229Schristos static void
stackdepth(void)6597d0b3229Schristos stackdepth(void)
6607d0b3229Schristos {
6617d0b3229Schristos 	size_t i;
6627d0b3229Schristos 	struct number *n;
6637d0b3229Schristos 
6647d0b3229Schristos 	i = stack_size(&bmachine.stack);
6657d0b3229Schristos 	n = new_number();
666*3c7417b2Smartin 	bn_check(BN_set_word(n->number, (BN_ULONG)i));
6677d0b3229Schristos 	push_number(n);
6687d0b3229Schristos }
6697d0b3229Schristos 
6707d0b3229Schristos static void
push_scale(void)6717d0b3229Schristos push_scale(void)
6727d0b3229Schristos {
6737d0b3229Schristos 	struct value	*value;
6747d0b3229Schristos 	u_int		scale = 0;
6757d0b3229Schristos 	struct number	*n;
6767d0b3229Schristos 
6777d0b3229Schristos 
6787d0b3229Schristos 	value = pop();
6797d0b3229Schristos 	if (value != NULL) {
6807d0b3229Schristos 		switch (value->type) {
6817d0b3229Schristos 		case BCODE_NONE:
6827d0b3229Schristos 			return;
6837d0b3229Schristos 		case BCODE_NUMBER:
6847d0b3229Schristos 			scale = value->u.num->scale;
6857d0b3229Schristos 			break;
6867d0b3229Schristos 		case BCODE_STRING:
6877d0b3229Schristos 			break;
6887d0b3229Schristos 		}
6897d0b3229Schristos 		stack_free_value(value);
6907d0b3229Schristos 		n = new_number();
6917d0b3229Schristos 		bn_check(BN_set_word(n->number, scale));
6927d0b3229Schristos 		push_number(n);
6937d0b3229Schristos 	}
6947d0b3229Schristos }
6957d0b3229Schristos 
6967d0b3229Schristos static u_int
count_digits(const struct number * n)6977d0b3229Schristos count_digits(const struct number *n)
6987d0b3229Schristos {
6997d0b3229Schristos 	struct number	*int_part, *fract_part;
7007d0b3229Schristos 	u_int		i;
7017d0b3229Schristos 
7027d0b3229Schristos 	if (BN_is_zero(n->number))
7037d0b3229Schristos 		return n->scale ? n->scale : 1;
7047d0b3229Schristos 
7057d0b3229Schristos 	int_part = new_number();
7067d0b3229Schristos 	fract_part = new_number();
7077d0b3229Schristos 	fract_part->scale = n->scale;
7087d0b3229Schristos 	split_number(n, int_part->number, fract_part->number);
7097d0b3229Schristos 
7107d0b3229Schristos 	i = 0;
7117d0b3229Schristos 	while (!BN_is_zero(int_part->number)) {
7127d0b3229Schristos 		(void)BN_div_word(int_part->number, 10);
7137d0b3229Schristos 		i++;
7147d0b3229Schristos 	}
7157d0b3229Schristos 	free_number(int_part);
7167d0b3229Schristos 	free_number(fract_part);
7177d0b3229Schristos 	return i + n->scale;
7187d0b3229Schristos }
7197d0b3229Schristos 
7207d0b3229Schristos static void
num_digits(void)7217d0b3229Schristos num_digits(void)
7227d0b3229Schristos {
7237d0b3229Schristos 	struct value	*value;
7247d0b3229Schristos 	size_t		digits;
7257d0b3229Schristos 	struct number	*n = NULL;
7267d0b3229Schristos 
7277d0b3229Schristos 	value = pop();
7287d0b3229Schristos 	if (value != NULL) {
7297d0b3229Schristos 		switch (value->type) {
7307d0b3229Schristos 		case BCODE_NONE:
7317d0b3229Schristos 			return;
7327d0b3229Schristos 		case BCODE_NUMBER:
7337d0b3229Schristos 			digits = count_digits(value->u.num);
7347d0b3229Schristos 			n = new_number();
735*3c7417b2Smartin 			bn_check(BN_set_word(n->number, (BN_ULONG)digits));
7367d0b3229Schristos 			break;
7377d0b3229Schristos 		case BCODE_STRING:
7387d0b3229Schristos 			digits = strlen(value->u.string);
7397d0b3229Schristos 			n = new_number();
740*3c7417b2Smartin 			bn_check(BN_set_word(n->number, (BN_ULONG)digits));
7417d0b3229Schristos 			break;
7427d0b3229Schristos 		}
7437d0b3229Schristos 		stack_free_value(value);
7447d0b3229Schristos 		push_number(n);
7457d0b3229Schristos 	}
7467d0b3229Schristos }
7477d0b3229Schristos 
7487d0b3229Schristos static void
to_ascii(void)7497d0b3229Schristos to_ascii(void)
7507d0b3229Schristos {
7517d0b3229Schristos 	char		str[2];
7527d0b3229Schristos 	struct value	*value;
7537d0b3229Schristos 	struct number	*n;
7547d0b3229Schristos 
7557d0b3229Schristos 	value = pop();
7567d0b3229Schristos 	if (value != NULL) {
7577d0b3229Schristos 		str[1] = '\0';
7587d0b3229Schristos 		switch (value->type) {
7597d0b3229Schristos 		case BCODE_NONE:
7607d0b3229Schristos 			return;
7617d0b3229Schristos 		case BCODE_NUMBER:
7627d0b3229Schristos 			n = value->u.num;
7637d0b3229Schristos 			normalize(n, 0);
7647d0b3229Schristos 			if (BN_num_bits(n->number) > 8)
7657d0b3229Schristos 				bn_check(BN_mask_bits(n->number, 8));
7667d0b3229Schristos 			str[0] = (char)BN_get_word(n->number);
7677d0b3229Schristos 			break;
7687d0b3229Schristos 		case BCODE_STRING:
7697d0b3229Schristos 			str[0] = value->u.string[0];
7707d0b3229Schristos 			break;
7717d0b3229Schristos 		}
7727d0b3229Schristos 		stack_free_value(value);
7737d0b3229Schristos 		push_string(bstrdup(str));
7747d0b3229Schristos 	}
7757d0b3229Schristos }
7767d0b3229Schristos 
7777d0b3229Schristos static int
readreg(void)7787d0b3229Schristos readreg(void)
7797d0b3229Schristos {
7807d0b3229Schristos 	int idx, ch1, ch2;
7817d0b3229Schristos 
7827d0b3229Schristos 	idx = readch();
7837d0b3229Schristos 	if (idx == 0xff && bmachine.extended_regs) {
7847d0b3229Schristos 		ch1 = readch();
7857d0b3229Schristos 		ch2 = readch();
7867d0b3229Schristos 		if (ch1 == EOF || ch2 == EOF) {
7877d0b3229Schristos 			warnx("unexpected eof");
7887d0b3229Schristos 			idx = -1;
7897d0b3229Schristos 		} else
7907d0b3229Schristos 			idx = (ch1 << 8) + ch2 + UCHAR_MAX + 1;
7917d0b3229Schristos 	}
792fc8ee2f5Schristos 	if (idx < 0 || (size_t)idx >= bmachine.reg_array_size) {
7937d0b3229Schristos 		warnx("internal error: reg num = %d", idx);
7947d0b3229Schristos 		idx = -1;
7957d0b3229Schristos 	}
7967d0b3229Schristos 	return idx;
7977d0b3229Schristos }
7987d0b3229Schristos 
7997d0b3229Schristos static void
load(void)8007d0b3229Schristos load(void)
8017d0b3229Schristos {
8027d0b3229Schristos 	int		idx;
8037d0b3229Schristos 	struct value	*v, copy;
8047d0b3229Schristos 	struct number	*n;
8057d0b3229Schristos 
8067d0b3229Schristos 	idx = readreg();
8077d0b3229Schristos 	if (idx >= 0) {
8087d0b3229Schristos 		v = stack_tos(&bmachine.reg[idx]);
8097d0b3229Schristos 		if (v == NULL) {
8107d0b3229Schristos 			n = new_number();
8117d0b3229Schristos 			bn_check(BN_set_word(n->number, 0));
8127d0b3229Schristos 			push_number(n);
8137d0b3229Schristos 		} else
8147d0b3229Schristos 			push(stack_dup_value(v, &copy));
8157d0b3229Schristos 	}
8167d0b3229Schristos }
8177d0b3229Schristos 
8187d0b3229Schristos static void
store(void)8197d0b3229Schristos store(void)
8207d0b3229Schristos {
8217d0b3229Schristos 	int		idx;
8227d0b3229Schristos 	struct value	*val;
8237d0b3229Schristos 
8247d0b3229Schristos 	idx = readreg();
8257d0b3229Schristos 	if (idx >= 0) {
8267d0b3229Schristos 		val = pop();
8277d0b3229Schristos 		if (val == NULL) {
8287d0b3229Schristos 			return;
8297d0b3229Schristos 		}
8307d0b3229Schristos 		stack_set_tos(&bmachine.reg[idx], val);
8317d0b3229Schristos 	}
8327d0b3229Schristos }
8337d0b3229Schristos 
8347d0b3229Schristos static void
load_stack(void)8357d0b3229Schristos load_stack(void)
8367d0b3229Schristos {
8377d0b3229Schristos 	int		idx;
8387d0b3229Schristos 	struct stack	*stack;
8397d0b3229Schristos 	struct value	*value;
8407d0b3229Schristos 
8417d0b3229Schristos 	idx = readreg();
8427d0b3229Schristos 	if (idx >= 0) {
8437d0b3229Schristos 		stack = &bmachine.reg[idx];
8447d0b3229Schristos 		value = NULL;
8457d0b3229Schristos 		if (stack_size(stack) > 0) {
8467d0b3229Schristos 			value = stack_pop(stack);
8477d0b3229Schristos 		}
8487d0b3229Schristos 		if (value != NULL)
8497d0b3229Schristos 			push(value);
8507d0b3229Schristos 		else
8517d0b3229Schristos 			warnx("stack register '%c' (0%o) is empty",
8527d0b3229Schristos 			    idx, idx);
8537d0b3229Schristos 	}
8547d0b3229Schristos }
8557d0b3229Schristos 
8567d0b3229Schristos static void
store_stack(void)8577d0b3229Schristos store_stack(void)
8587d0b3229Schristos {
8597d0b3229Schristos 	int		idx;
8607d0b3229Schristos 	struct value	*value;
8617d0b3229Schristos 
8627d0b3229Schristos 	idx = readreg();
8637d0b3229Schristos 	if (idx >= 0) {
8647d0b3229Schristos 		value = pop();
8657d0b3229Schristos 		if (value == NULL)
8667d0b3229Schristos 			return;
8677d0b3229Schristos 		stack_push(&bmachine.reg[idx], value);
8687d0b3229Schristos 	}
8697d0b3229Schristos }
8707d0b3229Schristos 
8717d0b3229Schristos static void
load_array(void)8727d0b3229Schristos load_array(void)
8737d0b3229Schristos {
8747d0b3229Schristos 	int			reg;
8757d0b3229Schristos 	struct number		*inumber, *n;
8767d0b3229Schristos 	u_long			idx;
8777d0b3229Schristos 	struct stack		*stack;
8787d0b3229Schristos 	struct value		*v, copy;
8797d0b3229Schristos 
8807d0b3229Schristos 	reg = readreg();
8817d0b3229Schristos 	if (reg >= 0) {
8827d0b3229Schristos 		inumber = pop_number();
8837d0b3229Schristos 		if (inumber == NULL)
8847d0b3229Schristos 			return;
8857d0b3229Schristos 		idx = get_ulong(inumber);
8867d0b3229Schristos 		if (BN_is_negative(inumber->number))
8877d0b3229Schristos 			warnx("negative idx");
888fa34604aSchristos 		else if (idx == NO_NUMBER || idx > MAX_ARRAY_INDEX)
8897d0b3229Schristos 			warnx("idx too big");
8907d0b3229Schristos 		else {
8917d0b3229Schristos 			stack = &bmachine.reg[reg];
8927d0b3229Schristos 			v = frame_retrieve(stack, idx);
8937d0b3229Schristos 			if (v == NULL || v->type == BCODE_NONE) {
8947d0b3229Schristos 				n = new_number();
8957d0b3229Schristos 				bn_check(BN_set_word(n->number, 0));
8967d0b3229Schristos 				push_number(n);
8977d0b3229Schristos 			}
8987d0b3229Schristos 			else
8997d0b3229Schristos 				push(stack_dup_value(v, &copy));
9007d0b3229Schristos 		}
9017d0b3229Schristos 		free_number(inumber);
9027d0b3229Schristos 	}
9037d0b3229Schristos }
9047d0b3229Schristos 
9057d0b3229Schristos static void
store_array(void)9067d0b3229Schristos store_array(void)
9077d0b3229Schristos {
9087d0b3229Schristos 	int			reg;
9097d0b3229Schristos 	struct number		*inumber;
9107d0b3229Schristos 	u_long			idx;
9117d0b3229Schristos 	struct value		*value;
9127d0b3229Schristos 	struct stack		*stack;
9137d0b3229Schristos 
9147d0b3229Schristos 	reg = readreg();
9157d0b3229Schristos 	if (reg >= 0) {
9167d0b3229Schristos 		inumber = pop_number();
9177d0b3229Schristos 		if (inumber == NULL)
9187d0b3229Schristos 			return;
9197d0b3229Schristos 		value = pop();
9207d0b3229Schristos 		if (value == NULL) {
9217d0b3229Schristos 			free_number(inumber);
9227d0b3229Schristos 			return;
9237d0b3229Schristos 		}
9247d0b3229Schristos 		idx = get_ulong(inumber);
9257d0b3229Schristos 		if (BN_is_negative(inumber->number)) {
9267d0b3229Schristos 			warnx("negative idx");
9277d0b3229Schristos 			stack_free_value(value);
928fa34604aSchristos 		} else if (idx == NO_NUMBER || idx > MAX_ARRAY_INDEX) {
9297d0b3229Schristos 			warnx("idx too big");
9307d0b3229Schristos 			stack_free_value(value);
9317d0b3229Schristos 		} else {
9327d0b3229Schristos 			stack = &bmachine.reg[reg];
9337d0b3229Schristos 			frame_assign(stack, idx, value);
9347d0b3229Schristos 		}
9357d0b3229Schristos 		free_number(inumber);
9367d0b3229Schristos 	}
9377d0b3229Schristos }
9387d0b3229Schristos 
9397d0b3229Schristos static void
push_line(void)9407d0b3229Schristos push_line(void)
9417d0b3229Schristos {
9427d0b3229Schristos 	push_string(read_string(&bmachine.readstack[bmachine.readsp]));
9437d0b3229Schristos }
9447d0b3229Schristos 
9457d0b3229Schristos static void
comment(void)9467d0b3229Schristos comment(void)
9477d0b3229Schristos {
9487d0b3229Schristos 	free(readline());
9497d0b3229Schristos }
9507d0b3229Schristos 
9517d0b3229Schristos static void
badd(void)9527d0b3229Schristos badd(void)
9537d0b3229Schristos {
9547d0b3229Schristos 	struct number	*a, *b;
9557d0b3229Schristos 	struct number	*r;
9567d0b3229Schristos 
9577d0b3229Schristos 	a = pop_number();
9587d0b3229Schristos 	if (a == NULL)
9597d0b3229Schristos 		return;
9607d0b3229Schristos 	b = pop_number();
9617d0b3229Schristos 	if (b == NULL) {
9627d0b3229Schristos 		push_number(a);
9637d0b3229Schristos 		return;
9647d0b3229Schristos 	}
9657d0b3229Schristos 
9667d0b3229Schristos 	r = new_number();
9677d0b3229Schristos 	r->scale = max(a->scale, b->scale);
9687d0b3229Schristos 	if (r->scale > a->scale)
9697d0b3229Schristos 		normalize(a, r->scale);
9707d0b3229Schristos 	else if (r->scale > b->scale)
9717d0b3229Schristos 		normalize(b, r->scale);
9727d0b3229Schristos 	bn_check(BN_add(r->number, a->number, b->number));
9737d0b3229Schristos 	push_number(r);
9747d0b3229Schristos 	free_number(a);
9757d0b3229Schristos 	free_number(b);
9767d0b3229Schristos }
9777d0b3229Schristos 
9787d0b3229Schristos static void
bsub(void)9797d0b3229Schristos bsub(void)
9807d0b3229Schristos {
9817d0b3229Schristos 	struct number	*a, *b;
9827d0b3229Schristos 	struct number	*r;
9837d0b3229Schristos 
9847d0b3229Schristos 	a = pop_number();
9857d0b3229Schristos 	if (a == NULL)
9867d0b3229Schristos 		return;
9877d0b3229Schristos 	b = pop_number();
9887d0b3229Schristos 	if (b == NULL) {
9897d0b3229Schristos 		push_number(a);
9907d0b3229Schristos 		return;
9917d0b3229Schristos 	}
9927d0b3229Schristos 
9937d0b3229Schristos 	r = new_number();
9947d0b3229Schristos 
9957d0b3229Schristos 	r->scale = max(a->scale, b->scale);
9967d0b3229Schristos 	if (r->scale > a->scale)
9977d0b3229Schristos 		normalize(a, r->scale);
9987d0b3229Schristos 	else if (r->scale > b->scale)
9997d0b3229Schristos 		normalize(b, r->scale);
10007d0b3229Schristos 	bn_check(BN_sub(r->number, b->number, a->number));
10017d0b3229Schristos 	push_number(r);
10027d0b3229Schristos 	free_number(a);
10037d0b3229Schristos 	free_number(b);
10047d0b3229Schristos }
10057d0b3229Schristos 
10067d0b3229Schristos void
bmul_number(struct number * r,struct number * a,struct number * b,u_int scale)10077d0b3229Schristos bmul_number(struct number *r, struct number *a, struct number *b, u_int scale)
10087d0b3229Schristos {
10097d0b3229Schristos 	BN_CTX		*ctx;
10107d0b3229Schristos 
10117d0b3229Schristos 	/* Create copies of the scales, since r might be equal to a or b */
10127d0b3229Schristos 	u_int ascale = a->scale;
10137d0b3229Schristos 	u_int bscale = b->scale;
10147d0b3229Schristos 	u_int rscale = ascale + bscale;
10157d0b3229Schristos 
10167d0b3229Schristos 	ctx = BN_CTX_new();
10177d0b3229Schristos 	bn_checkp(ctx);
10187d0b3229Schristos 	bn_check(BN_mul(r->number, a->number, b->number, ctx));
10197d0b3229Schristos 	BN_CTX_free(ctx);
10207d0b3229Schristos 
10217d0b3229Schristos 	r->scale = rscale;
10227d0b3229Schristos 	if (rscale > bmachine.scale && rscale > ascale && rscale > bscale)
10237d0b3229Schristos 		normalize(r, max(scale, max(ascale, bscale)));
10247d0b3229Schristos }
10257d0b3229Schristos 
10267d0b3229Schristos static void
bmul(void)10277d0b3229Schristos bmul(void)
10287d0b3229Schristos {
10297d0b3229Schristos 	struct number	*a, *b;
10307d0b3229Schristos 	struct number	*r;
10317d0b3229Schristos 
10327d0b3229Schristos 	a = pop_number();
10337d0b3229Schristos 	if (a == NULL)
10347d0b3229Schristos 		return;
10357d0b3229Schristos 	b = pop_number();
10367d0b3229Schristos 	if (b == NULL) {
10377d0b3229Schristos 		push_number(a);
10387d0b3229Schristos 		return;
10397d0b3229Schristos 	}
10407d0b3229Schristos 
10417d0b3229Schristos 	r = new_number();
10427d0b3229Schristos 	bmul_number(r, a, b, bmachine.scale);
10437d0b3229Schristos 
10447d0b3229Schristos 	push_number(r);
10457d0b3229Schristos 	free_number(a);
10467d0b3229Schristos 	free_number(b);
10477d0b3229Schristos }
10487d0b3229Schristos 
10497d0b3229Schristos static void
bdiv(void)10507d0b3229Schristos bdiv(void)
10517d0b3229Schristos {
10527d0b3229Schristos 	struct number	*a, *b;
10537d0b3229Schristos 	struct number	*r;
10547d0b3229Schristos 	u_int		scale;
10557d0b3229Schristos 	BN_CTX		*ctx;
10567d0b3229Schristos 
10577d0b3229Schristos 	a = pop_number();
10587d0b3229Schristos 	if (a == NULL)
10597d0b3229Schristos 		return;
10607d0b3229Schristos 	b = pop_number();
10617d0b3229Schristos 	if (b == NULL) {
10627d0b3229Schristos 		push_number(a);
10637d0b3229Schristos 		return;
10647d0b3229Schristos 	}
10657d0b3229Schristos 
10667d0b3229Schristos 	r = new_number();
10677d0b3229Schristos 	r->scale = bmachine.scale;
10687d0b3229Schristos 	scale = max(a->scale, b->scale);
10697d0b3229Schristos 
10707d0b3229Schristos 	if (BN_is_zero(a->number))
10717d0b3229Schristos 		warnx("divide by zero");
10727d0b3229Schristos 	else {
10737d0b3229Schristos 		normalize(a, scale);
10747d0b3229Schristos 		normalize(b, scale + r->scale);
10757d0b3229Schristos 
10767d0b3229Schristos 		ctx = BN_CTX_new();
10777d0b3229Schristos 		bn_checkp(ctx);
10787d0b3229Schristos 		bn_check(BN_div(r->number, NULL, b->number, a->number, ctx));
10797d0b3229Schristos 		BN_CTX_free(ctx);
10807d0b3229Schristos 	}
10817d0b3229Schristos 	push_number(r);
10827d0b3229Schristos 	free_number(a);
10837d0b3229Schristos 	free_number(b);
10847d0b3229Schristos }
10857d0b3229Schristos 
10867d0b3229Schristos static void
bmod(void)10877d0b3229Schristos bmod(void)
10887d0b3229Schristos {
10897d0b3229Schristos 	struct number	*a, *b;
10907d0b3229Schristos 	struct number	*r;
10917d0b3229Schristos 	u_int		scale;
10927d0b3229Schristos 	BN_CTX		*ctx;
10937d0b3229Schristos 
10947d0b3229Schristos 	a = pop_number();
10957d0b3229Schristos 	if (a == NULL)
10967d0b3229Schristos 		return;
10977d0b3229Schristos 	b = pop_number();
10987d0b3229Schristos 	if (b == NULL) {
10997d0b3229Schristos 		push_number(a);
11007d0b3229Schristos 		return;
11017d0b3229Schristos 	}
11027d0b3229Schristos 
11037d0b3229Schristos 	r = new_number();
11047d0b3229Schristos 	scale = max(a->scale, b->scale);
11057d0b3229Schristos 	r->scale = max(b->scale, a->scale + bmachine.scale);
11067d0b3229Schristos 
11077d0b3229Schristos 	if (BN_is_zero(a->number))
11087d0b3229Schristos 		warnx("remainder by zero");
11097d0b3229Schristos 	else {
11107d0b3229Schristos 		normalize(a, scale);
11117d0b3229Schristos 		normalize(b, scale + bmachine.scale);
11127d0b3229Schristos 
11137d0b3229Schristos 		ctx = BN_CTX_new();
11147d0b3229Schristos 		bn_checkp(ctx);
11157d0b3229Schristos 		bn_check(BN_mod(r->number, b->number, a->number, ctx));
11167d0b3229Schristos 		BN_CTX_free(ctx);
11177d0b3229Schristos 	}
11187d0b3229Schristos 	push_number(r);
11197d0b3229Schristos 	free_number(a);
11207d0b3229Schristos 	free_number(b);
11217d0b3229Schristos }
11227d0b3229Schristos 
11237d0b3229Schristos static void
bdivmod(void)11247d0b3229Schristos bdivmod(void)
11257d0b3229Schristos {
11267d0b3229Schristos 	struct number	*a, *b;
11277d0b3229Schristos 	struct number	*rdiv, *rmod;
11287d0b3229Schristos 	u_int		scale;
11297d0b3229Schristos 	BN_CTX		*ctx;
11307d0b3229Schristos 
11317d0b3229Schristos 	a = pop_number();
11327d0b3229Schristos 	if (a == NULL)
11337d0b3229Schristos 		return;
11347d0b3229Schristos 	b = pop_number();
11357d0b3229Schristos 	if (b == NULL) {
11367d0b3229Schristos 		push_number(a);
11377d0b3229Schristos 		return;
11387d0b3229Schristos 	}
11397d0b3229Schristos 
11407d0b3229Schristos 	rdiv = new_number();
11417d0b3229Schristos 	rmod = new_number();
11427d0b3229Schristos 	rdiv->scale = bmachine.scale;
11437d0b3229Schristos 	rmod->scale = max(b->scale, a->scale + bmachine.scale);
11447d0b3229Schristos 	scale = max(a->scale, b->scale);
11457d0b3229Schristos 
11467d0b3229Schristos 	if (BN_is_zero(a->number))
11477d0b3229Schristos 		warnx("divide by zero");
11487d0b3229Schristos 	else {
11497d0b3229Schristos 		normalize(a, scale);
11507d0b3229Schristos 		normalize(b, scale + bmachine.scale);
11517d0b3229Schristos 
11527d0b3229Schristos 		ctx = BN_CTX_new();
11537d0b3229Schristos 		bn_checkp(ctx);
11547d0b3229Schristos 		bn_check(BN_div(rdiv->number, rmod->number,
11557d0b3229Schristos 		    b->number, a->number, ctx));
11567d0b3229Schristos 		BN_CTX_free(ctx);
11577d0b3229Schristos 	}
11587d0b3229Schristos 	push_number(rdiv);
11597d0b3229Schristos 	push_number(rmod);
11607d0b3229Schristos 	free_number(a);
11617d0b3229Schristos 	free_number(b);
11627d0b3229Schristos }
11637d0b3229Schristos 
11647d0b3229Schristos static void
bexp(void)11657d0b3229Schristos bexp(void)
11667d0b3229Schristos {
11677d0b3229Schristos 	struct number	*a, *p;
11687d0b3229Schristos 	struct number	*r;
11697d0b3229Schristos 	bool		neg;
11707d0b3229Schristos 	u_int		rscale;
11717d0b3229Schristos 
11727d0b3229Schristos 	p = pop_number();
11737d0b3229Schristos 	if (p == NULL)
11747d0b3229Schristos 		return;
11757d0b3229Schristos 	a = pop_number();
11767d0b3229Schristos 	if (a == NULL) {
11777d0b3229Schristos 		push_number(p);
11787d0b3229Schristos 		return;
11797d0b3229Schristos 	}
11807d0b3229Schristos 
11817d0b3229Schristos 	if (p->scale != 0) {
11827d0b3229Schristos 		BIGNUM *i, *f;
11837d0b3229Schristos 		i = BN_new();
11847d0b3229Schristos 		bn_checkp(i);
11857d0b3229Schristos 		f = BN_new();
11867d0b3229Schristos 		bn_checkp(f);
11877d0b3229Schristos 		split_number(p, i, f);
11887d0b3229Schristos 		if (!BN_is_zero(f))
11897d0b3229Schristos 			warnx("Runtime warning: non-zero fractional part in exponent");
11907d0b3229Schristos 		BN_free(i);
11917d0b3229Schristos 		BN_free(f);
11927d0b3229Schristos 	}
11937d0b3229Schristos 
11947d0b3229Schristos 	normalize(p, 0);
11957d0b3229Schristos 
11967d0b3229Schristos 	neg = false;
11977d0b3229Schristos 	if (BN_is_negative(p->number)) {
11987d0b3229Schristos 		neg = true;
11997d0b3229Schristos 		negate(p);
12007d0b3229Schristos 		rscale = bmachine.scale;
12017d0b3229Schristos 	} else {
12027d0b3229Schristos 		/* Posix bc says min(a.scale * b, max(a.scale, scale) */
12037d0b3229Schristos 		u_long	b;
12047d0b3229Schristos 		u_int	m;
12057d0b3229Schristos 
12067d0b3229Schristos 		b = BN_get_word(p->number);
12077d0b3229Schristos 		m = max(a->scale, bmachine.scale);
12087d0b3229Schristos 		rscale = a->scale * (u_int)b;
1209fa34604aSchristos 		if (rscale > m || (a->scale > 0 && (b == NO_NUMBER ||
12107d0b3229Schristos 		    b > UINT_MAX)))
12117d0b3229Schristos 			rscale = m;
12127d0b3229Schristos 	}
12137d0b3229Schristos 
12147d0b3229Schristos 	if (BN_is_zero(p->number)) {
12157d0b3229Schristos 		r = new_number();
12167d0b3229Schristos 		bn_check(BN_one(r->number));
12177d0b3229Schristos 		normalize(r, rscale);
12187d0b3229Schristos 	} else {
12197d0b3229Schristos 		u_int ascale, mscale;
12207d0b3229Schristos 
12217d0b3229Schristos 		ascale = a->scale;
12227d0b3229Schristos 		while (!BN_is_bit_set(p->number, 0)) {
12237d0b3229Schristos 			ascale *= 2;
12247d0b3229Schristos 			bmul_number(a, a, a, ascale);
12257d0b3229Schristos 			bn_check(BN_rshift1(p->number, p->number));
12267d0b3229Schristos 		}
12277d0b3229Schristos 
12287d0b3229Schristos 		r = dup_number(a);
12297d0b3229Schristos 		bn_check(BN_rshift1(p->number, p->number));
12307d0b3229Schristos 
12317d0b3229Schristos 		mscale = ascale;
12327d0b3229Schristos 		while (!BN_is_zero(p->number)) {
12337d0b3229Schristos 			ascale *= 2;
12347d0b3229Schristos 			bmul_number(a, a, a, ascale);
12357d0b3229Schristos 			if (BN_is_bit_set(p->number, 0)) {
12367d0b3229Schristos 				mscale += ascale;
12377d0b3229Schristos 				bmul_number(r, r, a, mscale);
12387d0b3229Schristos 			}
12397d0b3229Schristos 			bn_check(BN_rshift1(p->number, p->number));
12407d0b3229Schristos 		}
12417d0b3229Schristos 
12427d0b3229Schristos 		if (neg) {
12437d0b3229Schristos 			BN_CTX	*ctx;
12447d0b3229Schristos 			BIGNUM	*one;
12457d0b3229Schristos 
12467d0b3229Schristos 			one = BN_new();
12477d0b3229Schristos 			bn_checkp(one);
12487d0b3229Schristos 			bn_check(BN_one(one));
12497d0b3229Schristos 			ctx = BN_CTX_new();
12507d0b3229Schristos 			bn_checkp(ctx);
1251fc8ee2f5Schristos 			scale_number(one, (int)(r->scale + rscale));
12527d0b3229Schristos 
12537d0b3229Schristos 			if (BN_is_zero(r->number))
12547d0b3229Schristos 				warnx("divide by zero");
12557d0b3229Schristos 			else
12567d0b3229Schristos 				bn_check(BN_div(r->number, NULL, one,
12577d0b3229Schristos 				    r->number, ctx));
12587d0b3229Schristos 			BN_free(one);
12597d0b3229Schristos 			BN_CTX_free(ctx);
12607d0b3229Schristos 			r->scale = rscale;
12617d0b3229Schristos 		} else
12627d0b3229Schristos 			normalize(r, rscale);
12637d0b3229Schristos 	}
12647d0b3229Schristos 	push_number(r);
12657d0b3229Schristos 	free_number(a);
12667d0b3229Schristos 	free_number(p);
12677d0b3229Schristos }
12687d0b3229Schristos 
12697d0b3229Schristos static bool
bsqrt_stop(const BIGNUM * x,const BIGNUM * y,u_int * onecount)12707d0b3229Schristos bsqrt_stop(const BIGNUM *x, const BIGNUM *y, u_int *onecount)
12717d0b3229Schristos {
12727d0b3229Schristos 	BIGNUM *r;
12737d0b3229Schristos 	bool ret;
12747d0b3229Schristos 
12757d0b3229Schristos 	r = BN_new();
12767d0b3229Schristos 	bn_checkp(r);
12777d0b3229Schristos 	bn_check(BN_sub(r, x, y));
12787d0b3229Schristos 	if (BN_is_one(r))
12797d0b3229Schristos 		(*onecount)++;
12807d0b3229Schristos 	ret = BN_is_zero(r);
12817d0b3229Schristos 	BN_free(r);
12827d0b3229Schristos 	return ret || *onecount > 1;
12837d0b3229Schristos }
12847d0b3229Schristos 
12857d0b3229Schristos static void
bsqrt(void)12867d0b3229Schristos bsqrt(void)
12877d0b3229Schristos {
12887d0b3229Schristos 	struct number	*n;
12897d0b3229Schristos 	struct number	*r;
12907d0b3229Schristos 	BIGNUM		*x, *y;
12917d0b3229Schristos 	u_int		scale, onecount;
12927d0b3229Schristos 	BN_CTX		*ctx;
12937d0b3229Schristos 
12947d0b3229Schristos 	onecount = 0;
12957d0b3229Schristos 	n = pop_number();
12967d0b3229Schristos 	if (n == NULL)
12977d0b3229Schristos 		return;
12987d0b3229Schristos 	if (BN_is_zero(n->number)) {
12997d0b3229Schristos 		r = new_number();
13007d0b3229Schristos 		push_number(r);
13017d0b3229Schristos 	} else if (BN_is_negative(n->number))
13027d0b3229Schristos 		warnx("square root of negative number");
13037d0b3229Schristos 	else {
13047d0b3229Schristos 		scale = max(bmachine.scale, n->scale);
13057d0b3229Schristos 		normalize(n, 2*scale);
13067d0b3229Schristos 		x = BN_dup(n->number);
13077d0b3229Schristos 		bn_checkp(x);
13087d0b3229Schristos 		bn_check(BN_rshift(x, x, BN_num_bits(x)/2));
13097d0b3229Schristos 		y = BN_new();
13107d0b3229Schristos 		bn_checkp(y);
13117d0b3229Schristos 		ctx = BN_CTX_new();
13127d0b3229Schristos 		bn_checkp(ctx);
13137d0b3229Schristos 		for (;;) {
13147d0b3229Schristos 			bn_checkp(BN_copy(y, x));
13157d0b3229Schristos 			bn_check(BN_div(x, NULL, n->number, x, ctx));
13167d0b3229Schristos 			bn_check(BN_add(x, x, y));
13177d0b3229Schristos 			bn_check(BN_rshift1(x, x));
13187d0b3229Schristos 			if (bsqrt_stop(x, y, &onecount))
13197d0b3229Schristos 				break;
13207d0b3229Schristos 		}
13217d0b3229Schristos 		r = bmalloc(sizeof(*r));
13227d0b3229Schristos 		r->scale = scale;
13237d0b3229Schristos 		r->number = y;
13247d0b3229Schristos 		BN_free(x);
13257d0b3229Schristos 		BN_CTX_free(ctx);
13267d0b3229Schristos 		push_number(r);
13277d0b3229Schristos 	}
13287d0b3229Schristos 
13297d0b3229Schristos 	free_number(n);
13307d0b3229Schristos }
13317d0b3229Schristos 
13327d0b3229Schristos static void
not(void)13337d0b3229Schristos not(void)
13347d0b3229Schristos {
13357d0b3229Schristos 	struct number	*a;
13367d0b3229Schristos 
13377d0b3229Schristos 	a = pop_number();
13387d0b3229Schristos 	if (a == NULL)
13397d0b3229Schristos 		return;
13407d0b3229Schristos 	a->scale = 0;
13417d0b3229Schristos 	bn_check(BN_set_word(a->number, BN_get_word(a->number) ? 0 : 1));
13427d0b3229Schristos 	push_number(a);
13437d0b3229Schristos }
13447d0b3229Schristos 
13457d0b3229Schristos static void
equal(void)13467d0b3229Schristos equal(void)
13477d0b3229Schristos {
13487d0b3229Schristos 	compare(BCODE_EQUAL);
13497d0b3229Schristos }
13507d0b3229Schristos 
13517d0b3229Schristos static void
equal_numbers(void)13527d0b3229Schristos equal_numbers(void)
13537d0b3229Schristos {
13547d0b3229Schristos 	struct number *a, *b, *r;
13557d0b3229Schristos 
13567d0b3229Schristos 	a = pop_number();
13577d0b3229Schristos 	if (a == NULL)
13587d0b3229Schristos 		return;
13597d0b3229Schristos 	b = pop_number();
13607d0b3229Schristos 	if (b == NULL) {
13617d0b3229Schristos 		push_number(a);
13627d0b3229Schristos 		return;
13637d0b3229Schristos 	}
13647d0b3229Schristos 	r = new_number();
13657d0b3229Schristos 	bn_check(BN_set_word(r->number,
13667d0b3229Schristos 	    compare_numbers(BCODE_EQUAL, a, b) ? 1 : 0));
13677d0b3229Schristos 	push_number(r);
13687d0b3229Schristos }
13697d0b3229Schristos 
13707d0b3229Schristos static void
less_numbers(void)13717d0b3229Schristos less_numbers(void)
13727d0b3229Schristos {
13737d0b3229Schristos 	struct number *a, *b, *r;
13747d0b3229Schristos 
13757d0b3229Schristos 	a = pop_number();
13767d0b3229Schristos 	if (a == NULL)
13777d0b3229Schristos 		return;
13787d0b3229Schristos 	b = pop_number();
13797d0b3229Schristos 	if (b == NULL) {
13807d0b3229Schristos 		push_number(a);
13817d0b3229Schristos 		return;
13827d0b3229Schristos 	}
13837d0b3229Schristos 	r = new_number();
13847d0b3229Schristos 	bn_check(BN_set_word(r->number,
13857d0b3229Schristos 	    compare_numbers(BCODE_LESS, a, b) ? 1 : 0));
13867d0b3229Schristos 	push_number(r);
13877d0b3229Schristos }
13887d0b3229Schristos 
13897d0b3229Schristos static void
lesseq_numbers(void)13907d0b3229Schristos lesseq_numbers(void)
13917d0b3229Schristos {
13927d0b3229Schristos 	struct number *a, *b, *r;
13937d0b3229Schristos 
13947d0b3229Schristos 	a = pop_number();
13957d0b3229Schristos 	if (a == NULL)
13967d0b3229Schristos 		return;
13977d0b3229Schristos 	b = pop_number();
13987d0b3229Schristos 	if (b == NULL) {
13997d0b3229Schristos 		push_number(a);
14007d0b3229Schristos 		return;
14017d0b3229Schristos 	}
14027d0b3229Schristos 	r = new_number();
14037d0b3229Schristos 	bn_check(BN_set_word(r->number,
14047d0b3229Schristos 	    compare_numbers(BCODE_NOT_GREATER, a, b) ? 1 : 0));
14057d0b3229Schristos 	push_number(r);
14067d0b3229Schristos }
14077d0b3229Schristos 
14087d0b3229Schristos static void
not_equal(void)14097d0b3229Schristos not_equal(void)
14107d0b3229Schristos {
14117d0b3229Schristos 	compare(BCODE_NOT_EQUAL);
14127d0b3229Schristos }
14137d0b3229Schristos 
14147d0b3229Schristos static void
less(void)14157d0b3229Schristos less(void)
14167d0b3229Schristos {
14177d0b3229Schristos 	compare(BCODE_LESS);
14187d0b3229Schristos }
14197d0b3229Schristos 
14207d0b3229Schristos static void
not_compare(void)14217d0b3229Schristos not_compare(void)
14227d0b3229Schristos {
14237d0b3229Schristos 	switch (readch()) {
14247d0b3229Schristos 	case '<':
14257d0b3229Schristos 		not_less();
14267d0b3229Schristos 		break;
14277d0b3229Schristos 	case '>':
14287d0b3229Schristos 		not_greater();
14297d0b3229Schristos 		break;
14307d0b3229Schristos 	case '=':
14317d0b3229Schristos 		not_equal();
14327d0b3229Schristos 		break;
14337d0b3229Schristos 	default:
14347d0b3229Schristos 		unreadch();
14357d0b3229Schristos 		(void)fprintf(stderr, "! command is deprecated\n");
14367d0b3229Schristos 		break;
14377d0b3229Schristos 	}
14387d0b3229Schristos }
14397d0b3229Schristos 
14407d0b3229Schristos static void
not_less(void)14417d0b3229Schristos not_less(void)
14427d0b3229Schristos {
14437d0b3229Schristos 	compare(BCODE_NOT_LESS);
14447d0b3229Schristos }
14457d0b3229Schristos 
14467d0b3229Schristos static void
greater(void)14477d0b3229Schristos greater(void)
14487d0b3229Schristos {
14497d0b3229Schristos 	compare(BCODE_GREATER);
14507d0b3229Schristos }
14517d0b3229Schristos 
14527d0b3229Schristos static void
not_greater(void)14537d0b3229Schristos not_greater(void)
14547d0b3229Schristos {
14557d0b3229Schristos 	compare(BCODE_NOT_GREATER);
14567d0b3229Schristos }
14577d0b3229Schristos 
14587d0b3229Schristos static bool
compare_numbers(enum bcode_compare type,struct number * a,struct number * b)14597d0b3229Schristos compare_numbers(enum bcode_compare type, struct number *a, struct number *b)
14607d0b3229Schristos {
14617d0b3229Schristos 	u_int	scale;
14627d0b3229Schristos 	int	cmp;
14637d0b3229Schristos 
14647d0b3229Schristos 	scale = max(a->scale, b->scale);
14657d0b3229Schristos 
14667d0b3229Schristos 	if (scale > a->scale)
14677d0b3229Schristos 		normalize(a, scale);
14687d0b3229Schristos 	else if (scale > b->scale)
14697d0b3229Schristos 		normalize(b, scale);
14707d0b3229Schristos 
14717d0b3229Schristos 	cmp = BN_cmp(a->number, b->number);
14727d0b3229Schristos 
14737d0b3229Schristos 	free_number(a);
14747d0b3229Schristos 	free_number(b);
14757d0b3229Schristos 
14767d0b3229Schristos 	switch (type) {
14777d0b3229Schristos 	case BCODE_EQUAL:
14787d0b3229Schristos 		return cmp == 0;
14797d0b3229Schristos 	case BCODE_NOT_EQUAL:
14807d0b3229Schristos 		return cmp != 0;
14817d0b3229Schristos 	case BCODE_LESS:
14827d0b3229Schristos 		return cmp < 0;
14837d0b3229Schristos 	case BCODE_NOT_LESS:
14847d0b3229Schristos 		return cmp >= 0;
14857d0b3229Schristos 	case BCODE_GREATER:
14867d0b3229Schristos 		return cmp > 0;
14877d0b3229Schristos 	case BCODE_NOT_GREATER:
14887d0b3229Schristos 		return cmp <= 0;
14897d0b3229Schristos 	}
14907d0b3229Schristos 	return false;
14917d0b3229Schristos }
14927d0b3229Schristos 
14937d0b3229Schristos static void
compare(enum bcode_compare type)14947d0b3229Schristos compare(enum bcode_compare type)
14957d0b3229Schristos {
14967d0b3229Schristos 	int		idx, elseidx;
14977d0b3229Schristos 	struct number	*a, *b;
14987d0b3229Schristos 	bool		ok;
14997d0b3229Schristos 	struct value	*v;
15007d0b3229Schristos 
15017d0b3229Schristos 	elseidx = NO_ELSE;
15027d0b3229Schristos 	idx = readreg();
15037d0b3229Schristos 	if (readch() == 'e')
15047d0b3229Schristos 		elseidx = readreg();
15057d0b3229Schristos 	else
15067d0b3229Schristos 		unreadch();
15077d0b3229Schristos 
15087d0b3229Schristos 	a = pop_number();
15097d0b3229Schristos 	if (a == NULL)
15107d0b3229Schristos 		return;
15117d0b3229Schristos 	b = pop_number();
15127d0b3229Schristos 	if (b == NULL) {
15137d0b3229Schristos 		push_number(a);
15147d0b3229Schristos 		return;
15157d0b3229Schristos 	}
15167d0b3229Schristos 
15177d0b3229Schristos 	ok = compare_numbers(type, a, b);
15187d0b3229Schristos 
15197d0b3229Schristos 	if (!ok && elseidx != NO_ELSE)
15207d0b3229Schristos 		idx = elseidx;
15217d0b3229Schristos 
15227d0b3229Schristos 	if (idx >= 0 && (ok || (!ok && elseidx != NO_ELSE))) {
15237d0b3229Schristos 		v = stack_tos(&bmachine.reg[idx]);
15247d0b3229Schristos 		if (v == NULL)
15257d0b3229Schristos 			warnx("register '%c' (0%o) is empty", idx, idx);
15267d0b3229Schristos 		else {
15277d0b3229Schristos 			switch(v->type) {
15287d0b3229Schristos 			case BCODE_NONE:
15297d0b3229Schristos 				warnx("register '%c' (0%o) is empty", idx, idx);
15307d0b3229Schristos 				break;
15317d0b3229Schristos 			case BCODE_NUMBER:
15327d0b3229Schristos 				warn("eval called with non-string argument");
15337d0b3229Schristos 				break;
15347d0b3229Schristos 			case BCODE_STRING:
15357d0b3229Schristos 				eval_string(bstrdup(v->u.string));
15367d0b3229Schristos 				break;
15377d0b3229Schristos 			}
15387d0b3229Schristos 		}
15397d0b3229Schristos 	}
15407d0b3229Schristos }
15417d0b3229Schristos 
15427d0b3229Schristos 
15437d0b3229Schristos static void
nop(void)15447d0b3229Schristos nop(void)
15457d0b3229Schristos {
15467d0b3229Schristos }
15477d0b3229Schristos 
15487d0b3229Schristos static void
quit(void)15497d0b3229Schristos quit(void)
15507d0b3229Schristos {
15517d0b3229Schristos 	if (bmachine.readsp < 2)
15527d0b3229Schristos 		exit(0);
15537d0b3229Schristos 	src_free();
15547d0b3229Schristos 	bmachine.readsp--;
15557d0b3229Schristos 	src_free();
15567d0b3229Schristos 	bmachine.readsp--;
15577d0b3229Schristos }
15587d0b3229Schristos 
15597d0b3229Schristos static void
quitN(void)15607d0b3229Schristos quitN(void)
15617d0b3229Schristos {
15627d0b3229Schristos 	struct number	*n;
15637d0b3229Schristos 	u_long		i;
15647d0b3229Schristos 
15657d0b3229Schristos 	n = pop_number();
15667d0b3229Schristos 	if (n == NULL)
15677d0b3229Schristos 		return;
15687d0b3229Schristos 	i = get_ulong(n);
15697d0b3229Schristos 	free_number(n);
1570fa34604aSchristos 	if (i == NO_NUMBER || i == 0)
15717d0b3229Schristos 		warnx("Q command requires a number >= 1");
15727d0b3229Schristos 	else if (bmachine.readsp < i)
15737d0b3229Schristos 		warnx("Q command argument exceeded string execution depth");
15747d0b3229Schristos 	else {
15757d0b3229Schristos 		while (i-- > 0) {
15767d0b3229Schristos 			src_free();
15777d0b3229Schristos 			bmachine.readsp--;
15787d0b3229Schristos 		}
15797d0b3229Schristos 	}
15807d0b3229Schristos }
15817d0b3229Schristos 
15827d0b3229Schristos static void
skipN(void)15837d0b3229Schristos skipN(void)
15847d0b3229Schristos {
15857d0b3229Schristos 	struct number	*n;
15867d0b3229Schristos 	u_long		i;
15877d0b3229Schristos 
15887d0b3229Schristos 	n = pop_number();
15897d0b3229Schristos 	if (n == NULL)
15907d0b3229Schristos 		return;
15917d0b3229Schristos 	i = get_ulong(n);
1592fa34604aSchristos 	if (i == NO_NUMBER)
15937d0b3229Schristos 		warnx("J command requires a number >= 0");
15947d0b3229Schristos 	else if (i > 0 && bmachine.readsp < i)
15957d0b3229Schristos 		warnx("J command argument exceeded string execution depth");
15967d0b3229Schristos 	else {
15977d0b3229Schristos 		while (i-- > 0) {
15987d0b3229Schristos 			src_free();
15997d0b3229Schristos 			bmachine.readsp--;
16007d0b3229Schristos 		}
16017d0b3229Schristos 		skip_until_mark();
16027d0b3229Schristos 	}
16037d0b3229Schristos }
16047d0b3229Schristos 
16057d0b3229Schristos static void
skip_until_mark(void)16067d0b3229Schristos skip_until_mark(void)
16077d0b3229Schristos {
16087d0b3229Schristos 	int ch;
16097d0b3229Schristos 
16107d0b3229Schristos 	for (;;) {
16117d0b3229Schristos 		ch = readch();
16127d0b3229Schristos 		switch (ch) {
16137d0b3229Schristos 		case 'M':
16147d0b3229Schristos 			return;
16157d0b3229Schristos 		case EOF:
16167d0b3229Schristos 			errx(1, "mark not found");
16177d0b3229Schristos 			return;
16187d0b3229Schristos 		case 'l':
16197d0b3229Schristos 		case 'L':
16207d0b3229Schristos 		case 's':
16217d0b3229Schristos 		case 'S':
16227d0b3229Schristos 		case ':':
16237d0b3229Schristos 		case ';':
16247d0b3229Schristos 		case '<':
16257d0b3229Schristos 		case '>':
16267d0b3229Schristos 		case '=':
16277d0b3229Schristos 			(void)readreg();
16287d0b3229Schristos 			if (readch() == 'e')
16297d0b3229Schristos 				(void)readreg();
16307d0b3229Schristos 			else
16317d0b3229Schristos 				unreadch();
16327d0b3229Schristos 			break;
16337d0b3229Schristos 		case '[':
16347d0b3229Schristos 			free(read_string(&bmachine.readstack[bmachine.readsp]));
16357d0b3229Schristos 			break;
16367d0b3229Schristos 		case '!':
16377d0b3229Schristos 			switch (ch = readch()) {
16387d0b3229Schristos 				case '<':
16397d0b3229Schristos 				case '>':
16407d0b3229Schristos 				case '=':
16417d0b3229Schristos 					(void)readreg();
16427d0b3229Schristos 					if (readch() == 'e')
16437d0b3229Schristos 						(void)readreg();
16447d0b3229Schristos 					else
16457d0b3229Schristos 						unreadch();
16467d0b3229Schristos 					break;
16477d0b3229Schristos 				default:
16487d0b3229Schristos 					free(readline());
16497d0b3229Schristos 					break;
16507d0b3229Schristos 			}
16517d0b3229Schristos 			break;
16527d0b3229Schristos 		default:
16537d0b3229Schristos 			break;
16547d0b3229Schristos 		}
16557d0b3229Schristos 	}
16567d0b3229Schristos }
16577d0b3229Schristos 
16587d0b3229Schristos static void
parse_number(void)16597d0b3229Schristos parse_number(void)
16607d0b3229Schristos {
16617d0b3229Schristos 	unreadch();
16627d0b3229Schristos 	push_number(readnumber(&bmachine.readstack[bmachine.readsp],
16637d0b3229Schristos 	    bmachine.ibase));
16647d0b3229Schristos }
16657d0b3229Schristos 
16667d0b3229Schristos static void
unknown(void)16677d0b3229Schristos unknown(void)
16687d0b3229Schristos {
16697d0b3229Schristos 	int ch = bmachine.readstack[bmachine.readsp].lastchar;
16707d0b3229Schristos 	warnx("%c (0%o) is unimplemented", ch, ch);
16717d0b3229Schristos }
16727d0b3229Schristos 
16737d0b3229Schristos static void
eval_string(char * p)16747d0b3229Schristos eval_string(char *p)
16757d0b3229Schristos {
16767d0b3229Schristos 	int ch;
16777d0b3229Schristos 
16787d0b3229Schristos 	if (bmachine.readsp > 0) {
16797d0b3229Schristos 		/* Check for tail call. Do not recurse in that case. */
16807d0b3229Schristos 		ch = readch();
16817d0b3229Schristos 		if (ch == EOF) {
16827d0b3229Schristos 			src_free();
16837d0b3229Schristos 			src_setstring(&bmachine.readstack[bmachine.readsp], p);
16847d0b3229Schristos 			return;
16857d0b3229Schristos 		} else
16867d0b3229Schristos 			unreadch();
16877d0b3229Schristos 	}
16887d0b3229Schristos 	if (bmachine.readsp == bmachine.readstack_sz - 1) {
16897d0b3229Schristos 		size_t newsz = bmachine.readstack_sz * 2;
1690fc8ee2f5Schristos 		struct source *stack = bmachine.readstack;
1691fc8ee2f5Schristos 		int ret = reallocarr(&stack, newsz, sizeof(struct source));
1692fc8ee2f5Schristos 		if (ret)
1693fc8ee2f5Schristos 			errc(1, ret, "recursion too deep");
16947d0b3229Schristos 		bmachine.readstack_sz = newsz;
16957d0b3229Schristos 		bmachine.readstack = stack;
16967d0b3229Schristos 	}
16977d0b3229Schristos 	src_setstring(&bmachine.readstack[++bmachine.readsp], p);
16987d0b3229Schristos }
16997d0b3229Schristos 
17007d0b3229Schristos static void
eval_line(void)17017d0b3229Schristos eval_line(void)
17027d0b3229Schristos {
17037d0b3229Schristos 	/* Always read from stdin */
17047d0b3229Schristos 	struct source	in;
17057d0b3229Schristos 	char		*p;
17067d0b3229Schristos 
17077d0b3229Schristos 	clearerr(stdin);
17087d0b3229Schristos 	src_setstream(&in, stdin);
17097d0b3229Schristos 	p = (*in.vtable->readline)(&in);
17107d0b3229Schristos 	eval_string(p);
17117d0b3229Schristos }
17127d0b3229Schristos 
17137d0b3229Schristos static void
eval_tos(void)17147d0b3229Schristos eval_tos(void)
17157d0b3229Schristos {
17167d0b3229Schristos 	char *p;
17177d0b3229Schristos 
17187d0b3229Schristos 	p = pop_string();
17197d0b3229Schristos 	if (p != NULL)
17207d0b3229Schristos 		eval_string(p);
17217d0b3229Schristos }
17227d0b3229Schristos 
17237d0b3229Schristos void
eval(void)17247d0b3229Schristos eval(void)
17257d0b3229Schristos {
17267d0b3229Schristos 	int	ch;
17277d0b3229Schristos 
17287d0b3229Schristos 	for (;;) {
17297d0b3229Schristos 		ch = readch();
17307d0b3229Schristos 		if (ch == EOF) {
17317d0b3229Schristos 			if (bmachine.readsp == 0)
17327d0b3229Schristos 				return;
17337d0b3229Schristos 			src_free();
17347d0b3229Schristos 			bmachine.readsp--;
17357d0b3229Schristos 			continue;
17367d0b3229Schristos 		}
17377d0b3229Schristos 		if (bmachine.interrupted) {
17387d0b3229Schristos 			if (bmachine.readsp > 0) {
17397d0b3229Schristos 				src_free();
17407d0b3229Schristos 				bmachine.readsp--;
17417d0b3229Schristos 				continue;
17427d0b3229Schristos 			} else
17437d0b3229Schristos 				bmachine.interrupted = false;
17447d0b3229Schristos 		}
17457d0b3229Schristos #ifdef DEBUGGING
17467d0b3229Schristos 		(void)fprintf(stderr, "# %c\n", ch);
17477d0b3229Schristos 		stack_print(stderr, &bmachine.stack, "* ",
17487d0b3229Schristos 		    bmachine.obase);
17497d0b3229Schristos 		(void)fprintf(stderr, "%zd =>\n", bmachine.readsp);
17507d0b3229Schristos #endif
17517d0b3229Schristos 
17527d0b3229Schristos 		if (0 <= ch && ch < UCHAR_MAX)
17537d0b3229Schristos 			(*jump_table[ch])();
17547d0b3229Schristos 		else
17557d0b3229Schristos 			warnx("internal error: opcode %d", ch);
17567d0b3229Schristos 
17577d0b3229Schristos #ifdef DEBUGGING
17587d0b3229Schristos 		stack_print(stderr, &bmachine.stack, "* ",
17597d0b3229Schristos 		    bmachine.obase);
17607d0b3229Schristos 		(void)fprintf(stderr, "%zd ==\n", bmachine.readsp);
17617d0b3229Schristos #endif
17627d0b3229Schristos 	}
17637d0b3229Schristos }
1764