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