summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3cl.c8
-rw-r--r--src/instruction.c28
-rw-r--r--src/instruction/add.c14
-rw-r--r--src/instruction/decrement.c5
-rw-r--r--src/instruction/increment.c5
-rw-r--r--src/instruction/nop.c1
-rw-r--r--src/instruction/pushzero.c1
-rw-r--r--src/instruction/reverse.c51
-rw-r--r--src/instruction/subtract.c12
-rw-r--r--src/readchar.c59
-rw-r--r--src/variable.c32
11 files changed, 206 insertions, 10 deletions
diff --git a/src/3cl.c b/src/3cl.c
index c8016a9..bcadf4d 100644
--- a/src/3cl.c
+++ b/src/3cl.c
@@ -1,6 +1,7 @@
 #include "3cl.h"
 
 #include <errno.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -12,6 +13,7 @@ int ccl_init(struct CCL *ccl, const char *code, int (*in)(), void (*out)(int))
     *ccl = (struct CCL)
     {
         .code = code,
+        .stopped = false,
         .in = in,
         .out = out,
         .rootframe = (struct CCLFrame)
@@ -69,6 +71,10 @@ void ccl_exec(struct CCL *ccl)
 {
     struct CCLFrame *curframe = &ccl->rootframe;
 
-    for (;;++curframe->ep)
+    for (;;)
+    {
         curframe = ccl_instruction(ccl, curframe);
+        if (ccl->stopped)
+            break;
+    }
 }
diff --git a/src/instruction.c b/src/instruction.c
index 8597d74..72cca6c 100644
--- a/src/instruction.c
+++ b/src/instruction.c
@@ -1,18 +1,36 @@
 #include "instruction.h"
+#include "instructions.h"
 
+#include <stdbool.h>
+
+#include "readchar.h"
 #include "3cl.h"
 
+
 struct CCLFrame *ccl_instruction(struct CCL *ccl, struct CCLFrame *frame)
 {
     CCLInstruction instruction;
-    switch (ccl->code[frame->ep])
+    char chr = ccl_readchar(ccl, frame, CCL_RC_CCL_INSTR);
+
+    if (chr == '\0')
+    {
+        ccl->stopped = true;
+        return INST(nop)(ccl, frame);
+    }
+
+#define ISSW(NAME) instruction = INST(NAME); break
+    switch (chr)
     {
     case '\n': /* FALLTHROUGH */
     case ' ' : /* FALLTHROUGH */
-    case '\t': instruction = ccl_instruction_nop;
-    case '^' : instruction = ccl_instruction_pushzero;
-    case '+' : instruction = ccl_instruction_increment;
-    case '-' : instruction = ccl_instruction_decrement;
+    case '\t': ISSW(nop);
+    case '^' : ISSW(pushzero);
+    case '+' : ISSW(increment);
+    case '-' : ISSW(decrement);
+    case '*' : ISSW(add);
+    case '~' : ISSW(subtract);
+    case '%' : ISSW(reverse);
     }
+#undef INSW
     return instruction(ccl, frame);
 }
diff --git a/src/instruction/add.c b/src/instruction/add.c
new file mode 100644
index 0000000..81bef71
--- /dev/null
+++ b/src/instruction/add.c
@@ -0,0 +1,14 @@
+#include "3cl.h"
+
+#include "readchar.h"
+#include "stack.h"
+#include "utils.h"
+
+struct CCLFrame *ccl_instruction_add(struct CCL *ccl, struct CCLFrame *frame)
+{
+    if (ccl->stack.cur < 2)
+        die(1, "stack size is %d (%d required)", ccl->stack.cur, 2);
+    ccl_stack_push(&ccl->stack, ccl_stack_pop(&ccl->stack) + ccl_stack_pop(&ccl->stack));
+
+    return frame;
+}
diff --git a/src/instruction/decrement.c b/src/instruction/decrement.c
index f7f54dd..ce3af87 100644
--- a/src/instruction/decrement.c
+++ b/src/instruction/decrement.c
@@ -1,8 +1,11 @@
 #include "3cl.h"
-#include "instruction.h"
+
+#include "utils.h"
 
 struct CCLFrame *ccl_instruction_decrement(struct CCL *ccl, struct CCLFrame *frame)
 {
+    if (ccl->stack.cur < 1)
+        die(1, "stack size is %d (%d required)", ccl->stack.cur, 1);
     --ccl->stack.stack[ccl->stack.cur];
     return frame;
 }
diff --git a/src/instruction/increment.c b/src/instruction/increment.c
index 51697f1..d2d51a5 100644
--- a/src/instruction/increment.c
+++ b/src/instruction/increment.c
@@ -1,8 +1,11 @@
 #include "3cl.h"
-#include "instruction.h"
+
+#include "utils.h"
 
 struct CCLFrame *ccl_instruction_increment(struct CCL *ccl, struct CCLFrame *frame)
 {
+    if (ccl->stack.cur < 1)
+        die(1, "stack size is %d (%d required)", ccl->stack.cur, 1);
     ++ccl->stack.stack[ccl->stack.cur];
     return frame;
 }
diff --git a/src/instruction/nop.c b/src/instruction/nop.c
index 8e05396..778b8ed 100644
--- a/src/instruction/nop.c
+++ b/src/instruction/nop.c
@@ -1,5 +1,4 @@
 #include "3cl.h"
-#include "instruction.h"
 
 struct CCLFrame *ccl_instruction_nop(struct CCL *ccl, struct CCLFrame *frame)
 {
diff --git a/src/instruction/pushzero.c b/src/instruction/pushzero.c
index ef380cd..cd0a023 100644
--- a/src/instruction/pushzero.c
+++ b/src/instruction/pushzero.c
@@ -1,5 +1,4 @@
 #include "3cl.h"
-#include "instruction.h"
 
 #include "stack.h"
 
diff --git a/src/instruction/reverse.c b/src/instruction/reverse.c
new file mode 100644
index 0000000..bd863ae
--- /dev/null
+++ b/src/instruction/reverse.c
@@ -0,0 +1,51 @@
+#include "3cl.h"
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "readchar.h"
+#include "utils.h"
+#include "variable.h"
+
+
+struct CCLFrame *ccl_instruction_reverse(struct CCL *ccl, struct CCLFrame *frame)
+{
+    char varname;
+    size_t toreverse;
+
+    varname = ccl_readchar(ccl, frame, CCL_RC_CCL_VARUS);
+    if (varname == '\0')
+    {
+        die(1, "Unexpected EOF");
+    } else if (varname == '_')
+    {
+        toreverse = ccl->stack.cur;
+    } else
+    {
+        struct CCLVariable *var = ccl_variable_getany(ccl, frame, varname);
+        if (var == NULL)
+            die(1, "Unknown variable '%c' at %d", varname, frame->ep);
+        toreverse = var->value;
+    }
+
+    if (ccl->stack.cur < toreverse)
+        die(1, "stack size is %d (%d required)", ccl->stack.cur, toreverse);
+
+    CCLNum *temp = malloc(sizeof(*temp) * toreverse);
+    if (temp == NULL)
+        die(1, "malloc(): %s", strerror(errno));
+
+    size_t start;
+    for (start = 0; start < toreverse; ++start)
+        temp[start] = ccl->stack.stack[ccl->stack.cur - start];
+    start = ccl->stack.cur - start;
+    for (int i = 0; i < toreverse; ++i)
+        ccl->stack.stack[start + i] = temp[i];
+
+    free(temp);
+
+    return frame;
+}
diff --git a/src/instruction/subtract.c b/src/instruction/subtract.c
new file mode 100644
index 0000000..f140cfb
--- /dev/null
+++ b/src/instruction/subtract.c
@@ -0,0 +1,12 @@
+#include "3cl.h"
+
+#include "stack.h"
+#include "utils.h"
+
+struct CCLFrame *ccl_instruction_subtract(struct CCL *ccl, struct CCLFrame *frame)
+{
+    if (ccl->stack.cur < 2)
+        die(1, "stack size is %d (%d required)", ccl->stack.cur, 2);
+    ccl_stack_push(&ccl->stack, -ccl_stack_pop(&ccl->stack) + ccl_stack_pop(&ccl->stack));
+    return frame;
+}
diff --git a/src/readchar.c b/src/readchar.c
new file mode 100644
index 0000000..51e1784
--- /dev/null
+++ b/src/readchar.c
@@ -0,0 +1,59 @@
+#include "3cl.h"
+#include "readchar.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "utils.h"
+
+
+static const char *const space    = " \n\t";
+static const char *const brackets = "{[(?;)]}";
+static const char *const instr    = "^+-*~%=!$&<>@#:";
+static const char *const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+char ccl_readchar(struct CCL *ccl, struct CCLFrame *frame, enum CCLRCFlags flags)
+{
+    bool iscomment;
+
+    char chr;
+    for (;(chr = ccl->code[frame->ep]) != '\0'; ++frame->ep)
+    {
+        if (iscomment && chr == '\n')
+            iscomment = false;
+        if (iscomment)
+            continue;
+        if (chr == '/')
+            iscomment = true;
+
+        if (strchr(space, chr))
+            continue;
+
+        if (strchr(brackets, chr))
+            if (!(flags & CCL_RC_BRACK) && flags & CCL_RC_DIE)
+                goto invalid;
+            else
+                goto ok;
+        else if (strchr(instr, chr))
+            if (!(flags & CCL_RC_IS) && flags & CCL_RC_DIE)
+                goto invalid;
+            else
+                goto ok;
+        else if (strchr(alphabet, chr))
+            if (!(flags & CCL_RC_ALP) && flags & CCL_RC_DIE)
+                goto invalid;
+            else
+                goto ok;
+        else if (chr == '_')
+            if (!(flags & CCL_RC_US) && flags & CCL_RC_DIE)
+                goto invalid;
+            else
+                goto ok;
+        else
+            goto invalid;
+    }
+ok:
+    return chr;
+invalid:
+    die(1, "Invalid symbol at %d", frame->ep);
+}
diff --git a/src/variable.c b/src/variable.c
new file mode 100644
index 0000000..38ea2e3
--- /dev/null
+++ b/src/variable.c
@@ -0,0 +1,32 @@
+#include "3cl.h"
+#include "variable.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+
+struct CCLVariable *ccl_variable_get(struct CCLVariable *vars, char name)
+{
+    for (struct CCLVariable *var = vars;;var = var->next)
+        if (var->name == name)
+            return var;
+        else if (var->name == '_' || var->next == NULL)
+            return NULL;
+}
+
+struct CCLVariable *ccl_variable_getany(struct CCL *ccl, struct CCLFrame *frame, char name)
+{
+    bool root = false;
+    struct CCLFrame *curframe;
+    struct CCLVariable *found;
+
+    for (curframe = frame; curframe->type != CCL_PROC && curframe->type != CCL_ROOT; curframe = curframe->prev);
+    if (curframe->type == CCL_ROOT)
+        root = true;
+
+    found = ccl_variable_get(&curframe->vars, name);
+    if (!found && !root)
+        return ccl_variable_get(&ccl->rootframe.vars, name);
+
+    return NULL;
+}