summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--cccl.c4
-rw-r--r--cccl.h8
-rw-r--r--executor.c96
-rw-r--r--parser.c6
-rw-r--r--str.c57
6 files changed, 131 insertions, 41 deletions
diff --git a/Makefile b/Makefile
index e503ccb..a1a5d01 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ OBJS += executor.o
 OBJS += main.o
 OBJS += parser.o
 OBJS += readfile.o
+OBJS += str.o
 OBJS += tokenizer.o
 
 RM ?= rm -f
diff --git a/cccl.c b/cccl.c
index 64da3b1..234fa7e 100644
--- a/cccl.c
+++ b/cccl.c
@@ -14,6 +14,6 @@ void cccl(struct cccl_File file)
 
     struct cccl_Node *parsed = cccl_parse(tokens, tokens_amount, 0, 0);
 
-    struct cccl_Variables scope;
-    cccl_execute(parsed, &scope);
+    struct cccl_Variables scope = {0};
+    cccl_execute(parsed, &scope, 0);
 }
diff --git a/cccl.h b/cccl.h
index 37b0970..5452b26 100644
--- a/cccl.h
+++ b/cccl.h
@@ -65,7 +65,7 @@ enum cccl_ExecutorStatus
 {
     cccl_Executr_OK = 0,
     cccl_Executor_ERROR,
-    cccl_EXECUTOR_CONTINUE,
+    cccl_Executor_CONTINUE,
     cccl_Executor_END,
 };
 
@@ -95,6 +95,10 @@ 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);
+enum cccl_ExecutorStatus cccl_execute(struct cccl_Node *code, struct cccl_Variables *scope, size_t depth);
+
+const char *strtoken(enum cccl_TokenType type);
+const char *strnode(enum cccl_NodeType type);
+const char *strstatus(enum cccl_ExecutorStatus status);
 
 #endif /* __CCCL_H__ */
diff --git a/executor.c b/executor.c
index 0458f1c..e39df2c 100644
--- a/executor.c
+++ b/executor.c
@@ -41,19 +41,25 @@ static short *get_variable(char name, struct cccl_Variables *scope)
     return NULL;
 }
 
-enum cccl_ExecutorStatus cccl_execute(struct cccl_Node *code, struct cccl_Variables *scope)
+enum cccl_ExecutorStatus cccl_execute(struct cccl_Node *code, struct cccl_Variables *scope, size_t depth)
 {
+    if (verbose)
+        if (code->value)
+            fprintf(stderr, "Executing %s with %d [%c], %lu nodes, depth %lu\n", strnode(code->type), code->value, code->value, code->in_length, depth);
+        else
+            fprintf(stderr, "Executing %s, %lu nodes, depth %lu\n", strnode(code->type), code->in_length, depth);
     switch (code->type)
     {
     case cccl_Node_CODE:
     {
-        int res;
+        enum cccl_ExecutorStatus 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;
+            switch ((res = cccl_execute(code->in[i], scope, depth + 1)))
+            {
+            case cccl_Executor_ERROR: return res;
+            case cccl_Executor_CONTINUE: return cccl_Executor_ERROR;
+            case cccl_Executor_END: goto end;
+            }
     } break;
     case cccl_Node_PUSHZERO:
     {
@@ -197,56 +203,78 @@ code_end:
 
         size_t i = geti(code->value);
         struct cccl_Variables localscope = {0};
-        int res;
+        enum cccl_ExecutorStatus 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;
+            switch ((res = cccl_execute(functions[i].body[j], &localscope, depth + 1)))
+            {
+            case cccl_Executor_ERROR: return res;
+            case cccl_Executor_CONTINUE: return cccl_Executor_ERROR;
+            case cccl_Executor_END: goto end;
+            }
     } break;
     case cccl_Node_INFINITE:
     {
-        int res;
+        short *p;
         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);
+        {
+            short n = 1;
+            p = &n;
+        } else
+        {
+            short *p = get_variable(code->value, scope);
+            if (!p)
+                errx(1, "Cannot loop over non-existent variable %c", code->value);
+        }
 
+        enum cccl_ExecutorStatus res;
         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;
+                switch ((res = cccl_execute(code->in[i], scope, depth + 1)))
+                {
+                case cccl_Executor_ERROR: return res;
+                case cccl_Executor_CONTINUE: break;
+                case cccl_Executor_END: goto end;
+                }
     } 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);
+            errx(1, "Cannot loop over non-existent variable %c", code->value);
         else if (*p < 0)
             errx(1, "Cannot iterate %c=%d times", code->value, *p);
 
