blob: 5d8b665433d4e4ecb36b8f4e663233afc929e7f0 [file] [log] [blame]
Gavin Howard6556eed2018-02-27 17:10:27 -07001/*
Gavin Howardb5904bf2018-02-20 13:28:18 -07002 * *****************************************************************************
Gavin Howard5715b042018-02-12 16:11:42 -07003 *
Gavin Howardb5904bf2018-02-20 13:28:18 -07004 * Copyright 2018 Gavin D. Howard
Gavin Howard5715b042018-02-12 16:11:42 -07005 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 *
Gavin Howardb5904bf2018-02-20 13:28:18 -070017 * *****************************************************************************
Gavin Howard5715b042018-02-12 16:11:42 -070018 *
19 * Code to execute bc programs.
20 *
21 */
22
Gavin Howard27fdfb92018-03-21 07:56:59 -060023#include <assert.h>
Gavin Howard411f7322018-09-26 17:21:19 -060024#include <stdbool.h>
Gavin Howard8a596d42018-01-15 15:46:01 -070025#include <string.h>
26
Gavin Howard82cdc6f2018-02-20 14:23:19 -070027#include <unistd.h>
Gavin Howard8a596d42018-01-15 15:46:01 -070028
Gavin Howarda54cabf2018-03-28 14:50:33 -060029#include <io.h>
Gavin Howard13ccc4a2018-02-15 14:09:41 -070030#include <parse.h>
Gavin Howardd2a05252018-09-27 14:00:40 -060031#include <program.h>
Gavin Howardd5551672018-09-22 19:52:42 -060032#include <vm.h>
Gavin Howard8a596d42018-01-15 15:46:01 -070033
Gavin Howard0e58ded2018-10-02 15:06:52 -060034BcStatus bc_program_search(BcProgram *p, char *name, BcVec **ret, bool var) {
Gavin Howard3affc802018-02-27 19:57:38 -070035
Gavin Howard63738202018-09-26 15:34:20 -060036 BcStatus s;
Gavin Howard0e58ded2018-10-02 15:06:52 -060037 BcEntry e, *ptr;
38 BcVec *v;
39 BcVecO *vo;
40 size_t i;
41 BcResultData data;
42 bool new;
Gavin Howard3affc802018-02-27 19:57:38 -070043
Gavin Howard0e58ded2018-10-02 15:06:52 -060044 v = var ? &p->vars : &p->arrs;
45 vo = var ? &p->var_map : &p->arr_map;
Gavin Howard97eb8562018-03-21 08:04:29 -060046
Gavin Howard0e58ded2018-10-02 15:06:52 -060047 e.name = name;
48 e.idx = v->len;
Gavin Howard3affc802018-02-27 19:57:38 -070049
Gavin Howard0e58ded2018-10-02 15:06:52 -060050 if ((new = (s = bc_veco_insert(vo, &e, &i)) != BC_STATUS_VEC_ITEM_EXISTS)) {
Gavin Howard63738202018-09-26 15:34:20 -060051 if (s) return s;
Gavin Howard0e58ded2018-10-02 15:06:52 -060052 if ((s = bc_array_init(&data.array, var))) return s;
53 if ((s = bc_vec_push(v, &data.array))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -060054 }
Gavin Howard3affc802018-02-27 19:57:38 -070055
Gavin Howard0e58ded2018-10-02 15:06:52 -060056 ptr = bc_veco_item(vo, i);
57 if (new && !(ptr->name = strdup(e.name))) return BC_STATUS_ALLOC_ERR;
58 *ret = bc_vec_item(v, ptr->idx);
Gavin Howard63738202018-09-26 15:34:20 -060059
60 return BC_STATUS_SUCCESS;
Gavin Howard37296462018-09-07 15:57:03 -060061
62err:
Gavin Howardc9a9c472018-10-02 17:23:01 -060063 bc_vec_free(&data.array);
Gavin Howard63738202018-09-26 15:34:20 -060064 return s;
Gavin Howard3affc802018-02-27 19:57:38 -070065}
66
Gavin Howard63738202018-09-26 15:34:20 -060067BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex) {
Gavin Howard84095072018-02-27 15:36:58 -070068
Gavin Howard63738202018-09-26 15:34:20 -060069 BcStatus s = BC_STATUS_SUCCESS;
Gavin Howard84095072018-02-27 15:36:58 -070070
Gavin Howard0e58ded2018-10-02 15:06:52 -060071 switch (r->t) {
Gavin Howard84095072018-02-27 15:36:58 -070072
Gavin Howard63738202018-09-26 15:34:20 -060073 case BC_RESULT_TEMP:
74 case BC_RESULT_SCALE:
75 {
Gavin Howard648c01c2018-10-04 10:14:16 -060076 *num = &r->data.n;
Gavin Howard63738202018-09-26 15:34:20 -060077 break;
78 }
Gavin Howard84095072018-02-27 15:36:58 -070079
Gavin Howard63738202018-09-26 15:34:20 -060080 case BC_RESULT_CONSTANT:
81 {
82 char **str = bc_vec_item(&p->consts, r->data.id.idx);
Gavin Howard03610742018-09-27 10:48:29 -060083 size_t base_t, len = strlen(*str);
84 BcNum *base;
Gavin Howard84095072018-02-27 15:36:58 -070085
Gavin Howard648c01c2018-10-04 10:14:16 -060086 if ((s = bc_num_init(&r->data.n, len))) return s;
Gavin Howard84095072018-02-27 15:36:58 -070087
Gavin Howard03610742018-09-27 10:48:29 -060088 hex = hex && len == 1;
89 base = hex ? &p->hexb : &p->ib;
90 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
Gavin Howard84095072018-02-27 15:36:58 -070091
Gavin Howard648c01c2018-10-04 10:14:16 -060092 if ((s = bc_num_parse(&r->data.n, *str, base, base_t))) {
93 bc_num_free(&r->data.n);
Gavin Howard63738202018-09-26 15:34:20 -060094 return s;
95 }
Gavin Howard84095072018-02-27 15:36:58 -070096
Gavin Howard648c01c2018-10-04 10:14:16 -060097 *num = &r->data.n;
Gavin Howard0e58ded2018-10-02 15:06:52 -060098 r->t = BC_RESULT_TEMP;
Gavin Howard84095072018-02-27 15:36:58 -070099
Gavin Howard63738202018-09-26 15:34:20 -0600100 break;
101 }
Gavin Howard84095072018-02-27 15:36:58 -0700102
Gavin Howard63738202018-09-26 15:34:20 -0600103 case BC_RESULT_VAR:
104 case BC_RESULT_ARRAY:
Gavin Howard13ab0152018-09-27 11:46:55 -0600105 case BC_RESULT_ARRAY_ELEM:
Gavin Howard63738202018-09-26 15:34:20 -0600106 {
Gavin Howard13ab0152018-09-27 11:46:55 -0600107 BcVec *v;
108
Gavin Howard0e58ded2018-10-02 15:06:52 -0600109 s = bc_program_search(p, r->data.id.name, &v, r->t == BC_RESULT_VAR);
Gavin Howard13ab0152018-09-27 11:46:55 -0600110 if (s) return s;
111
Gavin Howard0e58ded2018-10-02 15:06:52 -0600112 if (r->t == BC_RESULT_ARRAY_ELEM) {
Gavin Howard13ab0152018-09-27 11:46:55 -0600113
Gavin Howard0e58ded2018-10-02 15:06:52 -0600114 if ((v = bc_vec_top(v))->len <= r->data.id.idx) {
Gavin Howard13ab0152018-09-27 11:46:55 -0600115 if ((s = bc_array_expand(v, r->data.id.idx + 1))) return s;
116 }
117
118 *num = bc_vec_item(v, r->data.id.idx);
119 }
Gavin Howard0e58ded2018-10-02 15:06:52 -0600120 else if (r->t == BC_RESULT_ARRAY) {
121 v = bc_vec_top(v);
122 *num = (BcNum*) v;
123 }
124 else *num = bc_vec_top(v);
Gavin Howard13ab0152018-09-27 11:46:55 -0600125
Gavin Howard63738202018-09-26 15:34:20 -0600126 break;
127 }
Gavin Howard84095072018-02-27 15:36:58 -0700128
Gavin Howard63738202018-09-26 15:34:20 -0600129 case BC_RESULT_LAST:
130 {
131 *num = &p->last;
132 break;
133 }
Gavin Howard84095072018-02-27 15:36:58 -0700134
Gavin Howard63738202018-09-26 15:34:20 -0600135 case BC_RESULT_IBASE:
136 {
137 *num = &p->ib;
138 break;
139 }
Gavin Howard84095072018-02-27 15:36:58 -0700140
Gavin Howard63738202018-09-26 15:34:20 -0600141 case BC_RESULT_OBASE:
142 {
143 *num = &p->ob;
144 break;
145 }
Gavin Howard84095072018-02-27 15:36:58 -0700146
Gavin Howard63738202018-09-26 15:34:20 -0600147 case BC_RESULT_ONE:
148 {
149 *num = &p->one;
150 break;
151 }
Gavin Howard84095072018-02-27 15:36:58 -0700152
Gavin Howard63738202018-09-26 15:34:20 -0600153 default:
154 {
Gavin Howard63738202018-09-26 15:34:20 -0600155 assert(false);
Gavin Howardc39fd492018-10-04 10:07:03 -0600156 (void) r;
Gavin Howard63738202018-09-26 15:34:20 -0600157 break;
158 }
159 }
Gavin Howard84095072018-02-27 15:36:58 -0700160
Gavin Howard63738202018-09-26 15:34:20 -0600161 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700162}
Gavin Howard6d89b5d2018-02-26 13:21:34 -0700163
Gavin Howard63738202018-09-26 15:34:20 -0600164BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **left, BcNum **lval,
165 BcResult **right, BcNum **rval, bool assign)
Gavin Howard84095072018-02-27 15:36:58 -0700166{
Gavin Howard63738202018-09-26 15:34:20 -0600167 BcStatus s;
168 bool hex;
169 BcResultType lt, rt;
Gavin Howard84095072018-02-27 15:36:58 -0700170
Gavin Howard21925472018-09-29 19:29:25 -0600171 assert(p && left && lval && right && rval);
172
Gavin Howard1e758c82018-09-29 19:57:37 -0600173 if (!BC_PROG_CHECK_STACK(&p->results, 2)) return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howard84095072018-02-27 15:36:58 -0700174
Gavin Howard63738202018-09-26 15:34:20 -0600175 *right = bc_vec_item_rev(&p->results, 0);
176 *left = bc_vec_item_rev(&p->results, 1);
Gavin Howard84095072018-02-27 15:36:58 -0700177
Gavin Howard0e58ded2018-10-02 15:06:52 -0600178 lt = (*left)->t;
179 rt = (*right)->t;
Gavin Howard63738202018-09-26 15:34:20 -0600180 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
Gavin Howardc4987612018-09-21 13:14:09 -0600181
Gavin Howard985ad602018-10-02 14:50:25 -0600182 if (lt == BC_RESULT_ARRAY || rt == BC_RESULT_ARRAY ||
183 lt == BC_RESULT_STR || rt == BC_RESULT_STR)
Gavin Howard63738202018-09-26 15:34:20 -0600184 {
185 return BC_STATUS_EXEC_BAD_TYPE;
186 }
Gavin Howard4c8ff2d2018-09-18 15:24:07 -0600187
Gavin Howard63738202018-09-26 15:34:20 -0600188 if ((s = bc_program_num(p, *left, lval, false))) return s;
189 if ((s = bc_program_num(p, *right, rval, hex))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700190
Gavin Howard63738202018-09-26 15:34:20 -0600191 // We run this again under these conditions in case any vector has been
192 // reallocated out from under the BcNums or arrays we had.
193 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
194 s = bc_program_num(p, *left, lval, false);
Gavin Howardee938c02018-09-21 12:27:44 -0600195
Gavin Howard63738202018-09-26 15:34:20 -0600196 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700197}
198
Gavin Howard1f3e7582018-09-29 02:19:54 -0600199BcStatus bc_program_binOpRetire(BcProgram *p, BcResult *r) {
Gavin Howard0e58ded2018-10-02 15:06:52 -0600200 r->t = BC_RESULT_TEMP;
Gavin Howard63738202018-09-26 15:34:20 -0600201 bc_vec_pop(&p->results);
202 bc_vec_pop(&p->results);
Gavin Howard90198862018-09-29 03:37:47 -0600203 return bc_vec_push(&p->results, r);
Gavin Howard84095072018-02-27 15:36:58 -0700204}
205
Gavin Howardb4584aa2018-09-28 10:45:33 -0600206BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, bool arr)
Gavin Howard38bea812018-09-20 12:01:25 -0600207{
Gavin Howard4e4a0112018-09-28 15:45:34 -0600208 BcResultType t;
209
Gavin Howard21925472018-09-29 19:29:25 -0600210 assert(p && r && n);
211
Gavin Howard1e758c82018-09-29 19:57:37 -0600212 if (!BC_PROG_CHECK_STACK(&p->results, 1)) return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howard4c8ff2d2018-09-18 15:24:07 -0600213
Gavin Howard90198862018-09-29 03:37:47 -0600214 *r = bc_vec_top(&p->results);
Gavin Howard0e58ded2018-10-02 15:06:52 -0600215 t = (*r)->t;
Gavin Howard4c8ff2d2018-09-18 15:24:07 -0600216
Gavin Howard985ad602018-10-02 14:50:25 -0600217 if ((t == BC_RESULT_ARRAY && !arr) || t == BC_RESULT_STR)
Gavin Howard63738202018-09-26 15:34:20 -0600218 return BC_STATUS_EXEC_BAD_TYPE;
Gavin Howard4c8ff2d2018-09-18 15:24:07 -0600219
Gavin Howard63738202018-09-26 15:34:20 -0600220 return bc_program_num(p, *r, n, false);
Gavin Howard84095072018-02-27 15:36:58 -0700221}
222
Gavin Howard3950bb62018-09-28 15:46:00 -0600223BcStatus bc_program_retire(BcProgram *p, BcResult *r, BcResultType t) {
Gavin Howard0e58ded2018-10-02 15:06:52 -0600224 r->t = t;
Gavin Howard63738202018-09-26 15:34:20 -0600225 bc_vec_pop(&p->results);
Gavin Howard90198862018-09-29 03:37:47 -0600226 return bc_vec_push(&p->results, r);
Gavin Howard84095072018-02-27 15:36:58 -0700227}
228
Gavin Howard3f68df72018-03-22 20:30:27 -0600229BcStatus bc_program_op(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700230
Gavin Howard63738202018-09-26 15:34:20 -0600231 BcStatus s;
232 BcResult *opd1, *opd2, res;
233 BcNum *n1, *n2;
234 BcNumBinaryOp op;
Gavin Howard84095072018-02-27 15:36:58 -0700235
Gavin Howard63738202018-09-26 15:34:20 -0600236 if ((s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false))) return s;
Gavin Howard648c01c2018-10-04 10:14:16 -0600237 if ((s = bc_num_init(&res.data.n, BC_NUM_DEF_SIZE))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700238
Gavin Howard63738202018-09-26 15:34:20 -0600239 op = bc_program_ops[inst - BC_INST_POWER];
Gavin Howard648c01c2018-10-04 10:14:16 -0600240 if ((s = op(n1, n2, &res.data.n, p->scale))) goto err;
Gavin Howard1f3e7582018-09-29 02:19:54 -0600241 if ((s = bc_program_binOpRetire(p, &res))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700242
Gavin Howard63738202018-09-26 15:34:20 -0600243 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700244
245err:
Gavin Howard648c01c2018-10-04 10:14:16 -0600246 bc_num_free(&res.data.n);
Gavin Howard63738202018-09-26 15:34:20 -0600247 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700248}
249
Gavin Howard3f68df72018-03-22 20:30:27 -0600250BcStatus bc_program_read(BcProgram *p) {
Gavin Howard84095072018-02-27 15:36:58 -0700251
Gavin Howard63738202018-09-26 15:34:20 -0600252 BcStatus s;
253 BcParse parse;
Gavin Howard7efe7442018-09-27 10:47:01 -0600254 BcVec buf;
Gavin Howard63738202018-09-26 15:34:20 -0600255 BcInstPtr ip;
Gavin Howard63738202018-09-26 15:34:20 -0600256 BcFunc *func = bc_vec_item(&p->fns, BC_PROG_READ);
Gavin Howard84095072018-02-27 15:36:58 -0700257
Gavin Howard63738202018-09-26 15:34:20 -0600258 func->code.len = 0;
Gavin Howard84095072018-02-27 15:36:58 -0700259
Gavin Howard7efe7442018-09-27 10:47:01 -0600260 if ((s = bc_vec_init(&buf, sizeof(char), NULL))) return BC_STATUS_ALLOC_ERR;
Gavin Howard6e59dee2018-09-27 12:09:00 -0600261 if ((s = bc_io_getline(&buf, "read> "))) goto io_err;
Gavin Howard84095072018-02-27 15:36:58 -0700262
Gavin Howardd2a05252018-09-27 14:00:40 -0600263 if ((s = p->parse_init(&parse, p))) goto io_err;
Gavin Howardc39fd492018-10-04 10:07:03 -0600264 bc_lex_file(&parse.l, bc_program_stdin_name);
265 if ((s = bc_lex_text(&parse.l, buf.v))) goto exec_err;
Gavin Howard84095072018-02-27 15:36:58 -0700266
Gavin Howard00a7a5f2018-10-01 12:30:38 -0600267 s = p->parse_exp(&parse, &func->code, BC_PARSE_NOREAD, bc_parse_next_read);
Gavin Howard63738202018-09-26 15:34:20 -0600268 if (s) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700269
Gavin Howardc39fd492018-10-04 10:07:03 -0600270 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Gavin Howard63738202018-09-26 15:34:20 -0600271 s = BC_STATUS_EXEC_BAD_READ_EXPR;
272 goto exec_err;
273 }
Gavin Howard84095072018-02-27 15:36:58 -0700274
Gavin Howard63738202018-09-26 15:34:20 -0600275 ip.func = BC_PROG_READ;
276 ip.idx = 0;
277 ip.len = p->results.len;
Gavin Howard84095072018-02-27 15:36:58 -0700278
Gavin Howard90198862018-09-29 03:37:47 -0600279 if ((s = bc_vec_push(&p->stack, &ip))) goto exec_err;
Gavin Howard63738202018-09-26 15:34:20 -0600280 if ((s = bc_program_exec(p))) goto exec_err;
Gavin Howardceaf64d2018-03-05 11:20:34 -0700281
Gavin Howard63738202018-09-26 15:34:20 -0600282 bc_vec_pop(&p->stack);
Gavin Howardceaf64d2018-03-05 11:20:34 -0700283
Gavin Howard84095072018-02-27 15:36:58 -0700284exec_err:
Gavin Howard63738202018-09-26 15:34:20 -0600285 bc_parse_free(&parse);
Gavin Howard84095072018-02-27 15:36:58 -0700286io_err:
Gavin Howard7efe7442018-09-27 10:47:01 -0600287 bc_vec_free(&buf);
Gavin Howard63738202018-09-26 15:34:20 -0600288 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700289}
290
Gavin Howard63738202018-09-26 15:34:20 -0600291size_t bc_program_index(char *code, size_t *bgn) {
Gavin Howard84095072018-02-27 15:36:58 -0700292
Gavin Howard63738202018-09-26 15:34:20 -0600293 uint8_t amt = code[(*bgn)++], i = 0;
294 size_t res = 0;
Gavin Howard84095072018-02-27 15:36:58 -0700295
Gavin Howard63738202018-09-26 15:34:20 -0600296 for (; i < amt; ++i) res |= (((size_t) code[(*bgn)++]) << (i * CHAR_BIT));
Gavin Howard84095072018-02-27 15:36:58 -0700297
Gavin Howard63738202018-09-26 15:34:20 -0600298 return res;
Gavin Howard84095072018-02-27 15:36:58 -0700299}
300
Gavin Howard63738202018-09-26 15:34:20 -0600301char* bc_program_name(char *code, size_t *bgn) {
Gavin Howard84095072018-02-27 15:36:58 -0700302
Gavin Howard63738202018-09-26 15:34:20 -0600303 size_t len, i;
Gavin Howard74f99332018-09-28 10:03:07 -0600304 char byte, *s, *string = (char*) (code + *bgn), *ptr;
Gavin Howard84095072018-02-27 15:36:58 -0700305
Gavin Howard74f99332018-09-28 10:03:07 -0600306 ptr = strchr(string, BC_PARSE_STREND);
Gavin Howard63738202018-09-26 15:34:20 -0600307 if (ptr) len = ((unsigned long) ptr) - ((unsigned long) string);
308 else len = strlen(string);
Gavin Howard84095072018-02-27 15:36:58 -0700309
Gavin Howard63738202018-09-26 15:34:20 -0600310 if (!(s = malloc(len + 1))) return NULL;
Gavin Howard84095072018-02-27 15:36:58 -0700311
Gavin Howard74f99332018-09-28 10:03:07 -0600312 for (i = 0; (byte = (char) code[(*bgn)++]) && byte != BC_PARSE_STREND; ++i)
Gavin Howard63738202018-09-26 15:34:20 -0600313 s[i] = byte;
Gavin Howard84095072018-02-27 15:36:58 -0700314
Gavin Howard63738202018-09-26 15:34:20 -0600315 s[i] = '\0';
Gavin Howard84095072018-02-27 15:36:58 -0700316
Gavin Howard63738202018-09-26 15:34:20 -0600317 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700318}
319
Gavin Howard3f68df72018-03-22 20:30:27 -0600320BcStatus bc_program_printString(const char *str, size_t *nchars) {
Gavin Howard84095072018-02-27 15:36:58 -0700321
Gavin Howard63738202018-09-26 15:34:20 -0600322 size_t i, len = strlen(str);
Gavin Howard84095072018-02-27 15:36:58 -0700323
Gavin Howard63738202018-09-26 15:34:20 -0600324 for (i = 0; i < len; ++i, ++(*nchars)) {
Gavin Howard84095072018-02-27 15:36:58 -0700325
Gavin Howard6b7d6cb2018-09-28 14:21:47 -0600326 int err, c;
Gavin Howardf6e3fb32018-08-09 13:48:59 -0600327
Gavin Howard63738202018-09-26 15:34:20 -0600328 if ((c = str[i]) != '\\') err = putchar(c);
329 else {
Gavin Howard84095072018-02-27 15:36:58 -0700330
Gavin Howard6b7d6cb2018-09-28 14:21:47 -0600331 assert(i + 1 < len);
332 c = str[++i];
Gavin Howard84095072018-02-27 15:36:58 -0700333
Gavin Howard6b7d6cb2018-09-28 14:21:47 -0600334 switch (c) {
Gavin Howard84095072018-02-27 15:36:58 -0700335
Gavin Howard63738202018-09-26 15:34:20 -0600336 case 'a':
337 {
338 err = putchar('\a');
339 break;
340 }
Gavin Howard84095072018-02-27 15:36:58 -0700341
Gavin Howard63738202018-09-26 15:34:20 -0600342 case 'b':
343 {
344 err = putchar('\b');
345 break;
346 }
Gavin Howard84095072018-02-27 15:36:58 -0700347
Gavin Howard63738202018-09-26 15:34:20 -0600348 case 'e':
349 {
350 err = putchar('\\');
351 break;
352 }
Gavin Howard84095072018-02-27 15:36:58 -0700353
Gavin Howard63738202018-09-26 15:34:20 -0600354 case 'f':
355 {
356 err = putchar('\f');
357 break;
358 }
Gavin Howard84095072018-02-27 15:36:58 -0700359
Gavin Howard63738202018-09-26 15:34:20 -0600360 case 'n':
361 {
362 err = putchar('\n');
363 *nchars = SIZE_MAX;
364 break;
365 }
Gavin Howard84095072018-02-27 15:36:58 -0700366
Gavin Howard63738202018-09-26 15:34:20 -0600367 case 'r':
368 {
369 err = putchar('\r');
370 break;
371 }
Gavin Howard84095072018-02-27 15:36:58 -0700372
Gavin Howard63738202018-09-26 15:34:20 -0600373 case 'q':
374 {
375 err = putchar('"');
376 break;
377 }
Gavin Howard84095072018-02-27 15:36:58 -0700378
Gavin Howard63738202018-09-26 15:34:20 -0600379 case 't':
380 {
381 err = putchar('\t');
382 break;
383 }
Gavin Howard84095072018-02-27 15:36:58 -0700384
Gavin Howard63738202018-09-26 15:34:20 -0600385 default:
386 {
Gavin Howard07f7ff52018-09-28 14:22:06 -0600387 // Just print the character.
388 err = putchar(c);
Gavin Howard63738202018-09-26 15:34:20 -0600389 break;
390 }
391 }
392 }
Gavin Howard84095072018-02-27 15:36:58 -0700393
Gavin Howard63738202018-09-26 15:34:20 -0600394 if (err == EOF) return BC_STATUS_IO_ERR;
395 }
Gavin Howard84095072018-02-27 15:36:58 -0700396
Gavin Howard63738202018-09-26 15:34:20 -0600397 return BC_STATUS_SUCCESS;
Gavin Howard84095072018-02-27 15:36:58 -0700398}
399
Gavin Howardc935ff12018-09-29 02:18:45 -0600400BcStatus bc_program_print(BcProgram *p, uint8_t inst, size_t idx) {
Gavin Howard4e4a0112018-09-28 15:45:34 -0600401
402 BcStatus s = BC_STATUS_SUCCESS;
403 BcResult *r;
Gavin Howardc935ff12018-09-29 02:18:45 -0600404 size_t len, i;
Gavin Howard4e4a0112018-09-28 15:45:34 -0600405 char *str;
406
Gavin Howard21925472018-09-29 19:29:25 -0600407 assert(p);
408
Gavin Howard1e758c82018-09-29 19:57:37 -0600409 if (!BC_PROG_CHECK_STACK(&p->results, idx + 1))
410 return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howard4e4a0112018-09-28 15:45:34 -0600411
Gavin Howardc935ff12018-09-29 02:18:45 -0600412 r = bc_vec_item_rev(&p->results, idx);
Gavin Howard4e4a0112018-09-28 15:45:34 -0600413
Gavin Howard0e58ded2018-10-02 15:06:52 -0600414 if (r->t == BC_RESULT_STR) {
Gavin Howard4e4a0112018-09-28 15:45:34 -0600415
416 idx = r->data.id.idx;
417 assert(idx < p->strs.len);
418
419 str = *((char**) bc_vec_item(&p->strs, idx));
420
421 if (inst == BC_INST_PRINT_STR) {
Gavin Howardc935ff12018-09-29 02:18:45 -0600422 for (i = 0, len = strlen(str); i < len; ++i) {
423 char c = str[i];
Gavin Howard4e4a0112018-09-28 15:45:34 -0600424 if (putchar(c) == EOF) return BC_STATUS_IO_ERR;
425 if (c == '\n') p->nchars = SIZE_MAX;
426 ++p->nchars;
427 }
428 }
429 else s = bc_program_printString(str, &p->nchars);
430 }
431 else {
432
433 BcNum *num;
434 bool nl = inst == BC_INST_PRINT;
435
436 assert(inst != BC_INST_PRINT_STR);
437
438 if ((s = bc_program_prep(p, &r, &num, false))) return s;
439
440 s = bc_num_print(num, &p->ob, p->ob_t, nl, &p->nchars, p->len);
441 if (s) return s;
442 if ((s = bc_num_copy(&p->last, num))) return s;
443
444 if (!nl) bc_vec_pop(&p->results);
445 }
446
447 return s;
448}
449
Gavin Howard3f68df72018-03-22 20:30:27 -0600450BcStatus bc_program_negate(BcProgram *p) {
Gavin Howard3a947362018-03-02 11:25:48 -0700451
Gavin Howard63738202018-09-26 15:34:20 -0600452 BcStatus s;
453 BcResult res, *ptr;
454 BcNum *num;
Gavin Howard3a947362018-03-02 11:25:48 -0700455
Gavin Howardb4584aa2018-09-28 10:45:33 -0600456 if ((s = bc_program_prep(p, &ptr, &num, false))) return s;
Gavin Howard648c01c2018-10-04 10:14:16 -0600457 if ((s = bc_num_init(&res.data.n, num->len))) return s;
458 if ((s = bc_num_copy(&res.data.n, num))) goto err;
Gavin Howard3a947362018-03-02 11:25:48 -0700459
Gavin Howard648c01c2018-10-04 10:14:16 -0600460 res.data.n.neg = !res.data.n.neg;
Gavin Howarda654f112018-03-03 09:47:34 -0700461
Gavin Howardb4584aa2018-09-28 10:45:33 -0600462 if ((s = bc_program_retire(p, &res, BC_RESULT_TEMP))) goto err;
Gavin Howard3a947362018-03-02 11:25:48 -0700463
Gavin Howard63738202018-09-26 15:34:20 -0600464 return s;
Gavin Howard3a947362018-03-02 11:25:48 -0700465
466err:
Gavin Howard648c01c2018-10-04 10:14:16 -0600467 bc_num_free(&res.data.n);
Gavin Howard63738202018-09-26 15:34:20 -0600468 return s;
Gavin Howard3a947362018-03-02 11:25:48 -0700469}
470
Gavin Howard3f68df72018-03-22 20:30:27 -0600471BcStatus bc_program_logical(BcProgram *p, uint8_t inst) {
Gavin Howard843fa792018-02-27 16:42:52 -0700472
Gavin Howard63738202018-09-26 15:34:20 -0600473 BcStatus s;
474 BcResult *opd1, *opd2, res;
475 BcNum *n1, *n2;
476 bool cond;
477 ssize_t cmp;
Gavin Howard843fa792018-02-27 16:42:52 -0700478
Gavin Howard296c98b2018-10-02 15:07:36 -0600479 if ((s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false))) return s;
Gavin Howard648c01c2018-10-04 10:14:16 -0600480 if ((s = bc_num_init(&res.data.n, BC_NUM_DEF_SIZE))) return s;
Gavin Howard843fa792018-02-27 16:42:52 -0700481
Gavin Howard63738202018-09-26 15:34:20 -0600482 if (inst == BC_INST_BOOL_AND)
483 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
484 else if (inst == BC_INST_BOOL_OR)
485 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
486 else {
Gavin Howard843fa792018-02-27 16:42:52 -0700487
Gavin Howard63738202018-09-26 15:34:20 -0600488 cmp = bc_num_cmp(n1, n2);
Gavin Howard843fa792018-02-27 16:42:52 -0700489
Gavin Howard63738202018-09-26 15:34:20 -0600490 switch (inst) {
Gavin Howard28827802018-09-27 11:01:51 -0600491
Gavin Howard63738202018-09-26 15:34:20 -0600492 case BC_INST_REL_EQ:
493 {
494 cond = cmp == 0;
495 break;
496 }
Gavin Howard843fa792018-02-27 16:42:52 -0700497
Gavin Howard63738202018-09-26 15:34:20 -0600498 case BC_INST_REL_LE:
499 {
500 cond = cmp <= 0;
501 break;
502 }
Gavin Howard843fa792018-02-27 16:42:52 -0700503
Gavin Howard63738202018-09-26 15:34:20 -0600504 case BC_INST_REL_GE:
505 {
506 cond = cmp >= 0;
507 break;
508 }
Gavin Howard843fa792018-02-27 16:42:52 -0700509
Gavin Howard63738202018-09-26 15:34:20 -0600510 case BC_INST_REL_NE:
511 {
512 cond = cmp != 0;
513 break;
514 }
Gavin Howard843fa792018-02-27 16:42:52 -0700515
Gavin Howard63738202018-09-26 15:34:20 -0600516 case BC_INST_REL_LT:
517 {
518 cond = cmp < 0;
519 break;
520 }
Gavin Howard843fa792018-02-27 16:42:52 -0700521
Gavin Howard63738202018-09-26 15:34:20 -0600522 case BC_INST_REL_GT:
523 {
524 cond = cmp > 0;
525 break;
526 }
Gavin Howardc39fd492018-10-04 10:07:03 -0600527#ifndef NDEBUG
Gavin Howard63738202018-09-26 15:34:20 -0600528 default:
529 {
Gavin Howardc39fd492018-10-04 10:07:03 -0600530 assert(false);
Gavin Howard63738202018-09-26 15:34:20 -0600531 break;
532 }
Gavin Howardc39fd492018-10-04 10:07:03 -0600533#endif // NDEBUG
Gavin Howard63738202018-09-26 15:34:20 -0600534 }
535 }
Gavin Howard843fa792018-02-27 16:42:52 -0700536
Gavin Howard648c01c2018-10-04 10:14:16 -0600537 (cond ? bc_num_one : bc_num_zero)(&res.data.n);
Gavin Howard843fa792018-02-27 16:42:52 -0700538
Gavin Howard1f3e7582018-09-29 02:19:54 -0600539 if ((s = bc_program_binOpRetire(p, &res))) goto err;
Gavin Howard843fa792018-02-27 16:42:52 -0700540
Gavin Howard63738202018-09-26 15:34:20 -0600541 return s;
Gavin Howard843fa792018-02-27 16:42:52 -0700542
543err:
Gavin Howard648c01c2018-10-04 10:14:16 -0600544 bc_num_free(&res.data.n);
Gavin Howard63738202018-09-26 15:34:20 -0600545 return s;
Gavin Howard843fa792018-02-27 16:42:52 -0700546}
547
Gavin Howarde6e84762018-10-03 11:46:34 -0600548#ifdef DC_ENABLED
Gavin Howard0e58ded2018-10-02 15:06:52 -0600549BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *var, bool push)
Gavin Howardda4cfc02018-10-01 12:27:34 -0600550{
551 BcNum n2;
552
553 memset(&n2, 0, sizeof(BcNum));
554 n2.rdx = r->data.id.idx;
555
Gavin Howard0e58ded2018-10-02 15:06:52 -0600556 if (push) bc_vec_pop(&p->results);
Gavin Howardda4cfc02018-10-01 12:27:34 -0600557
558 return bc_vec_push(var, &n2);
559}
Gavin Howarde6e84762018-10-03 11:46:34 -0600560#endif // DC_ENABLED
Gavin Howardda4cfc02018-10-01 12:27:34 -0600561
Gavin Howard0e58ded2018-10-02 15:06:52 -0600562BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var) {
563
564 BcStatus s;
565 BcResult *ptr, r;
566 BcVec *v;
567 BcNum *n;
568
569 if (!BC_PROG_CHECK_STACK(&p->results, 1)) return BC_STATUS_EXEC_SMALL_STACK;
570
571 ptr = bc_vec_top(&p->results);
572 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
573
574 if ((s = bc_program_search(p, name, &v, var))) return s;
575
Gavin Howarde6e84762018-10-03 11:46:34 -0600576#ifdef DC_ENABLED
Gavin Howard0e58ded2018-10-02 15:06:52 -0600577 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
578 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
Gavin Howarde6e84762018-10-03 11:46:34 -0600579#endif // DC_ENABLED
Gavin Howard0e58ded2018-10-02 15:06:52 -0600580
581 if ((s = bc_program_num(p, ptr, &n, false))) return s;
582
583 // Do this once more to make sure that pointers were not invalidated.
584 if ((s = bc_program_search(p, name, &v, var))) return s;
585
586 if (var) {
Gavin Howard648c01c2018-10-04 10:14:16 -0600587 if ((s = bc_num_init(&r.data.n, BC_NUM_DEF_SIZE))) return s;
588 s = bc_num_copy(&r.data.n, n);
Gavin Howard0e58ded2018-10-02 15:06:52 -0600589 }
590 else {
591 if ((s = bc_array_init(&r.data.array, true))) return s;
592 s = bc_array_copy(&r.data.array, (BcVec*) n);
593 }
594
595 if (s || (s = bc_vec_push(v, &r.data))) goto err;
596
597 bc_vec_pop(&p->results);
598
599 return s;
600
601err:
Gavin Howard648c01c2018-10-04 10:14:16 -0600602 if (var) bc_num_free(&r.data.n);
Gavin Howardc9a9c472018-10-02 17:23:01 -0600603 else bc_vec_free(&r.data.array);
Gavin Howard0e58ded2018-10-02 15:06:52 -0600604 return s;
605}
606
Gavin Howard3f68df72018-03-22 20:30:27 -0600607BcStatus bc_program_assign(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700608
Gavin Howard63738202018-09-26 15:34:20 -0600609 BcStatus s;
610 BcResult *left, *right, res;
611 BcNum *l, *r;
612 unsigned long val, max;
613 bool assign = inst == BC_INST_ASSIGN;
Gavin Howard84095072018-02-27 15:36:58 -0700614
Gavin Howard63738202018-09-26 15:34:20 -0600615 if ((s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700616
Gavin Howarde6e84762018-10-03 11:46:34 -0600617#ifdef DC_ENABLED
Gavin Howard0e58ded2018-10-02 15:06:52 -0600618 assert(left->t != BC_RESULT_STR);
Gavin Howardda4cfc02018-10-01 12:27:34 -0600619
Gavin Howard0e58ded2018-10-02 15:06:52 -0600620 if (right->t == BC_RESULT_STR) {
Gavin Howardda4cfc02018-10-01 12:27:34 -0600621
622 BcVec *v;
623
Gavin Howard0e58ded2018-10-02 15:06:52 -0600624 assert(assign && left->t == BC_RESULT_VAR);
Gavin Howardda4cfc02018-10-01 12:27:34 -0600625
Gavin Howard0e58ded2018-10-02 15:06:52 -0600626 if ((s = bc_program_search(p, right->data.id.name, &v, true))) return s;
627 if ((s = bc_program_assignStr(p, right, v, false))) return s;
Gavin Howardda4cfc02018-10-01 12:27:34 -0600628 bc_vec_pop(&p->results);
629
630 return s;
Gavin Howard4e4a0112018-09-28 15:45:34 -0600631 }
Gavin Howarde6e84762018-10-03 11:46:34 -0600632#endif // DC_ENABLED
Gavin Howardda4cfc02018-10-01 12:27:34 -0600633
Gavin Howard0e58ded2018-10-02 15:06:52 -0600634 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Gavin Howardda4cfc02018-10-01 12:27:34 -0600635 return BC_STATUS_PARSE_BAD_ASSIGN;
Gavin Howard84095072018-02-27 15:36:58 -0700636
Gavin Howarde6e84762018-10-03 11:46:34 -0600637#ifdef BC_ENABLED
Gavin Howard63738202018-09-26 15:34:20 -0600638 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
639 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
Gavin Howard84095072018-02-27 15:36:58 -0700640
Gavin Howard63738202018-09-26 15:34:20 -0600641 if (assign) s = bc_num_copy(l, r);
642 else s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
Gavin Howardd5a51e62018-03-26 12:34:27 -0600643
Gavin Howard63738202018-09-26 15:34:20 -0600644 if (s) return s;
Gavin Howarde6e84762018-10-03 11:46:34 -0600645#else // BC_ENABLED
Gavin Howard0e58ded2018-10-02 15:06:52 -0600646 assert(assign);
647 if ((s = bc_num_copy(l, r))) return s;
Gavin Howarde6e84762018-10-03 11:46:34 -0600648#endif // BC_ENABLED
Gavin Howardd5a51e62018-03-26 12:34:27 -0600649
Gavin Howard0e58ded2018-10-02 15:06:52 -0600650 if (left->t == BC_RESULT_IBASE || left->t == BC_RESULT_OBASE) {
Gavin Howardd5a51e62018-03-26 12:34:27 -0600651
Gavin Howard0e58ded2018-10-02 15:06:52 -0600652 size_t *ptr = left->t == BC_RESULT_IBASE ? &p->ib_t : &p->ob_t;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600653
Gavin Howard63738202018-09-26 15:34:20 -0600654 if ((s = bc_num_ulong(r, &val))) return s;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600655
Gavin Howard0e58ded2018-10-02 15:06:52 -0600656 max = left->t == BC_RESULT_IBASE ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Gavin Howard691cfd52018-09-21 10:47:58 -0600657
Gavin Howard63738202018-09-26 15:34:20 -0600658 if (val < BC_NUM_MIN_BASE || val > max)
Gavin Howard296c98b2018-10-02 15:07:36 -0600659 return left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600660
Gavin Howard63738202018-09-26 15:34:20 -0600661 *ptr = (size_t) val;
662 }
Gavin Howard0e58ded2018-10-02 15:06:52 -0600663 else if (left->t == BC_RESULT_SCALE) {
Gavin Howardd5a51e62018-03-26 12:34:27 -0600664
Gavin Howard63738202018-09-26 15:34:20 -0600665 if ((s = bc_num_ulong(l, &val))) return s;
666 if (val > (unsigned long) BC_MAX_SCALE) return BC_STATUS_EXEC_BAD_SCALE;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600667
Gavin Howard63738202018-09-26 15:34:20 -0600668 p->scale = (size_t) val;
669 }
Gavin Howard84095072018-02-27 15:36:58 -0700670
Gavin Howard648c01c2018-10-04 10:14:16 -0600671 if ((s = bc_num_init(&res.data.n, l->len))) return s;
672 if ((s = bc_num_copy(&res.data.n, l))) goto err;
Gavin Howard0e58ded2018-10-02 15:06:52 -0600673 res.t = BC_RESULT_TEMP;
Gavin Howard1f3e7582018-09-29 02:19:54 -0600674 if ((s = bc_program_binOpRetire(p, &res))) goto err;
Gavin Howardb8181162018-02-28 12:58:09 -0700675
Gavin Howard63738202018-09-26 15:34:20 -0600676 return s;
Gavin Howardb8181162018-02-28 12:58:09 -0700677
678err:
Gavin Howard648c01c2018-10-04 10:14:16 -0600679 bc_num_free(&res.data.n);
Gavin Howard63738202018-09-26 15:34:20 -0600680 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700681}
682
Gavin Howardda4cfc02018-10-01 12:27:34 -0600683BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn, bool pop) {
684
685 BcStatus s;
686 BcResult r;
Gavin Howardc9a9c472018-10-02 17:23:01 -0600687 char *name;
Gavin Howarde6e84762018-10-03 11:46:34 -0600688#ifdef DC_ENABLED // Exclude
Gavin Howardda4cfc02018-10-01 12:27:34 -0600689 BcNum *num;
690 BcVec *v;
Gavin Howarde6e84762018-10-03 11:46:34 -0600691#else // DC_ENABLED
Gavin Howardda4cfc02018-10-01 12:27:34 -0600692 (void) pop;
Gavin Howarde6e84762018-10-03 11:46:34 -0600693#endif // DC_ENABLED Exclude
Gavin Howardda4cfc02018-10-01 12:27:34 -0600694
Gavin Howard0e58ded2018-10-02 15:06:52 -0600695 if (!(name = bc_program_name(code, bgn))) return BC_STATUS_ALLOC_ERR;
696 r.t = BC_RESULT_VAR;
697 r.data.id.name = name;
Gavin Howardda4cfc02018-10-01 12:27:34 -0600698
Gavin Howarde6e84762018-10-03 11:46:34 -0600699#ifdef DC_ENABLED
Gavin Howard0e58ded2018-10-02 15:06:52 -0600700 if ((s = bc_program_search(p, name, &v, true))) goto err;
701 assert(BC_PROG_CHECK_STACK(v, 1));
Gavin Howardda4cfc02018-10-01 12:27:34 -0600702 num = bc_vec_top(v);
703
Gavin Howard0e58ded2018-10-02 15:06:52 -0600704 if (BC_PROG_STR_VAR(num) || pop) {
Gavin Howardda4cfc02018-10-01 12:27:34 -0600705
Gavin Howard0e58ded2018-10-02 15:06:52 -0600706 if (pop) {
Gavin Howardda4cfc02018-10-01 12:27:34 -0600707
Gavin Howard0e58ded2018-10-02 15:06:52 -0600708 r.t = BC_RESULT_TEMP;
709
710 if (!BC_PROG_CHECK_STACK(v, 2)) {
711 s = BC_STATUS_EXEC_SMALL_STACK;
712 goto err;
713 }
714
Gavin Howard648c01c2018-10-04 10:14:16 -0600715 if ((s = bc_num_init(&r.data.n, BC_NUM_DEF_SIZE))) goto err;
716 if ((s = bc_num_copy(&r.data.n, num))) goto copy_err;
Gavin Howard0e58ded2018-10-02 15:06:52 -0600717
718 bc_vec_pop(v);
719 }
720 else {
721 r.t = BC_RESULT_STR;
722 r.data.id.idx = num->rdx;
Gavin Howardda4cfc02018-10-01 12:27:34 -0600723 }
724
Gavin Howard0e58ded2018-10-02 15:06:52 -0600725 free(name);
726 name = NULL;
Gavin Howardda4cfc02018-10-01 12:27:34 -0600727 }
Gavin Howarde6e84762018-10-03 11:46:34 -0600728#endif // DC_ENABLED
Gavin Howardda4cfc02018-10-01 12:27:34 -0600729
Gavin Howard0e58ded2018-10-02 15:06:52 -0600730 s = bc_vec_push(&p->results, &r);
Gavin Howardda4cfc02018-10-01 12:27:34 -0600731
Gavin Howarde6e84762018-10-03 11:46:34 -0600732#ifdef DC_ENABLED
Gavin Howard0e58ded2018-10-02 15:06:52 -0600733copy_err:
Gavin Howard648c01c2018-10-04 10:14:16 -0600734 if (s && pop) bc_num_free(&r.data.n);
Gavin Howardda4cfc02018-10-01 12:27:34 -0600735err:
Gavin Howarde6e84762018-10-03 11:46:34 -0600736#endif // DC_ENABLED
Gavin Howard0e58ded2018-10-02 15:06:52 -0600737 if (name && s) free(name);
Gavin Howardda4cfc02018-10-01 12:27:34 -0600738 return s;
739}
740
741BcStatus bc_program_pushArray(BcProgram *p, char *code,
742 size_t *bgn, uint8_t inst)
743{
744 BcStatus s;
745 BcResult r;
746 BcNum *num;
747
748 if (!(r.data.id.name = bc_program_name(code, bgn)))
749 return BC_STATUS_ALLOC_ERR;
750
751 if (inst == BC_INST_ARRAY) {
Gavin Howard0e58ded2018-10-02 15:06:52 -0600752 r.t = BC_RESULT_ARRAY;
Gavin Howardda4cfc02018-10-01 12:27:34 -0600753 s = bc_vec_push(&p->results, &r);
754 }
755 else {
756
757 BcResult *operand;
758 unsigned long temp;
759
760 if ((s = bc_program_prep(p, &operand, &num, false))) goto err;
761 if ((s = bc_num_ulong(num, &temp))) goto err;
762
763 if (temp > (unsigned long) BC_MAX_DIM) {
764 s = BC_STATUS_EXEC_ARRAY_LEN;
765 goto err;
766 }
767
768 r.data.id.idx = (size_t) temp;
769 s = bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
770 }
771
772err:
773 if (s) free(r.data.id.name);
774 return s;
775}
776
Gavin Howarde6e84762018-10-03 11:46:34 -0600777#ifdef BC_ENABLED
Gavin Howard972e8402018-10-01 13:11:49 -0600778BcStatus bc_program_incdec(BcProgram *p, uint8_t inst) {
779
780 BcStatus s;
781 BcResult *ptr, res, copy;
782 BcNum *num;
783 uint8_t inst2 = inst;
784
785 if ((s = bc_program_prep(p, &ptr, &num, false))) return s;
786
787 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
Gavin Howard0e58ded2018-10-02 15:06:52 -0600788 copy.t = BC_RESULT_TEMP;
Gavin Howard648c01c2018-10-04 10:14:16 -0600789 if ((s = bc_num_init(&copy.data.n, num->len))) return s;
790 if ((s = bc_num_copy(&copy.data.n, num))) goto err;
Gavin Howard972e8402018-10-01 13:11:49 -0600791 }
792
Gavin Howard0e58ded2018-10-02 15:06:52 -0600793 res.t = BC_RESULT_ONE;
Gavin Howard972e8402018-10-01 13:11:49 -0600794 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
795 BC_INST_ASSIGN_PLUS : BC_INST_ASSIGN_MINUS;
796
797 if ((s = bc_vec_push(&p->results, &res))) goto err;
798 if ((s = bc_program_assign(p, inst))) goto err;
799
800 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
801 bc_vec_pop(&p->results);
802 if ((s = bc_vec_push(&p->results, &copy))) goto err;
803 }
804
805 return s;
806
807err:
Gavin Howard972e8402018-10-01 13:11:49 -0600808 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST)
Gavin Howard648c01c2018-10-04 10:14:16 -0600809 bc_num_free(&copy.data.n);
Gavin Howard972e8402018-10-01 13:11:49 -0600810 return s;
811}
812
Gavin Howardaac24bf2018-09-22 23:24:53 -0600813BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx) {
Gavin Howard84095072018-02-27 15:36:58 -0700814
Gavin Howarde956c612018-09-27 11:40:28 -0600815 BcStatus s = BC_STATUS_SUCCESS;
Gavin Howard63738202018-09-26 15:34:20 -0600816 BcInstPtr ip;
817 size_t i, nparams = bc_program_index(code, idx);
818 BcFunc *func;
Gavin Howard0e58ded2018-10-02 15:06:52 -0600819 BcVec *v;
820 BcAuto *a;
821 BcResultData param;
822 BcResult *arg;
Gavin Howard84095072018-02-27 15:36:58 -0700823
Gavin Howard63738202018-09-26 15:34:20 -0600824 ip.idx = 0;
Gavin Howard63738202018-09-26 15:34:20 -0600825 ip.func = bc_program_index(code, idx);
Gavin Howard63738202018-09-26 15:34:20 -0600826 func = bc_vec_item(&p->fns, ip.func);
Gavin Howard84095072018-02-27 15:36:58 -0700827
Gavin Howard63738202018-09-26 15:34:20 -0600828 if (!func->code.len) return BC_STATUS_EXEC_UNDEFINED_FUNC;
829 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
Gavin Howard0e58ded2018-10-02 15:06:52 -0600830 ip.len = p->results.len - nparams;
831
832 assert(BC_PROG_CHECK_STACK(&p->results, nparams));
Gavin Howard84095072018-02-27 15:36:58 -0700833
Gavin Howard63738202018-09-26 15:34:20 -0600834 for (i = 0; i < nparams; ++i) {
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700835
Gavin Howard0e58ded2018-10-02 15:06:52 -0600836 a = bc_vec_item(&func->autos, nparams - 1 - i);
837 arg = bc_vec_top(&p->results);
Gavin Howarde87dcb82018-09-29 21:37:54 -0600838
Gavin Howard0e58ded2018-10-02 15:06:52 -0600839 if (!a->var != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Gavin Howard63738202018-09-26 15:34:20 -0600840 return BC_STATUS_EXEC_BAD_TYPE;
Gavin Howard1ce83252018-09-04 15:21:47 -0600841
Gavin Howard0e58ded2018-10-02 15:06:52 -0600842 if ((s = bc_program_copyToVar(p, a->name, a->var))) return s;
Gavin Howard63738202018-09-26 15:34:20 -0600843 }
Gavin Howard90f13ad2018-03-17 13:32:16 -0600844
Gavin Howarde87dcb82018-09-29 21:37:54 -0600845 for (; i < func->autos.len; ++i) {
Gavin Howard90f13ad2018-03-17 13:32:16 -0600846
Gavin Howard0e58ded2018-10-02 15:06:52 -0600847 a = bc_vec_item(&func->autos, i);
848 if ((s = bc_program_search(p, a->name, &v, a->var))) return s;
Gavin Howard90f13ad2018-03-17 13:32:16 -0600849
Gavin Howard0e58ded2018-10-02 15:06:52 -0600850 if (a->var) {
Gavin Howard648c01c2018-10-04 10:14:16 -0600851 if ((s = bc_num_init(&param.n, BC_NUM_DEF_SIZE))) return s;
852 if ((s = bc_vec_push(v, &param.n))) goto err;
Gavin Howard0e58ded2018-10-02 15:06:52 -0600853 }
854 else {
855 if ((s = bc_array_init(&param.array, true))) return s;
856 if ((s = bc_vec_push(v, &param.array))) goto err;
857 }
Gavin Howard63738202018-09-26 15:34:20 -0600858 }
Gavin Howard84095072018-02-27 15:36:58 -0700859
Gavin Howard90198862018-09-29 03:37:47 -0600860 return bc_vec_push(&p->stack, &ip);
Gavin Howard57323432018-03-14 20:06:35 -0600861
862err:
Gavin Howard648c01c2018-10-04 10:14:16 -0600863 if (a->var) bc_num_free(&param.n);
Gavin Howardc9a9c472018-10-02 17:23:01 -0600864 else bc_vec_free(&param.array);
Gavin Howarde956c612018-09-27 11:40:28 -0600865 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700866}
Gavin Howarde6e84762018-10-03 11:46:34 -0600867#endif // BC_ENABLED
Gavin Howard84095072018-02-27 15:36:58 -0700868
Gavin Howard3f68df72018-03-22 20:30:27 -0600869BcStatus bc_program_return(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700870
Gavin Howard63738202018-09-26 15:34:20 -0600871 BcStatus s;
872 BcResult res;
873 BcFunc *f;
Gavin Howard0e58ded2018-10-02 15:06:52 -0600874 size_t i;
Gavin Howard63738202018-09-26 15:34:20 -0600875 BcInstPtr *ip = bc_vec_top(&p->stack);
Gavin Howard84095072018-02-27 15:36:58 -0700876
Gavin Howard1e758c82018-09-29 19:57:37 -0600877 assert(BC_PROG_CHECK_STACK(&p->stack, 2));
Gavin Howard21925472018-09-29 19:29:25 -0600878
Gavin Howard1e758c82018-09-29 19:57:37 -0600879 if (!BC_PROG_CHECK_STACK(&p->results, ip->len + inst == BC_INST_RET))
Gavin Howard21925472018-09-29 19:29:25 -0600880 return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howardc410b0f2018-02-27 16:57:05 -0700881
Gavin Howard63738202018-09-26 15:34:20 -0600882 f = bc_vec_item(&p->fns, ip->func);
Gavin Howard0e58ded2018-10-02 15:06:52 -0600883 res.t = BC_RESULT_TEMP;
Gavin Howard84095072018-02-27 15:36:58 -0700884
Gavin Howard65bf0362018-09-28 11:28:56 -0600885 if (inst == BC_INST_RET) {
Gavin Howard84095072018-02-27 15:36:58 -0700886
Gavin Howard63738202018-09-26 15:34:20 -0600887 BcNum *num;
888 BcResult *operand = bc_vec_top(&p->results);
Gavin Howard84095072018-02-27 15:36:58 -0700889
Gavin Howard63738202018-09-26 15:34:20 -0600890 if ((s = bc_program_num(p, operand, &num, false))) return s;
Gavin Howard648c01c2018-10-04 10:14:16 -0600891 if ((s = bc_num_init(&res.data.n, num->len))) return s;
892 if ((s = bc_num_copy(&res.data.n, num))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600893 }
894 else {
Gavin Howard648c01c2018-10-04 10:14:16 -0600895 if ((s = bc_num_init(&res.data.n, BC_NUM_DEF_SIZE))) return s;
896 bc_num_zero(&res.data.n);
Gavin Howard63738202018-09-26 15:34:20 -0600897 }
Gavin Howard84095072018-02-27 15:36:58 -0700898
Gavin Howard63738202018-09-26 15:34:20 -0600899 // We need to pop arguments as well, so this takes that into account.
Gavin Howard0e58ded2018-10-02 15:06:52 -0600900 for (i = 0; i < f->autos.len; ++i) {
Gavin Howardc410b0f2018-02-27 16:57:05 -0700901
Gavin Howard0e58ded2018-10-02 15:06:52 -0600902 BcVec *v;
903 BcAuto *a = bc_vec_item(&f->autos, i);
904
905 if ((s = bc_program_search(p, a->name, &v, a->var))) goto err;
906
907 bc_vec_pop(v);
908 }
909
910 bc_vec_npop(&p->results, p->results.len - ip->len);
Gavin Howard90198862018-09-29 03:37:47 -0600911 if ((s = bc_vec_push(&p->results, &res))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600912 bc_vec_pop(&p->stack);
Gavin Howard0eb2a372018-03-24 09:52:55 -0600913
Gavin Howard63738202018-09-26 15:34:20 -0600914 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700915
916err:
Gavin Howard648c01c2018-10-04 10:14:16 -0600917 bc_num_free(&res.data.n);
Gavin Howard63738202018-09-26 15:34:20 -0600918 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700919}
920
Gavin Howard3f68df72018-03-22 20:30:27 -0600921unsigned long bc_program_scale(BcNum *n) {
Gavin Howard63738202018-09-26 15:34:20 -0600922 return (unsigned long) n->rdx;
Gavin Howard84095072018-02-27 15:36:58 -0700923}
924
Gavin Howard77d489d2018-09-04 15:14:06 -0600925unsigned long bc_program_len(BcNum *n) {
Gavin Howard6e2fd062018-03-20 19:34:12 -0600926
Gavin Howard63738202018-09-26 15:34:20 -0600927 unsigned long len = n->len;
Gavin Howard6e2fd062018-03-20 19:34:12 -0600928
Gavin Howard63738202018-09-26 15:34:20 -0600929 if (n->rdx == n->len) {
930 size_t i;
931 for (i = n->len - 1; i < n->len && !n->num[i]; --len, --i);
932 }
Gavin Howard6e2fd062018-03-20 19:34:12 -0600933
Gavin Howard63738202018-09-26 15:34:20 -0600934 return len;
Gavin Howard84095072018-02-27 15:36:58 -0700935}
936
Gavin Howard3f68df72018-03-22 20:30:27 -0600937BcStatus bc_program_builtin(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700938
Gavin Howard63738202018-09-26 15:34:20 -0600939 BcStatus s;
940 BcResult *opnd;
941 BcNum *num;
Gavin Howardc935ff12018-09-29 02:18:45 -0600942 BcResult res;
Gavin Howard84095072018-02-27 15:36:58 -0700943
Gavin Howardb4584aa2018-09-28 10:45:33 -0600944 if ((s = bc_program_prep(p, &opnd, &num, inst == BC_INST_LENGTH))) return s;
Gavin Howard648c01c2018-10-04 10:14:16 -0600945 if ((s = bc_num_init(&res.data.n, BC_NUM_DEF_SIZE))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700946
Gavin Howard648c01c2018-10-04 10:14:16 -0600947 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.data.n, p->scale);
Gavin Howard0e58ded2018-10-02 15:06:52 -0600948 else if (inst == BC_INST_LENGTH && opnd->t == BC_RESULT_ARRAY) {
Gavin Howard63738202018-09-26 15:34:20 -0600949 BcVec *vec = (BcVec*) num;
Gavin Howard648c01c2018-10-04 10:14:16 -0600950 s = bc_num_ulong2num(&res.data.n, (unsigned long) vec->len);
Gavin Howard63738202018-09-26 15:34:20 -0600951 }
952 else {
Gavin Howard0e58ded2018-10-02 15:06:52 -0600953 assert(opnd->t != BC_RESULT_ARRAY);
Gavin Howard63738202018-09-26 15:34:20 -0600954 BcProgramBuiltIn f = inst == BC_INST_LENGTH ? bc_program_len :
955 bc_program_scale;
Gavin Howard648c01c2018-10-04 10:14:16 -0600956 s = bc_num_ulong2num(&res.data.n, f(num));
Gavin Howard63738202018-09-26 15:34:20 -0600957 }
Gavin Howard84095072018-02-27 15:36:58 -0700958
Gavin Howardc935ff12018-09-29 02:18:45 -0600959 if (s || (s = bc_program_retire(p, &res, BC_RESULT_TEMP))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700960
Gavin Howard296c98b2018-10-02 15:07:36 -0600961 return s;
962
Gavin Howard84095072018-02-27 15:36:58 -0700963err:
Gavin Howard648c01c2018-10-04 10:14:16 -0600964 bc_num_free(&res.data.n);
Gavin Howard63738202018-09-26 15:34:20 -0600965 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700966}
967
Gavin Howarde6e84762018-10-03 11:46:34 -0600968#ifdef DC_ENABLED
Gavin Howard24d3dbe2018-10-04 10:55:40 -0600969BcStatus bc_program_divmod(BcProgram *p) {
970
971 BcStatus s;
972 BcResult *opd1, *opd2, res, res2;
973 BcNum *n1, *n2;
974
975 if ((s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false))) return s;
976 if ((s = bc_num_init(&res.data.n, BC_NUM_DEF_SIZE))) return s;
977 if ((s = bc_num_init(&res2.data.n, n2->len))) goto res2_err;
978
979 if ((s = bc_num_div(n1, n2, &res2.data.n, p->scale))) goto err;
980 if ((s = bc_num_rem(n1, n2, &res.data.n, p->scale))) goto err;
981
982 if ((s = bc_program_binOpRetire(p, &res2))) goto err;
983 res.t = BC_RESULT_TEMP;
984 if ((s = bc_vec_push(&p->results, &res))) goto res2_err;
985
986 return s;
987
988err:
989 bc_num_free(&res2.data.n);
990res2_err:
991 bc_num_free(&res.data.n);
992 return s;
993}
994
Gavin Howardba009802018-09-29 04:41:51 -0600995BcStatus bc_program_modexp(BcProgram *p) {
996
997 BcStatus s;
998 BcResult *opd1, *opd2, *opd3, res;
999 BcNum *n1, *n2, *n3;
1000
Gavin Howard1e758c82018-09-29 19:57:37 -06001001 if (!BC_PROG_CHECK_STACK(&p->results, 3)) return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howardba009802018-09-29 04:41:51 -06001002 if ((s = bc_program_binOpPrep(p, &opd2, &n2, &opd3, &n3, false))) return s;
1003
1004 opd1 = bc_vec_item_rev(&p->results, 2);
1005 if ((s = bc_program_num(p, opd1, &n1, false))) return s;
1006
Gavin Howardda4cfc02018-10-01 12:27:34 -06001007 // Make sure that the values have their pointers updated, if necessary.
Gavin Howard4da68312018-10-02 15:08:02 -06001008 if (opd1->t == BC_RESULT_VAR || opd1->t == BC_RESULT_ARRAY_ELEM) {
1009 if (opd1->t == opd2->t) {
Gavin Howardda4cfc02018-10-01 12:27:34 -06001010 if ((s = bc_program_num(p, opd2, &n2, false))) return s;
1011 }
Gavin Howard4da68312018-10-02 15:08:02 -06001012 if (opd1->t == opd3->t) {
Gavin Howardda4cfc02018-10-01 12:27:34 -06001013 if ((s = bc_program_num(p, opd3, &n3, false))) return s;
1014 }
1015 }
1016
Gavin Howard648c01c2018-10-04 10:14:16 -06001017 if ((s = bc_num_init(&res.data.n, n3->len))) return s;
Gavin Howardba009802018-09-29 04:41:51 -06001018
Gavin Howard648c01c2018-10-04 10:14:16 -06001019 if ((s = bc_num_modexp(n1, n2, n3, &res.data.n, p->scale))) goto err;
Gavin Howardba009802018-09-29 04:41:51 -06001020 bc_vec_pop(&p->results);
1021
1022 if ((s = bc_program_binOpRetire(p, &res))) goto err;
1023
1024 return s;
1025
1026err:
Gavin Howard648c01c2018-10-04 10:14:16 -06001027 bc_num_free(&res.data.n);
Gavin Howardba009802018-09-29 04:41:51 -06001028 return s;
1029}
1030
Gavin Howardc935ff12018-09-29 02:18:45 -06001031BcStatus bc_program_stackLen(BcProgram *p) {
1032
1033 BcStatus s;
1034 BcResult res;
1035 size_t len = p->results.len;
1036
Gavin Howard0e58ded2018-10-02 15:06:52 -06001037 res.t = BC_RESULT_TEMP;
Gavin Howardc935ff12018-09-29 02:18:45 -06001038
Gavin Howard648c01c2018-10-04 10:14:16 -06001039 if ((s = bc_num_init(&res.data.n, BC_NUM_DEF_SIZE))) return s;
1040 if ((s = bc_num_ulong2num(&res.data.n, len))) goto err;
Gavin Howard90198862018-09-29 03:37:47 -06001041 if ((s = bc_vec_push(&p->results, &res))) goto err;
Gavin Howardc935ff12018-09-29 02:18:45 -06001042
1043 return s;
1044
1045err:
Gavin Howard648c01c2018-10-04 10:14:16 -06001046 bc_num_free(&res.data.n);
Gavin Howardc935ff12018-09-29 02:18:45 -06001047 return s;
1048}
1049
1050BcStatus bc_program_nquit(BcProgram *p) {
1051
1052 BcStatus s;
1053 BcResult *opnd;
1054 BcNum *num;
1055 unsigned long val;
1056
1057 if ((s = bc_program_prep(p, &opnd, &num, false))) return s;
1058 if ((s = bc_num_ulong(num, &val))) return s;
1059
1060 bc_vec_pop(&p->results);
1061
1062 if (p->stack.len < val) return BC_STATUS_EXEC_SMALL_STACK;
1063 else if (p->stack.len == val) return BC_STATUS_QUIT;
1064
1065 bc_vec_npop(&p->stack, val);
1066
1067 return s;
1068}
Gavin Howard503f3932018-09-29 19:24:29 -06001069
Gavin Howardda4cfc02018-10-01 12:27:34 -06001070BcStatus bc_program_executeStr(BcProgram *p) {
Gavin Howard077e30a2018-09-29 22:29:56 -06001071
1072 BcStatus s;
1073 BcResult *r;
1074 char *str;
1075 BcFunc *f;
1076 BcParse prs;
1077 BcInstPtr ip;
1078 size_t fidx;
1079 bool do_parse;
1080
1081 if (!BC_PROG_CHECK_STACK(&p->results, 1)) return BC_STATUS_EXEC_SMALL_STACK;
1082
1083 r = bc_vec_top(&p->results);
1084 fidx = r->data.id.idx + 2;
1085
Gavin Howard0e58ded2018-10-02 15:06:52 -06001086 if (r->t != BC_RESULT_STR) return BC_STATUS_SUCCESS;
Gavin Howard077e30a2018-09-29 22:29:56 -06001087
1088 assert(p->strs.len > r->data.id.idx && p->fns.len > fidx);
1089
1090 str = bc_vec_item(&p->strs, r->data.id.idx);
1091 f = bc_vec_item(&p->fns, fidx);
1092 do_parse = !f->code.len;
1093
1094 if (do_parse) {
1095
1096 if ((s = p->parse_init(&prs, p))) return s;
Gavin Howardc39fd492018-10-04 10:07:03 -06001097 if ((s = bc_lex_text(&prs.l, str))) goto err;
Gavin Howard077e30a2018-09-29 22:29:56 -06001098
Gavin Howard00a7a5f2018-10-01 12:30:38 -06001099 if ((s = p->parse_exp(&prs, &f->code, 0, bc_parse_next_read))) goto err;
Gavin Howard077e30a2018-09-29 22:29:56 -06001100
Gavin Howardc39fd492018-10-04 10:07:03 -06001101 if (prs.l.t.t != BC_LEX_EOF) {
Gavin Howard077e30a2018-09-29 22:29:56 -06001102 s = BC_STATUS_PARSE_BAD_EXP;
1103 goto err;
1104 }
1105
1106 if ((s = bc_vec_pushByte(&f->code, BC_INST_RET0))) goto err;
1107 bc_parse_free(&prs);
1108 }
1109
1110 ip.idx = 0;
1111 ip.len = p->results.len;
1112 ip.func = fidx;
1113
1114 return bc_vec_push(&p->stack, &ip);
1115
1116err:
1117 bc_parse_free(&prs);
1118 bc_vec_npop(&f->code, f->code.len);
1119 return s;
1120}
Gavin Howarde6e84762018-10-03 11:46:34 -06001121#endif // DC_ENABLED
Gavin Howardc935ff12018-09-29 02:18:45 -06001122
Gavin Howard3f68df72018-03-22 20:30:27 -06001123BcStatus bc_program_pushScale(BcProgram *p) {
Gavin Howard84095072018-02-27 15:36:58 -07001124
Gavin Howard63738202018-09-26 15:34:20 -06001125 BcStatus s;
1126 BcResult res;
Gavin Howard84095072018-02-27 15:36:58 -07001127
Gavin Howard0e58ded2018-10-02 15:06:52 -06001128 res.t = BC_RESULT_SCALE;
Gavin Howard84095072018-02-27 15:36:58 -07001129
Gavin Howard648c01c2018-10-04 10:14:16 -06001130 if ((s = bc_num_init(&res.data.n, BC_NUM_DEF_SIZE))) return s;
1131 s = bc_num_ulong2num(&res.data.n, (unsigned long) p->scale);
Gavin Howard90198862018-09-29 03:37:47 -06001132 if (s || (s = bc_vec_push(&p->results, &res))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -07001133
Gavin Howard63738202018-09-26 15:34:20 -06001134 return s;
Gavin Howard84095072018-02-27 15:36:58 -07001135
1136err:
Gavin Howard648c01c2018-10-04 10:14:16 -06001137 bc_num_free(&res.data.n);
Gavin Howard63738202018-09-26 15:34:20 -06001138 return s;
Gavin Howard84095072018-02-27 15:36:58 -07001139}
1140
Gavin Howardd2a05252018-09-27 14:00:40 -06001141BcStatus bc_program_init(BcProgram *p, size_t line_len,
1142 BcParseInit parse_init, BcParseExpr parse_expr)
1143{
Gavin Howard63738202018-09-26 15:34:20 -06001144 BcStatus s;
1145 size_t idx;
1146 char *main_name = NULL, *read_name = NULL;
1147 BcInstPtr ip;
Gavin Howard8a596d42018-01-15 15:46:01 -07001148
Gavin Howard63738202018-09-26 15:34:20 -06001149 assert(p);
Gavin Howard8a596d42018-01-15 15:46:01 -07001150
Gavin Howard63738202018-09-26 15:34:20 -06001151 assert((unsigned long) sysconf(_SC_BC_BASE_MAX) <= BC_MAX_OBASE);
1152 assert((unsigned long) sysconf(_SC_BC_DIM_MAX) <= BC_MAX_DIM);
1153 assert((unsigned long) sysconf(_SC_BC_SCALE_MAX) <= BC_MAX_SCALE);
1154 assert((unsigned long) sysconf(_SC_BC_STRING_MAX) <= BC_MAX_STRING);
Gavin Howard57c843e2018-03-28 19:28:08 -06001155
Gavin Howard63738202018-09-26 15:34:20 -06001156 p->nchars = p->scale = 0;
Gavin Howard08f74ad2018-09-28 14:46:29 -06001157 p->len = line_len;
Gavin Howardd2a05252018-09-27 14:00:40 -06001158 p->parse_init = parse_init;
Gavin Howard00a7a5f2018-10-01 12:30:38 -06001159 p->parse_exp = parse_expr;
Gavin Howard5d74e962018-02-26 13:44:13 -07001160
Gavin Howard63738202018-09-26 15:34:20 -06001161 if ((s = bc_num_init(&p->ib, BC_NUM_DEF_SIZE))) return s;
1162 bc_num_ten(&p->ib);
1163 p->ib_t = 10;
Gavin Howard5d74e962018-02-26 13:44:13 -07001164
Gavin Howard63738202018-09-26 15:34:20 -06001165 if ((s = bc_num_init(&p->ob, BC_NUM_DEF_SIZE))) goto obase_err;
1166 bc_num_ten(&p->ob);
1167 p->ob_t = 10;
Gavin Howard5d74e962018-02-26 13:44:13 -07001168
Gavin Howard03610742018-09-27 10:48:29 -06001169 if ((s = bc_num_init(&p->hexb, BC_NUM_DEF_SIZE))) goto hexb_err;
1170 bc_num_ten(&p->hexb);
1171 p->hexb.num[0] = 6;
1172
Gavin Howard63738202018-09-26 15:34:20 -06001173 if ((s = bc_num_init(&p->last, BC_NUM_DEF_SIZE))) goto last_err;
1174 bc_num_zero(&p->last);
Gavin Howardb5c77212018-02-14 17:12:34 -07001175
Gavin Howard63738202018-09-26 15:34:20 -06001176 if ((s = bc_num_init(&p->zero, BC_NUM_DEF_SIZE))) goto zero_err;
1177 bc_num_zero(&p->zero);
Gavin Howard5a8949e2018-02-05 16:46:06 -07001178
Gavin Howard63738202018-09-26 15:34:20 -06001179 if ((s = bc_num_init(&p->one, BC_NUM_DEF_SIZE))) goto one_err;
1180 bc_num_one(&p->one);
Gavin Howard645200e2018-02-15 15:33:35 -07001181
Gavin Howard63738202018-09-26 15:34:20 -06001182 if ((s = bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free))) goto fn_err;
Gavin Howard8a596d42018-01-15 15:46:01 -07001183
Gavin Howard63738202018-09-26 15:34:20 -06001184 s = bc_veco_init(&p->fn_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
1185 if (s) goto func_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001186
Gavin Howard3bc436f2018-09-28 14:02:34 -06001187 if (!(main_name = strdup(bc_func_main))) {
Gavin Howard63738202018-09-26 15:34:20 -06001188 s = BC_STATUS_ALLOC_ERR;
1189 goto name_err;
1190 }
Gavin Howardd50539a2018-02-08 20:52:57 -07001191
Gavin Howard63738202018-09-26 15:34:20 -06001192 s = bc_program_addFunc(p, main_name, &idx);
1193 if (s || idx != BC_PROG_MAIN) goto name_err;
1194 main_name = NULL;
Gavin Howardb42810f2018-03-09 10:07:58 -07001195
Gavin Howard3bc436f2018-09-28 14:02:34 -06001196 if (!(read_name = strdup(bc_func_read))) {
Gavin Howard63738202018-09-26 15:34:20 -06001197 s = BC_STATUS_ALLOC_ERR;
1198 goto name_err;
1199 }
Gavin Howarded392aa2018-02-27 13:09:26 -07001200
Gavin Howard63738202018-09-26 15:34:20 -06001201 s = bc_program_addFunc(p, read_name, &idx);
1202 if (s || idx != BC_PROG_READ) goto name_err;
1203 read_name = NULL;
Gavin Howardb42810f2018-03-09 10:07:58 -07001204
Gavin Howard0e58ded2018-10-02 15:06:52 -06001205 if ((s = bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free))) goto name_err;
Gavin Howard63738202018-09-26 15:34:20 -06001206 s = bc_veco_init(&p->var_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
1207 if (s) goto var_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001208
Gavin Howard63738202018-09-26 15:34:20 -06001209 if ((s = bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free))) goto arr_err;
1210 s = bc_veco_init(&p->arr_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
1211 if (s) goto array_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001212
Gavin Howard63738202018-09-26 15:34:20 -06001213 s = bc_vec_init(&p->strs, sizeof(char*), bc_string_free);
1214 if (s) goto string_err;
Gavin Howard5a8949e2018-02-05 16:46:06 -07001215
Gavin Howard63738202018-09-26 15:34:20 -06001216 s = bc_vec_init(&p->consts, sizeof(char*), bc_string_free);
1217 if (s) goto const_err;
Gavin Howarde46c6822018-02-08 20:05:39 -07001218
Gavin Howard63738202018-09-26 15:34:20 -06001219 s = bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
1220 if (s) goto expr_err;
Gavin Howard2534a812018-02-10 15:34:15 -07001221
Gavin Howard63738202018-09-26 15:34:20 -06001222 if ((s = bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL))) goto stack_err;
Gavin Howard2534a812018-02-10 15:34:15 -07001223
Gavin Howard63738202018-09-26 15:34:20 -06001224 memset(&ip, 0, sizeof(BcInstPtr));
Gavin Howard2534a812018-02-10 15:34:15 -07001225
Gavin Howard90198862018-09-29 03:37:47 -06001226 if ((s = bc_vec_push(&p->stack, &ip))) goto push_err;
Gavin Howardd28e80a2018-01-23 18:24:18 -07001227
Gavin Howard63738202018-09-26 15:34:20 -06001228 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001229
Gavin Howarded392aa2018-02-27 13:09:26 -07001230push_err:
Gavin Howard63738202018-09-26 15:34:20 -06001231 bc_vec_free(&p->stack);
Gavin Howard2534a812018-02-10 15:34:15 -07001232stack_err:
Gavin Howard63738202018-09-26 15:34:20 -06001233 bc_vec_free(&p->results);
Gavin Howard2534a812018-02-10 15:34:15 -07001234expr_err:
Gavin Howard63738202018-09-26 15:34:20 -06001235 bc_vec_free(&p->consts);
Gavin Howarde46c6822018-02-08 20:05:39 -07001236const_err:
Gavin Howard63738202018-09-26 15:34:20 -06001237 bc_vec_free(&p->strs);
Gavin Howard5a8949e2018-02-05 16:46:06 -07001238string_err:
Gavin Howard63738202018-09-26 15:34:20 -06001239 bc_veco_free(&p->arr_map);
Gavin Howardd96bcae2018-02-07 19:16:19 -07001240array_map_err:
Gavin Howard63738202018-09-26 15:34:20 -06001241 bc_vec_free(&p->arrs);
1242arr_err:
1243 bc_veco_free(&p->var_map);
Gavin Howardd96bcae2018-02-07 19:16:19 -07001244var_map_err:
Gavin Howard63738202018-09-26 15:34:20 -06001245 bc_vec_free(&p->vars);
Gavin Howardd50539a2018-02-08 20:52:57 -07001246name_err:
Gavin Howard63738202018-09-26 15:34:20 -06001247 bc_veco_free(&p->fn_map);
Gavin Howardd96bcae2018-02-07 19:16:19 -07001248func_map_err:
Gavin Howard63738202018-09-26 15:34:20 -06001249 bc_vec_free(&p->fns);
1250fn_err:
1251 bc_num_free(&p->one);
Gavin Howardb5c77212018-02-14 17:12:34 -07001252one_err:
Gavin Howard63738202018-09-26 15:34:20 -06001253 bc_num_free(&p->zero);
Gavin Howardb5c77212018-02-14 17:12:34 -07001254zero_err:
Gavin Howard63738202018-09-26 15:34:20 -06001255 bc_num_free(&p->last);
Gavin Howard5d74e962018-02-26 13:44:13 -07001256last_err:
Gavin Howard03610742018-09-27 10:48:29 -06001257 bc_num_free(&p->hexb);
1258hexb_err:
Gavin Howard63738202018-09-26 15:34:20 -06001259 bc_num_free(&p->ob);
Gavin Howard5d74e962018-02-26 13:44:13 -07001260obase_err:
Gavin Howard63738202018-09-26 15:34:20 -06001261 bc_num_free(&p->ib);
1262 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001263}
1264
Gavin Howard859e2902018-03-17 14:23:35 -06001265BcStatus bc_program_addFunc(BcProgram *p, char *name, size_t *idx) {
Gavin Howard3b90f9f2018-01-17 13:01:33 -07001266
Gavin Howard63738202018-09-26 15:34:20 -06001267 BcStatus s;
1268 BcEntry entry, *entry_ptr;
1269 BcFunc f;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001270
Gavin Howard63738202018-09-26 15:34:20 -06001271 assert(p && name && idx);
Gavin Howard3b90f9f2018-01-17 13:01:33 -07001272
Gavin Howard63738202018-09-26 15:34:20 -06001273 entry.name = name;
1274 entry.idx = p->fns.len;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001275
Gavin Howardc39fd492018-10-04 10:07:03 -06001276 if ((s = bc_veco_insert(&p->fn_map, &entry, idx))) {
Gavin Howard63738202018-09-26 15:34:20 -06001277 free(name);
1278 if (s != BC_STATUS_VEC_ITEM_EXISTS) return s;
1279 }
Gavin Howardded20a22018-03-07 15:15:19 -07001280
Gavin Howard63738202018-09-26 15:34:20 -06001281 entry_ptr = bc_veco_item(&p->fn_map, *idx);
1282 *idx = entry_ptr->idx;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001283
Gavin Howard63738202018-09-26 15:34:20 -06001284 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
Gavin Howardab67e7c2018-02-09 10:35:44 -07001285
Gavin Howard63738202018-09-26 15:34:20 -06001286 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
1287 s = BC_STATUS_SUCCESS;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001288
Gavin Howard63738202018-09-26 15:34:20 -06001289 // We need to reset these, so the function can be repopulated.
1290 func->nparams = 0;
1291 bc_vec_npop(&func->autos, func->autos.len);
1292 bc_vec_npop(&func->code, func->code.len);
1293 bc_vec_npop(&func->labels, func->labels.len);
1294 }
1295 else {
1296 if ((s = bc_func_init(&f))) return s;
Gavin Howard90198862018-09-29 03:37:47 -06001297 if ((s = bc_vec_push(&p->fns, &f))) bc_func_free(&f);
Gavin Howard63738202018-09-26 15:34:20 -06001298 }
Gavin Howardded20a22018-03-07 15:15:19 -07001299
Gavin Howard63738202018-09-26 15:34:20 -06001300 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001301}
1302
Gavin Howard63738202018-09-26 15:34:20 -06001303BcStatus bc_program_reset(BcProgram *p, BcStatus s) {
Gavin Howardf4167dc2018-03-26 14:19:28 -06001304
Gavin Howard63738202018-09-26 15:34:20 -06001305 BcFunc *f;
1306 BcInstPtr *ip;
Gavin Howardf4167dc2018-03-26 14:19:28 -06001307
Gavin Howard63738202018-09-26 15:34:20 -06001308 bc_vec_npop(&p->stack, p->stack.len - 1);
1309 bc_vec_npop(&p->results, p->results.len);
Gavin Howardabdc2d32018-03-27 08:01:08 -06001310
Gavin Howard63738202018-09-26 15:34:20 -06001311 f = bc_vec_item(&p->fns, 0);
1312 ip = bc_vec_top(&p->stack);
1313 ip->idx = f->code.len;
Gavin Howardf4167dc2018-03-26 14:19:28 -06001314
Gavin Howard63738202018-09-26 15:34:20 -06001315 if (!s && bcg.signe && !bcg.tty) return BC_STATUS_QUIT;
Gavin Howardabdc2d32018-03-27 08:01:08 -06001316
Gavin Howard63738202018-09-26 15:34:20 -06001317 bcg.sigc += bcg.signe;
1318 bcg.signe = bcg.sig != bcg.sigc;
Gavin Howardabdc2d32018-03-27 08:01:08 -06001319
Gavin Howard63738202018-09-26 15:34:20 -06001320 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
Gavin Howardca893d72018-09-28 14:15:16 -06001321 if (bcg.ttyin) {
Gavin Howard63738202018-09-26 15:34:20 -06001322 if (fputs(bc_program_ready_msg, stderr) < 0 || fflush(stderr) < 0)
1323 s = BC_STATUS_IO_ERR;
1324 else s = BC_STATUS_SUCCESS;
1325 }
1326 else s = BC_STATUS_QUIT;
1327 }
1328
1329 return s;
Gavin Howardf4167dc2018-03-26 14:19:28 -06001330}
1331
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001332BcStatus bc_program_exec(BcProgram *p) {
Gavin Howard5b5dc572018-01-24 11:57:38 -07001333
Gavin Howard63738202018-09-26 15:34:20 -06001334 BcStatus s = BC_STATUS_SUCCESS;
Gavin Howard972e8402018-10-01 13:11:49 -06001335 size_t idx;
Gavin Howardb4584aa2018-09-28 10:45:33 -06001336 BcResult res;
Gavin Howard63738202018-09-26 15:34:20 -06001337 BcResult *ptr;
1338 BcNum *num;
Gavin Howard63738202018-09-26 15:34:20 -06001339 BcInstPtr *ip = bc_vec_top(&p->stack);
1340 BcFunc *func = bc_vec_item(&p->fns, ip->func);
Gavin Howardc39fd492018-10-04 10:07:03 -06001341 char *code = func->code.v;
Gavin Howarde6e84762018-10-03 11:46:34 -06001342#ifdef BC_ENABLED
Gavin Howard972e8402018-10-01 13:11:49 -06001343 bool cond = false;
Gavin Howarde6e84762018-10-03 11:46:34 -06001344#endif // BC_ENABLED
Gavin Howardb09d9b12018-03-23 09:57:07 -06001345
Gavin Howard63738202018-09-26 15:34:20 -06001346 while (!s && !bcg.sig_other && ip->idx < func->code.len) {
Gavin Howard368459a2018-03-28 13:23:51 -06001347
Gavin Howard63738202018-09-26 15:34:20 -06001348 uint8_t inst = code[(ip->idx)++];
Gavin Howard7c8dc772018-02-21 12:12:11 -07001349
Gavin Howard63738202018-09-26 15:34:20 -06001350 switch (inst) {
Gavin Howard7c8dc772018-02-21 12:12:11 -07001351
Gavin Howarde6e84762018-10-03 11:46:34 -06001352#ifdef BC_ENABLED
Gavin Howard63738202018-09-26 15:34:20 -06001353 case BC_INST_JUMP_ZERO:
1354 {
Gavin Howardb4584aa2018-09-28 10:45:33 -06001355 if ((s = bc_program_prep(p, &ptr, &num, false))) return s;
Gavin Howard63738202018-09-26 15:34:20 -06001356 cond = !bc_num_cmp(num, &p->zero);
1357 bc_vec_pop(&p->results);
1358 }
1359 // Fallthrough.
1360 case BC_INST_JUMP:
1361 {
Gavin Howard972e8402018-10-01 13:11:49 -06001362 size_t *addr;
Gavin Howard63738202018-09-26 15:34:20 -06001363 idx = bc_program_index(code, &ip->idx);
1364 addr = bc_vec_item(&func->labels, idx);
1365 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
1366 break;
1367 }
Gavin Howard195706a2018-02-26 17:45:58 -07001368
Gavin Howard972e8402018-10-01 13:11:49 -06001369 case BC_INST_CALL:
1370 {
1371 s = bc_program_call(p, code, &ip->idx);
1372 break;
1373 }
1374
1375 case BC_INST_INC_PRE:
1376 case BC_INST_DEC_PRE:
1377 case BC_INST_INC_POST:
1378 case BC_INST_DEC_POST:
1379 {
1380 s = bc_program_incdec(p, inst);
1381 break;
1382 }
1383
1384 case BC_INST_HALT:
1385 {
1386 s = BC_STATUS_QUIT;
1387 break;
1388 }
1389
1390 case BC_INST_RET:
Gavin Howarde6e84762018-10-03 11:46:34 -06001391#endif // BC_ENABLED
Gavin Howard972e8402018-10-01 13:11:49 -06001392 case BC_INST_RET0:
1393 {
1394 s = bc_program_return(p, inst);
1395 break;
1396 }
1397
1398 case BC_INST_READ:
1399 {
1400 s = bc_program_read(p);
1401 break;
1402 }
1403
Gavin Howard63738202018-09-26 15:34:20 -06001404 case BC_INST_VAR:
Gavin Howardda4cfc02018-10-01 12:27:34 -06001405 {
Gavin Howard30ec94e2018-10-02 15:08:31 -06001406 s = bc_program_pushVar(p, code, &ip->idx, false);
Gavin Howardda4cfc02018-10-01 12:27:34 -06001407 break;
1408 }
1409
Gavin Howard63738202018-09-26 15:34:20 -06001410 case BC_INST_ARRAY_ELEM:
1411 case BC_INST_ARRAY:
1412 {
Gavin Howardda4cfc02018-10-01 12:27:34 -06001413 s = bc_program_pushArray(p, code, &ip->idx, inst);
Gavin Howard63738202018-09-26 15:34:20 -06001414 break;
1415 }
Gavin Howard195706a2018-02-26 17:45:58 -07001416
Gavin Howard63738202018-09-26 15:34:20 -06001417 case BC_INST_IBASE:
1418 case BC_INST_LAST:
1419 case BC_INST_OBASE:
1420 {
Gavin Howard0e58ded2018-10-02 15:06:52 -06001421 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
Gavin Howard90198862018-09-29 03:37:47 -06001422 s = bc_vec_push(&p->results, &res);
Gavin Howard63738202018-09-26 15:34:20 -06001423 break;
1424 }
Gavin Howard195706a2018-02-26 17:45:58 -07001425
Gavin Howard63738202018-09-26 15:34:20 -06001426 case BC_INST_SCALE:
1427 {
1428 s = bc_program_pushScale(p);
1429 break;
1430 }
Gavin Howard195706a2018-02-26 17:45:58 -07001431
Gavin Howard63738202018-09-26 15:34:20 -06001432 case BC_INST_SCALE_FUNC:
1433 case BC_INST_LENGTH:
1434 case BC_INST_SQRT:
1435 {
1436 s = bc_program_builtin(p, inst);
1437 break;
1438 }
Gavin Howard195706a2018-02-26 17:45:58 -07001439
Gavin Howard63738202018-09-26 15:34:20 -06001440 case BC_INST_NUM:
1441 {
Gavin Howard0e58ded2018-10-02 15:06:52 -06001442 res.t = BC_RESULT_CONSTANT;
Gavin Howardb4584aa2018-09-28 10:45:33 -06001443 res.data.id.idx = bc_program_index(code, &ip->idx);
Gavin Howard90198862018-09-29 03:37:47 -06001444 s = bc_vec_push(&p->results, &res);
Gavin Howard63738202018-09-26 15:34:20 -06001445 break;
1446 }
Gavin Howard195706a2018-02-26 17:45:58 -07001447
Gavin Howard63738202018-09-26 15:34:20 -06001448 case BC_INST_POP:
1449 {
1450 bc_vec_pop(&p->results);
1451 break;
1452 }
Gavin Howard5c222e32018-02-28 13:06:41 -07001453
Gavin Howard63738202018-09-26 15:34:20 -06001454 case BC_INST_PRINT:
Gavin Howard08f74ad2018-09-28 14:46:29 -06001455 case BC_INST_PRINT_POP:
Gavin Howard4e4a0112018-09-28 15:45:34 -06001456 case BC_INST_PRINT_STR:
Gavin Howard63738202018-09-26 15:34:20 -06001457 {
Gavin Howardc935ff12018-09-29 02:18:45 -06001458 s = bc_program_print(p, inst, 0);
Gavin Howard63738202018-09-26 15:34:20 -06001459 break;
1460 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001461
Gavin Howard63738202018-09-26 15:34:20 -06001462 case BC_INST_STR:
1463 {
Gavin Howard0e58ded2018-10-02 15:06:52 -06001464 res.t = BC_RESULT_STR;
Gavin Howard4e4a0112018-09-28 15:45:34 -06001465 res.data.id.idx = bc_program_index(code, &ip->idx);
Gavin Howard90198862018-09-29 03:37:47 -06001466 s = bc_vec_push(&p->results, &res);
Gavin Howard63738202018-09-26 15:34:20 -06001467 break;
1468 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001469
Gavin Howard63738202018-09-26 15:34:20 -06001470 case BC_INST_POWER:
1471 case BC_INST_MULTIPLY:
1472 case BC_INST_DIVIDE:
1473 case BC_INST_MODULUS:
1474 case BC_INST_PLUS:
1475 case BC_INST_MINUS:
1476 {
1477 s = bc_program_op(p, inst);
1478 break;
1479 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001480
Gavin Howarde6e84762018-10-03 11:46:34 -06001481#ifdef BC_ENABLED
Gavin Howard972e8402018-10-01 13:11:49 -06001482 case BC_INST_BOOL_OR:
1483 case BC_INST_BOOL_AND:
Gavin Howarde6e84762018-10-03 11:46:34 -06001484#endif // BC_ENABLED
Gavin Howard63738202018-09-26 15:34:20 -06001485 case BC_INST_REL_EQ:
1486 case BC_INST_REL_LE:
1487 case BC_INST_REL_GE:
1488 case BC_INST_REL_NE:
1489 case BC_INST_REL_LT:
1490 case BC_INST_REL_GT:
1491 {
1492 s = bc_program_logical(p, inst);
1493 break;
1494 }
Gavin Howard195706a2018-02-26 17:45:58 -07001495
Gavin Howard63738202018-09-26 15:34:20 -06001496 case BC_INST_BOOL_NOT:
1497 {
Gavin Howardb4584aa2018-09-28 10:45:33 -06001498 if ((s = bc_program_prep(p, &ptr, &num, false))) return s;
Gavin Howard648c01c2018-10-04 10:14:16 -06001499 if ((s = bc_num_init(&res.data.n, BC_NUM_DEF_SIZE))) return s;
Gavin Howarde8095352018-02-27 09:17:20 -07001500
Gavin Howard648c01c2018-10-04 10:14:16 -06001501 if (!bc_num_cmp(num, &p->zero)) bc_num_one(&res.data.n);
1502 else bc_num_zero(&res.data.n);
Gavin Howarde8095352018-02-27 09:17:20 -07001503
Gavin Howardb4584aa2018-09-28 10:45:33 -06001504 s = bc_program_retire(p, &res, BC_RESULT_TEMP);
Gavin Howard648c01c2018-10-04 10:14:16 -06001505 if (s) bc_num_free(&res.data.n);
Gavin Howarde8095352018-02-27 09:17:20 -07001506
Gavin Howard63738202018-09-26 15:34:20 -06001507 break;
1508 }
Gavin Howard195706a2018-02-26 17:45:58 -07001509
Gavin Howard63738202018-09-26 15:34:20 -06001510 case BC_INST_NEG:
1511 {
1512 s = bc_program_negate(p);
1513 break;
1514 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001515
Gavin Howarde6e84762018-10-03 11:46:34 -06001516#ifdef BC_ENABLED
Gavin Howard63738202018-09-26 15:34:20 -06001517 case BC_INST_ASSIGN_POWER:
1518 case BC_INST_ASSIGN_MULTIPLY:
1519 case BC_INST_ASSIGN_DIVIDE:
1520 case BC_INST_ASSIGN_MODULUS:
1521 case BC_INST_ASSIGN_PLUS:
1522 case BC_INST_ASSIGN_MINUS:
Gavin Howarde6e84762018-10-03 11:46:34 -06001523#endif // BC_ENABLED
Gavin Howard63738202018-09-26 15:34:20 -06001524 case BC_INST_ASSIGN:
1525 {
1526 s = bc_program_assign(p, inst);
1527 break;
1528 }
Gavin Howard6d89b5d2018-02-26 13:21:34 -07001529
Gavin Howarde6e84762018-10-03 11:46:34 -06001530#ifdef DC_ENABLED
Gavin Howardc935ff12018-09-29 02:18:45 -06001531 case BC_INST_MODEXP:
1532 {
Gavin Howardba009802018-09-29 04:41:51 -06001533 s = bc_program_modexp(p);
Gavin Howardc935ff12018-09-29 02:18:45 -06001534 break;
1535 }
1536
1537 case BC_INST_DIVMOD:
1538 {
Gavin Howard503f3932018-09-29 19:24:29 -06001539 s = bc_program_divmod(p);
Gavin Howardc935ff12018-09-29 02:18:45 -06001540 break;
1541 }
1542
Gavin Howard077e30a2018-09-29 22:29:56 -06001543 case BC_INST_EXECUTE:
1544 {
Gavin Howardda4cfc02018-10-01 12:27:34 -06001545 s = bc_program_executeStr(p);
Gavin Howard077e30a2018-09-29 22:29:56 -06001546 break;
1547 }
1548
Gavin Howardc935ff12018-09-29 02:18:45 -06001549 case BC_INST_PRINT_STACK:
1550 {
1551 for (idx = 0; !s && idx < p->results.len; ++idx) {
1552
1553 if ((s = bc_program_print(p, BC_INST_PRINT, idx))) break;
1554
1555 ptr = bc_vec_item_rev(&p->results, idx);
1556 assert(ptr);
1557
Gavin Howard0e58ded2018-10-02 15:06:52 -06001558 if (ptr->t == BC_RESULT_STR && putchar('\n') == EOF)
Gavin Howardc935ff12018-09-29 02:18:45 -06001559 s = BC_STATUS_IO_ERR;
1560 }
1561
1562 break;
1563 }
1564
1565 case BC_INST_CLEAR_STACK:
1566 {
1567 bc_vec_npop(&p->results, p->results.len);
1568 break;
1569 }
1570
1571 case BC_INST_STACK_LEN:
1572 {
1573 s = bc_program_stackLen(p);
1574 break;
1575 }
1576
1577 case BC_INST_DUPLICATE:
1578 {
1579 ptr = bc_vec_item_rev(&p->results, 1);
1580 if ((s = bc_result_copy(&res, ptr))) break;
Gavin Howard90198862018-09-29 03:37:47 -06001581 s = bc_vec_push(&p->results, &res);
Gavin Howardc935ff12018-09-29 02:18:45 -06001582 break;
1583 }
1584
1585 case BC_INST_SWAP:
1586 {
Gavin Howard4c2a13e2018-09-29 19:24:43 -06001587 BcResult *ptr2;
Gavin Howardc935ff12018-09-29 02:18:45 -06001588
Gavin Howard1e758c82018-09-29 19:57:37 -06001589 if (!BC_PROG_CHECK_STACK(&p->results, 2))
Gavin Howard21925472018-09-29 19:29:25 -06001590 return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howardc935ff12018-09-29 02:18:45 -06001591
Gavin Howard4c2a13e2018-09-29 19:24:43 -06001592 ptr = bc_vec_item_rev(&p->results, 0);
1593 ptr2 = bc_vec_item_rev(&p->results, 1);
Gavin Howardc935ff12018-09-29 02:18:45 -06001594 memcpy(&res, ptr, sizeof(BcResult));
1595 memcpy(ptr, ptr2, sizeof(BcResult));
1596 memcpy(ptr2, &res, sizeof(BcResult));
1597
1598 break;
1599 }
1600
Gavin Howardc8d426a2018-10-02 14:47:26 -06001601 case BC_INST_COPY_TO_VAR:
Gavin Howardc935ff12018-09-29 02:18:45 -06001602 {
Gavin Howard0e58ded2018-10-02 15:06:52 -06001603 char *name;
1604 if (!(name = bc_program_name(code, &ip->idx))) return s;
1605 s = bc_program_copyToVar(p, name, true);
1606 if (s) free(name);
Gavin Howardc935ff12018-09-29 02:18:45 -06001607 break;
1608 }
1609
Gavin Howardc8d426a2018-10-02 14:47:26 -06001610 case BC_INST_PUSH_VAR:
Gavin Howardc935ff12018-09-29 02:18:45 -06001611 {
Gavin Howardda4cfc02018-10-01 12:27:34 -06001612 s = bc_program_pushVar(p, code, &ip->idx, true);
Gavin Howardc935ff12018-09-29 02:18:45 -06001613 break;
1614 }
1615
1616 case BC_INST_QUIT:
1617 {
1618 if (p->stack.len <= 2) s = BC_STATUS_QUIT;
1619 else bc_vec_npop(&p->stack, 2);
1620 break;
1621 }
1622
1623 case BC_INST_NQUIT:
1624 {
1625 s = bc_program_nquit(p);
1626 break;
1627 }
Gavin Howarde6e84762018-10-03 11:46:34 -06001628#endif // DC_ENABLED
Gavin Howardc935ff12018-09-29 02:18:45 -06001629
Gavin Howardc39fd492018-10-04 10:07:03 -06001630#ifndef NDEBUG
Gavin Howard63738202018-09-26 15:34:20 -06001631 default:
1632 {
1633 assert(false);
1634 break;
1635 }
Gavin Howardc39fd492018-10-04 10:07:03 -06001636#endif // NDEBUG
Gavin Howard63738202018-09-26 15:34:20 -06001637 }
Gavin Howard195706a2018-02-26 17:45:58 -07001638
Gavin Howard63738202018-09-26 15:34:20 -06001639 if ((s && s != BC_STATUS_QUIT) || bcg.signe) s = bc_program_reset(p, s);
Gavin Howard0a2a6742018-02-27 14:11:26 -07001640
Gavin Howard63738202018-09-26 15:34:20 -06001641 // We need to update bc if the stack changes, pointers may be invalid.
1642 ip = bc_vec_top(&p->stack);
1643 func = bc_vec_item(&p->fns, ip->func);
Gavin Howardc39fd492018-10-04 10:07:03 -06001644 code = func->code.v;
Gavin Howard63738202018-09-26 15:34:20 -06001645 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001646
Gavin Howard63738202018-09-26 15:34:20 -06001647 return s;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001648}
1649
Gavin Howard84590c82018-03-28 15:38:44 -06001650void bc_program_free(BcProgram *p) {
1651
Gavin Howard63738202018-09-26 15:34:20 -06001652 assert(p);
Gavin Howard84590c82018-03-28 15:38:44 -06001653
Gavin Howard63738202018-09-26 15:34:20 -06001654 bc_num_free(&p->ib);
1655 bc_num_free(&p->ob);
Gavin Howard03610742018-09-27 10:48:29 -06001656 bc_num_free(&p->hexb);
Gavin Howard84590c82018-03-28 15:38:44 -06001657
Gavin Howard63738202018-09-26 15:34:20 -06001658 bc_vec_free(&p->fns);
1659 bc_veco_free(&p->fn_map);
Gavin Howard84590c82018-03-28 15:38:44 -06001660
Gavin Howard63738202018-09-26 15:34:20 -06001661 bc_vec_free(&p->vars);
1662 bc_veco_free(&p->var_map);
Gavin Howard84590c82018-03-28 15:38:44 -06001663
Gavin Howard63738202018-09-26 15:34:20 -06001664 bc_vec_free(&p->arrs);
1665 bc_veco_free(&p->arr_map);
Gavin Howard84590c82018-03-28 15:38:44 -06001666
Gavin Howard63738202018-09-26 15:34:20 -06001667 bc_vec_free(&p->strs);
1668 bc_vec_free(&p->consts);
Gavin Howard84590c82018-03-28 15:38:44 -06001669
Gavin Howard63738202018-09-26 15:34:20 -06001670 bc_vec_free(&p->results);
1671 bc_vec_free(&p->stack);
Gavin Howard84590c82018-03-28 15:38:44 -06001672
Gavin Howard63738202018-09-26 15:34:20 -06001673 bc_num_free(&p->last);
1674 bc_num_free(&p->zero);
1675 bc_num_free(&p->one);
Gavin Howard84590c82018-03-28 15:38:44 -06001676}
1677
1678#ifndef NDEBUG
Gavin Howard63738202018-09-26 15:34:20 -06001679BcStatus bc_program_printIndex(char *code, size_t *bgn) {
Gavin Howard84590c82018-03-28 15:38:44 -06001680
Gavin Howard63738202018-09-26 15:34:20 -06001681 char byte, i, bytes = code[(*bgn)++];
1682 unsigned long val = 0;
Gavin Howard24c675f2018-06-22 16:00:02 -06001683
Gavin Howard63738202018-09-26 15:34:20 -06001684 for (byte = 1, i = 0; byte && i < bytes; ++i) {
1685 byte = code[(*bgn)++];
1686 if (byte) val |= ((unsigned long) byte) << (CHAR_BIT * i);
1687 }
Gavin Howard84590c82018-03-28 15:38:44 -06001688
Gavin Howard63738202018-09-26 15:34:20 -06001689 return printf(" (%lu) ", val) < 0 ? BC_STATUS_IO_ERR : BC_STATUS_SUCCESS;
Gavin Howard84590c82018-03-28 15:38:44 -06001690}
1691
Gavin Howardaf2b7712018-09-28 16:17:41 -06001692BcStatus bc_program_printName(char *code, size_t *bgn) {
Gavin Howard84590c82018-03-28 15:38:44 -06001693
Gavin Howardaf2b7712018-09-28 16:17:41 -06001694 char byte = (char) code[(*bgn)++];
Gavin Howard84590c82018-03-28 15:38:44 -06001695
Gavin Howardaf2b7712018-09-28 16:17:41 -06001696 if (printf(" (") < 0) return BC_STATUS_IO_ERR;
Gavin Howard9d760632018-08-30 13:03:51 -06001697
Gavin Howardaf2b7712018-09-28 16:17:41 -06001698 for (; byte && byte != BC_PARSE_STREND; byte = (char) code[(*bgn)++]) {
Gavin Howard63738202018-09-26 15:34:20 -06001699 if (putchar(byte) == EOF) return BC_STATUS_IO_ERR;
1700 }
Gavin Howard84590c82018-03-28 15:38:44 -06001701
Gavin Howard63738202018-09-26 15:34:20 -06001702 assert(byte);
Gavin Howard84590c82018-03-28 15:38:44 -06001703
Gavin Howardaf2b7712018-09-28 16:17:41 -06001704 if (printf(") ") < 0) return BC_STATUS_IO_ERR;
1705
1706 return BC_STATUS_SUCCESS;
1707}
1708
1709BcStatus bc_program_printStr(BcProgram *p, char *code, size_t *bgn) {
1710
1711 size_t idx = bc_program_index(code, bgn);
1712 char *s;
1713
1714 assert(idx < p->strs.len);
1715
1716 s = *((char**) bc_vec_item(&p->strs, idx));
1717
1718 if (printf(" (\"%s\") ", s) < 0) return BC_STATUS_IO_ERR;
1719
1720 return BC_STATUS_SUCCESS;
1721}
1722
Gavin Howarde436e2c2018-10-02 15:08:48 -06001723BcStatus bc_program_printInst(BcProgram *p, char *code, size_t *bgn) {
1724
Gavin Howarde319eb62018-09-28 16:50:16 -06001725 BcStatus s = BC_STATUS_SUCCESS;
Gavin Howardaf2b7712018-09-28 16:17:41 -06001726 uint8_t inst = code[(*bgn)++];
1727
1728 if (putchar(bc_inst_chars[inst]) == EOF) return BC_STATUS_IO_ERR;
1729
1730 if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
1731 inst == BC_INST_ARRAY)
1732 {
1733 s = bc_program_printName(code, bgn);
1734 }
1735 else if (inst == BC_INST_STR) {
1736 s = bc_program_printStr(p, code, bgn);
1737 }
Gavin Howarde436e2c2018-10-02 15:08:48 -06001738 else if (inst == BC_INST_NUM) {
1739 size_t idx = bc_program_index(code, bgn);
1740 char **str = bc_vec_item(&p->consts, idx);
1741 if (printf("(%s)", *str) < 0) s = BC_STATUS_IO_ERR;
1742 }
1743 else if (inst == BC_INST_CALL ||
Gavin Howardaf2b7712018-09-28 16:17:41 -06001744 (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
1745 {
1746 if ((s = bc_program_printIndex(code, bgn))) return s;
1747 if (inst == BC_INST_CALL) s = bc_program_printIndex(code, bgn);
1748 }
Gavin Howard84590c82018-03-28 15:38:44 -06001749
Gavin Howarde319eb62018-09-28 16:50:16 -06001750 if (!s && fflush(stdout) < 0) s = BC_STATUS_IO_ERR;
1751
Gavin Howard63738202018-09-26 15:34:20 -06001752 return s;
Gavin Howard84590c82018-03-28 15:38:44 -06001753}
1754
Gavin Howard4e4a0112018-09-28 15:45:34 -06001755BcStatus bc_program_code(BcProgram *p) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001756
Gavin Howard63738202018-09-26 15:34:20 -06001757 BcStatus s = BC_STATUS_SUCCESS;
1758 BcFunc *f;
1759 char *code;
1760 BcInstPtr ip;
1761 size_t i;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001762
Gavin Howard63738202018-09-26 15:34:20 -06001763 for (i = 0; !s && !bcg.sig_other && i < p->fns.len; ++i) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001764
Gavin Howard63738202018-09-26 15:34:20 -06001765 bool sig;
Gavin Howardf6e3fb32018-08-09 13:48:59 -06001766
Gavin Howard63738202018-09-26 15:34:20 -06001767 ip.idx = ip.len = 0;
1768 ip.func = i;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001769
Gavin Howard63738202018-09-26 15:34:20 -06001770 f = bc_vec_item(&p->fns, ip.func);
Gavin Howardc39fd492018-10-04 10:07:03 -06001771 code = f->code.v;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001772
Gavin Howard63738202018-09-26 15:34:20 -06001773 if (printf("func[%zu]:\n", ip.func) < 0) return BC_STATUS_IO_ERR;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001774
Gavin Howardaf2b7712018-09-28 16:17:41 -06001775 while (ip.idx < f->code.len) s = bc_program_printInst(p, code, &ip.idx);
Gavin Howardc0d9f312018-03-07 15:15:00 -07001776
Gavin Howard63738202018-09-26 15:34:20 -06001777 if (printf("\n\n") < 0) s = BC_STATUS_IO_ERR;
Gavin Howard368459a2018-03-28 13:23:51 -06001778
Gavin Howard63738202018-09-26 15:34:20 -06001779 sig = bcg.sig != bcg.sigc;
1780 if (s || sig) s = bc_program_reset(p, s);
1781 }
Gavin Howard0a2a6742018-02-27 14:11:26 -07001782
Gavin Howard63738202018-09-26 15:34:20 -06001783 return s;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001784}
Gavin Howard84590c82018-03-28 15:38:44 -06001785#endif // NDEBUG