commit 55078ff21d52c4ba961f6a33eae4af60bdd2d05f
parent 3b01d7d6fc61e75421d6133e505b709f7c605c58
Author: Demonstrandum <moi@knutsen.co>
Date: Wed, 24 Jun 2020 12:54:13 +0100
Added execution and addition capability
Diffstat:
8 files changed, 241 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,5 +1,7 @@
CC := gcc
-CFLAGS := -Wall -Wpedantic
+OPT := -O3
+WARN := -Wall -Wpedantic -Wextra -Wshadow
+CFLAGS := $(WARN) $(OPT)
TARGET := crepl
OBJS := main.o prelude.o parse.o displays.o error.o execute.o
LINKS := -lm -lreadline
@@ -11,8 +13,11 @@ endif
all: clean $(TARGET)
@printf "\033[1mBuilt \`$(TARGET)' successfully.\033[0m\n"
+debug: $(OBJS)
+ $(CC) -Og -o $(TARGET) $(LINKS) $(OBJS)
+
$(TARGET): $(OBJS)
- $(CC) -o $(TARGET) $(LINKS) $(OBJS)
+ $(CC) $(OPT) -o $(TARGET) $(LINKS) $(OBJS)
install: $(TARGET)
@echo "Installing to $(PREFIX)/bin/$(TARGET)."
@@ -25,7 +30,6 @@ main.o: prelude.o parse.o error.o
prelude.o: error.o
$(CC) -c $(CFLAGS) src/prelude.c
-
parse.o: error.o
$(CC) -c $(CFLAGS) src/parse.c
diff --git a/src/displays.c b/src/displays.c
@@ -4,8 +4,35 @@
#include "prelude.h"
#include "parse.h"
+#include "execute.h"
#include "displays.h"
+char *display_parampos(ParamPos pos)
+{
+ switch (pos) {
+ case LHS:
+ return "left-hand-side";
+ case RHS:
+ return "right-hand-side";
+ default:
+ return "argument";
+ }
+}
+
+char *display_datatype(DataType type)
+{
+ switch (type) {
+ case T_NUMBER:
+ return "number";
+ case T_FUNCTION_PTR:
+ return "function";
+ case T_STRING:
+ return "text-string";
+ default:
+ return "unknown-type";
+ }
+}
+
char *display_parsetree(const ParseNode *tree)
{
if (tree == NULL)
@@ -53,3 +80,23 @@ char *display_parsetree(const ParseNode *tree)
return "[Unknown Parse Node]";
}
}
+
+char *display_datavalue(const DataValue *data)
+{
+ // Safe bet.
+ char *string = malloc(sizeof(char) * 512);
+
+ switch (data->type) {
+ case T_NUMBER: {
+ NumberNode *num = data->value;
+ // TODO: Handle more than just INT type.
+ sprintf(string, "%ld", num->value.i);
+ break;
+ }
+ default:
+ sprintf(string, "<%s at 0x%p>",
+ display_datatype(data->type),
+ data->value);
+ }
+ return string;
+}
diff --git a/src/displays.h b/src/displays.h
@@ -1,3 +1,7 @@
#include "parse.h"
+#include "execute.h"
+char *display_parampos(ParamPos _);
+char *display_datatype(DataType _);
char *display_parsetree(const ParseNode *);
+char *display_datavalue(const DataValue *);
diff --git a/src/error.c b/src/error.c
@@ -12,6 +12,8 @@ const char *error_name(error_t err)
return "Syntax Error";
case PARSE_ERROR:
return "Grammar Error";
+ case TYPE_ERROR:
+ return "Type Error";
case EXECUTION_ERROR:
return "Error while executing";
default:
@@ -26,6 +28,8 @@ char ERROR_MSG[256] = DEFAULT_ERROR_MSG;
void handle_error()
{
+ if (ERROR_TYPE == NO_ERROR)
+ return;
// Display error.
printf("\033[31;1m%s\033[0m: %s\n",
error_name(ERROR_TYPE),
diff --git a/src/error.h b/src/error.h
@@ -4,6 +4,7 @@ typedef enum {
NO_ERROR,
SYNTAX_ERROR,
PARSE_ERROR,
+ TYPE_ERROR,
EXECUTION_ERROR,
} error_t;
diff --git a/src/execute.c b/src/execute.c
@@ -1 +1,125 @@
#include "execute.h"
+#include "error.h"
+#include "parse.h"
+#include "displays.h"
+
+/// Takes in an execution context (ctx) and a
+/// statement as produced by the parser (stmt).
+/// Returns what it evaluates to.
+DataValue *execute(Context *ctx, const ParseNode *stmt)
+{
+ DataValue *data = malloc(sizeof(DataValue));
+ switch (stmt->type) {
+ case NUMBER_NODE: {
+ data->type = T_NUMBER;
+ data->value = malloc(sizeof(NumberNode));
+ memcpy(data->value, &stmt->node.number, sizeof(NumberNode));
+ break;
+ }
+ case BINARY_NODE: {
+ IdentNode ident = stmt->node.binary.callee->node.ident;
+ if (stmt->node.binary.callee->type != IDENT_NODE) {
+ ERROR_TYPE = EXECUTION_ERROR;
+ strcpy(ERROR_MSG, "Binary operation has non-ident callee.");
+ return NULL;
+ }
+ // How to evaluate specific operators.
+ char *op = ident.value;
+ DataValue *lhs = execute(ctx, stmt->node.binary.left);
+ DataValue *rhs = execute(ctx, stmt->node.binary.right);
+
+ if (strcmp(op, "+") == 0) {
+ 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)
+ return NULL;
+ // TODO: Handle more numbers tham just INTs.
+ NumberNode *result_num = malloc(sizeof(NumberNode));
+ memcpy(result_num, l_num, sizeof(NumberNode));
+ // Finally, the addition is performed.
+ result_num->value.i = l_num->value.i + r_num->value.i;
+ data->type = T_NUMBER;
+ data->value = result_num;
+ } else if (strcmp(op, "-") == 0) {
+
+ } else {
+ ERROR_TYPE = EXECUTION_ERROR;
+ sprintf(ERROR_MSG, "Do not know how to evaluate"
+ " use of `%s' operator.", op);
+ return NULL;
+ }
+ break;
+ }
+ default: {
+ ERROR_TYPE = EXECUTION_ERROR;
+ strcpy(ERROR_MSG,
+ "Could not execute statement for unknown reason.");
+ return NULL;
+ }
+ }
+ return data;
+}
+
+DataValue *wrap_data(DataType type, void *value)
+{
+ DataValue *data = malloc(sizeof(DataValue));
+ data->type = type;
+ data->value = value;
+ return data;
+}
+
+void *type_check(char *function_name, ParamPos pos,
+ DataType type, DataValue *value)
+{
+ if (value->type == type) {
+ return value->value;
+ }
+ ERROR_TYPE = TYPE_ERROR;
+ sprintf(ERROR_MSG, "Wrong type for %s of `%s' operation,"
+ " needed type of `%s'.",
+ display_parampos(pos),
+ function_name,
+ display_datatype(type));
+ return NULL;
+}
+
+Local *make_local(char *name, DataType type, void *value)
+{
+ Local *local = malloc(sizeof(Local));
+ local->name = name;
+ local->value.type = type;
+ local->value.value = value;
+ return local;
+}
+
+Context *init_context()
+{
+ Context *ctx = malloc(sizeof(Context));
+ ctx->superior = NULL; // There is no context superior to this one.
+ ctx->function = "<main>"; // Main function/scope.
+
+ // Initialise with 16 free spaces for local variables.
+ // This may have to be reallocated if more than 16
+ // variables need to exist :^).
+ ctx->locals_count = 1;
+ ctx->locals_capacity = 16;
+ ctx->locals = malloc(sizeof(Local) * ctx->locals_capacity);
+
+ // Create an initial local varaible with the value of the
+ // name of the function/scope.
+ Local *scope_name = make_local(
+ "__this_scope", T_STRING, ctx->function);
+ ctx->locals = scope_name;
+ // ^ Sets the first variable, default in every scope
+ // (good for debuggin purposes).
+
+ return ctx;
+}
+
+Context *make_context(char *scope_name, Context *super_scope)
+{
+ Context *ctx = init_context();
+ ctx->function = scope_name;
+ ctx->superior = super_scope;
+ return ctx;
+}
diff --git a/src/execute.h b/src/execute.h
@@ -1 +1,41 @@
+#pragma once
+
#include "prelude.h"
+#include "parse.h"
+
+typedef enum {
+ T_NUMBER, // NumberNode (ParsNode).
+ T_STRING, // (Native?) char pointer.
+ T_FUNCTION_PTR, // Native function pointer.
+} DataType;
+
+typedef struct {
+ DataType type;
+ void *value;
+} DataValue;
+
+typedef struct {
+ char *name;
+ DataValue value;
+} Local;
+
+struct _context;
+
+typedef struct _context {
+ struct _context *superior;
+ char *function;
+ // `locals` works as a dynamic array;
+ usize locals_count;
+ usize locals_capacity;
+ Local *locals;
+} Context;
+
+typedef enum {
+ ARG, LHS, RHS
+} ParamPos;
+
+void *type_check(char *, ParamPos, DataType, DataValue *);
+DataValue *execute(Context *, const ParseNode *);
+Local *make_local(char *, DataType, void *);
+Context *init_context();
+Context *make_context(char *, Context *);
diff --git a/src/main.c b/src/main.c
@@ -10,6 +10,7 @@
#include "prelude.h"
#include "error.h"
#include "parse.h"
+#include "execute.h"
#include "displays.h"
static const char *PROMPT = "::> ";
@@ -34,7 +35,7 @@ int main(int argc, char **argv)
// Configure readline.
rl_clear_signals();
- rl_bind_key('\t', rl_insert);
+ rl_bind_key('\t', rl_complete);
signal(SIGINT, sigint_handle);
// Create or fetch history file.
@@ -50,6 +51,8 @@ int main(int argc, char **argv)
strcat(cache_loc, "/crepl.history");
read_history(cache_loc);
+ Context *ctx = init_context();
+
char *response = NULL;
do {
char *line = readline(PROMPT);
@@ -65,18 +68,25 @@ int main(int argc, char **argv)
// Try to lex & parse the input.
ParseNode *tree = parse(response);
- if (ERROR_TYPE != NO_ERROR) {
+ if (tree == NULL || ERROR_TYPE != NO_ERROR) {
handle_error();
continue;
}
- if (tree == NULL) continue;
+ DataValue *result = execute(ctx, tree);
+
+ if (result == NULL || ERROR_TYPE != NO_ERROR) {
+ handle_error();
+ continue;
+ }
printf("\033[%luC\033[1A", strlen(PROMPT) + strlen(response));
printf(" ≡ %s\n", display_parsetree(tree));
- printf("#=> %s\n", response);
+ printf("#=> %s\n", display_datavalue(result));
+ //free_datavalue(result);
free_parsenode(tree);
+ free(response);
} while (true);
write_history(cache_loc);