toybox/toys/pending/bc.c
<<
>>
Prefs
   1/* bc.c - An implementation of POSIX bc.
   2 *
   3 * Copyright 2018 Gavin D. Howard <yzena.tech@gmail.com>
   4 *
   5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html
   6
   7USE_BC(NEWTOY(bc, "i(interactive)l(mathlib)q(quiet)s(standard)w(warn)", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
   8
   9config BC
  10  bool "bc"
  11  default n
  12  help
  13    usage: bc [-ilqsw] [file ...]
  14
  15    bc is a command-line calculator with a Turing-complete language.
  16
  17    options:
  18
  19      -i  --interactive  force interactive mode
  20      -l  --mathlib      use predefined math routines:
  21
  22                         s(expr)  =  sine of expr in radians
  23                         c(expr)  =  cosine of expr in radians
  24                         a(expr)  =  arctangent of expr, returning radians
  25                         l(expr)  =  natural log of expr
  26                         e(expr)  =  raises e to the power of expr
  27                         j(n, x)  =  Bessel function of integer order n of x
  28
  29      -q  --quiet        don't print version and copyright
  30      -s  --standard     error if any non-POSIX extensions are used
  31      -w  --warn         warn if any non-POSIX extensions are used
  32
  33*/
  34
  35#define FOR_bc
  36#include "toys.h"
  37
  38GLOBALS(
  39  // This actually needs to be a BcVm*, but the toybox build
  40  // system complains if I make it so. Instead, we'll just cast.
  41  char *vm;
  42)
  43
  44#define BC_VM ((BcVm*) TT.vm)
  45
  46typedef enum BcStatus {
  47
  48  BC_STATUS_SUCCESS = 0,
  49  BC_STATUS_ERROR,
  50  BC_STATUS_EOF,
  51  BC_STATUS_EMPTY_EXPR,
  52  BC_STATUS_SIGNAL,
  53  BC_STATUS_QUIT,
  54
  55} BcStatus;
  56
  57typedef enum BcError {
  58
  59  BC_ERROR_VM_ALLOC_ERR,
  60  BC_ERROR_VM_IO_ERR,
  61  BC_ERROR_VM_BIN_FILE,
  62  BC_ERROR_VM_PATH_DIR,
  63
  64  BC_ERROR_PARSE_EOF,
  65  BC_ERROR_PARSE_CHAR,
  66  BC_ERROR_PARSE_STRING,
  67  BC_ERROR_PARSE_COMMENT,
  68  BC_ERROR_PARSE_TOKEN,
  69  BC_ERROR_EXEC_NUM_LEN,
  70  BC_ERROR_EXEC_NAME_LEN,
  71  BC_ERROR_EXEC_STRING_LEN,
  72  BC_ERROR_PARSE_EXPR,
  73  BC_ERROR_PARSE_EMPTY_EXPR,
  74  BC_ERROR_PARSE_PRINT,
  75  BC_ERROR_PARSE_FUNC,
  76  BC_ERROR_PARSE_ASSIGN,
  77  BC_ERROR_PARSE_NO_AUTO,
  78  BC_ERROR_PARSE_DUP_LOCAL,
  79  BC_ERROR_PARSE_BLOCK,
  80  BC_ERROR_PARSE_RET_VOID,
  81
  82  BC_ERROR_MATH_NEGATIVE,
  83  BC_ERROR_MATH_NON_INTEGER,
  84  BC_ERROR_MATH_OVERFLOW,
  85  BC_ERROR_MATH_DIVIDE_BY_ZERO,
  86
  87  BC_ERROR_EXEC_FILE_ERR,
  88  BC_ERROR_EXEC_ARRAY_LEN,
  89  BC_ERROR_EXEC_IBASE,
  90  BC_ERROR_EXEC_OBASE,
  91  BC_ERROR_EXEC_SCALE,
  92  BC_ERROR_EXEC_READ_EXPR,
  93  BC_ERROR_EXEC_REC_READ,
  94  BC_ERROR_EXEC_TYPE,
  95  BC_ERROR_EXEC_PARAMS,
  96  BC_ERROR_EXEC_UNDEF_FUNC,
  97  BC_ERROR_EXEC_VOID_VAL,
  98
  99  BC_ERROR_POSIX_START,
 100
 101  BC_ERROR_POSIX_NAME_LEN = BC_ERROR_POSIX_START,
 102  BC_ERROR_POSIX_COMMENT,
 103  BC_ERROR_POSIX_KW,
 104  BC_ERROR_POSIX_DOT,
 105  BC_ERROR_POSIX_RET,
 106  BC_ERROR_POSIX_BOOL,
 107  BC_ERROR_POSIX_REL_POS,
 108  BC_ERROR_POSIX_MULTIREL,
 109  BC_ERROR_POSIX_FOR1,
 110  BC_ERROR_POSIX_FOR2,
 111  BC_ERROR_POSIX_FOR3,
 112  BC_ERROR_POSIX_BRACE,
 113  BC_ERROR_POSIX_REF,
 114
 115} BcError;
 116
 117#define BC_ERR_IDX_VM (0)
 118#define BC_ERR_IDX_PARSE (1)
 119#define BC_ERR_IDX_MATH (2)
 120#define BC_ERR_IDX_EXEC (3)
 121#define BC_ERR_IDX_POSIX (4)
 122
 123#define BC_UNUSED(e) ((void) (e))
 124
 125#define BC_VEC_START_CAP (1<<5)
 126
 127typedef unsigned char uchar;
 128
 129typedef void (*BcVecFree)(void*);
 130
 131// Forward declaration.
 132struct BcId;
 133
 134typedef struct BcVec {
 135  char *v;
 136  size_t len;
 137  size_t cap;
 138  size_t size;
 139  BcVecFree dtor;
 140} BcVec;
 141
 142#define bc_vec_pop(v) (bc_vec_npop((v), 1))
 143#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
 144
 145#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
 146
 147#define BC_READ_BIN_CHAR(c) (((c) < ' ' && !isspace((c))) || ((uchar) c) > '~')
 148
 149typedef signed char BcDig;
 150
 151typedef struct BcNum {
 152  BcDig *num;
 153  size_t rdx;
 154  size_t len;
 155  size_t cap;
 156  int neg;
 157} BcNum;
 158
 159#define BC_NUM_MIN_BASE ((unsigned long) 2)
 160#define BC_NUM_MAX_POSIX_IBASE ((unsigned long) 16)
 161#define BC_NUM_MAX_IBASE ((unsigned long) 36)
 162// This is the max base allowed by bc_num_parseChar().
 163#define BC_NUM_MAX_LBASE ('Z' + 10 + 1)
 164#define BC_NUM_DEF_SIZE (16)
 165#define BC_NUM_PRINT_WIDTH (69)
 166
 167#define BC_NUM_KARATSUBA_LEN (32)
 168
 169// A crude, but always big enough, calculation of
 170// the size required for ibase and obase BcNum's.
 171#define BC_NUM_LONG_LOG10 ((CHAR_BIT * sizeof(unsigned long) + 1) / 2 + 1)
 172
 173#define BC_NUM_NEG(n, neg) ((((ssize_t) (n)) ^ -((ssize_t) (neg))) + (neg))
 174
 175#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
 176#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
 177#define BC_NUM_CMP_ZERO(a) (BC_NUM_NEG((a)->len != 0, (a)->neg))
 178#define BC_NUM_PREQ(a, b) ((a)->len + (b)->len + 1)
 179#define BC_NUM_SHREQ(a) ((a)->len)
 180
 181#define BC_NUM_NUM_LETTER(c) ((c) - 'A' + 10)
 182
 183typedef BcStatus (*BcNumBinaryOp)(BcNum*, BcNum*, BcNum*, size_t);
 184typedef size_t (*BcNumBinaryOpReq)(BcNum*, BcNum*, size_t);
 185typedef void (*BcNumDigitOp)(size_t, size_t, int);
 186
 187void bc_num_init(BcNum *n, size_t req);
 188void bc_num_setup(BcNum *n, BcDig *num, size_t cap);
 189void bc_num_expand(BcNum *n, size_t req);
 190void bc_num_copy(BcNum *d, BcNum *s);
 191void bc_num_createCopy(BcNum *d, BcNum *s);
 192void bc_num_createFromUlong(BcNum *n, unsigned long val);
 193void bc_num_free(void *num);
 194
 195BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
 196void bc_num_ulong2num(BcNum *n, unsigned long val);
 197
 198BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
 199BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
 200BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
 201BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
 202BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
 203BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
 204BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
 205BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale);
 206
 207size_t bc_num_addReq(BcNum *a, BcNum *b, size_t scale);
 208
 209size_t bc_num_mulReq(BcNum *a, BcNum *b, size_t scale);
 210size_t bc_num_powReq(BcNum *a, BcNum *b, size_t scale);
 211
 212typedef enum BcInst {
 213
 214  BC_INST_INC_POST = 0,
 215  BC_INST_DEC_POST,
 216  BC_INST_INC_PRE,
 217  BC_INST_DEC_PRE,
 218
 219  BC_INST_NEG,
 220  BC_INST_BOOL_NOT,
 221
 222  BC_INST_POWER,
 223  BC_INST_MULTIPLY,
 224  BC_INST_DIVIDE,
 225  BC_INST_MODULUS,
 226  BC_INST_PLUS,
 227  BC_INST_MINUS,
 228
 229  BC_INST_REL_EQ,
 230  BC_INST_REL_LE,
 231  BC_INST_REL_GE,
 232  BC_INST_REL_NE,
 233  BC_INST_REL_LT,
 234  BC_INST_REL_GT,
 235
 236  BC_INST_BOOL_OR,
 237  BC_INST_BOOL_AND,
 238
 239  BC_INST_ASSIGN_POWER,
 240  BC_INST_ASSIGN_MULTIPLY,
 241  BC_INST_ASSIGN_DIVIDE,
 242  BC_INST_ASSIGN_MODULUS,
 243  BC_INST_ASSIGN_PLUS,
 244  BC_INST_ASSIGN_MINUS,
 245  BC_INST_ASSIGN,
 246
 247  BC_INST_NUM,
 248  BC_INST_VAR,
 249  BC_INST_ARRAY_ELEM,
 250  BC_INST_ARRAY,
 251
 252  BC_INST_LAST,
 253  BC_INST_IBASE,
 254  BC_INST_OBASE,
 255  BC_INST_SCALE,
 256  BC_INST_LENGTH,
 257  BC_INST_SCALE_FUNC,
 258  BC_INST_SQRT,
 259  BC_INST_ABS,
 260  BC_INST_READ,
 261
 262  BC_INST_PRINT,
 263  BC_INST_PRINT_POP,
 264  BC_INST_STR,
 265  BC_INST_PRINT_STR,
 266
 267  BC_INST_JUMP,
 268  BC_INST_JUMP_ZERO,
 269
 270  BC_INST_CALL,
 271
 272  BC_INST_RET,
 273  BC_INST_RET0,
 274  BC_INST_RET_VOID,
 275
 276  BC_INST_HALT,
 277
 278  BC_INST_POP,
 279  BC_INST_POP_EXEC,
 280
 281} BcInst;
 282
 283typedef struct BcId {
 284  char *name;
 285  size_t idx;
 286} BcId;
 287
 288typedef struct BcFunc {
 289
 290  BcVec code;
 291  BcVec labels;
 292  BcVec autos;
 293  size_t nparams;
 294
 295  BcVec strs;
 296  BcVec consts;
 297
 298  char *name;
 299  int voidfn;
 300
 301} BcFunc;
 302
 303typedef enum BcResultType {
 304
 305  BC_RESULT_VAR,
 306  BC_RESULT_ARRAY_ELEM,
 307  BC_RESULT_ARRAY,
 308
 309  BC_RESULT_STR,
 310
 311  BC_RESULT_CONSTANT,
 312  BC_RESULT_TEMP,
 313
 314  BC_RESULT_VOID,
 315  BC_RESULT_ONE,
 316  BC_RESULT_LAST,
 317  BC_RESULT_IBASE,
 318  BC_RESULT_OBASE,
 319  BC_RESULT_SCALE,
 320
 321} BcResultType;
 322
 323typedef union BcResultData {
 324  BcNum n;
 325  BcVec v;
 326  BcId id;
 327} BcResultData;
 328
 329typedef struct BcResult {
 330  BcResultType t;
 331  BcResultData d;
 332} BcResult;
 333
 334typedef struct BcInstPtr {
 335  size_t func;
 336  size_t idx;
 337  size_t len;
 338} BcInstPtr;
 339
 340typedef enum BcType {
 341  BC_TYPE_VAR,
 342  BC_TYPE_ARRAY,
 343} BcType;
 344
 345void bc_array_expand(BcVec *a, size_t len);
 346int bc_id_cmp(BcId *e1, BcId *e2);
 347
 348#define bc_lex_err(l, e) (bc_vm_error((e), (l)->line))
 349#define bc_lex_verr(l, e, ...) (bc_vm_error((e), (l)->line, __VA_ARGS__))
 350
 351#define BC_LEX_NUM_CHAR(c, l, pt) \
 352  (isdigit(c) || ((c) >= 'A' && (c) <= (l)) || ((c) == '.' && !(pt)))
 353
 354// BC_LEX_NEG is not used in lexing; it is only for parsing.
 355typedef enum BcLexType {
 356
 357  BC_LEX_EOF,
 358  BC_LEX_INVALID,
 359
 360  BC_LEX_OP_INC,
 361  BC_LEX_OP_DEC,
 362
 363  BC_LEX_NEG,
 364  BC_LEX_OP_BOOL_NOT,
 365
 366  BC_LEX_OP_POWER,
 367  BC_LEX_OP_MULTIPLY,
 368  BC_LEX_OP_DIVIDE,
 369  BC_LEX_OP_MODULUS,
 370  BC_LEX_OP_PLUS,
 371  BC_LEX_OP_MINUS,
 372
 373  BC_LEX_OP_REL_EQ,
 374  BC_LEX_OP_REL_LE,
 375  BC_LEX_OP_REL_GE,
 376  BC_LEX_OP_REL_NE,
 377  BC_LEX_OP_REL_LT,
 378  BC_LEX_OP_REL_GT,
 379
 380  BC_LEX_OP_BOOL_OR,
 381  BC_LEX_OP_BOOL_AND,
 382
 383  BC_LEX_OP_ASSIGN_POWER,
 384  BC_LEX_OP_ASSIGN_MULTIPLY,
 385  BC_LEX_OP_ASSIGN_DIVIDE,
 386  BC_LEX_OP_ASSIGN_MODULUS,
 387  BC_LEX_OP_ASSIGN_PLUS,
 388  BC_LEX_OP_ASSIGN_MINUS,
 389  BC_LEX_OP_ASSIGN,
 390
 391  BC_LEX_NLINE,
 392  BC_LEX_WHITESPACE,
 393
 394  BC_LEX_LPAREN,
 395  BC_LEX_RPAREN,
 396
 397  BC_LEX_LBRACKET,
 398  BC_LEX_COMMA,
 399  BC_LEX_RBRACKET,
 400
 401  BC_LEX_LBRACE,
 402  BC_LEX_SCOLON,
 403  BC_LEX_RBRACE,
 404
 405  BC_LEX_STR,
 406  BC_LEX_NAME,
 407  BC_LEX_NUMBER,
 408
 409  BC_LEX_KEY_AUTO,
 410  BC_LEX_KEY_BREAK,
 411  BC_LEX_KEY_CONTINUE,
 412  BC_LEX_KEY_DEFINE,
 413  BC_LEX_KEY_FOR,
 414  BC_LEX_KEY_IF,
 415  BC_LEX_KEY_LIMITS,
 416  BC_LEX_KEY_RETURN,
 417  BC_LEX_KEY_WHILE,
 418  BC_LEX_KEY_HALT,
 419  BC_LEX_KEY_LAST,
 420  BC_LEX_KEY_IBASE,
 421  BC_LEX_KEY_OBASE,
 422  BC_LEX_KEY_SCALE,
 423  BC_LEX_KEY_LENGTH,
 424  BC_LEX_KEY_PRINT,
 425  BC_LEX_KEY_SQRT,
 426  BC_LEX_KEY_ABS,
 427  BC_LEX_KEY_QUIT,
 428  BC_LEX_KEY_READ,
 429  BC_LEX_KEY_ELSE,
 430
 431} BcLexType;
 432
 433typedef struct BcLex {
 434
 435  char *buf;
 436  size_t i;
 437  size_t line;
 438  size_t len;
 439
 440  BcLexType t;
 441  BcLexType last;
 442  BcVec str;
 443
 444} BcLex;
 445
 446#define BC_PARSE_STREND ((uchar) UCHAR_MAX)
 447
 448#define BC_PARSE_REL (1<<0)
 449#define BC_PARSE_PRINT (1<<1)
 450#define BC_PARSE_NOCALL (1<<2)
 451#define BC_PARSE_NOREAD (1<<3)
 452#define BC_PARSE_ARRAY (1<<4)
 453
 454#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (uchar) (i)))
 455#define bc_parse_number(p)(bc_parse_addId((p), BC_INST_NUM))
 456#define bc_parse_string(p)(bc_parse_addId((p), BC_INST_STR))
 457
 458#define bc_parse_err(p, e) (bc_vm_error((e), (p)->l.line))
 459#define bc_parse_verr(p, e, ...) (bc_vm_error((e), (p)->l.line, __VA_ARGS__))
 460
 461typedef struct BcParseNext {
 462  uchar len;
 463  uchar tokens[4];
 464} BcParseNext;
 465
 466#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
 467#define BC_PARSE_NEXT(a, ...) \
 468  { .len = (uchar) (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) }
 469
 470struct BcProgram;
 471
 472typedef struct BcParse {
 473
 474  BcLex l;
 475
 476  BcVec flags;
 477  BcVec exits;
 478  BcVec conds;
 479  BcVec ops;
 480
 481  struct BcProgram *prog;
 482  BcFunc *func;
 483  size_t fidx;
 484
 485  int auto_part;
 486
 487} BcParse;
 488
 489typedef struct BcLexKeyword {
 490  uchar data;
 491  char name[9];
 492} BcLexKeyword;
 493
 494#define BC_LEX_CHAR_MSB(bit) ((bit) << (CHAR_BIT - 1))
 495
 496#define BC_LEX_KW_POSIX(kw) ((kw)->data & (BC_LEX_CHAR_MSB(1)))
 497#define BC_LEX_KW_LEN(kw) ((size_t) ((kw)->data & ~(BC_LEX_CHAR_MSB(1))))
 498
 499#define BC_LEX_KW_ENTRY(a, b, c) \
 500  { .data = ((b) & ~(BC_LEX_CHAR_MSB(1))) | BC_LEX_CHAR_MSB(c),.name = a }
 501
 502#define bc_lex_posixErr(l, e) (bc_vm_posixError((e), (l)->line))
 503#define bc_lex_vposixErr(l, e, ...) \
 504  (bc_vm_posixError((e), (l)->line, __VA_ARGS__))
 505
 506BcStatus bc_lex_token(BcLex *l);
 507
 508#define BC_PARSE_TOP_FLAG_PTR(p) ((uint16_t*) bc_vec_top(&(p)->flags))
 509#define BC_PARSE_TOP_FLAG(p) (*(BC_PARSE_TOP_FLAG_PTR(p)))
 510
 511#define BC_PARSE_FLAG_BRACE (1<<0)
 512#define BC_PARSE_BRACE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BRACE)
 513
 514#define BC_PARSE_FLAG_FUNC_INNER (1<<1)
 515#define BC_PARSE_FUNC_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC_INNER)
 516
 517#define BC_PARSE_FLAG_FUNC (1<<2)
 518#define BC_PARSE_FUNC(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC)
 519
 520#define BC_PARSE_FLAG_BODY (1<<3)
 521#define BC_PARSE_BODY(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BODY)
 522
 523#define BC_PARSE_FLAG_LOOP (1<<4)
 524#define BC_PARSE_LOOP(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP)
 525
 526#define BC_PARSE_FLAG_LOOP_INNER (1<<5)
 527#define BC_PARSE_LOOP_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP_INNER)
 528
 529#define BC_PARSE_FLAG_IF (1<<6)
 530#define BC_PARSE_IF(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF)
 531
 532#define BC_PARSE_FLAG_ELSE (1<<7)
 533#define BC_PARSE_ELSE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_ELSE)
 534
 535#define BC_PARSE_FLAG_IF_END (1<<8)
 536#define BC_PARSE_IF_END(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF_END)
 537
 538#define BC_PARSE_NO_EXEC(p) ((p)->flags.len != 1 || BC_PARSE_TOP_FLAG(p) != 0)
 539
 540#define BC_PARSE_DELIMITER(t) \
 541  ((t) == BC_LEX_SCOLON || (t) == BC_LEX_NLINE || (t) == BC_LEX_EOF)
 542
 543#define BC_PARSE_BLOCK_STMT(f) \
 544  ((f) & (BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_LOOP_INNER))
 545
 546#define BC_PARSE_OP(p, l) (((p) & ~(BC_LEX_CHAR_MSB(1))) | (BC_LEX_CHAR_MSB(l)))
 547
 548#define BC_PARSE_OP_DATA(t) bc_parse_ops[((t) - BC_LEX_OP_INC)]
 549#define BC_PARSE_OP_LEFT(op) (BC_PARSE_OP_DATA(op) & BC_LEX_CHAR_MSB(1))
 550#define BC_PARSE_OP_PREC(op) (BC_PARSE_OP_DATA(op) & ~(BC_LEX_CHAR_MSB(1)))
 551
 552#define BC_PARSE_EXPR_ENTRY(e1, e2, e3, e4, e5, e6, e7, e8)  \
 553  (((e1) << 7) | ((e2) << 6) | ((e3) << 5) | ((e4) << 4) | \
 554   ((e5) << 3) | ((e6) << 2) | ((e7) << 1) | ((e8) << 0))
 555
 556#define BC_PARSE_EXPR(i) \
 557  (bc_parse_exprs[(((i) & (uchar) ~(0x07)) >> 3)] & (1 << (7 - ((i) & 0x07))))
 558
 559#define BC_PARSE_TOP_OP(p) (*((BcLexType*) bc_vec_top(&(p)->ops)))
 560#define BC_PARSE_LEAF(prev, bin_last, rparen) \
 561  (!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev)))
 562#define BC_PARSE_INST_VAR(t) \
 563  ((t) >= BC_INST_VAR && (t) <= BC_INST_SCALE && (t) != BC_INST_ARRAY)
 564
 565#define BC_PARSE_PREV_PREFIX(p) \
 566  ((p) >= BC_INST_INC_PRE && (p) <= BC_INST_BOOL_NOT)
 567#define BC_PARSE_OP_PREFIX(t) ((t) == BC_LEX_OP_BOOL_NOT || (t) == BC_LEX_NEG)
 568
 569// We can calculate the conversion between tokens and exprs by subtracting the
 570// position of the first operator in the lex enum and adding the position of
 571// the first in the expr enum. Note: This only works for binary operators.
 572#define BC_PARSE_TOKEN_INST(t) ((uchar) ((t) - BC_LEX_NEG + BC_INST_NEG))
 573
 574#define bc_parse_posixErr(p, e) (bc_vm_posixError((e), (p)->l.line))
 575
 576BcStatus bc_parse_parse(BcParse *p);
 577BcStatus bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next);
 578
 579#define BC_PROG_ONE_CAP (1)
 580
 581typedef struct BcProgram {
 582
 583  size_t scale;
 584
 585  BcNum ib;
 586  size_t ib_t;
 587  BcNum ob;
 588  size_t ob_t;
 589
 590  BcVec results;
 591  BcVec stack;
 592
 593  BcVec fns;
 594  BcVec fn_map;
 595
 596  BcVec vars;
 597  BcVec var_map;
 598
 599  BcVec arrs;
 600  BcVec arr_map;
 601
 602  BcNum one;
 603  BcNum last;
 604
 605  BcDig ib_num[BC_NUM_LONG_LOG10];
 606  BcDig ob_num[BC_NUM_LONG_LOG10];
 607  BcDig one_num[BC_PROG_ONE_CAP];
 608
 609} BcProgram;
 610
 611#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) (n)))
 612
 613#define BC_PROG_MAIN (0)
 614#define BC_PROG_READ (1)
 615
 616#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
 617#define BC_PROG_NUM(r, n) \
 618  ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
 619
 620typedef void (*BcProgramUnary)(BcResult*, BcNum*);
 621
 622void bc_program_addFunc(BcProgram *p, BcFunc *f, char *name);
 623size_t bc_program_insertFunc(BcProgram *p, char *name);
 624BcStatus bc_program_reset(BcProgram *p, BcStatus s);
 625BcStatus bc_program_exec(BcProgram *p);
 626
 627unsigned long bc_program_scale(BcNum *n);
 628unsigned long bc_program_len(BcNum *n);
 629
 630void bc_program_negate(BcResult *r, BcNum *n);
 631void bc_program_not(BcResult *r, BcNum *n);
 632
 633#define BC_FLAG_TTYIN (1<<7)
 634#define BC_TTYIN (toys.optflags & BC_FLAG_TTYIN)
 635
 636#define BC_S (toys.optflags & FLAG_s)
 637#define BC_W (toys.optflags & FLAG_w)
 638#define BC_L (toys.optflags & FLAG_l)
 639#define BC_I (toys.optflags & FLAG_i)
 640
 641#define BC_MAX_OBASE ((unsigned long) INT_MAX)
 642#define BC_MAX_DIM ((unsigned long) INT_MAX)
 643#define BC_MAX_SCALE ((unsigned long) UINT_MAX)
 644#define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
 645#define BC_MAX_NAME BC_MAX_STRING
 646#define BC_MAX_NUM BC_MAX_STRING
 647#define BC_MAX_EXP ((unsigned long) ULONG_MAX)
 648#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
 649
 650#define BC_SIGNAL (BC_VM->sig)
 651#define BC_SIGINT (BC_VM->sig == SIGINT)
 652
 653#ifdef SIGQUIT
 654#define BC_SIGTERM (BC_VM->sig == SIGTERM || BC_VM->sig == SIGQUIT)
 655#else // SIGQUIT
 656#define BC_SIGTERM (BC_VM->sig == SIGTERM)
 657#endif // SIGQUIT
 658
 659#define bc_vm_err(e) (bc_vm_error((e), 0))
 660#define bc_vm_verr(e, ...) (bc_vm_error((e), 0, __VA_ARGS__))
 661
 662typedef struct BcVm {
 663
 664  BcParse prs;
 665  BcProgram prog;
 666
 667  size_t nchars;
 668
 669  char *file;
 670
 671  uchar sig;
 672
 673  uint16_t line_len;
 674  uchar max_ibase;
 675
 676} BcVm;
 677
 678BcStatus bc_vm_posixError(BcError e, size_t line, ...);
 679
 680BcStatus bc_vm_error(BcError e, size_t line, ...);
 681
 682char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n";
 683
 684char bc_copyright[] =
 685  "Copyright (c) 2018 Gavin D. Howard and contributors\n"
 686  "Report bugs at: https://github.com/gavinhoward/bc\n\n"
 687  "This is free software with ABSOLUTELY NO WARRANTY.\n";
 688
 689char *bc_err_fmt = "\n%s error: ";
 690char *bc_warn_fmt = "\n%s warning: ";
 691char *bc_err_line = ":%zu";
 692
 693char *bc_errs[] = {
 694  "VM",
 695  "Parse",
 696  "Math",
 697  "Runtime",
 698  "POSIX",
 699};
 700
 701char bc_err_ids[] = {
 702  BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
 703  BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
 704  BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
 705  BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
 706  BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
 707  BC_ERR_IDX_PARSE,
 708  BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
 709  BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
 710  BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
 711  BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
 712  BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
 713  BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
 714  BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
 715  BC_ERR_IDX_POSIX,
 716};
 717
 718char *bc_err_msgs[] = {
 719
 720  "memory allocation error",
 721  "I/O error",
 722  "file is not ASCII: %s",
 723  "path is a directory: %s",
 724
 725  "end of file",
 726  "bad character (%c)",
 727  "string end could not be found",
 728  "comment end could not be found",
 729  "bad token",
 730  "name too long: must be [1, %lu]",
 731  "string too long: must be [1, %lu]",
 732  "array too long; must be [1, %lu]",
 733  "bad expression",
 734  "empty expression",
 735  "bad print statement",
 736  "bad function definition",
 737  "bad assignment: left side must be scale, ibase, "
 738    "obase, last, var, or array element",
 739  "no auto variable found",
 740  "function parameter or auto \"%s\" already exists",
 741  "block end could not be found",
 742  "cannot return a value from void function: %s()",
 743
 744  "negative number",
 745  "non integer number",
 746  "overflow; %s",
 747  "divide by zero",
 748
 749  "could not open file: %s",
 750  "number too long: must be [1, %lu]",
 751  "bad ibase; must be [%lu, %lu]",
 752  "bad obase; must be [%lu, %lu]",
 753  "bad scale; must be [%lu, %lu]",
 754  "bad read() expression",
 755  "read() call inside of a read() call",
 756  "variable is wrong type",
 757  "mismatched parameters; need %zu, have %zu",
 758  "undefined function: %s()",
 759  "cannot use a void value in an expression",
 760
 761  "POSIX does not allow names longer than 1 character, like \"%s\"",
 762  "POSIX does not allow '#' script comments",
 763  "POSIX does not allow \"%s\" as a keyword",
 764  "POSIX does not allow a period ('.') as a shortcut for the last result",
 765  "POSIX requires parentheses around return expressions",
 766  "POSIX does not allow the \"%s\" operators",
 767  "POSIX does not allow comparison operators outside if or loops",
 768  "POSIX requires zero or one comparison operator per condition",
 769  "POSIX does not allow an empty init expression in a for loop",
 770  "POSIX does not allow an empty condition expression in a for loop",
 771  "POSIX does not allow an empty update expression in a for loop",
 772  "POSIX requires the left brace be on the same line as the function header",
 773  "POSIX does not allow array references as function parameters",
 774
 775};
 776
 777char bc_func_main[] = "(main)";
 778char bc_func_read[] = "(read)";
 779
 780BcLexKeyword bc_lex_kws[] = {
 781  BC_LEX_KW_ENTRY("auto", 4, 1),
 782  BC_LEX_KW_ENTRY("break", 5, 1),
 783  BC_LEX_KW_ENTRY("continue", 8, 0),
 784  BC_LEX_KW_ENTRY("define", 6, 1),
 785  BC_LEX_KW_ENTRY("for", 3, 1),
 786  BC_LEX_KW_ENTRY("if", 2, 1),
 787  BC_LEX_KW_ENTRY("limits", 6, 0),
 788  BC_LEX_KW_ENTRY("return", 6, 1),
 789  BC_LEX_KW_ENTRY("while", 5, 1),
 790  BC_LEX_KW_ENTRY("halt", 4, 0),
 791  BC_LEX_KW_ENTRY("last", 4, 0),
 792  BC_LEX_KW_ENTRY("ibase", 5, 1),
 793  BC_LEX_KW_ENTRY("obase", 5, 1),
 794  BC_LEX_KW_ENTRY("scale", 5, 1),
 795  BC_LEX_KW_ENTRY("length", 6, 1),
 796  BC_LEX_KW_ENTRY("print", 5, 0),
 797  BC_LEX_KW_ENTRY("sqrt", 4, 1),
 798  BC_LEX_KW_ENTRY("abs", 3, 0),
 799  BC_LEX_KW_ENTRY("quit", 4, 1),
 800  BC_LEX_KW_ENTRY("read", 4, 0),
 801  BC_LEX_KW_ENTRY("else", 4, 0),
 802};
 803
 804size_t bc_lex_kws_len = sizeof(bc_lex_kws) / sizeof(BcLexKeyword);
 805
 806char *bc_parse_const1 = "1";
 807
 808// This is an array that corresponds to token types. An entry is
 809// 1 if the token is valid in an expression, 0 otherwise.
 810uint8_t bc_parse_exprs[] = {
 811  BC_PARSE_EXPR_ENTRY(0, 0, 1, 1, 1, 1, 1, 1),
 812  BC_PARSE_EXPR_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
 813  BC_PARSE_EXPR_ENTRY(1, 1, 1, 1, 1, 1, 1, 1),
 814  BC_PARSE_EXPR_ENTRY(1, 1, 1, 0, 0, 1, 1, 0),
 815  BC_PARSE_EXPR_ENTRY(0, 0, 0, 0, 0, 0, 1, 1),
 816  BC_PARSE_EXPR_ENTRY(0, 0, 0, 0, 0, 0, 0, 0),
 817  BC_PARSE_EXPR_ENTRY(0, 0, 1, 1, 1, 1, 1, 0),
 818  BC_PARSE_EXPR_ENTRY(1, 1, 0, 1, 0, 0, 0, 0)
 819};
 820
 821// This is an array of data for operators that correspond to token types.
 822uchar bc_parse_ops[] = {
 823  BC_PARSE_OP(0, 0), BC_PARSE_OP(0, 0),
 824  BC_PARSE_OP(1, 0), BC_PARSE_OP(1, 0),
 825  BC_PARSE_OP(4, 0),
 826  BC_PARSE_OP(5, 1), BC_PARSE_OP(5, 1), BC_PARSE_OP(5, 1),
 827  BC_PARSE_OP(6, 1), BC_PARSE_OP(6, 1),
 828  BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1),
 829  BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1),
 830  BC_PARSE_OP(11, 1), BC_PARSE_OP(10, 1),
 831  BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0),
 832  BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0),
 833  BC_PARSE_OP(8, 0),
 834};
 835
 836// These identify what tokens can come after expressions in certain cases.
 837BcParseNext bc_parse_next_expr =
 838  BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
 839BcParseNext bc_parse_next_param =
 840  BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
 841BcParseNext bc_parse_next_print =
 842  BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
 843BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
 844BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
 845BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
 846BcParseNext bc_parse_next_read =
 847  BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
 848
 849char bc_num_hex_digits[] = "0123456789ABCDEF";
 850
 851BcNumBinaryOp bc_program_ops[] = {
 852  bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
 853};
 854
 855BcNumBinaryOpReq bc_program_opReqs[] = {
 856  bc_num_powReq, bc_num_mulReq, bc_num_mulReq, bc_num_mulReq,
 857  bc_num_addReq, bc_num_addReq,
 858};
 859
 860BcProgramUnary bc_program_unarys[] = {
 861  bc_program_negate, bc_program_not,
 862};
 863
 864char bc_program_stdin_name[] = "<stdin>";
 865char bc_program_ready_msg[] = "ready for more input\n";
 866char bc_program_esc_chars[] = "ab\\efnqrt";
 867char bc_program_esc_seqs[] = "\a\b\\\\\f\n\"\r\t";
 868
 869char *bc_lib_name = "gen/lib.bc";
 870
 871char bc_lib[] = {
 872  115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
 873  10,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,44,
 874  118,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,105,102,40,120,
 875  60,48,41,123,10,110,61,49,10,120,61,45,120,10,125,10,115,61,115,99,97,108,101,
 876  10,114,61,54,43,115,43,46,52,52,42,120,10,115,99,97,108,101,61,115,99,97,108,
 877  101,40,120,41,43,49,10,119,104,105,108,101,40,120,62,49,41,123,10,100,43,61,
 878  49,10,120,47,61,50,10,115,99,97,108,101,43,61,49,10,125,10,115,99,97,108,101,
 879  61,114,10,114,61,120,43,49,10,112,61,120,10,102,61,118,61,49,10,102,111,114,
 880  40,105,61,50,59,118,59,43,43,105,41,123,10,112,42,61,120,10,102,42,61,105,10,
 881  118,61,112,47,102,10,114,43,61,118,10,125,10,119,104,105,108,101,40,100,45,
 882  45,41,114,42,61,114,10,115,99,97,108,101,61,115,10,105,98,97,115,101,61,98,
 883  10,105,102,40,110,41,114,101,116,117,114,110,40,49,47,114,41,10,114,101,116,
 884  117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,108,40,120,
 885  41,123,10,97,117,116,111,32,98,44,115,44,114,44,112,44,97,44,113,44,105,44,
 886  118,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,105,102,40,120,
 887  60,61,48,41,123,10,114,61,40,49,45,49,48,94,115,99,97,108,101,41,47,49,10,105,
 888  98,97,115,101,61,98,10,114,101,116,117,114,110,40,114,41,10,125,10,115,61,115,
 889  99,97,108,101,10,115,99,97,108,101,43,61,54,10,112,61,50,10,119,104,105,108,
 890  101,40,120,62,61,50,41,123,10,112,42,61,50,10,120,61,115,113,114,116,40,120,
 891  41,10,125,10,119,104,105,108,101,40,120,60,61,46,53,41,123,10,112,42,61,50,
 892  10,120,61,115,113,114,116,40,120,41,10,125,10,114,61,97,61,40,120,45,49,41,
 893  47,40,120,43,49,41,10,113,61,97,42,97,10,118,61,49,10,102,111,114,40,105,61,
 894  51,59,118,59,105,43,61,50,41,123,10,97,42,61,113,10,118,61,97,47,105,10,114,
 895  43,61,118,10,125,10,114,42,61,112,10,115,99,97,108,101,61,115,10,105,98,97,
 896  115,101,61,98,10,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,
 897  102,105,110,101,32,115,40,120,41,123,10,97,117,116,111,32,98,44,115,44,114,
 898  44,97,44,113,44,105,10,105,102,40,120,60,48,41,114,101,116,117,114,110,40,45,
 899  115,40,45,120,41,41,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,
 900  115,61,115,99,97,108,101,10,115,99,97,108,101,61,49,46,49,42,115,43,50,10,97,
 901  61,97,40,49,41,10,115,99,97,108,101,61,48,10,113,61,40,120,47,97,43,50,41,47,
 902  52,10,120,45,61,52,42,113,42,97,10,105,102,40,113,37,50,41,120,61,45,120,10,
 903  115,99,97,108,101,61,115,43,50,10,114,61,97,61,120,10,113,61,45,120,42,120,
 904  10,102,111,114,40,105,61,51,59,97,59,105,43,61,50,41,123,10,97,42,61,113,47,
 905  40,105,42,40,105,45,49,41,41,10,114,43,61,97,10,125,10,115,99,97,108,101,61,
 906  115,10,105,98,97,115,101,61,98,10,114,101,116,117,114,110,40,114,47,49,41,10,
 907  125,10,100,101,102,105,110,101,32,99,40,120,41,123,10,97,117,116,111,32,98,
 908  44,115,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,115,61,115,
 909  99,97,108,101,10,115,99,97,108,101,42,61,49,46,50,10,120,61,115,40,50,42,97,
 910  40,49,41,43,120,41,10,115,99,97,108,101,61,115,10,105,98,97,115,101,61,98,10,
 911  114,101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,
 912  97,40,120,41,123,10,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,
 913  44,116,44,102,44,105,44,117,10,98,61,105,98,97,115,101,10,105,98,97,115,101,
 914  61,65,10,110,61,49,10,105,102,40,120,60,48,41,123,10,110,61,45,49,10,120,61,
 915  45,120,10,125,10,105,102,40,115,99,97,108,101,60,54,53,41,123,10,105,102,40,
 916  120,61,61,49,41,123,10,114,61,46,55,56,53,51,57,56,49,54,51,51,57,55,52,52,
 917  56,51,48,57,54,49,53,54,54,48,56,52,53,56,49,57,56,55,53,55,50,49,48,52,57,
 918  50,57,50,51,52,57,56,52,51,55,55,54,52,53,53,50,52,51,55,51,54,49,52,56,48,
 919  47,110,10,105,98,97,115,101,61,98,10,114,101,116,117,114,110,40,114,41,10,125,
 920  10,105,102,40,120,61,61,46,50,41,123,10,114,61,46,49,57,55,51,57,53,53,53,57,
 921  56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,50,
 922  57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,56,
 923  56,57,52,48,50,47,110,10,105,98,97,115,101,61,98,10,114,101,116,117,114,110,
 924  40,114,41,10,125,10,125,10,115,61,115,99,97,108,101,10,105,102,40,120,62,46,
 925  50,41,123,10,115,99,97,108,101,43,61,53,10,97,61,97,40,46,50,41,10,125,10,115,
 926  99,97,108,101,61,115,43,51,10,119,104,105,108,101,40,120,62,46,50,41,123,10,
 927  109,43,61,49,10,120,61,40,120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,125,
 928  10,114,61,117,61,120,10,102,61,45,120,42,120,10,116,61,49,10,102,111,114,40,
 929  105,61,51,59,116,59,105,43,61,50,41,123,10,117,42,61,102,10,116,61,117,47,105,
 930  10,114,43,61,116,10,125,10,115,99,97,108,101,61,115,10,105,98,97,115,101,61,
 931  98,10,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,41,10,125,10,
 932  100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,97,117,116,111,32,98,
 933  44,115,44,111,44,97,44,105,44,118,44,102,10,98,61,105,98,97,115,101,10,105,
 934  98,97,115,101,61,65,10,115,61,115,99,97,108,101,10,115,99,97,108,101,61,48,
 935  10,110,47,61,49,10,105,102,40,110,60,48,41,123,10,110,61,45,110,10,111,61,110,
 936  37,50,10,125,10,97,61,49,10,102,111,114,40,105,61,50,59,105,60,61,110,59,43,
 937  43,105,41,97,42,61,105,10,115,99,97,108,101,61,49,46,53,42,115,10,97,61,40,
 938  120,94,110,41,47,50,94,110,47,97,10,114,61,118,61,49,10,102,61,45,120,42,120,
 939  47,52,10,115,99,97,108,101,43,61,108,101,110,103,116,104,40,97,41,45,115,99,
 940  97,108,101,40,97,41,10,102,111,114,40,105,61,49,59,118,59,43,43,105,41,123,
 941  10,118,61,118,42,102,47,105,47,40,110,43,105,41,10,114,43,61,118,10,125,10,
 942  115,99,97,108,101,61,115,10,105,98,97,115,101,61,98,10,105,102,40,111,41,97,
 943  61,45,97,10,114,101,116,117,114,110,40,97,42,114,47,49,41,10,125,10,0
 944};
 945
 946static void bc_vec_grow(BcVec *v, size_t n) {
 947  size_t cap = v->cap * 2;
 948  while (cap < v->len + n) cap *= 2;
 949  v->v = xrealloc(v->v, v->size * cap);
 950  v->cap = cap;
 951}
 952
 953void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor) {
 954  v->size = esize;
 955  v->cap = BC_VEC_START_CAP;
 956  v->len = 0;
 957  v->dtor = dtor;
 958  v->v = xmalloc(esize * BC_VEC_START_CAP);
 959}
 960
 961void bc_vec_expand(BcVec *v, size_t req) {
 962  if (v->cap < req) {
 963    v->v = xrealloc(v->v, v->size * req);
 964    v->cap = req;
 965  }
 966}
 967
 968void bc_vec_npop(BcVec *v, size_t n) {
 969  if (!v->dtor) v->len -= n;
 970  else {
 971    size_t len = v->len - n;
 972    while (v->len > len) v->dtor(v->v + (v->size * --v->len));
 973  }
 974}
 975
 976void bc_vec_npush(BcVec *v, size_t n, void *data) {
 977  if (v->len + n > v->cap) bc_vec_grow(v, n);
 978  memcpy(v->v + (v->size * v->len), data, v->size * n);
 979  v->len += n;
 980}
 981
 982void bc_vec_push(BcVec *v, void *data) {
 983  bc_vec_npush(v, 1, data);
 984}
 985
 986void bc_vec_pushByte(BcVec *v, uchar data) {
 987  bc_vec_push(v, &data);
 988}
 989
 990void bc_vec_pushIndex(BcVec *v, size_t idx) {
 991
 992  uchar amt, nums[sizeof(size_t)];
 993
 994  for (amt = 0; idx; ++amt) {
 995    nums[amt] = (uchar) idx;
 996    idx &= ((size_t) ~(UCHAR_MAX));
 997    idx >>= sizeof(uchar) * CHAR_BIT;
 998  }
 999
1000  bc_vec_push(v, &amt);
1001  bc_vec_npush(v, amt, nums);
1002}
1003
1004static void bc_vec_pushAt(BcVec *v, void *data, size_t idx) {
1005
1006  if (idx == v->len) bc_vec_push(v, data);
1007  else {
1008
1009    char *ptr;
1010
1011    if (v->len == v->cap) bc_vec_grow(v, 1);
1012
1013    ptr = v->v + v->size * idx;
1014
1015    memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1016    memmove(ptr, data, v->size);
1017  }
1018}
1019
1020void bc_vec_string(BcVec *v, size_t len, char *str) {
1021
1022  bc_vec_npop(v, v->len);
1023  bc_vec_expand(v, len + 1);
1024  memcpy(v->v, str, len);
1025  v->len = len;
1026
1027  bc_vec_pushByte(v, '\0');
1028}
1029
1030void bc_vec_concat(BcVec *v, char *str) {
1031
1032  size_t len;
1033
1034  if (!v->len) bc_vec_pushByte(v, '\0');
1035
1036  len = v->len + strlen(str);
1037
1038  if (v->cap < len) bc_vec_grow(v, len - v->len);
1039  strcat(v->v, str);
1040
1041  v->len = len;
1042}
1043
1044void bc_vec_empty(BcVec *v) {
1045  bc_vec_npop(v, v->len);
1046  bc_vec_pushByte(v, '\0');
1047}
1048
1049void* bc_vec_item(BcVec *v, size_t idx) {
1050  return v->v + v->size * idx;
1051}
1052
1053void* bc_vec_item_rev(BcVec *v, size_t idx) {
1054  return v->v + v->size * (v->len - idx - 1);
1055}
1056
1057void bc_vec_free(void *vec) {
1058  BcVec *v = (BcVec*) vec;
1059  bc_vec_npop(v, v->len);
1060  free(v->v);
1061}
1062
1063static size_t bc_map_find(BcVec *v, BcId *ptr) {
1064
1065  size_t low = 0, high = v->len;
1066
1067  while (low < high) {
1068
1069    size_t mid = (low + high) / 2;
1070    BcId *id = bc_vec_item(v, mid);
1071    int result = bc_id_cmp(ptr, id);
1072
1073    if (!result) return mid;
1074    else if (result < 0) high = mid;
1075    else low = mid + 1;
1076  }
1077
1078  return low;
1079}
1080
1081int bc_map_insert(BcVec *v, BcId *ptr, size_t *i) {
1082
1083  *i = bc_map_find(v, ptr);
1084
1085  if (*i == v->len) bc_vec_push(v, ptr);
1086  else if (!bc_id_cmp(ptr, bc_vec_item(v, *i))) return 0;
1087  else bc_vec_pushAt(v, ptr, *i);
1088
1089  return 1;
1090}
1091
1092size_t bc_map_index(BcVec *v, BcId *ptr) {
1093  size_t i = bc_map_find(v, ptr);
1094  if (i >= v->len) return SIZE_MAX;
1095  return bc_id_cmp(ptr, bc_vec_item(v, i)) ? SIZE_MAX : i;
1096}
1097
1098static int bc_read_binary(char *buf, size_t size) {
1099
1100  size_t i;
1101
1102  for (i = 0; i < size; ++i) {
1103    if (BC_READ_BIN_CHAR(buf[i])) return 1;
1104  }
1105
1106  return 0;
1107}
1108
1109BcStatus bc_read_chars(BcVec *vec, char *prompt) {
1110
1111  int i;
1112  signed char c = 0;
1113
1114  bc_vec_npop(vec, vec->len);
1115
1116  if (BC_TTYIN && !BC_S) {
1117    fputs(prompt, stderr);
1118    fflush(stderr);
1119  }
1120
1121  while (!BC_SIGNAL && c != '\n') {
1122
1123    i = fgetc(stdin);
1124
1125    if (i == EOF) {
1126
1127      if (errno == EINTR) {
1128
1129        if (BC_SIGTERM) return BC_STATUS_SIGNAL;
1130
1131        BC_VM->sig = 0;
1132
1133        if (BC_TTYIN) {
1134          fputs(bc_program_ready_msg, stderr);
1135          if (!BC_S) fputs(prompt, stderr);
1136          fflush(stderr);
1137        }
1138        else return BC_STATUS_SIGNAL;
1139
1140        continue;
1141      }
1142
1143      bc_vec_pushByte(vec, '\0');
1144      return BC_STATUS_EOF;
1145    }
1146
1147    c = (signed char) i;
1148    bc_vec_push(vec, &c);
1149  }
1150
1151  bc_vec_pushByte(vec, '\0');
1152
1153  return BC_SIGNAL ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1154}
1155
1156BcStatus bc_read_line(BcVec *vec, char *prompt) {
1157
1158  BcStatus s;
1159
1160  // We are about to output to stderr, so flush stdout to
1161  // make sure that we don't get the outputs mixed up.
1162  fflush(stdout);
1163
1164  s = bc_read_chars(vec, prompt);
1165  if (s && s != BC_STATUS_EOF) return s;
1166  if (bc_read_binary(vec->v, vec->len - 1))
1167    return bc_vm_verr(BC_ERROR_VM_BIN_FILE, bc_program_stdin_name);
1168
1169  return BC_STATUS_SUCCESS;
1170}
1171
1172BcStatus bc_read_file(char *path, char **buf) {
1173
1174  BcError e = BC_ERROR_VM_IO_ERR;
1175  FILE *f;
1176  size_t size, read;
1177  long res;
1178  struct stat pstat;
1179
1180  f = fopen(path, "r");
1181  if (!f) return bc_vm_verr(BC_ERROR_EXEC_FILE_ERR, path);
1182  if (fstat(fileno(f), &pstat) == -1) goto malloc_err;
1183
1184  if (S_ISDIR(pstat.st_mode)) {
1185    e = BC_ERROR_VM_PATH_DIR;
1186    goto malloc_err;
1187  }
1188
1189  if (fseek(f, 0, SEEK_END) == -1) goto malloc_err;
1190  res = ftell(f);
1191  if (res < 0) goto malloc_err;
1192  if (fseek(f, 0, SEEK_SET) == -1) goto malloc_err;
1193
1194  size = (size_t) res;
1195  *buf = xmalloc(size + 1);
1196
1197  read = fread(*buf, 1, size, f);
1198  if (read != size) goto read_err;
1199
1200  (*buf)[size] = '\0';
1201
1202  if (bc_read_binary(*buf, size)) {
1203    e = BC_ERROR_VM_BIN_FILE;
1204    goto read_err;
1205  }
1206
1207  fclose(f);
1208
1209  return BC_STATUS_SUCCESS;
1210
1211read_err:
1212  free(*buf);
1213malloc_err:
1214  fclose(f);
1215  return bc_vm_verr(e, path);
1216}
1217
1218static void bc_num_setToZero(BcNum *n, size_t scale) {
1219  n->len = 0;
1220  n->neg = 0;
1221  n->rdx = scale;
1222}
1223
1224static void bc_num_zero(BcNum *n) {
1225  bc_num_setToZero(n, 0);
1226}
1227
1228void bc_num_one(BcNum *n) {
1229  bc_num_setToZero(n, 0);
1230  n->len = 1;
1231  n->num[0] = 1;
1232}
1233
1234void bc_num_ten(BcNum *n) {
1235  bc_num_setToZero(n, 0);
1236  n->len = 2;
1237  n->num[0] = 0;
1238  n->num[1] = 1;
1239}
1240
1241static size_t bc_num_log10(size_t i) {
1242  size_t len;
1243  for (len = 1; i; i /= 10, ++len);
1244  return len;
1245}
1246
1247static BcStatus bc_num_subArrays(BcDig *a, BcDig *b, size_t len)
1248{
1249  size_t i, j;
1250  for (i = 0; !BC_SIGNAL && i < len; ++i) {
1251    for (a[i] -= b[i], j = 0; !BC_SIGNAL && a[i + j] < 0;) {
1252      a[i + j++] += 10;
1253      a[i + j] -= 1;
1254    }
1255  }
1256  return BC_SIGNAL ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1257}
1258
1259static ssize_t bc_num_compare(BcDig *a, BcDig *b, size_t len)
1260{
1261  size_t i;
1262  int c = 0;
1263  for (i = len - 1; !BC_SIGNAL && i < len && !(c = a[i] - b[i]); --i);
1264  return BC_NUM_NEG(i + 1, c < 0);
1265}
1266
1267ssize_t bc_num_cmp(BcNum *a, BcNum *b) {
1268
1269  size_t i, min, a_int, b_int, diff;
1270  BcDig *max_num, *min_num;
1271  int a_max, neg = 0;
1272  ssize_t cmp;
1273
1274  if (a == b) return 0;
1275  if (!a->len) return BC_NUM_NEG(b->len != 0, !b->neg);
1276  if (!b->len) return BC_NUM_CMP_ZERO(a);
1277  if (a->neg) {
1278    if (b->neg) neg = 1;
1279    else return -1;
1280  }
1281  else if (b->neg) return 1;
1282
1283  a_int = BC_NUM_INT(a);
1284  b_int = BC_NUM_INT(b);
1285  a_int -= b_int;
1286  a_max = (a->rdx > b->rdx);
1287
1288  if (a_int) return (ssize_t) a_int;
1289
1290  if (a_max) {
1291    min = b->rdx;
1292    diff = a->rdx - b->rdx;
1293    max_num = a->num + diff;
1294    min_num = b->num;
1295  }
1296  else {
1297    min = a->rdx;
1298    diff = b->rdx - a->rdx;
1299    max_num = b->num + diff;
1300    min_num = a->num;
1301  }
1302
1303  cmp = bc_num_compare(max_num, min_num, b_int + min);
1304  if (cmp) return BC_NUM_NEG(cmp, (!a_max) != neg);
1305
1306  for (max_num -= diff, i = diff - 1; !BC_SIGNAL && i < diff; --i) {
1307    if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1308  }
1309
1310  return 0;
1311}
1312
1313static void bc_num_clean(BcNum *n) {
1314  while (n->len && !n->num[n->len - 1]) --n->len;
1315  if (!n->len) n->neg = 0;
1316  else if (n->len < n->rdx) n->len = n->rdx;
1317}
1318
1319void bc_num_truncate(BcNum *n, size_t places) {
1320
1321  if (!places) return;
1322
1323  n->rdx -= places;
1324
1325  if (n->len) {
1326    n->len -= places;
1327    memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1328    bc_num_clean(n);
1329  }
1330}
1331
1332static void bc_num_extend(BcNum *n, size_t places) {
1333
1334  size_t len = n->len + places;
1335
1336  if (!places) return;
1337
1338  if (n->cap < len) bc_num_expand(n, len);
1339
1340  memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1341  memset(n->num, 0, sizeof(BcDig) * places);
1342
1343  if (n->len) n->len += places;
1344
1345  n->rdx += places;
1346}
1347
1348static void bc_num_retireMul(BcNum *n, size_t scale, int neg1, int neg2) {
1349
1350  if (n->rdx < scale) bc_num_extend(n, scale - n->rdx);
1351  else bc_num_truncate(n, n->rdx - scale);
1352
1353  bc_num_clean(n);
1354  if (n->len) n->neg = (!neg1 != !neg2);
1355}
1356
1357static void bc_num_split(BcNum *n, size_t idx, BcNum *a, BcNum *b) {
1358
1359  if (idx < n->len) {
1360
1361    b->len = n->len - idx;
1362    a->len = idx;
1363    a->rdx = b->rdx = 0;
1364
1365    memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1366    memcpy(a->num, n->num, idx * sizeof(BcDig));
1367
1368    bc_num_clean(b);
1369  }
1370  else bc_num_copy(a, n);
1371
1372  bc_num_clean(a);
1373}
1374
1375static BcStatus bc_num_shift(BcNum *n, size_t places) {
1376
1377  if (!places || !n->len) return BC_STATUS_SUCCESS;
1378  if (places + n->len > BC_MAX_NUM)
1379    return bc_vm_verr(BC_ERROR_MATH_OVERFLOW, "shifted left too far");
1380
1381  if (n->rdx >= places) n->rdx -= places;
1382  else {
1383    bc_num_extend(n, places - n->rdx);
1384    n->rdx = 0;
1385  }
1386
1387  bc_num_clean(n);
1388
1389  return BC_STATUS_SUCCESS;
1390}
1391
1392static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale) {
1393
1394  BcNum one;
1395  BcDig num[2];
1396
1397  one.cap = 2;
1398  one.num = num;
1399  bc_num_one(&one);
1400
1401  return bc_num_div(&one, a, b, scale);
1402}
1403
1404static unsigned int bc_num_addDigit(BcDig *num, unsigned int d, unsigned int c)
1405{
1406  d += c;
1407  *num = (BcDig) (d % 10);
1408  return d / 10;
1409}
1410
1411static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *c, size_t sub) {
1412
1413  BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1414  size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1415  unsigned int carry;
1416
1417  // Because this function doesn't need to use scale (per the bc spec),
1418  // I am hijacking it to say whether it's doing an add or a subtract.
1419
1420  if (!a->len) {
1421    bc_num_copy(c, b);
1422    if (sub && c->len) c->neg = !c->neg;
1423    return BC_STATUS_SUCCESS;
1424  }
1425  if (!b->len) {
1426    bc_num_copy(c, a);
1427    return BC_STATUS_SUCCESS;
1428  }
1429
1430  c->neg = a->neg;
1431  c->rdx = maxof(a->rdx, b->rdx);
1432  min_rdx = minof(a->rdx, b->rdx);
1433
1434  if (a->rdx > b->rdx) {
1435    diff = a->rdx - b->rdx;
1436    ptr = a->num;
1437    ptr_a = a->num + diff;
1438    ptr_b = b->num;
1439  }
1440  else {
1441    diff = b->rdx - a->rdx;
1442    ptr = b->num;
1443    ptr_a = a->num;
1444    ptr_b = b->num + diff;
1445  }
1446
1447  for (ptr_c = c->num, i = 0; i < diff; ++i) ptr_c[i] = ptr[i];
1448
1449  c->len = diff;
1450  ptr_c += diff;
1451  a_int = BC_NUM_INT(a);
1452  b_int = BC_NUM_INT(b);
1453
1454  if (a_int > b_int) {
1455    min_int = b_int;
1456    max = a_int;
1457    ptr = ptr_a;
1458  }
1459  else {
1460    min_int = a_int;
1461    max = b_int;
1462    ptr = ptr_b;
1463  }
1464
1465  for (carry = 0, i = 0; !BC_SIGNAL && i < min_rdx + min_int; ++i) {
1466    unsigned int in = (unsigned int) (ptr_a[i] + ptr_b[i]);
1467    carry = bc_num_addDigit(ptr_c + i, in, carry);
1468  }
1469
1470  for (; !BC_SIGNAL && i < max + min_rdx; ++i)
1471    carry = bc_num_addDigit(ptr_c + i, (unsigned int) ptr[i], carry);
1472
1473  c->len += i;
1474
1475  if (carry) c->num[c->len++] = (BcDig) carry;
1476
1477  return BC_SIGNAL ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1478}
1479
1480static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) {
1481
1482  BcStatus s;
1483  ssize_t cmp;
1484  BcNum *minuend, *subtrahend;
1485  size_t start;
1486  int aneg, bneg, neg;
1487
1488  // Because this function doesn't need to use scale (per the bc spec),
1489  // I am hijacking it to say whether it's doing an add or a subtract.
1490
1491  if (!a->len) {
1492    bc_num_copy(c, b);
1493    if (sub && c->len) c->neg = !c->neg;
1494    return BC_STATUS_SUCCESS;
1495  }
1496  if (!b->len) {
1497    bc_num_copy(c, a);
1498    return BC_STATUS_SUCCESS;
1499  }
1500
1501  aneg = a->neg;
1502  bneg = b->neg;
1503  a->neg = b->neg = 0;
1504
1505  cmp = bc_num_cmp(a, b);
1506
1507  a->neg = aneg;
1508  b->neg = bneg;
1509
1510  if (!cmp) {
1511    bc_num_setToZero(c, maxof(a->rdx, b->rdx));
1512    return BC_STATUS_SUCCESS;
1513  }
1514
1515  if (cmp > 0) {
1516    neg = a->neg;
1517    minuend = a;
1518    subtrahend = b;
1519  }
1520  else {
1521    neg = b->neg;
1522    if (sub) neg = !neg;
1523    minuend = b;
1524    subtrahend = a;
1525  }
1526
1527  bc_num_copy(c, minuend);
1528  c->neg = neg;
1529
1530  if (c->rdx < subtrahend->rdx) {
1531    bc_num_extend(c, subtrahend->rdx - c->rdx);
1532    start = 0;
1533  }
1534  else start = c->rdx - subtrahend->rdx;
1535
1536  s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1537
1538  bc_num_clean(c);
1539
1540  return s;
1541}
1542
1543static BcStatus bc_num_k(BcNum *a, BcNum *b, BcNum *c) {
1544
1545  BcStatus s;
1546  size_t max = maxof(a->len, b->len), max2 = (max + 1) / 2;
1547  BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1548  int aone = BC_NUM_ONE(a);
1549
1550  // This is here because the function is recursive.
1551  if (BC_SIGNAL) return BC_STATUS_SIGNAL;
1552  if (!a->len || !b->len) {
1553    bc_num_zero(c);
1554    return BC_STATUS_SUCCESS;
1555  }
1556  if (aone || BC_NUM_ONE(b)) {
1557    bc_num_copy(c, aone ? b : a);
1558    return BC_STATUS_SUCCESS;
1559  }
1560
1561  if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1562      a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1563  {
1564    size_t i, j, len;
1565    unsigned int carry;
1566    BcDig *ptr_c;
1567
1568    bc_num_expand(c, a->len + b->len + 1);
1569
1570    ptr_c = c->num;
1571    memset(ptr_c, 0, sizeof(BcDig) * c->cap);
1572    c->len = len = 0;
1573
1574    for (i = 0; !BC_SIGNAL && i < b->len; ++i) {
1575
1576      BcDig *ptr = ptr_c + i;
1577
1578      carry = 0;
1579
1580      for (j = 0; !BC_SIGNAL && j < a->len; ++j) {
1581        unsigned int in = (uchar) ptr[j];
1582        in += ((unsigned int) a->num[j]) * ((unsigned int) b->num[i]);
1583        carry = bc_num_addDigit(ptr + j, in, carry);
1584      }
1585
1586      ptr[j] += (BcDig) carry;
1587      len = maxof(len, i + j + (carry != 0));
1588    }
1589
1590    c->len = len;
1591
1592    return BC_SIGNAL ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1593  }
1594
1595  bc_num_init(&l1, max);
1596  bc_num_init(&h1, max);
1597  bc_num_init(&l2, max);
1598  bc_num_init(&h2, max);
1599  bc_num_init(&m1, max);
1600  bc_num_init(&m2, max);
1601  bc_num_init(&z0, max);
1602  bc_num_init(&z1, max);
1603  bc_num_init(&z2, max);
1604  bc_num_init(&temp, max + max);
1605
1606  bc_num_split(a, max2, &l1, &h1);
1607  bc_num_split(b, max2, &l2, &h2);
1608
1609  s = bc_num_add(&h1, &l1, &m1, 0);
1610  if (s) goto err;
1611  s = bc_num_add(&h2, &l2, &m2, 0);
1612  if (s) goto err;
1613
1614  s = bc_num_k(&h1, &h2, &z0);
1615  if (s) goto err;
1616  s = bc_num_k(&m1, &m2, &z1);
1617  if (s) goto err;
1618  s = bc_num_k(&l1, &l2, &z2);
1619  if (s) goto err;
1620
1621  s = bc_num_sub(&z1, &z0, &temp, 0);
1622  if (s) goto err;
1623  s = bc_num_sub(&temp, &z2, &z1, 0);
1624  if (s) goto err;
1625
1626  s = bc_num_shift(&z0, max2 * 2);
1627  if (s) goto err;
1628  s = bc_num_shift(&z1, max2);
1629  if (s) goto err;
1630  s = bc_num_add(&z0, &z1, &temp, 0);
1631  if (s) goto err;
1632  s = bc_num_add(&temp, &z2, c, 0);
1633
1634err:
1635  bc_num_free(&temp);
1636  bc_num_free(&z2);
1637  bc_num_free(&z1);
1638  bc_num_free(&z0);
1639  bc_num_free(&m2);
1640  bc_num_free(&m1);
1641  bc_num_free(&h2);
1642  bc_num_free(&l2);
1643  bc_num_free(&h1);
1644  bc_num_free(&l1);
1645  return s;
1646}
1647
1648static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
1649
1650  BcStatus s;
1651  BcNum cpa, cpb;
1652  size_t maxrdx = maxof(a->rdx, b->rdx);
1653
1654  scale = maxof(scale, a->rdx);
1655  scale = maxof(scale, b->rdx);
1656  scale = minof(a->rdx + b->rdx, scale);
1657  maxrdx = maxof(maxrdx, scale);
1658
1659  bc_num_createCopy(&cpa, a);
1660  bc_num_createCopy(&cpb, b);
1661
1662  cpa.neg = cpb.neg = 0;
1663
1664  s = bc_num_shift(&cpa, maxrdx);
1665  if (s) goto err;
1666  s = bc_num_shift(&cpb, maxrdx);
1667  if (s) goto err;
1668  s = bc_num_k(&cpa, &cpb, c);
1669  if (s) goto err;
1670
1671  maxrdx += scale;
1672  bc_num_expand(c, c->len + maxrdx);
1673
1674  if (c->len < maxrdx) {
1675    memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1676    c->len += maxrdx;
1677  }
1678
1679  c->rdx = maxrdx;
1680  bc_num_retireMul(c, scale, a->neg, b->neg);
1681
1682err:
1683  bc_num_free(&cpb);
1684  bc_num_free(&cpa);
1685  return s;
1686}
1687
1688static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
1689
1690  BcStatus s = BC_STATUS_SUCCESS;
1691  BcDig *n, *p, q;
1692  size_t len, end, i;
1693  BcNum cp;
1694  int zero = 1;
1695
1696  if (!b->len) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO);
1697  if (!a->len) {
1698    bc_num_setToZero(c, scale);
1699    return BC_STATUS_SUCCESS;
1700  }
1701  if (BC_NUM_ONE(b)) {
1702    bc_num_copy(c, a);
1703    bc_num_retireMul(c, scale, a->neg, b->neg);
1704    return BC_STATUS_SUCCESS;
1705  }
1706
1707  bc_num_init(&cp, bc_num_mulReq(a, b, scale));
1708  bc_num_copy(&cp, a);
1709  len = b->len;
1710
1711  if (len > cp.len) {
1712    bc_num_expand(&cp, len + 2);
1713    bc_num_extend(&cp, len - cp.len);
1714  }
1715
1716  if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1717  cp.rdx -= b->rdx;
1718  if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1719
1720  if (b->rdx == b->len) {
1721    for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1722    len -= i - 1;
1723  }
1724
1725  if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1726
1727  // We want an extra zero in front to make things simpler.
1728  cp.num[cp.len++] = 0;
1729  end = cp.len - len;
1730
1731  bc_num_expand(c, cp.len);
1732
1733  memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1734  c->rdx = cp.rdx;
1735  c->len = cp.len;
1736  p = b->num;
1737
1738  for (i = end - 1; !BC_SIGNAL && !s && i < end; --i) {
1739    n = cp.num + i;
1740    for (q = 0; !s && (n[len] || bc_num_compare(n, p, len) >= 0); ++q)
1741      s = bc_num_subArrays(n, p, len);
1742    c->num[i] = q;
1743  }
1744
1745  if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
1746  bc_num_free(&cp);
1747
1748  return s;
1749}
1750
1751static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale,
1752                  size_t ts)
1753{
1754  BcStatus s;
1755  BcNum temp;
1756  int neg;
1757
1758  if (!b->len) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO);
1759  if (!a->len) {
1760    bc_num_setToZero(c, ts);
1761    bc_num_setToZero(d, ts);
1762    return BC_STATUS_SUCCESS;
1763  }
1764
1765  bc_num_init(&temp, d->cap);
1766  bc_num_d(a, b, c, scale);
1767
1768  if (scale) scale = ts;
1769
1770  s = bc_num_m(c, b, &temp, scale);
1771  if (s) goto err;
1772  s = bc_num_sub(a, &temp, d, scale);
1773  if (s) goto err;
1774
1775  if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1776
1777  neg = d->neg;
1778  bc_num_retireMul(d, ts, a->neg, b->neg);
1779  d->neg = neg;
1780
1781err:
1782  bc_num_free(&temp);
1783  return s;
1784}
1785
1786static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
1787
1788  BcStatus s;
1789  BcNum c1;
1790  size_t ts = maxof(scale + b->rdx, a->rdx), len = bc_num_mulReq(a, b, ts);
1791
1792  bc_num_init(&c1, len);
1793  s = bc_num_r(a, b, &c1, c, scale, ts);
1794  bc_num_free(&c1);
1795
1796  return s;
1797}
1798
1799static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
1800
1801  BcStatus s = BC_STATUS_SUCCESS;
1802  BcNum copy;
1803  unsigned long pow = 0;
1804  size_t i, powrdx, resrdx;
1805  int neg, zero;
1806
1807  if (b->rdx) return bc_vm_err(BC_ERROR_MATH_NON_INTEGER);
1808
1809  if (!b->len) {
1810    bc_num_one(c);
1811    return BC_STATUS_SUCCESS;
1812  }
1813  if (!a->len) {
1814    bc_num_setToZero(c, scale);
1815    return BC_STATUS_SUCCESS;
1816  }
1817  if (BC_NUM_ONE(b)) {
1818    if (!b->neg) bc_num_copy(c, a);
1819    else s = bc_num_inv(a, c, scale);
1820    return s;
1821  }
1822
1823  neg = b->neg;
1824  b->neg = 0;
1825  s = bc_num_ulong(b, &pow);
1826  b->neg = neg;
1827  if (s) return s;
1828
1829  bc_num_createCopy(&copy, a);
1830
1831  if (!neg) scale = minof(a->rdx * pow, maxof(scale, a->rdx));
1832
1833  for (powrdx = a->rdx; !BC_SIGNAL && !(pow & 1); pow >>= 1) {
1834    powrdx <<= 1;
1835    s = bc_num_mul(&copy, &copy, &copy, powrdx);
1836    if (s) goto err;
1837  }
1838
1839  if (BC_SIGNAL) {
1840    s = BC_STATUS_SIGNAL;
1841    goto err;
1842  }
1843
1844  bc_num_copy(c, &copy);
1845  resrdx = powrdx;
1846
1847  while (!BC_SIGNAL && (pow >>= 1)) {
1848
1849    powrdx <<= 1;
1850    s = bc_num_mul(&copy, &copy, &copy, powrdx);
1851    if (s) goto err;
1852
1853    if (pow & 1) {
1854      resrdx += powrdx;
1855      s = bc_num_mul(c, &copy, c, resrdx);
1856      if (s) goto err;
1857    }
1858  }
1859
1860  if (neg) {
1861    s = bc_num_inv(c, c, scale);
1862    if (s) goto err;
1863  }
1864
1865  if (BC_SIGNAL) {
1866    s = BC_STATUS_SIGNAL;
1867    goto err;
1868  }
1869
1870  if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1871
1872  // We can't use bc_num_clean() here.
1873  for (zero = 1, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1874  if (zero) bc_num_setToZero(c, scale);
1875
1876err:
1877  bc_num_free(&copy);
1878  return s;
1879}
1880
1881static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1882                              BcNumBinaryOp op, size_t req)
1883{
1884  BcStatus s;
1885  BcNum num2, *ptr_a, *ptr_b;
1886  int init = 0;
1887
1888  if (c == a) {
1889    ptr_a = &num2;
1890    memcpy(ptr_a, c, sizeof(BcNum));
1891    init = 1;
1892  }
1893  else ptr_a = a;
1894
1895  if (c == b) {
1896    ptr_b = &num2;
1897    if (c != a) {
1898      memcpy(ptr_b, c, sizeof(BcNum));
1899      init = 1;
1900    }
1901  }
1902  else ptr_b = b;
1903
1904  if (init) bc_num_init(c, req);
1905  else bc_num_expand(c, req);
1906
1907  s = op(ptr_a, ptr_b, c, scale);
1908
1909  if (init) bc_num_free(&num2);
1910
1911  return s;
1912}
1913
1914static unsigned long bc_num_parseChar(char c, size_t base_t) {
1915
1916  if (isupper(c)) {
1917    c = BC_NUM_NUM_LETTER(c);
1918    c = ((size_t) c) >= base_t ? (char) base_t - 1 : c;
1919  }
1920  else c -= '0';
1921
1922  return (unsigned long) (uchar) c;
1923}
1924
1925static void bc_num_parseDecimal(BcNum *n, char *val) {
1926
1927  size_t len, i;
1928  char *ptr;
1929  int zero = 1;
1930
1931  for (i = 0; val[i] == '0'; ++i);
1932
1933  val += i;
1934  len = strlen(val);
1935
1936  if (len) {
1937    for (i = 0; zero && i < len; ++i) zero = (val[i] == '0') || val[i] == '.';
1938    bc_num_expand(n, len);
1939  }
1940
1941  ptr = strchr(val, '.');
1942
1943  // Explicitly test for NULL here to produce either a 0 or 1.
1944  n->rdx = (size_t) ((ptr != NULL) * ((val + len) - (ptr + 1)));
1945
1946  if (!zero) {
1947    for (i = len - 1; i < len; ++n->len, --i) {
1948
1949      char c = val[i];
1950
1951      if (c == '.') n->len -= 1;
1952      else {
1953        if (isupper(c)) c = '9';
1954        n->num[n->len] = c - '0';
1955      }
1956    }
1957  }
1958}
1959
1960static BcStatus bc_num_parseBase(BcNum *n, char *val,
1961                                 BcNum *base, size_t base_t)
1962{
1963  BcStatus s = BC_STATUS_SUCCESS;
1964  BcNum temp, mult, result;
1965  BcDig c = 0;
1966  int zero = 1;
1967  unsigned long v;
1968  size_t i, digits, len = strlen(val);
1969
1970  for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
1971  if (zero) return BC_STATUS_SUCCESS;
1972
1973  bc_num_init(&temp, BC_NUM_LONG_LOG10);
1974  bc_num_init(&mult, BC_NUM_LONG_LOG10);
1975
1976  for (i = 0; i < len && (c = val[i]) && c != '.'; ++i) {
1977
1978    v = bc_num_parseChar(c, base_t);
1979
1980    s = bc_num_mul(n, base, &mult, 0);
1981    if (s) goto int_err;
1982    bc_num_ulong2num(&temp, v);
1983    s = bc_num_add(&mult, &temp, n, 0);
1984    if (s) goto int_err;
1985  }
1986
1987  if (i == len && !(c = val[i])) goto int_err;
1988
1989  bc_num_init(&result, base->len);
1990  bc_num_one(&mult);
1991
1992  for (i += 1, digits = 0; i < len && (c = val[i]); ++i, ++digits) {
1993
1994    v = bc_num_parseChar(c, base_t);
1995
1996    s = bc_num_mul(&result, base, &result, 0);
1997    if (s) goto err;
1998    bc_num_ulong2num(&temp, v);
1999    s = bc_num_add(&result, &temp, &result, 0);
2000    if (s) goto err;
2001    s = bc_num_mul(&mult, base, &mult, 0);
2002    if (s) goto err;
2003  }
2004
2005  s = bc_num_div(&result, &mult, &result, digits);
2006  if (s) goto err;
2007  s = bc_num_add(n, &result, n, digits);
2008  if (s) goto err;
2009
2010  if (n->len) {
2011    if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2012  }
2013  else bc_num_zero(n);
2014
2015err:
2016  bc_num_free(&result);
2017int_err:
2018  bc_num_free(&mult);
2019  bc_num_free(&temp);
2020  return s;
2021}
2022
2023static void bc_num_printNewline() {
2024  if (BC_VM->nchars >= (size_t) (BC_VM->line_len - 1)) {
2025    putchar('\\');
2026    putchar('\n');
2027    BC_VM->nchars = 0;
2028  }
2029}
2030
2031static void bc_num_printDigits(size_t n, size_t len, int rdx) {
2032
2033  size_t exp, pow;
2034
2035  bc_num_printNewline();
2036  putchar(rdx ? '.' : ' ');
2037  ++BC_VM->nchars;
2038
2039  bc_num_printNewline();
2040  for (exp = 0, pow = 1; exp < len - 1; ++exp, pow *= 10);
2041
2042  for (exp = 0; exp < len; pow /= 10, ++BC_VM->nchars, ++exp) {
2043    size_t dig;
2044    bc_num_printNewline();
2045    dig = n / pow;
2046    n -= dig * pow;
2047    putchar(((uchar) dig) + '0');
2048  }
2049}
2050
2051static void bc_num_printHex(size_t n, size_t len, int rdx) {
2052
2053  if (rdx) {
2054    bc_num_printNewline();
2055    putchar('.');
2056    BC_VM->nchars += 1;
2057  }
2058
2059  bc_num_printNewline();
2060  putchar(bc_num_hex_digits[n]);
2061  BC_VM->nchars += len;
2062}
2063
2064static void bc_num_printDecimal(BcNum *n) {
2065
2066  size_t i, rdx = n->rdx - 1;
2067
2068  if (n->neg) putchar('-');
2069  BC_VM->nchars += n->neg;
2070
2071  for (i = n->len - 1; i < n->len; --i)
2072    bc_num_printHex((size_t) n->num[i], 1, i == rdx);
2073}
2074
2075static BcStatus bc_num_printNum(BcNum *n, BcNum *base,
2076                                size_t len, BcNumDigitOp print)
2077{
2078  BcStatus s;
2079  BcVec stack;
2080  BcNum intp, fracp, digit, frac_len;
2081  unsigned long dig, *ptr;
2082  size_t i;
2083  int radix;
2084
2085  if (!n->len) {
2086    print(0, len, 0);
2087    return BC_STATUS_SUCCESS;
2088  }
2089
2090  bc_vec_init(&stack, sizeof(unsigned long), NULL);
2091  bc_num_init(&fracp, n->rdx);
2092  bc_num_init(&digit, len);
2093  bc_num_init(&frac_len, BC_NUM_INT(n));
2094  bc_num_one(&frac_len);
2095  bc_num_createCopy(&intp, n);
2096
2097  bc_num_truncate(&intp, intp.rdx);
2098  s = bc_num_sub(n, &intp, &fracp, 0);
2099  if (s) goto err;
2100
2101  while (intp.len) {
2102    s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2103    if (s) goto err;
2104    s = bc_num_ulong(&digit, &dig);
2105    if (s) goto err;
2106    bc_vec_push(&stack, &dig);
2107  }
2108
2109  for (i = 0; i < stack.len; ++i) {
2110    ptr = bc_vec_item_rev(&stack, i);
2111    print(*ptr, len, 0);
2112  }
2113
2114  if (!n->rdx) goto err;
2115
2116  for (radix = 1; frac_len.len <= n->rdx; radix = 0) {
2117    s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2118    if (s) goto err;
2119    s = bc_num_ulong(&fracp, &dig);
2120    if (s) goto err;
2121    bc_num_ulong2num(&intp, dig);
2122    s = bc_num_sub(&fracp, &intp, &fracp, 0);
2123    if (s) goto err;
2124    print(dig, len, radix);
2125    s = bc_num_mul(&frac_len, base, &frac_len, 0);
2126    if (s) goto err;
2127  }
2128
2129err:
2130  bc_num_free(&frac_len);
2131  bc_num_free(&digit);
2132  bc_num_free(&fracp);
2133  bc_num_free(&intp);
2134  bc_vec_free(&stack);
2135  return s;
2136}
2137
2138static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t) {
2139
2140  BcStatus s;
2141  size_t width;
2142  BcNumDigitOp print;
2143  int neg = n->neg;
2144
2145  if (neg) putchar('-');
2146  BC_VM->nchars += neg;
2147
2148  n->neg = 0;
2149
2150  if (base_t <= BC_NUM_MAX_POSIX_IBASE) {
2151    width = 1;
2152    print = bc_num_printHex;
2153  }
2154  else {
2155    width = bc_num_log10(base_t - 1) - 1;
2156    print = bc_num_printDigits;
2157  }
2158
2159  s = bc_num_printNum(n, base, width, print);
2160  n->neg = neg;
2161
2162  return s;
2163}
2164
2165void bc_num_setup(BcNum *n, BcDig *num, size_t cap) {
2166  n->num = num;
2167  n->cap = cap;
2168  n->rdx = n->len = 0;
2169  n->neg = 0;
2170}
2171
2172void bc_num_init(BcNum *n, size_t req) {
2173  req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2174  bc_num_setup(n, xmalloc(req), req);
2175}
2176
2177void bc_num_expand(BcNum *n, size_t req) {
2178  req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2179  if (req > n->cap) {
2180    n->num = xrealloc(n->num, req);
2181    n->cap = req;
2182  }
2183}
2184
2185void bc_num_free(void *num) {
2186  free(((BcNum*) num)->num);
2187}
2188
2189void bc_num_copy(BcNum *d, BcNum *s) {
2190  if (d == s) return;
2191  bc_num_expand(d, s->len);
2192  d->len = s->len;
2193  d->neg = s->neg;
2194  d->rdx = s->rdx;
2195  memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2196}
2197
2198void bc_num_createCopy(BcNum *d, BcNum *s) {
2199  bc_num_init(d, s->len);
2200  bc_num_copy(d, s);
2201}
2202
2203void bc_num_createFromUlong(BcNum *n, unsigned long val) {
2204  bc_num_init(n, BC_NUM_LONG_LOG10);
2205  bc_num_ulong2num(n, val);
2206}
2207
2208BcStatus bc_num_parse(BcNum *n, char *val,
2209                      BcNum *base, size_t base_t, int letter)
2210{
2211  BcStatus s = BC_STATUS_SUCCESS;
2212
2213  if (letter) bc_num_ulong2num(n, bc_num_parseChar(val[0], BC_NUM_MAX_LBASE));
2214  else if (base_t == 10) bc_num_parseDecimal(n, val);
2215  else s = bc_num_parseBase(n, val, base, base_t);
2216
2217  return s;
2218}
2219
2220BcStatus bc_num_print(BcNum *n, BcNum *base,
2221                      size_t base_t, int newline)
2222{
2223  BcStatus s = BC_STATUS_SUCCESS;
2224
2225  bc_num_printNewline();
2226
2227  if (!n->len) bc_num_printHex(0, 1, 0);
2228  else if (base_t == 10) bc_num_printDecimal(n);
2229  else s = bc_num_printBase(n, base, base_t);
2230
2231  if (!s && newline) {
2232    putchar('\n');
2233    BC_VM->nchars = 0;
2234  }
2235
2236  return s;
2237}
2238
2239BcStatus bc_num_ulong(BcNum *n, unsigned long *result) {
2240
2241  size_t i;
2242  unsigned long pow, r;
2243
2244  *result = 0;
2245
2246  if (n->neg) return bc_vm_err(BC_ERROR_MATH_NEGATIVE);
2247
2248  for (r = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2249
2250    unsigned long prev = r, powprev = pow;
2251
2252    r += ((unsigned long) n->num[i]) * pow;
2253    pow *= 10;
2254
2255    if (r < prev || pow < powprev)
2256      return bc_vm_verr(BC_ERROR_MATH_OVERFLOW, "number cannot fit");
2257  }
2258
2259  *result = r;
2260
2261  return BC_STATUS_SUCCESS;
2262}
2263
2264void bc_num_ulong2num(BcNum *n, unsigned long val) {
2265
2266  size_t len;
2267  BcDig *ptr;
2268  unsigned long i;
2269
2270  bc_num_zero(n);
2271
2272  if (!val) return;
2273
2274  len = bc_num_log10(ULONG_MAX);
2275  bc_num_expand(n, len);
2276  for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2277}
2278
2279size_t bc_num_addReq(BcNum *a, BcNum *b, size_t scale) {
2280  BC_UNUSED(scale);
2281  return maxof(a->rdx, b->rdx) + maxof(BC_NUM_INT(a), BC_NUM_INT(b)) + 1;
2282}
2283
2284size_t bc_num_mulReq(BcNum *a, BcNum *b, size_t scale) {
2285  return BC_NUM_INT(a) + BC_NUM_INT(b) + maxof(scale, a->rdx + b->rdx) + 1;
2286}
2287
2288size_t bc_num_powReq(BcNum *a, BcNum *b, size_t scale) {
2289  BC_UNUSED(scale);
2290  return BC_NUM_PREQ(a, b);
2291}
2292
2293BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2294  BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2295  BC_UNUSED(scale);
2296  return bc_num_binary(a, b, c, 0, op, bc_num_addReq(a, b, scale));
2297}
2298
2299BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2300  BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2301  BC_UNUSED(scale);
2302  return bc_num_binary(a, b, c, 1, op, bc_num_addReq(a, b, scale));
2303}
2304
2305BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2306  return bc_num_binary(a, b, c, scale, bc_num_m, bc_num_mulReq(a, b, scale));
2307}
2308
2309BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2310  return bc_num_binary(a, b, c, scale, bc_num_d, bc_num_mulReq(a, b, scale));
2311}
2312
2313BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2314  return bc_num_binary(a, b, c, scale, bc_num_rem, bc_num_mulReq(a, b, scale));
2315}
2316
2317BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2318  return bc_num_binary(a, b, c, scale, bc_num_p, BC_NUM_PREQ(a, b));
2319}
2320
2321BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale) {
2322
2323  BcStatus s = BC_STATUS_SUCCESS;
2324  BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2325  size_t pow, len, digs, digs1, resrdx, times = 0;
2326  ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2327  BcDig half_digs[2];
2328
2329  bc_num_init(b, maxof(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1);
2330
2331  if (!a->len) {
2332    bc_num_setToZero(b, scale);
2333    return BC_STATUS_SUCCESS;
2334  }
2335  if (a->neg) return bc_vm_err(BC_ERROR_MATH_NEGATIVE);
2336  if (BC_NUM_ONE(a)) {
2337    bc_num_one(b);
2338    bc_num_extend(b, scale);
2339    return BC_STATUS_SUCCESS;
2340  }
2341
2342  scale = maxof(scale, a->rdx) + 1;
2343  len = a->len + scale;
2344
2345  bc_num_init(&num1, len);
2346  bc_num_init(&num2, len);
2347  bc_num_setup(&half, half_digs, sizeof(half_digs) / sizeof(BcDig));
2348
2349  bc_num_one(&half);
2350  half.num[0] = 5;
2351  half.rdx = 1;
2352
2353  bc_num_init(&f, len);
2354  bc_num_init(&fprime, len);
2355
2356  x0 = &num1;
2357  x1 = &num2;
2358
2359  bc_num_one(x0);
2360  pow = BC_NUM_INT(a);
2361
2362  if (pow) {
2363
2364    if (pow & 1) x0->num[0] = 2;
2365    else x0->num[0] = 6;
2366
2367    pow -= 2 - (pow & 1);
2368
2369    bc_num_extend(x0, pow);
2370
2371    // Make sure to move the radix back.
2372    x0->rdx -= pow;
2373  }
2374
2375  x0->rdx = digs = digs1 = 0;
2376  resrdx = scale + 2;
2377  len = BC_NUM_INT(x0) + resrdx - 1;
2378
2379  while (!BC_SIGNAL && (cmp || digs < len)) {
2380
2381    s = bc_num_div(a, x0, &f, resrdx);
2382    if (s) goto err;
2383    s = bc_num_add(x0, &f, &fprime, resrdx);
2384    if (s) goto err;
2385    s = bc_num_mul(&fprime, &half, x1, resrdx);
2386    if (s) goto err;
2387
2388    cmp = bc_num_cmp(x1, x0);
2389    digs = x1->len - (unsigned long long) llabs(cmp);
2390
2391    if (cmp == cmp2 && digs == digs1) times += 1;
2392    else times = 0;
2393
2394    resrdx += times > 4;
2395
2396    cmp2 = cmp1;
2397    cmp1 = cmp;
2398    digs1 = digs;
2399
2400    temp = x0;
2401    x0 = x1;
2402    x1 = temp;
2403  }
2404
2405  if (BC_SIGNAL) {
2406    s = BC_STATUS_SIGNAL;
2407    goto err;
2408  }
2409
2410  bc_num_copy(b, x0);
2411  scale -= 1;
2412  if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2413
2414err:
2415  bc_num_free(&fprime);
2416  bc_num_free(&f);
2417  bc_num_free(&num2);
2418  bc_num_free(&num1);
2419  return s;
2420}
2421
2422BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) {
2423
2424  BcStatus s;
2425  BcNum num2, *ptr_a;
2426  int init = 0;
2427  size_t ts = maxof(scale + b->rdx, a->rdx), len = bc_num_mulReq(a, b, ts);
2428
2429  if (c == a) {
2430    memcpy(&num2, c, sizeof(BcNum));
2431    ptr_a = &num2;
2432    bc_num_init(c, len);
2433    init = 1;
2434  }
2435  else {
2436    ptr_a = a;
2437    bc_num_expand(c, len);
2438  }
2439
2440  s = bc_num_r(ptr_a, b, c, d, scale, ts);
2441
2442  if (init) bc_num_free(&num2);
2443
2444  return s;
2445}
2446
2447int bc_id_cmp(BcId *e1, BcId *e2) {
2448  return strcmp(e1->name, e2->name);
2449}
2450
2451void bc_id_free(void *id) {
2452  free(((BcId*) id)->name);
2453}
2454
2455void bc_string_free(void *string) {
2456  free(*((char**) string));
2457}
2458
2459BcStatus bc_func_insert(BcFunc *f, char *name, BcType type, size_t line) {
2460
2461  BcId a;
2462  size_t i;
2463
2464  for (i = 0; i < f->autos.len; ++i) {
2465    BcId *id = bc_vec_item(&f->autos, i);
2466    if (!strcmp(name, id->name) && type == (BcType) id->idx)
2467      return bc_vm_error(BC_ERROR_PARSE_DUP_LOCAL, line, name);
2468  }
2469
2470  a.idx = type;
2471  a.name = name;
2472
2473  bc_vec_push(&f->autos, &a);
2474
2475  return BC_STATUS_SUCCESS;
2476}
2477
2478void bc_func_init(BcFunc *f, char *name) {
2479  bc_vec_init(&f->code, sizeof(uchar), NULL);
2480  bc_vec_init(&f->strs, sizeof(char*), bc_string_free);
2481  bc_vec_init(&f->consts, sizeof(char*), bc_string_free);
2482  bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2483  bc_vec_init(&f->labels, sizeof(size_t), NULL);
2484  f->nparams = 0;
2485  f->voidfn = 0;
2486  f->name = name;
2487}
2488
2489void bc_func_reset(BcFunc *f) {
2490  bc_vec_npop(&f->code, f->code.len);
2491  bc_vec_npop(&f->strs, f->strs.len);
2492  bc_vec_npop(&f->consts, f->consts.len);
2493  bc_vec_npop(&f->autos, f->autos.len);
2494  bc_vec_npop(&f->labels, f->labels.len);
2495  f->nparams = 0;
2496  f->voidfn = 0;
2497}
2498
2499void bc_func_free(void *func) {
2500  BcFunc *f = (BcFunc*) func;
2501  bc_vec_free(&f->code);
2502  bc_vec_free(&f->strs);
2503  bc_vec_free(&f->consts);
2504  bc_vec_free(&f->autos);
2505  bc_vec_free(&f->labels);
2506}
2507
2508void bc_array_init(BcVec *a, int nums) {
2509  if (nums) bc_vec_init(a, sizeof(BcNum), bc_num_free);
2510  else bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2511  bc_array_expand(a, 1);
2512}
2513
2514void bc_array_copy(BcVec *d, BcVec *s) {
2515
2516  size_t i;
2517
2518  bc_vec_npop(d, d->len);
2519  bc_vec_expand(d, s->cap);
2520  d->len = s->len;
2521
2522  for (i = 0; i < s->len; ++i) {
2523    BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2524    bc_num_createCopy(dnum, snum);
2525  }
2526}
2527
2528void bc_array_expand(BcVec *a, size_t len) {
2529
2530  if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2531    BcNum n;
2532    while (len > a->len) {
2533      bc_num_init(&n, BC_NUM_DEF_SIZE);
2534      bc_vec_push(a, &n);
2535    }
2536  }
2537  else {
2538    BcVec v;
2539    while (len > a->len) {
2540      bc_array_init(&v, 1);
2541      bc_vec_push(a, &v);
2542    }
2543  }
2544}
2545
2546void bc_result_free(void *result) {
2547
2548  BcResult *r = (BcResult*) result;
2549
2550  switch (r->t) {
2551
2552    case BC_RESULT_TEMP:
2553    case BC_RESULT_IBASE:
2554    case BC_RESULT_SCALE:
2555    case BC_RESULT_OBASE:
2556    {
2557      bc_num_free(&r->d.n);
2558      break;
2559    }
2560
2561    case BC_RESULT_VAR:
2562    case BC_RESULT_ARRAY:
2563    case BC_RESULT_ARRAY_ELEM:
2564    {
2565      free(r->d.id.name);
2566      break;
2567    }
2568
2569    case BC_RESULT_STR:
2570    case BC_RESULT_CONSTANT:
2571    case BC_RESULT_VOID:
2572    case BC_RESULT_ONE:
2573    case BC_RESULT_LAST:
2574    {
2575      // Do nothing.
2576      break;
2577    }
2578  }
2579}
2580
2581BcStatus bc_lex_invalidChar(BcLex *l, char c) {
2582  l->t = BC_LEX_INVALID;
2583  return bc_lex_verr(l, BC_ERROR_PARSE_CHAR, c);
2584}
2585
2586void bc_lex_lineComment(BcLex *l) {
2587  l->t = BC_LEX_WHITESPACE;
2588  while (l->i < l->len && l->buf[l->i] != '\n') ++l->i;
2589}
2590
2591BcStatus bc_lex_comment(BcLex *l) {
2592
2593  size_t i, nlines = 0;
2594  char *buf = l->buf;
2595  int end = 0;
2596  char c;
2597
2598  l->t = BC_LEX_WHITESPACE;
2599
2600  for (i = ++l->i; !end; i += !end) {
2601
2602    for (; (c = buf[i]) && c != '*'; ++i) nlines += (c == '\n');
2603
2604    if (!c || buf[i + 1] == '\0') {
2605      l->i = i;
2606      return bc_lex_err(l, BC_ERROR_PARSE_COMMENT);
2607    }
2608
2609    end = buf[i + 1] == '/';
2610  }
2611
2612  l->i = i + 2;
2613  l->line += nlines;
2614
2615  return BC_STATUS_SUCCESS;
2616}
2617
2618void bc_lex_whitespace(BcLex *l) {
2619  char c;
2620  l->t = BC_LEX_WHITESPACE;
2621  for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2622}
2623
2624BcStatus bc_lex_number(BcLex *l, char start) {
2625
2626  char *buf = l->buf + l->i;
2627  size_t i;
2628  char last_valid, c;
2629  int last_pt, pt = (start == '.');
2630
2631  l->t = BC_LEX_NUMBER;
2632  last_valid = 'Z';
2633
2634  bc_vec_npop(&l->str, l->str.len);
2635  bc_vec_push(&l->str, &start);
2636
2637  for (i = 0; (c = buf[i]) && (BC_LEX_NUM_CHAR(c, last_valid, pt) ||
2638                               (c == '\\' && buf[i + 1] == '\n')); ++i)
2639  {
2640    if (c == '\\') {
2641
2642      if (buf[i + 1] == '\n') {
2643
2644        i += 2;
2645
2646        // Make sure to eat whitespace at the beginning of the line.
2647        while(isspace(buf[i]) && buf[i] != '\n') ++i;
2648
2649        c = buf[i];
2650
2651        if (!BC_LEX_NUM_CHAR(c, last_valid, pt)) break;
2652      }
2653      else break;
2654    }
2655
2656    last_pt = (c == '.');
2657    if (pt && last_pt) break;
2658    pt = pt || last_pt;
2659
2660    bc_vec_push(&l->str, &c);
2661  }
2662
2663  if (l->str.len - pt > BC_MAX_NUM)
2664    return bc_lex_verr(l, BC_ERROR_EXEC_NUM_LEN, BC_MAX_NUM);
2665
2666  bc_vec_pushByte(&l->str, '\0');
2667  l->i += i;
2668
2669  return BC_STATUS_SUCCESS;
2670}
2671
2672BcStatus bc_lex_name(BcLex *l) {
2673
2674  size_t i = 0;
2675  char *buf = l->buf + l->i - 1;
2676  char c = buf[i];
2677
2678  l->t = BC_LEX_NAME;
2679
2680  while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2681
2682  if (i > BC_MAX_NAME)
2683    return bc_lex_verr(l, BC_ERROR_EXEC_NAME_LEN, BC_MAX_NAME);
2684
2685  bc_vec_string(&l->str, i, buf);
2686
2687  // Increment the index. We minus 1 because it has already been incremented.
2688  l->i += i - 1;
2689
2690  return BC_STATUS_SUCCESS;
2691}
2692
2693void bc_lex_init(BcLex *l) {
2694  bc_vec_init(&l->str, sizeof(char), NULL);
2695}
2696
2697void bc_lex_free(BcLex *l) {
2698  bc_vec_free(&l->str);
2699}
2700
2701void bc_lex_file(BcLex *l, char *file) {
2702  l->line = 1;
2703  BC_VM->file = file;
2704}
2705
2706BcStatus bc_lex_next(BcLex *l) {
2707
2708  BcStatus s;
2709
2710  l->last = l->t;
2711  l->line += (l->i != 0 && l->buf[l->i - 1] == '\n');
2712
2713  if (l->last == BC_LEX_EOF) return bc_lex_err(l, BC_ERROR_PARSE_EOF);
2714
2715  l->t = BC_LEX_EOF;
2716
2717  if (l->i == l->len) return BC_STATUS_SUCCESS;
2718
2719  // Loop until failure or we don't have whitespace. This
2720  // is so the parser doesn't get inundated with whitespace.
2721  do {
2722    s = bc_lex_token(l);
2723  } while (!s && l->t == BC_LEX_WHITESPACE);
2724
2725  return s;
2726}
2727
2728BcStatus bc_lex_text(BcLex *l, char *text) {
2729  l->buf = text;
2730  l->i = 0;
2731  l->len = strlen(text);
2732  l->t = l->last = BC_LEX_INVALID;
2733  return bc_lex_next(l);
2734}
2735
2736static BcStatus bc_lex_identifier(BcLex *l) {
2737
2738  BcStatus s;
2739  size_t i;
2740  char *buf = l->buf + l->i - 1;
2741
2742  for (i = 0; i < bc_lex_kws_len; ++i) {
2743
2744    BcLexKeyword *kw = bc_lex_kws + i;
2745    size_t len = BC_LEX_KW_LEN(kw);
2746
2747    if (!strncmp(buf, kw->name, len) && !isalnum(buf[len]) && buf[len] != '_')
2748    {
2749      l->t = BC_LEX_KEY_AUTO + (BcLexType) i;
2750
2751      if (!BC_LEX_KW_POSIX(kw)) {
2752        s = bc_lex_vposixErr(l, BC_ERROR_POSIX_KW, kw->name);
2753        if (s) return s;
2754      }
2755
2756      // We minus 1 because the index has already been incremented.
2757      l->i += len - 1;
2758      return BC_STATUS_SUCCESS;
2759    }
2760  }
2761
2762  s = bc_lex_name(l);
2763  if (s) return s;
2764
2765  if (l->str.len - 1 > 1) s = bc_lex_vposixErr(l, BC_ERROR_POSIX_NAME_LEN, buf);
2766
2767  return s;
2768}
2769
2770static BcStatus bc_lex_string(BcLex *l) {
2771
2772  size_t len, nlines = 0, i = l->i;
2773  char *buf = l->buf;
2774  char c;
2775
2776  l->t = BC_LEX_STR;
2777
2778  for (; (c = buf[i]) && c != '"'; ++i) nlines += c == '\n';
2779
2780  if (c == '\0') {
2781    l->i = i;
2782    return bc_lex_err(l, BC_ERROR_PARSE_STRING);
2783  }
2784
2785  len = i - l->i;
2786
2787  if (len > BC_MAX_STRING)
2788    return bc_lex_verr(l, BC_ERROR_EXEC_STRING_LEN, BC_MAX_STRING);
2789
2790  bc_vec_string(&l->str, len, l->buf + l->i);
2791
2792  l->i = i + 1;
2793  l->line += nlines;
2794
2795  return BC_STATUS_SUCCESS;
2796}
2797
2798static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without) {
2799  if (l->buf[l->i] == '=') {
2800    ++l->i;
2801    l->t = with;
2802  }
2803  else l->t = without;
2804}
2805
2806BcStatus bc_lex_token(BcLex *l) {
2807
2808  BcStatus s = BC_STATUS_SUCCESS;
2809  char c = l->buf[l->i++], c2;
2810
2811  // This is the workhorse of the lexer.
2812  switch (c) {
2813
2814    case '\0':
2815    case '\n':
2816    {
2817      l->t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
2818      break;
2819    }
2820
2821    case '\t':
2822    case '\v':
2823    case '\f':
2824    case '\r':
2825    case ' ':
2826    {
2827      bc_lex_whitespace(l);
2828      break;
2829    }
2830
2831    case '!':
2832    {
2833      bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
2834
2835      if (l->t == BC_LEX_OP_BOOL_NOT) {
2836        s = bc_lex_vposixErr(l, BC_ERROR_POSIX_BOOL, "!");
2837        if (s) return s;
2838      }
2839
2840      break;
2841    }
2842
2843    case '"':
2844    {
2845      s = bc_lex_string(l);
2846      break;
2847    }
2848
2849    case '#':
2850    {
2851      s = bc_lex_posixErr(l, BC_ERROR_POSIX_COMMENT);
2852      if (s) return s;
2853
2854      bc_lex_lineComment(l);
2855
2856      break;
2857    }
2858
2859    case '%':
2860    {
2861      bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
2862      break;
2863    }
2864
2865    case '&':
2866    {
2867      c2 = l->buf[l->i];
2868      if (c2 == '&') {
2869
2870        s = bc_lex_vposixErr(l, BC_ERROR_POSIX_BOOL, "&&");
2871        if (s) return s;
2872
2873        ++l->i;
2874        l->t = BC_LEX_OP_BOOL_AND;
2875      }
2876      else s = bc_lex_invalidChar(l, c);
2877
2878      break;
2879    }
2880    case '(':
2881    case ')':
2882    {
2883      l->t = (BcLexType) (c - '(' + BC_LEX_LPAREN);
2884      break;
2885    }
2886
2887    case '*':
2888    {
2889      bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
2890      break;
2891    }
2892
2893    case '+':
2894    {
2895      c2 = l->buf[l->i];
2896      if (c2 == '+') {
2897        ++l->i;
2898        l->t = BC_LEX_OP_INC;
2899      }
2900      else bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
2901      break;
2902    }
2903
2904    case ',':
2905    {
2906      l->t = BC_LEX_COMMA;
2907      break;
2908    }
2909
2910    case '-':
2911    {
2912      c2 = l->buf[l->i];
2913      if (c2 == '-') {
2914        ++l->i;
2915        l->t = BC_LEX_OP_DEC;
2916      }
2917      else bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
2918      break;
2919    }
2920
2921    case '.':
2922    {
2923      c2 = l->buf[l->i];
2924      if (BC_LEX_NUM_CHAR(c2, 'Z', 1)) s = bc_lex_number(l, c);
2925      else {
2926        l->t = BC_LEX_KEY_LAST;
2927        s = bc_lex_posixErr(l, BC_ERROR_POSIX_DOT);
2928      }
2929      break;
2930    }
2931
2932    case '/':
2933    {
2934      c2 = l->buf[l->i];
2935      if (c2 =='*') s = bc_lex_comment(l);
2936      else bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
2937      break;
2938    }
2939
2940    case '0':
2941    case '1':
2942    case '2':
2943    case '3':
2944    case '4':
2945    case '5':
2946    case '6':
2947    case '7':
2948    case '8':
2949    case '9':
2950    case 'A':
2951    case 'B':
2952    case 'C':
2953    case 'D':
2954    case 'E':
2955    case 'F':
2956    // Apparently, GNU bc (and maybe others) allows any uppercase letter as a
2957    // number. When single digits, they act like the ones above. When multi-
2958    // digit, any letter above the input base is automatically set to the
2959    // biggest allowable digit in the input base.
2960    case 'G':
2961    case 'H':
2962    case 'I':
2963    case 'J':
2964    case 'K':
2965    case 'L':
2966    case 'M':
2967    case 'N':
2968    case 'O':
2969    case 'P':
2970    case 'Q':
2971    case 'R':
2972    case 'S':
2973    case 'T':
2974    case 'U':
2975    case 'V':
2976    case 'W':
2977    case 'X':
2978    case 'Y':
2979    case 'Z':
2980    {
2981      s = bc_lex_number(l, c);
2982      break;
2983    }
2984
2985    case ';':
2986    {
2987      l->t = BC_LEX_SCOLON;
2988      break;
2989    }
2990
2991    case '<':
2992    {
2993      bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
2994      break;
2995    }
2996
2997    case '=':
2998    {
2999      bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3000      break;
3001    }
3002
3003    case '>':
3004    {
3005      bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3006      break;
3007    }
3008
3009    case '[':
3010    case ']':
3011    {
3012      l->t = (BcLexType) (c - '[' + BC_LEX_LBRACKET);
3013      break;
3014    }
3015
3016    case '\\':
3017    {
3018      if (l->buf[l->i] == '\n') {
3019        l->t = BC_LEX_WHITESPACE;
3020        ++l->i;
3021      }
3022      else s = bc_lex_invalidChar(l, c);
3023      break;
3024    }
3025
3026    case '^':
3027    {
3028      bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3029      break;
3030    }
3031
3032    case 'a':
3033    case 'b':
3034    case 'c':
3035    case 'd':
3036    case 'e':
3037    case 'f':
3038    case 'g':
3039    case 'h':
3040    case 'i':
3041    case 'j':
3042    case 'k':
3043    case 'l':
3044    case 'm':
3045    case 'n':
3046    case 'o':
3047    case 'p':
3048    case 'q':
3049    case 'r':
3050    case 's':
3051    case 't':
3052    case 'u':
3053    case 'v':
3054    case 'w':
3055    case 'x':
3056    case 'y':
3057    case 'z':
3058    {
3059      s = bc_lex_identifier(l);
3060      break;
3061    }
3062
3063    case '{':
3064    case '}':
3065    {
3066      l->t = (BcLexType) (c - '{' + BC_LEX_LBRACE);
3067      break;
3068    }
3069
3070    case '|':
3071    {
3072      c2 = l->buf[l->i];
3073
3074      if (c2 == '|') {
3075
3076        s = bc_lex_vposixErr(l, BC_ERROR_POSIX_BOOL, "||");
3077        if (s) return s;
3078
3079        ++l->i;
3080        l->t = BC_LEX_OP_BOOL_OR;
3081      }
3082      else s = bc_lex_invalidChar(l, c);
3083
3084      break;
3085    }
3086
3087    default:
3088    {
3089      s = bc_lex_invalidChar(l, c);
3090      break;
3091    }
3092  }
3093
3094  return s;
3095}
3096
3097void bc_parse_updateFunc(BcParse *p, size_t fidx) {
3098  p->fidx = fidx;
3099  p->func = bc_vec_item(&p->prog->fns, fidx);
3100}
3101
3102void bc_parse_pushName(BcParse *p, char *name) {
3103  bc_vec_npush(&p->func->code, strlen(name), name);
3104  bc_parse_push(p, BC_PARSE_STREND);
3105}
3106
3107void bc_parse_pushIndex(BcParse *p, size_t idx) {
3108  bc_vec_pushIndex(&p->func->code, idx);
3109}
3110
3111void bc_parse_addId(BcParse *p, uchar inst) {
3112
3113  BcFunc *f = p->func;
3114  BcVec *v = inst == BC_INST_NUM ? &f->consts : &f->strs;
3115  size_t idx = v->len;
3116  char *str = xstrdup(p->l.str.v);
3117
3118  bc_vec_push(v, &str);
3119  bc_parse_updateFunc(p, p->fidx);
3120  bc_parse_push(p, inst);
3121  bc_parse_pushIndex(p, idx);
3122}
3123
3124BcStatus bc_parse_text(BcParse *p, char *text) {
3125  // Make sure the pointer isn't invalidated.
3126  p->func = bc_vec_item(&p->prog->fns, p->fidx);
3127  return bc_lex_text(&p->l, text);
3128}
3129
3130BcStatus bc_parse_reset(BcParse *p, BcStatus s) {
3131
3132  if (p->fidx != BC_PROG_MAIN) {
3133    bc_func_reset(p->func);
3134    bc_parse_updateFunc(p, BC_PROG_MAIN);
3135  }
3136
3137  p->l.i = p->l.len;
3138  p->l.t = BC_LEX_EOF;
3139  p->auto_part = 0;
3140
3141  bc_vec_npop(&p->flags, p->flags.len - 1);
3142  bc_vec_npop(&p->exits, p->exits.len);
3143  bc_vec_npop(&p->conds, p->conds.len);
3144  bc_vec_npop(&p->ops, p->ops.len);
3145
3146  return bc_program_reset(p->prog, s);
3147}
3148
3149void bc_parse_free(BcParse *p) {
3150  bc_vec_free(&p->flags);
3151  bc_vec_free(&p->exits);
3152  bc_vec_free(&p->conds);
3153  bc_vec_free(&p->ops);
3154  bc_lex_free(&p->l);
3155}
3156
3157void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
3158{
3159  uint16_t flag = 0;
3160  bc_vec_init(&p->flags, sizeof(uint16_t), NULL);
3161  bc_vec_push(&p->flags, &flag);
3162  bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3163  bc_vec_init(&p->conds, sizeof(size_t), NULL);
3164  bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3165
3166  bc_lex_init(&p->l);
3167
3168  p->prog = prog;
3169  p->auto_part = 0;
3170  bc_parse_updateFunc(p, func);
3171}
3172
3173static BcStatus bc_parse_else(BcParse *p);
3174static BcStatus bc_parse_stmt(BcParse *p);
3175static BcStatus bc_parse_expr_err(BcParse *p, uint8_t flags, BcParseNext next);
3176
3177static int bc_parse_inst_isLeaf(BcInst t) {
3178  return (t >= BC_INST_NUM && t <= BC_INST_ABS) ||
3179          t == BC_INST_INC_POST || t == BC_INST_DEC_POST;
3180}
3181
3182static int bc_parse_isDelimiter(BcParse *p) {
3183
3184  BcLexType t = p->l.t;
3185  int good = 0;
3186
3187  if (BC_PARSE_DELIMITER(t)) return 1;
3188
3189  if (t == BC_LEX_KEY_ELSE) {
3190
3191    size_t i;
3192    uint16_t *fptr = NULL, flags = BC_PARSE_FLAG_ELSE;
3193
3194    for (i = 0; i < p->flags.len && BC_PARSE_BLOCK_STMT(flags); ++i) {
3195      fptr = bc_vec_item_rev(&p->flags, i);
3196      flags = *fptr;
3197      if ((flags & BC_PARSE_FLAG_BRACE) && p->l.last != BC_LEX_RBRACE)
3198        return 0;
3199    }
3200
3201    good = ((flags & BC_PARSE_FLAG_IF) != 0);
3202  }
3203  else if (t == BC_LEX_RBRACE) {
3204
3205    size_t i;
3206
3207    for (i = 0; !good && i < p->flags.len; ++i) {
3208      uint16_t *fptr = bc_vec_item_rev(&p->flags, i);
3209      good = (((*fptr) & BC_PARSE_FLAG_BRACE) != 0);
3210    }
3211  }
3212
3213  return good;
3214}
3215
3216static void bc_parse_setLabel(BcParse *p) {
3217
3218  BcFunc *func = p->func;
3219  BcInstPtr *ip = bc_vec_top(&p->exits);
3220  size_t *label;
3221
3222  label = bc_vec_item(&func->labels, ip->idx);
3223  *label = func->code.len;
3224
3225  bc_vec_pop(&p->exits);
3226}
3227
3228static void bc_parse_createLabel(BcParse *p, size_t idx) {
3229  bc_vec_push(&p->func->labels, &idx);
3230}
3231
3232static void bc_parse_createCondLabel(BcParse *p, size_t idx) {
3233  bc_parse_createLabel(p, p->func->code.len);
3234  bc_vec_push(&p->conds, &idx);
3235}
3236
3237static void bc_parse_createExitLabel(BcParse *p, size_t idx, int loop) {
3238
3239  BcInstPtr ip;
3240
3241  ip.func = loop;
3242  ip.idx = idx;
3243  ip.len = 0;
3244
3245  bc_vec_push(&p->exits, &ip);
3246  bc_parse_createLabel(p, SIZE_MAX);
3247}
3248
3249static size_t bc_parse_addFunc(BcParse *p, char *name) {
3250
3251  size_t idx = bc_program_insertFunc(p->prog, name);
3252
3253  // Make sure that this pointer was not invalidated.
3254  p->func = bc_vec_item(&p->prog->fns, p->fidx);
3255
3256  return idx;
3257}
3258
3259static void bc_parse_operator(BcParse *p, BcLexType type,
3260                              size_t start, size_t *nexprs)
3261{
3262  BcLexType t;
3263  uchar l, r = BC_PARSE_OP_PREC(type);
3264  uchar left = BC_PARSE_OP_LEFT(type);
3265
3266  while (p->ops.len > start) {
3267
3268    t = BC_PARSE_TOP_OP(p);
3269    if (t == BC_LEX_LPAREN) break;
3270
3271    l = BC_PARSE_OP_PREC(t);
3272    if (l >= r && (l != r || !left)) break;
3273
3274    bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3275    bc_vec_pop(&p->ops);
3276    *nexprs -= !BC_PARSE_OP_PREFIX(t);
3277  }
3278
3279  bc_vec_push(&p->ops, &type);
3280}
3281
3282static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs) {
3283
3284  BcLexType top;
3285
3286  if (p->ops.len <= ops_bgn) return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
3287
3288  while ((top = BC_PARSE_TOP_OP(p)) != BC_LEX_LPAREN) {
3289
3290    bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3291
3292    bc_vec_pop(&p->ops);
3293    *nexs -= !BC_PARSE_OP_PREFIX(top);
3294
3295    if (p->ops.len <= ops_bgn) return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
3296  }
3297
3298  bc_vec_pop(&p->ops);
3299
3300  return bc_lex_next(&p->l);
3301}
3302
3303static BcStatus bc_parse_params(BcParse *p, uint8_t flags) {
3304
3305  BcStatus s;
3306  int comma = 0;
3307  size_t nparams;
3308
3309  s = bc_lex_next(&p->l);
3310  if (s) return s;
3311
3312  for (nparams = 0; p->l.t != BC_LEX_RPAREN; ++nparams) {
3313
3314    flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3315    s = bc_parse_expr_status(p, flags, bc_parse_next_param);
3316    if (s) return s;
3317
3318    comma = p->l.t == BC_LEX_COMMA;
3319    if (comma) {
3320      s = bc_lex_next(&p->l);
3321      if (s) return s;
3322    }
3323  }
3324
3325  if (comma) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3326  bc_parse_push(p, BC_INST_CALL);
3327  bc_parse_pushIndex(p, nparams);
3328
3329  return BC_STATUS_SUCCESS;
3330}
3331
3332static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags) {
3333
3334  BcStatus s;
3335  BcId id, *id_ptr;
3336  size_t idx;
3337
3338  id.name = name;
3339
3340  s = bc_parse_params(p, flags);
3341  if (s) goto err;
3342
3343  if (p->l.t != BC_LEX_RPAREN) {
3344    s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3345    goto err;
3346  }
3347
3348  idx = bc_map_index(&p->prog->fn_map, &id);
3349
3350  if (idx == SIZE_MAX) {
3351    bc_parse_addFunc(p, name);
3352    idx = bc_map_index(&p->prog->fn_map, &id);
3353  }
3354  else free(name);
3355
3356  id_ptr = bc_vec_item(&p->prog->fn_map, idx);
3357  bc_parse_pushIndex(p, id_ptr->idx);
3358
3359  return bc_lex_next(&p->l);
3360
3361err:
3362  free(name);
3363  return s;
3364}
3365
3366static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags) {
3367
3368  BcStatus s;
3369  char *name;
3370
3371  name = xstrdup(p->l.str.v);
3372  s = bc_lex_next(&p->l);
3373  if (s) goto err;
3374
3375  if (p->l.t == BC_LEX_LBRACKET) {
3376
3377    s = bc_lex_next(&p->l);
3378    if (s) goto err;
3379
3380    if (p->l.t == BC_LEX_RBRACKET) {
3381
3382      if (!(flags & BC_PARSE_ARRAY)) {
3383        s = bc_parse_err(p, BC_ERROR_PARSE_EXPR);
3384        goto err;
3385      }
3386
3387      *type = BC_INST_ARRAY;
3388    }
3389    else {
3390
3391      *type = BC_INST_ARRAY_ELEM;
3392
3393      flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3394      s = bc_parse_expr_status(p, flags, bc_parse_next_elem);
3395      if (s) goto err;
3396
3397      if (p->l.t != BC_LEX_RBRACKET) {
3398        s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3399        goto err;
3400      }
3401    }
3402
3403    s = bc_lex_next(&p->l);
3404    if (s) goto err;
3405
3406    bc_parse_push(p, *type);
3407    bc_parse_pushName(p, name);
3408  }
3409  else if (p->l.t == BC_LEX_LPAREN) {
3410
3411    if (flags & BC_PARSE_NOCALL) {
3412      s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3413      goto err;
3414    }
3415
3416    *type = BC_INST_CALL;
3417
3418    // Return early because bc_parse_call() frees the name.
3419    return bc_parse_call(p, name, flags);
3420  }
3421  else {
3422    *type = BC_INST_VAR;
3423    bc_parse_push(p, BC_INST_VAR);
3424    bc_parse_pushName(p, name);
3425  }
3426
3427err:
3428  free(name);
3429  return s;
3430}
3431
3432static BcStatus bc_parse_read(BcParse *p) {
3433
3434  BcStatus s;
3435
3436  s = bc_lex_next(&p->l);
3437  if (s) return s;
3438  if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3439
3440  s = bc_lex_next(&p->l);
3441  if (s) return s;
3442  if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3443
3444  bc_parse_push(p, BC_INST_READ);
3445
3446  return bc_lex_next(&p->l);
3447}
3448
3449static BcStatus bc_parse_builtin(BcParse *p, BcLexType type,
3450                                 uint8_t flags, BcInst *prev)
3451{
3452  BcStatus s;
3453
3454  s = bc_lex_next(&p->l);
3455  if (s) return s;
3456  if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3457
3458  s = bc_lex_next(&p->l);
3459  if (s) return s;
3460
3461  flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL));
3462  if (type == BC_LEX_KEY_LENGTH) flags |= BC_PARSE_ARRAY;
3463
3464  s = bc_parse_expr_status(p, flags, bc_parse_next_rel);
3465  if (s) return s;
3466
3467  if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3468
3469  *prev = type - BC_LEX_KEY_LENGTH + BC_INST_LENGTH;
3470  bc_parse_push(p, *prev);
3471
3472  return bc_lex_next(&p->l);
3473}
3474
3475static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags) {
3476
3477  BcStatus s;
3478
3479  s = bc_lex_next(&p->l);
3480  if (s) return s;
3481
3482  if (p->l.t != BC_LEX_LPAREN) {
3483    *type = BC_INST_SCALE;
3484    bc_parse_push(p, BC_INST_SCALE);
3485    return BC_STATUS_SUCCESS;
3486  }
3487
3488  *type = BC_INST_SCALE_FUNC;
3489  flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3490
3491  s = bc_lex_next(&p->l);
3492  if (s) return s;
3493
3494  s = bc_parse_expr_status(p, flags, bc_parse_next_rel);
3495  if (s) return s;
3496  if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3497
3498  bc_parse_push(p, BC_INST_SCALE_FUNC);
3499
3500  return bc_lex_next(&p->l);
3501}
3502
3503static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev,
3504                                size_t *nexs, uint8_t flags)
3505{
3506  BcStatus s;
3507  BcLexType type;
3508  uchar inst;
3509  BcInst etype = *prev;
3510  BcLexType last = p->l.last;
3511
3512  if (last == BC_LEX_OP_INC || last == BC_LEX_OP_DEC || last == BC_LEX_RPAREN)
3513    return s = bc_parse_err(p, BC_ERROR_PARSE_ASSIGN);
3514
3515  if (BC_PARSE_INST_VAR(etype)) {
3516    *prev = inst = BC_INST_INC_POST + (p->l.t != BC_LEX_OP_INC);
3517    bc_parse_push(p, inst);
3518    s = bc_lex_next(&p->l);
3519  }
3520  else {
3521
3522    *prev = inst = BC_INST_INC_PRE + (p->l.t != BC_LEX_OP_INC);
3523
3524    s = bc_lex_next(&p->l);
3525    if (s) return s;
3526    type = p->l.t;
3527
3528    // Because we parse the next part of the expression
3529    // right here, we need to increment this.
3530    *nexs = *nexs + 1;
3531
3532    if (type == BC_LEX_NAME)
3533      s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3534    else if (type >= BC_LEX_KEY_LAST && type <= BC_LEX_KEY_OBASE) {
3535      bc_parse_push(p, type - BC_LEX_KEY_LAST + BC_INST_LAST);
3536      s = bc_lex_next(&p->l);
3537    }
3538    else if (type == BC_LEX_KEY_SCALE) {
3539      s = bc_lex_next(&p->l);
3540      if (s) return s;
3541      if (p->l.t == BC_LEX_LPAREN) s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3542      else bc_parse_push(p, BC_INST_SCALE);
3543    }
3544    else s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3545
3546    if (!s) bc_parse_push(p, inst);
3547  }
3548
3549  return s;
3550}
3551
3552static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3553                               int rparen, int bin_last, size_t *nexprs)
3554{
3555  BcStatus s;
3556  BcLexType type;
3557
3558  s = bc_lex_next(&p->l);
3559  if (s) return s;
3560
3561  type = BC_PARSE_LEAF(*prev, bin_last, rparen) ? BC_LEX_OP_MINUS : BC_LEX_NEG;
3562  *prev = BC_PARSE_TOKEN_INST(type);
3563
3564  // We can just push onto the op stack because this is the largest
3565  // precedence operator that gets pushed. Inc/dec does not.
3566  if (type != BC_LEX_OP_MINUS) bc_vec_push(&p->ops, &type);
3567  else bc_parse_operator(p, type, ops_bgn, nexprs);
3568
3569  return s;
3570}
3571
3572static BcStatus bc_parse_str(BcParse *p, char inst) {
3573  bc_parse_string(p);
3574  bc_parse_push(p, inst);
3575  return bc_lex_next(&p->l);
3576}
3577
3578static BcStatus bc_parse_print(BcParse *p) {
3579
3580  BcStatus s;
3581  BcLexType t;
3582  int comma = 0;
3583
3584  s = bc_lex_next(&p->l);
3585  if (s) return s;
3586
3587  t = p->l.t;
3588
3589  if (bc_parse_isDelimiter(p)) return bc_parse_err(p, BC_ERROR_PARSE_PRINT);
3590
3591  do {
3592    if (t == BC_LEX_STR) s = bc_parse_str(p, BC_INST_PRINT_POP);
3593    else {
3594      s = bc_parse_expr_status(p, 0, bc_parse_next_print);
3595      if (!s) bc_parse_push(p, BC_INST_PRINT_POP);
3596    }
3597
3598    if (s) return s;
3599
3600    comma = (p->l.t == BC_LEX_COMMA);
3601
3602    if (comma) s = bc_lex_next(&p->l);
3603    else {
3604      if (!bc_parse_isDelimiter(p))
3605        return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3606      else break;
3607    }
3608
3609    t = p->l.t;
3610  } while (!s);
3611
3612  if (s) return s;
3613  if (comma) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3614
3615  return s;
3616}
3617
3618static BcStatus bc_parse_return(BcParse *p) {
3619
3620  BcStatus s;
3621  BcLexType t;
3622  int paren;
3623  uchar inst = BC_INST_RET0;
3624
3625  if (!BC_PARSE_FUNC(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3626
3627  if (p->func->voidfn) inst = BC_INST_RET_VOID;
3628
3629  s = bc_lex_next(&p->l);
3630  if (s) return s;
3631
3632  t = p->l.t;
3633  paren = t == BC_LEX_LPAREN;
3634
3635  if (bc_parse_isDelimiter(p)) bc_parse_push(p, inst);
3636  else {
3637
3638    s = bc_parse_expr_err(p, 0, bc_parse_next_expr);
3639    if (s && s != BC_STATUS_EMPTY_EXPR) return s;
3640    else if (s == BC_STATUS_EMPTY_EXPR) {
3641      bc_parse_push(p, inst);
3642      s = bc_lex_next(&p->l);
3643      if (s) return s;
3644    }
3645
3646    if (!paren || p->l.last != BC_LEX_RPAREN) {
3647      s = bc_parse_posixErr(p, BC_ERROR_POSIX_RET);
3648      if (s) return s;
3649    }
3650    else if (p->func->voidfn)
3651      return bc_parse_verr(p, BC_ERROR_PARSE_RET_VOID, p->func->name);
3652
3653    bc_parse_push(p, BC_INST_RET);
3654  }
3655
3656  return s;
3657}
3658
3659static BcStatus bc_parse_endBody(BcParse *p, int brace) {
3660
3661  BcStatus s = BC_STATUS_SUCCESS;
3662  int has_brace, new_else = 0;
3663
3664  if (p->flags.len <= 1) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3665
3666  if (brace) {
3667    if (p->l.t == BC_LEX_RBRACE) {
3668      s = bc_lex_next(&p->l);
3669      if (s) return s;
3670      if (!bc_parse_isDelimiter(p))
3671        return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3672    }
3673    else return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3674  }
3675
3676  has_brace = (BC_PARSE_BRACE(p) != 0);
3677
3678  do {
3679    size_t len = p->flags.len;
3680    int loop;
3681
3682    if (has_brace && !brace) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3683
3684    loop = BC_PARSE_LOOP_INNER(p) != 0;
3685
3686    if (loop || BC_PARSE_ELSE(p)) {
3687
3688      if (loop) {
3689
3690        size_t *label = bc_vec_top(&p->conds);
3691
3692        bc_parse_push(p, BC_INST_JUMP);
3693        bc_parse_pushIndex(p, *label);
3694
3695        bc_vec_pop(&p->conds);
3696      }
3697
3698      bc_parse_setLabel(p);
3699      bc_vec_pop(&p->flags);
3700    }
3701    else if (BC_PARSE_FUNC_INNER(p)) {
3702      BcInst inst = (p->func->voidfn ? BC_INST_RET_VOID : BC_INST_RET0);
3703      bc_parse_push(p, inst);
3704      bc_parse_updateFunc(p, BC_PROG_MAIN);
3705      bc_vec_pop(&p->flags);
3706    }
3707    else if (BC_PARSE_BRACE(p) && !BC_PARSE_IF(p)) bc_vec_pop(&p->flags);
3708
3709    // This needs to be last to parse nested if's properly.
3710    if (BC_PARSE_IF(p) && (len == p->flags.len || !BC_PARSE_BRACE(p))) {
3711
3712      while (p->l.t == BC_LEX_NLINE) {
3713        s = bc_lex_next(&p->l);
3714        if (s) return s;
3715      }
3716
3717      bc_vec_pop(&p->flags);
3718      *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_IF_END;
3719
3720      new_else = (p->l.t == BC_LEX_KEY_ELSE);
3721      if (new_else) s = bc_parse_else(p);
3722    }
3723
3724    if (brace && has_brace) brace = 0;
3725
3726  } while (p->flags.len > 1 && !new_else && (!BC_PARSE_IF_END(p) || brace) &&
3727           !(has_brace = (BC_PARSE_BRACE(p) != 0)));
3728
3729  if (!s && p->flags.len == 1 && brace)
3730    s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3731
3732  return s;
3733}
3734
3735static void bc_parse_startBody(BcParse *p, uint16_t flags) {
3736  flags |= (BC_PARSE_TOP_FLAG(p) & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
3737  flags |= BC_PARSE_FLAG_BODY;
3738  bc_vec_push(&p->flags, &flags);
3739}
3740
3741static void bc_parse_noElse(BcParse *p) {
3742  uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
3743  *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
3744  bc_parse_setLabel(p);
3745}
3746
3747static BcStatus bc_parse_if(BcParse *p) {
3748
3749  BcStatus s;
3750  size_t idx;
3751
3752  s = bc_lex_next(&p->l);
3753  if (s) return s;
3754  if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3755
3756  s = bc_lex_next(&p->l);
3757  if (s) return s;
3758  s = bc_parse_expr_status(p, BC_PARSE_REL, bc_parse_next_rel);
3759  if (s) return s;
3760  if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3761
3762  s = bc_lex_next(&p->l);
3763  if (s) return s;
3764  bc_parse_push(p, BC_INST_JUMP_ZERO);
3765
3766  idx = p->func->labels.len;
3767
3768  bc_parse_pushIndex(p, idx);
3769  bc_parse_createExitLabel(p, idx, 0);
3770  bc_parse_startBody(p, BC_PARSE_FLAG_IF);
3771
3772  return BC_STATUS_SUCCESS;
3773}
3774
3775static BcStatus bc_parse_else(BcParse *p) {
3776
3777  size_t idx = p->func->labels.len;
3778
3779  if (!BC_PARSE_IF_END(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3780
3781  bc_parse_push(p, BC_INST_JUMP);
3782  bc_parse_pushIndex(p, idx);
3783
3784  bc_parse_noElse(p);
3785
3786  bc_parse_createExitLabel(p, idx, 0);
3787  bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
3788
3789  return bc_lex_next(&p->l);
3790}
3791
3792static BcStatus bc_parse_while(BcParse *p) {
3793
3794  BcStatus s;
3795  size_t idx;
3796
3797  s = bc_lex_next(&p->l);
3798  if (s) return s;
3799  if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3800  s = bc_lex_next(&p->l);
3801  if (s) return s;
3802
3803  bc_parse_createCondLabel(p, p->func->labels.len);
3804
3805  idx = p->func->labels.len;
3806
3807  bc_parse_createExitLabel(p, idx, 1);
3808
3809  s = bc_parse_expr_status(p, BC_PARSE_REL, bc_parse_next_rel);
3810  if (s) return s;
3811  if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3812  s = bc_lex_next(&p->l);
3813  if (s) return s;
3814
3815  bc_parse_push(p, BC_INST_JUMP_ZERO);
3816  bc_parse_pushIndex(p, idx);
3817  bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
3818
3819  return BC_STATUS_SUCCESS;
3820}
3821
3822static BcStatus bc_parse_for(BcParse *p) {
3823
3824  BcStatus s;
3825  size_t cond_idx, exit_idx, body_idx, update_idx;
3826
3827  s = bc_lex_next(&p->l);
3828  if (s) return s;
3829  if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3830  s = bc_lex_next(&p->l);
3831  if (s) return s;
3832
3833  if (p->l.t != BC_LEX_SCOLON) {
3834    s = bc_parse_expr_status(p, 0, bc_parse_next_for);
3835    if (!s) bc_parse_push(p, BC_INST_POP);
3836  }
3837  else s = bc_parse_posixErr(p, BC_ERROR_POSIX_FOR1);
3838
3839  if (s) return s;
3840  if (p->l.t != BC_LEX_SCOLON) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3841  s = bc_lex_next(&p->l);
3842  if (s) return s;
3843
3844  cond_idx = p->func->labels.len;
3845  update_idx = cond_idx + 1;
3846  body_idx = update_idx + 1;
3847  exit_idx = body_idx + 1;
3848
3849  bc_parse_createLabel(p, p->func->code.len);
3850
3851  if (p->l.t != BC_LEX_SCOLON)
3852    s = bc_parse_expr_status(p, BC_PARSE_REL, bc_parse_next_for);
3853  else {
3854
3855    // Set this for the next call to bc_parse_number.
3856    // This is safe to set because the current token
3857    // is a semicolon, which has no string requirement.
3858    bc_vec_string(&p->l.str, strlen(bc_parse_const1), bc_parse_const1);
3859    bc_parse_number(p);
3860
3861    s = bc_parse_posixErr(p, BC_ERROR_POSIX_FOR2);
3862  }
3863
3864  if (s) return s;
3865  if (p->l.t != BC_LEX_SCOLON) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3866
3867  s = bc_lex_next(&p->l);
3868  if (s) return s;
3869
3870  bc_parse_push(p, BC_INST_JUMP_ZERO);
3871  bc_parse_pushIndex(p, exit_idx);
3872  bc_parse_push(p, BC_INST_JUMP);
3873  bc_parse_pushIndex(p, body_idx);
3874
3875  bc_parse_createCondLabel(p, update_idx);
3876
3877  if (p->l.t != BC_LEX_RPAREN) {
3878    s = bc_parse_expr_status(p, 0, bc_parse_next_rel);
3879    if (!s) bc_parse_push(p, BC_INST_POP);
3880  }
3881  else s = bc_parse_posixErr(p, BC_ERROR_POSIX_FOR3);
3882
3883  if (s) return s;
3884
3885  if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3886  bc_parse_push(p, BC_INST_JUMP);
3887  bc_parse_pushIndex(p, cond_idx);
3888  bc_parse_createLabel(p, p->func->code.len);
3889
3890  bc_parse_createExitLabel(p, exit_idx, 1);
3891  s = bc_lex_next(&p->l);
3892  if (!s) bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
3893
3894  return s;
3895}
3896
3897static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type) {
3898
3899  size_t i;
3900  BcInstPtr *ip;
3901
3902  if (!BC_PARSE_LOOP(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3903
3904  if (type == BC_LEX_KEY_BREAK) {
3905
3906    if (!p->exits.len) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3907
3908    i = p->exits.len - 1;
3909    ip = bc_vec_item(&p->exits, i);
3910
3911    while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
3912    if (i >= p->exits.len && !ip->func)
3913      return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3914
3915    i = ip->idx;
3916  }
3917  else i = *((size_t*) bc_vec_top(&p->conds));
3918
3919  bc_parse_push(p, BC_INST_JUMP);
3920  bc_parse_pushIndex(p, i);
3921
3922  return bc_lex_next(&p->l);
3923}
3924
3925static BcStatus bc_parse_func(BcParse *p) {
3926
3927  BcStatus s;
3928  int comma = 0, voidfn;
3929  uint16_t flags;
3930  char *name;
3931  size_t idx;
3932
3933  s = bc_lex_next(&p->l);
3934  if (s) return s;
3935
3936  if (p->l.t != BC_LEX_NAME) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3937
3938  voidfn = (!BC_S && !BC_W && p->l.t == BC_LEX_NAME &&
3939            !strcmp(p->l.str.v, "void"));
3940
3941  s = bc_lex_next(&p->l);
3942  if (s) return s;
3943
3944  voidfn = (voidfn && p->l.t == BC_LEX_NAME);
3945
3946  if (voidfn) {
3947    s = bc_lex_next(&p->l);
3948    if (s) return s;
3949  }
3950
3951  if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3952
3953  name = xstrdup(p->l.str.v);
3954  idx = bc_program_insertFunc(p->prog, name);
3955  bc_parse_updateFunc(p, idx);
3956  p->func->voidfn = voidfn;
3957
3958  s = bc_lex_next(&p->l);
3959  if (s) return s;
3960
3961  while (p->l.t != BC_LEX_RPAREN) {
3962
3963    BcType t = BC_TYPE_VAR;
3964
3965    if (p->l.t != BC_LEX_NAME) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3966
3967    ++p->func->nparams;
3968
3969    name = xstrdup(p->l.str.v);
3970    s = bc_lex_next(&p->l);
3971    if (s) goto err;
3972
3973    if (p->l.t == BC_LEX_LBRACKET) {
3974
3975      if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY;
3976
3977      s = bc_lex_next(&p->l);
3978      if (s) goto err;
3979
3980      if (p->l.t != BC_LEX_RBRACKET) {
3981        s = bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3982        goto err;
3983      }
3984
3985      s = bc_lex_next(&p->l);
3986      if (s) goto err;
3987    }
3988
3989    comma = p->l.t == BC_LEX_COMMA;
3990    if (comma) {
3991      s = bc_lex_next(&p->l);
3992      if (s) goto err;
3993    }
3994
3995    s = bc_func_insert(p->func, name, t, p->l.line);
3996    if (s) goto err;
3997  }
3998
3999  if (comma) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
4000
4001  flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4002  bc_parse_startBody(p, flags);
4003
4004  s = bc_lex_next(&p->l);
4005  if (s) return s;
4006
4007  if (p->l.t != BC_LEX_LBRACE) s = bc_parse_posixErr(p, BC_ERROR_POSIX_BRACE);
4008
4009  return s;
4010
4011err:
4012  free(name);
4013  return s;
4014}
4015
4016static BcStatus bc_parse_auto(BcParse *p) {
4017
4018  BcStatus s;
4019  int comma, one;
4020  char *name;
4021
4022  if (!p->auto_part) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4023  s = bc_lex_next(&p->l);
4024  if (s) return s;
4025
4026  p->auto_part = comma = 0;
4027  one = p->l.t == BC_LEX_NAME;
4028
4029  while (p->l.t == BC_LEX_NAME) {
4030
4031    BcType t;
4032
4033    name = xstrdup(p->l.str.v);
4034    s = bc_lex_next(&p->l);
4035    if (s) goto err;
4036
4037    if (p->l.t == BC_LEX_LBRACKET) {
4038
4039      t = BC_TYPE_ARRAY;
4040
4041      s = bc_lex_next(&p->l);
4042      if (s) goto err;
4043
4044      if (p->l.t != BC_LEX_RBRACKET) {
4045        s = bc_parse_err(p, BC_ERROR_PARSE_FUNC);
4046        goto err;
4047      }
4048
4049      s = bc_lex_next(&p->l);
4050      if (s) goto err;
4051    }
4052    else t = BC_TYPE_VAR;
4053
4054    comma = p->l.t == BC_LEX_COMMA;
4055    if (comma) {
4056      s = bc_lex_next(&p->l);
4057      if (s) goto err;
4058    }
4059
4060    s = bc_func_insert(p->func, name, t, p->l.line);
4061    if (s) goto err;
4062  }
4063
4064  if (comma) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
4065  if (!one) return bc_parse_err(p, BC_ERROR_PARSE_NO_AUTO);
4066  if (!bc_parse_isDelimiter(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4067
4068  return s;
4069
4070err:
4071  free(name);
4072  return s;
4073}
4074
4075static BcStatus bc_parse_body(BcParse *p, int brace) {
4076
4077  BcStatus s = BC_STATUS_SUCCESS;
4078  uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4079
4080  *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4081
4082  if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4083
4084    if (!brace) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4085
4086    p->auto_part = p->l.t != BC_LEX_KEY_AUTO;
4087
4088    if (!p->auto_part) {
4089
4090      // Make sure this is 1 to not get a parse error.
4091      p->auto_part = 1;
4092
4093      s = bc_parse_auto(p);
4094      if (s) return s;
4095    }
4096
4097    if (p->l.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4098  }
4099  else {
4100    s = bc_parse_stmt(p);
4101    if (!s && !brace && !BC_PARSE_BODY(p)) s = bc_parse_endBody(p, 0);
4102  }
4103
4104  return s;
4105}
4106
4107static BcStatus bc_parse_stmt(BcParse *p) {
4108
4109  BcStatus s = BC_STATUS_SUCCESS;
4110  size_t len;
4111  uint16_t flags;
4112  BcLexType type = p->l.t;
4113
4114  if (type == BC_LEX_NLINE) return bc_lex_next(&p->l);
4115  if (type == BC_LEX_KEY_AUTO) return bc_parse_auto(p);
4116
4117  p->auto_part = 0;
4118
4119  if (type != BC_LEX_KEY_ELSE) {
4120
4121    if (BC_PARSE_IF_END(p)) {
4122      bc_parse_noElse(p);
4123      if (p->flags.len > 1 && !BC_PARSE_BRACE(p))
4124        s = bc_parse_endBody(p, 0);
4125      return s;
4126    }
4127    else if (type == BC_LEX_LBRACE) {
4128
4129      if (!BC_PARSE_BODY(p)) {
4130        bc_parse_startBody(p, BC_PARSE_FLAG_BRACE);
4131        s = bc_lex_next(&p->l);
4132      }
4133      else {
4134        *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_BRACE;
4135        s = bc_lex_next(&p->l);
4136        if (!s) s = bc_parse_body(p, 1);
4137      }
4138
4139      return s;
4140    }
4141    else if (BC_PARSE_BODY(p) && !BC_PARSE_BRACE(p))
4142      return bc_parse_body(p, 0);
4143  }
4144
4145  len = p->flags.len;
4146  flags = BC_PARSE_TOP_FLAG(p);
4147
4148  switch (type) {
4149
4150    case BC_LEX_OP_INC:
4151    case BC_LEX_OP_DEC:
4152    case BC_LEX_OP_MINUS:
4153    case BC_LEX_OP_BOOL_NOT:
4154    case BC_LEX_LPAREN:
4155    case BC_LEX_NAME:
4156    case BC_LEX_NUMBER:
4157    case BC_LEX_KEY_IBASE:
4158    case BC_LEX_KEY_LAST:
4159    case BC_LEX_KEY_LENGTH:
4160    case BC_LEX_KEY_OBASE:
4161    case BC_LEX_KEY_READ:
4162    case BC_LEX_KEY_SCALE:
4163    case BC_LEX_KEY_SQRT:
4164    case BC_LEX_KEY_ABS:
4165    {
4166      s = bc_parse_expr_status(p, BC_PARSE_PRINT, bc_parse_next_expr);
4167      break;
4168    }
4169
4170    case BC_LEX_KEY_ELSE:
4171    {
4172      s = bc_parse_else(p);
4173      break;
4174    }
4175
4176    case BC_LEX_SCOLON:
4177    {
4178      // Do nothing.
4179      break;
4180    }
4181
4182    case BC_LEX_RBRACE:
4183    {
4184      s = bc_parse_endBody(p, 1);
4185      break;
4186    }
4187
4188    case BC_LEX_STR:
4189    {
4190      s = bc_parse_str(p, BC_INST_PRINT_STR);
4191      break;
4192    }
4193
4194    case BC_LEX_KEY_BREAK:
4195    case BC_LEX_KEY_CONTINUE:
4196    {
4197      s = bc_parse_loopExit(p, p->l.t);
4198      break;
4199    }
4200
4201    case BC_LEX_KEY_FOR:
4202    {
4203      s = bc_parse_for(p);
4204      break;
4205    }
4206
4207    case BC_LEX_KEY_HALT:
4208    {
4209      bc_parse_push(p, BC_INST_HALT);
4210      s = bc_lex_next(&p->l);
4211      break;
4212    }
4213
4214    case BC_LEX_KEY_IF:
4215    {
4216      s = bc_parse_if(p);
4217      break;
4218    }
4219
4220    case BC_LEX_KEY_LIMITS:
4221    {
4222      printf("BC_BASE_MAX     = %lu\n", BC_MAX_OBASE);
4223      printf("BC_DIM_MAX      = %lu\n", BC_MAX_DIM);
4224      printf("BC_SCALE_MAX    = %lu\n", BC_MAX_SCALE);
4225      printf("BC_STRING_MAX   = %lu\n", BC_MAX_STRING);
4226      printf("BC_NAME_MAX     = %lu\n", BC_MAX_NAME);
4227      printf("BC_NUM_MAX      = %lu\n", BC_MAX_NUM);
4228      printf("MAX Exponent    = %lu\n", BC_MAX_EXP);
4229      printf("Number of vars  = %lu\n", BC_MAX_VARS);
4230
4231      s = bc_lex_next(&p->l);
4232
4233      break;
4234    }
4235
4236    case BC_LEX_KEY_PRINT:
4237    {
4238      s = bc_parse_print(p);
4239      break;
4240    }
4241
4242    case BC_LEX_KEY_QUIT:
4243    {
4244      // Quit is a compile-time command. We don't exit directly,
4245      // so the vm can clean up. Limits do the same thing.
4246      s = BC_STATUS_QUIT;
4247      break;
4248    }
4249
4250    case BC_LEX_KEY_RETURN:
4251    {
4252      s = bc_parse_return(p);
4253      break;
4254    }
4255
4256    case BC_LEX_KEY_WHILE:
4257    {
4258      s = bc_parse_while(p);
4259      break;
4260    }
4261
4262    default:
4263    {
4264      s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4265      break;
4266    }
4267  }
4268
4269  if (!s && len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p)) {
4270    if (!bc_parse_isDelimiter(p)) s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4271  }
4272
4273  // Make sure semicolons are eaten.
4274  while (!s && p->l.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4275
4276  return s;
4277}
4278
4279BcStatus bc_parse_parse(BcParse *p) {
4280
4281  BcStatus s;
4282
4283  if (p->l.t == BC_LEX_EOF) s = bc_parse_err(p, BC_ERROR_PARSE_EOF);
4284  else if (p->l.t == BC_LEX_KEY_DEFINE) {
4285    if (BC_PARSE_NO_EXEC(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4286    s = bc_parse_func(p);
4287  }
4288  else s = bc_parse_stmt(p);
4289
4290  if ((s && s != BC_STATUS_QUIT) || BC_SIGNAL) s = bc_parse_reset(p, s);
4291
4292  return s;
4293}
4294
4295static BcStatus bc_parse_expr_err(BcParse *p, uint8_t flags, BcParseNext next) {
4296
4297  BcStatus s = BC_STATUS_SUCCESS;
4298  BcInst prev = BC_INST_PRINT;
4299  BcLexType top, t = p->l.t;
4300  size_t nexprs = 0, ops_bgn = p->ops.len;
4301  uint32_t i, nparens, nrelops;
4302  int pfirst, rprn, done, get_token, assign, bin_last, incdec;
4303
4304  pfirst = p->l.t == BC_LEX_LPAREN;
4305  nparens = nrelops = 0;
4306  rprn = done = get_token = assign = incdec = 0;
4307  bin_last = 1;
4308
4309  // We want to eat newlines if newlines are not a valid ending token.
4310  // This is for spacing in things like for loop headers.
4311  while (!s && (t = p->l.t) == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4312
4313  for (; !BC_SIGNAL && !s && !done && BC_PARSE_EXPR(t); t = p->l.t) {
4314
4315    switch (t) {
4316
4317      case BC_LEX_OP_INC:
4318      case BC_LEX_OP_DEC:
4319      {
4320        if (incdec) return bc_parse_err(p, BC_ERROR_PARSE_ASSIGN);
4321        s = bc_parse_incdec(p, &prev, &nexprs, flags);
4322        rprn = get_token = bin_last = 0;
4323        incdec = 1;
4324        break;
4325      }
4326
4327      case BC_LEX_OP_MINUS:
4328      {
4329        s = bc_parse_minus(p, &prev, ops_bgn, rprn, bin_last, &nexprs);
4330        rprn = get_token = 0;
4331        bin_last = (prev == BC_INST_MINUS);
4332        if (bin_last) incdec = 0;
4333        break;
4334      }
4335
4336      case BC_LEX_OP_ASSIGN_POWER:
4337      case BC_LEX_OP_ASSIGN_MULTIPLY:
4338      case BC_LEX_OP_ASSIGN_DIVIDE:
4339      case BC_LEX_OP_ASSIGN_MODULUS:
4340      case BC_LEX_OP_ASSIGN_PLUS:
4341      case BC_LEX_OP_ASSIGN_MINUS:
4342      case BC_LEX_OP_ASSIGN:
4343      {
4344        if (!BC_PARSE_INST_VAR(prev)) {
4345          s = bc_parse_err(p, BC_ERROR_PARSE_ASSIGN);
4346          break;
4347        }
4348      }
4349      // Fallthrough.
4350      case BC_LEX_OP_POWER:
4351      case BC_LEX_OP_MULTIPLY:
4352      case BC_LEX_OP_DIVIDE:
4353      case BC_LEX_OP_MODULUS:
4354      case BC_LEX_OP_PLUS:
4355      case BC_LEX_OP_REL_EQ:
4356      case BC_LEX_OP_REL_LE:
4357      case BC_LEX_OP_REL_GE:
4358      case BC_LEX_OP_REL_NE:
4359      case BC_LEX_OP_REL_LT:
4360      case BC_LEX_OP_REL_GT:
4361      case BC_LEX_OP_BOOL_NOT:
4362      case BC_LEX_OP_BOOL_OR:
4363      case BC_LEX_OP_BOOL_AND:
4364      {
4365        if (BC_PARSE_OP_PREFIX(t)) {
4366          if (!bin_last && !BC_PARSE_OP_PREFIX(p->l.last))
4367            return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4368        }
4369        else if (BC_PARSE_PREV_PREFIX(prev) || bin_last)
4370          return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4371
4372        nrelops += (t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT);
4373        prev = BC_PARSE_TOKEN_INST(t);
4374        bc_parse_operator(p, t, ops_bgn, &nexprs);
4375        rprn = incdec = 0;
4376        get_token = 1;
4377        bin_last = !BC_PARSE_OP_PREFIX(t);
4378
4379        break;
4380      }
4381
4382      case BC_LEX_LPAREN:
4383      {
4384        if (BC_PARSE_LEAF(prev, bin_last, rprn))
4385          return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4386
4387        ++nparens;
4388        rprn = incdec = 0;
4389        get_token = 1;
4390        bc_vec_push(&p->ops, &t);
4391
4392        break;
4393      }
4394
4395      case BC_LEX_RPAREN:
4396      {
4397        // This needs to be a status. The error
4398        // is handled in bc_parse_expr_status().
4399        if (p->l.last == BC_LEX_LPAREN) return BC_STATUS_EMPTY_EXPR;
4400
4401        if (bin_last || BC_PARSE_PREV_PREFIX(prev))
4402          return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4403
4404        if (!nparens) {
4405          s = BC_STATUS_SUCCESS;
4406          done = 1;
4407          get_token = 0;
4408          break;
4409        }
4410
4411        --nparens;
4412        rprn = 1;
4413        get_token = bin_last = incdec = 0;
4414
4415        s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4416
4417        break;
4418      }
4419
4420      case BC_LEX_NAME:
4421      {
4422        if (BC_PARSE_LEAF(prev, bin_last, rprn))
4423          return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4424
4425        get_token = bin_last = 0;
4426        s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4427        rprn = (prev == BC_INST_CALL);
4428        ++nexprs;
4429
4430        break;
4431      }
4432
4433      case BC_LEX_NUMBER:
4434      {
4435        if (BC_PARSE_LEAF(prev, bin_last, rprn))
4436          return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4437
4438        bc_parse_number(p);
4439        nexprs += 1;
4440        prev = BC_INST_NUM;
4441        get_token = 1;
4442        rprn = bin_last = 0;
4443
4444        break;
4445      }
4446
4447      case BC_LEX_KEY_IBASE:
4448      case BC_LEX_KEY_LAST:
4449      case BC_LEX_KEY_OBASE:
4450      {
4451        if (BC_PARSE_LEAF(prev, bin_last, rprn))
4452          return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4453
4454        prev = (uchar) (t - BC_LEX_KEY_LAST + BC_INST_LAST);
4455        bc_parse_push(p, (uchar) prev);
4456
4457        get_token = 1;
4458        rprn = bin_last = 0;
4459        ++nexprs;
4460
4461        break;
4462      }
4463
4464      case BC_LEX_KEY_LENGTH:
4465      case BC_LEX_KEY_SQRT:
4466      case BC_LEX_KEY_ABS:
4467      {
4468        if (BC_PARSE_LEAF(prev, bin_last, rprn))
4469          return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4470
4471        s = bc_parse_builtin(p, t, flags, &prev);
4472        rprn = get_token = bin_last = incdec = 0;
4473        ++nexprs;
4474
4475        break;
4476      }
4477
4478      case BC_LEX_KEY_READ:
4479      {
4480        if (BC_PARSE_LEAF(prev, bin_last, rprn))
4481          return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4482        else if (flags & BC_PARSE_NOREAD)
4483          s = bc_parse_err(p, BC_ERROR_EXEC_REC_READ);
4484        else s = bc_parse_read(p);
4485
4486        rprn = get_token = bin_last = incdec = 0;
4487        ++nexprs;
4488        prev = BC_INST_READ;
4489
4490        break;
4491      }
4492
4493      case BC_LEX_KEY_SCALE:
4494      {
4495        if (BC_PARSE_LEAF(prev, bin_last, rprn))
4496          return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4497
4498        s = bc_parse_scale(p, &prev, flags);
4499        rprn = get_token = bin_last = 0;
4500        ++nexprs;
4501
4502        break;
4503      }
4504
4505      default:
4506      {
4507        s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4508        break;
4509      }
4510    }
4511
4512    if (!s && get_token) s = bc_lex_next(&p->l);
4513  }
4514
4515  if (s) return s;
4516  if (BC_SIGNAL) return BC_STATUS_SIGNAL;
4517
4518  while (p->ops.len > ops_bgn) {
4519
4520    top = BC_PARSE_TOP_OP(p);
4521    assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4522
4523    if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4524      return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4525
4526    bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4527
4528    nexprs -= !BC_PARSE_OP_PREFIX(top);
4529    bc_vec_pop(&p->ops);
4530  }
4531
4532  if (nexprs != 1) return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4533
4534  for (i = 0; i < next.len && t != next.tokens[i]; ++i);
4535  if (i == next.len && !bc_parse_isDelimiter(p))
4536    return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4537
4538  if (!(flags & BC_PARSE_REL) && nrelops) {
4539    s = bc_parse_posixErr(p, BC_ERROR_POSIX_REL_POS);
4540    if (s) return s;
4541  }
4542  else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4543    s = bc_parse_posixErr(p, BC_ERROR_POSIX_MULTIREL);
4544    if (s) return s;
4545  }
4546
4547  if (flags & BC_PARSE_PRINT) {
4548    if (pfirst || !assign) bc_parse_push(p, BC_INST_PRINT);
4549    bc_parse_push(p, BC_INST_POP);
4550  }
4551
4552  // We want to eat newlines if newlines are not a valid ending token.
4553  // This is for spacing in things like for loop headers.
4554  for (incdec = 1, i = 0; i < next.len && incdec; ++i)
4555    incdec = (next.tokens[i] != BC_LEX_NLINE);
4556  if (incdec) {
4557    while (!s && p->l.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4558  }
4559
4560  return s;
4561}
4562
4563BcStatus bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next) {
4564
4565  BcStatus s = bc_parse_expr_err(p, flags, next);
4566
4567  if (s == BC_STATUS_EMPTY_EXPR) s = bc_parse_err(p, BC_ERROR_PARSE_EMPTY_EXPR);
4568
4569  return s;
4570}
4571
4572BcStatus bc_parse_expr(BcParse *p, uint8_t flags) {
4573  return bc_parse_expr_status(p, flags, bc_parse_next_read);
4574}
4575
4576static BcStatus bc_program_type_num(BcResult *r, BcNum *n) {
4577  if (!BC_PROG_NUM(r, n)) return bc_vm_err(BC_ERROR_EXEC_TYPE);
4578  return BC_STATUS_SUCCESS;
4579}
4580
4581static BcStatus bc_program_type_match(BcResult *r, BcType t) {
4582  if ((r->t != BC_RESULT_ARRAY) != (!t)) return bc_vm_err(BC_ERROR_EXEC_TYPE);
4583  return BC_STATUS_SUCCESS;
4584}
4585
4586static char *bc_program_str(BcProgram *p, size_t idx, int str) {
4587
4588  BcFunc *f;
4589  BcVec *v;
4590  size_t i;
4591
4592  BcInstPtr *ip = bc_vec_item_rev(&p->stack, 0);
4593  i = ip->func;
4594
4595  f = bc_vec_item(&p->fns, i);
4596  v = str ? &f->strs : &f->consts;
4597
4598  return *((char**) bc_vec_item(v, idx));
4599}
4600
4601static size_t bc_program_index(char *code, size_t *bgn) {
4602
4603  uchar amt = (uchar) code[(*bgn)++], i = 0;
4604  size_t res = 0;
4605
4606  for (; i < amt; ++i, ++(*bgn)) {
4607    size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
4608    res |= (temp << (i * CHAR_BIT));
4609  }
4610
4611  return res;
4612}
4613
4614static char *bc_program_name(char *code, size_t *bgn) {
4615
4616  size_t i;
4617  uchar c;
4618  char *s;
4619  char *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
4620
4621  s = xmalloc(((unsigned long) ptr) - ((unsigned long) str) + 1);
4622
4623  for (i = 0; (c = (uchar) code[(*bgn)++]) && c != BC_PARSE_STREND; ++i)
4624    s[i] = (char) c;
4625
4626  s[i] = '\0';
4627
4628  return s;
4629}
4630
4631static BcVec* bc_program_search(BcProgram *p, char *id, BcType type) {
4632
4633  BcId e, *ptr;
4634  BcVec *v, *map;
4635  size_t i;
4636  BcResultData data;
4637  int new, var = (type == BC_TYPE_VAR);
4638
4639  v = var ? &p->vars : &p->arrs;
4640  map = var ? &p->var_map : &p->arr_map;
4641
4642  e.name = id;
4643  e.idx = v->len;
4644  new = bc_map_insert(map, &e, &i);
4645
4646  if (new) {
4647    bc_array_init(&data.v, var);
4648    bc_vec_push(v, &data.v);
4649  }
4650
4651  ptr = bc_vec_item(map, i);
4652  if (new) ptr->name = xstrdup(e.name);
4653
4654  return bc_vec_item(v, ptr->idx);
4655}
4656
4657static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num) {
4658
4659  BcStatus s = BC_STATUS_SUCCESS;
4660  BcNum *n = &r->d.n;
4661
4662  switch (r->t) {
4663
4664    case BC_RESULT_CONSTANT:
4665    {
4666      char *str = bc_program_str(p, r->d.id.idx, 0);
4667      size_t len = strlen(str);
4668
4669      bc_num_init(n, len);
4670
4671      s = bc_num_parse(n, str, &p->ib, p->ib_t, len == 1);
4672
4673      if (s) {
4674        bc_num_free(n);
4675        return s;
4676      }
4677
4678      r->t = BC_RESULT_TEMP;
4679    }
4680    // Fallthrough.
4681    case BC_RESULT_STR:
4682    case BC_RESULT_TEMP:
4683    case BC_RESULT_IBASE:
4684    case BC_RESULT_SCALE:
4685    case BC_RESULT_OBASE:
4686    {
4687      *num = n;
4688      break;
4689    }
4690
4691    case BC_RESULT_VAR:
4692    case BC_RESULT_ARRAY:
4693    case BC_RESULT_ARRAY_ELEM:
4694    {
4695      BcVec *v;
4696      BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
4697
4698      v = bc_program_search(p, r->d.id.name, type);
4699
4700      if (r->t == BC_RESULT_ARRAY_ELEM) {
4701
4702        size_t idx = r->d.id.idx;
4703
4704        v = bc_vec_top(v);
4705
4706        if (v->len <= idx) bc_array_expand(v, idx + 1);
4707        *num = bc_vec_item(v, idx);
4708      }
4709      else *num = bc_vec_top(v);
4710
4711      break;
4712    }
4713
4714    case BC_RESULT_LAST:
4715    {
4716      *num = &p->last;
4717      break;
4718    }
4719
4720    case BC_RESULT_ONE:
4721    {
4722      *num = &p->one;
4723      break;
4724    }
4725
4726    case BC_RESULT_VOID:
4727    {
4728      s = bc_vm_err(BC_ERROR_EXEC_VOID_VAL);
4729      break;
4730    }
4731  }
4732
4733  return s;
4734}
4735
4736static BcStatus bc_program_operand(BcProgram *p, BcResult **r,
4737                                   BcNum **n, size_t idx)
4738{
4739
4740  *r = bc_vec_item_rev(&p->results, idx);
4741
4742  return bc_program_num(p, *r, n);
4743}
4744
4745static BcStatus bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
4746                                   BcResult **r, BcNum **rn)
4747{
4748  BcStatus s;
4749  BcResultType lt;
4750
4751  s = bc_program_operand(p, l, ln, 1);
4752  if (s) return s;
4753  s = bc_program_operand(p, r, rn, 0);
4754  if (s) return s;
4755
4756  lt = (*l)->t;
4757
4758  // We run this again under these conditions in case any vector has been
4759  // reallocated out from under the BcNums or arrays we had.
4760  if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
4761    s = bc_program_num(p, *l, ln);
4762
4763  if (lt == BC_RESULT_STR) return bc_vm_err(BC_ERROR_EXEC_TYPE);
4764
4765  return s;
4766}
4767
4768static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
4769                                     BcResult **r, BcNum **rn)
4770{
4771  BcStatus s;
4772
4773  s = bc_program_binPrep(p, l, ln, r, rn);
4774  if (s) return s;
4775
4776  s = bc_program_type_num(*l, *ln);
4777  if (s) return s;
4778
4779  return bc_program_type_num(*r, *rn);
4780}
4781
4782static BcStatus bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
4783                                      BcResult **r, BcNum **rn)
4784{
4785  BcStatus s;
4786  int good = 0;
4787  BcResultType lt;
4788
4789  s = bc_program_binPrep(p, l, ln, r, rn);
4790  if (s) return s;
4791
4792  lt = (*l)->t;
4793
4794  if (lt == BC_RESULT_CONSTANT || lt == BC_RESULT_TEMP ||lt == BC_RESULT_ARRAY)
4795    return bc_vm_err(BC_ERROR_EXEC_TYPE);
4796
4797  if (lt == BC_RESULT_ONE) return bc_vm_err(BC_ERROR_EXEC_TYPE);
4798
4799  if (!good) s = bc_program_type_num(*r, *rn);
4800
4801  return s;
4802}
4803
4804static void bc_program_binOpRetire(BcProgram *p, BcResult *r) {
4805  r->t = BC_RESULT_TEMP;
4806  bc_vec_pop(&p->results);
4807  bc_vec_pop(&p->results);
4808  bc_vec_push(&p->results, r);
4809}
4810
4811static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n) {
4812
4813  BcStatus s;
4814
4815  s = bc_program_operand(p, r, n, 0);
4816  if (s) return s;
4817
4818  return bc_program_type_num(*r, *n);
4819}
4820
4821static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t) {
4822  r->t = t;
4823  bc_vec_pop(&p->results);
4824  bc_vec_push(&p->results, r);
4825}
4826
4827static BcStatus bc_program_op(BcProgram *p, uchar inst) {
4828
4829  BcStatus s;
4830  BcResult *opd1, *opd2, res;
4831  BcNum *n1 = NULL, *n2 = NULL;
4832  size_t idx = inst - BC_INST_POWER;
4833
4834  s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2);
4835  if (s) return s;
4836  bc_num_init(&res.d.n, bc_program_opReqs[idx](n1, n2, p->scale));
4837
4838  s = bc_program_ops[idx](n1, n2, &res.d.n, p->scale);
4839  if (s) goto err;
4840  bc_program_binOpRetire(p, &res);
4841
4842  return s;
4843
4844err:
4845  bc_num_free(&res.d.n);
4846  return s;
4847}
4848
4849static BcStatus bc_program_read(BcProgram *p) {
4850
4851  BcStatus s;
4852  BcParse parse;
4853  BcVec buf;
4854  BcInstPtr ip;
4855  size_t i;
4856  char *file;
4857  BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
4858
4859  for (i = 0; i < p->stack.len; ++i) {
4860    BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
4861    if (ip_ptr->func == BC_PROG_READ)
4862      return bc_vm_err(BC_ERROR_EXEC_REC_READ);
4863  }
4864
4865  file = BC_VM->file;
4866  bc_lex_file(&parse.l, bc_program_stdin_name);
4867  bc_vec_npop(&f->code, f->code.len);
4868  bc_vec_init(&buf, sizeof(char), NULL);
4869
4870  s = bc_read_line(&buf, "read> ");
4871  if (s) {
4872    if (s == BC_STATUS_EOF) s = bc_vm_err(BC_ERROR_EXEC_READ_EXPR);
4873    goto io_err;
4874  }
4875
4876  bc_parse_init(&parse, p, BC_PROG_READ);
4877
4878  s = bc_parse_text(&parse, buf.v);
4879  if (s) goto exec_err;
4880  s = bc_parse_expr(&parse, BC_PARSE_NOREAD);
4881  if (s) goto exec_err;
4882
4883  if (parse.l.t != BC_LEX_NLINE && parse.l.t != BC_LEX_EOF) {
4884    s = bc_vm_err(BC_ERROR_EXEC_READ_EXPR);
4885    goto exec_err;
4886  }
4887
4888  ip.func = BC_PROG_READ;
4889  ip.idx = 0;
4890  ip.len = p->results.len;
4891
4892  // Update this pointer, just in case.
4893  f = bc_vec_item(&p->fns, BC_PROG_READ);
4894
4895  bc_vec_pushByte(&f->code, BC_INST_RET);
4896  bc_vec_push(&p->stack, &ip);
4897
4898exec_err:
4899  bc_parse_free(&parse);
4900io_err:
4901  bc_vec_free(&buf);
4902  BC_VM->file = file;
4903  return s;
4904}
4905
4906static void bc_program_printChars(char *str) {
4907  char *nl;
4908  BC_VM->nchars += printf("%s", str);
4909  nl = strrchr(str, '\n');
4910  if (nl) BC_VM->nchars = strlen(nl + 1);
4911}
4912
4913static void bc_program_printString(char *str) {
4914
4915  size_t i, len = strlen(str);
4916
4917  for (i = 0; i < len; ++i, ++BC_VM->nchars) {
4918
4919    int c = str[i];
4920
4921    if (c == '\\' && i != len - 1) {
4922
4923      char *ptr;
4924
4925      c = str[++i];
4926      ptr = strchr(bc_program_esc_chars, c);
4927
4928      if (ptr) {
4929        if (c == 'n') BC_VM->nchars = SIZE_MAX;
4930        c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
4931      }
4932      else {
4933        // Just print the backslash. The following
4934        // character will be printed later.
4935        putchar('\\');
4936        ++BC_VM->nchars;
4937      }
4938    }
4939
4940    putchar(c);
4941  }
4942}
4943
4944static BcStatus bc_program_print(BcProgram *p, uchar inst, size_t idx) {
4945
4946  BcStatus s = BC_STATUS_SUCCESS;
4947  BcResult *r;
4948  char *str;
4949  BcNum *n = NULL;
4950  int pop = inst != BC_INST_PRINT;
4951
4952  r = bc_vec_item_rev(&p->results, idx);
4953
4954  if (r->t == BC_RESULT_VOID) {
4955    if (pop) return bc_vm_err(BC_ERROR_EXEC_VOID_VAL);
4956    return s;
4957  }
4958
4959  s = bc_program_num(p, r, &n);
4960  if (s) return s;
4961
4962  if (BC_PROG_NUM(r, n)) {
4963    s = bc_num_print(n, &p->ob, p->ob_t, !pop);
4964    if (!s) bc_num_copy(&p->last, n);
4965  }
4966  else {
4967
4968    size_t i = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
4969
4970    str = bc_program_str(p, i, 1);
4971
4972    if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
4973    else {
4974      bc_program_printString(str);
4975      if (inst == BC_INST_PRINT) {
4976        putchar('\n');
4977        BC_VM->nchars = 0;
4978      }
4979    }
4980  }
4981
4982  if (!s && pop) bc_vec_pop(&p->results);
4983
4984  return s;
4985}
4986
4987void bc_program_negate(BcResult *r, BcNum *n) {
4988  BcNum *rn = &r->d.n;
4989  bc_num_copy(rn, n);
4990  if (rn->len) rn->neg = !rn->neg;
4991}
4992
4993void bc_program_not(BcResult *r, BcNum *n) {
4994  if (!BC_NUM_CMP_ZERO(n)) bc_num_one(&r->d.n);
4995}
4996
4997static BcStatus bc_program_unary(BcProgram *p, uchar inst) {
4998
4999  BcStatus s;
5000  BcResult res, *ptr;
5001  BcNum *num = NULL;
5002
5003  s = bc_program_prep(p, &ptr, &num);
5004  if (s) return s;
5005
5006  bc_num_init(&res.d.n, num->len);
5007  bc_program_unarys[inst - BC_INST_NEG](&res, num);
5008  bc_program_retire(p, &res, BC_RESULT_TEMP);
5009
5010  return s;
5011}
5012
5013static BcStatus bc_program_logical(BcProgram *p, uchar inst) {
5014
5015  BcStatus s;
5016  BcResult *opd1, *opd2, res;
5017  BcNum *n1 = NULL, *n2 = NULL;
5018  int cond = 0;
5019  ssize_t cmp;
5020
5021  s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2);
5022  if (s) return s;
5023  bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5024
5025  if (inst == BC_INST_BOOL_AND)
5026    cond = BC_NUM_CMP_ZERO(n1) && BC_NUM_CMP_ZERO(n2);
5027  else if (inst == BC_INST_BOOL_OR)
5028    cond = BC_NUM_CMP_ZERO(n1) || BC_NUM_CMP_ZERO(n2);
5029  else {
5030
5031    cmp = bc_num_cmp(n1, n2);
5032
5033    switch (inst) {
5034
5035      case BC_INST_REL_EQ:
5036      {
5037        cond = cmp == 0;
5038        break;
5039      }
5040
5041      case BC_INST_REL_LE:
5042      {
5043        cond = cmp <= 0;
5044        break;
5045      }
5046
5047      case BC_INST_REL_GE:
5048      {
5049        cond = cmp >= 0;
5050        break;
5051      }
5052
5053      case BC_INST_REL_NE:
5054      {
5055        cond = cmp != 0;
5056        break;
5057      }
5058
5059      case BC_INST_REL_LT:
5060      {
5061        cond = cmp < 0;
5062        break;
5063      }
5064
5065      case BC_INST_REL_GT:
5066      {
5067        cond = cmp > 0;
5068        break;
5069      }
5070    }
5071  }
5072
5073  if (cond) bc_num_one(&res.d.n);
5074
5075  bc_program_binOpRetire(p, &res);
5076
5077  return s;
5078}
5079
5080static BcStatus bc_program_copyToVar(BcProgram *p, char *name,
5081                                     BcType t, int last)
5082{
5083  BcStatus s = BC_STATUS_SUCCESS;
5084  BcResult *ptr, r;
5085  BcVec *vec;
5086  BcNum *n = NULL;
5087  int var = (t == BC_TYPE_VAR);
5088
5089  if (!last) {
5090
5091    ptr = bc_vec_top(&p->results);
5092
5093    if (ptr->t == BC_RESULT_VAR || ptr->t == BC_RESULT_ARRAY) {
5094      BcVec *v = bc_program_search(p, ptr->d.id.name, t);
5095      n = bc_vec_item_rev(v, 1);
5096    }
5097    else s = bc_program_num(p, ptr, &n);
5098  }
5099  else s = bc_program_operand(p, &ptr, &n, 0);
5100
5101  if (s) return s;
5102
5103  s = bc_program_type_match(ptr, t);
5104  if (s) return s;
5105
5106  vec = bc_program_search(p, name, t);
5107
5108  // Do this once more to make sure that pointers were not invalidated.
5109  vec = bc_program_search(p, name, t);
5110
5111  if (var) bc_num_createCopy(&r.d.n, n);
5112  else {
5113
5114    BcVec *v = (BcVec*) n, *rv = &r.d.v;
5115
5116    bc_array_init(rv, 1);
5117    bc_array_copy(rv, v);
5118  }
5119
5120  bc_vec_push(vec, &r.d);
5121  bc_vec_pop(&p->results);
5122
5123  return s;
5124}
5125
5126static BcStatus bc_program_assign(BcProgram *p, uchar inst) {
5127
5128  BcStatus s;
5129  BcResult *left, *right, res;
5130  BcNum *l = NULL, *r = NULL;
5131  int ib, sc;
5132
5133  s = bc_program_assignPrep(p, &left, &l, &right, &r);
5134  if (s) return s;
5135
5136  ib = (left->t == BC_RESULT_IBASE);
5137  sc = (left->t == BC_RESULT_SCALE);
5138
5139  if (inst == BC_INST_ASSIGN) bc_num_copy(l, r);
5140  else {
5141    s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5142    if (s) return s;
5143  }
5144
5145  if (ib || sc || left->t == BC_RESULT_OBASE) {
5146
5147    size_t *ptr;
5148    unsigned long val, max, min;
5149    BcError e;
5150
5151    s = bc_num_ulong(l, &val);
5152    if (s) return s;
5153    e = left->t - BC_RESULT_IBASE + BC_ERROR_EXEC_IBASE;
5154
5155    if (sc) {
5156      max = BC_MAX_SCALE;
5157      min = 0;
5158      ptr = &p->scale;
5159    }
5160    else {
5161      max = ib ? BC_VM->max_ibase : BC_MAX_OBASE;
5162      min = BC_NUM_MIN_BASE;
5163      ptr = ib ? &p->ib_t : &p->ob_t;
5164    }
5165
5166    if (val > max || val < min) return bc_vm_verr(e, min, max);
5167    if (!sc) bc_num_ulong2num(ib ? &p->ib : &p->ob, (unsigned long) val);
5168
5169    *ptr = (size_t) val;
5170    s = BC_STATUS_SUCCESS;
5171  }
5172
5173  bc_num_createCopy(&res.d.n, l);
5174  bc_program_binOpRetire(p, &res);
5175
5176  return s;
5177}
5178
5179static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn) {
5180
5181  BcStatus s = BC_STATUS_SUCCESS;
5182  BcResult r;
5183  char *name = bc_program_name(code, bgn);
5184
5185  r.t = BC_RESULT_VAR;
5186  r.d.id.name = name;
5187
5188  bc_vec_push(&p->results, &r);
5189
5190  return s;
5191}
5192
5193static BcStatus bc_program_pushArray(BcProgram *p, char *code,
5194                                     size_t *bgn, uchar inst)
5195{
5196  BcStatus s = BC_STATUS_SUCCESS;
5197  BcResult r;
5198  BcNum *num = NULL;
5199
5200  r.d.id.name = bc_program_name(code, bgn);
5201
5202  if (inst == BC_INST_ARRAY) {
5203    r.t = BC_RESULT_ARRAY;
5204    bc_vec_push(&p->results, &r);
5205  }
5206  else {
5207
5208    BcResult *operand;
5209    unsigned long temp;
5210
5211    s = bc_program_prep(p, &operand, &num);
5212    if (s) goto err;
5213    s = bc_num_ulong(num, &temp);
5214    if (s) goto err;
5215
5216    if (temp > BC_MAX_DIM) {
5217      s = bc_vm_verr(BC_ERROR_EXEC_ARRAY_LEN, BC_MAX_DIM);
5218      goto err;
5219    }
5220
5221    r.d.id.idx = (size_t) temp;
5222    bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
5223  }
5224
5225err:
5226  if (s) free(r.d.id.name);
5227  return s;
5228}
5229
5230static BcStatus bc_program_incdec(BcProgram *p, uchar inst) {
5231
5232  BcStatus s;
5233  BcResult *ptr, res, copy;
5234  BcNum *num = NULL;
5235  uchar inst2;
5236
5237  s = bc_program_prep(p, &ptr, &num);
5238  if (s) return s;
5239
5240  if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5241    copy.t = BC_RESULT_TEMP;
5242    bc_num_createCopy(&copy.d.n, num);
5243  }
5244
5245  res.t = BC_RESULT_ONE;
5246  inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01);
5247
5248  bc_vec_push(&p->results, &res);
5249  bc_program_assign(p, inst2);
5250
5251  if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5252    bc_vec_pop(&p->results);
5253    bc_vec_push(&p->results, &copy);
5254  }
5255
5256  return s;
5257}
5258
5259static BcStatus bc_program_call(BcProgram *p, char *code,
5260                                size_t *idx)
5261{
5262  BcStatus s = BC_STATUS_SUCCESS;
5263  BcInstPtr ip;
5264  size_t i, nparams = bc_program_index(code, idx);
5265  BcFunc *f;
5266  BcVec *v;
5267  BcId *a;
5268  BcResultData param;
5269  BcResult *arg;
5270
5271  ip.idx = 0;
5272  ip.func = bc_program_index(code, idx);
5273  f = bc_vec_item(&p->fns, ip.func);
5274
5275  if (!f->code.len) return bc_vm_verr(BC_ERROR_EXEC_UNDEF_FUNC, f->name);
5276  if (nparams != f->nparams)
5277    return bc_vm_verr(BC_ERROR_EXEC_PARAMS, f->nparams, nparams);
5278  ip.len = p->results.len - nparams;
5279
5280  for (i = 0; i < nparams; ++i) {
5281
5282    size_t j;
5283    int last = 1;
5284
5285    a = bc_vec_item(&f->autos, nparams - 1 - i);
5286    arg = bc_vec_top(&p->results);
5287
5288    // If I have already pushed to a var, I need to make sure I
5289    // get the previous version, not the already pushed one.
5290    if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) {
5291      for (j = 0; j < i && last; ++j) {
5292        BcId *id = bc_vec_item(&f->autos, nparams - 1 - j);
5293        last = (strcmp(arg->d.id.name, id->name) != 0 ||
5294               (!id->idx) != (arg->t == BC_RESULT_VAR));
5295      }
5296    }
5297
5298    s = bc_program_copyToVar(p, a->name, (BcType) a->idx, last);
5299    if (s) return s;
5300  }
5301
5302  for (; i < f->autos.len; ++i) {
5303
5304    a = bc_vec_item(&f->autos, i);
5305    v = bc_program_search(p, a->name, (BcType) a->idx);
5306
5307    if (a->idx == BC_TYPE_VAR) {
5308      bc_num_init(&param.n, BC_NUM_DEF_SIZE);
5309      bc_vec_push(v, &param.n);
5310    }
5311    else {
5312      bc_array_init(&param.v, 1);
5313      bc_vec_push(v, &param.v);
5314    }
5315  }
5316
5317  bc_vec_push(&p->stack, &ip);
5318
5319  return BC_STATUS_SUCCESS;
5320}
5321
5322static BcStatus bc_program_return(BcProgram *p, uchar inst) {
5323
5324  BcStatus s;
5325  BcResult res;
5326  BcFunc *f;
5327  size_t i;
5328  BcInstPtr *ip = bc_vec_top(&p->stack);
5329
5330  f = bc_vec_item(&p->fns, ip->func);
5331  res.t = BC_RESULT_TEMP;
5332
5333  if (inst == BC_INST_RET) {
5334
5335    BcNum *num = NULL;
5336    BcResult *operand;
5337
5338    s = bc_program_operand(p, &operand, &num, 0);
5339    if (s) return s;
5340
5341    bc_num_createCopy(&res.d.n, num);
5342  }
5343  else if (inst == BC_INST_RET_VOID) res.t = BC_RESULT_VOID;
5344  else bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5345
5346  // We need to pop arguments as well, so this takes that into account.
5347  for (i = 0; i < f->autos.len; ++i) {
5348
5349    BcVec *v;
5350    BcId *a = bc_vec_item(&f->autos, i);
5351
5352    v = bc_program_search(p, a->name, (BcType) a->idx);
5353    bc_vec_pop(v);
5354  }
5355
5356  bc_vec_npop(&p->results, p->results.len - ip->len);
5357  bc_vec_push(&p->results, &res);
5358  bc_vec_pop(&p->stack);
5359
5360  return BC_STATUS_SUCCESS;
5361}
5362
5363unsigned long bc_program_scale(BcNum *n) {
5364  return (unsigned long) n->rdx;
5365}
5366
5367unsigned long bc_program_len(BcNum *n) {
5368
5369  unsigned long len = n->len;
5370  size_t i;
5371
5372  if (n->rdx != n->len) return len;
5373  for (i = n->len - 1; i < n->len && !n->num[i]; --len, --i);
5374
5375  return len;
5376}
5377
5378static BcStatus bc_program_builtin(BcProgram *p, uchar inst) {
5379
5380  BcStatus s;
5381  BcResult *opnd;
5382  BcResult res;
5383  BcNum *num = NULL, *resn = &res.d.n;
5384  int len = (inst == BC_INST_LENGTH);
5385
5386  s = bc_program_operand(p, &opnd, &num, 0);
5387  if (s) return s;
5388
5389  if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, resn, p->scale);
5390  else if (inst == BC_INST_ABS) {
5391    bc_num_createCopy(resn, num);
5392    resn->neg = 0;
5393  }
5394  else {
5395
5396    unsigned long val = 0;
5397
5398    if (len) {
5399      if (opnd->t == BC_RESULT_ARRAY)
5400        val = (unsigned long) ((BcVec*) num)->len;
5401      else val = bc_program_len(num);
5402    }
5403    else val = bc_program_scale(num);
5404
5405    bc_num_createFromUlong(resn, val);
5406  }
5407
5408  bc_program_retire(p, &res, BC_RESULT_TEMP);
5409
5410  return s;
5411}
5412
5413static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
5414
5415  BcResult res;
5416  unsigned long val;
5417
5418  res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
5419  if (inst == BC_INST_IBASE) val = (unsigned long) p->ib_t;
5420  else if (inst == BC_INST_SCALE) val = (unsigned long) p->scale;
5421  else val = (unsigned long) p->ob_t;
5422
5423  bc_num_createFromUlong(&res.d.n, val);
5424  bc_vec_push(&p->results, &res);
5425}
5426
5427void bc_program_free(BcProgram *p) {
5428  bc_vec_free(&p->fns);
5429  bc_vec_free(&p->fn_map);
5430  bc_vec_free(&p->vars);
5431  bc_vec_free(&p->var_map);
5432  bc_vec_free(&p->arrs);
5433  bc_vec_free(&p->arr_map);
5434  bc_vec_free(&p->results);
5435  bc_vec_free(&p->stack);
5436  bc_num_free(&p->last);
5437}
5438
5439void bc_program_init(BcProgram *p) {
5440
5441  BcInstPtr ip;
5442
5443  memset(p, 0, sizeof(BcProgram));
5444  memset(&ip, 0, sizeof(BcInstPtr));
5445
5446  bc_num_setup(&p->ib, p->ib_num, BC_NUM_LONG_LOG10);
5447  bc_num_ten(&p->ib);
5448  p->ib_t = 10;
5449
5450  bc_num_setup(&p->ob, p->ob_num, BC_NUM_LONG_LOG10);
5451  bc_num_ten(&p->ob);
5452  p->ob_t = 10;
5453
5454  bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP);
5455  bc_num_one(&p->one);
5456  bc_num_init(&p->last, BC_NUM_DEF_SIZE);
5457
5458  bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
5459  bc_map_init(&p->fn_map);
5460  bc_program_insertFunc(p, xstrdup(bc_func_main));
5461  bc_program_insertFunc(p, xstrdup(bc_func_read));
5462
5463  bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
5464  bc_map_init(&p->var_map);
5465
5466  bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
5467  bc_map_init(&p->arr_map);
5468
5469  bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
5470  bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
5471  bc_vec_push(&p->stack, &ip);
5472}
5473
5474void bc_program_addFunc(BcProgram *p, BcFunc *f, char *name) {
5475  bc_func_init(f, name);
5476  bc_vec_push(&p->fns, f);
5477}
5478
5479size_t bc_program_insertFunc(BcProgram *p, char *name) {
5480
5481  BcId id, *id_ptr;
5482  BcFunc f;
5483  int new;
5484  size_t idx;
5485
5486  id.name = name;
5487  id.idx = p->fns.len;
5488
5489  new = bc_map_insert(&p->fn_map, &id, &idx);
5490  id_ptr = bc_vec_item(&p->fn_map, idx);
5491  idx = id_ptr->idx;
5492
5493  if (!new) {
5494    BcFunc *func = bc_vec_item(&p->fns, id_ptr->idx);
5495    bc_func_reset(func);
5496    free(name);
5497  }
5498  else bc_program_addFunc(p, &f, name);
5499
5500  return idx;
5501}
5502
5503BcStatus bc_program_reset(BcProgram *p, BcStatus s) {
5504
5505  BcFunc *f;
5506  BcInstPtr *ip;
5507
5508  bc_vec_npop(&p->stack, p->stack.len - 1);
5509  bc_vec_npop(&p->results, p->results.len);
5510
5511  f = bc_vec_item(&p->fns, 0);
5512  ip = bc_vec_top(&p->stack);
5513  ip->idx = f->code.len;
5514
5515  if (BC_SIGTERM || (!s && BC_SIGINT && BC_I)) return BC_STATUS_QUIT;
5516  BC_VM->sig = 0;
5517
5518  if (!s || s == BC_STATUS_SIGNAL) {
5519    if (BC_TTYIN) {
5520      fputs(bc_program_ready_msg, stderr);
5521      fflush(stderr);
5522      s = BC_STATUS_SUCCESS;
5523    }
5524    else s = BC_STATUS_QUIT;
5525  }
5526
5527  return s;
5528}
5529
5530BcStatus bc_program_exec(BcProgram *p) {
5531
5532  BcStatus s = BC_STATUS_SUCCESS;
5533  size_t idx;
5534  BcResult r, *ptr;
5535  BcInstPtr *ip = bc_vec_top(&p->stack);
5536  BcFunc *func = bc_vec_item(&p->fns, ip->func);
5537  char *code = func->code.v;
5538  int cond = 0;
5539  BcNum *num;
5540
5541  while (!s && ip->idx < func->code.len) {
5542
5543    uchar inst = (uchar) code[(ip->idx)++];
5544
5545    switch (inst) {
5546
5547      case BC_INST_JUMP_ZERO:
5548      {
5549        s = bc_program_prep(p, &ptr, &num);
5550        if (s) return s;
5551        cond = !BC_NUM_CMP_ZERO(num);
5552        bc_vec_pop(&p->results);
5553      }
5554      // Fallthrough.
5555      case BC_INST_JUMP:
5556      {
5557        size_t *addr;
5558        idx = bc_program_index(code, &ip->idx);
5559        addr = bc_vec_item(&func->labels, idx);
5560        if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
5561        break;
5562      }
5563
5564      case BC_INST_CALL:
5565      {
5566        s = bc_program_call(p, code, &ip->idx);
5567        break;
5568      }
5569
5570      case BC_INST_INC_PRE:
5571      case BC_INST_DEC_PRE:
5572      case BC_INST_INC_POST:
5573      case BC_INST_DEC_POST:
5574      {
5575        s = bc_program_incdec(p, inst);
5576        break;
5577      }
5578
5579      case BC_INST_HALT:
5580      {
5581        s = BC_STATUS_QUIT;
5582        break;
5583      }
5584
5585      case BC_INST_RET:
5586      case BC_INST_RET0:
5587      case BC_INST_RET_VOID:
5588      {
5589        s = bc_program_return(p, inst);
5590        break;
5591      }
5592
5593      case BC_INST_LAST:
5594      {
5595        r.t = BC_RESULT_LAST;
5596        bc_vec_push(&p->results, &r);
5597        break;
5598      }
5599
5600      case BC_INST_BOOL_OR:
5601      case BC_INST_BOOL_AND:
5602      case BC_INST_REL_EQ:
5603      case BC_INST_REL_LE:
5604      case BC_INST_REL_GE:
5605      case BC_INST_REL_NE:
5606      case BC_INST_REL_LT:
5607      case BC_INST_REL_GT:
5608      {
5609        s = bc_program_logical(p, inst);
5610        break;
5611      }
5612
5613      case BC_INST_READ:
5614      {
5615        s = bc_program_read(p);
5616        break;
5617      }
5618
5619      case BC_INST_VAR:
5620      {
5621        s = bc_program_pushVar(p, code, &ip->idx);
5622        break;
5623      }
5624
5625      case BC_INST_ARRAY_ELEM:
5626      case BC_INST_ARRAY:
5627      {
5628        s = bc_program_pushArray(p, code, &ip->idx, inst);
5629        break;
5630      }
5631
5632      case BC_INST_IBASE:
5633      case BC_INST_SCALE:
5634      case BC_INST_OBASE:
5635      {
5636        bc_program_pushGlobal(p, inst);
5637        break;
5638      }
5639
5640      case BC_INST_LENGTH:
5641      case BC_INST_SCALE_FUNC:
5642      case BC_INST_SQRT:
5643      case BC_INST_ABS:
5644      {
5645        s = bc_program_builtin(p, inst);
5646        break;
5647      }
5648
5649      case BC_INST_NUM:
5650      {
5651        r.t = BC_RESULT_CONSTANT;
5652        r.d.id.idx = bc_program_index(code, &ip->idx);
5653        bc_vec_push(&p->results, &r);
5654        break;
5655      }
5656
5657      case BC_INST_POP:
5658      {
5659        bc_vec_pop(&p->results);
5660        break;
5661      }
5662
5663      case BC_INST_PRINT:
5664      case BC_INST_PRINT_POP:
5665      case BC_INST_PRINT_STR:
5666      {
5667        s = bc_program_print(p, inst, 0);
5668        break;
5669      }
5670
5671      case BC_INST_STR:
5672      {
5673        r.t = BC_RESULT_STR;
5674        r.d.id.idx = bc_program_index(code, &ip->idx);
5675        bc_vec_push(&p->results, &r);
5676        break;
5677      }
5678
5679      case BC_INST_POWER:
5680      case BC_INST_MULTIPLY:
5681      case BC_INST_DIVIDE:
5682      case BC_INST_MODULUS:
5683      case BC_INST_PLUS:
5684      case BC_INST_MINUS:
5685      {
5686        s = bc_program_op(p, inst);
5687        break;
5688      }
5689
5690      case BC_INST_NEG:
5691      case BC_INST_BOOL_NOT:
5692      {
5693        s = bc_program_unary(p, inst);
5694        break;
5695      }
5696
5697      case BC_INST_ASSIGN_POWER:
5698      case BC_INST_ASSIGN_MULTIPLY:
5699      case BC_INST_ASSIGN_DIVIDE:
5700      case BC_INST_ASSIGN_MODULUS:
5701      case BC_INST_ASSIGN_PLUS:
5702      case BC_INST_ASSIGN_MINUS:
5703      case BC_INST_ASSIGN:
5704      {
5705        s = bc_program_assign(p, inst);
5706        break;
5707      }
5708    }
5709
5710    if ((s && s != BC_STATUS_QUIT) || BC_SIGNAL) s = bc_program_reset(p, s);
5711
5712    // If the stack has changed, pointers may be invalid.
5713    ip = bc_vec_top(&p->stack);
5714    func = bc_vec_item(&p->fns, ip->func);
5715    code = func->code.v;
5716  }
5717
5718  return s;
5719}
5720
5721static void bc_vm_sig(int sig) {
5722  int err = errno;
5723  if (sig == SIGINT) {
5724    size_t len = strlen(bc_sig_msg);
5725    if (write(2, bc_sig_msg, len) != (ssize_t) len) sig = 0;
5726  }
5727  BC_VM->sig = (uchar) sig;
5728  errno = err;
5729}
5730
5731void bc_vm_info(void) {
5732  printf("%s %s\n", toys.which->name, "1.1.0");
5733  fputs(bc_copyright, stdout);
5734}
5735
5736static void bc_vm_printError(BcError e, char *fmt,
5737                             size_t line, va_list args)
5738{
5739  // Make sure all of stdout is written first.
5740  fflush(stdout);
5741
5742  fprintf(stderr, fmt, bc_errs[(size_t) bc_err_ids[e]]);
5743  vfprintf(stderr, bc_err_msgs[e], args);
5744
5745  // This is the condition for parsing vs runtime.
5746  // If line is not 0, it is parsing.
5747  if (line) {
5748    fprintf(stderr, "\n    %s", BC_VM->file);
5749    fprintf(stderr, bc_err_line, line);
5750  }
5751  else {
5752    BcInstPtr *ip = bc_vec_item_rev(&BC_VM->prog.stack, 0);
5753    BcFunc *f = bc_vec_item(&BC_VM->prog.fns, ip->func);
5754    fprintf(stderr, "\n    Function: %s", f->name);
5755  }
5756
5757  fputs("\n\n", stderr);
5758  fflush(stderr);
5759}
5760
5761BcStatus bc_vm_error(BcError e, size_t line, ...) {
5762
5763  va_list args;
5764
5765  va_start(args, line);
5766  bc_vm_printError(e, bc_err_fmt, line, args);
5767  va_end(args);
5768
5769  return BC_STATUS_ERROR;
5770}
5771
5772BcStatus bc_vm_posixError(BcError e, size_t line, ...) {
5773
5774  va_list args;
5775  int p = (int) BC_S, w = (int) BC_W;
5776
5777  if (!(p || w)) return BC_STATUS_SUCCESS;
5778
5779  va_start(args, line);
5780  bc_vm_printError(e, p ? bc_err_fmt : bc_warn_fmt, line, args);
5781  va_end(args);
5782
5783  return p ? BC_STATUS_ERROR : BC_STATUS_SUCCESS;
5784}
5785
5786static size_t bc_vm_envLen(char *var) {
5787
5788  char *lenv = getenv(var);
5789  size_t i, len = BC_NUM_PRINT_WIDTH;
5790  int num;
5791
5792  if (!lenv) return len;
5793
5794  len = strlen(lenv);
5795
5796  for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
5797  if (num) {
5798    len = (size_t) atoi(lenv) - 1;
5799    if (len < 2 || len >= UINT16_MAX) len = BC_NUM_PRINT_WIDTH;
5800  }
5801  else len = BC_NUM_PRINT_WIDTH;
5802
5803  return len;
5804}
5805
5806void bc_vm_shutdown(void) {
5807  bc_program_free(&BC_VM->prog);
5808  bc_parse_free(&BC_VM->prs);
5809  free(BC_VM);
5810}
5811
5812static void bc_vm_clean() {
5813
5814  BcProgram *prog = &BC_VM->prog;
5815  BcVec *fns = &prog->fns;
5816  BcFunc *f = bc_vec_item(fns, BC_PROG_MAIN);
5817  BcInstPtr *ip = bc_vec_item(&prog->stack, 0);
5818  int good = !BC_PARSE_NO_EXEC(&BC_VM->prs);
5819
5820  // If this condition is 1, we can get rid of strings,
5821  // constants, and code. This is an idea from busybox.
5822  if (good && prog->stack.len == 1 && !prog->results.len &&
5823      ip->idx == f->code.len)
5824  {
5825    bc_vec_npop(&f->labels, f->labels.len);
5826    bc_vec_npop(&f->strs, f->strs.len);
5827    bc_vec_npop(&f->consts, f->consts.len);
5828    bc_vec_npop(&f->code, f->code.len);
5829    ip->idx = 0;
5830  }
5831}
5832
5833static BcStatus bc_vm_process(char *text, int is_stdin) {
5834
5835  BcStatus s;
5836
5837  s = bc_parse_text(&BC_VM->prs, text);
5838  if (s) goto err;
5839
5840  while (BC_VM->prs.l.t != BC_LEX_EOF) {
5841    s = bc_parse_parse(&BC_VM->prs);
5842    if (s) goto err;
5843  }
5844
5845  if (BC_PARSE_NO_EXEC(&BC_VM->prs)) goto err;
5846
5847  s = bc_program_exec(&BC_VM->prog);
5848  if (BC_I) fflush(stdout);
5849
5850err:
5851  if (s || BC_SIGNAL) s = bc_program_reset(&BC_VM->prog, s);
5852  bc_vm_clean();
5853  return s == BC_STATUS_QUIT || !BC_I || !is_stdin ? s : BC_STATUS_SUCCESS;
5854}
5855
5856static BcStatus bc_vm_file(char *file) {
5857
5858  BcStatus s;
5859  char *data;
5860
5861  bc_lex_file(&BC_VM->prs.l, file);
5862  s = bc_read_file(file, &data);
5863  if (s) return s;
5864
5865  s = bc_vm_process(data, 0);
5866  if (s) goto err;
5867
5868  if (BC_PARSE_NO_EXEC(&BC_VM->prs))
5869    s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_BLOCK);
5870
5871err:
5872  free(data);
5873  return s;
5874}
5875
5876static BcStatus bc_vm_stdin(void) {
5877
5878  BcStatus s = BC_STATUS_SUCCESS;
5879  BcVec buf, buffer;
5880  size_t string = 0;
5881  int comment = 0, done = 0;
5882
5883  bc_lex_file(&BC_VM->prs.l, bc_program_stdin_name);
5884
5885  bc_vec_init(&buffer, sizeof(uchar), NULL);
5886  bc_vec_init(&buf, sizeof(uchar), NULL);
5887  bc_vec_pushByte(&buffer, '\0');
5888
5889  // This loop is complex because the vm tries not to send any lines that end
5890  // with a backslash to the parser. The reason for that is because the parser
5891  // treats a backslash+newline combo as whitespace, per the bc spec. In that
5892  // case, and for strings and comments, the parser will expect more stuff.
5893  while (!done && (s = bc_read_line(&buf, ">>> ")) != BC_STATUS_ERROR &&
5894         buf.len > 1 && !BC_SIGNAL && s != BC_STATUS_SIGNAL)
5895  {
5896    char c2, *str = buf.v;
5897    size_t i, len = buf.len - 1;
5898
5899    done = (s == BC_STATUS_EOF);
5900
5901    if (len >= 2 && str[len - 1] == '\n' && str[len - 2] == '\\') {
5902      bc_vec_concat(&buffer, buf.v);
5903      continue;
5904    }
5905
5906    for (i = 0; i < len; ++i) {
5907
5908      int notend = len > i + 1;
5909      uchar c = (uchar) str[i];
5910
5911      if (!comment && (i - 1 > len || str[i - 1] != '\\')) string ^= c == '"';
5912
5913      if (!string && notend) {
5914
5915        c2 = str[i + 1];
5916
5917        if (c == '/' && !comment && c2 == '*') {
5918          comment = 1;
5919          ++i;
5920        }
5921        else if (c == '*' && comment && c2 == '/') {
5922          comment = 0;
5923          ++i;
5924        }
5925      }
5926    }
5927
5928    bc_vec_concat(&buffer, buf.v);
5929
5930    if (string || comment) continue;
5931    if (len >= 2 && str[len - 2] == '\\' && str[len - 1] == '\n') continue;
5932
5933    s = bc_vm_process(buffer.v, 1);
5934    if (s) goto err;
5935
5936    bc_vec_empty(&buffer);
5937  }
5938
5939  if (s && s != BC_STATUS_EOF) goto err;
5940  else if (BC_SIGNAL && !s) s = BC_STATUS_SIGNAL;
5941  else if (s != BC_STATUS_ERROR) {
5942    if (comment) s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_COMMENT);
5943    else if (string) s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_STRING);
5944    else if (BC_PARSE_NO_EXEC(&BC_VM->prs))
5945      s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_BLOCK);
5946  }
5947
5948err:
5949  bc_vec_free(&buf);
5950  bc_vec_free(&buffer);
5951  return s;
5952}
5953
5954static BcStatus bc_vm_load(char *name, char *text) {
5955
5956  BcStatus s;
5957
5958  bc_lex_file(&BC_VM->prs.l, name);
5959  s = bc_parse_text(&BC_VM->prs, text);
5960
5961  while (!s && BC_VM->prs.l.t != BC_LEX_EOF) s = bc_parse_parse(&BC_VM->prs);
5962
5963  return s;
5964}
5965
5966static BcStatus bc_vm_exec(void) {
5967
5968  BcStatus s = BC_STATUS_SUCCESS;
5969  size_t i;
5970
5971  if (toys.optflags & FLAG_l) {
5972    s = bc_vm_load(bc_lib_name, bc_lib);
5973    if (s) return s;
5974  }
5975
5976  for (i = 0; !s && i < toys.optc; ++i) s = bc_vm_file(toys.optargs[i]);
5977  if (s && s != BC_STATUS_QUIT) return s;
5978
5979  return bc_vm_stdin();
5980}
5981
5982void bc_main(void) {
5983
5984  BcStatus s;
5985  struct sigaction sa;
5986
5987  sigemptyset(&sa.sa_mask);
5988  sa.sa_handler = bc_vm_sig;
5989  sa.sa_flags = 0;
5990  sigaction(SIGINT, &sa, NULL);
5991  sigaction(SIGTERM, &sa, NULL);
5992  sigaction(SIGQUIT, &sa, NULL);
5993
5994  TT.vm = xzalloc(sizeof(BcVm));
5995  BC_VM->line_len = (uint16_t) bc_vm_envLen("BC_LINE_LENGTH");
5996
5997  bc_program_init(&BC_VM->prog);
5998  bc_parse_init(&BC_VM->prs, &BC_VM->prog, BC_PROG_MAIN);
5999
6000  toys.optflags |= FLAG_s * (getenv("POSIXLY_CORRECT") != NULL);
6001  toys.optflags |= isatty(0) ? BC_FLAG_TTYIN : 0;
6002  toys.optflags |= BC_TTYIN && isatty(1) ? FLAG_i : 0;
6003
6004  BC_VM->max_ibase = !BC_S && !BC_W ? BC_NUM_MAX_POSIX_IBASE : BC_NUM_MAX_IBASE;
6005
6006  if (BC_I && !(toys.optflags & FLAG_q)) bc_vm_info();
6007
6008  s = bc_vm_exec();
6009
6010  if (CFG_TOYBOX_FREE) bc_vm_shutdown();
6011  toys.exitval = (int) (s != BC_STATUS_ERROR ? BC_STATUS_SUCCESS : s);
6012}
6013