summary refs log tree commit diff
diff options
context:
space:
mode:
authorNakidai <nakidai@disroot.org>2025-03-25 02:01:10 +0300
committerNakidai <nakidai@disroot.org>2025-03-25 02:01:10 +0300
commit98a243bf9ab1a3e8bd2de56d7b16302f303f323a (patch)
tree86f9fd5125b0677b9964f9f66d540358285be374
parente8703c985af8cbe2de5eb235c7ec295ce1811c7f (diff)
download3cl-98a243bf9ab1a3e8bd2de56d7b16302f303f323a.tar.gz
3cl-98a243bf9ab1a3e8bd2de56d7b16302f303f323a.zip
Add almost done executor
-rw-r--r--Makefile1
-rw-r--r--cccl.c4
-rw-r--r--cccl.h32
-rw-r--r--executor.c252
-rw-r--r--main.c9
5 files changed, 294 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index d98e9bd..e503ccb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
 OBJS += cccl.o
+OBJS += executor.o
 OBJS += main.o
 OBJS += parser.o
 OBJS += readfile.o
diff --git a/cccl.c b/cccl.c
index eedea7c..64da3b1 100644
--- a/cccl.c
+++ b/cccl.c
@@ -11,5 +11,9 @@ void cccl(struct cccl_File file)
     size_t tokens_amount = cccl_tokenize(file.buffer, file.size, tokens, TOKENS_LIMIT);
     if (verbose)
         fprintf(stderr, "Read: %lu\n", tokens_amount);
+
     struct cccl_Node *parsed = cccl_parse(tokens, tokens_amount, 0, 0);
+
+    struct cccl_Variables scope;
+    cccl_execute(parsed, &scope);
 }
diff --git a/cccl.h b/cccl.h
index 48ad499..37b0970 100644
--- a/cccl.h
+++ b/cccl.h
@@ -6,8 +6,6 @@
 
 #define TOKENS_LIMIT 16384
 
-extern int verbose;
-
 struct cccl_File
 {
     char *buffer;
@@ -63,10 +61,40 @@ struct cccl_Node
     char value;
 };
 
+enum cccl_ExecutorStatus
+{
+    cccl_Executr_OK = 0,
+    cccl_Executor_ERROR,
+    cccl_EXECUTOR_CONTINUE,
+    cccl_Executor_END,
+};
+
+struct cccl_Variables
+{
+    short buffer[52];
+    char used[52];
+};
+
+struct cccl_Function
+{
+    struct cccl_Node **body;
+    size_t length;
+};
+
+struct cccl_Stack
+{
+    short *buffer;
+    size_t length;
+    size_t allocated;
+};
+
+extern int verbose;
+
 int cccl_allocfile(const char *path, struct cccl_File *file);
 
 void cccl(struct cccl_File file);
 size_t cccl_tokenize(const char *code, size_t size, struct cccl_Token tokens[], size_t tokens_length);
 struct cccl_Node *cccl_parse(struct cccl_Token tokens[], size_t tokens_length, enum cccl_NodeType type, char value);
+enum cccl_ExecutorStatus cccl_execute(struct cccl_Node *code, struct cccl_Variables *scope);
 
 #endif /* __CCCL_H__ */
