blob: d1805d33aa0bd783a29342cce850586346b844b9 [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 Howard13ccc4a2018-02-15 14:09:41 -070031#include <program.h>
32#include <parse.h>
Gavin Howard29493062018-03-20 19:57:37 -060033#include <bc.h>
Gavin Howard8a596d42018-01-15 15:46:01 -070034
Gavin Howard3f68df72018-03-22 20:30:27 -060035BcStatus bc_program_search(BcProgram *p, BcResult *result,
36 BcNum **ret, uint8_t flags)
Gavin Howard3affc802018-02-27 19:57:38 -070037{
38 BcStatus status;
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060039 BcEntry entry, *entry_ptr;
Gavin Howard3affc802018-02-27 19:57:38 -070040 BcVec *vec;
41 BcVecO *veco;
Gavin Howard42d7c6d2018-03-20 14:09:01 -060042 size_t idx, ip_idx;
Gavin Howard57323432018-03-14 20:06:35 -060043 BcAuto *a;
Gavin Howarde3c7c8e2018-03-23 08:15:46 -060044 int var;
Gavin Howard3affc802018-02-27 19:57:38 -070045
Gavin Howard42d7c6d2018-03-20 14:09:01 -060046 for (ip_idx = 0; ip_idx < p->stack.len - 1; ++ip_idx) {
Gavin Howard3affc802018-02-27 19:57:38 -070047
Gavin Howard97eb8562018-03-21 08:04:29 -060048 BcFunc *func;
49 BcInstPtr *ip;
50
51 ip = bc_vec_item_rev(&p->stack, ip_idx);
Gavin Howard3affc802018-02-27 19:57:38 -070052
Gavin Howard27fdfb92018-03-21 07:56:59 -060053 assert(ip);
Gavin Howard3affc802018-02-27 19:57:38 -070054
Gavin Howard42d7c6d2018-03-20 14:09:01 -060055 if (ip->func == BC_PROGRAM_READ || ip->func == BC_PROGRAM_MAIN) continue;
Gavin Howard3affc802018-02-27 19:57:38 -070056
57 func = bc_vec_item(&p->funcs, ip->func);
58
Gavin Howard27fdfb92018-03-21 07:56:59 -060059 assert(func);
Gavin Howard3affc802018-02-27 19:57:38 -070060
Gavin Howard3898d192018-03-14 20:44:33 -060061 for (idx = 0; idx < func->autos.len; ++idx) {
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060062
Gavin Howard3898d192018-03-14 20:44:33 -060063 a = bc_vec_item(&func->autos, idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -060064 assert(a);
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060065
Gavin Howard3898d192018-03-14 20:44:33 -060066 if (!strcmp(a->name, result->data.id.name)) {
Gavin Howard3affc802018-02-27 19:57:38 -070067
Gavin Howard90f13ad2018-03-17 13:32:16 -060068 BcResult *r;
Gavin Howard3898d192018-03-14 20:44:33 -060069 uint8_t cond;
70
71 cond = flags & BC_PROGRAM_SEARCH_VAR;
72
Gavin Howardbdb2f922018-03-15 09:25:18 -060073 if (!a->var != !cond) return BC_STATUS_EXEC_BAD_TYPE;
Gavin Howard3898d192018-03-14 20:44:33 -060074
Gavin Howard0c0d1922018-03-21 17:00:21 -060075 r = bc_vec_item(&p->results, ip->len + idx);
Gavin Howard3898d192018-03-14 20:44:33 -060076
Gavin Howard4b9bb2b2018-03-23 08:11:11 -060077 assert(r);
Gavin Howard3898d192018-03-14 20:44:33 -060078
Gavin Howardb09d9b12018-03-23 09:57:07 -060079 if (cond || flags & BC_PROGRAM_SEARCH_ARRAY) *ret = &r->data.num;
Gavin Howard3898d192018-03-14 20:44:33 -060080 else {
Gavin Howard90f13ad2018-03-17 13:32:16 -060081 status = bc_array_expand(&r->data.array, result->data.id.idx + 1);
Gavin Howard3898d192018-03-14 20:44:33 -060082 if (status) return status;
Gavin Howard90f13ad2018-03-17 13:32:16 -060083 *ret = bc_vec_item(&r->data.array, result->data.id.idx);
Gavin Howard3898d192018-03-14 20:44:33 -060084 }
85
86 return BC_STATUS_SUCCESS;
87 }
Gavin Howard57323432018-03-14 20:06:35 -060088 }
Gavin Howard3affc802018-02-27 19:57:38 -070089 }
90
Gavin Howarde3c7c8e2018-03-23 08:15:46 -060091 var = flags & BC_PROGRAM_SEARCH_VAR;
92 vec = var ? &p->vars : &p->arrays;
93 veco = var ? &p->var_map : &p->array_map;
Gavin Howard3affc802018-02-27 19:57:38 -070094
95 entry.name = result->data.id.name;
96 entry.idx = vec->len;
97
Gavin Howardea932f02018-03-23 09:53:40 -060098 status = bc_veco_insert(veco, &entry, &idx);
Gavin Howard3affc802018-02-27 19:57:38 -070099
Gavin Howardea932f02018-03-23 09:53:40 -0600100 if (status != BC_STATUS_VEC_ITEM_EXISTS) {
Gavin Howard3affc802018-02-27 19:57:38 -0700101
Gavin Howardea932f02018-03-23 09:53:40 -0600102 // We use this because it has a union of BcNum and BcVec.
103 BcResult data;
104 size_t len;
Gavin Howarda1ff02f2018-03-07 12:32:25 -0700105
Gavin Howardea932f02018-03-23 09:53:40 -0600106 if (status) return status;
Gavin Howard3affc802018-02-27 19:57:38 -0700107
Gavin Howardea932f02018-03-23 09:53:40 -0600108 len = strlen(entry.name) + 1;
Gavin Howarda1ff02f2018-03-07 12:32:25 -0700109
Gavin Howardea932f02018-03-23 09:53:40 -0600110 if (!(result->data.id.name = malloc(len))) return BC_STATUS_MALLOC_FAIL;
Gavin Howarda1ff02f2018-03-07 12:32:25 -0700111
Gavin Howardea932f02018-03-23 09:53:40 -0600112 strcpy(result->data.id.name, entry.name);
Gavin Howarda1ff02f2018-03-07 12:32:25 -0700113
Gavin Howardea932f02018-03-23 09:53:40 -0600114 if (flags & BC_PROGRAM_SEARCH_VAR)
115 status = bc_num_init(&data.data.num, BC_NUM_DEF_SIZE);
116 else status = bc_vec_init(&data.data.array, sizeof(BcNum), bc_num_free);
Gavin Howard3affc802018-02-27 19:57:38 -0700117
Gavin Howardea932f02018-03-23 09:53:40 -0600118 if (status) return status;
Gavin Howard3affc802018-02-27 19:57:38 -0700119
Gavin Howardea932f02018-03-23 09:53:40 -0600120 if ((status = bc_vec_push(vec, &data.data))) return status;
Gavin Howard3affc802018-02-27 19:57:38 -0700121 }
Gavin Howard3affc802018-02-27 19:57:38 -0700122
123 entry_ptr = bc_veco_item(veco, idx);
124
Gavin Howard4b9bb2b2018-03-23 08:11:11 -0600125 assert(entry_ptr);
Gavin Howard3affc802018-02-27 19:57:38 -0700126
Gavin Howardb09d9b12018-03-23 09:57:07 -0600127 if (var) {
Gavin Howardf23448c2018-02-27 20:36:24 -0700128 *ret = bc_vec_item(vec, entry_ptr->idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -0600129 assert(*ret);
Gavin Howard3affc802018-02-27 19:57:38 -0700130 }
131 else {
132
Gavin Howard4b9bb2b2018-03-23 08:11:11 -0600133 BcVec *aptr = bc_vec_item(vec, entry_ptr->idx);
Gavin Howard3affc802018-02-27 19:57:38 -0700134
Gavin Howardb09d9b12018-03-23 09:57:07 -0600135 assert(aptr);
Gavin Howard3affc802018-02-27 19:57:38 -0700136
Gavin Howardb09d9b12018-03-23 09:57:07 -0600137 if (flags & BC_PROGRAM_SEARCH_ARRAY) {
Gavin Howardf23448c2018-02-27 20:36:24 -0700138 *ret = (BcNum*) aptr;
139 return BC_STATUS_SUCCESS;
140 }
141
Gavin Howardaaa91402018-02-28 12:31:22 -0700142 status = bc_array_expand(aptr, result->data.id.idx + 1);
Gavin Howardaaa91402018-02-28 12:31:22 -0700143 if (status) return status;
Gavin Howard3affc802018-02-27 19:57:38 -0700144
Gavin Howardf23448c2018-02-27 20:36:24 -0700145 *ret = bc_vec_item(aptr, result->data.id.idx);
Gavin Howard3affc802018-02-27 19:57:38 -0700146 }
147
148 return BC_STATUS_SUCCESS;
149}
150
Gavin Howard3f68df72018-03-22 20:30:27 -0600151BcStatus bc_program_num(BcProgram *p, BcResult *result, BcNum** num, bool hex) {
Gavin Howard84095072018-02-27 15:36:58 -0700152
Gavin Howard4b9bb2b2018-03-23 08:11:11 -0600153 BcStatus status = BC_STATUS_SUCCESS;
Gavin Howard84095072018-02-27 15:36:58 -0700154
155 switch (result->type) {
156
157 case BC_RESULT_INTERMEDIATE:
158 case BC_RESULT_SCALE:
159 {
160 *num = &result->data.num;
161 break;
162 }
163
164 case BC_RESULT_CONSTANT:
165 {
166 char** s;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600167 size_t len, base;
Gavin Howard84095072018-02-27 15:36:58 -0700168
Gavin Howardb09d9b12018-03-23 09:57:07 -0600169 s = bc_vec_item(&p->constants, result->data.id.idx);
Gavin Howard4b9bb2b2018-03-23 08:11:11 -0600170 assert(s);
Gavin Howard84095072018-02-27 15:36:58 -0700171 len = strlen(*s);
172
Gavin Howardb09d9b12018-03-23 09:57:07 -0600173 if ((status = bc_num_init(&result->data.num, len))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700174
Gavin Howardcb3ce022018-03-21 09:13:24 -0600175 base = hex && len == 1 ? BC_NUM_MAX_INPUT_BASE : p->ibase_t;
Gavin Howard84095072018-02-27 15:36:58 -0700176
Gavin Howard5cea43b2018-03-02 11:32:11 -0700177 status = bc_num_parse(&result->data.num, *s, &p->ibase, base);
Gavin Howard84095072018-02-27 15:36:58 -0700178
Gavin Howard9ba6c252018-03-14 01:44:38 -0600179 if (status) {
180 bc_num_free(&result->data.num);
181 return status;
182 }
Gavin Howard84095072018-02-27 15:36:58 -0700183
184 *num = &result->data.num;
185
186 result->type = BC_RESULT_INTERMEDIATE;
187
188 break;
189 }
190
191 case BC_RESULT_VAR:
Gavin Howardabcc5e02018-03-14 16:02:20 -0600192 case BC_RESULT_ARRAY:
Gavin Howard84095072018-02-27 15:36:58 -0700193 {
Gavin Howard92b7ce02018-03-14 20:04:14 -0600194 uint8_t flags = result->type == BC_RESULT_VAR ? BC_PROGRAM_SEARCH_VAR : 0;
Gavin Howarde661b4a2018-02-28 10:53:01 -0700195 status = bc_program_search(p, result, num, flags);
Gavin Howard84095072018-02-27 15:36:58 -0700196 break;
197 }
198
199 case BC_RESULT_LAST:
200 {
201 *num = &p->last;
202 break;
203 }
204
205 case BC_RESULT_IBASE:
206 {
207 *num = &p->ibase;
208 break;
209 }
210
211 case BC_RESULT_OBASE:
212 {
213 *num = &p->obase;
214 break;
215 }
216
217 case BC_RESULT_ONE:
218 {
219 *num = &p->one;
220 break;
221 }
222
223 default:
224 {
Gavin Howardb09d9b12018-03-23 09:57:07 -0600225 // This is here to prevent compiler warnings in release mode.
Gavin Howard2168fb82018-03-24 10:40:37 -0600226 *num = &result->data.num;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600227 assert(false);
Gavin Howard84095072018-02-27 15:36:58 -0700228 break;
229 }
230 }
231
232 return status;
233}
Gavin Howard6d89b5d2018-02-26 13:21:34 -0700234
Gavin Howard3f68df72018-03-22 20:30:27 -0600235BcStatus bc_program_binaryOpPrep(BcProgram *p, BcResult **left, BcNum **lval,
236 BcResult **right, BcNum **rval)
Gavin Howard84095072018-02-27 15:36:58 -0700237{
238 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600239 BcResult *l, *r;
Gavin Howardef1b52e2018-03-20 14:02:57 -0600240 bool hex;
Gavin Howard84095072018-02-27 15:36:58 -0700241
Gavin Howard27fdfb92018-03-21 07:56:59 -0600242 assert(p && left && lval && right && rval &&
Gavin Howard0c0d1922018-03-21 17:00:21 -0600243 BC_PROGRAM_CHECK_RESULTS(p, 2));
Gavin Howard84095072018-02-27 15:36:58 -0700244
Gavin Howard0c0d1922018-03-21 17:00:21 -0600245 r = bc_vec_item_rev(&p->results, 0);
246 l = bc_vec_item_rev(&p->results, 1);
Gavin Howard84095072018-02-27 15:36:58 -0700247
Gavin Howard27fdfb92018-03-21 07:56:59 -0600248 assert(r && l);
Gavin Howard84095072018-02-27 15:36:58 -0700249
Gavin Howard2168fb82018-03-24 10:40:37 -0600250 *left = l;
251 *right = r;
252
Gavin Howardef1b52e2018-03-20 14:02:57 -0600253 hex = l->type == BC_RESULT_IBASE || l->type == BC_RESULT_OBASE;
Gavin Howard84095072018-02-27 15:36:58 -0700254
Gavin Howardb09d9b12018-03-23 09:57:07 -0600255 if ((status = bc_program_num(p, l, lval, false))) return status;
256 if ((status = bc_program_num(p, r, rval, hex))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700257
Gavin Howard84095072018-02-27 15:36:58 -0700258 return BC_STATUS_SUCCESS;
259}
260
Gavin Howard3f68df72018-03-22 20:30:27 -0600261BcStatus bc_program_binaryOpRetire(BcProgram *p, BcResult *result,
262 BcResultType type)
Gavin Howard5fb956f2018-03-05 10:57:16 -0700263{
Gavin Howard5fb956f2018-03-05 10:57:16 -0700264 result->type = type;
265
Gavin Howard0eb2a372018-03-24 09:52:55 -0600266 bc_vec_pop(&p->results);
267 bc_vec_pop(&p->results);
Gavin Howard84095072018-02-27 15:36:58 -0700268
Gavin Howard0c0d1922018-03-21 17:00:21 -0600269 return bc_vec_push(&p->results, result);
Gavin Howard84095072018-02-27 15:36:58 -0700270}
271
Gavin Howard3f68df72018-03-22 20:30:27 -0600272BcStatus bc_program_unaryOpPrep(BcProgram *p, BcResult **result, BcNum **val) {
273
Gavin Howard84095072018-02-27 15:36:58 -0700274 BcStatus status;
275 BcResult *r;
Gavin Howard195706a2018-02-26 17:45:58 -0700276
Gavin Howard0c0d1922018-03-21 17:00:21 -0600277 assert(p && result && val && BC_PROGRAM_CHECK_RESULTS(p, 1));
Gavin Howard195706a2018-02-26 17:45:58 -0700278
Gavin Howard0c0d1922018-03-21 17:00:21 -0600279 r = bc_vec_item_rev(&p->results, 0);
Gavin Howarde4cdf562018-01-23 13:42:39 -0700280
Gavin Howard27fdfb92018-03-21 07:56:59 -0600281 assert(r);
Gavin Howarda4a72892018-02-27 09:16:10 -0700282
Gavin Howardb09d9b12018-03-23 09:57:07 -0600283 if ((status = bc_program_num(p, r, val, false))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700284
285 *result = r;
286
287 return BC_STATUS_SUCCESS;
288}
289
Gavin Howard3f68df72018-03-22 20:30:27 -0600290BcStatus bc_program_unaryOpRetire(BcProgram *p, BcResult *result,
291 BcResultType type)
Gavin Howard5fb956f2018-03-05 10:57:16 -0700292{
Gavin Howard5fb956f2018-03-05 10:57:16 -0700293 result->type = type;
Gavin Howard0eb2a372018-03-24 09:52:55 -0600294 bc_vec_pop(&p->results);
Gavin Howard0c0d1922018-03-21 17:00:21 -0600295 return bc_vec_push(&p->results, result);
Gavin Howard84095072018-02-27 15:36:58 -0700296}
297
Gavin Howard3f68df72018-03-22 20:30:27 -0600298BcStatus bc_program_op(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700299
300 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600301 BcResult *operand1, *operand2, result;
302 BcNum *num1, *num2;
Gavin Howard101b5e62018-03-26 07:46:27 -0600303 BcNumBinaryFunc op;
Gavin Howard84095072018-02-27 15:36:58 -0700304
Gavin Howard4421cbb2018-03-05 14:06:03 -0700305 status = bc_program_binaryOpPrep(p, &operand1, &num1, &operand2, &num2);
Gavin Howard84095072018-02-27 15:36:58 -0700306 if (status) return status;
307
Gavin Howardb09d9b12018-03-23 09:57:07 -0600308 if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700309
Gavin Howard101b5e62018-03-26 07:46:27 -0600310 op = bc_program_math_ops[inst - BC_INST_POWER];
311 if ((status = op(num1, num2, &result.data.num, p->scale))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700312
Gavin Howard5fb956f2018-03-05 10:57:16 -0700313 status = bc_program_binaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howard84095072018-02-27 15:36:58 -0700314 if (status) goto err;
315
316 return status;
317
318err:
319
320 bc_num_free(&result.data.num);
321
322 return status;
323}
324
Gavin Howard3f68df72018-03-22 20:30:27 -0600325BcStatus bc_program_read(BcProgram *p) {
Gavin Howard84095072018-02-27 15:36:58 -0700326
327 BcStatus status;
328 BcParse parse;
329 char *buffer;
330 size_t size;
331 BcFunc *func;
332 BcInstPtr ip;
333
Gavin Howarda1601ae2018-03-17 19:43:28 -0600334 func = bc_vec_item(&p->funcs, BC_PROGRAM_READ);
Gavin Howardea9a9bd2018-03-21 08:04:07 -0600335 assert(func);
Gavin Howard84095072018-02-27 15:36:58 -0700336 func->code.len = 0;
337
Gavin Howardb09d9b12018-03-23 09:57:07 -0600338 if (!(buffer = malloc(BC_PROGRAM_BUF_SIZE + 1))) return BC_STATUS_MALLOC_FAIL;
Gavin Howard84095072018-02-27 15:36:58 -0700339
340 size = BC_PROGRAM_BUF_SIZE;
341
Gavin Howardfc4ef0c2018-03-22 23:00:25 -0600342 if (getline(&buffer, &size, stdin) < 0) {
343 status = BC_STATUS_IO_ERR;
344 goto io_err;
345 }
Gavin Howard84095072018-02-27 15:36:58 -0700346
Gavin Howardb09d9b12018-03-23 09:57:07 -0600347 if ((status = bc_parse_init(&parse, p))) goto io_err;
Gavin Howard27fdfb92018-03-21 07:56:59 -0600348 bc_lex_init(&parse.lex, "<stdin>");
Gavin Howard68f2bae2018-03-26 13:02:27 -0600349 if ((status = bc_lex_text(&parse.lex, buffer))) goto exec_err;
Gavin Howard84095072018-02-27 15:36:58 -0700350
Gavin Howardf4167dc2018-03-26 14:19:28 -0600351 if ((status = bc_parse_expr(&parse, &func->code, BC_PARSE_EXPR_NO_READ))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700352
Gavin Howardf4167dc2018-03-26 14:19:28 -0600353 if (parse.lex.token.type != BC_LEX_NEWLINE &&
354 parse.lex.token.type != BC_LEX_EOF)
355 {
356 status = BC_STATUS_EXEC_BAD_READ_EXPR;
Gavin Howard84095072018-02-27 15:36:58 -0700357 goto exec_err;
358 }
359
Gavin Howarda1601ae2018-03-17 19:43:28 -0600360 ip.func = BC_PROGRAM_READ;
Gavin Howard84095072018-02-27 15:36:58 -0700361 ip.idx = 0;
Gavin Howard0c0d1922018-03-21 17:00:21 -0600362 ip.len = p->results.len;
Gavin Howard84095072018-02-27 15:36:58 -0700363
Gavin Howardb09d9b12018-03-23 09:57:07 -0600364 if ((status = bc_vec_push(&p->stack, &ip))) goto exec_err;
365 if ((status = bc_program_exec(p))) goto exec_err;
Gavin Howardceaf64d2018-03-05 11:20:34 -0700366
Gavin Howard0eb2a372018-03-24 09:52:55 -0600367 bc_vec_pop(&p->stack);
Gavin Howardceaf64d2018-03-05 11:20:34 -0700368
Gavin Howard84095072018-02-27 15:36:58 -0700369exec_err:
370
371 bc_parse_free(&parse);
372
373io_err:
374
375 free(buffer);
376
377 return status;
378}
379
Gavin Howard3f68df72018-03-22 20:30:27 -0600380size_t bc_program_index(uint8_t *code, size_t *start) {
Gavin Howard84095072018-02-27 15:36:58 -0700381
Gavin Howard4cf49922018-03-12 17:13:50 -0600382 uint8_t bytes, byte, i;
Gavin Howard84095072018-02-27 15:36:58 -0700383 size_t result;
384
385 bytes = code[(*start)++];
Gavin Howard84095072018-02-27 15:36:58 -0700386 result = 0;
387
Gavin Howard030fd972018-03-13 17:57:09 -0600388 for (i = 0; i < bytes; ++i) {
Gavin Howard84095072018-02-27 15:36:58 -0700389 byte = code[(*start)++];
Gavin Howard389e69e2018-03-13 17:59:27 -0600390 result |= (((size_t) byte) << (i * CHAR_BIT));
Gavin Howard84095072018-02-27 15:36:58 -0700391 }
392
393 return result;
394}
395
Gavin Howard3f68df72018-03-22 20:30:27 -0600396char* bc_program_name(uint8_t *code, size_t *start) {
Gavin Howard84095072018-02-27 15:36:58 -0700397
Gavin Howardb09d9b12018-03-23 09:57:07 -0600398 char byte, *s, *string, *ptr;
399 size_t len, i;
Gavin Howard84095072018-02-27 15:36:58 -0700400
401 string = (char*) (code + *start);
Gavin Howardc2953692018-03-06 21:33:56 -0700402 ptr = strchr((char*) string, ':');
Gavin Howard84095072018-02-27 15:36:58 -0700403
404 if (ptr) len = ((unsigned long) ptr) - ((unsigned long) string);
405 else len = strlen(string);
406
Gavin Howardb09d9b12018-03-23 09:57:07 -0600407 if (!(s = malloc(len + 1))) return NULL;
Gavin Howard84095072018-02-27 15:36:58 -0700408
409 byte = code[(*start)++];
410 i = 0;
411
412 while (byte && byte != ':') {
413 s[i++] = byte;
414 byte = code[(*start)++];
415 }
416
417 s[i] = '\0';
418
419 return s;
420}
421
Gavin Howard3f68df72018-03-22 20:30:27 -0600422BcStatus bc_program_printIndex(uint8_t *code, size_t *start) {
Gavin Howard84095072018-02-27 15:36:58 -0700423
Gavin Howard4cf49922018-03-12 17:13:50 -0600424 uint8_t bytes, byte, i;
Gavin Howard84095072018-02-27 15:36:58 -0700425
426 bytes = code[(*start)++];
427 byte = 1;
428
Gavin Howardf456d372018-03-10 20:11:41 -0700429 if (printf(bc_program_byte_fmt, bytes) < 0) return BC_STATUS_IO_ERR;
Gavin Howard84095072018-02-27 15:36:58 -0700430
Gavin Howard4cf49922018-03-12 17:13:50 -0600431 for (i = 0; byte && i < bytes; ++i) {
Gavin Howard84095072018-02-27 15:36:58 -0700432 byte = code[(*start)++];
Gavin Howardf456d372018-03-10 20:11:41 -0700433 if (printf(bc_program_byte_fmt, byte) < 0) return BC_STATUS_IO_ERR;
Gavin Howard84095072018-02-27 15:36:58 -0700434 }
435
436 return BC_STATUS_SUCCESS;
437}
438
Gavin Howard3f68df72018-03-22 20:30:27 -0600439BcStatus bc_program_printName(uint8_t *code, size_t *start) {
Gavin Howard84095072018-02-27 15:36:58 -0700440
Gavin Howardc0d9f312018-03-07 15:15:00 -0700441 BcStatus status;
Gavin Howard84095072018-02-27 15:36:58 -0700442 char byte;
443
Gavin Howardc0d9f312018-03-07 15:15:00 -0700444 status = BC_STATUS_SUCCESS;
Gavin Howard84095072018-02-27 15:36:58 -0700445 byte = code[(*start)++];
446
447 while (byte && byte != ':') {
448 if (putchar(byte) == EOF) return BC_STATUS_IO_ERR;
449 byte = code[(*start)++];
450 }
451
Gavin Howard27fdfb92018-03-21 07:56:59 -0600452 assert(byte);
453
454 if (putchar(byte) == EOF) status = BC_STATUS_IO_ERR;
Gavin Howardc0d9f312018-03-07 15:15:00 -0700455
456 return status;
Gavin Howard84095072018-02-27 15:36:58 -0700457}
458
Gavin Howard3f68df72018-03-22 20:30:27 -0600459BcStatus bc_program_printString(const char *str, size_t *nchars) {
Gavin Howard84095072018-02-27 15:36:58 -0700460
Gavin Howardb09d9b12018-03-23 09:57:07 -0600461 char c, c2;
Gavin Howard4cf49922018-03-12 17:13:50 -0600462 size_t len, i;
Gavin Howard84095072018-02-27 15:36:58 -0700463 int err;
464
Gavin Howard84095072018-02-27 15:36:58 -0700465 len = strlen(str);
466
Gavin Howardbc7cae82018-03-14 13:43:04 -0600467 for (i = 0; i < len; ++i, ++(*nchars)) {
Gavin Howard84095072018-02-27 15:36:58 -0700468
469 c = str[i];
470
Gavin Howarda141a0f2018-03-23 13:16:10 -0600471 if (c != '\\') err = putchar(c);
Gavin Howard84095072018-02-27 15:36:58 -0700472 else {
473
474 ++i;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600475 assert(i < len);
Gavin Howard84095072018-02-27 15:36:58 -0700476 c2 = str[i];
477
478 switch (c2) {
479
480 case 'a':
481 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600482 err = putchar('\a');
Gavin Howard84095072018-02-27 15:36:58 -0700483 break;
484 }
485
486 case 'b':
487 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600488 err = putchar('\b');
Gavin Howard84095072018-02-27 15:36:58 -0700489 break;
490 }
491
492 case 'e':
493 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600494 err = putchar('\\');
Gavin Howard84095072018-02-27 15:36:58 -0700495 break;
496 }
497
498 case 'f':
499 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600500 err = putchar('\f');
Gavin Howard84095072018-02-27 15:36:58 -0700501 break;
502 }
503
504 case 'n':
505 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600506 err = putchar('\n');
Gavin Howardbc7cae82018-03-14 13:43:04 -0600507 *nchars = SIZE_MAX;
Gavin Howard84095072018-02-27 15:36:58 -0700508 break;
509 }
510
511 case 'r':
512 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600513 err = putchar('\r');
Gavin Howard84095072018-02-27 15:36:58 -0700514 break;
515 }
516
517 case 'q':
518 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600519 err = putchar('"');
Gavin Howard84095072018-02-27 15:36:58 -0700520 break;
521 }
522
523 case 't':
524 {
Gavin Howarda141a0f2018-03-23 13:16:10 -0600525 err = putchar('\t');
Gavin Howard84095072018-02-27 15:36:58 -0700526 break;
527 }
528
529 default:
530 {
531 // Do nothing.
532 err = 0;
533 break;
534 }
535 }
536 }
537
Gavin Howard16bba752018-03-15 11:28:29 -0600538 if (err == EOF) return BC_STATUS_IO_ERR;
Gavin Howard84095072018-02-27 15:36:58 -0700539 }
540
541 return BC_STATUS_SUCCESS;
542}
543
Gavin Howard3f68df72018-03-22 20:30:27 -0600544BcStatus bc_program_push(BcProgram *p, uint8_t *code, size_t *start, bool var) {
545
Gavin Howard843fa792018-02-27 16:42:52 -0700546 BcStatus status;
547 BcResult result;
Gavin Howard843fa792018-02-27 16:42:52 -0700548
Gavin Howardb09d9b12018-03-23 09:57:07 -0600549 result.data.id.name = bc_program_name(code, start);
Gavin Howard843fa792018-02-27 16:42:52 -0700550
Gavin Howardb09d9b12018-03-23 09:57:07 -0600551 assert(result.data.id.name);
Gavin Howard843fa792018-02-27 16:42:52 -0700552
553 if (var) {
554 result.type = BC_RESULT_VAR;
Gavin Howard0c0d1922018-03-21 17:00:21 -0600555 status = bc_vec_push(&p->results, &result);
Gavin Howard843fa792018-02-27 16:42:52 -0700556 }
557 else {
558
559 BcResult *operand;
560 BcNum *num;
561 unsigned long temp;
562
Gavin Howardb09d9b12018-03-23 09:57:07 -0600563 if ((status = bc_program_unaryOpPrep(p, &operand, &num))) goto err;
564 if ((status = bc_num_ulong(num, &temp))) goto err;
Gavin Howard843fa792018-02-27 16:42:52 -0700565
Gavin Howardbdb2f922018-03-15 09:25:18 -0600566 if (temp > (unsigned long) p->dim_max) {
567 status = BC_STATUS_EXEC_ARRAY_LEN;
568 goto err;
569 }
570
Gavin Howard843fa792018-02-27 16:42:52 -0700571 result.data.id.idx = (size_t) temp;
572
Gavin Howardabcc5e02018-03-14 16:02:20 -0600573 status = bc_program_unaryOpRetire(p, &result, BC_RESULT_ARRAY);
Gavin Howard843fa792018-02-27 16:42:52 -0700574 }
575
576 if (status) goto err;
577
578 return status;
579
580err:
581
Gavin Howardb09d9b12018-03-23 09:57:07 -0600582 free(result.data.id.name);
Gavin Howard843fa792018-02-27 16:42:52 -0700583
584 return status;
585}
586
Gavin Howard3f68df72018-03-22 20:30:27 -0600587BcStatus bc_program_negate(BcProgram *p) {
Gavin Howard3a947362018-03-02 11:25:48 -0700588
589 BcStatus status;
590 BcResult result;
591 BcResult *ptr;
592 BcNum *num;
593
Gavin Howardb09d9b12018-03-23 09:57:07 -0600594 if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status;
595 if ((status = bc_num_init(&result.data.num, num->len))) return status;
596 if ((status = bc_num_copy(&result.data.num, num))) goto err;
Gavin Howard3a947362018-03-02 11:25:48 -0700597
Gavin Howarda654f112018-03-03 09:47:34 -0700598 result.data.num.neg = !result.data.num.neg;
599
Gavin Howard5fb956f2018-03-05 10:57:16 -0700600 status = bc_program_unaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howard3a947362018-03-02 11:25:48 -0700601 if (status) goto err;
602
603 return status;
604
605err:
606
607 bc_num_free(&result.data.num);
608
609 return status;
610}
611
Gavin Howard3f68df72018-03-22 20:30:27 -0600612BcStatus bc_program_logical(BcProgram *p, uint8_t inst) {
Gavin Howard843fa792018-02-27 16:42:52 -0700613
614 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600615 BcResult *operand1, *operand2, result;
616 BcNum *num1, *num2;
Gavin Howard843fa792018-02-27 16:42:52 -0700617 BcNumInitFunc init;
618 bool cond;
Gavin Howard5df99ed2018-02-27 16:50:26 -0700619 int cmp;
Gavin Howard843fa792018-02-27 16:42:52 -0700620
621 status = bc_program_binaryOpPrep(p, &operand1, &num1, &operand2, &num2);
Gavin Howard843fa792018-02-27 16:42:52 -0700622 if (status) return status;
623
Gavin Howardb09d9b12018-03-23 09:57:07 -0600624 if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status;
Gavin Howard843fa792018-02-27 16:42:52 -0700625
Gavin Howard101b5e62018-03-26 07:46:27 -0600626 if (inst == BC_INST_BOOL_AND)
Gavin Howard2a064fd2018-03-20 15:56:12 -0600627 cond = bc_num_cmp(num1, &p->zero, NULL) && bc_num_cmp(num2, &p->zero, NULL);
Gavin Howard101b5e62018-03-26 07:46:27 -0600628 else if (inst == BC_INST_BOOL_OR)
Gavin Howard2a064fd2018-03-20 15:56:12 -0600629 cond = bc_num_cmp(num1, &p->zero, NULL) || bc_num_cmp(num2, &p->zero, NULL);
Gavin Howard843fa792018-02-27 16:42:52 -0700630 else {
631
Gavin Howard2a064fd2018-03-20 15:56:12 -0600632 cmp = bc_num_cmp(num1, num2, NULL);
Gavin Howard843fa792018-02-27 16:42:52 -0700633
634 switch (inst) {
Gavin Howard101b5e62018-03-26 07:46:27 -0600635 case BC_INST_REL_EQ:
Gavin Howard843fa792018-02-27 16:42:52 -0700636 {
637 cond = cmp == 0;
638 break;
639 }
640
Gavin Howard101b5e62018-03-26 07:46:27 -0600641 case BC_INST_REL_LE:
Gavin Howard843fa792018-02-27 16:42:52 -0700642 {
643 cond = cmp <= 0;
644 break;
645 }
646
Gavin Howard101b5e62018-03-26 07:46:27 -0600647 case BC_INST_REL_GE:
Gavin Howard843fa792018-02-27 16:42:52 -0700648 {
649 cond = cmp >= 0;
650 break;
651 }
652
Gavin Howard101b5e62018-03-26 07:46:27 -0600653 case BC_INST_REL_NE:
Gavin Howard843fa792018-02-27 16:42:52 -0700654 {
655 cond = cmp != 0;
656 break;
657 }
658
Gavin Howard101b5e62018-03-26 07:46:27 -0600659 case BC_INST_REL_LT:
Gavin Howard843fa792018-02-27 16:42:52 -0700660 {
661 cond = cmp < 0;
662 break;
663 }
664
Gavin Howard101b5e62018-03-26 07:46:27 -0600665 case BC_INST_REL_GT:
Gavin Howard843fa792018-02-27 16:42:52 -0700666 {
667 cond = cmp > 0;
668 break;
669 }
670
671 default:
672 {
Gavin Howardb09d9b12018-03-23 09:57:07 -0600673 // This is here to silence a compiler warning in release mode.
Gavin Howardf955c232018-03-21 08:56:58 -0600674 cond = 0;
Gavin Howard2168fb82018-03-24 10:40:37 -0600675 assert(cond);
Gavin Howard27fdfb92018-03-21 07:56:59 -0600676 break;
Gavin Howard843fa792018-02-27 16:42:52 -0700677 }
678 }
Gavin Howard843fa792018-02-27 16:42:52 -0700679 }
680
Gavin Howard17f66492018-02-27 19:22:18 -0700681 init = cond ? bc_num_one : bc_num_zero;
Gavin Howard843fa792018-02-27 16:42:52 -0700682 init(&result.data.num);
683
Gavin Howard5fb956f2018-03-05 10:57:16 -0700684 status = bc_program_binaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howard843fa792018-02-27 16:42:52 -0700685 if (status) goto err;
686
687 return status;
688
689err:
690
691 bc_num_free(&result.data.num);
692
693 return status;
694}
695
Gavin Howard3f68df72018-03-22 20:30:27 -0600696BcStatus bc_program_assign(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700697
698 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600699 BcResult *left, *right, result;
700 BcNum *lval, *rval;
Gavin Howard101b5e62018-03-26 07:46:27 -0600701 BcNumBinaryFunc op;
Gavin Howardd5a51e62018-03-26 12:34:27 -0600702 unsigned long l, max;
703 size_t *ptr;
Gavin Howard84095072018-02-27 15:36:58 -0700704
705 status = bc_program_binaryOpPrep(p, &left, &lval, &right, &rval);
Gavin Howard84095072018-02-27 15:36:58 -0700706 if (status) return status;
707
708 if (left->type == BC_RESULT_CONSTANT || left->type == BC_RESULT_INTERMEDIATE)
Gavin Howardbdb2f922018-03-15 09:25:18 -0600709 return BC_STATUS_PARSE_BAD_ASSIGN;
Gavin Howard84095072018-02-27 15:36:58 -0700710
Gavin Howard101b5e62018-03-26 07:46:27 -0600711 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(rval, &p->zero, NULL))
Gavin Howard84095072018-02-27 15:36:58 -0700712 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
713
Gavin Howardd5a51e62018-03-26 12:34:27 -0600714 if (inst == BC_INST_ASSIGN) status = bc_num_copy(lval, rval);
715 else {
716 op = bc_program_math_ops[inst - BC_INST_ASSIGN_POWER];
717 status = op(lval, rval, lval, p->scale);
Gavin Howardb8181162018-02-28 12:58:09 -0700718 }
Gavin Howardd5a51e62018-03-26 12:34:27 -0600719
720 if (status) return status;
721
722 if (left->type == BC_RESULT_IBASE || left->type == BC_RESULT_OBASE) {
723
724 ptr = left->type == BC_RESULT_IBASE ? &p->ibase_t : &p->obase_t;
725 max = left->type == BC_RESULT_IBASE ? BC_NUM_MAX_INPUT_BASE : p->base_max;
726
727 if ((status = bc_num_ulong(lval, &l))) return status;
728
729 if (l < BC_NUM_MIN_BASE || l > max)
730 return left->type - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
731
732 *ptr = (size_t) l;
733 }
734 else if (left->type == BC_RESULT_SCALE) {
735
736 if ((status = bc_num_ulong(lval, &l))) return status;
737 if (l > (unsigned long) p->scale_max) return BC_STATUS_EXEC_BAD_SCALE;
738
739 p->scale = (size_t) l;
740 }
Gavin Howard84095072018-02-27 15:36:58 -0700741
Gavin Howard9c4358c2018-03-22 20:11:28 -0600742 if ((status = bc_num_init(&result.data.num, lval->len))) return status;
743 if ((status = bc_num_copy(&result.data.num, lval))) goto err;
Gavin Howardb8181162018-02-28 12:58:09 -0700744
Gavin Howard5fb956f2018-03-05 10:57:16 -0700745 status = bc_program_binaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howardb8181162018-02-28 12:58:09 -0700746 if (status) goto err;
747
748 return status;
749
750err:
751
752 bc_num_free(&result.data.num);
753
754 return status;
Gavin Howard84095072018-02-27 15:36:58 -0700755}
756
Gavin Howard3f68df72018-03-22 20:30:27 -0600757BcStatus bc_program_call(BcProgram *p, uint8_t *code, size_t *idx) {
Gavin Howard84095072018-02-27 15:36:58 -0700758
759 BcStatus status;
760 BcInstPtr ip;
Gavin Howard90f13ad2018-03-17 13:32:16 -0600761 size_t nparams, i;
Gavin Howard84095072018-02-27 15:36:58 -0700762 BcFunc *func;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700763 BcAuto *auto_ptr;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600764 BcResult param, *arg;
Gavin Howard84095072018-02-27 15:36:58 -0700765
Gavin Howard53a89332018-03-23 10:32:24 -0600766 status = BC_STATUS_SUCCESS;
Gavin Howard84095072018-02-27 15:36:58 -0700767 nparams = bc_program_index(code, idx);
768
769 ip.idx = 0;
Gavin Howard0c0d1922018-03-21 17:00:21 -0600770 ip.len = p->results.len;
Gavin Howard84095072018-02-27 15:36:58 -0700771 ip.func = bc_program_index(code, idx);
772
773 func = bc_vec_item(&p->funcs, ip.func);
774
Gavin Howardea9a9bd2018-03-21 08:04:07 -0600775 assert(func);
776
777 if (!func->code.len) return BC_STATUS_EXEC_UNDEFINED_FUNC;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600778 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
Gavin Howard84095072018-02-27 15:36:58 -0700779
Gavin Howard3d3f73e2018-03-19 17:51:14 -0600780 for (i = 0; i < nparams; ++i) {
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700781
Gavin Howard3d3f73e2018-03-19 17:51:14 -0600782 auto_ptr = bc_vec_item(&func->autos, i);
Gavin Howard0c0d1922018-03-21 17:00:21 -0600783 arg = bc_vec_item_rev(&p->results, nparams - 1);
Gavin Howardb09d9b12018-03-23 09:57:07 -0600784 assert(auto_ptr && arg);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600785 param.type = auto_ptr->var + BC_RESULT_ARRAY_AUTO;
Gavin Howard57323432018-03-14 20:06:35 -0600786
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700787 if (auto_ptr->var) {
788
Gavin Howardb09d9b12018-03-23 09:57:07 -0600789 BcNum *n;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700790
Gavin Howardb09d9b12018-03-23 09:57:07 -0600791 if ((status = bc_program_num(p, arg, &n, false))) return status;
792 if ((status = bc_num_init(&param.data.num, n->len))) return status;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700793
Gavin Howardb09d9b12018-03-23 09:57:07 -0600794 status = bc_num_copy(&param.data.num, n);
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700795 }
796 else {
797
Gavin Howardb09d9b12018-03-23 09:57:07 -0600798 BcVec *a;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700799
Gavin Howard90f13ad2018-03-17 13:32:16 -0600800 if (arg->type != BC_RESULT_VAR || arg->type != BC_RESULT_ARRAY)
801 return BC_STATUS_EXEC_BAD_TYPE;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700802
Gavin Howardb09d9b12018-03-23 09:57:07 -0600803 status = bc_program_search(p, arg, (BcNum**) &a, BC_PROGRAM_SEARCH_ARRAY);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600804 if (status) return status;
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700805
Gavin Howard90f13ad2018-03-17 13:32:16 -0600806 status = bc_vec_init(&param.data.array, sizeof(BcNum), bc_num_free);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600807 if (status) return status;
808
Gavin Howardb09d9b12018-03-23 09:57:07 -0600809 status = bc_array_copy(&param.data.array, a);
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700810 }
811
Gavin Howard90f13ad2018-03-17 13:32:16 -0600812 if (status) goto err;
813
Gavin Howard0c0d1922018-03-21 17:00:21 -0600814 status = bc_vec_push(&p->results, &param);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600815 }
816
817 for (; i < func->autos.len; ++i) {
818
819 auto_ptr = bc_vec_item_rev(&func->autos, i);
Gavin Howardb09d9b12018-03-23 09:57:07 -0600820 assert(auto_ptr);
Gavin Howard90f13ad2018-03-17 13:32:16 -0600821 param.type = auto_ptr->var + BC_RESULT_ARRAY_AUTO;
822
823 if (auto_ptr->var) status = bc_num_init(&param.data.num, BC_NUM_DEF_SIZE);
824 else status = bc_vec_init(&param.data.array, sizeof(BcNum), bc_num_free);
825
826 if (status) return status;
827
Gavin Howard0c0d1922018-03-21 17:00:21 -0600828 status = bc_vec_push(&p->results, &param);
Gavin Howardd6e3b7b2018-02-28 12:31:58 -0700829 }
Gavin Howard84095072018-02-27 15:36:58 -0700830
Gavin Howardb09d9b12018-03-23 09:57:07 -0600831 if (status) goto err;
832
Gavin Howard84095072018-02-27 15:36:58 -0700833 return bc_vec_push(&p->stack, &ip);
Gavin Howard57323432018-03-14 20:06:35 -0600834
835err:
836
Gavin Howard90f13ad2018-03-17 13:32:16 -0600837 bc_result_free(&param);
Gavin Howard57323432018-03-14 20:06:35 -0600838
839 return status;
Gavin Howard84095072018-02-27 15:36:58 -0700840}
841
Gavin Howard3f68df72018-03-22 20:30:27 -0600842BcStatus bc_program_return(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700843
844 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600845 BcResult result, *operand;
Gavin Howard84095072018-02-27 15:36:58 -0700846 BcInstPtr *ip;
Gavin Howardc410b0f2018-02-27 16:57:05 -0700847 BcFunc *func;
Gavin Howard84095072018-02-27 15:36:58 -0700848
Gavin Howard27fdfb92018-03-21 07:56:59 -0600849 assert(BC_PROGRAM_CHECK_STACK(p));
Gavin Howard84095072018-02-27 15:36:58 -0700850
851 ip = bc_vec_top(&p->stack);
Gavin Howard27fdfb92018-03-21 07:56:59 -0600852 assert(ip);
Gavin Howard0c0d1922018-03-21 17:00:21 -0600853 assert(BC_PROGRAM_CHECK_RESULTS(p, ip->len + inst == BC_INST_RETURN));
Gavin Howardc410b0f2018-02-27 16:57:05 -0700854 func = bc_vec_item(&p->funcs, ip->func);
Gavin Howard27fdfb92018-03-21 07:56:59 -0600855 assert(func);
Gavin Howardc410b0f2018-02-27 16:57:05 -0700856
Gavin Howard84095072018-02-27 15:36:58 -0700857 result.type = BC_RESULT_INTERMEDIATE;
858
859 if (inst == BC_INST_RETURN) {
860
861 BcNum *num;
862
Gavin Howard0c0d1922018-03-21 17:00:21 -0600863 operand = bc_vec_top(&p->results);
Gavin Howard84095072018-02-27 15:36:58 -0700864
Gavin Howard27fdfb92018-03-21 07:56:59 -0600865 assert(operand);
Gavin Howard84095072018-02-27 15:36:58 -0700866
Gavin Howardb09d9b12018-03-23 09:57:07 -0600867 if ((status = bc_program_num(p, operand, &num, false))) return status;
868 if ((status = bc_num_init(&result.data.num, num->len))) return status;
869 if ((status = bc_num_copy(&result.data.num, num))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700870 }
871 else {
Gavin Howard84095072018-02-27 15:36:58 -0700872 status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE);
Gavin Howard84095072018-02-27 15:36:58 -0700873 if (status) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700874 bc_num_zero(&result.data.num);
875 }
876
Gavin Howardc410b0f2018-02-27 16:57:05 -0700877 // We need to pop arguments as well, so this takes that into account.
Gavin Howard0eb2a372018-03-24 09:52:55 -0600878 bc_vec_npop(&p->results, p->results.len - (ip->len - func->nparams));
Gavin Howardc410b0f2018-02-27 16:57:05 -0700879
Gavin Howardb09d9b12018-03-23 09:57:07 -0600880 if ((status = bc_vec_push(&p->results, &result))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700881
Gavin Howard0eb2a372018-03-24 09:52:55 -0600882 bc_vec_pop(&p->stack);
883
884 return status;
Gavin Howard84095072018-02-27 15:36:58 -0700885
886err:
887
888 bc_num_free(&result.data.num);
889
890 return status;
891}
892
Gavin Howard3f68df72018-03-22 20:30:27 -0600893unsigned long bc_program_scale(BcNum *n) {
Gavin Howard84095072018-02-27 15:36:58 -0700894 return (unsigned long) n->rdx;
895}
896
Gavin Howard3f68df72018-03-22 20:30:27 -0600897unsigned long bc_program_length(BcNum *n) {
Gavin Howard6e2fd062018-03-20 19:34:12 -0600898
Gavin Howard740989f2018-03-20 19:36:06 -0600899 unsigned long len = n->len;
Gavin Howard6e2fd062018-03-20 19:34:12 -0600900
901 if (n->rdx == n->len) {
Gavin Howard740989f2018-03-20 19:36:06 -0600902 size_t i;
Gavin Howard6e2fd062018-03-20 19:34:12 -0600903 for (i = n->len - 1; i < n->len && !n->num[i]; --len, --i);
904 }
905
906 return len;
Gavin Howard84095072018-02-27 15:36:58 -0700907}
908
Gavin Howard3f68df72018-03-22 20:30:27 -0600909BcStatus bc_program_builtin(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700910
911 BcStatus status;
Gavin Howard3aa58d12018-03-05 11:21:18 -0700912 BcResult *operand;
Gavin Howard84095072018-02-27 15:36:58 -0700913 BcNum *num1;
914 BcResult result;
915
Gavin Howardb09d9b12018-03-23 09:57:07 -0600916 if ((status = bc_program_unaryOpPrep(p, &operand, &num1))) return status;
917 if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700918
919 if (inst == BC_INST_SQRT) {
920 status = bc_num_sqrt(num1, &result.data.num, p->scale);
921 }
922 else {
923
Gavin Howard9bb13e22018-02-27 17:01:42 -0700924 BcProgramBuiltInFunc func;
Gavin Howard84095072018-02-27 15:36:58 -0700925 unsigned long ans;
926
927 func = inst == BC_INST_LENGTH ? bc_program_length : bc_program_scale;
Gavin Howard84095072018-02-27 15:36:58 -0700928 ans = func(num1);
929
930 status = bc_num_ulong2num(&result.data.num, ans);
931 }
932
933 if (status) goto err;
934
Gavin Howard5fb956f2018-03-05 10:57:16 -0700935 status = bc_program_unaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howard84095072018-02-27 15:36:58 -0700936 if (status) goto err;
937
938 return status;
939
940err:
941
942 bc_num_free(&result.data.num);
943
944 return status;
945}
946
Gavin Howard3f68df72018-03-22 20:30:27 -0600947BcStatus bc_program_pushScale(BcProgram *p) {
Gavin Howard84095072018-02-27 15:36:58 -0700948
949 BcStatus status;
950 BcResult result;
951
952 result.type = BC_RESULT_SCALE;
Gavin Howard84095072018-02-27 15:36:58 -0700953
Gavin Howardb09d9b12018-03-23 09:57:07 -0600954 if ((status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700955
956 status = bc_num_ulong2num(&result.data.num, (unsigned long) p->scale);
Gavin Howard84095072018-02-27 15:36:58 -0700957 if (status) goto err;
958
Gavin Howardb09d9b12018-03-23 09:57:07 -0600959 if ((status = bc_vec_push(&p->results, &result))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700960
961 return status;
962
963err:
964
965 bc_num_free(&result.data.num);
966
967 return status;
968}
969
Gavin Howard3f68df72018-03-22 20:30:27 -0600970BcStatus bc_program_incdec(BcProgram *p, uint8_t inst) {
Gavin Howard84095072018-02-27 15:36:58 -0700971
972 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600973 BcResult *ptr, result, copy;
Gavin Howard84095072018-02-27 15:36:58 -0700974 BcNum *num;
Gavin Howard84095072018-02-27 15:36:58 -0700975 uint8_t inst2;
Gavin Howard84095072018-02-27 15:36:58 -0700976
Gavin Howardb09d9b12018-03-23 09:57:07 -0600977 if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700978
Gavin Howard101b5e62018-03-26 07:46:27 -0600979 inst2 = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
980 BC_INST_ASSIGN_PLUS : BC_INST_ASSIGN_MINUS;
Gavin Howard84095072018-02-27 15:36:58 -0700981
Gavin Howard101b5e62018-03-26 07:46:27 -0600982 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
Gavin Howard84095072018-02-27 15:36:58 -0700983 copy.type = BC_RESULT_INTERMEDIATE;
Gavin Howardb09d9b12018-03-23 09:57:07 -0600984 if ((status = bc_num_init(&copy.data.num, num->len))) return status;
Gavin Howard84095072018-02-27 15:36:58 -0700985 }
986
987 result.type = BC_RESULT_ONE;
988
Gavin Howardb09d9b12018-03-23 09:57:07 -0600989 if ((status = bc_vec_push(&p->results, &result))) goto err;
990 if ((status = bc_program_assign(p, inst2))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700991
Gavin Howard101b5e62018-03-26 07:46:27 -0600992 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
Gavin Howard0eb2a372018-03-24 09:52:55 -0600993 bc_vec_pop(&p->results);
Gavin Howardb09d9b12018-03-23 09:57:07 -0600994 if ((status = bc_vec_push(&p->results, &copy))) goto err;
Gavin Howard84095072018-02-27 15:36:58 -0700995 }
996
997 return status;
998
999err:
1000
Gavin Howard101b5e62018-03-26 07:46:27 -06001001 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST)
Gavin Howard84095072018-02-27 15:36:58 -07001002 bc_num_free(&copy.data.num);
1003
1004 return status;
1005}
Gavin Howarde723a152018-02-27 15:24:00 -07001006
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001007BcStatus bc_program_init(BcProgram *p) {
Gavin Howard8a596d42018-01-15 15:46:01 -07001008
Gavin Howardd96bcae2018-02-07 19:16:19 -07001009 BcStatus s;
Gavin Howard91072cf2018-02-08 21:07:51 -07001010 size_t idx;
Gavin Howardb09d9b12018-03-23 09:57:07 -06001011 char *main_name, *read_name;
Gavin Howard2534a812018-02-10 15:34:15 -07001012 BcInstPtr ip;
Gavin Howard8a596d42018-01-15 15:46:01 -07001013
Gavin Howard27fdfb92018-03-21 07:56:59 -06001014 assert(p);
Gavin Howard8a596d42018-01-15 15:46:01 -07001015
Gavin Howardb09d9b12018-03-23 09:57:07 -06001016 main_name = read_name = NULL;
Gavin Howardbc7cae82018-03-14 13:43:04 -06001017 p->nchars = 0;
1018
Gavin Howard6fc77692018-01-24 18:05:21 -07001019#ifdef _POSIX_BC_BASE_MAX
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001020 p->base_max = _POSIX_BC_BASE_MAX;
Gavin Howard6fc77692018-01-24 18:05:21 -07001021#elif defined(_BC_BASE_MAX)
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001022 p->base_max = _BC_BASE_MAX;
Gavin Howard6fc77692018-01-24 18:05:21 -07001023#else
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001024 p->base_max = sysconf(_SC_BC_BASE_MAX);
Gavin Howard6fc77692018-01-24 18:05:21 -07001025#endif
1026
Gavin Howard27fdfb92018-03-21 07:56:59 -06001027 assert(p->base_max <= BC_BASE_MAX_DEF);
1028 p->base_max = BC_BASE_MAX_DEF;
1029
Gavin Howard6fc77692018-01-24 18:05:21 -07001030#ifdef _POSIX_BC_DIM_MAX
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001031 p->dim_max = _POSIX_BC_DIM_MAX;
Gavin Howard6fc77692018-01-24 18:05:21 -07001032#elif defined(_BC_DIM_MAX)
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001033 p->dim_max = _BC_DIM_MAX;
Gavin Howard6fc77692018-01-24 18:05:21 -07001034#else
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001035 p->dim_max = sysconf(_SC_BC_DIM_MAX);
Gavin Howard6fc77692018-01-24 18:05:21 -07001036#endif
1037
Gavin Howard27fdfb92018-03-21 07:56:59 -06001038 assert(p->dim_max <= BC_DIM_MAX_DEF);
1039 p->dim_max = BC_DIM_MAX_DEF;
1040
Gavin Howard6fc77692018-01-24 18:05:21 -07001041#ifdef _POSIX_BC_SCALE_MAX
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001042 p->scale_max = _POSIX_BC_SCALE_MAX;
Gavin Howard6fc77692018-01-24 18:05:21 -07001043#elif defined(_BC_SCALE_MAX)
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001044 p->scale_max = _BC_SCALE_MAX;
Gavin Howard6fc77692018-01-24 18:05:21 -07001045#else
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001046 p->scale_max = sysconf(_SC_BC_SCALE_MAX);
Gavin Howard6fc77692018-01-24 18:05:21 -07001047#endif
1048
Gavin Howard27fdfb92018-03-21 07:56:59 -06001049 assert(p->scale_max <= BC_SCALE_MAX_DEF);
1050 p->scale_max = BC_SCALE_MAX_DEF;
1051
Gavin Howard6fc77692018-01-24 18:05:21 -07001052#ifdef _POSIX_BC_STRING_MAX
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001053 p->string_max = _POSIX_BC_STRING_MAX;
Gavin Howard6fc77692018-01-24 18:05:21 -07001054#elif defined(_BC_STRING_MAX)
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001055 p->string_max = _BC_STRING_MAX;
Gavin Howard6fc77692018-01-24 18:05:21 -07001056#else
Gavin Howard4bc73ee2018-01-26 11:39:20 -07001057 p->string_max = sysconf(_SC_BC_STRING_MAX);
Gavin Howard6fc77692018-01-24 18:05:21 -07001058#endif
1059
Gavin Howard27fdfb92018-03-21 07:56:59 -06001060 assert(p->string_max <= BC_STRING_MAX_DEF);
1061 p->string_max = BC_STRING_MAX_DEF;
1062
Gavin Howard5d74e962018-02-26 13:44:13 -07001063 p->scale = 0;
1064
Gavin Howardb09d9b12018-03-23 09:57:07 -06001065 if ((s = bc_num_init(&p->ibase, BC_NUM_DEF_SIZE))) return s;
Gavin Howard5d74e962018-02-26 13:44:13 -07001066 bc_num_ten(&p->ibase);
1067 p->ibase_t = 10;
1068
Gavin Howardb09d9b12018-03-23 09:57:07 -06001069 if ((s = bc_num_init(&p->obase, BC_NUM_DEF_SIZE))) goto obase_err;
Gavin Howard5d74e962018-02-26 13:44:13 -07001070 bc_num_ten(&p->obase);
1071 p->obase_t = 10;
1072
Gavin Howardb09d9b12018-03-23 09:57:07 -06001073 if ((s = bc_num_init(&p->last, BC_NUM_DEF_SIZE))) goto last_err;
Gavin Howard43a027f2018-02-26 13:27:10 -07001074 bc_num_zero(&p->last);
Gavin Howardb5c77212018-02-14 17:12:34 -07001075
Gavin Howardb09d9b12018-03-23 09:57:07 -06001076 if ((s = bc_num_init(&p->zero, BC_NUM_DEF_SIZE))) goto zero_err;
Gavin Howard43a027f2018-02-26 13:27:10 -07001077 bc_num_zero(&p->zero);
Gavin Howard5a8949e2018-02-05 16:46:06 -07001078
Gavin Howardb09d9b12018-03-23 09:57:07 -06001079 if ((s = bc_num_init(&p->one, BC_NUM_DEF_SIZE))) goto one_err;
Gavin Howard43a027f2018-02-26 13:27:10 -07001080 bc_num_one(&p->one);
Gavin Howard645200e2018-02-15 15:33:35 -07001081
Gavin Howardb09d9b12018-03-23 09:57:07 -06001082 if ((s = bc_vec_init(&p->funcs, sizeof(BcFunc), bc_func_free))) goto func_err;
Gavin Howard8a596d42018-01-15 15:46:01 -07001083
Gavin Howardd96bcae2018-02-07 19:16:19 -07001084 s = bc_veco_init(&p->func_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001085 if (s) goto func_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001086
Gavin Howardb09d9b12018-03-23 09:57:07 -06001087 if (!(main_name = malloc(strlen(bc_lang_func_main) + 1))) {
Gavin Howard91072cf2018-02-08 21:07:51 -07001088 s = BC_STATUS_MALLOC_FAIL;
Gavin Howardd50539a2018-02-08 20:52:57 -07001089 goto name_err;
1090 }
1091
Gavin Howardb09d9b12018-03-23 09:57:07 -06001092 strcpy(main_name, bc_lang_func_main);
1093 s = bc_program_addFunc(p, main_name, &idx);
1094 main_name = NULL;
Gavin Howarda1601ae2018-03-17 19:43:28 -06001095 if (s || idx != BC_PROGRAM_MAIN) goto read_err;
Gavin Howardb42810f2018-03-09 10:07:58 -07001096
Gavin Howardb09d9b12018-03-23 09:57:07 -06001097 if (!(read_name = malloc(strlen(bc_lang_func_read) + 1))) {
Gavin Howarded392aa2018-02-27 13:09:26 -07001098 s = BC_STATUS_MALLOC_FAIL;
1099 goto read_err;
1100 }
1101
Gavin Howardf456d372018-03-10 20:11:41 -07001102 strcpy(read_name, bc_lang_func_read);
Gavin Howard859e2902018-03-17 14:23:35 -06001103 s = bc_program_addFunc(p, read_name, &idx);
Gavin Howarded392aa2018-02-27 13:09:26 -07001104 read_name = NULL;
Gavin Howarda1601ae2018-03-17 19:43:28 -06001105 if (s || idx != BC_PROGRAM_READ) goto var_err;
Gavin Howardb42810f2018-03-09 10:07:58 -07001106
Gavin Howardb09d9b12018-03-23 09:57:07 -06001107 ;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001108
Gavin Howardb09d9b12018-03-23 09:57:07 -06001109 if ((s = bc_vec_init(&p->vars, sizeof(BcNum), bc_num_free))) goto var_err;
Gavin Howard8a596d42018-01-15 15:46:01 -07001110
Gavin Howardd96bcae2018-02-07 19:16:19 -07001111 s = bc_veco_init(&p->var_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001112 if (s) goto var_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001113
Gavin Howardb09d9b12018-03-23 09:57:07 -06001114 if ((s = bc_vec_init(&p->arrays, sizeof(BcVec), bc_vec_free))) goto array_err;
Gavin Howard8a596d42018-01-15 15:46:01 -07001115
Gavin Howardd96bcae2018-02-07 19:16:19 -07001116 s = bc_veco_init(&p->array_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001117 if (s) goto array_map_err;
Gavin Howardd96bcae2018-02-07 19:16:19 -07001118
1119 s = bc_vec_init(&p->strings, sizeof(char*), bc_string_free);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001120 if (s) goto string_err;
Gavin Howard5a8949e2018-02-05 16:46:06 -07001121
Gavin Howard4dbb65b2018-03-21 19:47:01 -06001122 s = bc_vec_init(&p->constants, sizeof(char*), bc_string_free);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001123 if (s) goto const_err;
Gavin Howarde46c6822018-02-08 20:05:39 -07001124
Gavin Howard0c0d1922018-03-21 17:00:21 -06001125 s = bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
Gavin Howard1ff37d12018-02-26 09:20:51 -07001126 if (s) goto expr_err;
Gavin Howard2534a812018-02-10 15:34:15 -07001127
Gavin Howardb09d9b12018-03-23 09:57:07 -06001128 if ((s = bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL))) goto stack_err;
Gavin Howard2534a812018-02-10 15:34:15 -07001129
Gavin Howard0f32a852018-03-28 12:33:17 -06001130 memset(&ip, 0, sizeof(BcInstPtr));
Gavin Howard2534a812018-02-10 15:34:15 -07001131
Gavin Howardb09d9b12018-03-23 09:57:07 -06001132 if ((s = bc_vec_push(&p->stack, &ip))) goto push_err;
Gavin Howardd28e80a2018-01-23 18:24:18 -07001133
Gavin Howardd96bcae2018-02-07 19:16:19 -07001134 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001135
Gavin Howarded392aa2018-02-27 13:09:26 -07001136push_err:
Gavin Howarde4cdf562018-01-23 13:42:39 -07001137
Gavin Howard602178d2018-02-09 12:03:28 -07001138 bc_vec_free(&p->stack);
Gavin Howarde4cdf562018-01-23 13:42:39 -07001139
Gavin Howard2534a812018-02-10 15:34:15 -07001140stack_err:
1141
Gavin Howard0c0d1922018-03-21 17:00:21 -06001142 bc_vec_free(&p->results);
Gavin Howard2534a812018-02-10 15:34:15 -07001143
1144expr_err:
Gavin Howard4dc42662018-01-17 15:17:47 -07001145
Gavin Howarde46c6822018-02-08 20:05:39 -07001146 bc_vec_free(&p->constants);
1147
1148const_err:
1149
Gavin Howard5a8949e2018-02-05 16:46:06 -07001150 bc_vec_free(&p->strings);
1151
1152string_err:
1153
Gavin Howardd96bcae2018-02-07 19:16:19 -07001154 bc_veco_free(&p->array_map);
1155
1156array_map_err:
1157
Gavin Howard23fa3f32018-02-05 14:45:39 -07001158 bc_vec_free(&p->arrays);
Gavin Howard4dc42662018-01-17 15:17:47 -07001159
Gavin Howard8a596d42018-01-15 15:46:01 -07001160array_err:
1161
Gavin Howardd96bcae2018-02-07 19:16:19 -07001162 bc_veco_free(&p->var_map);
1163
1164var_map_err:
1165
Gavin Howard23fa3f32018-02-05 14:45:39 -07001166 bc_vec_free(&p->vars);
Gavin Howard8a596d42018-01-15 15:46:01 -07001167
1168var_err:
1169
Gavin Howarded392aa2018-02-27 13:09:26 -07001170 if (read_name) free(read_name);
1171
1172read_err:
1173
Gavin Howardb09d9b12018-03-23 09:57:07 -06001174 if (main_name) free(main_name);
Gavin Howardd50539a2018-02-08 20:52:57 -07001175
1176name_err:
1177
Gavin Howardd96bcae2018-02-07 19:16:19 -07001178 bc_veco_free(&p->func_map);
1179
1180func_map_err:
1181
Gavin Howard23fa3f32018-02-05 14:45:39 -07001182 bc_vec_free(&p->funcs);
Gavin Howard8a596d42018-01-15 15:46:01 -07001183
1184func_err:
1185
Gavin Howard8389bb22018-02-15 17:40:34 -07001186 bc_num_free(&p->one);
Gavin Howard91072cf2018-02-08 21:07:51 -07001187
Gavin Howardb5c77212018-02-14 17:12:34 -07001188one_err:
Gavin Howard91072cf2018-02-08 21:07:51 -07001189
Gavin Howard8389bb22018-02-15 17:40:34 -07001190 bc_num_free(&p->zero);
Gavin Howardb5c77212018-02-14 17:12:34 -07001191
1192zero_err:
1193
Gavin Howard8389bb22018-02-15 17:40:34 -07001194 bc_num_free(&p->last);
Gavin Howard8a596d42018-01-15 15:46:01 -07001195
Gavin Howard5d74e962018-02-26 13:44:13 -07001196last_err:
1197
1198 bc_num_free(&p->obase);
1199
1200obase_err:
1201
1202 bc_num_free(&p->ibase);
1203
Gavin Howardd96bcae2018-02-07 19:16:19 -07001204 return s;
Gavin Howard8a596d42018-01-15 15:46:01 -07001205}
1206
Gavin Howard859e2902018-03-17 14:23:35 -06001207BcStatus bc_program_addFunc(BcProgram *p, char *name, size_t *idx) {
Gavin Howard3b90f9f2018-01-17 13:01:33 -07001208
Gavin Howardab67e7c2018-02-09 10:35:44 -07001209 BcStatus status;
Gavin Howardb09d9b12018-03-23 09:57:07 -06001210 BcEntry entry, *entry_ptr;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001211 BcFunc f;
1212
Gavin Howard27fdfb92018-03-21 07:56:59 -06001213 assert(p && name && idx);
Gavin Howard3b90f9f2018-01-17 13:01:33 -07001214
Gavin Howardab67e7c2018-02-09 10:35:44 -07001215 entry.name = name;
Gavin Howardded20a22018-03-07 15:15:19 -07001216 entry.idx = p->funcs.len;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001217
Gavin Howardb09d9b12018-03-23 09:57:07 -06001218 if ((status = bc_veco_insert(&p->func_map, &entry, idx))) {
Gavin Howardb42810f2018-03-09 10:07:58 -07001219 free(name);
Gavin Howardbdb2f922018-03-15 09:25:18 -06001220 if (status != BC_STATUS_VEC_ITEM_EXISTS) return status;
Gavin Howardb42810f2018-03-09 10:07:58 -07001221 }
Gavin Howardded20a22018-03-07 15:15:19 -07001222
1223 entry_ptr = bc_veco_item(&p->func_map, *idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001224 assert(entry_ptr);
Gavin Howardded20a22018-03-07 15:15:19 -07001225 *idx = entry_ptr->idx;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001226
Gavin Howardbdb2f922018-03-15 09:25:18 -06001227 if (status == BC_STATUS_VEC_ITEM_EXISTS) {
Gavin Howardab67e7c2018-02-09 10:35:44 -07001228
Gavin Howard0ed12322018-03-17 14:21:15 -06001229 BcFunc *func = bc_vec_item(&p->funcs, entry_ptr->idx);
Gavin Howardab67e7c2018-02-09 10:35:44 -07001230
Gavin Howardea9a9bd2018-03-21 08:04:07 -06001231 assert(func);
Gavin Howardab67e7c2018-02-09 10:35:44 -07001232
Gavin Howarded392aa2018-02-27 13:09:26 -07001233 status = BC_STATUS_SUCCESS;
Gavin Howardab67e7c2018-02-09 10:35:44 -07001234
Gavin Howard90f13ad2018-03-17 13:32:16 -06001235 // We need to reset these, so the function can be repopulated.
Gavin Howardb09d9b12018-03-23 09:57:07 -06001236 func->nparams = 0;
Gavin Howard0eb2a372018-03-24 09:52:55 -06001237 bc_vec_npop(&func->autos, func->autos.len);
1238 bc_vec_npop(&func->code, func->code.len);
1239 bc_vec_npop(&func->labels, func->labels.len);
Gavin Howardab67e7c2018-02-09 10:35:44 -07001240 }
Gavin Howardded20a22018-03-07 15:15:19 -07001241 else {
Gavin Howardb09d9b12018-03-23 09:57:07 -06001242 if ((status = bc_func_init(&f))) return status;
Gavin Howardded20a22018-03-07 15:15:19 -07001243 status = bc_vec_push(&p->funcs, &f);
Gavin Howard19470a42018-03-17 14:21:30 -06001244 if (status) bc_func_free(&f);
Gavin Howardded20a22018-03-07 15:15:19 -07001245 }
1246
1247 return status;
Gavin Howard8a596d42018-01-15 15:46:01 -07001248}
1249
Gavin Howardabdc2d32018-03-27 08:01:08 -06001250BcStatus bc_program_reset(BcProgram *p, BcStatus status, bool sig) {
Gavin Howardf4167dc2018-03-26 14:19:28 -06001251
1252 BcFunc *func;
1253 BcInstPtr *ip;
1254
Gavin Howardabdc2d32018-03-27 08:01:08 -06001255 bc_vec_npop(&p->stack, p->stack.len - 1);
1256 bc_vec_npop(&p->results, p->results.len);
1257
Gavin Howardf4167dc2018-03-26 14:19:28 -06001258 func = bc_vec_item(&p->funcs, 0);
1259 assert(func);
1260 ip = bc_vec_top(&p->stack);
1261 assert(ip);
1262
1263 ip->idx = func->code.len;
1264
Gavin Howardabdc2d32018-03-27 08:01:08 -06001265 bcg.sig_int_catches += sig;
1266
1267 if (!status && sig && !bcg.interactive) return BC_STATUS_QUIT;
1268
Gavin Howard46f0e422018-03-27 08:12:00 -06001269 if (!status && bcg.interactive) {
1270 fprintf(stderr, "%s", bc_program_ready_prompt);
1271 fflush(stderr);
1272 }
1273
Gavin Howardabdc2d32018-03-27 08:01:08 -06001274 return status;
Gavin Howardf4167dc2018-03-26 14:19:28 -06001275}
1276
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001277BcStatus bc_program_exec(BcProgram *p) {
Gavin Howard5b5dc572018-01-24 11:57:38 -07001278
Gavin Howard7c8dc772018-02-21 12:12:11 -07001279 BcStatus status;
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001280 uint8_t *code;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001281 size_t idx;
Gavin Howard195706a2018-02-26 17:45:58 -07001282 BcResult result;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001283 BcFunc *func;
Gavin Howard195706a2018-02-26 17:45:58 -07001284 BcInstPtr *ip;
Gavin Howardabdc2d32018-03-27 08:01:08 -06001285 bool cond, sig;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001286
Gavin Howard0a2a6742018-02-27 14:11:26 -07001287 status = BC_STATUS_SUCCESS;
Gavin Howardb8181162018-02-28 12:58:09 -07001288 cond = false;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001289
Gavin Howardb09d9b12018-03-23 09:57:07 -06001290 ip = bc_vec_top(&p->stack);
1291 assert(ip);
1292 func = bc_vec_item(&p->funcs, ip->func);
1293 assert(func);
1294 code = func->code.array;
1295
Gavin Howardcdee77b2018-03-28 12:25:50 -06001296 while (!bcg.sig_other && bcg.sig_int == bcg.sig_int_catches &&
1297 ip->idx < func->code.len)
1298 {
Gavin Howardb09d9b12018-03-23 09:57:07 -06001299 uint8_t inst = code[(ip->idx)++];
Gavin Howard7c8dc772018-02-21 12:12:11 -07001300
Gavin Howard7c8dc772018-02-21 12:12:11 -07001301 switch (inst) {
1302
Gavin Howard195706a2018-02-26 17:45:58 -07001303 case BC_INST_CALL:
1304 {
1305 status = bc_program_call(p, code, &ip->idx);
1306 break;
1307 }
1308
1309 case BC_INST_RETURN:
1310 case BC_INST_RETURN_ZERO:
1311 {
1312 status = bc_program_return(p, inst);
1313 break;
1314 }
1315
Gavin Howard7c8dc772018-02-21 12:12:11 -07001316 case BC_INST_READ:
1317 {
1318 status = bc_program_read(p);
1319 break;
1320 }
1321
Gavin Howard195706a2018-02-26 17:45:58 -07001322 case BC_INST_JUMP_ZERO:
Gavin Howard170fcb02018-02-27 15:27:51 -07001323 {
1324 BcResult *operand;
1325 BcNum *num;
1326
Gavin Howardb09d9b12018-03-23 09:57:07 -06001327 if ((status = bc_program_unaryOpPrep(p, &operand, &num))) return status;
Gavin Howard2a064fd2018-03-20 15:56:12 -06001328 cond = bc_num_cmp(num, &p->zero, NULL) == 0;
Gavin Howard0eb2a372018-03-24 09:52:55 -06001329 bc_vec_pop(&p->results);
Gavin Howard170fcb02018-02-27 15:27:51 -07001330 }
Gavin Howard98d071b2018-03-19 19:36:23 -06001331 // Fallthrough.
Gavin Howard195706a2018-02-26 17:45:58 -07001332 case BC_INST_JUMP:
1333 {
Gavin Howard170fcb02018-02-27 15:27:51 -07001334 size_t idx;
1335 size_t *addr;
1336
1337 idx = bc_program_index(code, &ip->idx);
1338 addr = bc_vec_item(&func->labels, idx);
1339
Gavin Howard27fdfb92018-03-21 07:56:59 -06001340 assert(addr);
Gavin Howard170fcb02018-02-27 15:27:51 -07001341
Gavin Howardb09d9b12018-03-23 09:57:07 -06001342 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
Gavin Howard170fcb02018-02-27 15:27:51 -07001343
Gavin Howard195706a2018-02-26 17:45:58 -07001344 break;
1345 }
1346
1347 case BC_INST_PUSH_VAR:
Gavin Howard101b5e62018-03-26 07:46:27 -06001348 case BC_INST_PUSH_ARRAY_ELEM:
Gavin Howard195706a2018-02-26 17:45:58 -07001349 {
Gavin Howard843fa792018-02-27 16:42:52 -07001350 status = bc_program_push(p, code, &ip->idx, inst == BC_INST_PUSH_VAR);
Gavin Howard195706a2018-02-26 17:45:58 -07001351 break;
1352 }
1353
1354 case BC_INST_PUSH_LAST:
1355 {
1356 result.type = BC_RESULT_LAST;
Gavin Howard0c0d1922018-03-21 17:00:21 -06001357 status = bc_vec_push(&p->results, &result);
Gavin Howard195706a2018-02-26 17:45:58 -07001358 break;
1359 }
1360
1361 case BC_INST_PUSH_SCALE:
1362 {
Gavin Howarda4a72892018-02-27 09:16:10 -07001363 status = bc_program_pushScale(p);
Gavin Howard195706a2018-02-26 17:45:58 -07001364 break;
1365 }
1366
1367 case BC_INST_PUSH_IBASE:
1368 {
1369 result.type = BC_RESULT_IBASE;
Gavin Howard0c0d1922018-03-21 17:00:21 -06001370 status = bc_vec_push(&p->results, &result);
Gavin Howard195706a2018-02-26 17:45:58 -07001371 break;
1372 }
1373
1374 case BC_INST_PUSH_OBASE:
1375 {
1376 result.type = BC_RESULT_OBASE;
Gavin Howard0c0d1922018-03-21 17:00:21 -06001377 status = bc_vec_push(&p->results, &result);
Gavin Howard195706a2018-02-26 17:45:58 -07001378 break;
1379 }
1380
1381 case BC_INST_SCALE_FUNC:
1382 case BC_INST_LENGTH:
1383 case BC_INST_SQRT:
1384 {
1385 status = bc_program_builtin(p, inst);
1386 break;
1387 }
1388
1389 case BC_INST_PUSH_NUM:
1390 {
Gavin Howard195706a2018-02-26 17:45:58 -07001391 result.type = BC_RESULT_CONSTANT;
1392 result.data.id.idx = bc_program_index(code, &ip->idx);
Gavin Howard0c0d1922018-03-21 17:00:21 -06001393 status = bc_vec_push(&p->results, &result);
Gavin Howard195706a2018-02-26 17:45:58 -07001394 break;
1395 }
1396
Gavin Howard5c222e32018-02-28 13:06:41 -07001397 case BC_INST_POP:
1398 {
Gavin Howard0eb2a372018-03-24 09:52:55 -06001399 bc_vec_pop(&p->results);
Gavin Howard5c222e32018-02-28 13:06:41 -07001400 break;
1401 }
1402
Gavin Howard101b5e62018-03-26 07:46:27 -06001403 case BC_INST_INC_POST:
1404 case BC_INST_DEC_POST:
1405 case BC_INST_INC_PRE:
1406 case BC_INST_DEC_PRE:
Gavin Howard195706a2018-02-26 17:45:58 -07001407 {
Gavin Howarde723a152018-02-27 15:24:00 -07001408 status = bc_program_incdec(p, inst);
Gavin Howard195706a2018-02-26 17:45:58 -07001409 break;
1410 }
1411
1412 case BC_INST_HALT:
1413 {
Gavin Howard01d6ec32018-03-17 19:42:02 -06001414 status = BC_STATUS_QUIT;
Gavin Howard195706a2018-02-26 17:45:58 -07001415 break;
1416 }
1417
Gavin Howard7c8dc772018-02-21 12:12:11 -07001418 case BC_INST_PRINT:
Gavin Howard152f3e82018-03-07 12:33:15 -07001419 case BC_INST_PRINT_EXPR:
Gavin Howard7c8dc772018-02-21 12:12:11 -07001420 {
Gavin Howard3aa58d12018-03-05 11:21:18 -07001421 BcResult *operand;
Gavin Howard8d1f1db2018-02-23 11:29:41 -07001422 BcNum *num;
Gavin Howardb09d9b12018-03-23 09:57:07 -06001423 bool newline;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001424
Gavin Howardb09d9b12018-03-23 09:57:07 -06001425 if ((status = bc_program_unaryOpPrep(p, &operand, &num))) return status;
Gavin Howarda883ad92018-02-22 13:34:41 -07001426
Gavin Howardb09d9b12018-03-23 09:57:07 -06001427 newline = inst == BC_INST_PRINT;
1428 status = bc_num_print(num, &p->obase, p->obase_t, newline, &p->nchars);
Gavin Howard534a9802018-02-28 13:06:09 -07001429 if (status) return status;
Gavin Howardc44ce202018-02-21 19:02:02 -07001430
Gavin Howardb09d9b12018-03-23 09:57:07 -06001431 if ((status = bc_num_copy(&p->last, num))) return status;
Gavin Howarde351e9d2018-02-27 09:16:42 -07001432
Gavin Howard0eb2a372018-03-24 09:52:55 -06001433 bc_vec_pop(&p->results);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001434
1435 break;
1436 }
1437
1438 case BC_INST_STR:
1439 {
Gavin Howardb09d9b12018-03-23 09:57:07 -06001440 const char **string, *s;
Gavin Howardbc7cae82018-03-14 13:43:04 -06001441 size_t len;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001442
1443 idx = bc_program_index(code, &ip->idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001444 assert(idx < p->strings.len);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001445 string = bc_vec_item(&p->strings, idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001446 assert(string);
Gavin Howard0271bfc2018-03-14 10:52:48 -06001447
Gavin Howardbc7cae82018-03-14 13:43:04 -06001448 s = *string;
1449 len = strlen(s);
1450
1451 for (idx = 0; idx < len; ++idx) {
1452 char c = s[idx];
Gavin Howarda141a0f2018-03-23 13:16:10 -06001453 if (putchar(c) == EOF) return BC_STATUS_IO_ERR;
Gavin Howardbc7cae82018-03-14 13:43:04 -06001454 if (c == '\n') p->nchars = SIZE_MAX;
1455 ++p->nchars;
1456 }
Gavin Howard7c8dc772018-02-21 12:12:11 -07001457
1458 break;
1459 }
1460
1461 case BC_INST_PRINT_STR:
1462 {
Gavin Howarda1ff02f2018-03-07 12:32:25 -07001463 const char **string;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001464
1465 idx = bc_program_index(code, &ip->idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001466 assert(idx < p->strings.len);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001467 string = bc_vec_item(&p->strings, idx);
Gavin Howardb09d9b12018-03-23 09:57:07 -06001468 assert(string);
Gavin Howarda1ff02f2018-03-07 12:32:25 -07001469
Gavin Howardbc7cae82018-03-14 13:43:04 -06001470 status = bc_program_printString(*string, &p->nchars);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001471
1472 break;
1473 }
1474
Gavin Howard101b5e62018-03-26 07:46:27 -06001475 case BC_INST_POWER:
1476 case BC_INST_MULTIPLY:
1477 case BC_INST_DIVIDE:
1478 case BC_INST_MODULUS:
1479 case BC_INST_PLUS:
1480 case BC_INST_MINUS:
Gavin Howard7c8dc772018-02-21 12:12:11 -07001481 {
1482 status = bc_program_op(p, inst);
1483 break;
1484 }
1485
Gavin Howard101b5e62018-03-26 07:46:27 -06001486 case BC_INST_REL_EQ:
1487 case BC_INST_REL_LE:
1488 case BC_INST_REL_GE:
1489 case BC_INST_REL_NE:
1490 case BC_INST_REL_LT:
1491 case BC_INST_REL_GT:
Gavin Howard195706a2018-02-26 17:45:58 -07001492 {
Gavin Howard2c154002018-02-27 16:43:26 -07001493 status = bc_program_logical(p, inst);
Gavin Howard195706a2018-02-26 17:45:58 -07001494 break;
1495 }
1496
Gavin Howard101b5e62018-03-26 07:46:27 -06001497 case BC_INST_BOOL_NOT:
Gavin Howard195706a2018-02-26 17:45:58 -07001498 {
Gavin Howarde8095352018-02-27 09:17:20 -07001499 BcResult *ptr;
1500 BcNum *num;
1501
Gavin Howardb09d9b12018-03-23 09:57:07 -06001502 if ((status = bc_program_unaryOpPrep(p, &ptr, &num))) return status;
Gavin Howarde8095352018-02-27 09:17:20 -07001503
Gavin Howarde8095352018-02-27 09:17:20 -07001504 status = bc_num_init(&result.data.num, BC_NUM_DEF_SIZE);
Gavin Howarde8095352018-02-27 09:17:20 -07001505 if (status) return status;
1506
Gavin Howard2a064fd2018-03-20 15:56:12 -06001507 if (bc_num_cmp(num, &p->zero, NULL)) bc_num_one(&result.data.num);
Gavin Howarde8095352018-02-27 09:17:20 -07001508 else bc_num_zero(&result.data.num);
1509
Gavin Howard5fb956f2018-03-05 10:57:16 -07001510 status = bc_program_unaryOpRetire(p, &result, BC_RESULT_INTERMEDIATE);
Gavin Howarde8095352018-02-27 09:17:20 -07001511
1512 if (status) bc_num_free(&result.data.num);
1513
Gavin Howard195706a2018-02-26 17:45:58 -07001514 break;
1515 }
1516
Gavin Howard101b5e62018-03-26 07:46:27 -06001517 case BC_INST_BOOL_OR:
1518 case BC_INST_BOOL_AND:
Gavin Howard195706a2018-02-26 17:45:58 -07001519 {
Gavin Howard2c154002018-02-27 16:43:26 -07001520 status = bc_program_logical(p, inst);
Gavin Howard195706a2018-02-26 17:45:58 -07001521 break;
1522 }
1523
Gavin Howard101b5e62018-03-26 07:46:27 -06001524 case BC_INST_NEG:
Gavin Howard7c8dc772018-02-21 12:12:11 -07001525 {
Gavin Howard3a947362018-03-02 11:25:48 -07001526 status = bc_program_negate(p);
Gavin Howard7c8dc772018-02-21 12:12:11 -07001527 break;
1528 }
1529
Gavin Howard101b5e62018-03-26 07:46:27 -06001530 case BC_INST_ASSIGN_POWER:
1531 case BC_INST_ASSIGN_MULTIPLY:
1532 case BC_INST_ASSIGN_DIVIDE:
1533 case BC_INST_ASSIGN_MODULUS:
1534 case BC_INST_ASSIGN_PLUS:
1535 case BC_INST_ASSIGN_MINUS:
1536 case BC_INST_ASSIGN:
Gavin Howard6d89b5d2018-02-26 13:21:34 -07001537 {
1538 status = bc_program_assign(p, inst);
1539 break;
1540 }
1541
Gavin Howard7c8dc772018-02-21 12:12:11 -07001542 default:
1543 {
Gavin Howard27fdfb92018-03-21 07:56:59 -06001544 assert(false);
Gavin Howardd11c2622018-02-21 21:16:46 -07001545 break;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001546 }
1547 }
Gavin Howard195706a2018-02-26 17:45:58 -07001548
Gavin Howard0a2a6742018-02-27 14:11:26 -07001549 if (status) return status;
1550
1551 // We keep getting these because if the size of the
Gavin Howard195706a2018-02-26 17:45:58 -07001552 // stack changes, pointers may end up being invalid.
1553 ip = bc_vec_top(&p->stack);
Gavin Howard27fdfb92018-03-21 07:56:59 -06001554 assert(ip);
Gavin Howard0a2a6742018-02-27 14:11:26 -07001555 func = bc_vec_item(&p->funcs, ip->func);
Gavin Howard27fdfb92018-03-21 07:56:59 -06001556 assert(func);
Gavin Howarda1ff02f2018-03-07 12:32:25 -07001557 code = func->code.array;
Gavin Howard7c8dc772018-02-21 12:12:11 -07001558 }
1559
Gavin Howardabdc2d32018-03-27 08:01:08 -06001560 sig = bcg.sig_int != bcg.sig_int_catches;
1561
1562 if (status || sig) status = bc_program_reset(p, status, sig);
Gavin Howardf4167dc2018-03-26 14:19:28 -06001563
Gavin Howard7c8dc772018-02-21 12:12:11 -07001564 return status;
1565}
1566
Gavin Howard67c38522018-02-27 16:00:49 -07001567BcStatus bc_program_print(BcProgram *p) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001568
1569 BcStatus status;
1570 BcFunc *func;
1571 uint8_t *code;
Gavin Howardc0d9f312018-03-07 15:15:00 -07001572 BcInstPtr ip;
1573 size_t i;
Gavin Howardabdc2d32018-03-27 08:01:08 -06001574 bool sig;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001575
Gavin Howard0a2a6742018-02-27 14:11:26 -07001576 status = BC_STATUS_SUCCESS;
1577
Gavin Howardc0d9f312018-03-07 15:15:00 -07001578 for (i = 0; !status && i < p->funcs.len; ++i) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001579
Gavin Howardb09d9b12018-03-23 09:57:07 -06001580 ip.idx = ip.len = 0;
Gavin Howardc0d9f312018-03-07 15:15:00 -07001581 ip.func = i;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001582
Gavin Howardc0d9f312018-03-07 15:15:00 -07001583 func = bc_vec_item(&p->funcs, ip.func);
Gavin Howard27fdfb92018-03-21 07:56:59 -06001584 assert(func);
Gavin Howardc0d9f312018-03-07 15:15:00 -07001585 code = func->code.array;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001586
Gavin Howardc0d9f312018-03-07 15:15:00 -07001587 if (printf("func[%zu]: ", ip.func) < 0) return BC_STATUS_IO_ERR;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001588
Gavin Howardc0d9f312018-03-07 15:15:00 -07001589 while (ip.idx < func->code.len) {
Gavin Howard0a2a6742018-02-27 14:11:26 -07001590
Gavin Howardb09d9b12018-03-23 09:57:07 -06001591 uint8_t inst = code[ip.idx++];
Gavin Howard0a2a6742018-02-27 14:11:26 -07001592
Gavin Howardfd797192018-03-26 12:27:01 -06001593 if (putchar(bc_lang_inst_chars[inst]) == EOF) return BC_STATUS_IO_ERR;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001594
Gavin Howard642050e2018-03-26 12:25:45 -06001595 if (inst == BC_INST_PUSH_VAR || inst == BC_INST_PUSH_ARRAY_ELEM) {
1596 if ((status = bc_program_printName(code, &ip.idx))) return status;
1597 }
1598 else if (inst == BC_INST_PUSH_NUM || inst == BC_INST_CALL ||
1599 (inst >= BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
1600 {
1601 if ((status = bc_program_printIndex(code, &ip.idx))) return status;
1602 if (inst == BC_INST_CALL && (status = bc_program_printIndex(code, &ip.idx)))
1603 return status;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001604 }
1605 }
Gavin Howardc0d9f312018-03-07 15:15:00 -07001606
Gavin Howardc0d9f312018-03-07 15:15:00 -07001607 if (putchar('\n') == EOF) status = BC_STATUS_IO_ERR;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001608 }
1609
Gavin Howardabdc2d32018-03-27 08:01:08 -06001610 sig = bcg.sig_int != bcg.sig_int_catches;
1611
1612 if (status || sig) status = bc_program_reset(p, status, sig);
Gavin Howardf4167dc2018-03-26 14:19:28 -06001613
Gavin Howard0a2a6742018-02-27 14:11:26 -07001614 return status;
1615}
1616
1617void bc_program_free(BcProgram *p) {
1618
Gavin Howard2a9c6e92018-03-20 21:35:18 -06001619 if (!p) return;
Gavin Howard0a2a6742018-02-27 14:11:26 -07001620
Gavin Howard0a2a6742018-02-27 14:11:26 -07001621 bc_num_free(&p->ibase);
1622 bc_num_free(&p->obase);
1623
1624 bc_vec_free(&p->funcs);
1625 bc_veco_free(&p->func_map);
1626
1627 bc_vec_free(&p->vars);
1628 bc_veco_free(&p->var_map);
1629
1630 bc_vec_free(&p->arrays);
1631 bc_veco_free(&p->array_map);
1632
1633 bc_vec_free(&p->strings);
1634 bc_vec_free(&p->constants);
1635
Gavin Howard0c0d1922018-03-21 17:00:21 -06001636 bc_vec_free(&p->results);
Gavin Howard0a2a6742018-02-27 14:11:26 -07001637 bc_vec_free(&p->stack);
Gavin Howard0a2a6742018-02-27 14:11:26 -07001638
1639 bc_num_free(&p->last);
1640 bc_num_free(&p->zero);
1641 bc_num_free(&p->one);
1642
1643 memset(p, 0, sizeof(BcProgram));
1644}