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