diff --git a/executor.c b/executor.c
new file mode 100644
index 0000000..0458f1c
--- /dev/null
+++ b/executor.c
@@ -0,0 +1,252 @@
+#include "cccl.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static struct cccl_Variables globals = {0};
+static struct cccl_Function functions[52] = {0};
+static struct cccl_Stack stack = {0};
+
+static void expand_stack(void)
+{
+    if (!stack.buffer)
+    {
+        stack.allocated = sizeof(*stack.buffer) * stack.length;
+        stack.buffer = malloc(stack.allocated);
+    } else if (stack.length > stack.allocated / sizeof(*stack.buffer))
+    {
+        stack.allocated = sizeof(*stack.buffer) * stack.length;
+        stack.buffer = realloc(stack.buffer, stack.allocated);
+    }
+    assert(stack.buffer && "buy more ram");
+}
+
+static size_t geti(char name)
+{
+    return islower(name) ? name - 'a' : name - 'A' + 26;
+}
+
+static short *get_variable(char name, struct cccl_Variables *scope)
+{
+    size_t i = geti(name);
+    if (scope->used[i])
+        return &scope->buffer[i];
+    if (globals.used[i])
+        return &globals.buffer[i];
+    return NULL;
+}
+
+enum cccl_ExecutorStatus cccl_execute(struct cccl_Node *code, struct cccl_Variables *scope)
+{
+    switch (code->type)
+    {
+    case cccl_Node_CODE:
+    {
+        int res;
+        for (size_t i = 0; i < code->in_length; ++i)
+            if ((res = cccl_execute(code->in[i], scope)) != 0)
+                goto code_end;
+code_end:
+        if (res == cccl_Executor_ERROR)
+            return res;
+    } break;
+    case cccl_Node_PUSHZERO:
+    {
+        ++stack.length;
+        expand_stack();
+        stack.buffer[stack.length - 1] = 0;
+    } break;
+    case cccl_Node_INCREMENT:
+    {
+        assert(stack.length >= 1);
+        ++stack.buffer[stack.length - 1];
+    } break;
+    case cccl_Node_DECREMENT:
+    {
+        assert(stack.length >= 1);
+        --stack.buffer[stack.length - 1];
+    } break;
+    case cccl_Node_ADD:
+    {
+        --stack.length;
+        stack.buffer[stack.length - 1] += stack.buffer[stack.length];
+    } break;
+    case cccl_Node_SUBTRACT:
+    {
+        --stack.length;
+        stack.buffer[stack.length - 1] -= stack.buffer[stack.length];
+    } break;
+    case cccl_Node_REVERSE:
+    {
+        size_t torev;
+        if (code->value == '_')
+        {
+            torev = stack.length;
+        } else
+        {
+            short *p = get_variable(code->value, scope);
+            if (!p)
+                errx(1, "Variable %c doesn't exist!", code->value);
+            if (*p > stack.length || *p < 0)
+                errx(1, "Cannot reverse %d elements in a stack of length %lu", *p, stack.length);
+            torev = *p;
+        }
+
+        short *buffer = stack.buffer + (stack.length - torev);
+        for (size_t i = 0; i < torev / 2; ++i)
+        {
+            buffer[i] ^= buffer[torev - i - 1];
+            buffer[torev - i - 1] ^= buffer[i];
+            buffer[i] ^= buffer[torev - i - 1];
+        }
+    } break;
+    case cccl_Node_ASSIGN:
+    {
+        assert(stack.length >= 1);
+        --stack.length;
+        if (code->value == '_')
+            break;
+
+        size_t i = geti(code->value);
+        short *p = get_variable(code->value, scope);
+        if (!p)
+        {
+            globals.used[i] = 1;
+            p = &globals.buffer[i];
+        }
+        *p = stack.buffer[stack.length];
+    } break;
+    case cccl_Node_DELETE:
+    {
+        if (code->value == '_')
+            errx(1, "_ is not allowed with '%c'", '!');
+
+        size_t i = geti(code->value);
+        if (scope->used[i])
+            scope->used[i] = 0;
+        else if (!globals.used[i])
+            errx(1, "Cannot delete non-existent variable %c", code->value);
+        else
+            globals.used[i] = 0;
+    } break;
+    case cccl_Node_PUSHVAR:
+    {
+        ++stack.length;
+        expand_stack();
+
+        if (code->value == '_')
+            errx(1, "_ is not allowed with '%c'", '$');
+
+        short *p = get_variable(code->value, scope);
+        if (!p)
+            errx(1, "Cannot push %c on the stack is it doesn't exist", code->value);
+        stack.buffer[stack.length - 1] = *p;
+    } break;
+    case cccl_Node_ASSIGNLOCAL:
+    {
+        if (code->value == '_')
+            errx(1, "_ is not allowed with '%c'", '&');
+
+        size_t i = geti(code->value);
+        scope->used[i] = 1;
+        scope->buffer[i] = 0;
+    } break;
+    case cccl_Node_OUTPUT:
+    {
+        if (code->value == '_')
+            errx(1, "_ is not allowed with '%c'", '<');
+
+        short *p = get_variable(code->value, scope);
+        if (!p)
+            errx(1, "Cannot print non-existent variable %c", code->value);
+
+        putchar(*p);
+    } break;
+    case cccl_Node_INPUT:
+    {
+        if (code->value == '_')
+            errx(1, "_ is not allowed with '%c'", '>');
+
+        short *p = get_variable(code->value, scope);
+        if (!p)
+            errx(1, "Cannot save input in a non-existent variable %c", code->value);
+
+        int c = getchar();
+        if (c < 0)
+            err(1, "getchar()");
+
+        *p = c;
+    } break;
+    case cccl_Node_PROCEDURE:
+    {
+        functions[geti(code->value)] = (struct cccl_Function)
+        {
+            .body = code->in,
+            .length = code->in_length,
+        };
+    } break;
+    case cccl_Node_CALL:
+    {
+        if (functions[geti(code->value)].body == NULL)
+            errx(1, "Cannot call non-existent function %c", code->value);
+
+        size_t i = geti(code->value);
+        struct cccl_Variables localscope = {0};
+        int res;
+        for (size_t j = 0; j < functions[i].length; ++j)
+            if ((res = cccl_execute(functions[i].body[j], &localscope)) != 0)
+                goto call_end;
+call_end:
+        if (res == cccl_Executor_ERROR)
+            return res;
+    } break;
+    case cccl_Node_INFINITE:
+    {
+        int res;
+        if (code->value == '_')
+            for (;;)
+                for (size_t i = 0; i < code->in_length; ++i)
+                    if ((res = cccl_execute(code->in[i], scope)) != 0)
+                        goto infinite_end;
+
+        short *p = get_variable(code->value, scope);
+        if (!p)
+            errx(1, "Cannot loop using non-existent variable %c", code->value);
+
+        while (*p > 0)
+            for (size_t i = 0; i < code->in_length; ++i)
+                if ((res = cccl_execute(code->in[i], scope)) != 0)
+                    goto infinite_end;
+infinite_end:
+        if (res == cccl_Executor_ERROR)
+            return res;
+    } break;
+    case cccl_Node_REPEAT:
+    {
+        short *p = get_variable(code->value, scope);
+        if (!p)
+            errx(1, "Cannot loop using non-existent variable %c", code->value);
+        else if (*p < 0)
+            errx(1, "Cannot iterate %c=%d times", code->value, *p);
+
+        int res;
+        for (size_t i = 0; i < *p; ++i)
+            for (size_t j = 0; j < code->in_length; ++j)
+                if ((res = cccl_execute(code->in[j], scope)) != 0)
+                    goto repeat_end;
+repeat_end:
+        if (res == cccl_Executor_ERROR)
+            return res;
+    };
+    case cccl_Node_CONDITIONAL:
+    {
+    } break;
+    }
+
+    return 0;
+}
diff --git a/main.c b/main.c
index 262e9b6..b2d96ca 100644
--- a/main.c
+++ b/main.c
@@ -12,6 +12,8 @@ int verbose = 0;
 
 int main(int argc, char **argv)
 {
+    const char *name = *argv;
+
     int ch;
     while ((ch = getopt(argc, argv, "v")) >= 0)
     {
@@ -23,7 +25,7 @@ int main(int argc, char **argv)
             } break;
             default:
             {
-                fprintf(stderr, "usage: %s [-v] file\n", argv[0]);
+                fprintf(stderr, "usage: %s [-v] file\n", name);
                 exit(1);
             } break;
         }
@@ -32,7 +34,10 @@ int main(int argc, char **argv)
     argv += optind;
 
     if (!*argv)
-        return 1;
+    {
+        fprintf(stderr, "usage: %s [-v] file\n", name);
+        exit(1);
+    }
 
     struct cccl_File file;