summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig11
-rw-r--r--CMakeLists.txt12
-rw-r--r--README.md4
-rw-r--r--include/3cl.h118
-rw-r--r--include/cccl.h52
-rw-r--r--include/instruction.h16
-rw-r--r--include/main.h5
-rw-r--r--include/operation.h12
-rw-r--r--include/readfile.h6
-rw-r--r--include/stack.h9
-rw-r--r--include/thirdparty/cvector/LICENSE21
-rw-r--r--include/thirdparty/cvector/cvector.h483
-rw-r--r--include/types.h19
-rw-r--r--include/utils.h5
-rw-r--r--src/3cl.c74
-rw-r--r--src/cccl.c394
-rw-r--r--src/instruction.c18
-rw-r--r--src/instruction/decrement.c8
-rw-r--r--src/instruction/increment.c8
-rw-r--r--src/instruction/nop.c7
-rw-r--r--src/instruction/pushzero.c10
-rw-r--r--src/main.c25
-rw-r--r--src/operation.c133
-rw-r--r--src/readfile.c39
-rw-r--r--src/stack.c22
-rw-r--r--src/utils.c5
26 files changed, 370 insertions, 1146 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..f1bc949
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,11 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+
+[*.{c,h}]
+indent_size = 4
+indent_style = space
+trim_trailing_whitespace = true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1c3f5ac..45742b9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,10 +7,17 @@ endif()
 
 add_executable(
     "${PROJECT_NAME}"
-    src/cccl.c
+    src/3cl.c
+    src/instruction.c
+    src/instruction/nop.c
+    src/instruction/pushzero.c
+    src/instruction/increment.c
+    src/instruction/decrement.c
     src/main.c
-    src/utils.c
     src/platform/getch.c
+    src/readfile.c
+    src/stack.c
+    src/utils.c
 )
 
 set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