-        int res;
+        enum cccl_ExecutorStatus 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;
+                switch ((res = cccl_execute(code->in[j], scope, depth + 1)))
+                {
+                case cccl_Executor_ERROR: return res;
+                case cccl_Executor_CONTINUE: break;
+                case cccl_Executor_END: goto end;
+                }
     };
     case cccl_Node_CONDITIONAL:
     {
+        assert(stack.length >= 1);
+        short *p = get_variable(code->value, scope);
+        if (code->value == '_')
+            errx(1, "_ is not allowed with '%c'", '?');
+        if (!p)
+            errx(1, "Cannot check non-existent variable %c", code->value);
+
+        enum cccl_ExecutorStatus res;
+        if (stack.buffer[stack.length - 1] == *p)
+            for (size_t i = 0; i < code->in_length; ++i)
+                switch ((res = cccl_execute(code->in[i], scope, depth + 1)))
+                {
+                case cccl_Executor_ERROR: return res;
+                case cccl_Executor_CONTINUE: return res;
+                case cccl_Executor_END: goto end;
+                }
     } break;
     }
 
+end:
     return 0;
 }
diff --git a/parser.c b/parser.c
index 267bcb5..a2f5484 100644
--- a/parser.c
+++ b/parser.c
@@ -55,7 +55,7 @@ struct cccl_Node *cccl_parse(struct cccl_Token tokens[], size_t tokens_length, e
     for (size_t i = 0; i < tokens_length; ++i)
     {
         if (verbose)
-            fprintf(stderr, "T:[%c:%d] ", tokens[i].value, tokens[i].type);
+            fprintf(stderr, "T:[%c:%s] ", tokens[i].value, strtoken(tokens[i].type));
         switch (tokens[i].type)
         {
         case cccl_Token_COMMAND: case cccl_Token_COMMANDWITHARG: case cccl_Token_BLOCKSTART:
@@ -123,8 +123,8 @@ struct cccl_Node *cccl_parse(struct cccl_Token tokens[], size_t tokens_length, e
             errx(1, "No matching bracket for %c", opening);
 
 end:
-            putchar('\n');
-            puts("Exploring inner...");
+            if (verbose)
+                fputs("\nExploring inner...\n", stderr);
             res->in[res->in_length - 1] = cccl_parse(
                 tokens + oldi + 1,
                 i - oldi - 1,
diff --git a/str.c b/str.c
new file mode 100644
index 0000000..4277938
--- /dev/null
+++ b/str.c
@@ -0,0 +1,57 @@
+#include "cccl.h"
+
+#include <stddef.h>
+
+
+const char *strtoken(enum cccl_TokenType type)
+{
+    switch (type)
+    {
+    break; case cccl_Token_IDENTIFIER: return "IDENTIFIER";
+    break; case cccl_Token_COMMAND: return "COMMAND";
+    break; case cccl_Token_COMMANDWITHARG: return "COMMANDWITHARG";
+    break; case cccl_Token_BLOCKSTART: return "BLOCKSTART";
+    break; case cccl_Token_BLOCKEND: return "BLOCKEND";
+    }
+    return NULL;
+}
+
+const char *strnode(enum cccl_NodeType type)
+{
+    switch (type)
+    {
+    break; case cccl_Node_CODE: return "CODE";
+    break; case cccl_Node_PUSHZERO: return "PUSHZERO";
+    break; case cccl_Node_INCREMENT: return "INCREMENT";
+    break; case cccl_Node_DECREMENT: return "DECREMENT";
+    break; case cccl_Node_ADD: return "ADD";
+    break; case cccl_Node_SUBTRACT: return "SUBTRACT";
+    break; case cccl_Node_REVERSE: return "REVERSE";
+    break; case cccl_Node_ASSIGN: return "ASSIGN";
+    break; case cccl_Node_DELETE: return "DELETE";
+    break; case cccl_Node_PUSHVAR: return "PUSHVAR";
+    break; case cccl_Node_ASSIGNLOCAL: return "ASSIGNLOCAL";
+    break; case cccl_Node_OUTPUT: return "OUTPUT";
+    break; case cccl_Node_INPUT: return "INPUT";
+    break; case cccl_Node_CALL: return "CALL";
+    break; case cccl_Node_END: return "END";
+    break; case cccl_Node_CONTINUE: return "CONTINUE";
+    break; case cccl_Node_PROCEDURE: return "PROCEDURE";
+    break; case cccl_Node_INFINITE: return "INFINITE";
+    break; case cccl_Node_REPEAT: return "REPEAT";
+    break; case cccl_Node_CONDITIONAL: return "CONDITIONAL";
+    }
+    return NULL;
+}
+
+const char *strstatus(enum cccl_ExecutorStatus status)
+{
+    switch (status)
+    {
+    break; case cccl_Executr_OK: return "OK";
+    break; case cccl_Executor_ERROR: return "ERROR";
+    break; case cccl_Executor_CONTINUE: return "CONTINUE";
+    break; case cccl_Executor_END: return "END";
+    }
+    return NULL;
+}