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