crepl

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

commit 698df4516bb7a9224a726dc5117ae60ae156d21a
parent 520534baedc529ed128876adbf70be26eb0de73e
Author: Demonstrandum <moi@knutsen.co>
Date:   Thu, 25 Jun 2020 01:15:17 +0100

Added functions 'sin' and 'factorial'

Diffstat:
Msrc/builtin.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/builtin.h | 7+++++++
Msrc/execute.c | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/execute.h | 15+++++++++++++--
Msrc/main.c | 2+-
Msrc/parse.c | 21+++++++++++++++++++++
Msrc/parse.h | 1+
7 files changed, 160 insertions(+), 19 deletions(-)

diff --git a/src/builtin.c b/src/builtin.c @@ -75,6 +75,56 @@ NumberNode *upcast_pair(NumberNode lhs, NumberNode rhs) return pair; } +DataValue *builtin_sin(DataValue input) +{ + NumberNode *num = type_check("sin", ARG, T_NUMBER, &input); + if (num == NULL) + return NULL; + DataValue *result = wrap_data(T_NUMBER, num); + + NumberNode tmp = num_to_float(*num); + memcpy(num, &tmp, sizeof(NumberNode)); + num->value.f = sin(num->value.f); + num->type = FLOAT; + result->value = 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) { + ERROR_TYPE = EXECUTION_ERROR; + strcpy(ERROR_MSG, + "factorial (`!') is only defined for positve integers."); + } + + NumberNode tmp = num_to_int(*num); + memcpy(num, &tmp, sizeof(NumberNode)); + + DataValue *result = wrap_data(T_NUMBER, num); + if (num->value.i == 0) { + num->value.i = 1; + result->value = num; + return result; + } + ssize i = num->value.i - 1; + while (i > 1) { + num->value.i *= i; + --i; + } + result->value = num; + return result; +} + +FnPtr builtin_fns[] = { + { builtin_sin }, + { builtin_factorial }, +}; + #define BINARY_FUNCTION(NAME, OP) \ NumberNode *num_ ## NAME (NumberNode lhs, NumberNode rhs) \ { \ diff --git a/src/builtin.h b/src/builtin.h @@ -1,13 +1,20 @@ #pragma once +#include <math.h> + #include "prelude.h" #include "parse.h" +#include "execute.h" #include "error.h" NumberNode num_to_float(NumberNode); NumberNode num_to_int(NumberNode); NumberNode *upcast_pair(NumberNode, NumberNode); +DataValue *builtin_sin(DataValue); + +extern FnPtr builtin_fns[]; + NumberNode *num_add(NumberNode, NumberNode); NumberNode *num_sub(NumberNode, NumberNode); NumberNode *num_mul(NumberNode, NumberNode); diff --git a/src/execute.c b/src/execute.c @@ -4,7 +4,9 @@ #include "builtin.h" #include "displays.h" -#define BINARY_OPERATION(OPERATION) do { \ +#include <math.h> + +#define NUMERICAL_BINARY_OPERATION(OPERATION) do { \ NumberNode *l_num = type_check("+", LHS, T_NUMBER, lhs); \ NumberNode *r_num = type_check("+", RHS, T_NUMBER, rhs); \ if (l_num == NULL || r_num == NULL) \ @@ -35,28 +37,24 @@ DataValue *execute(Context *ctx, const ParseNode *stmt) // throw an execution error. char *ident_name = stmt->node.ident.value; - free(data); - data = NULL; - Context *current_ctx = ctx; while (current_ctx != NULL) { for (usize i = 0; i < current_ctx->locals_count; ++i) { Local *local = &current_ctx->locals[i]; if (strcmp(local->name, ident_name) == 0) { - data = &local->value; + *data = local->value; goto finished_search; } } current_ctx = current_ctx->superior; } + ERROR_TYPE = EXECUTION_ERROR; + sprintf(ERROR_MSG, "Could not find variable `%s'\n" + " in any local or superior scope.", ident_name); + return NULL; + finished_search: - if (data == NULL) { - ERROR_TYPE = EXECUTION_ERROR; - sprintf(ERROR_MSG, "Could not find variable `%s'\n" - " in any local or superior scope.", ident_name); - return NULL; - } break; } case NUMBER_NODE: { @@ -65,6 +63,32 @@ finished_search: memcpy(data->value, &stmt->node.number, sizeof(NumberNode)); break; } + case UNARY_NODE: { // Functions, essentially. + DataValue *callee = execute(ctx, stmt->node.unary.callee); + DataValue *operand = execute(ctx, stmt->node.unary.operand); + + if (callee == NULL || operand == NULL) + return NULL; + + // Juxtaposition of numbers, implies multiplication. + if (callee->type == T_NUMBER && operand->type == T_NUMBER) { + data->type = T_NUMBER; + data->value = num_mul(*(NumberNode *)callee->value, + *(NumberNode *)operand->value); + break; + } + + // Otheriwse, we expect a function pointer as callee. + FnPtr *func = type_check("function", ARG, T_FUNCTION_PTR, callee); + if (func == NULL) + return NULL; + + FUNC_PTR(fn) = func->fn; + free(data); + data = fn(*operand); + + break; + } case BINARY_NODE: { IdentNode ident = stmt->node.binary.callee->node.ident; if (stmt->node.binary.callee->type != IDENT_NODE) { @@ -78,13 +102,13 @@ finished_search: DataValue *rhs = execute(ctx, stmt->node.binary.right); if (strcmp(op, "+") == 0) { - BINARY_OPERATION(add); + NUMERICAL_BINARY_OPERATION(add); } else if (strcmp(op, "-") == 0) { - BINARY_OPERATION(sub); + NUMERICAL_BINARY_OPERATION(sub); } else if (strcmp(op, "*") == 0) { - BINARY_OPERATION(mul); + NUMERICAL_BINARY_OPERATION(mul); } else if (strcmp(op, "/") == 0) { - BINARY_OPERATION(div); + NUMERICAL_BINARY_OPERATION(div); } else { ERROR_TYPE = EXECUTION_ERROR; sprintf(ERROR_MSG, "Do not know how to evaluate" @@ -140,6 +164,25 @@ Local *make_local(char *name, DataType type, void *value) return local; } +void bind_local(Context *ctx, char *name, DataType type, void *value) +{ + Local *local = make_local(name, type, value); + ctx->locals[ctx->locals_count] = *local; + ++ctx->locals_count; +} + +void bind_builtin_functions(Context *ctx) +{ + bind_local(ctx, "sin", T_FUNCTION_PTR, &builtin_fns[0]); + bind_local(ctx, "!", T_FUNCTION_PTR, &builtin_fns[1]); +} + +void bind_default_globals(Context *ctx) +{ + fsize pi = M_PI; + bind_local(ctx, "pi", T_NUMBER, make_number(FLOAT, &pi)); +} + Context *init_context() { Context *ctx = malloc(sizeof(Context)); @@ -157,13 +200,21 @@ Context *init_context() // name of the function/scope. Local *scope_name = make_local( "__this_scope", T_STRING, ctx->function); - ctx->locals = scope_name; + ctx->locals[0] = *scope_name; // ^ Sets the first variable, default in every scope // (good for debuggin purposes). return ctx; } +Context *base_context() +{ + Context *ctx = init_context(); + bind_default_globals(ctx); + bind_builtin_functions(ctx); + return ctx; +} + Context *make_context(char *scope_name, Context *super_scope) { Context *ctx = init_context(); diff --git a/src/execute.h b/src/execute.h @@ -5,8 +5,8 @@ typedef enum { T_NUMBER, // NumberNode (ParsNode). - T_STRING, // (Native?) char pointer. - T_FUNCTION_PTR, // Native function pointer. + T_STRING, // Native char pointer. + T_FUNCTION_PTR, // Wrapper of native function pointer. } DataType; typedef struct { @@ -14,6 +14,13 @@ typedef struct { void *value; } DataValue; +#define FUNC_PTR(FUNC_NAME) \ + DataValue *(*FUNC_NAME)(DataValue) + +typedef struct { + FUNC_PTR(fn); +} FnPtr; + typedef struct { char *name; DataValue value; @@ -37,6 +44,10 @@ typedef enum { void free_datavalue(DataValue *); void *type_check(char *, ParamPos, DataType, DataValue *); DataValue *execute(Context *, const ParseNode *); +DataValue *wrap_data(DataType, void *); Local *make_local(char *, DataType, void *); +void bind_local(Context *, char *name, DataType, void*); +void bind_builtin_functions(Context *); Context *init_context(); +Context *base_context(); Context *make_context(char *, Context *); diff --git a/src/main.c b/src/main.c @@ -63,7 +63,7 @@ int main(int argc, char **argv) printf("Reading history from `%s'.\n", cache_loc); } - Context *ctx = init_context(); + Context *ctx = base_context(); char *response = NULL; do { diff --git a/src/parse.c b/src/parse.c @@ -178,6 +178,27 @@ void node_into_ident(const char *str, ParseNode *node) node->node.ident = *ident; } +NumberNode *make_number(NumberType type, void *val) +{ + NumberNode *num = malloc(sizeof(NumberNode)); + num->type = type; + num->value.i = -1; + switch (type) { + case INT: { + num->value.i = *(ssize *)val; + break; + } + case FLOAT: { + num->value.f = *((fsize *)val); + break; + } + default: + printf("Never get here!\n\n"); + break; + } + return num; +} + NumberNode *parse_number(const char *str) { NumberNode *number = malloc(sizeof(NumberNode)); diff --git a/src/parse.h b/src/parse.h @@ -123,6 +123,7 @@ void free_parsenode(ParseNode *); Token *lex(char **); Token *peek(char **); +NumberNode *make_number(NumberType, void *); NumberNode *parse_number(const char *); ParseNode *parse_prefix(const Token *, char **); ParseNode *parse_infix(const ParseNode *, const Token *, char **, u16);