@@ -19,4 +26,3 @@ set_target_properties("${PROJECT_NAME}" PROPERTIES C_STANDARD 11)
 set_target_properties("${PROJECT_NAME}" PROPERTIES C_EXTENSIONS FALSE)
 
 target_include_directories("${PROJECT_NAME}" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
-target_include_directories("${PROJECT_NAME}" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/thirdparty")
diff --git a/README.md b/README.md
index c22bef2..6982998 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,3 @@ directory
 
 Also I think you can use some wrapper of the cmake with gui (or iirc cmake has
 its own gui app)
-
-Dependencies
---
-- [cvector](https://github.com/eteran/c-vector) (header only, so included in the source)
diff --git a/include/3cl.h b/include/3cl.h
new file mode 100644
index 0000000..a6b9065
--- /dev/null
+++ b/include/3cl.h
@@ -0,0 +1,118 @@
+#ifndef __3CL_H__
+#define __3CL_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+#ifndef CCL_STACKSIZE
+#define CCL_STACKSIZE 8192
+#endif
+
+typedef int16_t CCLNum;   /**< Abstract type for numbers in ccl */
+typedef size_t  CCLAddr;  /**< Abstract type for address in ccl */
+
+/**
+ * Type of CCLFrame
+ */
+enum CCLFrameType
+{
+    CCL_ROOT,    /**< Root frame, stores global variables    */
+    CCL_PROC,    /**< Function frame, stores local variables */
+    CCL_INFLOOP, /**< Infinity loop, stores start and repeat */
+    CCL_REPLOOP, /**< Repeat loop, stores start and repeat   */
+};
+
+/**
+ * Pair which contains variable's name and value
+ */
+struct CCLVariable
+{
+    struct CCLVariable *prev, *next;
+    char                name;
+    CCLNum              value;
+};
+
+/**
+ * Pair which contains procedure's name and address
+ */
+struct CCLProcedure
+{
+    struct CCLProcedure *prev, *next;
+    char                 name;
+    CCLAddr              address;
+};
+
+/**
+ * Pair with length of stack and stack itself
+ */
+struct CCLStack
+{
+    size_t  length;
+    size_t  cur;
+    CCLNum *stack;
+};
+
+/**
+ * Linked list that stores current state and allows to do recursion with local variables.
+ */
+struct CCLFrame
+{
+    struct  CCLFrame      *prev, *next;  /**< Frames are connected as linked list */
+    enum    CCLFrameType   type;         /**< Type of the frame                   */
+    CCLAddr                ep;           /**< Execution point                     */
+    union
+    {
+        /* Frame stores either variables (for procedures)... */
+        struct
+        {
+            struct  CCLVariable vars;    /**< For root frame variables are global */
+        };
+        /* ...or start address and repeats left (for loops) */
+        struct
+        {
+            CCLAddr start;               /**< Used by CCL_*LOOP                   */
+            int     repeats;             /**< Used by CCL_REPLOOP                 */
+        };
+    };
+};
+
+/**
+ * Main structure for 3cl. It contains root frame, stack and code it's executing.
+ */
+struct CCL
+{
+    struct CCLStack   stack;
+    struct CCLFrame   rootframe;
+    const char       *code;
+    int             (*in)();
+    void            (*out)(int);
+};
+
+/**
+ * Inits CCL.
+ * @see ccl_free
+ * @see ccl_exec
+ * @param ccl The structure to init
+ * @param code The code to execute
+ * @param in Function to get input
+ * @param out Function to show output
+ * @return 0 on success, any other number otherwise
+ */
+int ccl_init(struct CCL *ccl, const char *code, int (*in)(), void (*out)(int));
+
+/**
+ * Frees all things that ware allocated in ccl_init.
+ * @see ccl_init
+ * @param ccl The structure to free
+ */
+void ccl_free(struct CCL *ccl);
+
+/**
+ * Executes inited CCL instance
+ * @see ccl_init
+ * @param ccl The strcture to execute
+ */
+void ccl_exec(struct CCL *ccl);
+
+#endif /* __3CL_H__ */
diff --git a/include/cccl.h b/include/cccl.h
deleted file mode 100644
index 119adf5..0000000
--- a/include/cccl.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef __CCCL_H__
-#define __CCCL_H__
-
-#include "types.h"
-
-#include <stdbool.h>
-
-
-typedef struct cccl_varpair
-{
-    i16 value;
-    s8  name;
-} cccl_varpair;
-
-typedef struct cccl_procpair
-{
-    i32 value;
-    s8  name;
-} cccl_procpair;
-
-typedef struct cccl_pointer
-{
-    i32  value;
-    i32  meta;
-} cccl_pointer;
-
-typedef struct cccl_brpair
-{
-    i32 pointer;
-    s8  bracket;
-} cccl_brpair;
-
-typedef struct cccl
-{
-    cccl_varpair    *variables;  /* Array with variables      */
-    cccl_procpair   *procedures; /* Array with procedures     */
-    i16             *stack;      /* User stack                */
-    cccl_brpair     *br_stack;   /* Stack for brackets        */
-    cccl_varpair   **lv_stack;   /* Local variable stack      */
-    cccl_pointer    *ep_stack;   /* Call stack                */
-    i32              ep;         /* Pointer to current symbol */
-    s8              *code;       /* Code being executed       */
-    s8              *filename;   /* File being executed       */
-    i32              size;       /* File size                 */
-} cccl;
-
-void cccl_init(s8 *filename);
-void cccl_read(void);
-void cccl_run(void);
-void cccl_free(void);
-
-#endif /* __CCCL_H__ */
diff --git a/include/instruction.h b/include/instruction.h
new file mode 100644
index 0000000..449c760
--- /dev/null
+++ b/include/instruction.h
@@ -0,0 +1,16 @@
+#ifndef __CCL_INSTRUCTION_H__
+#define __CCL_INSTRUCTION_H__
+
+#include "3cl.h"
+
+
+typedef struct CCLFrame *(*CCLInstruction)(struct CCL *ccl, struct CCLFrame *frame);
+
+struct CCLFrame *ccl_instruction_nop(struct CCL *ccl, struct CCLFrame *frame);
+struct CCLFrame *ccl_instruction_pushzero(struct CCL *ccl, struct CCLFrame *frame);
+struct CCLFrame *ccl_instruction_increment(struct CCL *ccl, struct CCLFrame *frame);
+struct CCLFrame *ccl_instruction_decrement(struct CCL *ccl, struct CCLFrame *frame);
+
+struct CCLFrame *ccl_instruction(struct CCL *ccl, struct CCLFrame *frame);
+
+#endif /* __CCL_INSTRUCTION_H__ */
diff --git a/include/main.h b/include/main.h
index 9cdf6ac..ad3bdc6 100644
--- a/include/main.h
+++ b/include/main.h
@@ -1,9 +1,6 @@
 #ifndef __MAIN_H__
 #define __MAIN_H__
 
-#include "types.h"
-
-
-extern const s8 *program_name;
+extern const char *program_name;
 
 #endif /* __MAIN_H__ */
diff --git a/include/operation.h b/include/operation.h
deleted file mode 100644
index ce487da..0000000
--- a/include/operation.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __OPERATION_H__
-#define __OPERATION_H__
-
-#include "cccl.h"
-
-
-typedef void (*cccl_operation)(void);
-
-void cccl_operation_init(cccl *pc);
-cccl_operation cccl_select_operation(void);
-
-#endif /* __OPERATION_H__ */
diff --git a/include/readfile.h b/include/readfile.h
new file mode 100644
index 0000000..5358fc7
--- /dev/null
+++ b/include/readfile.h
@@ -0,0 +1,6 @@
+#ifndef __READFILE_H__
+#define __READFILE_H__
+
+char *readfile(const char *name);
+
+#endif /* __READFILE_H__ */
diff --git a/include/stack.h b/include/stack.h
new file mode 100644
index 0000000..27cc2f0
--- /dev/null
+++ b/include/stack.h
@@ -0,0 +1,9 @@
+#ifndef __CCL_STACK_H__
+#define __CCL_STACK_H__
+
+#include "3cl.h"
+
+void ccl_stack_push(struct CCLStack *stack, CCLNum num);
+CCLNum ccl_stack_pop(struct CCLStack *stack);
+
+#endif /* __CCL_STACK_H__ */
diff --git a/include/thirdparty/cvector/LICENSE b/include/thirdparty/cvector/LICENSE
deleted file mode 100644
index 2eb0839..0000000
--- a/include/thirdparty/cvector/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Evan Teran
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/include/thirdparty/cvector/cvector.h b/include/thirdparty/cvector/cvector.h
deleted file mode 100644
index 7be970d..0000000
--- a/include/thirdparty/cvector/cvector.h
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright (c) 2015 Evan Teran
- *
- * License: The MIT License (MIT)
- */
-
-#ifndef CVECTOR_H_
-#define CVECTOR_H_
-
-#ifndef CVECTOR_LOGARITHMIC_GROWTH
-#define CVECTOR_LOGARITHMIC_GROWTH
-#endif
-
-/* cvector heap implemented using C library malloc() */
-
-/* in case C library malloc() needs extra protection,
- * allow these defines to be overridden.
- */
-#ifndef cvector_clib_free
-#include <stdlib.h> /* for free */
-#define cvector_clib_free free
-#endif
-#ifndef cvector_clib_malloc
-#include <stdlib.h> /* for malloc */
-#define cvector_clib_malloc malloc
-#endif
-#ifndef cvector_clib_calloc
-#include <stdlib.h> /* for calloc */
-#define cvector_clib_calloc calloc
-#endif
-#ifndef cvector_clib_realloc
-#include <stdlib.h> /* for realloc */
-#define cvector_clib_realloc realloc
-#endif
-#ifndef cvector_clib_assert
-#include <assert.h> /* for assert */
-#define cvector_clib_assert assert
-#endif
-#ifndef cvector_clib_memcpy
-#include <string.h> /* for memcpy */
-#define cvector_clib_memcpy memcpy
-#endif
-#ifndef cvector_clib_memmove
-#include <string.h> /* for memmove */
-#define cvector_clib_memmove memmove
-#endif
-
-/* NOTE: Similar to C's qsort and bsearch, you will receive a T*
- * for a vector of Ts. This means that you cannot use `free` directly
- * as a destructor. Instead if you have for example a cvector_vector_type(int *)
- * you will need to supply a function which casts `elem_ptr` to an `int**`
- * and then does a free on what that pointer points to:
- *
- * ex:
- *
- * void free_int(void *p) { free(*(int **)p); }
- */
-typedef void (*cvector_elem_destructor_t)(void *elem_ptr);
-
-typedef struct cvector_metadata_t {
-    size_t size;
-    size_t capacity;
-    cvector_elem_destructor_t elem_destructor;
-} cvector_metadata_t;
-
-/**
- * @brief cvector_vector_type - The vector type used in this library
- */
-#define cvector_vector_type(type) type *
-
-/**
- * @brief cvector - Syntactic sugar to retrieve a vector type
- *
- * @param type The type of vector to act on.
- */
-#define cvector(type) cvector_vector_type(type)
-
-/*
- * @brief cvector_iterator - The iterator type used for cvector
- */
-#define cvector_iterator(type) cvector_vector_type(type)
-
-/**
- * @brief cvector_vec_to_base - For internal use, converts a vector pointer to a metadata pointer
- * @param vec - the vector
- * @return the metadata pointer of the vector
- * @internal
- */
-#define cvector_vec_to_base(vec) \
-    (&((cvector_metadata_t *)(vec))[-1])
-
-/**
- * @brief cvector_base_to_vec - For internal use, converts a metadata pointer to a vector pointer
- * @param ptr - pointer to the metadata
- * @return the vector
- * @internal
- */
-#define cvector_base_to_vec(ptr) \
-    ((void *)&((cvector_metadata_t *)(ptr))[1])
-
-/**
- * @brief cvector_capacity - gets the current capacity of the vector
- * @param vec - the vector
- * @return the capacity as a size_t
- */
-#define cvector_capacity(vec) \
-    ((vec) ? cvector_vec_to_base(vec)->capacity : (size_t)0)
-
-/**
- * @brief cvector_size - gets the current size of the vector
- * @param vec - the vector
- * @return the size as a size_t
- */
-#define cvector_size(vec) \
-    ((vec) ? cvector_vec_to_base(vec)->size : (size_t)0)
-
-/**
- * @brief cvector_elem_destructor - get the element destructor function used
- * to clean up elements
- * @param vec - the vector
- * @return the function pointer as cvector_elem_destructor_t
- */
-#define cvector_elem_destructor(vec) \
-    ((vec) ? cvector_vec_to_base(vec)->elem_destructor : NULL)
-
-/**
- * @brief cvector_empty - returns non-zero if the vector is empty
- * @param vec - the vector
- * @return non-zero if empty, zero if non-empty
- */
-#define cvector_empty(vec) \
-    (cvector_size(vec) == 0)
-
-/**
- * @brief cvector_reserve - Requests that the vector capacity be at least enough
- * to contain n elements. If n is greater than the current vector capacity, the
- * function causes the container to reallocate its storage increasing its
- * capacity to n (or greater).
- * @param vec - the vector
- * @param n - Minimum capacity for the vector.
- * @return void
- */
-#define cvector_reserve(vec, n)                  \
-    do {                                         \
-        size_t cv_cap__ = cvector_capacity(vec); \
-        if (cv_cap__ < (n)) {                    \
-            cvector_grow((vec), (n));            \
-        }                                        \
-    } while (0)
-
-/*
- * @brief cvector_init - Initialize a vector.  The vector must be NULL for this to do anything.
- * @param vec - the vector
- * @param capacity - vector capacity to reserve
- * @param elem_destructor_fn - element destructor function
- * @return void
- */
-#define cvector_init(vec, capacity, elem_destructor_fn)               \
-    do {                                                              \
-        if (!(vec)) {                                                 \
-            cvector_reserve((vec), capacity);                         \
-            cvector_set_elem_destructor((vec), (elem_destructor_fn)); \
-        }                                                             \
-    } while (0)
-
-/**
- * @brief cvector_erase - removes the element at index i from the vector
- * @param vec - the vector
- * @param i - index of element to remove
- * @return void
- */
-#define cvector_erase(vec, i)                                                               \
-    do {                                                                                    \
-        if (vec) {                                                                          \
-            const size_t cv_sz__ = cvector_size(vec);                                       \
-            if ((i) < cv_sz__) {                                                            \
-                cvector_elem_destructor_t elem_destructor__ = cvector_elem_destructor(vec); \
-                if (elem_destructor__) {                                                    \
-                    elem_destructor__(&(vec)[i]);                                           \
-                }                                                                           \
-                cvector_set_size((vec), cv_sz__ - 1);                                       \
-                cvector_clib_memmove(                                                       \
-                    (vec) + (i),                                                            \
-                    (vec) + (i) + 1,                                                        \
-                    sizeof(*(vec)) * (cv_sz__ - 1 - (i)));                                  \
-            }                                                                               \
-        }                                                                                   \
-    } while (0)
-
-/**
- * @brief cvector_clear - erase all of the elements in the vector
- * @param vec - the vector
- * @return void
- */
-#define cvector_clear(vec)                                                              \
-    do {                                                                                \
-        if (vec) {                                                                      \
-            cvector_elem_destructor_t elem_destructor__ = cvector_elem_destructor(vec); \
-            if (elem_destructor__) {                                                    \
-                size_t i__;                                                             \
-                for (i__ = 0; i__ < cvector_size(vec); ++i__) {                         \
-                    elem_destructor__(&(vec)[i__]);                                     \
-                }                                                                       \
-            }                                                                           \
-            cvector_set_size(vec, 0);                                                   \
-        }                                                                               \
-    } while (0)
-
-/**
- * @brief cvector_free - frees all memory associated with the vector
- * @param vec - the vector
- * @return void
- */
-#define cvector_free(vec)                                                               \
-    do {                                                                                \
-        if (vec) {                                                                      \
-            void *p1__                                  = cvector_vec_to_base(vec);     \
-            cvector_elem_destructor_t elem_destructor__ = cvector_elem_destructor(vec); \
-            if (elem_destructor__) {                                                    \
-                size_t i__;                                                             \
-                for (i__ = 0; i__ < cvector_size(vec); ++i__) {                         \
-                    elem_destructor__(&(vec)[i__]);                                     \
-                }                                                                       \
-            }                                                                           \
-            cvector_clib_free(p1__);                                                    \
-        }                                                                               \
-    } while (0)
-
-/**
- * @brief cvector_begin - returns an iterator to first element of the vector
- * @param vec - the vector
- * @return a pointer to the first element (or NULL)
- */
-#define cvector_begin(vec) \
-    (vec)
-
-/**
- * @brief cvector_end - returns an iterator to one past the last element of the vector
- * @param vec - the vector
- * @return a pointer to one past the last element (or NULL)
- */
-#define cvector_end(vec) \
-    ((vec) ? &((vec)[cvector_size(vec)]) : NULL)
-
-/* user request to use logarithmic growth algorithm */
-#ifdef CVECTOR_LOGARITHMIC_GROWTH
-
-/**
- * @brief cvector_compute_next_grow - returns an the computed size in next vector grow
- * size is increased by multiplication of 2
- * @param size - current size
- * @return size after next vector grow
- */
-#define cvector_compute_next_grow(size) \
-    ((size) ? ((size) << 1) : 1)
-
-#else
-
-/**
- * @brief cvector_compute_next_grow - returns an the computed size in next vector grow
- * size is increased by 1
- * @param size - current size
- * @return size after next vector grow
- */
-#define cvector_compute_next_grow(size) \
-    ((size) + 1)
-
-#endif /* CVECTOR_LOGARITHMIC_GROWTH */
-
-/**
- * @brief cvector_push_back - adds an element to the end of the vector
- * @param vec - the vector
- * @param value - the value to add
- * @return void
- */
-#define cvector_push_back(vec, value)                                 \
-    do {                                                              \
-        size_t cv_cap__ = cvector_capacity(vec);                      \
-        if (cv_cap__ <= cvector_size(vec)) {                          \
-            cvector_grow((vec), cvector_compute_next_grow(cv_cap__)); \
-        }                                                             \
-        (vec)[cvector_size(vec)] = (value);                           \
-        cvector_set_size((vec), cvector_size(vec) + 1);               \
-    } while (0)
-
-/**
- * @brief cvector_insert - insert element at position pos to the vector
- * @param vec - the vector
- * @param pos - position in the vector where the new elements are inserted.
- * @param val - value to be copied (or moved) to the inserted elements.
- * @return void
- */
-#define cvector_insert(vec, pos, val)                                 \
-    do {                                                              \
-        size_t cv_cap__ = cvector_capacity(vec);                      \
-        if (cv_cap__ <= cvector_size(vec)) {                          \
-            cvector_grow((vec), cvector_compute_next_grow(cv_cap__)); \
-        }                                                             \
-        if ((pos) < cvector_size(vec)) {                              \
-            cvector_clib_memmove(                                     \
-                (vec) + (pos) + 1,                                    \
-                (vec) + (pos),                                        \
-                sizeof(*(vec)) * ((cvector_size(vec)) - (pos)));      \
-        }                                                             \
-        (vec)[(pos)] = (val);                                         \
-        cvector_set_size((vec), cvector_size(vec) + 1);               \
-    } while (0)
-
-/**
- * @brief cvector_pop_back - removes the last element from the vector
- * @param vec - the vector
- * @return void
- */
-#define cvector_pop_back(vec)                                                       \
-    do {                                                                            \
-        cvector_elem_destructor_t elem_destructor__ = cvector_elem_destructor(vec); \
-        if (elem_destructor__) {                                                    \
-            elem_destructor__(&(vec)[cvector_size(vec) - 1]);                       \
-        }                                                                           \
-        cvector_set_size((vec), cvector_size(vec) - 1);                             \
-    } while (0)
-
-/**
- * @brief cvector_copy - copy a vector
- * @param from - the original vector
- * @param to - destination to which the function copy to
- * @return void
- */
-#define cvector_copy(from, to)                                                       \
-    do {                                                                             \
-        if ((from)) {                                                                \
-            cvector_grow(to, cvector_size(from));                                    \
-            cvector_set_size(to, cvector_size(from));                                \
-            cvector_clib_memcpy((to), (from), cvector_size(from) * sizeof(*(from))); \
-        }                                                                            \
-    } while (0)
-
-/**
- * @brief cvector_swap - exchanges the content of the vector by the content of another vector of the same type
- * @param vec - the original vector
- * @param other - the other vector to swap content with
- * @param type - the type of both vectors
- * @return void
- */
-#define cvector_swap(vec, other, type)                       \
-    do {                                                     \
-        if (vec && other) {                                  \
-            cvector_vector_type(type) cv_swap__ = vec;       \
-            vec                                 = other;     \
-            other                               = cv_swap__; \
-        }                                                    \
-    } while (0)
-
-/**
- * @brief cvector_set_capacity - For internal use, sets the capacity variable of the vector
- * @param vec - the vector
- * @param size - the new capacity to set
- * @return void
- * @internal
- */
-#define cvector_set_capacity(vec, size)                  \
-    do {                                                 \
-        if (vec) {                                       \
-            cvector_vec_to_base(vec)->capacity = (size); \
-        }                                                \
-    } while (0)
-
-/**
- * @brief cvector_set_size - For internal use, sets the size variable of the vector
- * @param vec - the vector
- * @param size - the new capacity to set
- * @return void
- * @internal
- */
-#define cvector_set_size(vec, _size)                  \
-    do {                                              \
-        if (vec) {                                    \
-            cvector_vec_to_base(vec)->size = (_size); \
-        }                                             \
-    } while (0)
-
-/**
- * @brief cvector_set_elem_destructor - set the element destructor function
- * used to clean up removed elements. The vector must NOT be NULL for this to do anything.
- * @param vec - the vector
- * @param elem_destructor_fn - function pointer of type cvector_elem_destructor_t used to destroy elements
- * @return void
- */
-#define cvector_set_elem_destructor(vec, elem_destructor_fn)                  \
-    do {                                                                      \
-        if (vec) {                                                            \
-            cvector_vec_to_base(vec)->elem_destructor = (elem_destructor_fn); \
-        }                                                                     \
-    } while (0)
-
-/**
- * @brief cvector_grow - For internal use, ensures that the vector is at least <count> elements big
- * @param vec - the vector
- * @param count - the new capacity to set
- * @return void
- * @internal
- */
-#define cvector_grow(vec, count)                                                      \
-    do {                                                                              \
-        const size_t cv_sz__ = (count) * sizeof(*(vec)) + sizeof(cvector_metadata_t); \
-        if (vec) {                                                                    \
-            void *cv_p1__ = cvector_vec_to_base(vec);                                 \
-            void *cv_p2__ = cvector_clib_realloc(cv_p1__, cv_sz__);                   \
-            cvector_clib_assert(cv_p2__);                                             \
-            (vec) = cvector_base_to_vec(cv_p2__);                                     \
-        } else {                                                                      \
-            void *cv_p__ = cvector_clib_malloc(cv_sz__);                              \
-            cvector_clib_assert(cv_p__);                                              \
-            (vec) = cvector_base_to_vec(cv_p__);                                      \
-            cvector_set_size((vec), 0);                                               \
-            cvector_set_elem_destructor((vec), NULL);                                 \
-        }                                                                             \
-        cvector_set_capacity((vec), (count));                                         \
-    } while (0)
-
-/**
- * @brief cvector_shrink_to_fit - requests the container to reduce its capacity to fit its size
- * @param vec - the vector
- * @return void
- */
-#define cvector_shrink_to_fit(vec)                     \
-    do {                                               \
-        if (vec) {                                     \
-            const size_t cv_sz___ = cvector_size(vec); \
-            cvector_grow(vec, cv_sz___);               \
-        }                                              \
-    } while (0)
-
-/**
- * @brief cvector_at - returns a reference to the element at position n in the vector.
- * @param vec - the vector
- * @param n - position of an element in the vector.
- * @return the element at the specified position in the vector.
- */
-#define cvector_at(vec, n) \
-    ((vec) ? (((int)(n) < 0 || (size_t)(n) >= cvector_size(vec)) ? NULL : &(vec)[n]) : NULL)
-
-/**
- * @brief cvector_front - returns a reference to the first element in the vector. Unlike member cvector_begin, which returns an iterator to this same element, this function returns a direct reference.
- * @return a reference to the first element in the vector container.
- */
-#define cvector_front(vec) \
-    ((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, 0) : NULL) : NULL)
-
-/**
- * @brief cvector_back - returns a reference to the last element in the vector.Unlike member cvector_end, which returns an iterator just past this element, this function returns a direct reference.
- * @return a reference to the last element in the vector.
- */
-#define cvector_back(vec) \
-    ((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, cvector_size(vec) - 1) : NULL) : NULL)
-
-/**
- * @brief cvector_resize - resizes the container to contain count elements.
- * @param vec - the vector
- * @param count - new size of the vector
- * @param value - the value to initialize new elements with
- * @return void
- */
-#define cvector_resize(vec, count, value)                          \
-    do {                                                           \
-        if (vec) {                                                 \
-            size_t cv_sz_count__ = (size_t)(count);                \
-            size_t cv_sz__       = cvector_vec_to_base(vec)->size; \
-            if (cv_sz_count__ > cv_sz__) {                         \
-                cvector_reserve((vec), cv_sz_count__);             \
-                cvector_set_size((vec), cv_sz_count__);            \
-                do {                                               \
-                    (vec)[cv_sz__++] = (value);                    \
-                } while (cv_sz__ < cv_sz_count__);                 \
-            } else {                                               \
-                while (cv_sz_count__ < cv_sz__--) {                \
-                    cvector_pop_back(vec);                         \
-                }                                                  \
-            }                                                      \
-        }                                                          \
-    } while (0)
-
-#endif /* CVECTOR_H_ */
diff --git a/include/types.h b/include/types.h
deleted file mode 100644
index 4bf1da9..0000000
--- a/include/types.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __TYPES_H__
-#define __TYPES_H__
-
-#include <stdint.h>
-
-
-typedef char     s8;
-
-typedef uint8_t  u8;
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t i64;
-
-typedef int8_t   i8;
-typedef int16_t  i16;
-typedef int32_t  i32;
-typedef uint64_t i64;
-
-#endif /* __TYPES_H__ */
diff --git a/include/utils.h b/include/utils.h
index 29c59f1..40bb642 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -3,9 +3,6 @@
 
 #include <stdnoreturn.h>
 
-#include "types.h"
-
-
-noreturn void die(i32 code, s8 *fmt, ...);
+noreturn void die(int code, char *fmt, ...);
 
 #endif /* __UTILS_H__ */
diff --git a/src/3cl.c b/src/3cl.c
new file mode 100644
index 0000000..c8016a9
--- /dev/null
+++ b/src/3cl.c
@@ -0,0 +1,74 @@
+#include "3cl.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "instruction.h"
+
+
+int ccl_init(struct CCL *ccl, const char *code, int (*in)(), void (*out)(int))
+{
+    *ccl = (struct CCL)
+    {
+        .code = code,
+        .in = in,
+        .out = out,
+        .rootframe = (struct CCLFrame)
+        {
+            .prev = NULL, .next = NULL,
+            .type = CCL_ROOT,
+            .ep = 0,
+            .vars = (struct CCLVariable)
+            {
+                .prev = NULL,
+                .next = NULL,
+                .name = '_',
+                .value = 0
+            },
+        },
+        .stack = (struct CCLStack)
+        {
+            .length = CCL_STACKSIZE,
+            .stack = (CCLNum *)malloc(CCL_STACKSIZE)
+        },
+    };
+
+    return errno;
+}
+
+void ccl_free(struct CCL *ccl)
+{
+    free(ccl->stack.stack);
+    if (ccl->rootframe.next != NULL)
+    {
+        for (struct CCLFrame *frame = ccl->rootframe.next, *new;;)
+        {
+            if (frame->vars.next != NULL)
+            {
+                for (struct CCLVariable *var = frame->vars.next, *new;;)
+                {
+                    if (var->next == NULL)
+                        break;
+                    new = var->next;
+                    free(var);
+                    var = new;
+                }
+            }
+
+            if (frame->next == NULL)
+                break;
+            new = frame->next;
+            free(frame);
+            frame = new;
+        }
+    }
+}
+
+void ccl_exec(struct CCL *ccl)
+{
+    struct CCLFrame *curframe = &ccl->rootframe;
+
+    for (;;++curframe->ep)
+        curframe = ccl_instruction(ccl, curframe);
+}
diff --git a/src/cccl.c b/src/cccl.c
deleted file mode 100644
index e2bb788..0000000
--- a/src/cccl.c
+++ /dev/null
@@ -1,394 +0,0 @@
-#include "cccl.h"
-#include "types.h"
-
-#include <cvector/cvector.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "operation.h"
-#include "platform/getch.h"
-#include "utils.h"
-
-
-static cccl pc = {0};
-static const s8 *const name_allowed   = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-static const s8 *const name_allowed_  = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
-static const s8 *const all_allowed    = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}[]()?;@=!&$%<>^+-*~#:/ \n\t";
-static const s8 *const skippable      = " \t\n";
-static const s8 *const open_brackets  = "[({?";
-static const s8 *const close_brackets = "])};";
-
-static void cccl_varpair_free(void *p)
-{
-    cvector_free(*(cccl_varpair **)p);
-}
-
-void cccl_init(s8 *filename)
-{
-    memset(&pc, 0, sizeof(pc));
-
-    cvector_init(pc.stack,      1, NULL);
-    cvector_init(pc.variables,  1, NULL);
-    cvector_init(pc.procedures, 1, NULL);
-    cvector_init(pc.lv_stack,   1, cccl_varpair_free);
-    cvector_init(pc.ep_stack,   1, NULL);
-    if (errno) die(1, strerror(errno));
-
-    pc.filename = filename;
-    cccl_operation_init(&pc);
-}
-
-void cccl_free()
-{
-    cvector_free(pc.stack);
-    cvector_free(pc.variables);
-    cvector_free(pc.procedures);
-    cvector_free(pc.lv_stack);
-    cvector_free(pc.ep_stack);
-    free(pc.code);
-}
-
-void cccl_read(void)
-{
-    s8 chr;
-    FILE *file = fopen(pc.filename, "r");
-    if (errno) die(1, strerror(errno));
-        fseek(file, 0, SEEK_END);
-        pc.size = ftell(file);
-        fseek(file, 0, SEEK_SET);
-        pc.code = calloc(pc.size + 1, sizeof(s8));
-
-        for (u32 i = 0; i < pc.size; ++i)
-        {
-            if ((chr = fgetc(file)) == EOF)
-            {
-                if (errno)
-                {
-                    fclose(file);
-                    die(1, strerror(errno));
-                }
-                else
-                {
-                    break;
-                }
-            }
-            pc.code[i] = chr;
-        }
-    fclose(file);
-}
-
-static void check_symbol(void)
-{
-    if (!strchr(all_allowed, pc.code[pc.ep]))
-        die(1, "illegal character (%u at %d)", pc.code[pc.ep], pc.ep);
-}
-
-static void require_stack_size(u32 size, i32 start)
-{
-    if (cvector_size(pc.stack) < size)
-        die(1, "stack size is %d, but %d is required (%c at %d)", cvector_size(pc.stack), size, pc.code[start], start);
-}
-
-static i32 require_variable_local(s8 name)
-{
-    if (cvector_size(pc.lv_stack) > 0)
-        for (i32 i = 0; i < cvector_size(pc.lv_stack[cvector_size(pc.lv_stack) - 1]); ++i)
-            if (pc.lv_stack[cvector_size(pc.lv_stack) - 1][i].name == name)
-                return i;
-    return -1;
-}
-
-static i32 require_variable(s8 name)
-{
-    for (i32 i = 0; i < cvector_size(pc.variables); ++i)
-        if (pc.variables[i].name == name)
-            return i;
-    return -1;
-}
-
-static i32 require_procedure(s8 name)
-{
-    for (i32 i = 0; i < cvector_size(pc.procedures); ++i)
-        if (pc.procedures[i].name == name)
-            return i;
-    return -1;
-}
-
-static i32 find_bracket(i32 start)
-{
-    i32 start_length = cvector_size(pc.br_stack);
-    cccl_brpair brpair;
-    for (i32 pointer = pc.ep+1; pointer < pc.size; ++pointer)
-    {
-        check_symbol();
-        if (strchr(skippable, pc.code[pointer])) continue;
-        else if (strchr(open_brackets, pc.code[pointer]))
-        {
-            brpair = (cccl_brpair){.pointer=pointer, .bracket=close_brackets[strchr(open_brackets, pc.code[pointer]) - open_brackets]};
-            cvector_push_back(pc.br_stack, brpair);
-        }
-        else if (strchr(close_brackets, pc.code[pointer]))
-        {
-            if (pc.code[pointer] != pc.br_stack[cvector_size(pc.br_stack) - 1].bracket)
-                die(1, "invalid bracket (%c at %d for %c at %d)", pc.code[pointer], pointer, pc.code[pc.br_stack[cvector_size(pc.br_stack) - 1].pointer], pc.br_stack[cvector_size(pc.br_stack) - 1].pointer);
-            cvector_pop_back(pc.br_stack);
-        }
-        if (cvector_size(pc.br_stack) < start_length) return pointer;
-    }
-    die(1, "unclosed bracket (%c at %d)", pc.code[start], start);
-}
-
-static s8 read_operand(bool allow_underscore)
-{
-    i32 start = pc.ep;
-    for (++pc.ep; pc.ep < pc.size; ++pc.ep)
-    {
-        check_symbol();
-        if (strchr(skippable, pc.code[pc.ep])) continue;
-        if (!strchr(allow_underscore ? name_allowed_ : name_allowed, pc.code[pc.ep]))
-            die(1, "invalid operand name (%c at %d for %c at %d)", pc.code[pc.ep], pc.ep, pc.code[start], start);
-        return pc.code[pc.ep];
-    }
-    die(1, "no operand (for %c at %d)", pc.code[start], start);
-}
-
-void cccl_run(void)
-{
-    i32 variable, start, var, bracket;
-    cccl_varpair varpair;
-    cccl_pointer pointer;
-    cccl_brpair  brpair;
-    s8 operand;
-    bool is_comment;
-    for (pc.ep = 0; pc.ep < pc.size; ++pc.ep)
-    {
-        if (is_comment && pc.code[pc.ep] == '\n')
-            is_comment = false;
-        else if (is_comment)
-            continue;
-        check_symbol();
-        start = pc.ep;
-        switch (pc.code[pc.ep])
-        {
-        case ' ':
-        case '\t':
-        case ';':
-            break;
-        case '/':
-            is_comment = true;
-            break;
-        case '^':
-            cvector_push_back(pc.stack, 0);
-            break;
-        case '+':
-            require_stack_size(1, pc.ep);
-            ++pc.stack[cvector_size(pc.stack) - 1];
-            break;
-        case '-':
-            require_stack_size(1, pc.ep);
-            --pc.stack[cvector_size(pc.stack) - 1];
-            break;
-        case '*':
-            require_stack_size(2, pc.ep);
-            pc.stack[cvector_size(pc.stack) - 2] += pc.stack[cvector_size(pc.stack) - 1];
-            cvector_pop_back(pc.stack);
-            break;
-        case '~':
-            require_stack_size(2, pc.ep);
-            pc.stack[cvector_size(pc.stack) - 2] -= pc.stack[cvector_size(pc.stack) - 1];
-            cvector_pop_back(pc.stack);
-            break;
-        case '%':
-            operand = read_operand(true);
-            i16 *to_reverse = NULL;
-            i32 size;
-            if (operand == '_')
-            {
-                size = cvector_size(pc.stack);
-            }
-            else
-            {
-                if ((var = require_variable_local(operand)) == -1)
-                {
-                    if ((var = require_variable(operand)) == -1)
-                        die(1, "no %c variable found (%% at %d)", operand, start);
-                    else
-                        size = pc.lv_stack[cvector_size(pc.lv_stack) - 1][var].value;
-                } else
-                {
-                    size = pc.variables[var].value;
-                }
-            }
-            if (size < 1)
-                die(1, "invalid argument %d, should be not less than 1 (%% at %d)", size, start);
-            require_stack_size(size, start);
-            cvector_init(to_reverse, size, NULL);
-            for (int i = 0; i < size; ++i)
-            {
-                cvector_push_back(to_reverse, pc.stack[cvector_size(pc.stack) - 1]);
-                cvector_pop_back(pc.stack);
-            }
-            for (int i = 0; i < size; ++i)
-                cvector_push_back(pc.stack, to_reverse[i]);
-            cvector_free(to_reverse);
-            break;
-        case '=':
-            operand = read_operand(true);
-            require_stack_size(1, start);
-            varpair = (cccl_varpair){.name=operand, .value=pc.stack[cvector_size(pc.stack) - 1]};
-            if (operand != '_')
-            {
-                if ((var = require_variable_local(operand)) == -1)
-                    if ((var = require_variable(operand)) == -1)
-                        cvector_push_back(pc.variables, varpair);
-                    else
-                        pc.variables[var] = varpair;
-                else
-                    pc.lv_stack[cvector_size(pc.lv_stack) - 1][var] = varpair;
-            }
-            cvector_pop_back(pc.stack);
-            break;
-        case '!':
-            operand = read_operand(false);
-            if ((var = require_variable_local(operand)) == -1)
-                if ((var = require_variable(operand)) == -1)
-                    die(1, "no %c variable found (! at %d)", operand, start);
-                else
-                    cvector_erase(pc.variables, var);
-            else
-                cvector_erase(pc.lv_stack[cvector_size(pc.lv_stack) - 1], var);
-            break;
-        case '$':
-            operand = read_operand(false);
-            i16 value;
-            if ((var = require_variable_local(operand)) == -1)
-                if ((var = require_variable(operand)) == -1)
-                    die(1, "no %c variable found ($ at %d)", operand, start);
-                else
-                    value = pc.variables[var].value;
-            else
-                value = pc.lv_stack[cvector_size(pc.lv_stack) - 1][var].value;
-            cvector_push_back(pc.stack, value);
-            break;
-        case '&':
-            operand = read_operand(false);
-            if (cvector_size(pc.lv_stack) == 0)
-                die(1, "local variables cannot be created in global scope (& at %d)", start);
-            varpair = (cccl_varpair){.name=operand, .value=0};
-            if (require_variable_local(operand) == -1)
-                cvector_push_back(pc.lv_stack[cvector_size(pc.lv_stack) - 1], varpair);
-            break;
-        case '<':
-            operand = read_operand(false);
-            if ((var = require_variable_local(operand)) == -1)
-                if ((var = require_variable(operand)) == -1)
-                    die(1, "no %c variable found (< at %d)", operand, start);
-                else
-                    printf("%c", pc.variables[var].value);
-            else
-                printf("%c", pc.lv_stack[cvector_size(pc.lv_stack) - 1][var].value);
-            break;
-        case '>':
-            operand = read_operand(false);
-            i16 *to_store;
-            if ((var = require_variable_local(operand)) == -1)
-                if ((var = require_variable(operand)) == -1)
-                    die(1, "no %c variable found (> at %d)", operand, start);
-                else
-                    to_store = &pc.variables[var].value;
-            else
-                to_store = &pc.lv_stack[cvector_size(pc.lv_stack) - 1][var].value;
-            *to_store = getch();
-            break;
-        case '@':
-            operand = read_operand(false);
-            if ((var = require_procedure(operand)) == -1)
-                die(1, "no %c procedure found (@ at %d)", operand, start);
-            pointer = (cccl_pointer){.value=pc.ep, .meta=0};
-            cvector_push_back(pc.ep_stack, pointer);
-            pc.ep = pc.procedures[var].value;
-            break;
-        case '#':
-            if (cvector_size(pc.lv_stack) == 0)
-                exit(0);
-            pc.ep = pc.ep_stack[cvector_size(pc.ep_stack) - 1].value;
-            if (pc.ep_stack[cvector_size(pc.ep_stack) - 1].meta != -1)
-                cvector_pop_back(pc.ep_stack);
-            cvector_pop_back(pc.ep_stack);
-            break;
-        case ':':
-            if (pc.ep_stack[cvector_size(pc.ep_stack) - 1].meta == -1)
-            {
-                die(1, "not in a loop (: at %d)", start);
-            } else if (pc.ep_stack[cvector_size(pc.ep_stack) - 1].meta == 0)
-            {
-                pc.ep = pc.ep_stack[cvector_size(pc.ep_stack) - 1].value;
-                cvector_pop_back(pc.ep_stack);
-                cvector_pop_back(pc.ep_stack);
-            } else
-            {
-                if (pc.ep_stack[cvector_size(pc.ep_stack) - 1].meta > 0)
-                    --pc.ep_stack[cvector_size(pc.ep_stack) - 1].meta;
-                pc.ep = pc.ep_stack[cvector_size(pc.ep_stack) - 2].value;
-            }
-            break;
-        case '}':
-            pc.ep = pc.ep_stack[cvector_size(pc.ep_stack) - 1].value;
-            cvector_pop_back(pc.ep_stack);
-            break;
-        case ')':
-            pc.ep = pc.ep_stack[cvector_size(pc.ep_stack) - 2].value;
-            break;
-        case ']':
-            if (pc.ep_stack[cvector_size(pc.ep_stack) - 1].meta == 0)
-            {
-                pc.ep = pc.ep_stack[cvector_size(pc.ep_stack) - 1].value;
-                cvector_pop_back(pc.ep_stack);
-                cvector_pop_back(pc.ep_stack);
-            } else
-            {
-                --pc.ep_stack[cvector_size(pc.ep_stack) - 1].meta;
-                pc.ep = pc.ep_stack[cvector_size(pc.ep_stack) - 2].value;
-            }
-            break;
-        case '(':
-            pointer = (cccl_pointer){.value=start, .meta=-2};
-            brpair = (cccl_brpair){.pointer=start, .bracket=')'};
-            cvector_push_back(pc.br_stack, brpair);
-            bracket = find_bracket(start);
-            cvector_push_back(pc.ep_stack, pointer);
-            pointer.value = bracket;
-            cvector_push_back(pc.ep_stack, pointer);
-            break;
-        case '?':
-            operand = read_operand(false);
-            if ((var = require_variable_local(operand)) == -1)
-                if ((var = require_variable(operand)) == -1)
-                    die(1, "no %c variable found (? at %d)", operand, start);
-                else
-                    var = pc.variables[var].value;
-            else
-                var = pc.lv_stack[cvector_size(pc.lv_stack) - 1][var].value;
-            if (var != pc.stack[cvector_size(pc.stack) - 1])
-            {
-                brpair = (cccl_brpair){.pointer=start, .bracket='?'};
-                cvector_push_back(pc.br_stack, brpair);
-                bracket = find_bracket(start);
-                pc.ep = bracket;
-            }
-            break;
-        }
-    }
-    printf("Stack: ^^^\n");
-    for (int i = 0; i < cvector_size(pc.stack); ++i)
-        printf("%d\n", pc.stack[i]);
-    printf("Variables:\n");
-    for (int i = 0; i < cvector_size(pc.variables); ++i)
-        printf("%c:%d\n", pc.variables[i].name, pc.variables[i].value);
-    printf("Call stack:\n");
-    for (int i = 0; i < cvector_size(pc.ep_stack); ++i)
-        printf("%d(%d)", pc.ep_stack[i].value, pc.ep_stack[i].meta);
-}
diff --git a/src/instruction.c b/src/instruction.c
new file mode 100644
index 0000000..8597d74
--- /dev/null
+++ b/src/instruction.c
@@ -0,0 +1,18 @@
+#include "instruction.h"
+
+#include "3cl.h"
+
+struct CCLFrame *ccl_instruction(struct CCL *ccl, struct CCLFrame *frame)
+{
+    CCLInstruction instruction;
+    switch (ccl->code[frame->ep])
+    {
+    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;
+    }
+    return instruction(ccl, frame);
+}
diff --git a/src/instruction/decrement.c b/src/instruction/decrement.c
new file mode 100644
index 0000000..f7f54dd
--- /dev/null
+++ b/src/instruction/decrement.c
@@ -0,0 +1,8 @@
+#include "3cl.h"
+#include "instruction.h"
+
+struct CCLFrame *ccl_instruction_decrement(struct CCL *ccl, struct CCLFrame *frame)
+{
+    --ccl->stack.stack[ccl->stack.cur];
+    return frame;
+}
diff --git a/src/instruction/increment.c b/src/instruction/increment.c
new file mode 100644
index 0000000..51697f1
--- /dev/null
+++ b/src/instruction/increment.c
@@ -0,0 +1,8 @@
+#include "3cl.h"
+#include "instruction.h"
+
+struct CCLFrame *ccl_instruction_increment(struct CCL *ccl, struct CCLFrame *frame)
+{
+    ++ccl->stack.stack[ccl->stack.cur];
+    return frame;
+}
diff --git a/src/instruction/nop.c b/src/instruction/nop.c
new file mode 100644
index 0000000..8e05396
--- /dev/null
+++ b/src/instruction/nop.c
@@ -0,0 +1,7 @@
+#include "3cl.h"
+#include "instruction.h"
+
+struct CCLFrame *ccl_instruction_nop(struct CCL *ccl, struct CCLFrame *frame)
+{
+    return frame;
+}
diff --git a/src/instruction/pushzero.c b/src/instruction/pushzero.c
new file mode 100644
index 0000000..ef380cd
--- /dev/null
+++ b/src/instruction/pushzero.c
@@ -0,0 +1,10 @@
+#include "3cl.h"
+#include "instruction.h"
+
+#include "stack.h"
+
+struct CCLFrame *ccl_instruction_pushzero(struct CCL *ccl, struct CCLFrame *frame)
+{
+    ccl_stack_push(&ccl->stack, 0);
+    return frame;
+}
diff --git a/src/main.c b/src/main.c
index 0d69855..2df5779 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,5 +1,4 @@
 #include "main.h"
