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