bcode.c revision 203438
1202719Sgabor/* $OpenBSD: bcode.c,v 1.40 2009/10/27 23:59:37 deraadt Exp $ */ 2202719Sgabor 3202719Sgabor/* 4202719Sgabor * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net> 5202719Sgabor * 6202719Sgabor * Permission to use, copy, modify, and distribute this software for any 7202719Sgabor * purpose with or without fee is hereby granted, provided that the above 8202719Sgabor * copyright notice and this permission notice appear in all copies. 9202719Sgabor * 10202719Sgabor * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11202719Sgabor * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12202719Sgabor * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13202719Sgabor * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14202719Sgabor * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15202719Sgabor * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16202719Sgabor * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17202719Sgabor */ 18202719Sgabor 19202719Sgabor#include <sys/cdefs.h> 20202719Sgabor__FBSDID("$FreeBSD: head/usr.bin/dc/bcode.c 203438 2010-02-03 19:13:41Z gabor $"); 21202719Sgabor 22202719Sgabor#include <err.h> 23202719Sgabor#include <limits.h> 24202719Sgabor#include <openssl/ssl.h> 25202719Sgabor#include <signal.h> 26202719Sgabor#include <stdio.h> 27202719Sgabor#include <stdlib.h> 28202719Sgabor#include <string.h> 29202719Sgabor 30202719Sgabor#include "extern.h" 31202719Sgabor 32202719SgaborBIGNUM zero; 33202719Sgabor 34202719Sgabor#define __inline 35202719Sgabor 36202719Sgabor#define MAX_ARRAY_INDEX 2048 37202719Sgabor#define READSTACK_SIZE 8 38202719Sgabor 39202719Sgabor#define NO_ELSE -2 /* -1 is EOF */ 40202719Sgabor#define REG_ARRAY_SIZE_SMALL (UCHAR_MAX + 1) 41202719Sgabor#define REG_ARRAY_SIZE_BIG (UCHAR_MAX + 1 + USHRT_MAX + 1) 42202719Sgabor 43202719Sgaborstruct bmachine { 44202719Sgabor struct stack stack; 45202719Sgabor u_int scale; 46202719Sgabor u_int obase; 47202719Sgabor u_int ibase; 48202719Sgabor size_t readsp; 49202719Sgabor bool extended_regs; 50202719Sgabor size_t reg_array_size; 51202719Sgabor struct stack *reg; 52202719Sgabor volatile sig_atomic_t interrupted; 53202719Sgabor struct source *readstack; 54202719Sgabor size_t readstack_sz; 55202719Sgabor}; 56202719Sgabor 57202719Sgaborstatic struct bmachine bmachine; 58202719Sgaborstatic void sighandler(int); 59202719Sgabor 60202719Sgaborstatic __inline int readch(void); 61202719Sgaborstatic __inline void unreadch(void); 62202719Sgaborstatic __inline char *readline(void); 63202719Sgaborstatic __inline void src_free(void); 64202719Sgabor 65202719Sgaborstatic __inline u_int max(u_int, u_int); 66202719Sgaborstatic u_long get_ulong(struct number *); 67202719Sgabor 68202719Sgaborstatic __inline void push_number(struct number *); 69202719Sgaborstatic __inline void push_string(char *); 70202719Sgaborstatic __inline void push(struct value *); 71202719Sgaborstatic __inline struct value *tos(void); 72202719Sgaborstatic __inline struct number *pop_number(void); 73202719Sgaborstatic __inline char *pop_string(void); 74202719Sgaborstatic __inline void clear_stack(void); 75202719Sgaborstatic __inline void print_tos(void); 76202719Sgaborstatic void pop_print(void); 77202719Sgaborstatic void pop_printn(void); 78202719Sgaborstatic __inline void print_stack(void); 79202719Sgaborstatic __inline void dup(void); 80202719Sgaborstatic void swap(void); 81202719Sgaborstatic void drop(void); 82202719Sgabor 83202719Sgaborstatic void get_scale(void); 84202719Sgaborstatic void set_scale(void); 85202719Sgaborstatic void get_obase(void); 86202719Sgaborstatic void set_obase(void); 87202719Sgaborstatic void get_ibase(void); 88202719Sgaborstatic void set_ibase(void); 89202719Sgaborstatic void stackdepth(void); 90202719Sgaborstatic void push_scale(void); 91202719Sgaborstatic u_int count_digits(const struct number *); 92202719Sgaborstatic void num_digits(void); 93202719Sgaborstatic void to_ascii(void); 94202719Sgaborstatic void push_line(void); 95202719Sgaborstatic void comment(void); 96202719Sgaborstatic void bexec(char *); 97202719Sgaborstatic void badd(void); 98202719Sgaborstatic void bsub(void); 99202719Sgaborstatic void bmul(void); 100202719Sgaborstatic void bdiv(void); 101202719Sgaborstatic void bmod(void); 102202719Sgaborstatic void bdivmod(void); 103202719Sgaborstatic void bexp(void); 104202719Sgaborstatic bool bsqrt_stop(const BIGNUM *, const BIGNUM *, u_int *); 105202719Sgaborstatic void bsqrt(void); 106202719Sgaborstatic void not(void); 107202719Sgaborstatic void equal_numbers(void); 108202719Sgaborstatic void less_numbers(void); 109202719Sgaborstatic void lesseq_numbers(void); 110202719Sgaborstatic void equal(void); 111202719Sgaborstatic void not_equal(void); 112202719Sgaborstatic void less(void); 113202719Sgaborstatic void not_less(void); 114202719Sgaborstatic void greater(void); 115202719Sgaborstatic void not_greater(void); 116202719Sgaborstatic void not_compare(void); 117202719Sgaborstatic bool compare_numbers(enum bcode_compare, struct number *, 118202719Sgabor struct number *); 119202719Sgaborstatic void compare(enum bcode_compare); 120202719Sgaborstatic int readreg(void); 121202719Sgaborstatic void load(void); 122202719Sgaborstatic void store(void); 123202719Sgaborstatic void load_stack(void); 124202719Sgaborstatic void store_stack(void); 125202719Sgaborstatic void load_array(void); 126202719Sgaborstatic void store_array(void); 127202719Sgaborstatic void nop(void); 128202719Sgaborstatic void quit(void); 129202719Sgaborstatic void quitN(void); 130202719Sgaborstatic void skipN(void); 131202719Sgaborstatic void skip_until_mark(void); 132202719Sgaborstatic void parse_number(void); 133202719Sgaborstatic void unknown(void); 134202719Sgaborstatic void eval_string(char *); 135202719Sgaborstatic void eval_line(void); 136202719Sgaborstatic void eval_tos(void); 137202719Sgabor 138202719Sgabor 139202719Sgabortypedef void (*opcode_function)(void); 140202719Sgabor 141202719Sgaborstruct jump_entry { 142202719Sgabor u_char ch; 143202719Sgabor opcode_function f; 144202719Sgabor}; 145202719Sgabor 146202719Sgaborstatic opcode_function jump_table[UCHAR_MAX]; 147202719Sgabor 148202719Sgaborstatic const struct jump_entry jump_table_data[] = { 149202719Sgabor { ' ', nop }, 150202719Sgabor { '!', not_compare }, 151202719Sgabor { '#', comment }, 152202719Sgabor { '%', bmod }, 153202719Sgabor { '(', less_numbers }, 154202719Sgabor { '*', bmul }, 155202719Sgabor { '+', badd }, 156202719Sgabor { '-', bsub }, 157202719Sgabor { '.', parse_number }, 158202719Sgabor { '/', bdiv }, 159202719Sgabor { '0', parse_number }, 160202719Sgabor { '1', parse_number }, 161202719Sgabor { '2', parse_number }, 162202719Sgabor { '3', parse_number }, 163202719Sgabor { '4', parse_number }, 164202719Sgabor { '5', parse_number }, 165202719Sgabor { '6', parse_number }, 166202719Sgabor { '7', parse_number }, 167202719Sgabor { '8', parse_number }, 168202719Sgabor { '9', parse_number }, 169202719Sgabor { ':', store_array }, 170202719Sgabor { ';', load_array }, 171202719Sgabor { '<', less }, 172202719Sgabor { '=', equal }, 173202719Sgabor { '>', greater }, 174202719Sgabor { '?', eval_line }, 175202719Sgabor { 'A', parse_number }, 176202719Sgabor { 'B', parse_number }, 177202719Sgabor { 'C', parse_number }, 178202719Sgabor { 'D', parse_number }, 179202719Sgabor { 'E', parse_number }, 180202719Sgabor { 'F', parse_number }, 181202719Sgabor { 'G', equal_numbers }, 182202719Sgabor { 'I', get_ibase }, 183202719Sgabor { 'J', skipN }, 184202719Sgabor { 'K', get_scale }, 185202719Sgabor { 'L', load_stack }, 186202719Sgabor { 'M', nop }, 187202719Sgabor { 'N', not }, 188202719Sgabor { 'O', get_obase }, 189202719Sgabor { 'P', pop_print }, 190202719Sgabor { 'Q', quitN }, 191202719Sgabor { 'R', drop }, 192202719Sgabor { 'S', store_stack }, 193202719Sgabor { 'X', push_scale }, 194202719Sgabor { 'Z', num_digits }, 195202719Sgabor { '[', push_line }, 196202719Sgabor { '\f', nop }, 197202719Sgabor { '\n', nop }, 198202719Sgabor { '\r', nop }, 199202719Sgabor { '\t', nop }, 200202719Sgabor { '^', bexp }, 201202719Sgabor { '_', parse_number }, 202202719Sgabor { 'a', to_ascii }, 203202719Sgabor { 'c', clear_stack }, 204202719Sgabor { 'd', dup }, 205202719Sgabor { 'f', print_stack }, 206202719Sgabor { 'i', set_ibase }, 207202719Sgabor { 'k', set_scale }, 208202719Sgabor { 'l', load }, 209202719Sgabor { 'n', pop_printn }, 210202719Sgabor { 'o', set_obase }, 211202719Sgabor { 'p', print_tos }, 212202719Sgabor { 'q', quit }, 213202719Sgabor { 'r', swap }, 214202719Sgabor { 's', store }, 215202719Sgabor { 'v', bsqrt }, 216202719Sgabor { 'x', eval_tos }, 217202719Sgabor { 'z', stackdepth }, 218202719Sgabor { '{', lesseq_numbers }, 219202719Sgabor { '~', bdivmod } 220202719Sgabor}; 221202719Sgabor 222202719Sgabor#define JUMP_TABLE_DATA_SIZE \ 223202719Sgabor (sizeof(jump_table_data)/sizeof(jump_table_data[0])) 224202719Sgabor 225202719Sgaborstatic void 226202719Sgaborsighandler(int ignored) 227202719Sgabor{ 228202719Sgabor 229202719Sgabor switch (ignored) 230202719Sgabor { 231202719Sgabor default: 232202719Sgabor bmachine.interrupted = true; 233202719Sgabor } 234202719Sgabor} 235202719Sgabor 236202719Sgaborvoid 237202719Sgaborinit_bmachine(bool extended_registers) 238202719Sgabor{ 239202719Sgabor unsigned int i; 240202719Sgabor 241202719Sgabor bmachine.extended_regs = extended_registers; 242202719Sgabor bmachine.reg_array_size = bmachine.extended_regs ? 243202719Sgabor REG_ARRAY_SIZE_BIG : REG_ARRAY_SIZE_SMALL; 244202719Sgabor 245202719Sgabor bmachine.reg = calloc(bmachine.reg_array_size, 246202719Sgabor sizeof(bmachine.reg[0])); 247202719Sgabor if (bmachine.reg == NULL) 248202719Sgabor err(1, NULL); 249202719Sgabor 250202719Sgabor for (i = 0; i < UCHAR_MAX; i++) 251202719Sgabor jump_table[i] = unknown; 252202719Sgabor for (i = 0; i < JUMP_TABLE_DATA_SIZE; i++) 253202719Sgabor jump_table[jump_table_data[i].ch] = jump_table_data[i].f; 254202719Sgabor 255202719Sgabor stack_init(&bmachine.stack); 256202719Sgabor 257202719Sgabor for (i = 0; i < bmachine.reg_array_size; i++) 258202719Sgabor stack_init(&bmachine.reg[i]); 259202719Sgabor 260202719Sgabor bmachine.readstack_sz = READSTACK_SIZE; 261202719Sgabor bmachine.readstack = calloc(sizeof(struct source), 262202719Sgabor bmachine.readstack_sz); 263202719Sgabor if (bmachine.readstack == NULL) 264202719Sgabor err(1, NULL); 265202719Sgabor bmachine.obase = bmachine.ibase = 10; 266202719Sgabor BN_init(&zero); 267202719Sgabor bn_check(BN_zero(&zero)); 268202719Sgabor signal(SIGINT, sighandler); 269202719Sgabor} 270202719Sgabor 271202719Sgabor/* Reset the things needed before processing a (new) file */ 272202719Sgaborvoid 273202719Sgaborreset_bmachine(struct source *src) 274202719Sgabor{ 275202719Sgabor 276202719Sgabor bmachine.readsp = 0; 277202719Sgabor bmachine.readstack[0] = *src; 278202719Sgabor} 279202719Sgabor 280202719Sgaborstatic __inline int 281202719Sgaborreadch(void) 282202719Sgabor{ 283202719Sgabor struct source *src = &bmachine.readstack[bmachine.readsp]; 284202719Sgabor 285202719Sgabor return (src->vtable->readchar(src)); 286202719Sgabor} 287202719Sgabor 288202719Sgaborstatic __inline void 289202719Sgaborunreadch(void) 290202719Sgabor{ 291202719Sgabor struct source *src = &bmachine.readstack[bmachine.readsp]; 292202719Sgabor 293202719Sgabor src->vtable->unreadchar(src); 294202719Sgabor} 295202719Sgabor 296202719Sgaborstatic __inline char * 297202719Sgaborreadline(void) 298202719Sgabor{ 299202719Sgabor struct source *src = &bmachine.readstack[bmachine.readsp]; 300202719Sgabor 301202719Sgabor return (src->vtable->readline(src)); 302202719Sgabor} 303202719Sgabor 304202719Sgaborstatic __inline void 305202719Sgaborsrc_free(void) 306202719Sgabor{ 307202719Sgabor struct source *src = &bmachine.readstack[bmachine.readsp]; 308202719Sgabor 309202719Sgabor src->vtable->free(src); 310202719Sgabor} 311202719Sgabor 312202719Sgabor#ifdef DEBUGGING 313202719Sgaborvoid 314202719Sgaborpn(const char *str, const struct number *n) 315202719Sgabor{ 316202719Sgabor char *p = BN_bn2dec(n->number); 317202719Sgabor 318202719Sgabor if (p == NULL) 319202719Sgabor err(1, "BN_bn2dec failed"); 320202719Sgabor fputs(str, stderr); 321202719Sgabor fprintf(stderr, " %s (%u)\n" , p, n->scale); 322202719Sgabor OPENSSL_free(p); 323202719Sgabor} 324202719Sgabor 325202719Sgaborvoid 326202719Sgaborpbn(const char *str, const BIGNUM *n) 327202719Sgabor{ 328202719Sgabor char *p = BN_bn2dec(n); 329202719Sgabor 330202719Sgabor if (p == NULL) 331202719Sgabor err(1, "BN_bn2dec failed"); 332202719Sgabor fputs(str, stderr); 333202719Sgabor fprintf(stderr, " %s\n", p); 334202719Sgabor OPENSSL_free(p); 335202719Sgabor} 336202719Sgabor 337202719Sgabor#endif 338202719Sgabor 339202719Sgaborstatic __inline u_int 340202719Sgabormax(u_int a, u_int b) 341202719Sgabor{ 342202719Sgabor 343202719Sgabor return (a > b ? a : b); 344202719Sgabor} 345202719Sgabor 346202719Sgaborstatic unsigned long factors[] = { 347202719Sgabor 0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 348202719Sgabor 100000000, 1000000000 349202719Sgabor}; 350202719Sgabor 351202719Sgaborvoid 352202719Sgaborscale_number(BIGNUM *n, int s) 353202719Sgabor{ 354202719Sgabor unsigned int abs_scale; 355202719Sgabor 356202719Sgabor if (s == 0) 357202719Sgabor return; 358202719Sgabor 359202719Sgabor abs_scale = s > 0 ? s : -s; 360202719Sgabor 361202719Sgabor if (abs_scale < sizeof(factors)/sizeof(factors[0])) { 362202719Sgabor if (s > 0) 363202719Sgabor bn_check(BN_mul_word(n, factors[abs_scale])); 364202719Sgabor else 365202719Sgabor BN_div_word(n, factors[abs_scale]); 366202719Sgabor } else { 367202719Sgabor BIGNUM *a, *p; 368202719Sgabor BN_CTX *ctx; 369202719Sgabor 370202719Sgabor a = BN_new(); 371202719Sgabor bn_checkp(a); 372202719Sgabor p = BN_new(); 373202719Sgabor bn_checkp(p); 374202719Sgabor ctx = BN_CTX_new(); 375202719Sgabor bn_checkp(ctx); 376202719Sgabor 377202719Sgabor bn_check(BN_set_word(a, 10)); 378202719Sgabor bn_check(BN_set_word(p, abs_scale)); 379202719Sgabor bn_check(BN_exp(a, a, p, ctx)); 380202719Sgabor if (s > 0) 381202719Sgabor bn_check(BN_mul(n, n, a, ctx)); 382202719Sgabor else 383202719Sgabor bn_check(BN_div(n, NULL, n, a, ctx)); 384202719Sgabor BN_CTX_free(ctx); 385202719Sgabor BN_free(a); 386202719Sgabor BN_free(p); 387202719Sgabor } 388202719Sgabor} 389202719Sgabor 390202719Sgaborvoid 391202719Sgaborsplit_number(const struct number *n, BIGNUM *i, BIGNUM *f) 392202719Sgabor{ 393202719Sgabor u_long rem; 394202719Sgabor 395202719Sgabor bn_checkp(BN_copy(i, n->number)); 396202719Sgabor 397202719Sgabor if (n->scale == 0 && f != NULL) 398202719Sgabor bn_check(BN_zero(f)); 399202719Sgabor else if (n->scale < sizeof(factors)/sizeof(factors[0])) { 400202719Sgabor rem = BN_div_word(i, factors[n->scale]); 401202719Sgabor if (f != NULL) 402202719Sgabor bn_check(BN_set_word(f, rem)); 403202719Sgabor } else { 404202719Sgabor BIGNUM *a, *p; 405202719Sgabor BN_CTX *ctx; 406202719Sgabor 407202719Sgabor a = BN_new(); 408202719Sgabor bn_checkp(a); 409202719Sgabor p = BN_new(); 410202719Sgabor bn_checkp(p); 411202719Sgabor ctx = BN_CTX_new(); 412202719Sgabor bn_checkp(ctx); 413202719Sgabor 414202719Sgabor bn_check(BN_set_word(a, 10)); 415202719Sgabor bn_check(BN_set_word(p, n->scale)); 416202719Sgabor bn_check(BN_exp(a, a, p, ctx)); 417202719Sgabor bn_check(BN_div(i, f, n->number, a, ctx)); 418202719Sgabor BN_CTX_free(ctx); 419202719Sgabor BN_free(a); 420202719Sgabor BN_free(p); 421202719Sgabor } 422202719Sgabor} 423202719Sgabor 424202719Sgabor__inline void 425202719Sgabornormalize(struct number *n, u_int s) 426202719Sgabor{ 427202719Sgabor 428202719Sgabor scale_number(n->number, s - n->scale); 429202719Sgabor n->scale = s; 430202719Sgabor} 431202719Sgabor 432202719Sgaborstatic u_long 433202719Sgaborget_ulong(struct number *n) 434202719Sgabor{ 435202719Sgabor 436202719Sgabor normalize(n, 0); 437202719Sgabor return (BN_get_word(n->number)); 438202719Sgabor} 439202719Sgabor 440202719Sgaborvoid 441202719Sgabornegate(struct number *n) 442202719Sgabor{ 443202719Sgabor 444202719Sgabor bn_check(BN_sub(n->number, &zero, n->number)); 445202719Sgabor} 446202719Sgabor 447202719Sgaborstatic __inline void 448202719Sgaborpush_number(struct number *n) 449202719Sgabor{ 450202719Sgabor 451202719Sgabor stack_pushnumber(&bmachine.stack, n); 452202719Sgabor} 453202719Sgabor 454202719Sgaborstatic __inline void 455202719Sgaborpush_string(char *string) 456202719Sgabor{ 457202719Sgabor 458202719Sgabor stack_pushstring(&bmachine.stack, string); 459202719Sgabor} 460202719Sgabor 461202719Sgaborstatic __inline void 462202719Sgaborpush(struct value *v) 463202719Sgabor{ 464202719Sgabor 465202719Sgabor stack_push(&bmachine.stack, v); 466202719Sgabor} 467202719Sgabor 468202719Sgaborstatic __inline struct value * 469202719Sgabortos(void) 470202719Sgabor{ 471202719Sgabor 472202719Sgabor return (stack_tos(&bmachine.stack)); 473202719Sgabor} 474202719Sgabor 475202719Sgaborstatic __inline struct value * 476202719Sgaborpop(void) 477202719Sgabor{ 478202719Sgabor 479202719Sgabor return (stack_pop(&bmachine.stack)); 480202719Sgabor} 481202719Sgabor 482202719Sgaborstatic __inline struct number * 483202719Sgaborpop_number(void) 484202719Sgabor{ 485202719Sgabor 486202719Sgabor return (stack_popnumber(&bmachine.stack)); 487202719Sgabor} 488202719Sgabor 489202719Sgaborstatic __inline char * 490202719Sgaborpop_string(void) 491202719Sgabor{ 492202719Sgabor 493202719Sgabor return (stack_popstring(&bmachine.stack)); 494202719Sgabor} 495202719Sgabor 496202719Sgaborstatic __inline void 497202719Sgaborclear_stack(void) 498202719Sgabor{ 499202719Sgabor 500202719Sgabor stack_clear(&bmachine.stack); 501202719Sgabor} 502202719Sgabor 503202719Sgaborstatic __inline void 504202719Sgaborprint_stack(void) 505202719Sgabor{ 506202719Sgabor 507202719Sgabor stack_print(stdout, &bmachine.stack, "", bmachine.obase); 508202719Sgabor} 509202719Sgabor 510202719Sgaborstatic __inline void 511202719Sgaborprint_tos(void) 512202719Sgabor{ 513202719Sgabor struct value *value = tos(); 514202719Sgabor 515202719Sgabor if (value != NULL) { 516202719Sgabor print_value(stdout, value, "", bmachine.obase); 517202719Sgabor putchar('\n'); 518202719Sgabor } 519202719Sgabor else 520202719Sgabor warnx("stack empty"); 521202719Sgabor} 522202719Sgabor 523202719Sgaborstatic void 524202719Sgaborpop_print(void) 525202719Sgabor{ 526202719Sgabor struct value *value = pop(); 527202719Sgabor 528202719Sgabor if (value != NULL) { 529202719Sgabor switch (value->type) { 530202719Sgabor case BCODE_NONE: 531202719Sgabor break; 532202719Sgabor case BCODE_NUMBER: 533202719Sgabor normalize(value->u.num, 0); 534202719Sgabor print_ascii(stdout, value->u.num); 535202719Sgabor fflush(stdout); 536202719Sgabor break; 537202719Sgabor case BCODE_STRING: 538202719Sgabor fputs(value->u.string, stdout); 539202719Sgabor fflush(stdout); 540202719Sgabor break; 541202719Sgabor } 542202719Sgabor stack_free_value(value); 543202719Sgabor } 544202719Sgabor} 545202719Sgabor 546202719Sgaborstatic void 547202719Sgaborpop_printn(void) 548202719Sgabor{ 549202719Sgabor struct value *value = pop(); 550202719Sgabor 551202719Sgabor if (value != NULL) { 552202719Sgabor print_value(stdout, value, "", bmachine.obase); 553202719Sgabor fflush(stdout); 554202719Sgabor stack_free_value(value); 555202719Sgabor } 556202719Sgabor} 557202719Sgabor 558202719Sgaborstatic __inline void 559202719Sgabordup(void) 560202719Sgabor{ 561202719Sgabor 562202719Sgabor stack_dup(&bmachine.stack); 563202719Sgabor} 564202719Sgabor 565202719Sgaborstatic void 566202719Sgaborswap(void) 567202719Sgabor{ 568202719Sgabor 569202719Sgabor stack_swap(&bmachine.stack); 570202719Sgabor} 571202719Sgabor 572202719Sgaborstatic void 573202719Sgabordrop(void) 574202719Sgabor{ 575202719Sgabor struct value *v = pop(); 576202719Sgabor if (v != NULL) 577202719Sgabor stack_free_value(v); 578202719Sgabor} 579202719Sgabor 580202719Sgaborstatic void 581202719Sgaborget_scale(void) 582202719Sgabor{ 583202719Sgabor struct number *n; 584202719Sgabor 585202719Sgabor n = new_number(); 586202719Sgabor bn_check(BN_set_word(n->number, bmachine.scale)); 587202719Sgabor push_number(n); 588202719Sgabor} 589202719Sgabor 590202719Sgaborstatic void 591202719Sgaborset_scale(void) 592202719Sgabor{ 593202719Sgabor struct number *n; 594202719Sgabor u_long scale; 595202719Sgabor 596202719Sgabor n = pop_number(); 597202719Sgabor if (n != NULL) { 598202719Sgabor if (BN_cmp(n->number, &zero) < 0) 599202719Sgabor warnx("scale must be a nonnegative number"); 600202719Sgabor else { 601202719Sgabor scale = get_ulong(n); 602202719Sgabor if (scale != BN_MASK2 && scale <= UINT_MAX) 603202719Sgabor bmachine.scale = (u_int)scale; 604202719Sgabor else 605202719Sgabor warnx("scale too large"); 606202719Sgabor } 607202719Sgabor free_number(n); 608202719Sgabor } 609202719Sgabor} 610202719Sgabor 611202719Sgaborstatic void 612202719Sgaborget_obase(void) 613202719Sgabor{ 614202719Sgabor struct number *n; 615202719Sgabor 616202719Sgabor n = new_number(); 617202719Sgabor bn_check(BN_set_word(n->number, bmachine.obase)); 618202719Sgabor push_number(n); 619202719Sgabor} 620202719Sgabor 621202719Sgaborstatic void 622202719Sgaborset_obase(void) 623202719Sgabor{ 624202719Sgabor struct number *n; 625202719Sgabor u_long base; 626202719Sgabor 627202719Sgabor n = pop_number(); 628202719Sgabor if (n != NULL) { 629202719Sgabor base = get_ulong(n); 630202719Sgabor if (base != BN_MASK2 && base > 1 && base <= UINT_MAX) 631202719Sgabor bmachine.obase = (u_int)base; 632202719Sgabor else 633202719Sgabor warnx("output base must be a number greater than 1"); 634202719Sgabor free_number(n); 635202719Sgabor } 636202719Sgabor} 637202719Sgabor 638202719Sgaborstatic void 639202719Sgaborget_ibase(void) 640202719Sgabor{ 641202719Sgabor struct number *n; 642202719Sgabor 643202719Sgabor n = new_number(); 644202719Sgabor bn_check(BN_set_word(n->number, bmachine.ibase)); 645202719Sgabor push_number(n); 646202719Sgabor} 647202719Sgabor 648202719Sgaborstatic void 649202719Sgaborset_ibase(void) 650202719Sgabor{ 651202719Sgabor struct number *n; 652202719Sgabor u_long base; 653202719Sgabor 654202719Sgabor n = pop_number(); 655202719Sgabor if (n != NULL) { 656202719Sgabor base = get_ulong(n); 657202719Sgabor if (base != BN_MASK2 && 2 <= base && base <= 16) 658202719Sgabor bmachine.ibase = (u_int)base; 659202719Sgabor else 660202719Sgabor warnx("input base must be a number between 2 and 16 " 661202719Sgabor "(inclusive)"); 662202719Sgabor free_number(n); 663202719Sgabor } 664202719Sgabor} 665202719Sgabor 666202719Sgaborstatic void 667202719Sgaborstackdepth(void) 668202719Sgabor{ 669202719Sgabor size_t i; 670202719Sgabor struct number *n; 671202719Sgabor 672202719Sgabor i = stack_size(&bmachine.stack); 673202719Sgabor n = new_number(); 674202719Sgabor bn_check(BN_set_word(n->number, i)); 675202719Sgabor push_number(n); 676202719Sgabor} 677202719Sgabor 678202719Sgaborstatic void 679202719Sgaborpush_scale(void) 680202719Sgabor{ 681202719Sgabor struct value *value; 682202719Sgabor u_int scale = 0; 683202719Sgabor struct number *n; 684202719Sgabor 685202719Sgabor 686202719Sgabor value = pop(); 687202719Sgabor if (value != NULL) { 688202719Sgabor switch (value->type) { 689202719Sgabor case BCODE_NONE: 690202719Sgabor return; 691202719Sgabor case BCODE_NUMBER: 692202719Sgabor scale = value->u.num->scale; 693202719Sgabor break; 694202719Sgabor case BCODE_STRING: 695202719Sgabor break; 696202719Sgabor } 697202719Sgabor stack_free_value(value); 698202719Sgabor n = new_number(); 699202719Sgabor bn_check(BN_set_word(n->number, scale)); 700202719Sgabor push_number(n); 701202719Sgabor } 702202719Sgabor} 703202719Sgabor 704202719Sgaborstatic u_int 705202719Sgaborcount_digits(const struct number *n) 706202719Sgabor{ 707202719Sgabor struct number *int_part, *fract_part; 708202719Sgabor u_int i; 709202719Sgabor 710202719Sgabor if (BN_is_zero(n->number)) 711202719Sgabor return (1); 712202719Sgabor 713202719Sgabor int_part = new_number(); 714202719Sgabor fract_part = new_number(); 715202719Sgabor fract_part->scale = n->scale; 716202719Sgabor split_number(n, int_part->number, fract_part->number); 717202719Sgabor 718202719Sgabor i = 0; 719202719Sgabor while (!BN_is_zero(int_part->number)) { 720202719Sgabor BN_div_word(int_part->number, 10); 721202719Sgabor i++; 722202719Sgabor } 723202719Sgabor free_number(int_part); 724202719Sgabor free_number(fract_part); 725202719Sgabor return (i + n->scale); 726202719Sgabor} 727202719Sgabor 728202719Sgaborstatic void 729202719Sgabornum_digits(void) 730202719Sgabor{ 731202719Sgabor struct value *value; 732202719Sgabor size_t digits; 733202719Sgabor struct number *n = NULL; 734202719Sgabor 735202719Sgabor value = pop(); 736202719Sgabor if (value != NULL) { 737202719Sgabor switch (value->type) { 738202719Sgabor case BCODE_NONE: 739202719Sgabor return; 740202719Sgabor case BCODE_NUMBER: 741202719Sgabor digits = count_digits(value->u.num); 742202719Sgabor n = new_number(); 743202719Sgabor bn_check(BN_set_word(n->number, digits)); 744202719Sgabor break; 745202719Sgabor case BCODE_STRING: 746202719Sgabor digits = strlen(value->u.string); 747202719Sgabor n = new_number(); 748202719Sgabor bn_check(BN_set_word(n->number, digits)); 749202719Sgabor break; 750202719Sgabor } 751202719Sgabor stack_free_value(value); 752202719Sgabor push_number(n); 753202719Sgabor } 754202719Sgabor} 755202719Sgabor 756202719Sgaborstatic void 757202719Sgaborto_ascii(void) 758202719Sgabor{ 759202719Sgabor char str[2]; 760202719Sgabor struct value *value; 761202719Sgabor struct number *n; 762202719Sgabor 763202719Sgabor value = pop(); 764202719Sgabor if (value != NULL) { 765202719Sgabor str[1] = '\0'; 766202719Sgabor switch (value->type) { 767202719Sgabor case BCODE_NONE: 768202719Sgabor return; 769202719Sgabor case BCODE_NUMBER: 770202719Sgabor n = value->u.num; 771202719Sgabor normalize(n, 0); 772202719Sgabor if (BN_num_bits(n->number) > 8) 773202719Sgabor bn_check(BN_mask_bits(n->number, 8)); 774202719Sgabor str[0] = (char)BN_get_word(n->number); 775202719Sgabor break; 776202719Sgabor case BCODE_STRING: 777202719Sgabor str[0] = value->u.string[0]; 778202719Sgabor break; 779202719Sgabor } 780202719Sgabor stack_free_value(value); 781202719Sgabor push_string(bstrdup(str)); 782202719Sgabor } 783202719Sgabor} 784202719Sgabor 785202719Sgaborstatic int 786202719Sgaborreadreg(void) 787202719Sgabor{ 788202719Sgabor int idx, ch1, ch2; 789202719Sgabor 790202719Sgabor idx = readch(); 791202719Sgabor if (idx == 0xff && bmachine.extended_regs) { 792202719Sgabor ch1 = readch(); 793202719Sgabor ch2 = readch(); 794202719Sgabor if (ch1 == EOF || ch2 == EOF) { 795202719Sgabor warnx("unexpected eof"); 796202719Sgabor idx = -1; 797202719Sgabor } else 798202719Sgabor idx = (ch1 << 8) + ch2 + UCHAR_MAX + 1; 799202719Sgabor } 800202719Sgabor if (idx < 0 || (unsigned)idx >= bmachine.reg_array_size) { 801202719Sgabor warnx("internal error: reg num = %d", idx); 802202719Sgabor idx = -1; 803202719Sgabor } 804202719Sgabor return (idx); 805202719Sgabor} 806202719Sgabor 807202719Sgaborstatic void 808202719Sgaborload(void) 809202719Sgabor{ 810202719Sgabor int idx; 811202719Sgabor struct value *v, copy; 812202719Sgabor struct number *n; 813202719Sgabor 814202719Sgabor idx = readreg(); 815202719Sgabor if (idx >= 0) { 816202719Sgabor v = stack_tos(&bmachine.reg[idx]); 817202719Sgabor if (v == NULL) { 818202719Sgabor n = new_number(); 819202719Sgabor bn_check(BN_zero(n->number)); 820202719Sgabor push_number(n); 821202719Sgabor } else 822202719Sgabor push(stack_dup_value(v, ©)); 823202719Sgabor } 824202719Sgabor} 825202719Sgabor 826202719Sgaborstatic void 827202719Sgaborstore(void) 828202719Sgabor{ 829202719Sgabor int idx; 830202719Sgabor struct value *val; 831202719Sgabor 832202719Sgabor idx = readreg(); 833202719Sgabor if (idx >= 0) { 834202719Sgabor val = pop(); 835202719Sgabor if (val == NULL) { 836202719Sgabor return; 837202719Sgabor } 838202719Sgabor stack_set_tos(&bmachine.reg[idx], val); 839202719Sgabor } 840202719Sgabor} 841202719Sgabor 842202719Sgaborstatic void 843202719Sgaborload_stack(void) 844202719Sgabor{ 845202719Sgabor int idx; 846202719Sgabor struct stack *stack; 847202719Sgabor struct value *value; 848202719Sgabor 849202719Sgabor idx = readreg(); 850202719Sgabor if (idx >= 0) { 851202719Sgabor stack = &bmachine.reg[idx]; 852202719Sgabor value = NULL; 853202719Sgabor if (stack_size(stack) > 0) { 854202719Sgabor value = stack_pop(stack); 855202719Sgabor } 856202719Sgabor if (value != NULL) 857202719Sgabor push(value); 858202719Sgabor else 859202719Sgabor warnx("stack register '%c' (0%o) is empty", 860202719Sgabor idx, idx); 861202719Sgabor } 862202719Sgabor} 863202719Sgabor 864202719Sgaborstatic void 865202719Sgaborstore_stack(void) 866202719Sgabor{ 867202719Sgabor int idx; 868202719Sgabor struct value *value; 869202719Sgabor 870202719Sgabor idx = readreg(); 871202719Sgabor if (idx >= 0) { 872202719Sgabor value = pop(); 873202719Sgabor if (value == NULL) 874202719Sgabor return; 875202719Sgabor stack_push(&bmachine.reg[idx], value); 876202719Sgabor } 877202719Sgabor} 878202719Sgabor 879202719Sgaborstatic void 880202719Sgaborload_array(void) 881202719Sgabor{ 882202719Sgabor int reg; 883202719Sgabor struct number *inumber, *n; 884202719Sgabor u_long idx; 885202719Sgabor struct stack *stack; 886202719Sgabor struct value *v, copy; 887202719Sgabor 888202719Sgabor reg = readreg(); 889202719Sgabor if (reg >= 0) { 890202719Sgabor inumber = pop_number(); 891202719Sgabor if (inumber == NULL) 892202719Sgabor return; 893202719Sgabor idx = get_ulong(inumber); 894202719Sgabor if (BN_cmp(inumber->number, &zero) < 0) 895202719Sgabor warnx("negative idx"); 896202719Sgabor else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX) 897202719Sgabor warnx("idx too big"); 898202719Sgabor else { 899202719Sgabor stack = &bmachine.reg[reg]; 900202719Sgabor v = frame_retrieve(stack, idx); 901202719Sgabor if (v == NULL || v->type == BCODE_NONE) { 902202719Sgabor n = new_number(); 903202719Sgabor bn_check(BN_zero(n->number)); 904202719Sgabor push_number(n); 905202719Sgabor } 906202719Sgabor else 907202719Sgabor push(stack_dup_value(v, ©)); 908202719Sgabor } 909202719Sgabor free_number(inumber); 910202719Sgabor } 911202719Sgabor} 912202719Sgabor 913202719Sgaborstatic void 914202719Sgaborstore_array(void) 915202719Sgabor{ 916202719Sgabor int reg; 917202719Sgabor struct number *inumber; 918202719Sgabor u_long idx; 919202719Sgabor struct value *value; 920202719Sgabor struct stack *stack; 921202719Sgabor 922202719Sgabor reg = readreg(); 923202719Sgabor if (reg >= 0) { 924202719Sgabor inumber = pop_number(); 925202719Sgabor if (inumber == NULL) 926202719Sgabor return; 927202719Sgabor value = pop(); 928202719Sgabor if (value == NULL) { 929202719Sgabor free_number(inumber); 930202719Sgabor return; 931202719Sgabor } 932202719Sgabor idx = get_ulong(inumber); 933202719Sgabor if (BN_cmp(inumber->number, &zero) < 0) { 934202719Sgabor warnx("negative idx"); 935202719Sgabor stack_free_value(value); 936202719Sgabor } else if (idx == BN_MASK2 || idx > MAX_ARRAY_INDEX) { 937202719Sgabor warnx("idx too big"); 938202719Sgabor stack_free_value(value); 939202719Sgabor } else { 940202719Sgabor stack = &bmachine.reg[reg]; 941202719Sgabor frame_assign(stack, idx, value); 942202719Sgabor } 943202719Sgabor free_number(inumber); 944202719Sgabor } 945202719Sgabor} 946202719Sgabor 947202719Sgaborstatic void 948202719Sgaborpush_line(void) 949202719Sgabor{ 950202719Sgabor 951202719Sgabor push_string(read_string(&bmachine.readstack[bmachine.readsp])); 952202719Sgabor} 953202719Sgabor 954202719Sgaborstatic void 955202719Sgaborcomment(void) 956202719Sgabor{ 957202719Sgabor 958202719Sgabor free(readline()); 959202719Sgabor} 960202719Sgabor 961202719Sgaborstatic void 962202719Sgaborbexec(char *line) 963202719Sgabor{ 964202719Sgabor 965202719Sgabor system(line); 966202719Sgabor free(line); 967202719Sgabor} 968202719Sgabor 969202719Sgaborstatic void 970202719Sgaborbadd(void) 971202719Sgabor{ 972202719Sgabor struct number *a, *b; 973202719Sgabor struct number *r; 974202719Sgabor 975202719Sgabor a = pop_number(); 976202719Sgabor if (a == NULL) { 977202719Sgabor return; 978202719Sgabor } 979202719Sgabor b = pop_number(); 980202719Sgabor if (b == NULL) { 981202719Sgabor push_number(a); 982202719Sgabor return; 983202719Sgabor } 984202719Sgabor 985202719Sgabor r = new_number(); 986202719Sgabor r->scale = max(a->scale, b->scale); 987202719Sgabor if (r->scale > a->scale) 988202719Sgabor normalize(a, r->scale); 989202719Sgabor else if (r->scale > b->scale) 990202719Sgabor normalize(b, r->scale); 991202719Sgabor bn_check(BN_add(r->number, a->number, b->number)); 992202719Sgabor push_number(r); 993202719Sgabor free_number(a); 994202719Sgabor free_number(b); 995202719Sgabor} 996202719Sgabor 997202719Sgaborstatic void 998202719Sgaborbsub(void) 999202719Sgabor{ 1000202719Sgabor struct number *a, *b; 1001202719Sgabor struct number *r; 1002202719Sgabor 1003202719Sgabor a = pop_number(); 1004202719Sgabor if (a == NULL) { 1005202719Sgabor return; 1006202719Sgabor } 1007202719Sgabor b = pop_number(); 1008202719Sgabor if (b == NULL) { 1009202719Sgabor push_number(a); 1010202719Sgabor return; 1011202719Sgabor } 1012202719Sgabor 1013202719Sgabor r = new_number(); 1014202719Sgabor 1015202719Sgabor r->scale = max(a->scale, b->scale); 1016202719Sgabor if (r->scale > a->scale) 1017202719Sgabor normalize(a, r->scale); 1018202719Sgabor else if (r->scale > b->scale) 1019202719Sgabor normalize(b, r->scale); 1020202719Sgabor bn_check(BN_sub(r->number, b->number, a->number)); 1021202719Sgabor push_number(r); 1022202719Sgabor free_number(a); 1023202719Sgabor free_number(b); 1024202719Sgabor} 1025202719Sgabor 1026202719Sgaborvoid 1027202719Sgaborbmul_number(struct number *r, struct number *a, struct number *b) 1028202719Sgabor{ 1029202719Sgabor BN_CTX *ctx; 1030202719Sgabor 1031202719Sgabor /* Create copies of the scales, since r might be equal to a or b */ 1032202719Sgabor u_int ascale = a->scale; 1033202719Sgabor u_int bscale = b->scale; 1034202719Sgabor u_int rscale = ascale + bscale; 1035202719Sgabor 1036202719Sgabor ctx = BN_CTX_new(); 1037202719Sgabor bn_checkp(ctx); 1038202719Sgabor bn_check(BN_mul(r->number, a->number, b->number, ctx)); 1039202719Sgabor BN_CTX_free(ctx); 1040202719Sgabor 1041202719Sgabor if (rscale > bmachine.scale && rscale > ascale && rscale > bscale) { 1042202719Sgabor r->scale = rscale; 1043202719Sgabor normalize(r, max(bmachine.scale, max(ascale, bscale))); 1044202719Sgabor } else 1045202719Sgabor r->scale = rscale; 1046202719Sgabor} 1047202719Sgabor 1048202719Sgaborstatic void 1049202719Sgaborbmul(void) 1050202719Sgabor{ 1051202719Sgabor struct number *a, *b; 1052202719Sgabor struct number *r; 1053202719Sgabor 1054202719Sgabor a = pop_number(); 1055202719Sgabor if (a == NULL) { 1056202719Sgabor return; 1057202719Sgabor } 1058202719Sgabor b = pop_number(); 1059202719Sgabor if (b == NULL) { 1060202719Sgabor push_number(a); 1061202719Sgabor return; 1062202719Sgabor } 1063202719Sgabor 1064202719Sgabor r = new_number(); 1065202719Sgabor bmul_number(r, a, b); 1066202719Sgabor 1067202719Sgabor push_number(r); 1068202719Sgabor free_number(a); 1069202719Sgabor free_number(b); 1070202719Sgabor} 1071202719Sgabor 1072202719Sgaborstatic void 1073202719Sgaborbdiv(void) 1074202719Sgabor{ 1075202719Sgabor struct number *a, *b; 1076202719Sgabor struct number *r; 1077202719Sgabor u_int scale; 1078202719Sgabor BN_CTX *ctx; 1079202719Sgabor 1080202719Sgabor a = pop_number(); 1081202719Sgabor if (a == NULL) { 1082202719Sgabor return; 1083202719Sgabor } 1084202719Sgabor b = pop_number(); 1085202719Sgabor if (b == NULL) { 1086202719Sgabor push_number(a); 1087202719Sgabor return; 1088202719Sgabor } 1089202719Sgabor 1090202719Sgabor r = new_number(); 1091202719Sgabor r->scale = bmachine.scale; 1092202719Sgabor scale = max(a->scale, b->scale); 1093202719Sgabor 1094202719Sgabor if (BN_is_zero(a->number)) 1095202719Sgabor warnx("divide by zero"); 1096202719Sgabor else { 1097202719Sgabor normalize(a, scale); 1098202719Sgabor normalize(b, scale + r->scale); 1099202719Sgabor 1100202719Sgabor ctx = BN_CTX_new(); 1101202719Sgabor bn_checkp(ctx); 1102202719Sgabor bn_check(BN_div(r->number, NULL, b->number, a->number, ctx)); 1103202719Sgabor BN_CTX_free(ctx); 1104202719Sgabor } 1105202719Sgabor push_number(r); 1106202719Sgabor free_number(a); 1107202719Sgabor free_number(b); 1108202719Sgabor} 1109202719Sgabor 1110202719Sgaborstatic void 1111202719Sgaborbmod(void) 1112202719Sgabor{ 1113202719Sgabor struct number *a, *b; 1114202719Sgabor struct number *r; 1115202719Sgabor u_int scale; 1116202719Sgabor BN_CTX *ctx; 1117202719Sgabor 1118202719Sgabor a = pop_number(); 1119202719Sgabor if (a == NULL) { 1120202719Sgabor return; 1121202719Sgabor } 1122202719Sgabor b = pop_number(); 1123202719Sgabor if (b == NULL) { 1124202719Sgabor push_number(a); 1125202719Sgabor return; 1126202719Sgabor } 1127202719Sgabor 1128202719Sgabor r = new_number(); 1129202719Sgabor scale = max(a->scale, b->scale); 1130202719Sgabor r->scale = max(b->scale, a->scale + bmachine.scale); 1131202719Sgabor 1132202719Sgabor if (BN_is_zero(a->number)) 1133202719Sgabor warnx("remainder by zero"); 1134202719Sgabor else { 1135202719Sgabor normalize(a, scale); 1136202719Sgabor normalize(b, scale + bmachine.scale); 1137202719Sgabor 1138202719Sgabor ctx = BN_CTX_new(); 1139202719Sgabor bn_checkp(ctx); 1140202719Sgabor bn_check(BN_mod(r->number, b->number, a->number, ctx)); 1141202719Sgabor BN_CTX_free(ctx); 1142202719Sgabor } 1143202719Sgabor push_number(r); 1144202719Sgabor free_number(a); 1145202719Sgabor free_number(b); 1146202719Sgabor} 1147202719Sgabor 1148202719Sgaborstatic void 1149202719Sgaborbdivmod(void) 1150202719Sgabor{ 1151202719Sgabor struct number *a, *b; 1152202719Sgabor struct number *rdiv, *rmod; 1153202719Sgabor u_int scale; 1154202719Sgabor BN_CTX *ctx; 1155202719Sgabor 1156202719Sgabor a = pop_number(); 1157202719Sgabor if (a == NULL) { 1158202719Sgabor return; 1159202719Sgabor } 1160202719Sgabor b = pop_number(); 1161202719Sgabor if (b == NULL) { 1162202719Sgabor push_number(a); 1163202719Sgabor return; 1164202719Sgabor } 1165202719Sgabor 1166202719Sgabor rdiv = new_number(); 1167202719Sgabor rmod = new_number(); 1168202719Sgabor rdiv->scale = bmachine.scale; 1169202719Sgabor rmod->scale = max(b->scale, a->scale + bmachine.scale); 1170202719Sgabor scale = max(a->scale, b->scale); 1171202719Sgabor 1172202719Sgabor if (BN_is_zero(a->number)) 1173202719Sgabor warnx("divide by zero"); 1174202719Sgabor else { 1175202719Sgabor normalize(a, scale); 1176202719Sgabor normalize(b, scale + bmachine.scale); 1177202719Sgabor 1178202719Sgabor ctx = BN_CTX_new(); 1179202719Sgabor bn_checkp(ctx); 1180202719Sgabor bn_check(BN_div(rdiv->number, rmod->number, 1181202719Sgabor b->number, a->number, ctx)); 1182202719Sgabor BN_CTX_free(ctx); 1183202719Sgabor } 1184202719Sgabor push_number(rdiv); 1185202719Sgabor push_number(rmod); 1186202719Sgabor free_number(a); 1187202719Sgabor free_number(b); 1188202719Sgabor} 1189202719Sgabor 1190202719Sgaborstatic void 1191202719Sgaborbexp(void) 1192202719Sgabor{ 1193202719Sgabor struct number *a, *p; 1194202719Sgabor struct number *r; 1195202719Sgabor bool neg; 1196202719Sgabor u_int scale; 1197202719Sgabor 1198202719Sgabor p = pop_number(); 1199202719Sgabor if (p == NULL) { 1200202719Sgabor return; 1201202719Sgabor } 1202202719Sgabor a = pop_number(); 1203202719Sgabor if (a == NULL) { 1204202719Sgabor push_number(p); 1205202719Sgabor return; 1206202719Sgabor } 1207202719Sgabor 1208202719Sgabor if (p->scale != 0) 1209202719Sgabor warnx("Runtime warning: non-zero scale in exponent"); 1210202719Sgabor normalize(p, 0); 1211202719Sgabor 1212202719Sgabor neg = false; 1213202719Sgabor if (BN_cmp(p->number, &zero) < 0) { 1214202719Sgabor neg = true; 1215202719Sgabor negate(p); 1216202719Sgabor scale = bmachine.scale; 1217202719Sgabor } else { 1218202719Sgabor /* Posix bc says min(a.scale * b, max(a.scale, scale) */ 1219202719Sgabor u_long b; 1220202719Sgabor u_int m; 1221202719Sgabor 1222202719Sgabor b = BN_get_word(p->number); 1223202719Sgabor m = max(a->scale, bmachine.scale); 1224202719Sgabor scale = a->scale * (u_int)b; 1225202719Sgabor if (scale > m || (a->scale > 0 && (b == BN_MASK2 || 1226202719Sgabor b > UINT_MAX))) 1227202719Sgabor scale = m; 1228202719Sgabor } 1229202719Sgabor 1230202719Sgabor if (BN_is_zero(p->number)) { 1231202719Sgabor r = new_number(); 1232202719Sgabor bn_check(BN_one(r->number)); 1233202719Sgabor normalize(r, scale); 1234202719Sgabor } else { 1235202719Sgabor while (!BN_is_bit_set(p->number, 0)) { 1236202719Sgabor bmul_number(a, a, a); 1237202719Sgabor bn_check(BN_rshift1(p->number, p->number)); 1238202719Sgabor } 1239202719Sgabor 1240202719Sgabor r = dup_number(a); 1241202719Sgabor normalize(r, scale); 1242202719Sgabor bn_check(BN_rshift1(p->number, p->number)); 1243202719Sgabor 1244202719Sgabor while (!BN_is_zero(p->number)) { 1245202719Sgabor bmul_number(a, a, a); 1246202719Sgabor if (BN_is_bit_set(p->number, 0)) 1247202719Sgabor bmul_number(r, r, a); 1248202719Sgabor bn_check(BN_rshift1(p->number, p->number)); 1249202719Sgabor } 1250202719Sgabor 1251202719Sgabor if (neg) { 1252202719Sgabor BN_CTX *ctx; 1253202719Sgabor BIGNUM *one; 1254202719Sgabor 1255202719Sgabor one = BN_new(); 1256202719Sgabor bn_checkp(one); 1257202719Sgabor bn_check(BN_one(one)); 1258202719Sgabor ctx = BN_CTX_new(); 1259202719Sgabor bn_checkp(ctx); 1260202719Sgabor scale_number(one, r->scale + scale); 1261202719Sgabor normalize(r, scale); 1262202719Sgabor bn_check(BN_div(r->number, NULL, one, r->number, ctx)); 1263202719Sgabor BN_free(one); 1264202719Sgabor BN_CTX_free(ctx); 1265202719Sgabor } else 1266202719Sgabor normalize(r, scale); 1267202719Sgabor } 1268202719Sgabor push_number(r); 1269202719Sgabor free_number(a); 1270202719Sgabor free_number(p); 1271202719Sgabor} 1272202719Sgabor 1273202719Sgaborstatic bool 1274202719Sgaborbsqrt_stop(const BIGNUM *x, const BIGNUM *y, u_int *onecount) 1275202719Sgabor{ 1276202719Sgabor BIGNUM *r; 1277202719Sgabor bool ret; 1278202719Sgabor 1279202719Sgabor r = BN_new(); 1280202719Sgabor bn_checkp(r); 1281202719Sgabor bn_check(BN_sub(r, x, y)); 1282202719Sgabor if (BN_is_one(r)) 1283202719Sgabor (*onecount)++; 1284202719Sgabor ret = BN_is_zero(r); 1285202719Sgabor BN_free(r); 1286202719Sgabor return (ret || *onecount > 1); 1287202719Sgabor} 1288202719Sgabor 1289202719Sgaborstatic void 1290202719Sgaborbsqrt(void) 1291202719Sgabor{ 1292202719Sgabor struct number *n; 1293202719Sgabor struct number *r; 1294202719Sgabor BIGNUM *x, *y; 1295202719Sgabor u_int scale, onecount; 1296202719Sgabor BN_CTX *ctx; 1297202719Sgabor 1298202719Sgabor onecount = 0; 1299202719Sgabor n = pop_number(); 1300202719Sgabor if (n == NULL) { 1301202719Sgabor return; 1302202719Sgabor } 1303202719Sgabor if (BN_is_zero(n->number)) { 1304202719Sgabor r = new_number(); 1305202719Sgabor push_number(r); 1306202719Sgabor } else if (BN_cmp(n->number, &zero) < 0) 1307202719Sgabor warnx("square root of negative number"); 1308202719Sgabor else { 1309202719Sgabor scale = max(bmachine.scale, n->scale); 1310202719Sgabor normalize(n, 2*scale); 1311202719Sgabor x = BN_dup(n->number); 1312202719Sgabor bn_checkp(x); 1313202719Sgabor bn_check(BN_rshift(x, x, BN_num_bits(x)/2)); 1314202719Sgabor y = BN_new(); 1315202719Sgabor bn_checkp(y); 1316202719Sgabor ctx = BN_CTX_new(); 1317202719Sgabor bn_checkp(ctx); 1318202719Sgabor for (;;) { 1319202719Sgabor bn_checkp(BN_copy(y, x)); 1320202719Sgabor bn_check(BN_div(x, NULL, n->number, x, ctx)); 1321202719Sgabor bn_check(BN_add(x, x, y)); 1322202719Sgabor bn_check(BN_rshift1(x, x)); 1323202719Sgabor if (bsqrt_stop(x, y, &onecount)) 1324202719Sgabor break; 1325202719Sgabor } 1326202719Sgabor r = bmalloc(sizeof(*r)); 1327202719Sgabor r->scale = scale; 1328202719Sgabor r->number = y; 1329202719Sgabor BN_free(x); 1330202719Sgabor BN_CTX_free(ctx); 1331202719Sgabor push_number(r); 1332202719Sgabor } 1333202719Sgabor 1334202719Sgabor free_number(n); 1335202719Sgabor} 1336202719Sgabor 1337202719Sgaborstatic void 1338202719Sgabornot(void) 1339202719Sgabor{ 1340202719Sgabor struct number *a; 1341202719Sgabor 1342202719Sgabor a = pop_number(); 1343202719Sgabor if (a == NULL) { 1344202719Sgabor return; 1345202719Sgabor } 1346202719Sgabor a->scale = 0; 1347202719Sgabor bn_check(BN_set_word(a->number, BN_get_word(a->number) ? 0 : 1)); 1348202719Sgabor push_number(a); 1349202719Sgabor} 1350202719Sgabor 1351202719Sgaborstatic void 1352202719Sgaborequal(void) 1353202719Sgabor{ 1354202719Sgabor 1355202719Sgabor compare(BCODE_EQUAL); 1356202719Sgabor} 1357202719Sgabor 1358202719Sgaborstatic void 1359202719Sgaborequal_numbers(void) 1360202719Sgabor{ 1361202719Sgabor struct number *a, *b, *r; 1362202719Sgabor 1363202719Sgabor a = pop_number(); 1364202719Sgabor if (a == NULL) { 1365202719Sgabor return; 1366202719Sgabor } 1367202719Sgabor b = pop_number(); 1368202719Sgabor if (b == NULL) { 1369202719Sgabor push_number(a); 1370202719Sgabor return; 1371202719Sgabor } 1372202719Sgabor r = new_number(); 1373202719Sgabor bn_check(BN_set_word(r->number, 1374202719Sgabor compare_numbers(BCODE_EQUAL, a, b) ? 1 : 0)); 1375202719Sgabor push_number(r); 1376202719Sgabor} 1377202719Sgabor 1378202719Sgaborstatic void 1379202719Sgaborless_numbers(void) 1380202719Sgabor{ 1381202719Sgabor struct number *a, *b, *r; 1382202719Sgabor 1383202719Sgabor a = pop_number(); 1384202719Sgabor if (a == NULL) { 1385202719Sgabor return; 1386202719Sgabor } 1387202719Sgabor b = pop_number(); 1388202719Sgabor if (b == NULL) { 1389202719Sgabor push_number(a); 1390202719Sgabor return; 1391202719Sgabor } 1392202719Sgabor r = new_number(); 1393202719Sgabor bn_check(BN_set_word(r->number, 1394202719Sgabor compare_numbers(BCODE_LESS, a, b) ? 1 : 0)); 1395202719Sgabor push_number(r); 1396202719Sgabor} 1397202719Sgabor 1398202719Sgaborstatic void 1399202719Sgaborlesseq_numbers(void) 1400202719Sgabor{ 1401202719Sgabor struct number *a, *b, *r; 1402202719Sgabor 1403202719Sgabor a = pop_number(); 1404202719Sgabor if (a == NULL) { 1405202719Sgabor return; 1406202719Sgabor } 1407202719Sgabor b = pop_number(); 1408202719Sgabor if (b == NULL) { 1409202719Sgabor push_number(a); 1410202719Sgabor return; 1411202719Sgabor } 1412202719Sgabor r = new_number(); 1413202719Sgabor bn_check(BN_set_word(r->number, 1414202719Sgabor compare_numbers(BCODE_NOT_GREATER, a, b) ? 1 : 0)); 1415202719Sgabor push_number(r); 1416202719Sgabor} 1417202719Sgabor 1418202719Sgaborstatic void 1419202719Sgabornot_equal(void) 1420202719Sgabor{ 1421202719Sgabor 1422202719Sgabor compare(BCODE_NOT_EQUAL); 1423202719Sgabor} 1424202719Sgabor 1425202719Sgaborstatic void 1426202719Sgaborless(void) 1427202719Sgabor{ 1428202719Sgabor 1429202719Sgabor compare(BCODE_LESS); 1430202719Sgabor} 1431202719Sgabor 1432202719Sgaborstatic void 1433202719Sgabornot_compare(void) 1434202719Sgabor{ 1435202719Sgabor switch (readch()) { 1436202719Sgabor case '<': 1437202719Sgabor not_less(); 1438202719Sgabor break; 1439202719Sgabor case '>': 1440202719Sgabor not_greater(); 1441202719Sgabor break; 1442202719Sgabor case '=': 1443202719Sgabor not_equal(); 1444202719Sgabor break; 1445202719Sgabor default: 1446202719Sgabor unreadch(); 1447202719Sgabor bexec(readline()); 1448202719Sgabor break; 1449202719Sgabor } 1450202719Sgabor} 1451202719Sgabor 1452202719Sgaborstatic void 1453202719Sgabornot_less(void) 1454202719Sgabor{ 1455202719Sgabor 1456202719Sgabor compare(BCODE_NOT_LESS); 1457202719Sgabor} 1458202719Sgabor 1459202719Sgaborstatic void 1460202719Sgaborgreater(void) 1461202719Sgabor{ 1462202719Sgabor 1463202719Sgabor compare(BCODE_GREATER); 1464202719Sgabor} 1465202719Sgabor 1466202719Sgaborstatic void 1467202719Sgabornot_greater(void) 1468202719Sgabor{ 1469202719Sgabor 1470202719Sgabor compare(BCODE_NOT_GREATER); 1471202719Sgabor} 1472202719Sgabor 1473202719Sgaborstatic bool 1474202719Sgaborcompare_numbers(enum bcode_compare type, struct number *a, struct number *b) 1475202719Sgabor{ 1476202719Sgabor u_int scale; 1477202719Sgabor int cmp; 1478202719Sgabor 1479202719Sgabor scale = max(a->scale, b->scale); 1480202719Sgabor 1481202719Sgabor if (scale > a->scale) 1482202719Sgabor normalize(a, scale); 1483202719Sgabor else if (scale > b->scale) 1484202719Sgabor normalize(b, scale); 1485202719Sgabor 1486202719Sgabor cmp = BN_cmp(a->number, b->number); 1487202719Sgabor 1488202719Sgabor free_number(a); 1489202719Sgabor free_number(b); 1490202719Sgabor 1491202719Sgabor switch (type) { 1492202719Sgabor case BCODE_EQUAL: 1493202719Sgabor return (cmp == 0); 1494202719Sgabor case BCODE_NOT_EQUAL: 1495202719Sgabor return (cmp != 0); 1496202719Sgabor case BCODE_LESS: 1497202719Sgabor return (cmp < 0); 1498202719Sgabor case BCODE_NOT_LESS: 1499202719Sgabor return (cmp >= 0); 1500202719Sgabor case BCODE_GREATER: 1501202719Sgabor return (cmp > 0); 1502202719Sgabor case BCODE_NOT_GREATER: 1503202719Sgabor return (cmp <= 0); 1504202719Sgabor } 1505202719Sgabor return (false); 1506202719Sgabor} 1507202719Sgabor 1508202719Sgaborstatic void 1509202719Sgaborcompare(enum bcode_compare type) 1510202719Sgabor{ 1511202719Sgabor int idx, elseidx; 1512202719Sgabor struct number *a, *b; 1513202719Sgabor bool ok; 1514202719Sgabor struct value *v; 1515202719Sgabor 1516202719Sgabor elseidx = NO_ELSE; 1517202719Sgabor idx = readreg(); 1518202719Sgabor if (readch() == 'e') 1519202719Sgabor elseidx = readreg(); 1520202719Sgabor else 1521202719Sgabor unreadch(); 1522202719Sgabor 1523202719Sgabor a = pop_number(); 1524202719Sgabor if (a == NULL) 1525202719Sgabor return; 1526202719Sgabor b = pop_number(); 1527202719Sgabor if (b == NULL) { 1528202719Sgabor push_number(a); 1529202719Sgabor return; 1530202719Sgabor } 1531202719Sgabor 1532202719Sgabor ok = compare_numbers(type, a, b); 1533202719Sgabor 1534202719Sgabor if (!ok && elseidx != NO_ELSE) 1535202719Sgabor idx = elseidx; 1536202719Sgabor 1537202719Sgabor if (idx >= 0 && (ok || (!ok && elseidx != NO_ELSE))) { 1538202719Sgabor v = stack_tos(&bmachine.reg[idx]); 1539202719Sgabor if (v == NULL) 1540202719Sgabor warnx("register '%c' (0%o) is empty", idx, idx); 1541202719Sgabor else { 1542202719Sgabor switch(v->type) { 1543202719Sgabor case BCODE_NONE: 1544202719Sgabor warnx("register '%c' (0%o) is empty", idx, idx); 1545202719Sgabor break; 1546202719Sgabor case BCODE_NUMBER: 1547202719Sgabor warn("eval called with non-string argument"); 1548202719Sgabor break; 1549202719Sgabor case BCODE_STRING: 1550202719Sgabor eval_string(bstrdup(v->u.string)); 1551202719Sgabor break; 1552202719Sgabor } 1553202719Sgabor } 1554202719Sgabor } 1555202719Sgabor} 1556202719Sgabor 1557202719Sgabor 1558202719Sgaborstatic void 1559202719Sgabornop(void) 1560202719Sgabor{ 1561202719Sgabor} 1562202719Sgabor 1563202719Sgaborstatic void 1564202719Sgaborquit(void) 1565202719Sgabor{ 1566202719Sgabor if (bmachine.readsp < 2) 1567202719Sgabor exit(0); 1568202719Sgabor src_free(); 1569202719Sgabor bmachine.readsp--; 1570202719Sgabor src_free(); 1571202719Sgabor bmachine.readsp--; 1572202719Sgabor} 1573202719Sgabor 1574202719Sgaborstatic void 1575202719SgaborquitN(void) 1576202719Sgabor{ 1577202719Sgabor struct number *n; 1578202719Sgabor u_long i; 1579202719Sgabor 1580202719Sgabor n = pop_number(); 1581202719Sgabor if (n == NULL) 1582202719Sgabor return; 1583202719Sgabor i = get_ulong(n); 1584202719Sgabor free_number(n); 1585202719Sgabor if (i == BN_MASK2 || i == 0) 1586202719Sgabor warnx("Q command requires a number >= 1"); 1587202719Sgabor else if (bmachine.readsp < i) 1588202719Sgabor warnx("Q command argument exceeded string execution depth"); 1589202719Sgabor else { 1590202719Sgabor while (i-- > 0) { 1591202719Sgabor src_free(); 1592202719Sgabor bmachine.readsp--; 1593202719Sgabor } 1594202719Sgabor } 1595202719Sgabor} 1596202719Sgabor 1597202719Sgaborstatic void 1598202719SgaborskipN(void) 1599202719Sgabor{ 1600202719Sgabor struct number *n; 1601202719Sgabor u_long i; 1602202719Sgabor 1603202719Sgabor n = pop_number(); 1604202719Sgabor if (n == NULL) 1605202719Sgabor return; 1606202719Sgabor i = get_ulong(n); 1607202719Sgabor if (i == BN_MASK2) 1608202719Sgabor warnx("J command requires a number >= 0"); 1609202719Sgabor else if (i > 0 && bmachine.readsp < i) 1610202719Sgabor warnx("J command argument exceeded string execution depth"); 1611202719Sgabor else { 1612202719Sgabor while (i-- > 0) { 1613202719Sgabor src_free(); 1614202719Sgabor bmachine.readsp--; 1615202719Sgabor } 1616202719Sgabor skip_until_mark(); 1617202719Sgabor } 1618202719Sgabor} 1619202719Sgabor 1620202719Sgaborstatic void 1621202719Sgaborskip_until_mark(void) 1622202719Sgabor{ 1623202719Sgabor 1624202719Sgabor for (;;) { 1625203438Sgabor switch (readch()) { 1626202719Sgabor case 'M': 1627202719Sgabor return; 1628202719Sgabor case EOF: 1629202719Sgabor errx(1, "mark not found"); 1630202719Sgabor return; 1631202719Sgabor case 'l': 1632202719Sgabor case 'L': 1633202719Sgabor case 's': 1634202719Sgabor case 'S': 1635202719Sgabor case ':': 1636202719Sgabor case ';': 1637202719Sgabor case '<': 1638202719Sgabor case '>': 1639202719Sgabor case '=': 1640202719Sgabor readreg(); 1641202719Sgabor if (readch() == 'e') 1642202719Sgabor readreg(); 1643202719Sgabor else 1644202719Sgabor unreadch(); 1645202719Sgabor break; 1646202719Sgabor case '[': 1647202719Sgabor free(read_string(&bmachine.readstack[bmachine.readsp])); 1648202719Sgabor break; 1649202719Sgabor case '!': 1650203438Sgabor switch (readch()) { 1651202719Sgabor case '<': 1652202719Sgabor case '>': 1653202719Sgabor case '=': 1654202719Sgabor readreg(); 1655202719Sgabor if (readch() == 'e') 1656202719Sgabor readreg(); 1657202719Sgabor else 1658202719Sgabor unreadch(); 1659202719Sgabor break; 1660202719Sgabor default: 1661202719Sgabor free(readline()); 1662202719Sgabor break; 1663202719Sgabor } 1664202719Sgabor break; 1665202719Sgabor default: 1666202719Sgabor break; 1667202719Sgabor } 1668202719Sgabor } 1669202719Sgabor} 1670202719Sgabor 1671202719Sgaborstatic void 1672202719Sgaborparse_number(void) 1673202719Sgabor{ 1674202719Sgabor 1675202719Sgabor unreadch(); 1676202719Sgabor push_number(readnumber(&bmachine.readstack[bmachine.readsp], 1677202719Sgabor bmachine.ibase)); 1678202719Sgabor} 1679202719Sgabor 1680202719Sgaborstatic void 1681202719Sgaborunknown(void) 1682202719Sgabor{ 1683202719Sgabor int ch = bmachine.readstack[bmachine.readsp].lastchar; 1684202719Sgabor warnx("%c (0%o) is unimplemented", ch, ch); 1685202719Sgabor} 1686202719Sgabor 1687202719Sgaborstatic void 1688202719Sgaboreval_string(char *p) 1689202719Sgabor{ 1690202719Sgabor int ch; 1691202719Sgabor 1692202719Sgabor if (bmachine.readsp > 0) { 1693202719Sgabor /* Check for tail call. Do not recurse in that case. */ 1694202719Sgabor ch = readch(); 1695202719Sgabor if (ch == EOF) { 1696202719Sgabor src_free(); 1697202719Sgabor src_setstring(&bmachine.readstack[bmachine.readsp], p); 1698202719Sgabor return; 1699202719Sgabor } else 1700202719Sgabor unreadch(); 1701202719Sgabor } 1702202719Sgabor if (bmachine.readsp == bmachine.readstack_sz - 1) { 1703202719Sgabor size_t newsz = bmachine.readstack_sz * 2; 1704202719Sgabor struct source *stack; 1705202719Sgabor stack = realloc(bmachine.readstack, newsz * 1706202719Sgabor sizeof(struct source)); 1707202719Sgabor if (stack == NULL) 1708202719Sgabor err(1, "recursion too deep"); 1709202719Sgabor bmachine.readstack_sz = newsz; 1710202719Sgabor bmachine.readstack = stack; 1711202719Sgabor } 1712202719Sgabor src_setstring(&bmachine.readstack[++bmachine.readsp], p); 1713202719Sgabor} 1714202719Sgabor 1715202719Sgaborstatic void 1716202719Sgaboreval_line(void) 1717202719Sgabor{ 1718202719Sgabor /* Always read from stdin */ 1719202719Sgabor struct source in; 1720202719Sgabor char *p; 1721202719Sgabor 1722202719Sgabor clearerr(stdin); 1723202719Sgabor src_setstream(&in, stdin); 1724202719Sgabor p = (*in.vtable->readline)(&in); 1725202719Sgabor eval_string(p); 1726202719Sgabor} 1727202719Sgabor 1728202719Sgaborstatic void 1729202719Sgaboreval_tos(void) 1730202719Sgabor{ 1731202719Sgabor char *p; 1732202719Sgabor 1733202719Sgabor p = pop_string(); 1734202719Sgabor if (p == NULL) 1735202719Sgabor return; 1736202719Sgabor eval_string(p); 1737202719Sgabor} 1738202719Sgabor 1739202719Sgaborvoid 1740202719Sgaboreval(void) 1741202719Sgabor{ 1742202719Sgabor int ch; 1743202719Sgabor 1744202719Sgabor for (;;) { 1745202719Sgabor ch = readch(); 1746202719Sgabor if (ch == EOF) { 1747202719Sgabor if (bmachine.readsp == 0) 1748202719Sgabor return; 1749202719Sgabor src_free(); 1750202719Sgabor bmachine.readsp--; 1751202719Sgabor continue; 1752202719Sgabor } 1753202719Sgabor if (bmachine.interrupted) { 1754202719Sgabor if (bmachine.readsp > 0) { 1755202719Sgabor src_free(); 1756202719Sgabor bmachine.readsp--; 1757202719Sgabor continue; 1758202719Sgabor } else 1759202719Sgabor bmachine.interrupted = false; 1760202719Sgabor } 1761202719Sgabor#ifdef DEBUGGING 1762202719Sgabor fprintf(stderr, "# %c\n", ch); 1763202719Sgabor stack_print(stderr, &bmachine.stack, "* ", 1764202719Sgabor bmachine.obase); 1765202719Sgabor fprintf(stderr, "%zd =>\n", bmachine.readsp); 1766202719Sgabor#endif 1767202719Sgabor 1768202719Sgabor if (0 <= ch && ch < (signed)UCHAR_MAX) 1769202719Sgabor (*jump_table[ch])(); 1770202719Sgabor else 1771202719Sgabor warnx("internal error: opcode %d", ch); 1772202719Sgabor 1773202719Sgabor#ifdef DEBUGGING 1774202719Sgabor stack_print(stderr, &bmachine.stack, "* ", 1775202719Sgabor bmachine.obase); 1776202719Sgabor fprintf(stderr, "%zd ==\n", bmachine.readsp); 1777202719Sgabor#endif 1778202719Sgabor } 1779202719Sgabor} 1780