-#include "types.h"
 
 #include <getopt.h>
 #include <stdbool.h>
@@ -7,15 +6,16 @@
 #include <stdlib.h>
 #include <stdnoreturn.h>
 
-#include "cccl.h"
 #include "platform/getch.h"
+#include "3cl.h"
+#include "readfile.h"
 
 
-const s8 *program_name;
+const char *program_name;
 
-static const s8 *const usage_message =
+static const char *const usage_message =
     "usage: %s [-h] file\n";
-static const s8 *const usage_description =
+static const char *const usage_description =
     "ccl language interpreter\n"
     "Arguments:\n"
     "  file         file to execute\n"
@@ -35,12 +35,12 @@ noreturn void usage(bool full)
     exit(full ? 0 : 1);
 }
 
-int main(i32 argc, s8 **argv)
+int main(int argc, char **argv)
 {
     program_name = argv[0];
     getch_init();
 
-    i32 ch;
+    int ch;
     while ((ch = getopt_long(argc, argv, "h", long_options, NULL)) != EOF)
     {
         switch (ch)
@@ -56,10 +56,9 @@ int main(i32 argc, s8 **argv)
     if (argv[optind] == NULL)
         usage(false);
 
-    cccl_init(argv[optind]);
-        cccl_read();
-        cccl_run();
-    cccl_free();
-
-    return 0;
+    char *code = readfile(argv[optind]);
+    struct CCL ccl;
+    ccl_init(&ccl, code, getch, (void(*)(int))putchar);
+    free(code);
+    ccl_free(&ccl);
 }
diff --git a/src/operation.c b/src/operation.c
deleted file mode 100644
index c56e381..0000000
--- a/src/operation.c
+++ /dev/null
@@ -1,133 +0,0 @@
-#include "operation.h"
-#include "types.h"
-
-#include <cvector/cvector.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "cccl.h"
-#include "utils.h"
-
-
-static cccl *pc;
-static bool is_comment;
-static i32  current;
-
-static const s8 *const name_allowed             = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-static const s8 *const all_allowed              = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}[]()?;@=!&$%<>^+-*~#:/ \n\t";
-static const s8 *const skippable                = " \t\n";
-static const s8 *const open_brackets            = "[({?";
-static const s8 *const close_brackets           = "])};";
-
-static void check_symbol(void)
-{
-    if (!strchr(all_allowed, pc->code[pc->ep]))
-        die(1, "illegal character (%u at %d)", pc->code[pc->ep], pc->ep);
-}
-
-static s8 read_operand(bool allow_underscore)
-{
-    i32 start = pc->ep;
-    for (++pc->ep; pc->ep < pc->size; ++pc->ep)
-    {
-        check_symbol();
-        if (strchr(skippable, pc->code[pc->ep]))
-            continue;
-        if (!strchr(allow_underscore ? name_allowed : name_allowed + 1, pc->code[pc->ep]))
-            die(
-                1, "invalid operand name (%c at %d for %c at %d)",
-                pc->code[pc->ep], pc->ep,
-                pc->code[start], start
-            );
-        return pc->code[pc->ep];
-    }
-    die(
-        1, "no operand (for %c at %d)",
-        pc->code[start], start
-    );
-}
-
-static void require_stack_size(u32 size)
-{
-    if (cvector_size(pc->stack) < size)
-        die(1, "stack size is %d, but %d is required (%c at %d)", cvector_size(pc->stack), size, pc->code[current], current);
-}
-
-static void op_noth(void) {}
-
-static void op_comment(void)
-{
-    is_comment = !is_comment;
-}
-
-static void op_pushzero(void)
-{
-    cvector_push_back(pc->stack, 0);
-}
-
-static void op_increment(void)
-{
-    require_stack_size(1);
-    ++*cvector_back(pc->stack);
-}
-
-static void op_decrement(void)
-{
-    require_stack_size(1);
-    --*cvector_back(pc->stack);
-}
-
-static void op_add(void)
-{
-    require_stack_size(2);
-    *(cvector_back(pc->stack) - 1) += *cvector_back(pc->stack);
-    cvector_pop_back(pc->stack);
-}
-
-static void op_sub(void)
-{
-    require_stack_size(2);
-    *(cvector_back(pc->stack) - 1) -= *cvector_back(pc->stack);
-    cvector_pop_back(pc->stack);
-}
-
-static void op_reverse(void)
-{
-    s8 operand = read_operand(true);
-    i16 *to_reverse = NULL;
-    i32 size;
-
-    if (operand == '_')
-        size = cvector_size(pc->stack);
-}
-
-void cccl_operation_init(cccl *pcp)
-{
-    pc = pcp;
-    is_comment = false;
-    current = 0;
-}
-
-cccl_operation cccl_select_operation(void)
-{
-    if (is_comment && pc->code[pc->ep] == '\n')
-        return op_comment;
-    if (is_comment)
-        return op_noth;
-
-    current = pc->ep;
-    check_symbol();
-
-    switch (pc->code[pc->ep])
-    {
-    case ' ':  /* FALLTHROUGH */
-    case '\t': /* FALLTHROUGH */
-    case ';':  return op_noth;
-    case '/':  return op_comment;
-    case '^':  return op_pushzero;
-    case '+':  return op_increment;
-    case '-':  return op_decrement;
-    default:   die(1, "You shouldn't be there!");
-    }
-}
diff --git a/src/readfile.c b/src/readfile.c
new file mode 100644
index 0000000..8a0ff2e
--- /dev/null
+++ b/src/readfile.c
@@ -0,0 +1,39 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils.h"
+
+
+char *readfile(const char *name)
+{
+    char *code, chr;
+    FILE *file = fopen(name, "r");
+    if (errno) die(1, strerror(errno));
+        fseek(file, 0, SEEK_END);
+        size_t size = ftell(file);
+        fseek(file, 0, SEEK_SET);
+        code = calloc(size + 1, sizeof(*code));
+
+        for (int i = 0; i < size; ++i)
+        {
+            if ((chr = fgetc(file)) == EOF)
+            {
+                if (errno)
+                {
+                    fclose(file);
+                    die(1, strerror(errno));
+                }
+                else
+                {
+                    break;
+                }
+            }
+            code[i] = chr;
+        }
+        code[size - 1] = '\0';
+    fclose(file);
+
+    return code;
+}
diff --git a/src/stack.c b/src/stack.c
new file mode 100644
index 0000000..3a1f697
--- /dev/null
+++ b/src/stack.c
@@ -0,0 +1,22 @@
+#include "3cl.h"
+
+#include <stdlib.h>
+
+
+static inline void resize(struct CCLStack *stack)
+{
+    stack->length *= 2;
+    stack->stack = realloc(stack->stack, stack->length * sizeof(*stack->stack));
+}
+
+void ccl_stack_push(struct CCLStack *stack, CCLNum num)
+{
+    if (stack->cur + 1 == stack->length)
+        resize(stack);
+    stack->stack[++stack->cur] = num;
+}
+
+CCLNum ccl_stack_pop(struct CCLStack *stack, CCLNum num)
+{
+    return stack->stack[stack->cur--];
+}
diff --git a/src/utils.c b/src/utils.c
index 978396c..ba5638f 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,6 +1,3 @@
-#include "utils.h"
-#include "types.h"
-
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -9,7 +6,7 @@
 #include "main.h"
 
 
-noreturn void die(i32 code, s8 *fmt, ...)
+noreturn void die(int code, char *fmt, ...)
 {
     va_list args;