From 98a243bf9ab1a3e8bd2de56d7b16302f303f323a Mon Sep 17 00:00:00 2001 From: Nakidai Date: Tue, 25 Mar 2025 02:01:10 +0300 Subject: Add almost done executor --- Makefile | 1 + cccl.c | 4 + cccl.h | 32 +++++++- executor.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 9 ++- 5 files changed, 294 insertions(+), 4 deletions(-) create mode 100644 executor.c 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 +#include +#include +#include +#include +#include + + +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; -- cgit 1.4.1