blob: cf7a4f01b30e97c1065a217a0218225d11606bbe [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 Howard13ab0152018-09-27 11:46:55 -060034BcStatus bc_program_search(BcProgram *p, BcResult *r, BcVec **ret, bool var) {
Gavin Howard3affc802018-02-27 19:57:38 -070035
Gavin Howard63738202018-09-26 15:34:20 -060036 BcStatus s;
37 BcEntry entry, *entry_ptr;
38 BcVec *vec;
39 BcVecO *veco;
40 size_t idx, ip_idx;
41 BcAuto *a;
42 // We use this because it has a union of BcNum and BcVec.
43 BcResult data;
Gavin Howard3affc802018-02-27 19:57:38 -070044
Gavin Howard63738202018-09-26 15:34:20 -060045 for (ip_idx = 0; ip_idx < p->stack.len - 1; ++ip_idx) {
Gavin Howard97eb8562018-03-21 08:04:29 -060046
Gavin Howard63738202018-09-26 15:34:20 -060047 BcFunc *func;
48 BcInstPtr *ip = bc_vec_item_rev(&p->stack, ip_idx);
Gavin Howard3affc802018-02-27 19:57:38 -070049
Gavin Howard63738202018-09-26 15:34:20 -060050 if (ip->func == BC_PROG_READ || ip->func == BC_PROG_MAIN) continue;
Gavin Howard3affc802018-02-27 19:57:38 -070051
Gavin Howard63738202018-09-26 15:34:20 -060052 func = bc_vec_item(&p->fns, ip->func);
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060053
Gavin Howard63738202018-09-26 15:34:20 -060054 for (idx = 0; idx < func->autos.len; ++idx) {
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060055
Gavin Howard63738202018-09-26 15:34:20 -060056 a = bc_vec_item(&func->autos, idx);
Gavin Howard3affc802018-02-27 19:57:38 -070057
Gavin Howard63738202018-09-26 15:34:20 -060058 if (!strcmp(a->name, r->data.id.name)) {
Gavin Howard3898d192018-03-14 20:44:33 -060059
Gavin Howard63738202018-09-26 15:34:20 -060060 BcResult *r = bc_vec_item(&p->results, ip->len + idx);
Gavin Howard3898d192018-03-14 20:44:33 -060061
Gavin Howard63738202018-09-26 15:34:20 -060062 if (!a->var != !var) return BC_STATUS_EXEC_BAD_TYPE;
Gavin Howard13ab0152018-09-27 11:46:55 -060063 *ret = &r->data.array;
Gavin Howard3affc802018-02-27 19:57:38 -070064
Gavin Howard63738202018-09-26 15:34:20 -060065 return BC_STATUS_SUCCESS;
66 }
67 }
68 }
Gavin Howard3affc802018-02-27 19:57:38 -070069
Gavin Howard63738202018-09-26 15:34:20 -060070 vec = var ? &p->vars : &p->arrs;
71 veco = var ? &p->var_map : &p->arr_map;
Gavin Howard3affc802018-02-27 19:57:38 -070072
Gavin Howard63738202018-09-26 15:34:20 -060073 entry.name = r->data.id.name;
74 entry.idx = vec->len;
Gavin Howard3affc802018-02-27 19:57:38 -070075
Gavin Howard63738202018-09-26 15:34:20 -060076 s = bc_veco_insert(veco, &entry, &idx);
Gavin Howard3affc802018-02-27 19:57:38 -070077
Gavin Howard63738202018-09-26 15:34:20 -060078 if (s != BC_STATUS_VEC_ITEM_EXISTS) {
Gavin Howard3affc802018-02-27 19:57:38 -070079
Gavin Howard63738202018-09-26 15:34:20 -060080 if (s) return s;
Gavin Howarda1ff02f2018-03-07 12:32:25 -070081
Gavin Howard63738202018-09-26 15:34:20 -060082 if (!(r->data.id.name = strdup(entry.name))) return BC_STATUS_ALLOC_ERR;
Gavin Howard13ab0152018-09-27 11:46:55 -060083 if ((s = bc_array_init(&data.data.array))) goto num_err;
Gavin Howarde87dcb82018-09-29 21:37:54 -060084 if ((s = bc_vec_push(vec, &data.data.array))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -060085 }
Gavin Howard3affc802018-02-27 19:57:38 -070086
Gavin Howard63738202018-09-26 15:34:20 -060087 entry_ptr = bc_veco_item(veco, idx);
88 *ret = bc_vec_item(vec, entry_ptr->idx);
89
90 return BC_STATUS_SUCCESS;
Gavin Howard37296462018-09-07 15:57:03 -060091
92err:
Gavin Howard13ab0152018-09-27 11:46:55 -060093 bc_array_free(&data.data.array);
Gavin Howard37296462018-09-07 15:57:03 -060094num_err:
Gavin Howard63738202018-09-26 15:34:20 -060095 free(r->data.id.name);
96 return s;
Gavin Howard3affc802018-02-27 19:57:38 -070097}
98
Gavin Howard63738202018-09-26 15:34:20 -060099BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex) {
Gavin Howard84095072018-02-27 15:36:58 -0700100
Gavin Howard63738202018-09-26 15:34:20 -0600101 BcStatus s = BC_STATUS_SUCCESS;
Gavin Howard84095072018-02-27 15:36:58 -0700102
Gavin Howard63738202018-09-26 15:34:20 -0600103 switch (r->type) {
Gavin Howard84095072018-02-27 15:36:58 -0700104
Gavin Howard63738202018-09-26 15:34:20 -0600105 case BC_RESULT_TEMP:
106 case BC_RESULT_SCALE:
107 {
108 *num = &r->data.num;
109 break;
110 }
Gavin Howard84095072018-02-27 15:36:58 -0700111
Gavin Howard63738202018-09-26 15:34:20 -0600112 case BC_RESULT_CONSTANT:
113 {
114 char **str = bc_vec_item(&p->consts, r->data.id.idx);
Gavin Howard03610742018-09-27 10:48:29 -0600115 size_t base_t, len = strlen(*str);
116 BcNum *base;
Gavin Howard84095072018-02-27 15:36:58 -0700117
Gavin Howard63738202018-09-26 15:34:20 -0600118 if ((s = bc_num_init(&r->data.num, len))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700119
Gavin Howard03610742018-09-27 10:48:29 -0600120 hex = hex && len == 1;
121 base = hex ? &p->hexb : &p->ib;
122 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
Gavin Howard84095072018-02-27 15:36:58 -0700123
Gavin Howard03610742018-09-27 10:48:29 -0600124 if ((s = bc_num_parse(&r->data.num, *str, base, base_t))) {
Gavin Howard63738202018-09-26 15:34:20 -0600125 bc_num_free(&r->data.num);
126 return s;
127 }
Gavin Howard84095072018-02-27 15:36:58 -0700128
Gavin Howard63738202018-09-26 15:34:20 -0600129 *num = &r->data.num;
130 r->type = BC_RESULT_TEMP;
Gavin Howard84095072018-02-27 15:36:58 -0700131
Gavin Howard63738202018-09-26 15:34:20 -0600132 break;
133 }
Gavin Howard84095072018-02-27 15:36:58 -0700134
Gavin Howard63738202018-09-26 15:34:20 -0600135 case BC_RESULT_VAR:
136 case BC_RESULT_ARRAY:
Gavin Howard13ab0152018-09-27 11:46:55 -0600137 case BC_RESULT_ARRAY_ELEM:
Gavin Howard63738202018-09-26 15:34:20 -0600138 {
Gavin Howard13ab0152018-09-27 11:46:55 -0600139 BcVec *v;
140
141 s = bc_program_search(p, r, &v, r->type == BC_RESULT_VAR);
142 if (s) return s;
143
144 if (r->type == BC_RESULT_ARRAY_ELEM) {
145
146 if (v->len <= r->data.id.idx) {
147 if ((s = bc_array_expand(v, r->data.id.idx + 1))) return s;
148 }
149
150 *num = bc_vec_item(v, r->data.id.idx);
151 }
Gavin Howarde87dcb82018-09-29 21:37:54 -0600152 else if (r->type == BC_RESULT_VAR) *num = bc_vec_top(v);
Gavin Howard13ab0152018-09-27 11:46:55 -0600153 else *num = (BcNum*) v;
154
Gavin Howard63738202018-09-26 15:34:20 -0600155 break;
156 }
Gavin Howard84095072018-02-27 15:36:58 -0700157
Gavin Howard63738202018-09-26 15:34:20 -0600158 case BC_RESULT_LAST:
159 {
160 *num = &p->last;
161 break;
162 }
Gavin Howard84095072018-02-27 15:36:58 -0700163
Gavin Howard63738202018-09-26 15:34:20 -0600164 case BC_RESULT_IBASE:
165 {
166 *num = &p->ib;
167 break;
168 }
Gavin Howard84095072018-02-27 15:36:58 -0700169
Gavin Howard63738202018-09-26 15:34:20 -0600170 case BC_RESULT_OBASE:
171 {
172 *num = &p->ob;
173 break;
174 }
Gavin Howard84095072018-02-27 15:36:58 -0700175
Gavin Howard63738202018-09-26 15:34:20 -0600176 case BC_RESULT_ONE:
177 {
178 *num = &p->one;
179 break;
180 }
Gavin Howard84095072018-02-27 15:36:58 -0700181
Gavin Howard63738202018-09-26 15:34:20 -0600182 default:
183 {
184 // This is here to prevent compiler warnings in release mode.
185 *num = &r->data.num;
186 assert(false);
187 break;
188 }
189 }
Gavin Howard84095072018-02-27 15:36:58 -0700190
Gavin Howard63738202018-09-26 15:34:20 -0600191 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700192}
Gavin Howard6d89b5d2018-02-26 13:21:34 -0700193
Gavin Howard63738202018-09-26 15:34:20 -0600194BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **left, BcNum **lval,
195 BcResult **right, BcNum **rval, bool assign)
Gavin Howard84095072018-02-27 15:36:58 -0700196{
Gavin Howard63738202018-09-26 15:34:20 -0600197 BcStatus s;
198 bool hex;
199 BcResultType lt, rt;
Gavin Howard84095072018-02-27 15:36:58 -0700200
Gavin Howard21925472018-09-29 19:29:25 -0600201 assert(p && left && lval && right && rval);
202
Gavin Howard1e758c82018-09-29 19:57:37 -0600203 if (!BC_PROG_CHECK_STACK(&p->results, 2)) return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howard84095072018-02-27 15:36:58 -0700204
Gavin Howard63738202018-09-26 15:34:20 -0600205 *right = bc_vec_item_rev(&p->results, 0);
206 *left = bc_vec_item_rev(&p->results, 1);
Gavin Howard84095072018-02-27 15:36:58 -0700207
Gavin Howard63738202018-09-26 15:34:20 -0600208 lt = (*left)->type;
209 rt = (*right)->type;
210 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
Gavin Howardc4987612018-09-21 13:14:09 -0600211
Gavin Howard63738202018-09-26 15:34:20 -0600212 if (lt == BC_RESULT_ARRAY || lt == BC_RESULT_ARRAY_AUTO ||
Gavin Howard4e4a0112018-09-28 15:45:34 -0600213 lt == BC_RESULT_STRING || rt == BC_RESULT_STRING ||
Gavin Howard63738202018-09-26 15:34:20 -0600214 rt == BC_RESULT_ARRAY || rt == BC_RESULT_ARRAY_AUTO)
215 {
216 return BC_STATUS_EXEC_BAD_TYPE;
217 }
Gavin Howard4c8ff2d2018-09-18 15:24:07 -0600218
Gavin Howard63738202018-09-26 15:34:20 -0600219 if ((s = bc_program_num(p, *left, lval, false))) return s;
220 if ((s = bc_program_num(p, *right, rval, hex))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700221
Gavin Howard63738202018-09-26 15:34:20 -0600222 // We run this again under these conditions in case any vector has been
223 // reallocated out from under the BcNums or arrays we had.
224 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
225 s = bc_program_num(p, *left, lval, false);
Gavin Howardee938c02018-09-21 12:27:44 -0600226
Gavin Howard63738202018-09-26 15:34:20 -0600227 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700228}
229
Gavin Howard1f3e7582018-09-29 02:19:54 -0600230BcStatus bc_program_binOpRetire(BcProgram *p, BcResult *r) {
231 r->type = BC_RESULT_TEMP;
Gavin Howard63738202018-09-26 15:34:20 -0600232 bc_vec_pop(&p->results);
233 bc_vec_pop(&p->results);
Gavin Howard90198862018-09-29 03:37:47 -0600234 return bc_vec_push(&p->results, r);
Gavin Howard84095072018-02-27 15:36:58 -0700235}
236
Gavin Howardb4584aa2018-09-28 10:45:33 -0600237BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, bool arr)
Gavin Howard38bea812018-09-20 12:01:25 -0600238{
Gavin Howard4e4a0112018-09-28 15:45:34 -0600239 BcResultType t;
240
Gavin Howard21925472018-09-29 19:29:25 -0600241 assert(p && r && n);
242
Gavin Howard1e758c82018-09-29 19:57:37 -0600243 if (!BC_PROG_CHECK_STACK(&p->results, 1)) return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howard4c8ff2d2018-09-18 15:24:07 -0600244
Gavin Howard90198862018-09-29 03:37:47 -0600245 *r = bc_vec_top(&p->results);
Gavin Howard4e4a0112018-09-28 15:45:34 -0600246 t = (*r)->type;
Gavin Howard4c8ff2d2018-09-18 15:24:07 -0600247
Gavin Howard4e4a0112018-09-28 15:45:34 -0600248 if (((t == BC_RESULT_ARRAY_AUTO || t == BC_RESULT_ARRAY) && !arr) ||
249 t == BC_RESULT_STRING)
Gavin Howard63738202018-09-26 15:34:20 -0600250 {
251 return BC_STATUS_EXEC_BAD_TYPE;
252 }
Gavin Howard4c8ff2d2018-09-18 15:24:07 -0600253
Gavin Howard63738202018-09-26 15:34:20 -0600254 return bc_program_num(p, *r, n, false);
Gavin Howard84095072018-02-27 15:36:58 -0700255}
256
Gavin Howard3950bb62018-09-28 15:46:00 -0600257BcStatus bc_program_retire(BcProgram *p, BcResult *r, BcResultType t) {
258 r->type = t;
Gavin Howard63738202018-09-26 15:34:20 -0600259 bc_vec_pop(&p->results);
Gavin Howard90198862018-09-29 03:37:47 -0600260 return bc_vec_push(&p->results, r);
Gavin Howard84095072018-02-27 15:36:58 -0700261}
262
Gavin Howard3f68df72018-03-22 20:30:27 -0600263BcStatus bc_program_op(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700264
Gavin Howard63738202018-09-26 15:34:20 -0600265 BcStatus s;
266 BcResult *opd1, *opd2, res;
267 BcNum *n1, *n2;
268 BcNumBinaryOp op;
Gavin Howard84095072018-02-27 15:36:58 -0700269
Gavin Howard63738202018-09-26 15:34:20 -0600270 if ((s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false))) return s;
271 if ((s = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700272
Gavin Howard63738202018-09-26 15:34:20 -0600273 op = bc_program_ops[inst - BC_INST_POWER];
274 if ((s = op(n1, n2, &res.data.num, p->scale))) goto err;
Gavin Howard1f3e7582018-09-29 02:19:54 -0600275 if ((s = bc_program_binOpRetire(p, &res))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700276
Gavin Howard63738202018-09-26 15:34:20 -0600277 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700278
279err:
Gavin Howard63738202018-09-26 15:34:20 -0600280 bc_num_free(&res.data.num);
281 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700282}
283
Gavin Howard3f68df72018-03-22 20:30:27 -0600284BcStatus bc_program_read(BcProgram *p) {
Gavin Howard84095072018-02-27 15:36:58 -0700285
Gavin Howard63738202018-09-26 15:34:20 -0600286 BcStatus s;
287 BcParse parse;
Gavin Howard7efe7442018-09-27 10:47:01 -0600288 BcVec buf;
Gavin Howard63738202018-09-26 15:34:20 -0600289 BcInstPtr ip;
Gavin Howard63738202018-09-26 15:34:20 -0600290 BcFunc *func = bc_vec_item(&p->fns, BC_PROG_READ);
Gavin Howard84095072018-02-27 15:36:58 -0700291
Gavin Howard63738202018-09-26 15:34:20 -0600292 func->code.len = 0;
Gavin Howard84095072018-02-27 15:36:58 -0700293
Gavin Howard7efe7442018-09-27 10:47:01 -0600294 if ((s = bc_vec_init(&buf, sizeof(char), NULL))) return BC_STATUS_ALLOC_ERR;
Gavin Howard6e59dee2018-09-27 12:09:00 -0600295 if ((s = bc_io_getline(&buf, "read> "))) goto io_err;
Gavin Howard84095072018-02-27 15:36:58 -0700296
Gavin Howardd2a05252018-09-27 14:00:40 -0600297 if ((s = p->parse_init(&parse, p))) goto io_err;
Gavin Howard63738202018-09-26 15:34:20 -0600298 bc_lex_file(&parse.lex, bc_program_stdin_name);
Gavin Howard7efe7442018-09-27 10:47:01 -0600299 if ((s = bc_lex_text(&parse.lex, buf.vec))) goto exec_err;
Gavin Howard84095072018-02-27 15:36:58 -0700300
Gavin Howardd2a05252018-09-27 14:00:40 -0600301 s = p->parse_expr(&parse, &func->code, BC_PARSE_NOREAD, bc_parse_next_read);
Gavin Howard63738202018-09-26 15:34:20 -0600302 if (s) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700303
Gavin Howard63738202018-09-26 15:34:20 -0600304 if (parse.lex.t.t != BC_LEX_NLINE && parse.lex.t.t != BC_LEX_EOF) {
305 s = BC_STATUS_EXEC_BAD_READ_EXPR;
306 goto exec_err;
307 }
Gavin Howard84095072018-02-27 15:36:58 -0700308
Gavin Howard63738202018-09-26 15:34:20 -0600309 ip.func = BC_PROG_READ;
310 ip.idx = 0;
311 ip.len = p->results.len;
Gavin Howard84095072018-02-27 15:36:58 -0700312
Gavin Howard90198862018-09-29 03:37:47 -0600313 if ((s = bc_vec_push(&p->stack, &ip))) goto exec_err;
Gavin Howard63738202018-09-26 15:34:20 -0600314 if ((s = bc_program_exec(p))) goto exec_err;
Gavin Howardceaf64d2018-03-05 11:20:34 -0700315
Gavin Howard63738202018-09-26 15:34:20 -0600316 bc_vec_pop(&p->stack);
Gavin Howardceaf64d2018-03-05 11:20:34 -0700317
Gavin Howard84095072018-02-27 15:36:58 -0700318exec_err:
Gavin Howard63738202018-09-26 15:34:20 -0600319 bc_parse_free(&parse);
Gavin Howard84095072018-02-27 15:36:58 -0700320io_err:
Gavin Howard7efe7442018-09-27 10:47:01 -0600321 bc_vec_free(&buf);
Gavin Howard63738202018-09-26 15:34:20 -0600322 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700323}
324
Gavin Howard63738202018-09-26 15:34:20 -0600325size_t bc_program_index(char *code, size_t *bgn) {
Gavin Howard84095072018-02-27 15:36:58 -0700326
Gavin Howard63738202018-09-26 15:34:20 -0600327 uint8_t amt = code[(*bgn)++], i = 0;
328 size_t res = 0;
Gavin Howard84095072018-02-27 15:36:58 -0700329
Gavin Howard63738202018-09-26 15:34:20 -0600330 for (; i < amt; ++i) res |= (((size_t) code[(*bgn)++]) << (i * CHAR_BIT));
Gavin Howard84095072018-02-27 15:36:58 -0700331
Gavin Howard63738202018-09-26 15:34:20 -0600332 return res;
Gavin Howard84095072018-02-27 15:36:58 -0700333}
334
Gavin Howard63738202018-09-26 15:34:20 -0600335char* bc_program_name(char *code, size_t *bgn) {
Gavin Howard84095072018-02-27 15:36:58 -0700336
Gavin Howard63738202018-09-26 15:34:20 -0600337 size_t len, i;
Gavin Howard74f99332018-09-28 10:03:07 -0600338 char byte, *s, *string = (char*) (code + *bgn), *ptr;
Gavin Howard84095072018-02-27 15:36:58 -0700339
Gavin Howard74f99332018-09-28 10:03:07 -0600340 ptr = strchr(string, BC_PARSE_STREND);
Gavin Howard63738202018-09-26 15:34:20 -0600341 if (ptr) len = ((unsigned long) ptr) - ((unsigned long) string);
342 else len = strlen(string);
Gavin Howard84095072018-02-27 15:36:58 -0700343
Gavin Howard63738202018-09-26 15:34:20 -0600344 if (!(s = malloc(len + 1))) return NULL;
Gavin Howard84095072018-02-27 15:36:58 -0700345
Gavin Howard74f99332018-09-28 10:03:07 -0600346 for (i = 0; (byte = (char) code[(*bgn)++]) && byte != BC_PARSE_STREND; ++i)
Gavin Howard63738202018-09-26 15:34:20 -0600347 s[i] = byte;
Gavin Howard84095072018-02-27 15:36:58 -0700348
Gavin Howard63738202018-09-26 15:34:20 -0600349 s[i] = '\0';
Gavin Howard84095072018-02-27 15:36:58 -0700350
Gavin Howard63738202018-09-26 15:34:20 -0600351 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700352}
353
Gavin Howard3f68df72018-03-22 20:30:27 -0600354BcStatus bc_program_printString(const char *str, size_t *nchars) {
Gavin Howard84095072018-02-27 15:36:58 -0700355
Gavin Howard63738202018-09-26 15:34:20 -0600356 size_t i, len = strlen(str);
Gavin Howard84095072018-02-27 15:36:58 -0700357
Gavin Howard63738202018-09-26 15:34:20 -0600358 for (i = 0; i < len; ++i, ++(*nchars)) {
Gavin Howard84095072018-02-27 15:36:58 -0700359
Gavin Howard6b7d6cb2018-09-28 14:21:47 -0600360 int err, c;
Gavin Howardf6e3fb32018-08-09 13:48:59 -0600361
Gavin Howard63738202018-09-26 15:34:20 -0600362 if ((c = str[i]) != '\\') err = putchar(c);
363 else {
Gavin Howard84095072018-02-27 15:36:58 -0700364
Gavin Howard6b7d6cb2018-09-28 14:21:47 -0600365 assert(i + 1 < len);
366 c = str[++i];
Gavin Howard84095072018-02-27 15:36:58 -0700367
Gavin Howard6b7d6cb2018-09-28 14:21:47 -0600368 switch (c) {
Gavin Howard84095072018-02-27 15:36:58 -0700369
Gavin Howard63738202018-09-26 15:34:20 -0600370 case 'a':
371 {
372 err = putchar('\a');
373 break;
374 }
Gavin Howard84095072018-02-27 15:36:58 -0700375
Gavin Howard63738202018-09-26 15:34:20 -0600376 case 'b':
377 {
378 err = putchar('\b');
379 break;
380 }
Gavin Howard84095072018-02-27 15:36:58 -0700381
Gavin Howard63738202018-09-26 15:34:20 -0600382 case 'e':
383 {
384 err = putchar('\\');
385 break;
386 }
Gavin Howard84095072018-02-27 15:36:58 -0700387
Gavin Howard63738202018-09-26 15:34:20 -0600388 case 'f':
389 {
390 err = putchar('\f');
391 break;
392 }
Gavin Howard84095072018-02-27 15:36:58 -0700393
Gavin Howard63738202018-09-26 15:34:20 -0600394 case 'n':
395 {
396 err = putchar('\n');
397 *nchars = SIZE_MAX;
398 break;
399 }
Gavin Howard84095072018-02-27 15:36:58 -0700400
Gavin Howard63738202018-09-26 15:34:20 -0600401 case 'r':
402 {
403 err = putchar('\r');
404 break;
405 }
Gavin Howard84095072018-02-27 15:36:58 -0700406
Gavin Howard63738202018-09-26 15:34:20 -0600407 case 'q':
408 {
409 err = putchar('"');
410 break;
411 }
Gavin Howard84095072018-02-27 15:36:58 -0700412
Gavin Howard63738202018-09-26 15:34:20 -0600413 case 't':
414 {
415 err = putchar('\t');
416 break;
417 }
Gavin Howard84095072018-02-27 15:36:58 -0700418
Gavin Howard63738202018-09-26 15:34:20 -0600419 default:
420 {
Gavin Howard07f7ff52018-09-28 14:22:06 -0600421 // Just print the character.
422 err = putchar(c);
Gavin Howard63738202018-09-26 15:34:20 -0600423 break;
424 }
425 }
426 }
Gavin Howard84095072018-02-27 15:36:58 -0700427
Gavin Howard63738202018-09-26 15:34:20 -0600428 if (err == EOF) return BC_STATUS_IO_ERR;
429 }
Gavin Howard84095072018-02-27 15:36:58 -0700430
Gavin Howard63738202018-09-26 15:34:20 -0600431 return BC_STATUS_SUCCESS;
Gavin Howard84095072018-02-27 15:36:58 -0700432}
433
Gavin Howardc935ff12018-09-29 02:18:45 -0600434BcStatus bc_program_print(BcProgram *p, uint8_t inst, size_t idx) {
Gavin Howard4e4a0112018-09-28 15:45:34 -0600435
436 BcStatus s = BC_STATUS_SUCCESS;
437 BcResult *r;
Gavin Howardc935ff12018-09-29 02:18:45 -0600438 size_t len, i;
Gavin Howard4e4a0112018-09-28 15:45:34 -0600439 char *str;
440
Gavin Howard21925472018-09-29 19:29:25 -0600441 assert(p);
442
Gavin Howard1e758c82018-09-29 19:57:37 -0600443 if (!BC_PROG_CHECK_STACK(&p->results, idx + 1))
444 return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howard4e4a0112018-09-28 15:45:34 -0600445
Gavin Howardc935ff12018-09-29 02:18:45 -0600446 r = bc_vec_item_rev(&p->results, idx);
Gavin Howard4e4a0112018-09-28 15:45:34 -0600447
448 if (r->type == BC_RESULT_STRING) {
449
450 idx = r->data.id.idx;
451 assert(idx < p->strs.len);
452
453 str = *((char**) bc_vec_item(&p->strs, idx));
454
455 if (inst == BC_INST_PRINT_STR) {
Gavin Howardc935ff12018-09-29 02:18:45 -0600456 for (i = 0, len = strlen(str); i < len; ++i) {
457 char c = str[i];
Gavin Howard4e4a0112018-09-28 15:45:34 -0600458 if (putchar(c) == EOF) return BC_STATUS_IO_ERR;
459 if (c == '\n') p->nchars = SIZE_MAX;
460 ++p->nchars;
461 }
462 }
463 else s = bc_program_printString(str, &p->nchars);
464 }
465 else {
466
467 BcNum *num;
468 bool nl = inst == BC_INST_PRINT;
469
470 assert(inst != BC_INST_PRINT_STR);
471
472 if ((s = bc_program_prep(p, &r, &num, false))) return s;
473
474 s = bc_num_print(num, &p->ob, p->ob_t, nl, &p->nchars, p->len);
475 if (s) return s;
476 if ((s = bc_num_copy(&p->last, num))) return s;
477
478 if (!nl) bc_vec_pop(&p->results);
479 }
480
481 return s;
482}
483
Gavin Howard63738202018-09-26 15:34:20 -0600484BcStatus bc_program_push(BcProgram *p, char *code, size_t *bgn, uint8_t inst) {
Gavin Howard843fa792018-02-27 16:42:52 -0700485
Gavin Howard63738202018-09-26 15:34:20 -0600486 BcStatus s;
487 BcResult res;
Gavin Howard843fa792018-02-27 16:42:52 -0700488
Gavin Howard63738202018-09-26 15:34:20 -0600489 res.data.id.name = bc_program_name(code, bgn);
Gavin Howard843fa792018-02-27 16:42:52 -0700490
Gavin Howard63738202018-09-26 15:34:20 -0600491 assert(res.data.id.name);
Gavin Howard843fa792018-02-27 16:42:52 -0700492
Gavin Howard63738202018-09-26 15:34:20 -0600493 if (inst == BC_INST_VAR || inst == BC_INST_ARRAY) {
494 res.type = inst == BC_INST_VAR ? BC_RESULT_VAR : BC_RESULT_ARRAY;
Gavin Howard90198862018-09-29 03:37:47 -0600495 s = bc_vec_push(&p->results, &res);
Gavin Howard63738202018-09-26 15:34:20 -0600496 }
497 else {
Gavin Howard843fa792018-02-27 16:42:52 -0700498
Gavin Howard63738202018-09-26 15:34:20 -0600499 BcResult *operand;
500 BcNum *num;
501 unsigned long temp;
Gavin Howard843fa792018-02-27 16:42:52 -0700502
Gavin Howardb4584aa2018-09-28 10:45:33 -0600503 if ((s = bc_program_prep(p, &operand, &num, false))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600504 if ((s = bc_num_ulong(num, &temp))) goto err;
Gavin Howardbdb2f922018-03-15 09:25:18 -0600505
Gavin Howard63738202018-09-26 15:34:20 -0600506 if (temp > (unsigned long) BC_MAX_DIM) {
507 s = BC_STATUS_EXEC_ARRAY_LEN;
508 goto err;
509 }
510
511 res.data.id.idx = (size_t) temp;
Gavin Howardb4584aa2018-09-28 10:45:33 -0600512 s = bc_program_retire(p, &res, BC_RESULT_ARRAY_ELEM);
Gavin Howard63738202018-09-26 15:34:20 -0600513 }
Gavin Howard843fa792018-02-27 16:42:52 -0700514
Gavin Howard843fa792018-02-27 16:42:52 -0700515err:
Gavin Howard63738202018-09-26 15:34:20 -0600516 if (s) free(res.data.id.name);
517 return s;
Gavin Howard843fa792018-02-27 16:42:52 -0700518}
519
Gavin Howard3f68df72018-03-22 20:30:27 -0600520BcStatus bc_program_negate(BcProgram *p) {
Gavin Howard3a947362018-03-02 11:25:48 -0700521
Gavin Howard63738202018-09-26 15:34:20 -0600522 BcStatus s;
523 BcResult res, *ptr;
524 BcNum *num;
Gavin Howard3a947362018-03-02 11:25:48 -0700525
Gavin Howardb4584aa2018-09-28 10:45:33 -0600526 if ((s = bc_program_prep(p, &ptr, &num, false))) return s;
Gavin Howard63738202018-09-26 15:34:20 -0600527 if ((s = bc_num_init(&res.data.num, num->len))) return s;
528 if ((s = bc_num_copy(&res.data.num, num))) goto err;
Gavin Howard3a947362018-03-02 11:25:48 -0700529
Gavin Howard63738202018-09-26 15:34:20 -0600530 res.data.num.neg = !res.data.num.neg;
Gavin Howarda654f112018-03-03 09:47:34 -0700531
Gavin Howardb4584aa2018-09-28 10:45:33 -0600532 if ((s = bc_program_retire(p, &res, BC_RESULT_TEMP))) goto err;
Gavin Howard3a947362018-03-02 11:25:48 -0700533
Gavin Howard63738202018-09-26 15:34:20 -0600534 return s;
Gavin Howard3a947362018-03-02 11:25:48 -0700535
536err:
Gavin Howard63738202018-09-26 15:34:20 -0600537 bc_num_free(&res.data.num);
538 return s;
Gavin Howard3a947362018-03-02 11:25:48 -0700539}
540
Gavin Howard3f68df72018-03-22 20:30:27 -0600541BcStatus bc_program_logical(BcProgram *p, uint8_t inst) {
Gavin Howard843fa792018-02-27 16:42:52 -0700542
Gavin Howard63738202018-09-26 15:34:20 -0600543 BcStatus s;
544 BcResult *opd1, *opd2, res;
545 BcNum *n1, *n2;
546 bool cond;
547 ssize_t cmp;
Gavin Howard843fa792018-02-27 16:42:52 -0700548
Gavin Howard63738202018-09-26 15:34:20 -0600549 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
550 if (s) return s;
Gavin Howard843fa792018-02-27 16:42:52 -0700551
Gavin Howard63738202018-09-26 15:34:20 -0600552 if ((s = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE))) return s;
Gavin Howard843fa792018-02-27 16:42:52 -0700553
Gavin Howard63738202018-09-26 15:34:20 -0600554 if (inst == BC_INST_BOOL_AND)
555 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
556 else if (inst == BC_INST_BOOL_OR)
557 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
558 else {
Gavin Howard843fa792018-02-27 16:42:52 -0700559
Gavin Howard63738202018-09-26 15:34:20 -0600560 cmp = bc_num_cmp(n1, n2);
Gavin Howard843fa792018-02-27 16:42:52 -0700561
Gavin Howard63738202018-09-26 15:34:20 -0600562 switch (inst) {
Gavin Howard28827802018-09-27 11:01:51 -0600563
Gavin Howard63738202018-09-26 15:34:20 -0600564 case BC_INST_REL_EQ:
565 {
566 cond = cmp == 0;
567 break;
568 }
Gavin Howard843fa792018-02-27 16:42:52 -0700569
Gavin Howard63738202018-09-26 15:34:20 -0600570 case BC_INST_REL_LE:
571 {
572 cond = cmp <= 0;
573 break;
574 }
Gavin Howard843fa792018-02-27 16:42:52 -0700575
Gavin Howard63738202018-09-26 15:34:20 -0600576 case BC_INST_REL_GE:
577 {
578 cond = cmp >= 0;
579 break;
580 }
Gavin Howard843fa792018-02-27 16:42:52 -0700581
Gavin Howard63738202018-09-26 15:34:20 -0600582 case BC_INST_REL_NE:
583 {
584 cond = cmp != 0;
585 break;
586 }
Gavin Howard843fa792018-02-27 16:42:52 -0700587
Gavin Howard63738202018-09-26 15:34:20 -0600588 case BC_INST_REL_LT:
589 {
590 cond = cmp < 0;
591 break;
592 }
Gavin Howard843fa792018-02-27 16:42:52 -0700593
Gavin Howard63738202018-09-26 15:34:20 -0600594 case BC_INST_REL_GT:
595 {
596 cond = cmp > 0;
597 break;
598 }
Gavin Howard843fa792018-02-27 16:42:52 -0700599
Gavin Howard63738202018-09-26 15:34:20 -0600600 default:
601 {
602 // This is here to silence a compiler warning in release mode.
603 cond = 0;
604 assert(cond);
605 break;
606 }
607 }
608 }
Gavin Howard843fa792018-02-27 16:42:52 -0700609
Gavin Howard63738202018-09-26 15:34:20 -0600610 (cond ? bc_num_one : bc_num_zero)(&res.data.num);
Gavin Howard843fa792018-02-27 16:42:52 -0700611
Gavin Howard1f3e7582018-09-29 02:19:54 -0600612 if ((s = bc_program_binOpRetire(p, &res))) goto err;
Gavin Howard843fa792018-02-27 16:42:52 -0700613
Gavin Howard63738202018-09-26 15:34:20 -0600614 return s;
Gavin Howard843fa792018-02-27 16:42:52 -0700615
616err:
Gavin Howard63738202018-09-26 15:34:20 -0600617 bc_num_free(&res.data.num);
618 return s;
Gavin Howard843fa792018-02-27 16:42:52 -0700619}
620
Gavin Howard3f68df72018-03-22 20:30:27 -0600621BcStatus bc_program_assign(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700622
Gavin Howard63738202018-09-26 15:34:20 -0600623 BcStatus s;
624 BcResult *left, *right, res;
625 BcNum *l, *r;
626 unsigned long val, max;
627 bool assign = inst == BC_INST_ASSIGN;
Gavin Howard84095072018-02-27 15:36:58 -0700628
Gavin Howard63738202018-09-26 15:34:20 -0600629 if ((s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700630
Gavin Howard4e4a0112018-09-28 15:45:34 -0600631 if (left->type == BC_RESULT_CONSTANT || left->type == BC_RESULT_TEMP ||
632 left->type == BC_RESULT_STRING)
633 {
Gavin Howard63738202018-09-26 15:34:20 -0600634 return BC_STATUS_PARSE_BAD_ASSIGN;
Gavin Howard4e4a0112018-09-28 15:45:34 -0600635 }
Gavin Howard84095072018-02-27 15:36:58 -0700636
Gavin Howard63738202018-09-26 15:34:20 -0600637 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
638 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
Gavin Howard84095072018-02-27 15:36:58 -0700639
Gavin Howard63738202018-09-26 15:34:20 -0600640 if (assign) s = bc_num_copy(l, r);
641 else s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
Gavin Howardd5a51e62018-03-26 12:34:27 -0600642
Gavin Howard63738202018-09-26 15:34:20 -0600643 if (s) return s;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600644
Gavin Howard63738202018-09-26 15:34:20 -0600645 if (left->type == BC_RESULT_IBASE || left->type == BC_RESULT_OBASE) {
Gavin Howardd5a51e62018-03-26 12:34:27 -0600646
Gavin Howard63738202018-09-26 15:34:20 -0600647 size_t * ptr = left->type == BC_RESULT_IBASE ? &p->ib_t : &p->ob_t;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600648
Gavin Howard63738202018-09-26 15:34:20 -0600649 if ((s = bc_num_ulong(r, &val))) return s;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600650
Gavin Howard63738202018-09-26 15:34:20 -0600651 max = left->type == BC_RESULT_IBASE ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Gavin Howard691cfd52018-09-21 10:47:58 -0600652
Gavin Howard63738202018-09-26 15:34:20 -0600653 if (val < BC_NUM_MIN_BASE || val > max)
Gavin Howardee2e8df2018-09-27 10:50:22 -0600654 return left->type == BC_RESULT_IBASE ? BC_STATUS_EXEC_BAD_IBASE :
655 BC_STATUS_EXEC_BAD_OBASE;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600656
Gavin Howard63738202018-09-26 15:34:20 -0600657 *ptr = (size_t) val;
658 }
659 else if (left->type == BC_RESULT_SCALE) {
Gavin Howardd5a51e62018-03-26 12:34:27 -0600660
Gavin Howard63738202018-09-26 15:34:20 -0600661 if ((s = bc_num_ulong(l, &val))) return s;
662 if (val > (unsigned long) BC_MAX_SCALE) return BC_STATUS_EXEC_BAD_SCALE;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600663
Gavin Howard63738202018-09-26 15:34:20 -0600664 p->scale = (size_t) val;
665 }
Gavin Howard84095072018-02-27 15:36:58 -0700666
Gavin Howard63738202018-09-26 15:34:20 -0600667 if ((s = bc_num_init(&res.data.num, l->len))) return s;
668 if ((s = bc_num_copy(&res.data.num, l))) goto err;
Gavin Howardb8181162018-02-28 12:58:09 -0700669
Gavin Howard1f3e7582018-09-29 02:19:54 -0600670 if ((s = bc_program_binOpRetire(p, &res))) goto err;
Gavin Howardb8181162018-02-28 12:58:09 -0700671
Gavin Howard63738202018-09-26 15:34:20 -0600672 return s;
Gavin Howardb8181162018-02-28 12:58:09 -0700673
674err:
Gavin Howard63738202018-09-26 15:34:20 -0600675 bc_num_free(&res.data.num);
676 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700677}
678
Gavin Howardaac24bf2018-09-22 23:24:53 -0600679BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx) {
Gavin Howard84095072018-02-27 15:36:58 -0700680
Gavin Howarde956c612018-09-27 11:40:28 -0600681 BcStatus s = BC_STATUS_SUCCESS;
Gavin Howard63738202018-09-26 15:34:20 -0600682 BcInstPtr ip;
683 size_t i, nparams = bc_program_index(code, idx);
684 BcFunc *func;
685 BcAuto *auto_ptr;
686 BcResult param, *arg;
Gavin Howard84095072018-02-27 15:36:58 -0700687
Gavin Howard63738202018-09-26 15:34:20 -0600688 ip.idx = 0;
689 ip.len = p->results.len;
690 ip.func = bc_program_index(code, idx);
Gavin Howard84095072018-02-27 15:36:58 -0700691
Gavin Howard63738202018-09-26 15:34:20 -0600692 func = bc_vec_item(&p->fns, ip.func);
Gavin Howard84095072018-02-27 15:36:58 -0700693
Gavin Howard63738202018-09-26 15:34:20 -0600694 if (!func->code.len) return BC_STATUS_EXEC_UNDEFINED_FUNC;
695 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
Gavin Howard84095072018-02-27 15:36:58 -0700696
Gavin Howard63738202018-09-26 15:34:20 -0600697 for (i = 0; i < nparams; ++i) {
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700698
Gavin Howarde87dcb82018-09-29 21:37:54 -0600699 BcVec *a;
700 BcNum *n;
701
Gavin Howard63738202018-09-26 15:34:20 -0600702 auto_ptr = bc_vec_item(&func->autos, i);
703 arg = bc_vec_item_rev(&p->results, nparams - 1);
704 param.type = auto_ptr->var + BC_RESULT_ARRAY_AUTO;
Gavin Howard57323432018-03-14 20:06:35 -0600705
Gavin Howard4e4a0112018-09-28 15:45:34 -0600706 if (!auto_ptr->var != (arg->type == BC_RESULT_ARRAY) ||
707 arg->type == BC_RESULT_STRING)
708 {
Gavin Howard63738202018-09-26 15:34:20 -0600709 return BC_STATUS_EXEC_BAD_TYPE;
Gavin Howard4e4a0112018-09-28 15:45:34 -0600710 }
Gavin Howard1ce83252018-09-04 15:21:47 -0600711
Gavin Howarde87dcb82018-09-29 21:37:54 -0600712 if ((s = bc_array_init(&param.data.array))) return s;
713
Gavin Howard63738202018-09-26 15:34:20 -0600714 if (auto_ptr->var) {
Gavin Howarde956c612018-09-27 11:40:28 -0600715 if ((s = bc_program_num(p, arg, &n, false))) return s;
Gavin Howarde87dcb82018-09-29 21:37:54 -0600716 if ((s = bc_num_copy(bc_vec_top(&param.data.array), n))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600717 }
718 else {
Gavin Howarde87dcb82018-09-29 21:37:54 -0600719 if ((s = bc_program_search(p, arg, &a, auto_ptr->var))) return s;
720 if ((s = bc_array_copy(&param.data.array, a))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600721 }
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700722
Gavin Howarde87dcb82018-09-29 21:37:54 -0600723 if ((s = bc_vec_push(&p->results, &param))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600724 }
Gavin Howard90f13ad2018-03-17 13:32:16 -0600725
Gavin Howarde87dcb82018-09-29 21:37:54 -0600726 for (; i < func->autos.len; ++i) {
Gavin Howard90f13ad2018-03-17 13:32:16 -0600727
Gavin Howard63738202018-09-26 15:34:20 -0600728 auto_ptr = bc_vec_item_rev(&func->autos, i);
729 param.type = auto_ptr->var + BC_RESULT_ARRAY_AUTO;
Gavin Howard90f13ad2018-03-17 13:32:16 -0600730
Gavin Howarde87dcb82018-09-29 21:37:54 -0600731 if ((s = bc_array_init(&param.data.array))) return s;
732 if ((s = bc_vec_push(&p->results, &param))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600733 }
Gavin Howard84095072018-02-27 15:36:58 -0700734
Gavin Howard90198862018-09-29 03:37:47 -0600735 return bc_vec_push(&p->stack, &ip);
Gavin Howard57323432018-03-14 20:06:35 -0600736
737err:
Gavin Howard63738202018-09-26 15:34:20 -0600738 bc_result_free(&param);
Gavin Howarde956c612018-09-27 11:40:28 -0600739 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700740}
741
Gavin Howard3f68df72018-03-22 20:30:27 -0600742BcStatus bc_program_return(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700743
Gavin Howard63738202018-09-26 15:34:20 -0600744 BcStatus s;
745 BcResult res;
746 BcFunc *f;
747 BcInstPtr *ip = bc_vec_top(&p->stack);
Gavin Howard84095072018-02-27 15:36:58 -0700748
Gavin Howard1e758c82018-09-29 19:57:37 -0600749 assert(BC_PROG_CHECK_STACK(&p->stack, 2));
Gavin Howard21925472018-09-29 19:29:25 -0600750
Gavin Howard1e758c82018-09-29 19:57:37 -0600751 if (!BC_PROG_CHECK_STACK(&p->results, ip->len + inst == BC_INST_RET))
Gavin Howard21925472018-09-29 19:29:25 -0600752 return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howardc410b0f2018-02-27 16:57:05 -0700753
Gavin Howard63738202018-09-26 15:34:20 -0600754 f = bc_vec_item(&p->fns, ip->func);
755 res.type = BC_RESULT_TEMP;
Gavin Howard84095072018-02-27 15:36:58 -0700756
Gavin Howard65bf0362018-09-28 11:28:56 -0600757 if (inst == BC_INST_RET) {
Gavin Howard84095072018-02-27 15:36:58 -0700758
Gavin Howard63738202018-09-26 15:34:20 -0600759 BcNum *num;
760 BcResult *operand = bc_vec_top(&p->results);
Gavin Howard84095072018-02-27 15:36:58 -0700761
Gavin Howard63738202018-09-26 15:34:20 -0600762 if ((s = bc_program_num(p, operand, &num, false))) return s;
763 if ((s = bc_num_init(&res.data.num, num->len))) return s;
764 if ((s = bc_num_copy(&res.data.num, num))) goto err;
765 }
766 else {
767 s = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE);
768 if (s) return s;
769 bc_num_zero(&res.data.num);
770 }
Gavin Howard84095072018-02-27 15:36:58 -0700771
Gavin Howard63738202018-09-26 15:34:20 -0600772 // We need to pop arguments as well, so this takes that into account.
773 bc_vec_npop(&p->results, p->results.len - (ip->len - f->nparams));
Gavin Howardc410b0f2018-02-27 16:57:05 -0700774
Gavin Howard90198862018-09-29 03:37:47 -0600775 if ((s = bc_vec_push(&p->results, &res))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600776 bc_vec_pop(&p->stack);
Gavin Howard0eb2a372018-03-24 09:52:55 -0600777
Gavin Howard63738202018-09-26 15:34:20 -0600778 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700779
780err:
Gavin Howard63738202018-09-26 15:34:20 -0600781 bc_num_free(&res.data.num);
782 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700783}
784
Gavin Howard3f68df72018-03-22 20:30:27 -0600785unsigned long bc_program_scale(BcNum *n) {
Gavin Howard63738202018-09-26 15:34:20 -0600786 return (unsigned long) n->rdx;
Gavin Howard84095072018-02-27 15:36:58 -0700787}
788
Gavin Howard77d489d2018-09-04 15:14:06 -0600789unsigned long bc_program_len(BcNum *n) {
Gavin Howard6e2fd062018-03-20 19:34:12 -0600790
Gavin Howard63738202018-09-26 15:34:20 -0600791 unsigned long len = n->len;
Gavin Howard6e2fd062018-03-20 19:34:12 -0600792
Gavin Howard63738202018-09-26 15:34:20 -0600793 if (n->rdx == n->len) {
794 size_t i;
795 for (i = n->len - 1; i < n->len && !n->num[i]; --len, --i);
796 }
Gavin Howard6e2fd062018-03-20 19:34:12 -0600797
Gavin Howard63738202018-09-26 15:34:20 -0600798 return len;
Gavin Howard84095072018-02-27 15:36:58 -0700799}
800
Gavin Howard3f68df72018-03-22 20:30:27 -0600801BcStatus bc_program_builtin(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700802
Gavin Howard63738202018-09-26 15:34:20 -0600803 BcStatus s;
804 BcResult *opnd;
805 BcNum *num;
Gavin Howardc935ff12018-09-29 02:18:45 -0600806 BcResult res;
Gavin Howard84095072018-02-27 15:36:58 -0700807
Gavin Howardb4584aa2018-09-28 10:45:33 -0600808 if ((s = bc_program_prep(p, &opnd, &num, inst == BC_INST_LENGTH))) return s;
Gavin Howardc935ff12018-09-29 02:18:45 -0600809 if ((s = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700810
Gavin Howardc935ff12018-09-29 02:18:45 -0600811 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.data.num, p->scale);
Gavin Howard63738202018-09-26 15:34:20 -0600812 else if (inst == BC_INST_LENGTH && opnd->type == BC_RESULT_ARRAY) {
813 BcVec *vec = (BcVec*) num;
Gavin Howardc935ff12018-09-29 02:18:45 -0600814 s = bc_num_ulong2num(&res.data.num, (unsigned long) vec->len);
Gavin Howard63738202018-09-26 15:34:20 -0600815 }
816 else {
817 assert(opnd->type != BC_RESULT_ARRAY);
818 BcProgramBuiltIn f = inst == BC_INST_LENGTH ? bc_program_len :
819 bc_program_scale;
Gavin Howardc935ff12018-09-29 02:18:45 -0600820 s = bc_num_ulong2num(&res.data.num, f(num));
Gavin Howard63738202018-09-26 15:34:20 -0600821 }
Gavin Howard84095072018-02-27 15:36:58 -0700822
Gavin Howardc935ff12018-09-29 02:18:45 -0600823 if (s || (s = bc_program_retire(p, &res, BC_RESULT_TEMP))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700824
825err:
Gavin Howardc935ff12018-09-29 02:18:45 -0600826 if (s) bc_num_free(&res.data.num);
Gavin Howard63738202018-09-26 15:34:20 -0600827 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700828}
829
Gavin Howardc935ff12018-09-29 02:18:45 -0600830#ifdef DC_CONFIG
Gavin Howardba009802018-09-29 04:41:51 -0600831BcStatus bc_program_modexp(BcProgram *p) {
832
833 BcStatus s;
834 BcResult *opd1, *opd2, *opd3, res;
835 BcNum *n1, *n2, *n3;
836
Gavin Howard1e758c82018-09-29 19:57:37 -0600837 if (!BC_PROG_CHECK_STACK(&p->results, 3)) return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howardba009802018-09-29 04:41:51 -0600838
839 if ((s = bc_program_binOpPrep(p, &opd2, &n2, &opd3, &n3, false))) return s;
840
841 opd1 = bc_vec_item_rev(&p->results, 2);
842 if ((s = bc_program_num(p, opd1, &n1, false))) return s;
843
844 if ((s = bc_num_init(&res.data.num, n3->len))) return s;
845
846 if ((s = bc_num_modexp(n1, n2, n3, &res.data.num, p->scale))) goto err;
847 bc_vec_pop(&p->results);
848
849 if ((s = bc_program_binOpRetire(p, &res))) goto err;
850
851 return s;
852
853err:
854 bc_num_free(&res.data.num);
855 return s;
856}
857
Gavin Howardc935ff12018-09-29 02:18:45 -0600858BcStatus bc_program_stackLen(BcProgram *p) {
859
860 BcStatus s;
861 BcResult res;
862 size_t len = p->results.len;
863
864 res.type = BC_RESULT_TEMP;
865
866 if ((s = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE))) return s;
867 if ((s = bc_num_ulong2num(&res.data.num, len))) goto err;
Gavin Howard90198862018-09-29 03:37:47 -0600868 if ((s = bc_vec_push(&p->results, &res))) goto err;
Gavin Howardc935ff12018-09-29 02:18:45 -0600869
870 return s;
871
872err:
873 bc_num_free(&res.data.num);
874 return s;
875}
876
877BcStatus bc_program_nquit(BcProgram *p) {
878
879 BcStatus s;
880 BcResult *opnd;
881 BcNum *num;
882 unsigned long val;
883
884 if ((s = bc_program_prep(p, &opnd, &num, false))) return s;
885 if ((s = bc_num_ulong(num, &val))) return s;
886
887 bc_vec_pop(&p->results);
888
889 if (p->stack.len < val) return BC_STATUS_EXEC_SMALL_STACK;
890 else if (p->stack.len == val) return BC_STATUS_QUIT;
891
892 bc_vec_npop(&p->stack, val);
893
894 return s;
895}
Gavin Howard503f3932018-09-29 19:24:29 -0600896
897BcStatus bc_program_divmod(BcProgram *p) {
898
899 BcStatus s;
900 BcResult *opd1, *opd2, res, res2;
901 BcNum *n1, *n2;
902
903 if ((s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false))) return s;
904 if ((s = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE))) return s;
905 if ((s = bc_num_init(&res2.data.num, n2->len))) goto res2_err;
906
907 if ((s = bc_num_div(n1, n2, &res2.data.num, p->scale))) goto err;
908 if ((s = bc_num_mod(n1, n2, &res.data.num, p->scale))) goto err;
909
910 if ((s = bc_program_binOpRetire(p, &res2))) goto err;
911 res.type = BC_RESULT_TEMP;
912 if ((s = bc_vec_push(&p->results, &res))) goto res2_err;
913
914 return s;
915
916err:
917 bc_num_free(&res2.data.num);
918res2_err:
919 bc_num_free(&res.data.num);
920 return s;
921}
Gavin Howardc935ff12018-09-29 02:18:45 -0600922#endif // DC_CONFIG
923
Gavin Howard3f68df72018-03-22 20:30:27 -0600924BcStatus bc_program_pushScale(BcProgram *p) {
Gavin Howard84095072018-02-27 15:36:58 -0700925
Gavin Howard63738202018-09-26 15:34:20 -0600926 BcStatus s;
927 BcResult res;
Gavin Howard84095072018-02-27 15:36:58 -0700928
Gavin Howard63738202018-09-26 15:34:20 -0600929 res.type = BC_RESULT_SCALE;
Gavin Howard84095072018-02-27 15:36:58 -0700930
Gavin Howard63738202018-09-26 15:34:20 -0600931 if ((s = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE))) return s;
932 s = bc_num_ulong2num(&res.data.num, (unsigned long) p->scale);
Gavin Howard90198862018-09-29 03:37:47 -0600933 if (s || (s = bc_vec_push(&p->results, &res))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700934
Gavin Howard63738202018-09-26 15:34:20 -0600935 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700936
937err:
Gavin Howard63738202018-09-26 15:34:20 -0600938 bc_num_free(&res.data.num);
939 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700940}
941
Gavin Howard3f68df72018-03-22 20:30:27 -0600942BcStatus bc_program_incdec(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700943
Gavin Howard63738202018-09-26 15:34:20 -0600944 BcStatus s;
945 BcResult *ptr, res, copy;
946 BcNum *num;
947 uint8_t inst2 = inst;
Gavin Howard84095072018-02-27 15:36:58 -0700948
Gavin Howardb4584aa2018-09-28 10:45:33 -0600949 if ((s = bc_program_prep(p, &ptr, &num, false))) return s;
Gavin Howard84095072018-02-27 15:36:58 -0700950
Gavin Howard63738202018-09-26 15:34:20 -0600951 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
952 copy.type = BC_RESULT_TEMP;
953 if ((s = bc_num_init(&copy.data.num, num->len))) return s;
954 if ((s = bc_num_copy(&copy.data.num, num))) goto err;
955 }
Gavin Howard84095072018-02-27 15:36:58 -0700956
Gavin Howard63738202018-09-26 15:34:20 -0600957 res.type = BC_RESULT_ONE;
958 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
959 BC_INST_ASSIGN_PLUS : BC_INST_ASSIGN_MINUS;
Gavin Howard84095072018-02-27 15:36:58 -0700960
Gavin Howard90198862018-09-29 03:37:47 -0600961 if ((s = bc_vec_push(&p->results, &res))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600962 if ((s = bc_program_assign(p, inst))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700963
Gavin Howard63738202018-09-26 15:34:20 -0600964 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
965 bc_vec_pop(&p->results);
Gavin Howard90198862018-09-29 03:37:47 -0600966 if ((s = bc_vec_push(&p->results, &copy))) goto err;
Gavin Howard63738202018-09-26 15:34:20 -0600967 }
Gavin Howard84095072018-02-27 15:36:58 -0700968
Gavin Howard63738202018-09-26 15:34:20 -0600969 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700970
971err:
972
Gavin Howard63738202018-09-26 15:34:20 -0600973 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST)
974 bc_num_free(&copy.data.num);
Gavin Howard84095072018-02-27 15:36:58 -0700975
Gavin Howard63738202018-09-26 15:34:20 -0600976 return s;
Gavin Howard84095072018-02-27 15:36:58 -0700977}
Gavin Howarde723a152018-02-27 15:24:00 -0700978
Gavin Howardd2a05252018-09-27 14:00:40 -0600979BcStatus bc_program_init(BcProgram *p, size_t line_len,
980 BcParseInit parse_init, BcParseExpr parse_expr)
981{
Gavin Howard63738202018-09-26 15:34:20 -0600982 BcStatus s;
983 size_t idx;
984 char *main_name = NULL, *read_name = NULL;
985 BcInstPtr ip;
Gavin Howard8a596d42018-01-15 15:46:01 -0700986
Gavin Howard63738202018-09-26 15:34:20 -0600987 assert(p);
Gavin Howard8a596d42018-01-15 15:46:01 -0700988
Gavin Howard63738202018-09-26 15:34:20 -0600989 assert((unsigned long) sysconf(_SC_BC_BASE_MAX) <= BC_MAX_OBASE);
990 assert((unsigned long) sysconf(_SC_BC_DIM_MAX) <= BC_MAX_DIM);
991 assert((unsigned long) sysconf(_SC_BC_SCALE_MAX) <= BC_MAX_SCALE);
992 assert((unsigned long) sysconf(_SC_BC_STRING_MAX) <= BC_MAX_STRING);
Gavin Howard57c843e2018-03-28 19:28:08 -0600993
Gavin Howard63738202018-09-26 15:34:20 -0600994 p->nchars = p->scale = 0;
Gavin Howard08f74ad2018-09-28 14:46:29 -0600995 p->len = line_len;
Gavin Howardd2a05252018-09-27 14:00:40 -0600996 p->parse_init = parse_init;
997 p->parse_expr = parse_expr;
Gavin Howard5d74e962018-02-26 13:44:13 -0700998
Gavin Howard63738202018-09-26 15:34:20 -0600999 if ((s = bc_num_init(&p->ib, BC_NUM_DEF_SIZE))) return s;
1000 bc_num_ten(&p->ib);
1001 p->ib_t = 10;
Gavin Howard5d74e962018-02-26 13:44:13 -07001002
Gavin Howard63738202018-09-26 15:34:20 -06001003 if ((s = bc_num_init(&p->ob, BC_NUM_DEF_SIZE))) goto obase_err;
1004 bc_num_ten(&p->ob);
1005 p->ob_t = 10;
Gavin Howard5d74e962018-02-26 13:44:13 -07001006
Gavin Howard03610742018-09-27 10:48:29 -06001007 if ((s = bc_num_init(&p->hexb, BC_NUM_DEF_SIZE))) goto hexb_err;
1008 bc_num_ten(&p->hexb);
1009 p->hexb.num[0] = 6;
1010
Gavin Howard63738202018-09-26 15:34:20 -06001011 if ((s = bc_num_init(&p->last, BC_NUM_DEF_SIZE))) goto last_err;
1012 bc_num_zero(&p->last);
Gavin Howardb5c77212018-02-14 17:12:34 -07001013
Gavin Howard63738202018-09-26 15:34:20 -06001014 if ((s = bc_num_init(&p->zero, BC_NUM_DEF_SIZE))) goto zero_err;
1015 bc_num_zero(&p->zero);
Gavin Howard5a8949e2018-02-05 16:46:06 -07001016
Gavin Howard63738202018-09-26 15:34:20 -06001017 if ((s = bc_num_init(&p->one, BC_NUM_DEF_SIZE))) goto one_err;
1018 bc_num_one(&p->one);
Gavin Howard645200e2018-02-15 15:33:35 -07001019
Gavin Howard63738202018-09-26 15:34:20 -06001020 if ((s = bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free))) goto fn_err;
Gavin Howard8a596d42018-01-15 15:46:01 -07001021
Gavin Howard63738202018-09-26 15:34:20 -06001022 s = bc_veco_init(&p->fn_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
1023 if (s) goto func_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001024
Gavin Howard3bc436f2018-09-28 14:02:34 -06001025 if (!(main_name = strdup(bc_func_main))) {
Gavin Howard63738202018-09-26 15:34:20 -06001026 s = BC_STATUS_ALLOC_ERR;
1027 goto name_err;
1028 }
Gavin Howardd50539a2018-02-08 20:52:57 -07001029
Gavin Howard63738202018-09-26 15:34:20 -06001030 s = bc_program_addFunc(p, main_name, &idx);
1031 if (s || idx != BC_PROG_MAIN) goto name_err;
1032 main_name = NULL;
Gavin Howardb42810f2018-03-09 10:07:58 -07001033
Gavin Howard3bc436f2018-09-28 14:02:34 -06001034 if (!(read_name = strdup(bc_func_read))) {
Gavin Howard63738202018-09-26 15:34:20 -06001035 s = BC_STATUS_ALLOC_ERR;
1036 goto name_err;
1037 }
Gavin Howarded392aa2018-02-27 13:09:26 -07001038
Gavin Howard63738202018-09-26 15:34:20 -06001039 s = bc_program_addFunc(p, read_name, &idx);
1040 if (s || idx != BC_PROG_READ) goto name_err;
1041 read_name = NULL;
Gavin Howardb42810f2018-03-09 10:07:58 -07001042
Gavin Howard63738202018-09-26 15:34:20 -06001043 if ((s = bc_vec_init(&p->vars, sizeof(BcNum), bc_num_free))) goto name_err;
1044 s = bc_veco_init(&p->var_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
1045 if (s) goto var_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001046
Gavin Howard63738202018-09-26 15:34:20 -06001047 if ((s = bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free))) goto arr_err;
1048 s = bc_veco_init(&p->arr_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
1049 if (s) goto array_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001050
Gavin Howard63738202018-09-26 15:34:20 -06001051 s = bc_vec_init(&p->strs, sizeof(char*), bc_string_free);
1052 if (s) goto string_err;
Gavin Howard5a8949e2018-02-05 16:46:06 -07001053
Gavin Howard63738202018-09-26 15:34:20 -06001054 s = bc_vec_init(&p->consts, sizeof(char*), bc_string_free);
1055 if (s) goto const_err;
Gavin Howarde46c6822018-02-08 20:05:39 -07001056
Gavin Howard63738202018-09-26 15:34:20 -06001057 s = bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
1058 if (s) goto expr_err;
Gavin Howard2534a812018-02-10 15:34:15 -07001059
Gavin Howard63738202018-09-26 15:34:20 -06001060 if ((s = bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL))) goto stack_err;
Gavin Howard2534a812018-02-10 15:34:15 -07001061
Gavin Howard63738202018-09-26 15:34:20 -06001062 memset(&ip, 0, sizeof(BcInstPtr));
Gavin Howard2534a812018-02-10 15:34:15 -07001063
Gavin Howard90198862018-09-29 03:37:47 -06001064 if ((s = bc_vec_push(&p->stack, &ip))) goto push_err;
Gavin Howardd28e80a2018-01-23 18:24:18 -07001065
Gavin Howard63738202018-09-26 15:34:20 -06001066 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001067
Gavin Howarded392aa2018-02-27 13:09:26 -07001068push_err:
Gavin Howard63738202018-09-26 15:34:20 -06001069 bc_vec_free(&p->stack);
Gavin Howard2534a812018-02-10 15:34:15 -07001070stack_err:
Gavin Howard63738202018-09-26 15:34:20 -06001071 bc_vec_free(&p->results);
Gavin Howard2534a812018-02-10 15:34:15 -07001072expr_err:
Gavin Howard63738202018-09-26 15:34:20 -06001073 bc_vec_free(&p->consts);
Gavin Howarde46c6822018-02-08 20:05:39 -07001074const_err:
Gavin Howard63738202018-09-26 15:34:20 -06001075 bc_vec_free(&p->strs);
Gavin Howard5a8949e2018-02-05 16:46:06 -07001076string_err:
Gavin Howard63738202018-09-26 15:34:20 -06001077 bc_veco_free(&p->arr_map);
Gavin Howardd96bcae2018-02-07 19:16:19 -07001078array_map_err:
Gavin Howard63738202018-09-26 15:34:20 -06001079 bc_vec_free(&p->arrs);
1080arr_err:
1081 bc_veco_free(&p->var_map);
Gavin Howardd96bcae2018-02-07 19:16:19 -07001082var_map_err:
Gavin Howard63738202018-09-26 15:34:20 -06001083 bc_vec_free(&p->vars);
Gavin Howardd50539a2018-02-08 20:52:57 -07001084name_err:
Gavin Howard63738202018-09-26 15:34:20 -06001085 bc_veco_free(&p->fn_map);
Gavin Howardd96bcae2018-02-07 19:16:19 -07001086func_map_err:
Gavin Howard63738202018-09-26 15:34:20 -06001087 bc_vec_free(&p->fns);
1088fn_err:
1089 bc_num_free(&p->one);
Gavin Howardb5c77212018-02-14 17:12:34 -07001090one_err:
Gavin Howard63738202018-09-26 15:34:20 -06001091 bc_num_free(&p->zero);
Gavin Howardb5c77212018-02-14 17:12:34 -07001092zero_err:
Gavin Howard63738202018-09-26 15:34:20 -06001093 bc_num_free(&p->last);
Gavin Howard5d74e962018-02-26 13:44:13 -07001094last_err:
Gavin Howard03610742018-09-27 10:48:29 -06001095 bc_num_free(&p->hexb);
1096hexb_err:
Gavin Howard63738202018-09-26 15:34:20 -06001097 bc_num_free(&p->ob);
Gavin Howard5d74e962018-02-26 13:44:13 -07001098obase_err:
Gavin Howard63738202018-09-26 15:34:20 -06001099 bc_num_free(&p->ib);
1100 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001101}
1102
Gavin Howard859e2902018-03-17 14:23:35 -06001103BcStatus bc_program_addFunc(BcProgram *p, char *name, size_t *idx) {
Gavin Howard3b90f9f2018-01-17 13:01:33 -07001104
Gavin Howard63738202018-09-26 15:34:20 -06001105 BcStatus s;
1106 BcEntry entry, *entry_ptr;
1107 BcFunc f;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001108
Gavin Howard63738202018-09-26 15:34:20 -06001109 assert(p && name && idx);
Gavin Howard3b90f9f2018-01-17 13:01:33 -07001110
Gavin Howard63738202018-09-26 15:34:20 -06001111 entry.name = name;
1112 entry.idx = p->fns.len;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001113
Gavin Howard63738202018-09-26 15:34:20 -06001114 s = bc_veco_insert(&p->fn_map, &entry, idx);
Gavin Howardff526122018-09-06 19:58:52 -06001115
Gavin Howard63738202018-09-26 15:34:20 -06001116 if (s) {
1117 free(name);
1118 if (s != BC_STATUS_VEC_ITEM_EXISTS) return s;
1119 }
Gavin Howardded20a22018-03-07 15:15:19 -07001120
Gavin Howard63738202018-09-26 15:34:20 -06001121 entry_ptr = bc_veco_item(&p->fn_map, *idx);
1122 *idx = entry_ptr->idx;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001123
Gavin Howard63738202018-09-26 15:34:20 -06001124 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
Gavin Howardab67e7c2018-02-09 10:35:44 -07001125
Gavin Howard63738202018-09-26 15:34:20 -06001126 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
1127 s = BC_STATUS_SUCCESS;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001128
Gavin Howard63738202018-09-26 15:34:20 -06001129 // We need to reset these, so the function can be repopulated.
1130 func->nparams = 0;
1131 bc_vec_npop(&func->autos, func->autos.len);
1132 bc_vec_npop(&func->code, func->code.len);
1133 bc_vec_npop(&func->labels, func->labels.len);
1134 }
1135 else {
1136 if ((s = bc_func_init(&f))) return s;
Gavin Howard90198862018-09-29 03:37:47 -06001137 if ((s = bc_vec_push(&p->fns, &f))) bc_func_free(&f);
Gavin Howard63738202018-09-26 15:34:20 -06001138 }
Gavin Howardded20a22018-03-07 15:15:19 -07001139
Gavin Howard63738202018-09-26 15:34:20 -06001140 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001141}
1142
Gavin Howard63738202018-09-26 15:34:20 -06001143BcStatus bc_program_reset(BcProgram *p, BcStatus s) {
Gavin Howardf4167dc2018-03-26 14:19:28 -06001144
Gavin Howard63738202018-09-26 15:34:20 -06001145 BcFunc *f;
1146 BcInstPtr *ip;
Gavin Howardf4167dc2018-03-26 14:19:28 -06001147
Gavin Howard63738202018-09-26 15:34:20 -06001148 bc_vec_npop(&p->stack, p->stack.len - 1);
1149 bc_vec_npop(&p->results, p->results.len);
Gavin Howardabdc2d32018-03-27 08:01:08 -06001150
Gavin Howard63738202018-09-26 15:34:20 -06001151 f = bc_vec_item(&p->fns, 0);
1152 ip = bc_vec_top(&p->stack);
1153 ip->idx = f->code.len;
Gavin Howardf4167dc2018-03-26 14:19:28 -06001154
Gavin Howard63738202018-09-26 15:34:20 -06001155 if (!s && bcg.signe && !bcg.tty) return BC_STATUS_QUIT;
Gavin Howardabdc2d32018-03-27 08:01:08 -06001156
Gavin Howard63738202018-09-26 15:34:20 -06001157 bcg.sigc += bcg.signe;
1158 bcg.signe = bcg.sig != bcg.sigc;
Gavin Howardabdc2d32018-03-27 08:01:08 -06001159
Gavin Howard63738202018-09-26 15:34:20 -06001160 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
Gavin Howard46f0e422018-03-27 08:12:00 -06001161
Gavin Howardca893d72018-09-28 14:15:16 -06001162 if (bcg.ttyin) {
Gavin Howard63738202018-09-26 15:34:20 -06001163 if (fputs(bc_program_ready_msg, stderr) < 0 || fflush(stderr) < 0)
1164 s = BC_STATUS_IO_ERR;
1165 else s = BC_STATUS_SUCCESS;
1166 }
1167 else s = BC_STATUS_QUIT;
1168 }
1169
1170 return s;
Gavin Howardf4167dc2018-03-26 14:19:28 -06001171}
1172
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001173BcStatus bc_program_exec(BcProgram *p) {
Gavin Howard5b5dc572018-01-24 11:57:38 -07001174
Gavin Howard63738202018-09-26 15:34:20 -06001175 BcStatus s = BC_STATUS_SUCCESS;
Gavin Howard4e4a0112018-09-28 15:45:34 -06001176 size_t idx, *addr;
Gavin Howardb4584aa2018-09-28 10:45:33 -06001177 BcResult res;
Gavin Howard63738202018-09-26 15:34:20 -06001178 BcResult *ptr;
1179 BcNum *num;
1180 bool cond = false;
1181 BcInstPtr *ip = bc_vec_top(&p->stack);
1182 BcFunc *func = bc_vec_item(&p->fns, ip->func);
1183 char *code = func->code.vec;
Gavin Howardb09d9b12018-03-23 09:57:07 -06001184
Gavin Howard63738202018-09-26 15:34:20 -06001185 while (!s && !bcg.sig_other && ip->idx < func->code.len) {
Gavin Howard368459a2018-03-28 13:23:51 -06001186
Gavin Howard63738202018-09-26 15:34:20 -06001187 uint8_t inst = code[(ip->idx)++];
Gavin Howard7c8dc772018-02-21 12:12:11 -07001188
Gavin Howard63738202018-09-26 15:34:20 -06001189 switch (inst) {
Gavin Howard7c8dc772018-02-21 12:12:11 -07001190
Gavin Howard63738202018-09-26 15:34:20 -06001191 case BC_INST_CALL:
1192 {
1193 s = bc_program_call(p, code, &ip->idx);
1194 break;
1195 }
Gavin Howard195706a2018-02-26 17:45:58 -07001196
Gavin Howard65bf0362018-09-28 11:28:56 -06001197 case BC_INST_RET:
1198 case BC_INST_RET0:
Gavin Howard63738202018-09-26 15:34:20 -06001199 {
1200 s = bc_program_return(p, inst);
1201 break;
1202 }
Gavin Howard195706a2018-02-26 17:45:58 -07001203
Gavin Howard63738202018-09-26 15:34:20 -06001204 case BC_INST_READ:
1205 {
1206 s = bc_program_read(p);
1207 break;
1208 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001209
Gavin Howard63738202018-09-26 15:34:20 -06001210 case BC_INST_JUMP_ZERO:
1211 {
Gavin Howardb4584aa2018-09-28 10:45:33 -06001212 if ((s = bc_program_prep(p, &ptr, &num, false))) return s;
Gavin Howard63738202018-09-26 15:34:20 -06001213 cond = !bc_num_cmp(num, &p->zero);
1214 bc_vec_pop(&p->results);
1215 }
1216 // Fallthrough.
1217 case BC_INST_JUMP:
1218 {
1219 idx = bc_program_index(code, &ip->idx);
1220 addr = bc_vec_item(&func->labels, idx);
1221 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
1222 break;
1223 }
Gavin Howard195706a2018-02-26 17:45:58 -07001224
Gavin Howard63738202018-09-26 15:34:20 -06001225 case BC_INST_VAR:
1226 case BC_INST_ARRAY_ELEM:
1227 case BC_INST_ARRAY:
1228 {
1229 s = bc_program_push(p, code, &ip->idx, inst);
1230 break;
1231 }
Gavin Howard195706a2018-02-26 17:45:58 -07001232
Gavin Howard63738202018-09-26 15:34:20 -06001233 case BC_INST_IBASE:
1234 case BC_INST_LAST:
1235 case BC_INST_OBASE:
1236 {
Gavin Howardb4584aa2018-09-28 10:45:33 -06001237 res.type = inst - BC_INST_IBASE + BC_RESULT_IBASE;
Gavin Howard90198862018-09-29 03:37:47 -06001238 s = bc_vec_push(&p->results, &res);
Gavin Howard63738202018-09-26 15:34:20 -06001239 break;
1240 }
Gavin Howard195706a2018-02-26 17:45:58 -07001241
Gavin Howard63738202018-09-26 15:34:20 -06001242 case BC_INST_SCALE:
1243 {
1244 s = bc_program_pushScale(p);
1245 break;
1246 }
Gavin Howard195706a2018-02-26 17:45:58 -07001247
Gavin Howard63738202018-09-26 15:34:20 -06001248 case BC_INST_SCALE_FUNC:
1249 case BC_INST_LENGTH:
1250 case BC_INST_SQRT:
1251 {
1252 s = bc_program_builtin(p, inst);
1253 break;
1254 }
Gavin Howard195706a2018-02-26 17:45:58 -07001255
Gavin Howard63738202018-09-26 15:34:20 -06001256 case BC_INST_NUM:
1257 {
Gavin Howardb4584aa2018-09-28 10:45:33 -06001258 res.type = BC_RESULT_CONSTANT;
1259 res.data.id.idx = bc_program_index(code, &ip->idx);
Gavin Howard90198862018-09-29 03:37:47 -06001260 s = bc_vec_push(&p->results, &res);
Gavin Howard63738202018-09-26 15:34:20 -06001261 break;
1262 }
Gavin Howard195706a2018-02-26 17:45:58 -07001263
Gavin Howard63738202018-09-26 15:34:20 -06001264 case BC_INST_POP:
1265 {
1266 bc_vec_pop(&p->results);
1267 break;
1268 }
Gavin Howard5c222e32018-02-28 13:06:41 -07001269
Gavin Howard63738202018-09-26 15:34:20 -06001270 case BC_INST_INC_PRE:
1271 case BC_INST_DEC_PRE:
1272 case BC_INST_INC_POST:
1273 case BC_INST_DEC_POST:
1274 {
1275 s = bc_program_incdec(p, inst);
1276 break;
1277 }
Gavin Howard195706a2018-02-26 17:45:58 -07001278
Gavin Howard63738202018-09-26 15:34:20 -06001279 case BC_INST_HALT:
1280 {
1281 s = BC_STATUS_QUIT;
1282 break;
1283 }
Gavin Howard195706a2018-02-26 17:45:58 -07001284
Gavin Howard63738202018-09-26 15:34:20 -06001285 case BC_INST_PRINT:
Gavin Howard08f74ad2018-09-28 14:46:29 -06001286 case BC_INST_PRINT_POP:
Gavin Howard4e4a0112018-09-28 15:45:34 -06001287 case BC_INST_PRINT_STR:
Gavin Howard63738202018-09-26 15:34:20 -06001288 {
Gavin Howardc935ff12018-09-29 02:18:45 -06001289 s = bc_program_print(p, inst, 0);
Gavin Howard63738202018-09-26 15:34:20 -06001290 break;
1291 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001292
Gavin Howard63738202018-09-26 15:34:20 -06001293 case BC_INST_STR:
1294 {
Gavin Howard4e4a0112018-09-28 15:45:34 -06001295 res.type = BC_RESULT_STRING;
1296 res.data.id.idx = bc_program_index(code, &ip->idx);
Gavin Howard90198862018-09-29 03:37:47 -06001297 s = bc_vec_push(&p->results, &res);
Gavin Howard63738202018-09-26 15:34:20 -06001298 break;
1299 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001300
Gavin Howard63738202018-09-26 15:34:20 -06001301 case BC_INST_POWER:
1302 case BC_INST_MULTIPLY:
1303 case BC_INST_DIVIDE:
1304 case BC_INST_MODULUS:
1305 case BC_INST_PLUS:
1306 case BC_INST_MINUS:
1307 {
1308 s = bc_program_op(p, inst);
1309 break;
1310 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001311
Gavin Howard63738202018-09-26 15:34:20 -06001312 case BC_INST_REL_EQ:
1313 case BC_INST_REL_LE:
1314 case BC_INST_REL_GE:
1315 case BC_INST_REL_NE:
1316 case BC_INST_REL_LT:
1317 case BC_INST_REL_GT:
1318 {
1319 s = bc_program_logical(p, inst);
1320 break;
1321 }
Gavin Howard195706a2018-02-26 17:45:58 -07001322
Gavin Howard63738202018-09-26 15:34:20 -06001323 case BC_INST_BOOL_NOT:
1324 {
Gavin Howardb4584aa2018-09-28 10:45:33 -06001325 if ((s = bc_program_prep(p, &ptr, &num, false))) return s;
1326 if ((s = bc_num_init(&res.data.num, BC_NUM_DEF_SIZE))) return s;
Gavin Howarde8095352018-02-27 09:17:20 -07001327
Gavin Howardb4584aa2018-09-28 10:45:33 -06001328 if (!bc_num_cmp(num, &p->zero)) bc_num_one(&res.data.num);
1329 else bc_num_zero(&res.data.num);
Gavin Howarde8095352018-02-27 09:17:20 -07001330
Gavin Howardb4584aa2018-09-28 10:45:33 -06001331 s = bc_program_retire(p, &res, BC_RESULT_TEMP);
1332 if (s) bc_num_free(&res.data.num);
Gavin Howarde8095352018-02-27 09:17:20 -07001333
Gavin Howard63738202018-09-26 15:34:20 -06001334 break;
1335 }
Gavin Howard195706a2018-02-26 17:45:58 -07001336
Gavin Howard63738202018-09-26 15:34:20 -06001337 case BC_INST_BOOL_OR:
1338 case BC_INST_BOOL_AND:
1339 {
1340 s = bc_program_logical(p, inst);
1341 break;
1342 }
Gavin Howard195706a2018-02-26 17:45:58 -07001343
Gavin Howard63738202018-09-26 15:34:20 -06001344 case BC_INST_NEG:
1345 {
1346 s = bc_program_negate(p);
1347 break;
1348 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001349
Gavin Howard63738202018-09-26 15:34:20 -06001350 case BC_INST_ASSIGN_POWER:
1351 case BC_INST_ASSIGN_MULTIPLY:
1352 case BC_INST_ASSIGN_DIVIDE:
1353 case BC_INST_ASSIGN_MODULUS:
1354 case BC_INST_ASSIGN_PLUS:
1355 case BC_INST_ASSIGN_MINUS:
1356 case BC_INST_ASSIGN:
1357 {
1358 s = bc_program_assign(p, inst);
1359 break;
1360 }
Gavin Howard6d89b5d2018-02-26 13:21:34 -07001361
Gavin Howardc935ff12018-09-29 02:18:45 -06001362#ifdef DC_CONFIG
1363 case BC_INST_MODEXP:
1364 {
Gavin Howardba009802018-09-29 04:41:51 -06001365 s = bc_program_modexp(p);
Gavin Howardc935ff12018-09-29 02:18:45 -06001366 break;
1367 }
1368
1369 case BC_INST_DIVMOD:
1370 {
Gavin Howard503f3932018-09-29 19:24:29 -06001371 s = bc_program_divmod(p);
Gavin Howardc935ff12018-09-29 02:18:45 -06001372 break;
1373 }
1374
Gavin Howardc935ff12018-09-29 02:18:45 -06001375 case BC_INST_PRINT_STACK:
1376 {
1377 for (idx = 0; !s && idx < p->results.len; ++idx) {
1378
1379 if ((s = bc_program_print(p, BC_INST_PRINT, idx))) break;
1380
1381 ptr = bc_vec_item_rev(&p->results, idx);
1382 assert(ptr);
1383
1384 if (ptr->type == BC_RESULT_STRING && putchar('\n') == EOF)
1385 s = BC_STATUS_IO_ERR;
1386 }
1387
1388 break;
1389 }
1390
1391 case BC_INST_CLEAR_STACK:
1392 {
1393 bc_vec_npop(&p->results, p->results.len);
1394 break;
1395 }
1396
1397 case BC_INST_STACK_LEN:
1398 {
1399 s = bc_program_stackLen(p);
1400 break;
1401 }
1402
1403 case BC_INST_DUPLICATE:
1404 {
1405 ptr = bc_vec_item_rev(&p->results, 1);
1406 if ((s = bc_result_copy(&res, ptr))) break;
Gavin Howard90198862018-09-29 03:37:47 -06001407 s = bc_vec_push(&p->results, &res);
Gavin Howardc935ff12018-09-29 02:18:45 -06001408 break;
1409 }
1410
1411 case BC_INST_SWAP:
1412 {
Gavin Howard4c2a13e2018-09-29 19:24:43 -06001413 BcResult *ptr2;
Gavin Howardc935ff12018-09-29 02:18:45 -06001414
Gavin Howard1e758c82018-09-29 19:57:37 -06001415 if (!BC_PROG_CHECK_STACK(&p->results, 2))
Gavin Howard21925472018-09-29 19:29:25 -06001416 return BC_STATUS_EXEC_SMALL_STACK;
Gavin Howardc935ff12018-09-29 02:18:45 -06001417
Gavin Howard4c2a13e2018-09-29 19:24:43 -06001418 ptr = bc_vec_item_rev(&p->results, 0);
1419 ptr2 = bc_vec_item_rev(&p->results, 1);
Gavin Howardc935ff12018-09-29 02:18:45 -06001420 memcpy(&res, ptr, sizeof(BcResult));
1421 memcpy(ptr, ptr2, sizeof(BcResult));
1422 memcpy(ptr2, &res, sizeof(BcResult));
1423
1424 break;
1425 }
1426
1427 case BC_INST_PUSH_VAR:
1428 {
1429 // TODO
1430 break;
1431 }
1432
1433 case BC_INST_POP_VAR:
1434 {
1435 // TODO
1436 break;
1437 }
1438
1439 case BC_INST_QUIT:
1440 {
1441 if (p->stack.len <= 2) s = BC_STATUS_QUIT;
1442 else bc_vec_npop(&p->stack, 2);
1443 break;
1444 }
1445
1446 case BC_INST_NQUIT:
1447 {
1448 s = bc_program_nquit(p);
1449 break;
1450 }
1451#endif // DC_CONFIG
1452
Gavin Howard63738202018-09-26 15:34:20 -06001453 default:
1454 {
1455 assert(false);
1456 break;
1457 }
1458 }
Gavin Howard195706a2018-02-26 17:45:58 -07001459
Gavin Howard63738202018-09-26 15:34:20 -06001460 if ((s && s != BC_STATUS_QUIT) || bcg.signe) s = bc_program_reset(p, s);
Gavin Howard0a2a6742018-02-27 14:11:26 -07001461
Gavin Howard63738202018-09-26 15:34:20 -06001462 // We need to update bc if the stack changes, pointers may be invalid.
1463 ip = bc_vec_top(&p->stack);
1464 func = bc_vec_item(&p->fns, ip->func);
1465 code = func->code.vec;
1466 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001467
Gavin Howard63738202018-09-26 15:34:20 -06001468 return s;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001469}
1470
Gavin Howard84590c82018-03-28 15:38:44 -06001471void bc_program_free(BcProgram *p) {
1472
Gavin Howard63738202018-09-26 15:34:20 -06001473 assert(p);
Gavin Howard84590c82018-03-28 15:38:44 -06001474
Gavin Howard63738202018-09-26 15:34:20 -06001475 bc_num_free(&p->ib);
1476 bc_num_free(&p->ob);
Gavin Howard03610742018-09-27 10:48:29 -06001477 bc_num_free(&p->hexb);
Gavin Howard84590c82018-03-28 15:38:44 -06001478
Gavin Howard63738202018-09-26 15:34:20 -06001479 bc_vec_free(&p->fns);
1480 bc_veco_free(&p->fn_map);
Gavin Howard84590c82018-03-28 15:38:44 -06001481
Gavin Howard63738202018-09-26 15:34:20 -06001482 bc_vec_free(&p->vars);
1483 bc_veco_free(&p->var_map);
Gavin Howard84590c82018-03-28 15:38:44 -06001484
Gavin Howard63738202018-09-26 15:34:20 -06001485 bc_vec_free(&p->arrs);
1486 bc_veco_free(&p->arr_map);
Gavin Howard84590c82018-03-28 15:38:44 -06001487
Gavin Howard63738202018-09-26 15:34:20 -06001488 bc_vec_free(&p->strs);
1489 bc_vec_free(&p->consts);
Gavin Howard84590c82018-03-28 15:38:44 -06001490
Gavin Howard63738202018-09-26 15:34:20 -06001491 bc_vec_free(&p->results);
1492 bc_vec_free(&p->stack);
Gavin Howard84590c82018-03-28 15:38:44 -06001493
Gavin Howard63738202018-09-26 15:34:20 -06001494 bc_num_free(&p->last);
1495 bc_num_free(&p->zero);
1496 bc_num_free(&p->one);
Gavin Howard84590c82018-03-28 15:38:44 -06001497}
1498
1499#ifndef NDEBUG
Gavin Howard63738202018-09-26 15:34:20 -06001500BcStatus bc_program_printIndex(char *code, size_t *bgn) {
Gavin Howard84590c82018-03-28 15:38:44 -06001501
Gavin Howard63738202018-09-26 15:34:20 -06001502 char byte, i, bytes = code[(*bgn)++];
1503 unsigned long val = 0;
Gavin Howard24c675f2018-06-22 16:00:02 -06001504
Gavin Howard63738202018-09-26 15:34:20 -06001505 for (byte = 1, i = 0; byte && i < bytes; ++i) {
1506 byte = code[(*bgn)++];
1507 if (byte) val |= ((unsigned long) byte) << (CHAR_BIT * i);
1508 }
Gavin Howard84590c82018-03-28 15:38:44 -06001509
Gavin Howard63738202018-09-26 15:34:20 -06001510 return printf(" (%lu) ", val) < 0 ? BC_STATUS_IO_ERR : BC_STATUS_SUCCESS;
Gavin Howard84590c82018-03-28 15:38:44 -06001511}
1512
Gavin Howardaf2b7712018-09-28 16:17:41 -06001513BcStatus bc_program_printName(char *code, size_t *bgn) {
Gavin Howard84590c82018-03-28 15:38:44 -06001514
Gavin Howardaf2b7712018-09-28 16:17:41 -06001515 char byte = (char) code[(*bgn)++];
Gavin Howard84590c82018-03-28 15:38:44 -06001516
Gavin Howardaf2b7712018-09-28 16:17:41 -06001517 if (printf(" (") < 0) return BC_STATUS_IO_ERR;
Gavin Howard9d760632018-08-30 13:03:51 -06001518
Gavin Howardaf2b7712018-09-28 16:17:41 -06001519 for (; byte && byte != BC_PARSE_STREND; byte = (char) code[(*bgn)++]) {
Gavin Howard63738202018-09-26 15:34:20 -06001520 if (putchar(byte) == EOF) return BC_STATUS_IO_ERR;
1521 }
Gavin Howard84590c82018-03-28 15:38:44 -06001522
Gavin Howard63738202018-09-26 15:34:20 -06001523 assert(byte);
Gavin Howard84590c82018-03-28 15:38:44 -06001524
Gavin Howardaf2b7712018-09-28 16:17:41 -06001525 if (printf(") ") < 0) return BC_STATUS_IO_ERR;
1526
1527 return BC_STATUS_SUCCESS;
1528}
1529
1530BcStatus bc_program_printStr(BcProgram *p, char *code, size_t *bgn) {
1531
1532 size_t idx = bc_program_index(code, bgn);
1533 char *s;
1534
1535 assert(idx < p->strs.len);
1536
1537 s = *((char**) bc_vec_item(&p->strs, idx));
1538
1539 if (printf(" (\"%s\") ", s) < 0) return BC_STATUS_IO_ERR;
1540
1541 return BC_STATUS_SUCCESS;
1542}
1543
1544BcStatus bc_program_printInst(BcProgram *p, char *code, size_t *bgn)
1545{
Gavin Howarde319eb62018-09-28 16:50:16 -06001546 BcStatus s = BC_STATUS_SUCCESS;
Gavin Howardaf2b7712018-09-28 16:17:41 -06001547 uint8_t inst = code[(*bgn)++];
1548
1549 if (putchar(bc_inst_chars[inst]) == EOF) return BC_STATUS_IO_ERR;
1550
1551 if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
1552 inst == BC_INST_ARRAY)
1553 {
1554 s = bc_program_printName(code, bgn);
1555 }
1556 else if (inst == BC_INST_STR) {
1557 s = bc_program_printStr(p, code, bgn);
1558 }
1559 else if (inst == BC_INST_NUM || inst == BC_INST_CALL ||
1560 (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
1561 {
1562 if ((s = bc_program_printIndex(code, bgn))) return s;
1563 if (inst == BC_INST_CALL) s = bc_program_printIndex(code, bgn);
1564 }
Gavin Howard84590c82018-03-28 15:38:44 -06001565
Gavin Howarde319eb62018-09-28 16:50:16 -06001566 if (!s && fflush(stdout) < 0) s = BC_STATUS_IO_ERR;
1567
Gavin Howard63738202018-09-26 15:34:20 -06001568 return s;
Gavin Howard84590c82018-03-28 15:38:44 -06001569}
1570
Gavin Howard4e4a0112018-09-28 15:45:34 -06001571BcStatus bc_program_code(BcProgram *p) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001572
Gavin Howard63738202018-09-26 15:34:20 -06001573 BcStatus s = BC_STATUS_SUCCESS;
1574 BcFunc *f;
1575 char *code;
1576 BcInstPtr ip;
1577 size_t i;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001578
Gavin Howard63738202018-09-26 15:34:20 -06001579 for (i = 0; !s && !bcg.sig_other && i < p->fns.len; ++i) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001580
Gavin Howard63738202018-09-26 15:34:20 -06001581 bool sig;
Gavin Howardf6e3fb32018-08-09 13:48:59 -06001582
Gavin Howard63738202018-09-26 15:34:20 -06001583 ip.idx = ip.len = 0;
1584 ip.func = i;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001585
Gavin Howard63738202018-09-26 15:34:20 -06001586 f = bc_vec_item(&p->fns, ip.func);
1587 code = f->code.vec;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001588
Gavin Howard63738202018-09-26 15:34:20 -06001589 if (printf("func[%zu]:\n", ip.func) < 0) return BC_STATUS_IO_ERR;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001590
Gavin Howardaf2b7712018-09-28 16:17:41 -06001591 while (ip.idx < f->code.len) s = bc_program_printInst(p, code, &ip.idx);
Gavin Howardc0d9f312018-03-07 15:15:00 -07001592
Gavin Howard63738202018-09-26 15:34:20 -06001593 if (printf("\n\n") < 0) s = BC_STATUS_IO_ERR;
Gavin Howard368459a2018-03-28 13:23:51 -06001594
Gavin Howard63738202018-09-26 15:34:20 -06001595 sig = bcg.sig != bcg.sigc;
1596 if (s || sig) s = bc_program_reset(p, s);
1597 }
Gavin Howard0a2a6742018-02-27 14:11:26 -07001598
Gavin Howard63738202018-09-26 15:34:20 -06001599 return s;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001600}
Gavin Howard84590c82018-03-28 15:38:44 -06001601#endif // NDEBUG