diff options
| author | Nakidai <plaza521@inbox.ru> | 2024-07-05 07:16:05 +0300 |
|---|---|---|
| committer | Nakidai <plaza521@inbox.ru> | 2024-07-05 07:19:48 +0300 |
| commit | aea40f3877e36e95f2a70e3eeb0569fd156e3841 (patch) | |
| tree | e6bd202ac4e5499db3b9983fc46e3b880a20f5ff | |
| parent | a9c159f5f7bf3479c3236735960597b4bc36a204 (diff) | |
| download | 3cl-aea40f3877e36e95f2a70e3eeb0569fd156e3841.tar.gz 3cl-aea40f3877e36e95f2a70e3eeb0569fd156e3841.zip | |
Add almost all
Only continue operation and "blocks" of code are left. Now I'm gonna sleep And yes, I understand that code need to be refactored, and if I will not get bored with writing this thing I will rewrite it in a better way, cuz now code is awful
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | include/cccl.h | 21 | ||||
| -rw-r--r-- | include/platform/getch.h | 13 | ||||
| -rw-r--r-- | include/types.h | 2 | ||||
| -rw-r--r-- | src/cccl.c | 228 | ||||
| -rw-r--r-- | src/main.c | 9 | ||||
| -rw-r--r-- | src/platform/getch.c | 53 | ||||
| -rw-r--r-- | src/utils.c | 2 |
8 files changed, 315 insertions, 15 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index aa41599..a9ddeda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,10 @@ endif() add_executable( "${PROJECT_NAME}" + src/cccl.c src/main.c src/utils.c + src/platform/getch.c ) set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") diff --git a/include/cccl.h b/include/cccl.h index 6652453..9e41730 100644 --- a/include/cccl.h +++ b/include/cccl.h @@ -5,8 +5,6 @@ #include <stdbool.h> -#include "cvector.h" - typedef struct cccl_varpair { @@ -28,15 +26,16 @@ typedef struct cccl_pointer typedef struct cccl { - cccl_varpair *variables; /* Array with variables */ - cccl_procpair *procedures; /* Array with procedures */ - i16 *stack; /* User stack */ - s8 *br_stack; /* Stack for brackets */ - i32 *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_varpair *variables; /* Array with variables */ + cccl_procpair *procedures; /* Array with procedures */ + i16 *stack; /* User stack */ + s8 *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); diff --git a/include/platform/getch.h b/include/platform/getch.h new file mode 100644 index 0000000..490b536 --- /dev/null +++ b/include/platform/getch.h @@ -0,0 +1,13 @@ +#ifndef __GETCH_H__ +#define __GETCH_H__ + +#ifdef _WIN32 +#include <conio.h> +#define getch _getche +#else +int getch(void); +#endif /* _WIN32 */ + +void getch_init(void); + +#endif /* __GETCH_H__ */ diff --git a/include/types.h b/include/types.h index 9c92d57..4bf1da9 100644 --- a/include/types.h +++ b/include/types.h @@ -9,9 +9,11 @@ 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/src/cccl.c b/src/cccl.c index 1803fcf..4734620 100644 --- a/src/cccl.c +++ b/src/cccl.c @@ -4,22 +4,34 @@ #include <errno.h> #include <stdbool.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include "cvector.h" +#include "platform/getch.h" #include "utils.h" static cccl pc = {0}; +static const s8 *const name_allowed = "abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static const s8 *const name_allowed_ = "abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"; +static const s8 *const all_allowed = "abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}[]()?;@=!&$%<>^+-*~#:/ \n\t"; +static const s8 *const skippable = " \t\n"; + +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.stack, 1, NULL); + cvector_init(pc.variables, 1, NULL); cvector_init(pc.procedures, 1, NULL); - cvector_init(pc.ep_stack, 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; @@ -30,6 +42,7 @@ 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); } @@ -63,18 +76,227 @@ void cccl_read(void) 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 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; + cccl_varpair varpair; + cccl_pointer pointer; + 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': + 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 (for %% 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 (for %% 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 (for ! 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 (for ! 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 (for < 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 (for > 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 (for @ at %d)", operand, start); + pointer = (cccl_pointer){.value=pc.ep, .is_loop=false}; + 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].is_loop) + cvector_pop_back(pc.ep_stack); + cvector_pop_back(pc.ep_stack); + 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); } diff --git a/src/main.c b/src/main.c index 36cdf5b..0d69855 100644 --- a/src/main.c +++ b/src/main.c @@ -7,6 +7,9 @@ #include <stdlib.h> #include <stdnoreturn.h> +#include "cccl.h" +#include "platform/getch.h" + const s8 *program_name; @@ -35,6 +38,7 @@ noreturn void usage(bool full) int main(i32 argc, s8 **argv) { program_name = argv[0]; + getch_init(); i32 ch; while ((ch = getopt_long(argc, argv, "h", long_options, NULL)) != EOF) @@ -52,5 +56,10 @@ int main(i32 argc, s8 **argv) if (argv[optind] == NULL) usage(false); + cccl_init(argv[optind]); + cccl_read(); + cccl_run(); + cccl_free(); + return 0; } diff --git a/src/platform/getch.c b/src/platform/getch.c new file mode 100644 index 0000000..48c846e --- /dev/null +++ b/src/platform/getch.c @@ -0,0 +1,53 @@ +#ifdef _WIN32 +void getch_init(void) {} +#else +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdnoreturn.h> +#include <termios.h> +#include <unistd.h> + +static struct termios default_state = {0}; + +int getch(void) +{ + int ch = 0; + struct termios old = {0}; + fflush(stdout); + + tcgetattr(0, &old); + old.c_lflag &= ~ICANON; + + tcsetattr(0, TCSANOW, &old); + ch = getchar(); + tcsetattr(0, TCSADRAIN, &default_state); + + return ch; +} + +static void get_reset_terminal_state(void) +{ + tcsetattr(0, TCSANOW, &default_state); +} + +static noreturn void get_reset_terminal_state_handler(int sig) +{ + get_reset_terminal_state(); + _Exit(sig); +} + +void getch_init(void) +{ + tcgetattr(0, &default_state); + + atexit(get_reset_terminal_state); + + signal(SIGINT, get_reset_terminal_state_handler); + signal(SIGABRT, get_reset_terminal_state_handler); + signal(SIGFPE, get_reset_terminal_state_handler); + signal(SIGILL, get_reset_terminal_state_handler); + signal(SIGSEGV, get_reset_terminal_state_handler); + signal(SIGTERM, get_reset_terminal_state_handler); +} +#endif /* _WIN32 */ diff --git a/src/utils.c b/src/utils.c index ee37110..978396c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -14,10 +14,10 @@ noreturn void die(i32 code, s8 *fmt, ...) va_list args; fprintf(stderr, "%s: ", program_name); - va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); + putc('\n', stderr); exit(code); } |