blob: a830b7dac636e7e3730b0c65216e103a3dabfafb [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 Howard8a596d42018-01-15 15:46:01 -070024#include <stdint.h>
25#include <stdlib.h>
26#include <string.h>
27
Gavin Howardd525df82018-02-22 13:34:29 -070028#include <limits.h>
Gavin Howard82cdc6f2018-02-20 14:23:19 -070029#include <unistd.h>
Gavin Howard8a596d42018-01-15 15:46:01 -070030
Gavin Howarda54cabf2018-03-28 14:50:33 -060031#include <io.h>
Gavin Howard13ccc4a2018-02-15 14:09:41 -070032#include <program.h>
33#include <parse.h>
Gavin Howard29493062018-03-20 19:57:37 -060034#include <bc.h>
Gavin Howard8a596d42018-01-15 15:46:01 -070035
Gavin Howard3f68df72018-03-22 20:30:27 -060036BcStatus bc_program_search(BcProgram *p, BcResult *result,
37 BcNum **ret, uint8_t flags)
Gavin Howard3affc802018-02-27 19:57:38 -070038{
39 BcStatus status;
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060040 BcEntry entry, *entry_ptr;
Gavin Howard3affc802018-02-27 19:57:38 -070041 BcVec *vec;
42 BcVecO *veco;
Gavin Howard42d7c6d2018-03-20 14:09:01 -060043 size_t idx, ip_idx;
Gavin Howard57323432018-03-14 20:06:35 -060044 BcAuto *a;
Gavin Howarde3c7c8e2018-03-23 08:15:46 -060045 int var;
Gavin Howard3affc802018-02-27 19:57:38 -070046
Gavin Howard42d7c6d2018-03-20 14:09:01 -060047 for (ip_idx = 0; ip_idx < p->stack.len - 1; ++ip_idx) {
Gavin Howard3affc802018-02-27 19:57:38 -070048
Gavin Howard97eb8562018-03-21 08:04:29 -060049 BcFunc *func;
50 BcInstPtr *ip;
51
52 ip = bc_vec_item_rev(&p->stack, ip_idx);
Gavin Howard3affc802018-02-27 19:57:38 -070053
Gavin Howard27fdfb92018-03-21 07:56:59 -060054 assert(ip);
Gavin Howard3affc802018-02-27 19:57:38 -070055
Gavin Howard42d7c6d2018-03-20 14:09:01 -060056 if (ip->func == BC_PROGRAM_READ || ip->func == BC_PROGRAM_MAIN) continue;
Gavin Howard3affc802018-02-27 19:57:38 -070057
58 func = bc_vec_item(&p->funcs, ip->func);
59
Gavin Howard27fdfb92018-03-21 07:56:59 -060060 assert(func);
Gavin Howard3affc802018-02-27 19:57:38 -070061
Gavin Howard3898d192018-03-14 20:44:33 -060062 for (idx = 0; idx < func->autos.len; ++idx) {
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060063
Gavin Howard3898d192018-03-14 20:44:33 -060064 a = bc_vec_item(&func->autos, idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -060065 assert(a);
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060066
Gavin Howard3898d192018-03-14 20:44:33 -060067 if (!strcmp(a->name, result->data.id.name)) {
Gavin Howard3affc802018-02-27 19:57:38 -070068
Gavin Howard90f13ad2018-03-17 13:32:16 -060069 BcResult *r;
Gavin Howard3898d192018-03-14 20:44:33 -060070 uint8_t cond;
71
72 cond = flags & BC_PROGRAM_SEARCH_VAR;
73
Gavin Howardbdb2f922018-03-15 09:25:18 -060074 if (!a->var != !cond) return BC_STATUS_EXEC_BAD_TYPE;
Gavin Howard3898d192018-03-14 20:44:33 -060075
Gavin Howard0c0d1922018-03-21 17:00:21 -060076 r = bc_vec_item(&p->results, ip->len + idx);
Gavin Howard3898d192018-03-14 20:44:33 -060077
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060078 assert(r);
Gavin Howard3898d192018-03-14 20:44:33 -060079
Gavin Howardb09d9b12018-03-23 09:57:07 -060080 if (cond || flags & BC_PROGRAM_SEARCH_ARRAY) *ret = &r->data.num;
Gavin Howard3898d192018-03-14 20:44:33 -060081 else {
Gavin Howard90f13ad2018-03-17 13:32:16 -060082 status = bc_array_expand(&r->data.array, result->data.id.idx + 1);
Gavin Howard3898d192018-03-14 20:44:33 -060083 if (status) return status;
Gavin Howard90f13ad2018-03-17 13:32:16 -060084 *ret = bc_vec_item(&r->data.array, result->data.id.idx);
Gavin Howard3898d192018-03-14 20:44:33 -060085 }
86
87 return BC_STATUS_SUCCESS;
88 }
Gavin Howard57323432018-03-14 20:06:35 -060089 }
Gavin Howard3affc802018-02-27 19:57:38 -070090 }
91
Gavin Howarde3c7c8e2018-03-23 08:15:46 -060092 var = flags & BC_PROGRAM_SEARCH_VAR;
93 vec = var ? &p->vars : &p->arrays;
94 veco = var ? &p->var_map : &p->array_map;
Gavin Howard3affc802018-02-27 19:57:38 -070095
96 entry.name = result->data.id.name;
97 entry.idx = vec->len;
98
Gavin Howardea932f02018-03-23 09:53:40 -060099 status = bc_veco_insert(veco, &entry, &idx);
Gavin Howard3affc802018-02-27 19:57:38 -0700100
Gavin Howardea932f02018-03-23 09:53:40 -0600101 if (status != BC_STATUS_VEC_ITEM_EXISTS) {
Gavin Howard3affc802018-02-27 19:57:38 -0700102
Gavin Howardea932f02018-03-23 09:53:40 -0600103 // We use this because it has a union of BcNum and BcVec.
104 BcResult data;
105 size_t len;
Gavin Howarda1ff02f2018-03-07 12:32:25 -0700106
Gavin Howardea932f02018-03-23 09:53:40 -0600107 if (status) return status;
Gavin Howard3affc802018-02-27 19:57:38 -0700108
Gavin Howardea932f02018-03-23 09:53:40 -0600109 len = strlen(entry.name) + 1;
Gavin Howarda1ff02f2018-03-07 12:32:25 -0700110
Gavin Howardea932f02018-03-23 09:53:40 -0600111 if (!(result->data.id.name = malloc(len))) return BC_STATUS_MALLOC_FAIL;
Gavin Howarda1ff02f2018-03-07 12:32:25 -0700112
Gavin Howardea932f02018-03-23 09:53:40 -0600113 strcpy(result->data.id.name, entry.name);
Gavin Howarda1ff02f2018-03-07 12:32:25 -0700114
Gavin Howardea932f02018-03-23 09:53:40 -0600115 if (flags & BC_PROGRAM_SEARCH_VAR)
116 status = bc_num_init(&data.data.num, BC_NUM_DEF_SIZE);
117 else status = bc_vec_init(&data.data.array, sizeof(BcNum), bc_num_free);
Gavin Howard3affc802018-02-27 19:57:38 -0700118
Gavin Howardea932f02018-03-23 09:53:40 -0600119 if (status) return status;
Gavin Howard3affc802018-02-27 19:57:38 -0700120
Gavin Howardea932f02018-03-23 09:53:40 -0600121 if ((status = bc_vec_push(vec, &data.data))) return status;
Gavin Howard3affc802018-02-27 19:57:38 -0700122 }
Gavin Howard3affc802018-02-27 19:57:38 -0700123
124 entry_ptr = bc_veco_item(veco, idx);
125
Gavin Howard4b9bb2b2018-03-23 08:11:11 -0600126 assert(entry_ptr);
Gavin Howard3affc802018-02-27 19:57:38 -0700127
Gavin Howardb09d9b12018-03-23 09:57:07 -0600128 if (var) {
Gavin Howardf23448c2018-02-27 20:36:24 -0700129 *ret = bc_vec_item(vec, entry_ptr->idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -0600130 assert(*ret);
Gavin Howard3affc802018-02-27 19:57:38 -0700131 }
132 else {
133
Gavin Howard4b9bb2b2018-03-23 08:11:11 -0600134 BcVec *aptr = bc_vec_item(vec, entry_ptr->idx);
Gavin Howard3affc802018-02-27 19:57:38 -0700135
Gavin Howardb09d9b12018-03-23 09:57:07 -0600136 assert(aptr);
Gavin Howard3affc802018-02-27 19:57:38 -0700137
Gavin Howardb09d9b12018-03-23 09:57:07 -0600138 if (flags & BC_PROGRAM_SEARCH_ARRAY) {
Gavin Howardf23448c2018-02-27 20:36:24 -0700139 *ret = (BcNum*) aptr;
140 return BC_STATUS_SUCCESS;
141 }
142
Gavin Howardaaa91402018-02-28 12:31:22 -0700143 status = bc_array_expand(aptr, result->data.id.idx + 1);
Gavin Howardaaa91402018-02-28 12:31:22 -0700144 if (status) return status;
Gavin Howard3affc802018-02-27 19:57:38 -0700145
Gavin Howardf23448c2018-02-27 20:36:24 -0700146 *ret = bc_vec_item(aptr, result->data.id.idx);
Gavin Howard3affc802018-02-27 19:57:38 -0700147 }
148
149 return BC_STATUS_SUCCESS;
150}
151
Gavin Howard3f68df72018-03-22 20:30:27 -0600152BcStatus bc_program_num(BcProgram *p, BcResult *result, BcNum** num, bool hex) {
Gavin Howard84095072018-02-27 15:36:58 -0700153
Gavin Howard4b9bb2b2018-03-23 08:11:11 -0600154 BcStatus status = BC_STATUS_SUCCESS;
Gavin Howard84095072018-02-27 15:36:58 -0700155
156 switch (result->type) {
157
158 case BC_RESULT_INTERMEDIATE:
159 case BC_RESULT_SCALE:
160 {
161 *num = &result->data.num;
162 break;
163 }
164
165 case BC_RESULT_CONSTANT:
166 {
167 char** s;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600168 size_t len, base;
Gavin Howard84095072018-02-27 15:36:58 -0700169
Gavin Howardb09d9b12018-03-23 09:57:07 -0600170 s = bc_vec_item(&p->constants, result->data.id.idx);
Gavin Howard4b9bb2b2018-03-23 08:11:11 -0600171 assert(s);
Gavin Howard84095072018-02-27 15:36:58 -0700172 len = strlen(*s);
173
Gavin Howardb09d9b12018-03-23 09:57:07 -0600174 if ((status = bc_num_init(&result->data.num, len))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700175
Gavin Howardcb3ce022018-03-21 09:13:24 -0600176 base = hex && len == 1 ? BC_NUM_MAX_INPUT_BASE : p->ibase_t;
Gavin Howard84095072018-02-27 15:36:58 -0700177
Gavin Howard5cea43b2018-03-02 11:32:11 -0700178 status = bc_num_parse(&result->data.num, *s, &p->ibase, base);
Gavin Howard84095072018-02-27 15:36:58 -0700179
Gavin Howard9ba6c252018-03-14 01:44:38 -0600180 if (status) {
181 bc_num_free(&result->data.num);
182 return status;
183 }
Gavin Howard84095072018-02-27 15:36:58 -0700184
185 *num = &result->data.num;
186
187 result->type = BC_RESULT_INTERMEDIATE;
188
189 break;
190 }
191
192 case BC_RESULT_VAR:
Gavin Howardabcc5e02018-03-14 16:02:20 -0600193 case BC_RESULT_ARRAY:
Gavin Howard84095072018-02-27 15:36:58 -0700194 {
Gavin Howard92b7ce02018-03-14 20:04:14 -0600195 uint8_t flags = result->type == BC_RESULT_VAR ? BC_PROGRAM_SEARCH_VAR : 0;
Gavin Howarde661b4a2018-02-28 10:53:01 -0700196 status = bc_program_search(p, result, num, flags);
Gavin Howard84095072018-02-27 15:36:58 -0700197 break;
198 }
199
200 case BC_RESULT_LAST:
201 {
202 *num = &p->last;
203 break;
204 }
205
206 case BC_RESULT_IBASE:
207 {
208 *num = &p->ibase;
209 break;
210 }
211
212 case BC_RESULT_OBASE:
213 {
214 *num = &p->obase;
215 break;
216 }
217
218 case BC_RESULT_ONE:
219 {
220 *num = &p->one;
221 break;
222 }
223
224 default:
225 {
Gavin Howardb09d9b12018-03-23 09:57:07 -0600226 // This is here to prevent compiler warnings in release mode.
Gavin Howard2168fb82018-03-24 10:40:37 -0600227 *num = &result->data.num;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600228 assert(false);
Gavin Howard84095072018-02-27 15:36:58 -0700229 break;
230 }
231 }
232
233 return status;
234}
Gavin Howard6d89b5d2018-02-26 13:21:34 -0700235
Gavin Howard3f68df72018-03-22 20:30:27 -0600236BcStatus bc_program_binaryOpPrep(BcProgram *p, BcResult **left, BcNum **lval,
237 BcResult **right, BcNum **rval)
Gavin Howard84095072018-02-27 15:36:58 -0700238{
239 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600240 BcResult *l, *r;
Gavin Howardef1b52e2018-03-20 14:02:57 -0600241 bool hex;
Gavin Howard84095072018-02-27 15:36:58 -0700242
Gavin Howard27fdfb92018-03-21 07:56:59 -0600243 assert(p && left && lval && right && rval &&
Gavin Howard0c0d1922018-03-21 17:00:21 -0600244 BC_PROGRAM_CHECK_RESULTS(p, 2));
Gavin Howard84095072018-02-27 15:36:58 -0700245
Gavin Howard0c0d1922018-03-21 17:00:21 -0600246 r = bc_vec_item_rev(&p->results, 0);
247 l = bc_vec_item_rev(&p->results, 1);
Gavin Howard84095072018-02-27 15:36:58 -0700248
Gavin Howard27fdfb92018-03-21 07:56:59 -0600249 assert(r && l);
Gavin Howard84095072018-02-27 15:36:58 -0700250
Gavin Howard2168fb82018-03-24 10:40:37 -0600251 *left = l;
252 *right = r;
253
Gavin Howardef1b52e2018-03-20 14:02:57 -0600254 hex = l->type == BC_RESULT_IBASE || l->type == BC_RESULT_OBASE;
Gavin Howard84095072018-02-27 15:36:58 -0700255
Gavin Howardb09d9b12018-03-23 09:57:07 -0600256 if ((status = bc_program_num(p, l, lval, false))) return status;
257 if ((status = bc_program_num(p, r, rval, hex))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700258
Gavin Howard84095072018-02-27 15:36:58 -0700259 return BC_STATUS_SUCCESS;
260}
261
Gavin Howard3f68df72018-03-22 20:30:27 -0600262BcStatus bc_program_binaryOpRetire(BcProgram *p, BcResult *result,
263 BcResultType type)
Gavin Howard5fb956f2018-03-05 10:57:16 -0700264{
Gavin Howard5fb956f2018-03-05 10:57:16 -0700265 result->type = type;
266
Gavin Howard0eb2a372018-03-24 09:52:55 -0600267 bc_vec_pop(&p->results);
268 bc_vec_pop(&p->results);
Gavin Howard84095072018-02-27 15:36:58 -0700269
Gavin Howard0c0d1922018-03-21 17:00:21 -0600270 return bc_vec_push(&p->results, result);
Gavin Howard84095072018-02-27 15:36:58 -0700271}
272
Gavin Howard3f68df72018-03-22 20:30:27 -0600273BcStatus bc_program_unaryOpPrep(BcProgram *p, BcResult **result, BcNum **val) {
274
Gavin Howard84095072018-02-27 15:36:58 -0700275 BcStatus status;
276 BcResult *r;
Gavin Howard195706a2018-02-26 17:45:58 -0700277
Gavin Howard0c0d1922018-03-21 17:00:21 -0600278 assert(p && result && val && BC_PROGRAM_CHECK_RESULTS(p, 1));
Gavin Howard195706a2018-02-26 17:45:58 -0700279
Gavin Howard0c0d1922018-03-21 17:00:21 -0600280 r = bc_vec_item_rev(&p->results, 0);
Gavin Howarde4cdf562018-01-23 13:42:39 -0700281
Gavin Howard27fdfb92018-03-21 07:56:59 -0600282 assert(r);
Gavin Howarda4a72892018-02-27 09:16:10 -0700283
Gavin Howardb09d9b12018-03-23 09:57:07 -0600284 if ((status = bc_program_num(p, r, val, false))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700285
286 *result = r;
287
288 return BC_STATUS_SUCCESS;
289}
290
Gavin Howard3f68df72018-03-22 20:30:27 -0600291BcStatus bc_program_unaryOpRetire(BcProgram *p, BcResult *result,
292 BcResultType type)
Gavin Howard5fb956f2018-03-05 10:57:16 -0700293{
Gavin Howard5fb956f2018-03-05 10:57:16 -0700294 result->type = type;
Gavin Howard0eb2a372018-03-24 09:52:55 -0600295 bc_vec_pop(&p->results);
Gavin Howard0c0d1922018-03-21 17:00:21 -0600296 return bc_vec_push(&p->results, result);
Gavin Howard84095072018-02-27 15:36:58 -0700297}
298
Gavin Howard3f68df72018-03-22 20:30:27 -0600299BcStatus bc_program_op(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700300
301 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600302 BcResult *operand1, *operand2, result;
303 BcNum *num1, *num2;
Gavin Howard101b5e62018-03-26 07:46:27 -0600304 BcNumBinaryFunc op;
Gavin Howard84095072018-02-27 15:36:58 -0700305
Gavin Howard4421cbb2018-03-05 14:06:03 -0700306 status = bc_program_binaryOpPrep(p, &operand1, &num1, &operand2, &num2);
Gavin Howard84095072018-02-27 15:36:58 -0700307 if (status) return status;
308
Gavin Howardb09d9b12018-03-23 09:57:07 -0600309 if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700310
Gavin Howard101b5e62018-03-26 07:46:27 -0600311 op = bc_program_math_ops[inst - BC_INST_POWER];
312 if ((status = op(num1, num2, &result.data.num, p->scale))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700313
Gavin Howard5fb956f2018-03-05 10:57:16 -0700314 status = bc_program_binaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howard84095072018-02-27 15:36:58 -0700315 if (status) goto err;
316
317 return status;
318
319err:
320
321 bc_num_free(&result.data.num);
322
323 return status;
324}
325
Gavin Howard3f68df72018-03-22 20:30:27 -0600326BcStatus bc_program_read(BcProgram *p) {
Gavin Howard84095072018-02-27 15:36:58 -0700327
328 BcStatus status;
329 BcParse parse;
330 char *buffer;
331 size_t size;
332 BcFunc *func;
333 BcInstPtr ip;
334
Gavin Howarda1601ae2018-03-17 19:43:28 -0600335 func = bc_vec_item(&p->funcs, BC_PROGRAM_READ);
Gavin Howardea9a9bd2018-03-21 08:04:07 -0600336 assert(func);
Gavin Howard84095072018-02-27 15:36:58 -0700337 func->code.len = 0;
338
Gavin Howardb09d9b12018-03-23 09:57:07 -0600339 if (!(buffer = malloc(BC_PROGRAM_BUF_SIZE + 1))) return BC_STATUS_MALLOC_FAIL;
Gavin Howard84095072018-02-27 15:36:58 -0700340
341 size = BC_PROGRAM_BUF_SIZE;
342
Gavin Howard81990302018-03-29 21:35:31 -0600343 if ((status = bc_io_getline(&buffer, &size)))goto io_err;
Gavin Howard84095072018-02-27 15:36:58 -0700344
Gavin Howardb09d9b12018-03-23 09:57:07 -0600345 if ((status = bc_parse_init(&parse, p))) goto io_err;
Gavin Howard27fdfb92018-03-21 07:56:59 -0600346 bc_lex_init(&parse.lex, "<stdin>");
Gavin Howard68f2bae2018-03-26 13:02:27 -0600347 if ((status = bc_lex_text(&parse.lex, buffer))) goto exec_err;
Gavin Howard84095072018-02-27 15:36:58 -0700348
Gavin Howardf4167dc2018-03-26 14:19:28 -0600349 if ((status = bc_parse_expr(&parse, &func->code, BC_PARSE_EXPR_NO_READ))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700350
Gavin Howardf4167dc2018-03-26 14:19:28 -0600351 if (parse.lex.token.type != BC_LEX_NEWLINE &&
352 parse.lex.token.type != BC_LEX_EOF)
353 {
354 status = BC_STATUS_EXEC_BAD_READ_EXPR;
Gavin Howard84095072018-02-27 15:36:58 -0700355 goto exec_err;
356 }
357
Gavin Howarda1601ae2018-03-17 19:43:28 -0600358 ip.func = BC_PROGRAM_READ;
Gavin Howard84095072018-02-27 15:36:58 -0700359 ip.idx = 0;
Gavin Howard0c0d1922018-03-21 17:00:21 -0600360 ip.len = p->results.len;
Gavin Howard84095072018-02-27 15:36:58 -0700361
Gavin Howardb09d9b12018-03-23 09:57:07 -0600362 if ((status = bc_vec_push(&p->stack, &ip))) goto exec_err;
363 if ((status = bc_program_exec(p))) goto exec_err;
Gavin Howardceaf64d2018-03-05 11:20:34 -0700364
Gavin Howard0eb2a372018-03-24 09:52:55 -0600365 bc_vec_pop(&p->stack);
Gavin Howardceaf64d2018-03-05 11:20:34 -0700366
Gavin Howard84095072018-02-27 15:36:58 -0700367exec_err:
368
369 bc_parse_free(&parse);
370
371io_err:
372
373 free(buffer);
374
375 return status;
376}
377
Gavin Howard3f68df72018-03-22 20:30:27 -0600378size_t bc_program_index(uint8_t *code, size_t *start) {
Gavin Howard84095072018-02-27 15:36:58 -0700379
Gavin Howard4cf49922018-03-12 17:13:50 -0600380 uint8_t bytes, byte, i;
Gavin Howard84095072018-02-27 15:36:58 -0700381 size_t result;
382
383 bytes = code[(*start)++];
Gavin Howard84095072018-02-27 15:36:58 -0700384 result = 0;
385
Gavin Howard030fd972018-03-13 17:57:09 -0600386 for (i = 0; i < bytes; ++i) {
Gavin Howard84095072018-02-27 15:36:58 -0700387 byte = code[(*start)++];
Gavin Howard389e69e2018-03-13 17:59:27 -0600388 result |= (((size_t) byte) << (i * CHAR_BIT));
Gavin Howard84095072018-02-27 15:36:58 -0700389 }
390
391 return result;
392}
393
Gavin Howard3f68df72018-03-22 20:30:27 -0600394char* bc_program_name(uint8_t *code, size_t *start) {
Gavin Howard84095072018-02-27 15:36:58 -0700395
Gavin Howardb09d9b12018-03-23 09:57:07 -0600396 char byte, *s, *string, *ptr;
397 size_t len, i;
Gavin Howard84095072018-02-27 15:36:58 -0700398
399 string = (char*) (code + *start);
Gavin Howardc2953692018-03-06 21:33:56 -0700400 ptr = strchr((char*) string, ':');
Gavin Howard84095072018-02-27 15:36:58 -0700401
402 if (ptr) len = ((unsigned long) ptr) - ((unsigned long) string);
403 else len = strlen(string);
404
Gavin Howardb09d9b12018-03-23 09:57:07 -0600405 if (!(s = malloc(len + 1))) return NULL;
Gavin Howard84095072018-02-27 15:36:58 -0700406
407 byte = code[(*start)++];
408 i = 0;
409
410 while (byte && byte != ':') {
411 s[i++] = byte;
412 byte = code[(*start)++];
413 }
414
415 s[i] = '\0';
416
417 return s;
418}
419
Gavin Howard3f68df72018-03-22 20:30:27 -0600420BcStatus bc_program_printString(const char *str, size_t *nchars) {
Gavin Howard84095072018-02-27 15:36:58 -0700421
Gavin Howardb09d9b12018-03-23 09:57:07 -0600422 char c, c2;
Gavin Howard4cf49922018-03-12 17:13:50 -0600423 size_t len, i;
Gavin Howard84095072018-02-27 15:36:58 -0700424 int err;
425
Gavin Howard84095072018-02-27 15:36:58 -0700426 len = strlen(str);
427
Gavin Howardbc7cae82018-03-14 13:43:04 -0600428 for (i = 0; i < len; ++i, ++(*nchars)) {
Gavin Howard84095072018-02-27 15:36:58 -0700429
430 c = str[i];
431
Gavin Howarda141a0f2018-03-23 13:16:10 -0600432 if (c != '\\') err = putchar(c);
Gavin Howard84095072018-02-27 15:36:58 -0700433 else {
434
435 ++i;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600436 assert(i < len);
Gavin Howard84095072018-02-27 15:36:58 -0700437 c2 = str[i];
438
439 switch (c2) {
440
441 case 'a':
442 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600443 err = putchar('\a');
Gavin Howard84095072018-02-27 15:36:58 -0700444 break;
445 }
446
447 case 'b':
448 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600449 err = putchar('\b');
Gavin Howard84095072018-02-27 15:36:58 -0700450 break;
451 }
452
453 case 'e':
454 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600455 err = putchar('\\');
Gavin Howard84095072018-02-27 15:36:58 -0700456 break;
457 }
458
459 case 'f':
460 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600461 err = putchar('\f');
Gavin Howard84095072018-02-27 15:36:58 -0700462 break;
463 }
464
465 case 'n':
466 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600467 err = putchar('\n');
Gavin Howardbc7cae82018-03-14 13:43:04 -0600468 *nchars = SIZE_MAX;
Gavin Howard84095072018-02-27 15:36:58 -0700469 break;
470 }
471
472 case 'r':
473 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600474 err = putchar('\r');
Gavin Howard84095072018-02-27 15:36:58 -0700475 break;
476 }
477
478 case 'q':
479 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600480 err = putchar('"');
Gavin Howard84095072018-02-27 15:36:58 -0700481 break;
482 }
483
484 case 't':
485 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600486 err = putchar('\t');
Gavin Howard84095072018-02-27 15:36:58 -0700487 break;
488 }
489
490 default:
491 {
492 // Do nothing.
493 err = 0;
494 break;
495 }
496 }
497 }
498
Gavin Howard16bba752018-03-15 11:28:29 -0600499 if (err == EOF) return BC_STATUS_IO_ERR;
Gavin Howard84095072018-02-27 15:36:58 -0700500 }
501
502 return BC_STATUS_SUCCESS;
503}
504
Gavin Howard3f68df72018-03-22 20:30:27 -0600505BcStatus bc_program_push(BcProgram *p, uint8_t *code, size_t *start, bool var) {
506
Gavin Howard843fa792018-02-27 16:42:52 -0700507 BcStatus status;
508 BcResult result;
Gavin Howard843fa792018-02-27 16:42:52 -0700509
Gavin Howardb09d9b12018-03-23 09:57:07 -0600510 result.data.id.name = bc_program_name(code, start);
Gavin Howard843fa792018-02-27 16:42:52 -0700511
Gavin Howardb09d9b12018-03-23 09:57:07 -0600512 assert(result.data.id.name);
Gavin Howard843fa792018-02-27 16:42:52 -0700513
514 if (var) {
515 result.type = BC_RESULT_VAR;
Gavin Howard0c0d1922018-03-21 17:00:21 -0600516 status = bc_vec_push(&p->results, &result);
Gavin Howard843fa792018-02-27 16:42:52 -0700517 }
518 else {
519
520 BcResult *operand;
521 BcNum *num;
522 unsigned long temp;
523
Gavin Howardb09d9b12018-03-23 09:57:07 -0600524 if ((status = bc_program_unaryOpPrep(p, &operand, &num))) goto err;
525 if ((status = bc_num_ulong(num, &temp))) goto err;
Gavin Howard843fa792018-02-27 16:42:52 -0700526
Gavin Howard0dd566d2018-03-28 19:29:34 -0600527 if (temp > (unsigned long) BC_MAX_DIM) {
Gavin Howardbdb2f922018-03-15 09:25:18 -0600528 status = BC_STATUS_EXEC_ARRAY_LEN;
529 goto err;
530 }
531
Gavin Howard843fa792018-02-27 16:42:52 -0700532 result.data.id.idx = (size_t) temp;
533
Gavin Howardabcc5e02018-03-14 16:02:20 -0600534 status = bc_program_unaryOpRetire(p, &result, BC_RESULT_ARRAY);
Gavin Howard843fa792018-02-27 16:42:52 -0700535 }
536
537 if (status) goto err;
538
539 return status;
540
541err:
542
Gavin Howardb09d9b12018-03-23 09:57:07 -0600543 free(result.data.id.name);
Gavin Howard843fa792018-02-27 16:42:52 -0700544
545 return status;
546}
547
Gavin Howard3f68df72018-03-22 20:30:27 -0600548BcStatus bc_program_negate(BcProgram *p) {
Gavin Howard3a947362018-03-02 11:25:48 -0700549
550 BcStatus status;
551 BcResult result;
552 BcResult *ptr;
553 BcNum *num;
554
Gavin Howardb09d9b12018-03-23 09:57:07 -0600555 if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status;
556 if ((status = bc_num_init(&result.data.num, num->len))) return status;
557 if ((status = bc_num_copy(&result.data.num, num))) goto err;
Gavin Howard3a947362018-03-02 11:25:48 -0700558
Gavin Howarda654f112018-03-03 09:47:34 -0700559 result.data.num.neg = !result.data.num.neg;
560
Gavin Howard5fb956f2018-03-05 10:57:16 -0700561 status = bc_program_unaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howard3a947362018-03-02 11:25:48 -0700562 if (status) goto err;
563
564 return status;
565
566err:
567
568 bc_num_free(&result.data.num);
569
570 return status;
571}
572
Gavin Howard3f68df72018-03-22 20:30:27 -0600573BcStatus bc_program_logical(BcProgram *p, uint8_t inst) {
Gavin Howard843fa792018-02-27 16:42:52 -0700574
575 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600576 BcResult *operand1, *operand2, result;
577 BcNum *num1, *num2;
Gavin Howard843fa792018-02-27 16:42:52 -0700578 BcNumInitFunc init;
579 bool cond;
Gavin Howard5df99ed2018-02-27 16:50:26 -0700580 int cmp;
Gavin Howard843fa792018-02-27 16:42:52 -0700581
582 status = bc_program_binaryOpPrep(p, &operand1, &num1, &operand2, &num2);
Gavin Howard843fa792018-02-27 16:42:52 -0700583 if (status) return status;
584
Gavin Howardb09d9b12018-03-23 09:57:07 -0600585 if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status;
Gavin Howard843fa792018-02-27 16:42:52 -0700586
Gavin Howard101b5e62018-03-26 07:46:27 -0600587 if (inst == BC_INST_BOOL_AND)
Gavin Howard2a064fd2018-03-20 15:56:12 -0600588 cond = bc_num_cmp(num1, &p->zero, NULL) && bc_num_cmp(num2, &p->zero, NULL);
Gavin Howard101b5e62018-03-26 07:46:27 -0600589 else if (inst == BC_INST_BOOL_OR)
Gavin Howard2a064fd2018-03-20 15:56:12 -0600590 cond = bc_num_cmp(num1, &p->zero, NULL) || bc_num_cmp(num2, &p->zero, NULL);
Gavin Howard843fa792018-02-27 16:42:52 -0700591 else {
592
Gavin Howard2a064fd2018-03-20 15:56:12 -0600593 cmp = bc_num_cmp(num1, num2, NULL);
Gavin Howard843fa792018-02-27 16:42:52 -0700594
595 switch (inst) {
Gavin Howard101b5e62018-03-26 07:46:27 -0600596 case BC_INST_REL_EQ:
Gavin Howard843fa792018-02-27 16:42:52 -0700597 {
598 cond = cmp == 0;
599 break;
600 }
601
Gavin Howard101b5e62018-03-26 07:46:27 -0600602 case BC_INST_REL_LE:
Gavin Howard843fa792018-02-27 16:42:52 -0700603 {
604 cond = cmp <= 0;
605 break;
606 }
607
Gavin Howard101b5e62018-03-26 07:46:27 -0600608 case BC_INST_REL_GE:
Gavin Howard843fa792018-02-27 16:42:52 -0700609 {
610 cond = cmp >= 0;
611 break;
612 }
613
Gavin Howard101b5e62018-03-26 07:46:27 -0600614 case BC_INST_REL_NE:
Gavin Howard843fa792018-02-27 16:42:52 -0700615 {
616 cond = cmp != 0;
617 break;
618 }
619
Gavin Howard101b5e62018-03-26 07:46:27 -0600620 case BC_INST_REL_LT:
Gavin Howard843fa792018-02-27 16:42:52 -0700621 {
622 cond = cmp < 0;
623 break;
624 }
625
Gavin Howard101b5e62018-03-26 07:46:27 -0600626 case BC_INST_REL_GT:
Gavin Howard843fa792018-02-27 16:42:52 -0700627 {
628 cond = cmp > 0;
629 break;
630 }
631
632 default:
633 {
Gavin Howardb09d9b12018-03-23 09:57:07 -0600634 // This is here to silence a compiler warning in release mode.
Gavin Howardf955c232018-03-21 08:56:58 -0600635 cond = 0;
Gavin Howard2168fb82018-03-24 10:40:37 -0600636 assert(cond);
Gavin Howard27fdfb92018-03-21 07:56:59 -0600637 break;
Gavin Howard843fa792018-02-27 16:42:52 -0700638 }
639 }
Gavin Howard843fa792018-02-27 16:42:52 -0700640 }
641
Gavin Howard17f66492018-02-27 19:22:18 -0700642 init = cond ? bc_num_one : bc_num_zero;
Gavin Howard843fa792018-02-27 16:42:52 -0700643 init(&result.data.num);
644
Gavin Howard5fb956f2018-03-05 10:57:16 -0700645 status = bc_program_binaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howard843fa792018-02-27 16:42:52 -0700646 if (status) goto err;
647
648 return status;
649
650err:
651
652 bc_num_free(&result.data.num);
653
654 return status;
655}
656
Gavin Howard3f68df72018-03-22 20:30:27 -0600657BcStatus bc_program_assign(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700658
659 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600660 BcResult *left, *right, result;
661 BcNum *lval, *rval;
Gavin Howard101b5e62018-03-26 07:46:27 -0600662 BcNumBinaryFunc op;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600663 unsigned long l, max;
664 size_t *ptr;
Gavin Howard84095072018-02-27 15:36:58 -0700665
666 status = bc_program_binaryOpPrep(p, &left, &lval, &right, &rval);
Gavin Howard84095072018-02-27 15:36:58 -0700667 if (status) return status;
668
669 if (left->type == BC_RESULT_CONSTANT || left->type == BC_RESULT_INTERMEDIATE)
Gavin Howardbdb2f922018-03-15 09:25:18 -0600670 return BC_STATUS_PARSE_BAD_ASSIGN;
Gavin Howard84095072018-02-27 15:36:58 -0700671
Gavin Howard101b5e62018-03-26 07:46:27 -0600672 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(rval, &p->zero, NULL))
Gavin Howard84095072018-02-27 15:36:58 -0700673 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
674
Gavin Howardd5a51e62018-03-26 12:34:27 -0600675 if (inst == BC_INST_ASSIGN) status = bc_num_copy(lval, rval);
676 else {
677 op = bc_program_math_ops[inst - BC_INST_ASSIGN_POWER];
678 status = op(lval, rval, lval, p->scale);
Gavin Howardb8181162018-02-28 12:58:09 -0700679 }
Gavin Howardd5a51e62018-03-26 12:34:27 -0600680
681 if (status) return status;
682
683 if (left->type == BC_RESULT_IBASE || left->type == BC_RESULT_OBASE) {
684
685 ptr = left->type == BC_RESULT_IBASE ? &p->ibase_t : &p->obase_t;
Gavin Howard0dd566d2018-03-28 19:29:34 -0600686 max = left->type == BC_RESULT_IBASE ? BC_NUM_MAX_INPUT_BASE : BC_MAX_BASE;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600687
688 if ((status = bc_num_ulong(lval, &l))) return status;
689
690 if (l < BC_NUM_MIN_BASE || l > max)
691 return left->type - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
692
693 *ptr = (size_t) l;
694 }
695 else if (left->type == BC_RESULT_SCALE) {
696
697 if ((status = bc_num_ulong(lval, &l))) return status;
Gavin Howard0dd566d2018-03-28 19:29:34 -0600698 if (l > (unsigned long) BC_MAX_SCALE) return BC_STATUS_EXEC_BAD_SCALE;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600699
700 p->scale = (size_t) l;
701 }
Gavin Howard84095072018-02-27 15:36:58 -0700702
Gavin Howard9c4358c2018-03-22 20:11:28 -0600703 if ((status = bc_num_init(&result.data.num, lval->len))) return status;
704 if ((status = bc_num_copy(&result.data.num, lval))) goto err;
Gavin Howardb8181162018-02-28 12:58:09 -0700705
Gavin Howard5fb956f2018-03-05 10:57:16 -0700706 status = bc_program_binaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howardb8181162018-02-28 12:58:09 -0700707 if (status) goto err;
708
709 return status;
710
711err:
712
713 bc_num_free(&result.data.num);
714
715 return status;
Gavin Howard84095072018-02-27 15:36:58 -0700716}
717
Gavin Howard3f68df72018-03-22 20:30:27 -0600718BcStatus bc_program_call(BcProgram *p, uint8_t *code, size_t *idx) {
Gavin Howard84095072018-02-27 15:36:58 -0700719
720 BcStatus status;
721 BcInstPtr ip;
Gavin Howard90f13ad2018-03-17 13:32:16 -0600722 size_t nparams, i;
Gavin Howard84095072018-02-27 15:36:58 -0700723 BcFunc *func;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700724 BcAuto *auto_ptr;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600725 BcResult param, *arg;
Gavin Howard84095072018-02-27 15:36:58 -0700726
Gavin Howard53a89332018-03-23 10:32:24 -0600727 status = BC_STATUS_SUCCESS;
Gavin Howard84095072018-02-27 15:36:58 -0700728 nparams = bc_program_index(code, idx);
729
730 ip.idx = 0;
Gavin Howard0c0d1922018-03-21 17:00:21 -0600731 ip.len = p->results.len;
Gavin Howard84095072018-02-27 15:36:58 -0700732 ip.func = bc_program_index(code, idx);
733
734 func = bc_vec_item(&p->funcs, ip.func);
735
Gavin Howardea9a9bd2018-03-21 08:04:07 -0600736 assert(func);
737
738 if (!func->code.len) return BC_STATUS_EXEC_UNDEFINED_FUNC;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600739 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
Gavin Howard84095072018-02-27 15:36:58 -0700740
Gavin Howard3d3f73e2018-03-19 17:51:14 -0600741 for (i = 0; i < nparams; ++i) {
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700742
Gavin Howard3d3f73e2018-03-19 17:51:14 -0600743 auto_ptr = bc_vec_item(&func->autos, i);
Gavin Howard0c0d1922018-03-21 17:00:21 -0600744 arg = bc_vec_item_rev(&p->results, nparams - 1);
Gavin Howardb09d9b12018-03-23 09:57:07 -0600745 assert(auto_ptr && arg);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600746 param.type = auto_ptr->var + BC_RESULT_ARRAY_AUTO;
Gavin Howard57323432018-03-14 20:06:35 -0600747
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700748 if (auto_ptr->var) {
749
Gavin Howardb09d9b12018-03-23 09:57:07 -0600750 BcNum *n;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700751
Gavin Howardb09d9b12018-03-23 09:57:07 -0600752 if ((status = bc_program_num(p, arg, &n, false))) return status;
753 if ((status = bc_num_init(&param.data.num, n->len))) return status;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700754
Gavin Howardb09d9b12018-03-23 09:57:07 -0600755 status = bc_num_copy(&param.data.num, n);
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700756 }
757 else {
758
Gavin Howardb09d9b12018-03-23 09:57:07 -0600759 BcVec *a;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700760
Gavin Howard90f13ad2018-03-17 13:32:16 -0600761 if (arg->type != BC_RESULT_VAR || arg->type != BC_RESULT_ARRAY)
762 return BC_STATUS_EXEC_BAD_TYPE;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700763
Gavin Howardb09d9b12018-03-23 09:57:07 -0600764 status = bc_program_search(p, arg, (BcNum**) &a, BC_PROGRAM_SEARCH_ARRAY);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600765 if (status) return status;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700766
Gavin Howard90f13ad2018-03-17 13:32:16 -0600767 status = bc_vec_init(&param.data.array, sizeof(BcNum), bc_num_free);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600768 if (status) return status;
769
Gavin Howardb09d9b12018-03-23 09:57:07 -0600770 status = bc_array_copy(&param.data.array, a);
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700771 }
772
Gavin Howard90f13ad2018-03-17 13:32:16 -0600773 if (status) goto err;
774
Gavin Howard0c0d1922018-03-21 17:00:21 -0600775 status = bc_vec_push(&p->results, &param);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600776 }
777
778 for (; i < func->autos.len; ++i) {
779
780 auto_ptr = bc_vec_item_rev(&func->autos, i);
Gavin Howardb09d9b12018-03-23 09:57:07 -0600781 assert(auto_ptr);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600782 param.type = auto_ptr->var + BC_RESULT_ARRAY_AUTO;
783
784 if (auto_ptr->var) status = bc_num_init(&param.data.num, BC_NUM_DEF_SIZE);
785 else status = bc_vec_init(&param.data.array, sizeof(BcNum), bc_num_free);
786
787 if (status) return status;
788
Gavin Howard0c0d1922018-03-21 17:00:21 -0600789 status = bc_vec_push(&p->results, &param);
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700790 }
Gavin Howard84095072018-02-27 15:36:58 -0700791
Gavin Howardb09d9b12018-03-23 09:57:07 -0600792 if (status) goto err;
793
Gavin Howard84095072018-02-27 15:36:58 -0700794 return bc_vec_push(&p->stack, &ip);
Gavin Howard57323432018-03-14 20:06:35 -0600795
796err:
797
Gavin Howard90f13ad2018-03-17 13:32:16 -0600798 bc_result_free(&param);
Gavin Howard57323432018-03-14 20:06:35 -0600799
800 return status;
Gavin Howard84095072018-02-27 15:36:58 -0700801}
802
Gavin Howard3f68df72018-03-22 20:30:27 -0600803BcStatus bc_program_return(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700804
805 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600806 BcResult result, *operand;
Gavin Howard84095072018-02-27 15:36:58 -0700807 BcInstPtr *ip;
Gavin Howardc410b0f2018-02-27 16:57:05 -0700808 BcFunc *func;
Gavin Howard84095072018-02-27 15:36:58 -0700809
Gavin Howard27fdfb92018-03-21 07:56:59 -0600810 assert(BC_PROGRAM_CHECK_STACK(p));
Gavin Howard84095072018-02-27 15:36:58 -0700811
812 ip = bc_vec_top(&p->stack);
Gavin Howard27fdfb92018-03-21 07:56:59 -0600813 assert(ip);
Gavin Howard0c0d1922018-03-21 17:00:21 -0600814 assert(BC_PROGRAM_CHECK_RESULTS(p, ip->len + inst == BC_INST_RETURN));
Gavin Howardc410b0f2018-02-27 16:57:05 -0700815 func = bc_vec_item(&p->funcs, ip->func);
Gavin Howard27fdfb92018-03-21 07:56:59 -0600816 assert(func);
Gavin Howardc410b0f2018-02-27 16:57:05 -0700817
Gavin Howard84095072018-02-27 15:36:58 -0700818 result.type = BC_RESULT_INTERMEDIATE;
819
820 if (inst == BC_INST_RETURN) {
821
822 BcNum *num;
823
Gavin Howard0c0d1922018-03-21 17:00:21 -0600824 operand = bc_vec_top(&p->results);
Gavin Howard84095072018-02-27 15:36:58 -0700825
Gavin Howard27fdfb92018-03-21 07:56:59 -0600826 assert(operand);
Gavin Howard84095072018-02-27 15:36:58 -0700827
Gavin Howardb09d9b12018-03-23 09:57:07 -0600828 if ((status = bc_program_num(p, operand, &num, false))) return status;
829 if ((status = bc_num_init(&result.data.num, num->len))) return status;
830 if ((status = bc_num_copy(&result.data.num, num))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700831 }
832 else {
Gavin Howard84095072018-02-27 15:36:58 -0700833 status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE);
Gavin Howard84095072018-02-27 15:36:58 -0700834 if (status) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700835 bc_num_zero(&result.data.num);
836 }
837
Gavin Howardc410b0f2018-02-27 16:57:05 -0700838 // We need to pop arguments as well, so this takes that into account.
Gavin Howard0eb2a372018-03-24 09:52:55 -0600839 bc_vec_npop(&p->results, p->results.len - (ip->len - func->nparams));
Gavin Howardc410b0f2018-02-27 16:57:05 -0700840
Gavin Howardb09d9b12018-03-23 09:57:07 -0600841 if ((status = bc_vec_push(&p->results, &result))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700842
Gavin Howard0eb2a372018-03-24 09:52:55 -0600843 bc_vec_pop(&p->stack);
844
845 return status;
Gavin Howard84095072018-02-27 15:36:58 -0700846
847err:
848
849 bc_num_free(&result.data.num);
850
851 return status;
852}
853
Gavin Howard3f68df72018-03-22 20:30:27 -0600854unsigned long bc_program_scale(BcNum *n) {
Gavin Howard84095072018-02-27 15:36:58 -0700855 return (unsigned long) n->rdx;
856}
857
Gavin Howard3f68df72018-03-22 20:30:27 -0600858unsigned long bc_program_length(BcNum *n) {
Gavin Howard6e2fd062018-03-20 19:34:12 -0600859
Gavin Howard740989f2018-03-20 19:36:06 -0600860 unsigned long len = n->len;
Gavin Howard6e2fd062018-03-20 19:34:12 -0600861
862 if (n->rdx == n->len) {
Gavin Howard740989f2018-03-20 19:36:06 -0600863 size_t i;
Gavin Howard6e2fd062018-03-20 19:34:12 -0600864 for (i = n->len - 1; i < n->len && !n->num[i]; --len, --i);
865 }
866
867 return len;
Gavin Howard84095072018-02-27 15:36:58 -0700868}
869
Gavin Howard3f68df72018-03-22 20:30:27 -0600870BcStatus bc_program_builtin(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700871
872 BcStatus status;
Gavin Howard3aa58d12018-03-05 11:21:18 -0700873 BcResult *operand;
Gavin Howard84095072018-02-27 15:36:58 -0700874 BcNum *num1;
875 BcResult result;
876
Gavin Howardb09d9b12018-03-23 09:57:07 -0600877 if ((status = bc_program_unaryOpPrep(p, &operand, &num1))) return status;
878 if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700879
880 if (inst == BC_INST_SQRT) {
881 status = bc_num_sqrt(num1, &result.data.num, p->scale);
882 }
883 else {
884
Gavin Howard9bb13e22018-02-27 17:01:42 -0700885 BcProgramBuiltInFunc func;
Gavin Howard84095072018-02-27 15:36:58 -0700886 unsigned long ans;
887
888 func = inst == BC_INST_LENGTH ? bc_program_length : bc_program_scale;
Gavin Howard84095072018-02-27 15:36:58 -0700889 ans = func(num1);
890
891 status = bc_num_ulong2num(&result.data.num, ans);
892 }
893
894 if (status) goto err;
895
Gavin Howard5fb956f2018-03-05 10:57:16 -0700896 status = bc_program_unaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howard84095072018-02-27 15:36:58 -0700897 if (status) goto err;
898
899 return status;
900
901err:
902
903 bc_num_free(&result.data.num);
904
905 return status;
906}
907
Gavin Howard3f68df72018-03-22 20:30:27 -0600908BcStatus bc_program_pushScale(BcProgram *p) {
Gavin Howard84095072018-02-27 15:36:58 -0700909
910 BcStatus status;
911 BcResult result;
912
913 result.type = BC_RESULT_SCALE;
Gavin Howard84095072018-02-27 15:36:58 -0700914
Gavin Howardb09d9b12018-03-23 09:57:07 -0600915 if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700916
917 status = bc_num_ulong2num(&result.data.num, (unsigned long) p->scale);
Gavin Howard84095072018-02-27 15:36:58 -0700918 if (status) goto err;
919
Gavin Howardb09d9b12018-03-23 09:57:07 -0600920 if ((status = bc_vec_push(&p->results, &result))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700921
922 return status;
923
924err:
925
926 bc_num_free(&result.data.num);
927
928 return status;
929}
930
Gavin Howard3f68df72018-03-22 20:30:27 -0600931BcStatus bc_program_incdec(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700932
933 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600934 BcResult *ptr, result, copy;
Gavin Howard84095072018-02-27 15:36:58 -0700935 BcNum *num;
Gavin Howard84095072018-02-27 15:36:58 -0700936 uint8_t inst2;
Gavin Howard84095072018-02-27 15:36:58 -0700937
Gavin Howardb09d9b12018-03-23 09:57:07 -0600938 if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700939
Gavin Howard101b5e62018-03-26 07:46:27 -0600940 inst2 = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
941 BC_INST_ASSIGN_PLUS : BC_INST_ASSIGN_MINUS;
Gavin Howard84095072018-02-27 15:36:58 -0700942
Gavin Howard101b5e62018-03-26 07:46:27 -0600943 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
Gavin Howard84095072018-02-27 15:36:58 -0700944 copy.type = BC_RESULT_INTERMEDIATE;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600945 if ((status = bc_num_init(&copy.data.num, num->len))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700946 }
947
948 result.type = BC_RESULT_ONE;
949
Gavin Howardb09d9b12018-03-23 09:57:07 -0600950 if ((status = bc_vec_push(&p->results, &result))) goto err;
951 if ((status = bc_program_assign(p, inst2))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700952
Gavin Howard101b5e62018-03-26 07:46:27 -0600953 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
Gavin Howard0eb2a372018-03-24 09:52:55 -0600954 bc_vec_pop(&p->results);
Gavin Howardb09d9b12018-03-23 09:57:07 -0600955 if ((status = bc_vec_push(&p->results, &copy))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700956 }
957
958 return status;
959
960err:
961
Gavin Howard101b5e62018-03-26 07:46:27 -0600962 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST)
Gavin Howard84095072018-02-27 15:36:58 -0700963 bc_num_free(&copy.data.num);
964
965 return status;
966}
Gavin Howarde723a152018-02-27 15:24:00 -0700967
Gavin Howard8d1f1db2018-02-23 11:29:41 -0700968BcStatus bc_program_init(BcProgram *p) {
Gavin Howard8a596d42018-01-15 15:46:01 -0700969
Gavin Howardd96bcae2018-02-07 19:16:19 -0700970 BcStatus s;
Gavin Howard91072cf2018-02-08 21:07:51 -0700971 size_t idx;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600972 char *main_name, *read_name;
Gavin Howard2534a812018-02-10 15:34:15 -0700973 BcInstPtr ip;
Gavin Howard8a596d42018-01-15 15:46:01 -0700974
Gavin Howard27fdfb92018-03-21 07:56:59 -0600975 assert(p);
Gavin Howard8a596d42018-01-15 15:46:01 -0700976
Gavin Howard0dd566d2018-03-28 19:29:34 -0600977 assert(sysconf(_SC_BC_BASE_MAX) <= BC_MAX_BASE);
978 assert(sysconf(_SC_BC_DIM_MAX) <= BC_MAX_DIM);
979 assert(sysconf(_SC_BC_SCALE_MAX) <= BC_MAX_SCALE);
980 assert(sysconf(_SC_BC_STRING_MAX) <= BC_MAX_STRING);
Gavin Howard57c843e2018-03-28 19:28:08 -0600981
Gavin Howardb09d9b12018-03-23 09:57:07 -0600982 main_name = read_name = NULL;
Gavin Howardbc7cae82018-03-14 13:43:04 -0600983 p->nchars = 0;
Gavin Howard5d74e962018-02-26 13:44:13 -0700984 p->scale = 0;
985
Gavin Howardb09d9b12018-03-23 09:57:07 -0600986 if ((s = bc_num_init(&p->ibase, BC_NUM_DEF_SIZE))) return s;
Gavin Howard5d74e962018-02-26 13:44:13 -0700987 bc_num_ten(&p->ibase);
988 p->ibase_t = 10;
989
Gavin Howardb09d9b12018-03-23 09:57:07 -0600990 if ((s = bc_num_init(&p->obase, BC_NUM_DEF_SIZE))) goto obase_err;
Gavin Howard5d74e962018-02-26 13:44:13 -0700991 bc_num_ten(&p->obase);
992 p->obase_t = 10;
993
Gavin Howardb09d9b12018-03-23 09:57:07 -0600994 if ((s = bc_num_init(&p->last, BC_NUM_DEF_SIZE))) goto last_err;
Gavin Howard43a027f2018-02-26 13:27:10 -0700995 bc_num_zero(&p->last);
Gavin Howardb5c77212018-02-14 17:12:34 -0700996
Gavin Howardb09d9b12018-03-23 09:57:07 -0600997 if ((s = bc_num_init(&p->zero, BC_NUM_DEF_SIZE))) goto zero_err;
Gavin Howard43a027f2018-02-26 13:27:10 -0700998 bc_num_zero(&p->zero);
Gavin Howard5a8949e2018-02-05 16:46:06 -0700999
Gavin Howardb09d9b12018-03-23 09:57:07 -06001000 if ((s = bc_num_init(&p->one, BC_NUM_DEF_SIZE))) goto one_err;
Gavin Howard43a027f2018-02-26 13:27:10 -07001001 bc_num_one(&p->one);
Gavin Howard645200e2018-02-15 15:33:35 -07001002
Gavin Howardb09d9b12018-03-23 09:57:07 -06001003 if ((s = bc_vec_init(&p->funcs, sizeof(BcFunc), bc_func_free))) goto func_err;
Gavin Howard8a596d42018-01-15 15:46:01 -07001004
Gavin Howardd96bcae2018-02-07 19:16:19 -07001005 s = bc_veco_init(&p->func_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001006 if (s) goto func_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001007
Gavin Howardff66e292018-03-28 12:47:58 -06001008 if (!(main_name = malloc(sizeof(bc_lang_func_main)))) {
Gavin Howard91072cf2018-02-08 21:07:51 -07001009 s = BC_STATUS_MALLOC_FAIL;
Gavin Howardd50539a2018-02-08 20:52:57 -07001010 goto name_err;
1011 }
1012
Gavin Howardb09d9b12018-03-23 09:57:07 -06001013 strcpy(main_name, bc_lang_func_main);
1014 s = bc_program_addFunc(p, main_name, &idx);
1015 main_name = NULL;
Gavin Howarda1601ae2018-03-17 19:43:28 -06001016 if (s || idx != BC_PROGRAM_MAIN) goto read_err;
Gavin Howardb42810f2018-03-09 10:07:58 -07001017
Gavin Howardff66e292018-03-28 12:47:58 -06001018 if (!(read_name = malloc(sizeof(bc_lang_func_read)))) {
Gavin Howarded392aa2018-02-27 13:09:26 -07001019 s = BC_STATUS_MALLOC_FAIL;
1020 goto read_err;
1021 }
1022
Gavin Howardf456d372018-03-10 20:11:41 -07001023 strcpy(read_name, bc_lang_func_read);
Gavin Howard859e2902018-03-17 14:23:35 -06001024 s = bc_program_addFunc(p, read_name, &idx);
Gavin Howarded392aa2018-02-27 13:09:26 -07001025 read_name = NULL;
Gavin Howarda1601ae2018-03-17 19:43:28 -06001026 if (s || idx != BC_PROGRAM_READ) goto var_err;
Gavin Howardb42810f2018-03-09 10:07:58 -07001027
Gavin Howardb09d9b12018-03-23 09:57:07 -06001028 if ((s = bc_vec_init(&p->vars, sizeof(BcNum), bc_num_free))) goto var_err;
Gavin Howard8a596d42018-01-15 15:46:01 -07001029
Gavin Howardd96bcae2018-02-07 19:16:19 -07001030 s = bc_veco_init(&p->var_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001031 if (s) goto var_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001032
Gavin Howardb09d9b12018-03-23 09:57:07 -06001033 if ((s = bc_vec_init(&p->arrays, sizeof(BcVec), bc_vec_free))) goto array_err;
Gavin Howard8a596d42018-01-15 15:46:01 -07001034
Gavin Howardd96bcae2018-02-07 19:16:19 -07001035 s = bc_veco_init(&p->array_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001036 if (s) goto array_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001037
1038 s = bc_vec_init(&p->strings, sizeof(char*), bc_string_free);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001039 if (s) goto string_err;
Gavin Howard5a8949e2018-02-05 16:46:06 -07001040
Gavin Howard4dbb65b2018-03-21 19:47:01 -06001041 s = bc_vec_init(&p->constants, sizeof(char*), bc_string_free);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001042 if (s) goto const_err;
Gavin Howarde46c6822018-02-08 20:05:39 -07001043
Gavin Howard0c0d1922018-03-21 17:00:21 -06001044 s = bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001045 if (s) goto expr_err;
Gavin Howard2534a812018-02-10 15:34:15 -07001046
Gavin Howardb09d9b12018-03-23 09:57:07 -06001047 if ((s = bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL))) goto stack_err;
Gavin Howard2534a812018-02-10 15:34:15 -07001048
Gavin Howard0f32a852018-03-28 12:33:17 -06001049 memset(&ip, 0, sizeof(BcInstPtr));
Gavin Howard2534a812018-02-10 15:34:15 -07001050
Gavin Howardb09d9b12018-03-23 09:57:07 -06001051 if ((s = bc_vec_push(&p->stack, &ip))) goto push_err;
Gavin Howardd28e80a2018-01-23 18:24:18 -07001052
Gavin Howardd96bcae2018-02-07 19:16:19 -07001053 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001054
Gavin Howarded392aa2018-02-27 13:09:26 -07001055push_err:
Gavin Howarde4cdf562018-01-23 13:42:39 -07001056
Gavin Howard602178d2018-02-09 12:03:28 -07001057 bc_vec_free(&p->stack);
Gavin Howarde4cdf562018-01-23 13:42:39 -07001058
Gavin Howard2534a812018-02-10 15:34:15 -07001059stack_err:
1060
Gavin Howard0c0d1922018-03-21 17:00:21 -06001061 bc_vec_free(&p->results);
Gavin Howard2534a812018-02-10 15:34:15 -07001062
1063expr_err:
Gavin Howard4dc42662018-01-17 15:17:47 -07001064
Gavin Howarde46c6822018-02-08 20:05:39 -07001065 bc_vec_free(&p->constants);
1066
1067const_err:
1068
Gavin Howard5a8949e2018-02-05 16:46:06 -07001069 bc_vec_free(&p->strings);
1070
1071string_err:
1072
Gavin Howardd96bcae2018-02-07 19:16:19 -07001073 bc_veco_free(&p->array_map);
1074
1075array_map_err:
1076
Gavin Howard23fa3f32018-02-05 14:45:39 -07001077 bc_vec_free(&p->arrays);
Gavin Howard4dc42662018-01-17 15:17:47 -07001078
Gavin Howard8a596d42018-01-15 15:46:01 -07001079array_err:
1080
Gavin Howardd96bcae2018-02-07 19:16:19 -07001081 bc_veco_free(&p->var_map);
1082
1083var_map_err:
1084
Gavin Howard23fa3f32018-02-05 14:45:39 -07001085 bc_vec_free(&p->vars);
Gavin Howard8a596d42018-01-15 15:46:01 -07001086
1087var_err:
1088
Gavin Howarded392aa2018-02-27 13:09:26 -07001089 if (read_name) free(read_name);
1090
1091read_err:
1092
Gavin Howardb09d9b12018-03-23 09:57:07 -06001093 if (main_name) free(main_name);
Gavin Howardd50539a2018-02-08 20:52:57 -07001094
1095name_err:
1096
Gavin Howardd96bcae2018-02-07 19:16:19 -07001097 bc_veco_free(&p->func_map);
1098
1099func_map_err:
1100
Gavin Howard23fa3f32018-02-05 14:45:39 -07001101 bc_vec_free(&p->funcs);
Gavin Howard8a596d42018-01-15 15:46:01 -07001102
1103func_err:
1104
Gavin Howard8389bb22018-02-15 17:40:34 -07001105 bc_num_free(&p->one);
Gavin Howard91072cf2018-02-08 21:07:51 -07001106
Gavin Howardb5c77212018-02-14 17:12:34 -07001107one_err:
Gavin Howard91072cf2018-02-08 21:07:51 -07001108
Gavin Howard8389bb22018-02-15 17:40:34 -07001109 bc_num_free(&p->zero);
Gavin Howardb5c77212018-02-14 17:12:34 -07001110
1111zero_err:
1112
Gavin Howard8389bb22018-02-15 17:40:34 -07001113 bc_num_free(&p->last);
Gavin Howard8a596d42018-01-15 15:46:01 -07001114
Gavin Howard5d74e962018-02-26 13:44:13 -07001115last_err:
1116
1117 bc_num_free(&p->obase);
1118
1119obase_err:
1120
1121 bc_num_free(&p->ibase);
1122
Gavin Howardd96bcae2018-02-07 19:16:19 -07001123 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001124}
1125
Gavin Howard859e2902018-03-17 14:23:35 -06001126BcStatus bc_program_addFunc(BcProgram *p, char *name, size_t *idx) {
Gavin Howard3b90f9f2018-01-17 13:01:33 -07001127
Gavin Howardab67e7c2018-02-09 10:35:44 -07001128 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -06001129 BcEntry entry, *entry_ptr;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001130 BcFunc f;
1131
Gavin Howard27fdfb92018-03-21 07:56:59 -06001132 assert(p && name && idx);
Gavin Howard3b90f9f2018-01-17 13:01:33 -07001133
Gavin Howardab67e7c2018-02-09 10:35:44 -07001134 entry.name = name;
Gavin Howardded20a22018-03-07 15:15:19 -07001135 entry.idx = p->funcs.len;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001136
Gavin Howardb09d9b12018-03-23 09:57:07 -06001137 if ((status = bc_veco_insert(&p->func_map, &entry, idx))) {
Gavin Howardb42810f2018-03-09 10:07:58 -07001138 free(name);
Gavin Howardbdb2f922018-03-15 09:25:18 -06001139 if (status != BC_STATUS_VEC_ITEM_EXISTS) return status;
Gavin Howardb42810f2018-03-09 10:07:58 -07001140 }
Gavin Howardded20a22018-03-07 15:15:19 -07001141
1142 entry_ptr = bc_veco_item(&p->func_map, *idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001143 assert(entry_ptr);
Gavin Howardded20a22018-03-07 15:15:19 -07001144 *idx = entry_ptr->idx;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001145
Gavin Howardbdb2f922018-03-15 09:25:18 -06001146 if (status == BC_STATUS_VEC_ITEM_EXISTS) {
Gavin Howardab67e7c2018-02-09 10:35:44 -07001147
Gavin Howard0ed12322018-03-17 14:21:15 -06001148 BcFunc *func = bc_vec_item(&p->funcs, entry_ptr->idx);
Gavin Howardab67e7c2018-02-09 10:35:44 -07001149
Gavin Howardea9a9bd2018-03-21 08:04:07 -06001150 assert(func);
Gavin Howardab67e7c2018-02-09 10:35:44 -07001151
Gavin Howarded392aa2018-02-27 13:09:26 -07001152 status = BC_STATUS_SUCCESS;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001153
Gavin Howard90f13ad2018-03-17 13:32:16 -06001154 // We need to reset these, so the function can be repopulated.
Gavin Howardb09d9b12018-03-23 09:57:07 -06001155 func->nparams = 0;
Gavin Howard0eb2a372018-03-24 09:52:55 -06001156 bc_vec_npop(&func->autos, func->autos.len);
1157 bc_vec_npop(&func->code, func->code.len);
1158 bc_vec_npop(&func->labels, func->labels.len);
Gavin Howardab67e7c2018-02-09 10:35:44 -07001159 }
Gavin Howardded20a22018-03-07 15:15:19 -07001160 else {
Gavin Howardb09d9b12018-03-23 09:57:07 -06001161 if ((status = bc_func_init(&f))) return status;
Gavin Howardded20a22018-03-07 15:15:19 -07001162 status = bc_vec_push(&p->funcs, &f);
Gavin Howard19470a42018-03-17 14:21:30 -06001163 if (status) bc_func_free(&f);
Gavin Howardded20a22018-03-07 15:15:19 -07001164 }
1165
1166 return status;
Gavin Howard8a596d42018-01-15 15:46:01 -07001167}
1168
Gavin Howardabdc2d32018-03-27 08:01:08 -06001169BcStatus bc_program_reset(BcProgram *p, BcStatus status, bool sig) {
Gavin Howardf4167dc2018-03-26 14:19:28 -06001170
1171 BcFunc *func;
1172 BcInstPtr *ip;
1173
Gavin Howardabdc2d32018-03-27 08:01:08 -06001174 bc_vec_npop(&p->stack, p->stack.len - 1);
1175 bc_vec_npop(&p->results, p->results.len);
1176
Gavin Howardf4167dc2018-03-26 14:19:28 -06001177 func = bc_vec_item(&p->funcs, 0);
1178 assert(func);
1179 ip = bc_vec_top(&p->stack);
1180 assert(ip);
1181
1182 ip->idx = func->code.len;
1183
Gavin Howardabdc2d32018-03-27 08:01:08 -06001184 bcg.sig_int_catches += sig;
1185
1186 if (!status && sig && !bcg.interactive) return BC_STATUS_QUIT;
1187
Gavin Howard46f0e422018-03-27 08:12:00 -06001188 if (!status && bcg.interactive) {
1189 fprintf(stderr, "%s", bc_program_ready_prompt);
1190 fflush(stderr);
1191 }
1192
Gavin Howardabdc2d32018-03-27 08:01:08 -06001193 return status;
Gavin Howardf4167dc2018-03-26 14:19:28 -06001194}
1195
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001196BcStatus bc_program_exec(BcProgram *p) {
Gavin Howard5b5dc572018-01-24 11:57:38 -07001197
Gavin Howard7c8dc772018-02-21 12:12:11 -07001198 BcStatus status;
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001199 uint8_t *code;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001200 size_t idx;
Gavin Howard195706a2018-02-26 17:45:58 -07001201 BcResult result;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001202 BcFunc *func;
Gavin Howard195706a2018-02-26 17:45:58 -07001203 BcInstPtr *ip;
Gavin Howardabdc2d32018-03-27 08:01:08 -06001204 bool cond, sig;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001205
Gavin Howard0a2a6742018-02-27 14:11:26 -07001206 status = BC_STATUS_SUCCESS;
Gavin Howardb8181162018-02-28 12:58:09 -07001207 cond = false;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001208
Gavin Howardb09d9b12018-03-23 09:57:07 -06001209 ip = bc_vec_top(&p->stack);
1210 assert(ip);
1211 func = bc_vec_item(&p->funcs, ip->func);
1212 assert(func);
1213 code = func->code.array;
1214
Gavin Howard2bb7bfc2018-03-28 15:19:45 -06001215 while (!status && !bcg.sig_other && ip->idx < func->code.len) {
Gavin Howard368459a2018-03-28 13:23:51 -06001216
Gavin Howardb09d9b12018-03-23 09:57:07 -06001217 uint8_t inst = code[(ip->idx)++];
Gavin Howard7c8dc772018-02-21 12:12:11 -07001218
Gavin Howard7c8dc772018-02-21 12:12:11 -07001219 switch (inst) {
1220
Gavin Howard195706a2018-02-26 17:45:58 -07001221 case BC_INST_CALL:
1222 {
1223 status = bc_program_call(p, code, &ip->idx);
1224 break;
1225 }
1226
1227 case BC_INST_RETURN:
1228 case BC_INST_RETURN_ZERO:
1229 {
1230 status = bc_program_return(p, inst);
1231 break;
1232 }
1233
Gavin Howard7c8dc772018-02-21 12:12:11 -07001234 case BC_INST_READ:
1235 {
1236 status = bc_program_read(p);
1237 break;
1238 }
1239
Gavin Howard195706a2018-02-26 17:45:58 -07001240 case BC_INST_JUMP_ZERO:
Gavin Howard170fcb02018-02-27 15:27:51 -07001241 {
1242 BcResult *operand;
1243 BcNum *num;
1244
Gavin Howardb09d9b12018-03-23 09:57:07 -06001245 if ((status = bc_program_unaryOpPrep(p, &operand, &num))) return status;
Gavin Howard2a064fd2018-03-20 15:56:12 -06001246 cond = bc_num_cmp(num, &p->zero, NULL) == 0;
Gavin Howard0eb2a372018-03-24 09:52:55 -06001247 bc_vec_pop(&p->results);
Gavin Howard170fcb02018-02-27 15:27:51 -07001248 }
Gavin Howard98d071b2018-03-19 19:36:23 -06001249 // Fallthrough.
Gavin Howard195706a2018-02-26 17:45:58 -07001250 case BC_INST_JUMP:
1251 {
Gavin Howard170fcb02018-02-27 15:27:51 -07001252 size_t idx;
1253 size_t *addr;
1254
1255 idx = bc_program_index(code, &ip->idx);
1256 addr = bc_vec_item(&func->labels, idx);
1257
Gavin Howard27fdfb92018-03-21 07:56:59 -06001258 assert(addr);
Gavin Howard170fcb02018-02-27 15:27:51 -07001259
Gavin Howardb09d9b12018-03-23 09:57:07 -06001260 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
Gavin Howard170fcb02018-02-27 15:27:51 -07001261
Gavin Howard195706a2018-02-26 17:45:58 -07001262 break;
1263 }
1264
1265 case BC_INST_PUSH_VAR:
Gavin Howard101b5e62018-03-26 07:46:27 -06001266 case BC_INST_PUSH_ARRAY_ELEM:
Gavin Howard195706a2018-02-26 17:45:58 -07001267 {
Gavin Howard843fa792018-02-27 16:42:52 -07001268 status = bc_program_push(p, code, &ip->idx, inst == BC_INST_PUSH_VAR);
Gavin Howard195706a2018-02-26 17:45:58 -07001269 break;
1270 }
1271
1272 case BC_INST_PUSH_LAST:
1273 {
1274 result.type = BC_RESULT_LAST;
Gavin Howard0c0d1922018-03-21 17:00:21 -06001275 status = bc_vec_push(&p->results, &result);
Gavin Howard195706a2018-02-26 17:45:58 -07001276 break;
1277 }
1278
1279 case BC_INST_PUSH_SCALE:
1280 {
Gavin Howarda4a72892018-02-27 09:16:10 -07001281 status = bc_program_pushScale(p);
Gavin Howard195706a2018-02-26 17:45:58 -07001282 break;
1283 }
1284
1285 case BC_INST_PUSH_IBASE:
1286 {
1287 result.type = BC_RESULT_IBASE;
Gavin Howard0c0d1922018-03-21 17:00:21 -06001288 status = bc_vec_push(&p->results, &result);
Gavin Howard195706a2018-02-26 17:45:58 -07001289 break;
1290 }
1291
1292 case BC_INST_PUSH_OBASE:
1293 {
1294 result.type = BC_RESULT_OBASE;
Gavin Howard0c0d1922018-03-21 17:00:21 -06001295 status = bc_vec_push(&p->results, &result);
Gavin Howard195706a2018-02-26 17:45:58 -07001296 break;
1297 }
1298
1299 case BC_INST_SCALE_FUNC:
1300 case BC_INST_LENGTH:
1301 case BC_INST_SQRT:
1302 {
1303 status = bc_program_builtin(p, inst);
1304 break;
1305 }
1306
1307 case BC_INST_PUSH_NUM:
1308 {
Gavin Howard195706a2018-02-26 17:45:58 -07001309 result.type = BC_RESULT_CONSTANT;
1310 result.data.id.idx = bc_program_index(code, &ip->idx);
Gavin Howard0c0d1922018-03-21 17:00:21 -06001311 status = bc_vec_push(&p->results, &result);
Gavin Howard195706a2018-02-26 17:45:58 -07001312 break;
1313 }
1314
Gavin Howard5c222e32018-02-28 13:06:41 -07001315 case BC_INST_POP:
1316 {
Gavin Howard0eb2a372018-03-24 09:52:55 -06001317 bc_vec_pop(&p->results);
Gavin Howard5c222e32018-02-28 13:06:41 -07001318 break;
1319 }
1320
Gavin Howard101b5e62018-03-26 07:46:27 -06001321 case BC_INST_INC_POST:
1322 case BC_INST_DEC_POST:
1323 case BC_INST_INC_PRE:
1324 case BC_INST_DEC_PRE:
Gavin Howard195706a2018-02-26 17:45:58 -07001325 {
Gavin Howarde723a152018-02-27 15:24:00 -07001326 status = bc_program_incdec(p, inst);
Gavin Howard195706a2018-02-26 17:45:58 -07001327 break;
1328 }
1329
1330 case BC_INST_HALT:
1331 {
Gavin Howard01d6ec32018-03-17 19:42:02 -06001332 status = BC_STATUS_QUIT;
Gavin Howard195706a2018-02-26 17:45:58 -07001333 break;
1334 }
1335
Gavin Howard7c8dc772018-02-21 12:12:11 -07001336 case BC_INST_PRINT:
Gavin Howard152f3e82018-03-07 12:33:15 -07001337 case BC_INST_PRINT_EXPR:
Gavin Howard7c8dc772018-02-21 12:12:11 -07001338 {
Gavin Howard3aa58d12018-03-05 11:21:18 -07001339 BcResult *operand;
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001340 BcNum *num;
Gavin Howardb09d9b12018-03-23 09:57:07 -06001341 bool newline;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001342
Gavin Howardb09d9b12018-03-23 09:57:07 -06001343 if ((status = bc_program_unaryOpPrep(p, &operand, &num))) return status;
Gavin Howarda883ad92018-02-22 13:34:41 -07001344
Gavin Howardb09d9b12018-03-23 09:57:07 -06001345 newline = inst == BC_INST_PRINT;
1346 status = bc_num_print(num, &p->obase, p->obase_t, newline, &p->nchars);
Gavin Howard534a9802018-02-28 13:06:09 -07001347 if (status) return status;
Gavin Howardc44ce202018-02-21 19:02:02 -07001348
Gavin Howardb09d9b12018-03-23 09:57:07 -06001349 if ((status = bc_num_copy(&p->last, num))) return status;
Gavin Howarde351e9d2018-02-27 09:16:42 -07001350
Gavin Howard0eb2a372018-03-24 09:52:55 -06001351 bc_vec_pop(&p->results);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001352
1353 break;
1354 }
1355
1356 case BC_INST_STR:
1357 {
Gavin Howardb09d9b12018-03-23 09:57:07 -06001358 const char **string, *s;
Gavin Howardbc7cae82018-03-14 13:43:04 -06001359 size_t len;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001360
1361 idx = bc_program_index(code, &ip->idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001362 assert(idx < p->strings.len);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001363 string = bc_vec_item(&p->strings, idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001364 assert(string);
Gavin Howard0271bfc2018-03-14 10:52:48 -06001365
Gavin Howardbc7cae82018-03-14 13:43:04 -06001366 s = *string;
1367 len = strlen(s);
1368
1369 for (idx = 0; idx < len; ++idx) {
1370 char c = s[idx];
Gavin Howarda141a0f2018-03-23 13:16:10 -06001371 if (putchar(c) == EOF) return BC_STATUS_IO_ERR;
Gavin Howardbc7cae82018-03-14 13:43:04 -06001372 if (c == '\n') p->nchars = SIZE_MAX;
1373 ++p->nchars;
1374 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001375
1376 break;
1377 }
1378
1379 case BC_INST_PRINT_STR:
1380 {
Gavin Howarda1ff02f2018-03-07 12:32:25 -07001381 const char **string;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001382
1383 idx = bc_program_index(code, &ip->idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001384 assert(idx < p->strings.len);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001385 string = bc_vec_item(&p->strings, idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001386 assert(string);
Gavin Howarda1ff02f2018-03-07 12:32:25 -07001387
Gavin Howardbc7cae82018-03-14 13:43:04 -06001388 status = bc_program_printString(*string, &p->nchars);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001389
1390 break;
1391 }
1392
Gavin Howard101b5e62018-03-26 07:46:27 -06001393 case BC_INST_POWER:
1394 case BC_INST_MULTIPLY:
1395 case BC_INST_DIVIDE:
1396 case BC_INST_MODULUS:
1397 case BC_INST_PLUS:
1398 case BC_INST_MINUS:
Gavin Howard7c8dc772018-02-21 12:12:11 -07001399 {
1400 status = bc_program_op(p, inst);
1401 break;
1402 }
1403
Gavin Howard101b5e62018-03-26 07:46:27 -06001404 case BC_INST_REL_EQ:
1405 case BC_INST_REL_LE:
1406 case BC_INST_REL_GE:
1407 case BC_INST_REL_NE:
1408 case BC_INST_REL_LT:
1409 case BC_INST_REL_GT:
Gavin Howard195706a2018-02-26 17:45:58 -07001410 {
Gavin Howard2c154002018-02-27 16:43:26 -07001411 status = bc_program_logical(p, inst);
Gavin Howard195706a2018-02-26 17:45:58 -07001412 break;
1413 }
1414
Gavin Howard101b5e62018-03-26 07:46:27 -06001415 case BC_INST_BOOL_NOT:
Gavin Howard195706a2018-02-26 17:45:58 -07001416 {
Gavin Howarde8095352018-02-27 09:17:20 -07001417 BcResult *ptr;
1418 BcNum *num;
1419
Gavin Howardb09d9b12018-03-23 09:57:07 -06001420 if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status;
Gavin Howarde8095352018-02-27 09:17:20 -07001421
Gavin Howarde8095352018-02-27 09:17:20 -07001422 status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE);
Gavin Howarde8095352018-02-27 09:17:20 -07001423 if (status) return status;
1424
Gavin Howard2a064fd2018-03-20 15:56:12 -06001425 if (bc_num_cmp(num, &p->zero, NULL)) bc_num_one(&result.data.num);
Gavin Howarde8095352018-02-27 09:17:20 -07001426 else bc_num_zero(&result.data.num);
1427
Gavin Howard5fb956f2018-03-05 10:57:16 -07001428 status = bc_program_unaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howarde8095352018-02-27 09:17:20 -07001429
1430 if (status) bc_num_free(&result.data.num);
1431
Gavin Howard195706a2018-02-26 17:45:58 -07001432 break;
1433 }
1434
Gavin Howard101b5e62018-03-26 07:46:27 -06001435 case BC_INST_BOOL_OR:
1436 case BC_INST_BOOL_AND:
Gavin Howard195706a2018-02-26 17:45:58 -07001437 {
Gavin Howard2c154002018-02-27 16:43:26 -07001438 status = bc_program_logical(p, inst);
Gavin Howard195706a2018-02-26 17:45:58 -07001439 break;
1440 }
1441
Gavin Howard101b5e62018-03-26 07:46:27 -06001442 case BC_INST_NEG:
Gavin Howard7c8dc772018-02-21 12:12:11 -07001443 {
Gavin Howard3a947362018-03-02 11:25:48 -07001444 status = bc_program_negate(p);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001445 break;
1446 }
1447
Gavin Howard101b5e62018-03-26 07:46:27 -06001448 case BC_INST_ASSIGN_POWER:
1449 case BC_INST_ASSIGN_MULTIPLY:
1450 case BC_INST_ASSIGN_DIVIDE:
1451 case BC_INST_ASSIGN_MODULUS:
1452 case BC_INST_ASSIGN_PLUS:
1453 case BC_INST_ASSIGN_MINUS:
1454 case BC_INST_ASSIGN:
Gavin Howard6d89b5d2018-02-26 13:21:34 -07001455 {
1456 status = bc_program_assign(p, inst);
1457 break;
1458 }
1459
Gavin Howard7c8dc772018-02-21 12:12:11 -07001460 default:
1461 {
Gavin Howard27fdfb92018-03-21 07:56:59 -06001462 assert(false);
Gavin Howardd11c2622018-02-21 21:16:46 -07001463 break;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001464 }
1465 }
Gavin Howard195706a2018-02-26 17:45:58 -07001466
Gavin Howard368459a2018-03-28 13:23:51 -06001467 sig = bcg.sig_int != bcg.sig_int_catches;
1468
Gavin Howarda54cabf2018-03-28 14:50:33 -06001469 if ((status && status != BC_STATUS_QUIT) || sig)
1470 status = bc_program_reset(p, status, sig);
Gavin Howard0a2a6742018-02-27 14:11:26 -07001471
1472 // We keep getting these because if the size of the
Gavin Howard195706a2018-02-26 17:45:58 -07001473 // stack changes, pointers may end up being invalid.
1474 ip = bc_vec_top(&p->stack);
Gavin Howard27fdfb92018-03-21 07:56:59 -06001475 assert(ip);
Gavin Howard0a2a6742018-02-27 14:11:26 -07001476 func = bc_vec_item(&p->funcs, ip->func);
Gavin Howard27fdfb92018-03-21 07:56:59 -06001477 assert(func);
Gavin Howarda1ff02f2018-03-07 12:32:25 -07001478 code = func->code.array;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001479 }
1480
1481 return status;
1482}
1483
Gavin Howard84590c82018-03-28 15:38:44 -06001484void bc_program_free(BcProgram *p) {
1485
1486 if (!p) return;
1487
1488 bc_num_free(&p->ibase);
1489 bc_num_free(&p->obase);
1490
1491 bc_vec_free(&p->funcs);
1492 bc_veco_free(&p->func_map);
1493
1494 bc_vec_free(&p->vars);
1495 bc_veco_free(&p->var_map);
1496
1497 bc_vec_free(&p->arrays);
1498 bc_veco_free(&p->array_map);
1499
1500 bc_vec_free(&p->strings);
1501 bc_vec_free(&p->constants);
1502
1503 bc_vec_free(&p->results);
1504 bc_vec_free(&p->stack);
1505
1506 bc_num_free(&p->last);
1507 bc_num_free(&p->zero);
1508 bc_num_free(&p->one);
1509
1510 memset(p, 0, sizeof(BcProgram));
1511}
1512
1513#ifndef NDEBUG
1514BcStatus bc_program_printIndex(uint8_t *code, size_t *start) {
1515
1516 uint8_t bytes, byte, i;
1517
1518 bytes = code[(*start)++];
1519 byte = 1;
1520
1521 if (printf(bc_program_byte_fmt, bytes) < 0) return BC_STATUS_IO_ERR;
1522
1523 for (i = 0; byte && i < bytes; ++i) {
1524 byte = code[(*start)++];
1525 if (printf(bc_program_byte_fmt, byte) < 0) return BC_STATUS_IO_ERR;
1526 }
1527
1528 return BC_STATUS_SUCCESS;
1529}
1530
1531BcStatus bc_program_printName(uint8_t *code, size_t *start) {
1532
1533 BcStatus status;
1534 char byte;
1535
1536 status = BC_STATUS_SUCCESS;
1537 byte = code[(*start)++];
1538
1539 while (byte && byte != ':') {
1540 if (putchar(byte) == EOF) return BC_STATUS_IO_ERR;
1541 byte = code[(*start)++];
1542 }
1543
1544 assert(byte);
1545
1546 if (putchar(byte) == EOF) status = BC_STATUS_IO_ERR;
1547
1548 return status;
1549}
1550
Gavin Howard67c38522018-02-27 16:00:49 -07001551BcStatus bc_program_print(BcProgram *p) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001552
1553 BcStatus status;
1554 BcFunc *func;
1555 uint8_t *code;
Gavin Howardc0d9f312018-03-07 15:15:00 -07001556 BcInstPtr ip;
1557 size_t i;
Gavin Howardabdc2d32018-03-27 08:01:08 -06001558 bool sig;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001559
Gavin Howard0a2a6742018-02-27 14:11:26 -07001560 status = BC_STATUS_SUCCESS;
1561
Gavin Howard8b3cb5b2018-03-28 15:20:15 -06001562 for (i = 0; !status && !bcg.sig_other && i < p->funcs.len; ++i) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001563
Gavin Howardb09d9b12018-03-23 09:57:07 -06001564 ip.idx = ip.len = 0;
Gavin Howardc0d9f312018-03-07 15:15:00 -07001565 ip.func = i;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001566
Gavin Howardc0d9f312018-03-07 15:15:00 -07001567 func = bc_vec_item(&p->funcs, ip.func);
Gavin Howard27fdfb92018-03-21 07:56:59 -06001568 assert(func);
Gavin Howardc0d9f312018-03-07 15:15:00 -07001569 code = func->code.array;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001570
Gavin Howardc0d9f312018-03-07 15:15:00 -07001571 if (printf("func[%zu]: ", ip.func) < 0) return BC_STATUS_IO_ERR;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001572
Gavin Howardc0d9f312018-03-07 15:15:00 -07001573 while (ip.idx < func->code.len) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001574
Gavin Howardb09d9b12018-03-23 09:57:07 -06001575 uint8_t inst = code[ip.idx++];
Gavin Howard0a2a6742018-02-27 14:11:26 -07001576
Gavin Howardfd797192018-03-26 12:27:01 -06001577 if (putchar(bc_lang_inst_chars[inst]) == EOF) return BC_STATUS_IO_ERR;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001578
Gavin Howard642050e2018-03-26 12:25:45 -06001579 if (inst == BC_INST_PUSH_VAR || inst == BC_INST_PUSH_ARRAY_ELEM) {
1580 if ((status = bc_program_printName(code, &ip.idx))) return status;
1581 }
1582 else if (inst == BC_INST_PUSH_NUM || inst == BC_INST_CALL ||
1583 (inst >= BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
1584 {
1585 if ((status = bc_program_printIndex(code, &ip.idx))) return status;
1586 if (inst == BC_INST_CALL && (status = bc_program_printIndex(code, &ip.idx)))
1587 return status;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001588 }
1589 }
Gavin Howardc0d9f312018-03-07 15:15:00 -07001590
Gavin Howardc0d9f312018-03-07 15:15:00 -07001591 if (putchar('\n') == EOF) status = BC_STATUS_IO_ERR;
Gavin Howard368459a2018-03-28 13:23:51 -06001592
1593 sig = bcg.sig_int != bcg.sig_int_catches;
1594
1595 if (status || sig) status = bc_program_reset(p, status, sig);
Gavin Howard0a2a6742018-02-27 14:11:26 -07001596 }
1597
Gavin Howard0a2a6742018-02-27 14:11:26 -07001598 return status;
1599}
Gavin Howard84590c82018-03-28 15:38:44 -06001600#endif // NDEBUG