crepl

An intuitive calculator REPL.
git clone git://git.knutsen.co/crepl
Log | Files | Refs | README | LICENSE

commit 397d47a11a34b9e1dd15971985186591c63e6bbd
parent e59d4e78bf59675ec4697a065b4453088e01d8ad
Author: Demonstrandum <moi@knutsen.co>
Date:   Thu, 25 Jun 2020 13:38:16 +0100

Use floats to compute large factorials, add floor and ceil.

Diffstat:
Msrc/builtin.c | 41+++++++++++++++++++++++++++++++++++------
Msrc/builtin.h | 7+++++++
Msrc/error.c | 2+-
Msrc/main.c | 2+-
Msrc/parse.c | 2--
5 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/src/builtin.c b/src/builtin.c @@ -117,31 +117,60 @@ MATH_WRAPPER(atanh, atanhl) MATH_WRAPPER(ceil, ceil) MATH_WRAPPER(floor, floor) +DataValue *builtin_neg(DataValue input) +{ + NumberNode *num = type_check("-", RHS, T_NUMBER, &input); + if (num == NULL) + return NULL; + NumberNode *new_num = malloc(sizeof(NumberNode)); + memcpy(new_num, num, sizeof(NumberNode)); + switch (new_num->type) { + case INT: { + new_num->value.i *= -1; + break; + } + case FLOAT: { + new_num->value.f *= -1.0f; + break; + } + default: { + ERROR_TYPE = TYPE_ERROR; + strcpy(ERROR_MSG, "Unsupported number type."); + return NULL; + } + } + DataValue *result = wrap_data(T_NUMBER, new_num); + return result; +} + DataValue *builtin_factorial(DataValue input) { NumberNode *num = type_check("!", LHS, T_NUMBER, &input); if (num == NULL) return NULL; - if (num->type != INT || num->value.i < 0) { + f32 integral = 0; + f32 fractional = modff(num->value.f, &integral); + if ((num->type == FLOAT && (fractional != 0 || num->value.f < 0)) + || (num->type == INT && num->value.i < 0)) { ERROR_TYPE = EXECUTION_ERROR; strcpy(ERROR_MSG, "factorial (`!') is only defined for positve integers."); } - NumberNode tmp = num_to_int(*num); + NumberNode tmp = num_to_float(*num); NumberNode *new_num = malloc(sizeof(NumberNode)); memcpy(new_num, &tmp, sizeof(NumberNode)); DataValue *result = wrap_data(T_NUMBER, new_num); - if (new_num->value.i == 0) { - new_num->value.i = 1; + if (new_num->value.f == 0) { + new_num->value.f = 1; result->value = new_num; return result; } - ssize i = new_num->value.i - 1; + ssize i = new_num->value.f - 1; while (i > 1) { - new_num->value.i *= i; + new_num->value.f *= i; --i; } result->value = new_num; diff --git a/src/builtin.h b/src/builtin.h @@ -30,7 +30,10 @@ DataValue *builtin_asin(DataValue); DataValue *builtin_asinh(DataValue); DataValue *builtin_atan(DataValue); DataValue *builtin_atanh(DataValue); +DataValue *builtin_ceil(DataValue); +DataValue *builtin_floor(DataValue); DataValue *builtin_factorial(DataValue); +DataValue *builtin_neg(DataValue); NumberNode *num_add(NumberNode, NumberNode); NumberNode *num_sub(NumberNode, NumberNode); @@ -72,7 +75,11 @@ static const struct _func_name_pair builtin_fns[] = { { "arctan", { builtin_atan } }, FUNC_PAIR(atanh), { "arctanh", { builtin_atanh } }, + FUNC_PAIR(ceil), + FUNC_PAIR(floor), FUNC_PAIR(factorial), { "!", { builtin_factorial } }, + FUNC_PAIR(neg), + { "-", { builtin_neg } }, }; diff --git a/src/error.c b/src/error.c @@ -31,7 +31,7 @@ void handle_error() if (ERROR_TYPE == NO_ERROR) return; // Display error. - printf("\033[31;1m%s\033[0m: %s\n", + fprintf(stderr, "\033[31;1m%s\033[0m: %s\n", error_name(ERROR_TYPE), ERROR_MSG); // Reset error values. diff --git a/src/main.c b/src/main.c @@ -88,7 +88,7 @@ int main(int argc, char **argv) printf("\033[%luC\033[1A", strlen(PROMPT) + strlen(response)); - printf("\033[2m ≡ %s\n\033[0m", display_parsetree(tree)); + printf("\033[2m ≡ %s\033[0m\n", display_parsetree(tree)); DataValue *result = execute(ctx, tree); diff --git a/src/parse.c b/src/parse.c @@ -312,8 +312,6 @@ ParseNode *parse_prefix(const Token *token, char **rest) node->type = UNARY_NODE; node->node.unary = *unary; - printf("Parsed prefix as: %s\n\n", display_parsetree(node)); - break; } case TT_LPAREN: {