blob: a2f807126ac96a6726d635b5ac6733fcc9fed046 [file] [log] [blame]
/*
* Copyright 2018 Contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************
*
* A special license exemption is granted to the Toybox project and to the
* Android Open Source Project to use this source under the following BSD
* 0-Clause License:
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
*******************************************************************************
*
* Code to execute bc programs.
*
*/
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <arbprec/arbprec.h>
#include <bc/io.h>
#include <bc/program.h>
#include <bc/parse.h>
#include <bc/instructions.h>
static const char* const bc_byte_fmt = "%02x";
static const BcMathOpFunc bc_math_ops[] = {
bc_num_mod,
NULL, // &
NULL, // '
NULL, // (
NULL, // )
bc_num_mul,
bc_num_add,
NULL, // ,
bc_num_sub,
NULL, // .
bc_num_div,
};
static BcStatus bc_program_printString(const char* str);
static BcStatus bc_program_execExpr(BcProgram* p, BcVec* exprs,
BcNum* num, bool print);
#if 0
static BcStatus bc_program_assign(BcProgram* p, BcExpr* expr,
BcExprType op, fxdpnt* amt);
#endif
static BcStatus bc_program_read(BcProgram* p);
static size_t bc_program_index(uint8_t* code, size_t* start);
static void bc_program_printIndex(uint8_t* code, size_t* start);
static void bc_program_printName(uint8_t* code, size_t* start);
BcStatus bc_program_init(BcProgram* p) {
BcStatus s;
size_t idx;
char* name;
BcInstPtr ip;
if (p == NULL) {
return BC_STATUS_INVALID_PARAM;
}
name = NULL;
p->scale = 0;
p->ibase = 10;
p->obase = 10;
#ifdef _POSIX_BC_BASE_MAX
p->base_max = _POSIX_BC_BASE_MAX;
#elif defined(_BC_BASE_MAX)
p->base_max = _BC_BASE_MAX;
#else
errno = 0;
p->base_max = sysconf(_SC_BC_BASE_MAX);
if (p->base_max == -1) {
if (errno) {
return BC_STATUS_NO_LIMIT;
}
p->base_max = BC_BASE_MAX_DEF;
}
else if (p->base_max > BC_BASE_MAX_DEF) {
return BC_STATUS_INVALID_LIMIT;
}
#endif
#ifdef _POSIX_BC_DIM_MAX
p->dim_max = _POSIX_BC_DIM_MAX;
#elif defined(_BC_DIM_MAX)
p->dim_max = _BC_DIM_MAX;
#else
errno = 0;
p->dim_max = sysconf(_SC_BC_DIM_MAX);
if (p->dim_max == -1) {
if (errno) {
return BC_STATUS_NO_LIMIT;
}
p->dim_max = BC_DIM_MAX_DEF;
}
else if (p->dim_max > BC_DIM_MAX_DEF) {
return BC_STATUS_INVALID_LIMIT;
}
#endif
#ifdef _POSIX_BC_SCALE_MAX
p->scale_max = _POSIX_BC_SCALE_MAX;
#elif defined(_BC_SCALE_MAX)
p->scale_max = _BC_SCALE_MAX;
#else
errno = 0;
p->scale_max = sysconf(_SC_BC_SCALE_MAX);
if (p->scale_max == -1) {
if (errno) {
return BC_STATUS_NO_LIMIT;
}
p->scale_max = BC_SCALE_MAX_DEF;
}
else if (p->scale_max > BC_SCALE_MAX_DEF) {
return BC_STATUS_INVALID_LIMIT;
}
#endif
#ifdef _POSIX_BC_STRING_MAX
p->string_max = _POSIX_BC_STRING_MAX;
#elif defined(_BC_STRING_MAX)
p->string_max = _BC_STRING_MAX;
#else
errno = 0;
p->string_max = sysconf(_SC_BC_STRING_MAX);
if (p->string_max == -1) {
if (errno) {
return BC_STATUS_NO_LIMIT;
}
p->string_max = BC_STRING_MAX_DEF;
}
else if (p->string_max > BC_STRING_MAX_DEF) {
return BC_STATUS_INVALID_LIMIT;
}
#endif
s = bc_num_parse(&p->last, "0", 10, 0);
if (s) return s;
s = bc_num_parse(&p->zero, "0", 10, 0);
if (s) goto zero_err;
s = bc_num_parse(&p->one, "1", 10, 0);
if (s) goto one_err;
p->num_buf = malloc(BC_PROGRAM_BUF_SIZE + 1);
if (!p->num_buf) {
s = BC_STATUS_MALLOC_FAIL;
goto num_buf_err;
}
p->buf_size = BC_PROGRAM_BUF_SIZE;
s = bc_vec_init(&p->funcs, sizeof(BcFunc), bc_func_free);
if (s) {
goto func_err;
}
s = bc_veco_init(&p->func_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
if (s) {
goto func_map_err;
}
name = malloc(1);
if (!name) {
s = BC_STATUS_MALLOC_FAIL;
goto name_err;
}
name[0] = '\0';
s = bc_program_func_add(p, name, &idx);
if (s) {
goto var_err;
}
name = NULL;
s = bc_vec_init(&p->vars, sizeof(BcVar), bc_var_free);
if (s) {
goto var_err;
}
s = bc_veco_init(&p->var_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
if (s) {
goto var_map_err;
}
s = bc_vec_init(&p->arrays, sizeof(BcArray), bc_array_free);
if (s) {
goto array_err;
}
s = bc_veco_init(&p->array_map, sizeof(BcEntry), bc_entry_free, bc_entry_cmp);
if (s) {
goto array_map_err;
}
s = bc_vec_init(&p->strings, sizeof(char*), bc_string_free);
if (s) {
goto string_err;
}
s = bc_vec_init(&p->constants, sizeof(char*), bc_constant_free);
if (s) {
goto const_err;
}
s = bc_vec_init(&p->expr_stack, sizeof(BcNum), bc_result_free);
if (s) {
goto expr_err;
}
s = bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
if (s) {
goto stack_err;
}
ip.idx = 0;
ip.func = 0;
s = bc_vec_push(&p->stack, &ip);
if (s) {
goto local_err;
}
s = bc_vec_init(&p->locals, sizeof(BcLocal), bc_local_free);
if (s) {
goto local_err;
}
s = bc_vec_init(&p->temps, sizeof(BcTemp), bc_temp_free);
if (s) {
goto temps_err;
}
return s;
temps_err:
bc_vec_free(&p->locals);
local_err:
bc_vec_free(&p->stack);
stack_err:
bc_vec_free(&p->expr_stack);
expr_err:
bc_vec_free(&p->constants);
const_err:
bc_vec_free(&p->strings);
string_err:
bc_veco_free(&p->array_map);
array_map_err:
bc_vec_free(&p->arrays);
array_err:
bc_veco_free(&p->var_map);
var_map_err:
bc_vec_free(&p->vars);
var_err:
if (name) {
free(name);
}
name_err:
bc_veco_free(&p->func_map);
func_map_err:
bc_vec_free(&p->funcs);
func_err:
free(p->num_buf);
num_buf_err:
bc_num_destruct(&p->one);
one_err:
bc_num_destruct(&p->zero);
zero_err:
bc_num_destruct(&p->last);
return s;
}
void bc_program_limits(BcProgram* p) {
putchar('\n');
printf("BC_BASE_MAX = %ld\n", p->base_max);
printf("BC_DIM_MAX = %ld\n", p->dim_max);
printf("BC_SCALE_MAX = %ld\n", p->scale_max);
printf("BC_STRING_MAX = %ld\n", p->string_max);
printf("Max Exponent = %ld\n", INT64_MAX);
printf("Number of Vars = %u\n", UINT32_MAX);
putchar('\n');
}
BcStatus bc_program_func_add(BcProgram* p, char* name, size_t* idx) {
BcStatus status;
BcEntry entry;
BcFunc f;
if (!p || !name || !idx) {
return BC_STATUS_INVALID_PARAM;
}
entry.name = name;
entry.idx = p->funcs.len;
status = bc_veco_insert(&p->func_map, &entry, idx);
if (status == BC_STATUS_VECO_ITEM_EXISTS) {
BcFunc* func;
func = bc_vec_item(&p->funcs, *idx);
if (!func) {
return BC_STATUS_EXEC_UNDEFINED_FUNC;
}
// We need to reset these so the function can be repopulated.
func->num_autos = 0;
func->num_params = 0;
func->code.len = 0;
func->labels.len = 0;
return BC_STATUS_SUCCESS;
}
else if (status) {
return status;
}
status = bc_func_init(&f);
if (status) {
return status;
}
return bc_vec_push(&p->funcs, &f);
}
BcStatus bc_program_var_add(BcProgram* p, char* name, size_t* idx) {
BcStatus status;
BcEntry entry;
BcVar v;
if (!p || !name || !idx) {
return BC_STATUS_INVALID_PARAM;
}
entry.name = name;
entry.idx = p->vars.len;
status = bc_veco_insert(&p->var_map, &entry, idx);
if (status) {
return status == BC_STATUS_VECO_ITEM_EXISTS ?
BC_STATUS_SUCCESS : status;
}
status = bc_var_init(&v);
if (status) {
return status;
}
return bc_vec_push(&p->vars, &v);
}
BcStatus bc_program_array_add(BcProgram* p, char* name, size_t* idx) {
BcStatus status;
BcEntry entry;
BcArray a;
if (!p || !name || !idx) {
return BC_STATUS_INVALID_PARAM;
}
entry.name = name;
entry.idx = p->arrays.len;
status = bc_veco_insert(&p->array_map, &entry, idx);
if (status) {
return status == BC_STATUS_VECO_ITEM_EXISTS ?
BC_STATUS_SUCCESS : status;
}
status = bc_array_init(&a);
if (status) {
return status;
}
return bc_vec_push(&p->arrays, &a);
}
BcStatus bc_program_exec(BcProgram* p) {
BcStatus status;
int pchars;
BcFunc* func;
uint8_t* code;
BcInstPtr* ip;
size_t idx;
status = BC_STATUS_SUCCESS;
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->funcs, ip->func);
assert(func);
code = func->code.array;
for (; ip->idx < func->code.len; ++ip->idx) {
uint8_t inst;
inst = code[ip->idx];
// TODO: Add all instructions.
switch (inst) {
case BC_INST_READ:
{
status = bc_program_read(p);
break;
}
case BC_INST_PRINT:
{
BcResult* num;
num = bc_vec_top(&p->expr_stack);
bc_num_print(&num->num, p->obase);
bc_vec_pop(&p->expr_stack);
break;
}
case BC_INST_STR:
{
const char* string;
idx = bc_program_index(code, &ip->idx);
if (idx >= p->strings.len) {
return BC_STATUS_EXEC_INVALID_STRING;
}
string = bc_vec_item(&p->strings, idx);
pchars = fprintf(stdout, "%s", string);
status = pchars > 0 ? BC_STATUS_SUCCESS :
BC_STATUS_EXEC_PRINT_ERR;
break;
}
case BC_INST_PRINT_STR:
{
const char* string;
idx = bc_program_index(code, &ip->idx);
if (idx >= p->strings.len) {
return BC_STATUS_EXEC_INVALID_STRING;
}
string = bc_vec_item(&p->strings, idx);
status = bc_program_printString(string);
break;
}
case BC_INST_HALT:
{
status = BC_STATUS_EXEC_HALT;
break;
}
case BC_INST_PUSH_NUM:
{
size_t idx;
BcResult result;
char* str;
idx = bc_program_index(code, &ip->idx);
str = *((char**) bc_vec_item(&p->constants, idx));
if (!str) {
return BC_STATUS_EXEC_INVALID_EXPR;
}
//result.num = arb_str2fxdpnt(str);
//if (!result.num) {
// return BC_STATUS_EXEC_INVALID_EXPR;
//}
result.type = BC_NUM_CONSTANT;
status = bc_vec_push(&p->expr_stack, &result);
break;
}
case BC_INST_OP_MODULUS:
case BC_INST_OP_MULTIPLY:
case BC_INST_OP_PLUS:
case BC_INST_OP_MINUS:
case BC_INST_OP_DIVIDE:
case BC_INST_OP_POWER:
{
BcResult* ptr;
BcResult num1;
BcResult num2;
BcResult result;
ptr = bc_vec_top(&p->expr_stack);
if (!ptr) return BC_STATUS_EXEC_INVALID_EXPR;
num2 = *ptr;
status = bc_vec_pop(&p->expr_stack);
if (status) return status;
ptr = bc_vec_top(&p->expr_stack);
if (!ptr) return BC_STATUS_EXEC_INVALID_EXPR;
num1 = *ptr;
status = bc_vec_pop(&p->expr_stack);
if (status) return status;
result.type = BC_NUM_RESULT;
status = bc_num_construct(&result.num, BC_NUM_DEF_SIZE);
if (status) return status;
if (inst != BC_INST_OP_POWER) {
BcMathOpFunc op;
op = bc_math_ops[inst - BC_INST_OP_MODULUS];
status = op(&num1.num, &num2.num, &result.num, p->scale);
}
else {
// TODO: Power.
}
if (status) return status;
status = bc_vec_push(&p->expr_stack, &result);
break;
}
default:
{
return BC_STATUS_EXEC_INVALID_STMT;
}
}
}
return status;
return BC_STATUS_SUCCESS;
}
void bc_program_printCode(BcProgram* p) {
BcFunc* func;
uint8_t* code;
BcInstPtr* ip;
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->funcs, ip->func);
assert(func);
code = func->code.array;
for (; ip->idx < func->code.len; ++ip->idx) {
uint8_t inst;
inst = code[ip->idx];
// TODO: Fill this out.
switch (inst) {
case BC_INST_PUSH_VAR:
case BC_INST_PUSH_ARRAY:
{
putchar(inst);
bc_program_printName(code, &ip->idx);
break;
}
case BC_INST_CALL:
{
putchar(inst);
bc_program_printIndex(code, &ip->idx);
bc_program_printIndex(code, &ip->idx);
break;
}
case BC_INST_JUMP:
case BC_INST_JUMP_NOT_ZERO:
case BC_INST_JUMP_ZERO:
case BC_INST_PUSH_NUM:
case BC_INST_STR:
case BC_INST_PRINT_STR:
{
putchar(inst);
bc_program_printIndex(code, &ip->idx);
break;
}
default:
{
putchar(inst);
break;
}
}
}
putchar('\n');
}
void bc_program_free(BcProgram* p) {
if (p == NULL) {
return;
}
free(p->num_buf);
bc_vec_free(&p->funcs);
bc_veco_free(&p->func_map);
bc_vec_free(&p->vars);
bc_veco_free(&p->var_map);
bc_vec_free(&p->arrays);
bc_veco_free(&p->array_map);
bc_vec_free(&p->strings);
bc_vec_free(&p->constants);
bc_vec_free(&p->expr_stack);
bc_vec_free(&p->stack);
bc_vec_free(&p->locals);
bc_vec_free(&p->temps);
bc_num_destruct(&p->last);
bc_num_destruct(&p->zero);
bc_num_destruct(&p->one);
memset(p, 0, sizeof(BcProgram));
}
static BcStatus bc_program_printString(const char* str) {
char c;
char c2;
size_t len;
int err;
len = strlen(str);
for (size_t i = 0; i < len; ++i) {
c = str[i];
if (c != '\\') {
err = fputc(c, stdout);
}
else {
++i;
if (i >= len) {
return BC_STATUS_EXEC_INVALID_STRING;
}
c2 = str[i];
switch (c2) {
case 'a':
{
err = fputc('\a', stdout);
break;
}
case 'b':
{
err = fputc('\b', stdout);
break;
}
case 'e':
{
err = fputc('\\', stdout);
break;
}
case 'f':
{
err = fputc('\f', stdout);
break;
}
case 'n':
{
err = fputc('\n', stdout);
break;
}
case 'r':
{
err = fputc('\r', stdout);
break;
}
case 'q':
{
fputc('"', stdout);
break;
}
case 't':
{
err = fputc('\t', stdout);
break;
}
default:
{
// Do nothing.
err = 0;
break;
}
}
}
if (err == EOF) {
return BC_STATUS_EXEC_PRINT_ERR;
}
}
return BC_STATUS_SUCCESS;
}
static BcStatus bc_program_execExpr(BcProgram* p, BcVec* exprs,
BcNum* num, bool print)
{
#if 0
BcStatus status;
uint32_t idx;
BcExpr* expr;
BcTemp temp;
uint32_t temp_len;
fxdpnt* temp_num;
BcExprType etype;
BcTempType ttype;
BcTemp* temp_ptr;
status = BC_STATUS_SUCCESS;
temp_len = p->temps.len;
idx = exprs->len - 1;
while (idx < exprs->len) {
expr = bc_vec_item(exprs, idx);
if (!expr) {
return BC_STATUS_EXEC_INVALID_EXPR;
}
etype = expr->type;
switch (etype) {
case BC_EXPR_INC_PRE:
case BC_EXPR_DEC_PRE:
{
if (idx - 1 >= exprs->len) {
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
expr = bc_vec_item(exprs, idx - 1);
if (!expr) {
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
if (expr->type != BC_EXPR_VAR && expr->type != BC_EXPR_ARRAY_ELEM &&
!(expr->type < BC_EXPR_SCALE || expr->type > BC_EXPR_LAST))
{
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
status = bc_program_assign(p, expr, etype + BC_EXPR_ASSIGN_PLUS, p->one);
break;
}
case BC_EXPR_INC_POST:
case BC_EXPR_DEC_POST:
{
// TODO: Do this.
break;
}
case BC_EXPR_NEGATE:
{
char sign;
if (p->temps.len <= temp_len) {
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
temp_ptr = bc_vec_top(&p->temps);
if (!temp_ptr) {
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
sign = temp_ptr->num->sign;
temp_ptr->num->sign = sign == '+' ? '-' : '+';
break;
}
case BC_EXPR_POWER:
case BC_EXPR_MULTIPLY:
case BC_EXPR_DIVIDE:
case BC_EXPR_MODULUS:
case BC_EXPR_PLUS:
case BC_EXPR_MINUS:
{
BcTemp* a;
BcTemp* b;
BcTemp result;
BcMathOpFunc op;
if (p->temps.len < temp_len + 2) {
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
b = bc_vec_top(&p->temps);
if (!b) {
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
status = bc_vec_pop(&p->temps);
if (status) {
break;
}
a = bc_vec_top(&p->temps);
if (!a) {
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
status = bc_vec_pop(&p->temps);
if (status) {
break;
}
result.type = BC_TEMP_NUM;
result.num = arb_alloc(a->num->len + b->num->len);
// TODO: Handle scale.
op = bc_math_ops[etype - BC_EXPR_POWER];
result.num = op(a->num, b->num, result.num, 10, 0);
status = bc_vec_push(&p->temps, &result);
break;
}
case BC_EXPR_ASSIGN_POWER:
case BC_EXPR_ASSIGN_MULTIPLY:
case BC_EXPR_ASSIGN_DIVIDE:
case BC_EXPR_ASSIGN_MODULUS:
case BC_EXPR_ASSIGN_PLUS:
case BC_EXPR_ASSIGN_MINUS:
case BC_EXPR_ASSIGN:
{
// TODO: Get the amount.
status = bc_program_assign(p, expr, etype, NULL);
break;
}
case BC_EXPR_REL_EQUAL:
case BC_EXPR_REL_LESS_EQ:
case BC_EXPR_REL_GREATER_EQ:
case BC_EXPR_REL_NOT_EQ:
case BC_EXPR_REL_LESS:
case BC_EXPR_REL_GREATER:
{
break;
}
case BC_EXPR_BOOL_NOT:
{
break;
}
case BC_EXPR_BOOL_OR:
{
break;
}
case BC_EXPR_BOOL_AND:
{
break;
}
case BC_EXPR_NUMBER:
{
status = bc_temp_initNum(&temp, expr->string);
if (status) {
break;
}
status = bc_vec_push(&p->temps, &temp);
break;
}
case BC_EXPR_VAR:
{
break;
}
case BC_EXPR_ARRAY_ELEM:
{
break;
}
case BC_EXPR_FUNC_CALL:
{
break;
}
case BC_EXPR_SCALE_FUNC:
{
break;
}
case BC_EXPR_SCALE:
case BC_EXPR_IBASE:
case BC_EXPR_OBASE:
{
ttype = etype - BC_EXPR_SCALE + BC_TEMP_SCALE;
status = bc_temp_init(&temp, ttype);
if (status) {
break;
}
status = bc_vec_push(&p->temps, &temp);
break;
}
case BC_EXPR_LAST:
{
break;
}
case BC_EXPR_LENGTH:
{
break;
}
case BC_EXPR_READ:
{
status = bc_program_read(p);
break;
}
case BC_EXPR_SQRT:
{
status = bc_program_execExpr(p, expr->exprs, &temp_num, false);
if (status) {
break;
}
if (temp_num->sign != '-') {
status = bc_temp_initNum(&temp, NULL);
if (status) {
break;
}
arb_newton_sqrt(temp_num, temp.num, 10, p->scale);
}
else {
status = BC_STATUS_MATH_NEG_SQRT;
}
break;
}
case BC_EXPR_PRINT:
{
if (!print) {
break;
}
if (p->temps.len != temp_len + 1) {
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
temp_ptr = bc_vec_top(&p->temps);
arb_copy(p->last, temp_ptr->num);
arb_print(p->last);
status = bc_vec_pop(&p->temps);
break;
}
default:
{
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
}
--idx;
}
if (status) {
return status;
}
if (p->temps.len != temp_len) {
return BC_STATUS_EXEC_INVALID_EXPR;
}
return status;
#endif
return BC_STATUS_SUCCESS;
}
#if 0
static BcStatus bc_program_assign(BcProgram* p, BcExpr* expr,
BcExprType op, fxdpnt* amt)
{
BcStatus status;
fxdpnt* left;
switch (expr->type) {
case BC_EXPR_VAR:
{
break;
}
case BC_EXPR_ARRAY_ELEM:
{
break;
}
case BC_EXPR_SCALE:
{
break;
}
case BC_EXPR_IBASE:
{
break;
}
case BC_EXPR_OBASE:
{
break;
}
case BC_EXPR_LAST:
{
break;
}
default:
{
return BC_STATUS_EXEC_INVALID_EXPR;
}
}
switch (op) {
case BC_EXPR_ASSIGN_DIVIDE:
if (!arb_compare(amt, p->zero, 10)) {
return BC_STATUS_MATH_DIVIDE_BY_ZERO;
}
// Fallthrough.
case BC_EXPR_ASSIGN_POWER:
case BC_EXPR_ASSIGN_MULTIPLY:
case BC_EXPR_ASSIGN_MODULUS:
case BC_EXPR_ASSIGN_PLUS:
case BC_EXPR_ASSIGN_MINUS:
{
// TODO: Get the right scale.
left = bc_math_ops[op - BC_EXPR_ASSIGN_POWER](left, amt, left, 10, 10);
status = BC_STATUS_SUCCESS;
break;
}
case BC_EXPR_ASSIGN:
{
break;
}
default:
{
status = BC_STATUS_EXEC_INVALID_EXPR;
break;
}
}
return status;
}
#endif
static BcStatus bc_program_read(BcProgram* p) {
BcStatus status;
BcParse parse;
char* buffer;
BcVec exprs;
BcTemp temp;
size_t size;
BcVec code;
buffer = malloc(BC_PROGRAM_BUF_SIZE + 1);
if (!buffer) {
return BC_STATUS_MALLOC_FAIL;
}
status = bc_vec_init(&code, sizeof(uint8_t), NULL);
if (status) {
goto vec_err;
}
size = BC_PROGRAM_BUF_SIZE;
if (bc_io_getline(&buffer, &size) == BC_INVALID_IDX) {
status = BC_STATUS_IO_ERR;
goto io_err;
}
status = bc_parse_init(&parse, p);
if (status) {
goto io_err;
}
status = bc_parse_file(&parse, "<stdin>");
if (status) {
goto exec_err;
}
status = bc_parse_text(&parse, buffer);
if (status) {
goto exec_err;
}
status = bc_parse_expr(&parse, &code, false, false);
if (status != BC_STATUS_LEX_EOF && status != BC_STATUS_PARSE_EOF) {
status = status ? status : BC_STATUS_EXEC_INVALID_READ_EXPR;
goto exec_err;
}
temp.type = BC_TEMP_NUM;
status = bc_program_execExpr(p, &exprs, &temp.num, false);
if (status) {
goto exec_err;
}
status = bc_vec_push(&p->temps, &temp);
exec_err:
bc_parse_free(&parse);
io_err:
bc_vec_free(&code);
vec_err:
free(buffer);
return status;
}
static size_t bc_program_index(uint8_t* code, size_t* start) {
uint8_t bytes;
uint8_t byte;
size_t result;
bytes = code[++(*start)];
result = 0;
for (uint8_t i = 0; i < bytes; ++i) {
byte = code[++(*start)];
result |= (((size_t) byte) << (i * 8));
}
return result;
}
static void bc_program_printIndex(uint8_t* code, size_t* start) {
uint8_t bytes;
uint8_t byte;
bytes = code[++(*start)];
printf(bc_byte_fmt, bytes);
for (uint8_t i = 0; i < bytes; ++i) {
byte = code[++(*start)];
printf(bc_byte_fmt, byte);
}
}
static void bc_program_printName(uint8_t* code, size_t* start) {
char byte;
byte = code[++(*start)];
while (byte != ':') {
putchar(byte);
byte = code[++(*start)];
}
putchar(byte);
}