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