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