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, ©));
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, ©));
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