diff --git a/bin/oraset.exe b/bin/oraset.exe
index 5cbcade..8d8db0d 100644
Binary files a/bin/oraset.exe and b/bin/oraset.exe differ
diff --git a/website/download.php b/website/download.php
index 1bb4dcd..cc50125 100644
--- a/website/download.php
+++ b/website/download.php
@@ -34,13 +34,11 @@
最新版本:B-5
构建日期: 2026.7.22 | 全新升级版本
- 源码下载
- 如果您想从源码编译 Oraset:
+ Windows B-5
+ EXE 可执行文件
- 编译方法:
- make
diff --git a/website/download/exe/Oraset-B-5.exe b/website/download/exe/Oraset-B-5.exe
new file mode 100644
index 0000000..8d8db0d
Binary files /dev/null and b/website/download/exe/Oraset-B-5.exe differ
diff --git a/website/download/source/Oraset-B-5-source/Makefile b/website/download/source/Oraset-B-5-source/Makefile
new file mode 100644
index 0000000..8558a60
--- /dev/null
+++ b/website/download/source/Oraset-B-5-source/Makefile
@@ -0,0 +1,26 @@
+CC = gcc
+CFLAGS = -Wall -Wextra -O2 -std=c11
+BINDIR = bin
+
+TARGET = $(BINDIR)/oraset
+
+SRCS = src/main.c
+
+all: $(TARGET)
+
+$(TARGET): $(SRCS)
+ @mkdir -p $(BINDIR)
+ $(CC) $(CFLAGS) -o $(TARGET) $(SRCS)
+
+clean:
+ rm -f $(TARGET)
+ rm -rf $(BINDIR)
+
+pkg: all
+ rm -rf pkg-root
+ mkdir -p pkg-root/usr/local/bin
+ cp bin/oraset pkg-root/usr/local/bin/oraset
+ chmod +x pkg-root/usr/local/bin/oraset
+ pkgbuild --root pkg-root --identifier com.oraset.lang --version B-5 --install-location / Oraset-B5.pkg
+
+.PHONY: all clean pkg
\ No newline at end of file
diff --git a/website/download/source/Oraset-B-5-source/src/main.c b/website/download/source/Oraset-B-5-source/src/main.c
new file mode 100644
index 0000000..f58fd3f
--- /dev/null
+++ b/website/download/source/Oraset-B-5-source/src/main.c
@@ -0,0 +1,2425 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef _WIN32
+ #include
+ #include
+ #define OS_WINDOWS 1
+#else
+ #include
+ #include
+ #include
+ #define OS_WINDOWS 0
+#endif
+
+#define VERSION "B-5"
+#define MAX_TOKENS 8192
+#define MAX_VARS 512
+#define MAX_LINE 8192
+#define MAX_STRING 2048
+#define MAX_ARRAY_SIZE 1024
+
+typedef enum {
+ TOKEN_EOF,
+ TOKEN_IDENTIFIER,
+ TOKEN_STRING,
+ TOKEN_NUMBER,
+ TOKEN_PRINT,
+ TOKEN_VAR,
+ TOKEN_IF,
+ TOKEN_WHILE,
+ TOKEN_FOR,
+ TOKEN_FUNCTION,
+ TOKEN_RETURN,
+ TOKEN_ELSE,
+ TOKEN_LPAREN,
+ TOKEN_RPAREN,
+ TOKEN_LBRACE,
+ TOKEN_RBRACE,
+ TOKEN_LBRACKET,
+ TOKEN_RBRACKET,
+ TOKEN_COMMA,
+ TOKEN_SEMICOLON,
+ TOKEN_ASSIGN,
+ TOKEN_PLUS,
+ TOKEN_MINUS,
+ TOKEN_MULTIPLY,
+ TOKEN_DIVIDE,
+ TOKEN_EQUAL,
+ TOKEN_NOT_EQUAL,
+ TOKEN_GREATER,
+ TOKEN_LESS,
+ TOKEN_AND,
+ TOKEN_OR,
+ TOKEN_NOT,
+ TOKEN_GREATER_EQUAL,
+ TOKEN_LESS_EQUAL,
+ TOKEN_MODULO,
+ TOKEN_PLUS_ASSIGN,
+ TOKEN_MINUS_ASSIGN,
+ TOKEN_MULTIPLY_ASSIGN,
+ TOKEN_DIVIDE_ASSIGN,
+ TOKEN_MODULO_ASSIGN,
+ TOKEN_INCREMENT,
+ TOKEN_DECREMENT,
+ TOKEN_COLON,
+ TOKEN_DOT,
+ TOKEN_ARROW,
+ TOKEN_SWITCH,
+ TOKEN_CASE,
+ TOKEN_DEFAULT,
+ TOKEN_BREAK,
+ TOKEN_CONTINUE,
+ TOKEN_DO,
+ TOKEN_STRUCT,
+ TOKEN_TYPEDEF,
+ TOKEN_ENUM,
+ TOKEN_GOTO,
+ TOKEN_BIT_AND,
+ TOKEN_BIT_OR,
+ TOKEN_BIT_XOR,
+ TOKEN_BIT_NOT,
+ TOKEN_SHIFT_LEFT,
+ TOKEN_SHIFT_RIGHT,
+ TOKEN_NEW,
+ TOKEN_DELETE,
+ TOKEN_TRY,
+ TOKEN_CATCH,
+ TOKEN_THROW,
+ TOKEN_ASTERISK,
+ TOKEN_LABEL
+} OraTokenType;
+
+typedef struct {
+ OraTokenType type;
+ char value[MAX_STRING];
+ int line;
+} Token;
+
+typedef enum {
+ VAL_NUMBER,
+ VAL_STRING,
+ VAL_ARRAY,
+ VAL_STRUCT,
+ VAL_ENUM,
+ VAL_POINTER
+} ValueType;
+
+typedef struct {
+ ValueType type;
+ double num_value;
+ char str_value[MAX_STRING];
+ double arr_value[MAX_ARRAY_SIZE];
+ int arr_size;
+ int struct_type;
+ int pointer_target;
+} Value;
+
+typedef struct {
+ char name[64];
+ Value value;
+} Variable;
+
+typedef struct {
+ char name[64];
+ int param_count;
+ char params[8][64];
+ int body_start;
+ int body_end;
+} Function;
+
+typedef struct {
+ char name[64];
+ char fields[16][64];
+ int field_count;
+} StructType;
+
+typedef struct {
+ char name[64];
+ char values[16][64];
+ int value_count;
+} EnumType;
+
+typedef struct {
+ char name[64];
+ int token_index;
+} Label;
+
+Token tokens[MAX_TOKENS];
+int token_count = 0;
+int current_token = 0;
+Variable vars[MAX_VARS];
+int var_count = 0;
+Function funcs[MAX_VARS];
+int func_count = 0;
+StructType structs[MAX_VARS];
+int struct_count = 0;
+EnumType enums[MAX_VARS];
+int enum_count = 0;
+Label labels[MAX_VARS];
+int label_count = 0;
+int print_newline = 1;
+int current_line = 1;
+int in_for_loop_update = 0;
+int in_repl = 0;
+int loop_depth = 0;
+int switch_active = 0;
+
+int match(OraTokenType type);
+Value* find_variable(const char* name);
+
+static const struct {
+ const char* name;
+ OraTokenType type;
+} keywords[] = {
+ {"echo", TOKEN_PRINT},
+ {"let", TOKEN_VAR},
+ {"if", TOKEN_IF},
+ {"else", TOKEN_ELSE},
+ {"while", TOKEN_WHILE},
+ {"for", TOKEN_FOR},
+ {"proc", TOKEN_FUNCTION},
+ {"return", TOKEN_RETURN},
+ {"switch", TOKEN_SWITCH},
+ {"case", TOKEN_CASE},
+ {"default", TOKEN_DEFAULT},
+ {"break", TOKEN_BREAK},
+ {"continue", TOKEN_CONTINUE},
+ {"do", TOKEN_DO},
+ {"struct", TOKEN_STRUCT},
+ {"typedef", TOKEN_TYPEDEF},
+ {"enum", TOKEN_ENUM},
+ {"goto", TOKEN_GOTO},
+ {"new", TOKEN_NEW},
+ {"delete", TOKEN_DELETE},
+ {"try", TOKEN_TRY},
+ {"catch", TOKEN_CATCH},
+ {"throw", TOKEN_THROW},
+ {NULL, TOKEN_EOF}
+};
+
+void error(const char* msg, ...) {
+ va_list args;
+ va_start(args, msg);
+ fprintf(stderr, "[Error at line %d] ", current_line);
+ vfprintf(stderr, msg, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ if (in_repl) return;
+ exit(1);
+}
+
+static const char* get_string_value() {
+ if (match(TOKEN_STRING)) {
+ return tokens[current_token - 1].value;
+ } else if (match(TOKEN_IDENTIFIER)) {
+ const char* name = tokens[current_token - 1].value;
+ Value* v = find_variable(name);
+ if (!v || v->type != VAL_STRING) {
+ error("Expected string variable: %s", name);
+ }
+ return v->str_value;
+ }
+ error("Expected string");
+ return "";
+}
+
+static void skip_whitespace_and_comments(const char** p) {
+ while (**p) {
+ if (**p == ' ' || **p == '\t' || **p == '\r') {
+ (*p)++;
+ } else if (**p == '\n') {
+ (*p)++;
+ current_line++;
+ } else if (**p == '#' || (**p == '/' && *(*p+1) == '/')) {
+ while (**p && **p != '\n') (*p)++;
+ } else if (**p == '/' && *(*p+1) == '*') {
+ (*p) += 2;
+ while (**p && !(*(*p) == '*' && *(*p+1) == '/')) {
+ if (**p == '\n') current_line++;
+ (*p)++;
+ }
+ if (**p) (*p) += 2;
+ } else {
+ break;
+ }
+ }
+}
+
+static void add_token(OraTokenType type, const char* value) {
+ if (token_count >= MAX_TOKENS) {
+ error("Too many tokens (max %d)", MAX_TOKENS);
+ }
+ tokens[token_count].type = type;
+ strncpy(tokens[token_count].value, value, MAX_STRING - 1);
+ tokens[token_count].value[MAX_STRING - 1] = '\0';
+ tokens[token_count].line = current_line;
+ token_count++;
+}
+
+void tokenize(const char* source) {
+ token_count = 0;
+ current_line = 1;
+ const char* p = source;
+
+ while (1) {
+ skip_whitespace_and_comments(&p);
+ if (!*p) break;
+
+ if (*p == '"') {
+ p++;
+ char buf[MAX_STRING];
+ int i = 0;
+ while (*p && *p != '"' && i < MAX_STRING - 1) {
+ if (*p == '\\' && *(p+1)) {
+ p++;
+ switch (*p) {
+ case 'n': buf[i++] = '\n'; break;
+ case 't': buf[i++] = '\t'; break;
+ case 'r': buf[i++] = '\r'; break;
+ case '\\': buf[i++] = '\\'; break;
+ case '"': buf[i++] = '"'; break;
+ case '0': buf[i++] = '\0'; break;
+ default: buf[i++] = *p; break;
+ }
+ } else {
+ buf[i++] = *p;
+ }
+ p++;
+ }
+ buf[i] = '\0';
+ if (*p != '"') error("Unterminated string literal");
+ p++;
+ add_token(TOKEN_STRING, buf);
+ continue;
+ }
+
+ if (*p == '\'') {
+ p++;
+ char buf[MAX_STRING];
+ int i = 0;
+ while (*p && *p != '\'' && i < MAX_STRING - 1) {
+ if (*p == '\\' && *(p+1)) {
+ p++;
+ switch (*p) {
+ case 'n': buf[i++] = '\n'; break;
+ case 't': buf[i++] = '\t'; break;
+ case 'r': buf[i++] = '\r'; break;
+ case '\\': buf[i++] = '\\'; break;
+ case '\'': buf[i++] = '\''; break;
+ default: buf[i++] = *p; break;
+ }
+ } else {
+ buf[i++] = *p;
+ }
+ p++;
+ }
+ buf[i] = '\0';
+ if (*p != '\'') error("Unterminated string literal");
+ p++;
+ add_token(TOKEN_STRING, buf);
+ continue;
+ }
+
+ if (isdigit(*p) || (*p == '.' && isdigit(*(p+1)))) {
+ char buf[64];
+ int i = 0;
+ int dot_count = 0;
+ while ((isdigit(*p) || (*p == '.' && dot_count < 1)) && i < 63) {
+ if (*p == '.') dot_count++;
+ buf[i++] = *p++;
+ }
+ buf[i] = '\0';
+ add_token(TOKEN_NUMBER, buf);
+ continue;
+ }
+
+ if (isalpha(*p) || *p == '_') {
+ char buf[64];
+ int i = 0;
+ while ((isalnum(*p) || *p == '_') && i < 63) {
+ buf[i++] = *p++;
+ }
+ buf[i] = '\0';
+
+ int j;
+ for (j = 0; keywords[j].name; j++) {
+ if (strcmp(buf, keywords[j].name) == 0) {
+ add_token(keywords[j].type, buf);
+ break;
+ }
+ }
+ if (!keywords[j].name) {
+ if (*p == ':') {
+ strncpy(labels[label_count].name, buf, 63);
+ labels[label_count].token_index = token_count + 1;
+ label_count++;
+ add_token(TOKEN_LABEL, buf);
+ p++;
+ } else {
+ add_token(TOKEN_IDENTIFIER, buf);
+ }
+ }
+ continue;
+ }
+
+ if (*p == '=' && *(p+1) == '=') { add_token(TOKEN_EQUAL, "=="); p += 2; continue; }
+ if (*p == '!' && *(p+1) == '=') { add_token(TOKEN_NOT_EQUAL, "!="); p += 2; continue; }
+ if (*p == '&' && *(p+1) == '&') { add_token(TOKEN_AND, "&&"); p += 2; continue; }
+ if (*p == '|' && *(p+1) == '|') { add_token(TOKEN_OR, "||"); p += 2; continue; }
+ if (*p == '>' && *(p+1) == '=') { add_token(TOKEN_GREATER_EQUAL, ">="); p += 2; continue; }
+ if (*p == '<' && *(p+1) == '=') { add_token(TOKEN_LESS_EQUAL, "<="); p += 2; continue; }
+ if (*p == '+' && *(p+1) == '=') { add_token(TOKEN_PLUS_ASSIGN, "+="); p += 2; continue; }
+ if (*p == '-' && *(p+1) == '=') { add_token(TOKEN_MINUS_ASSIGN, "-="); p += 2; continue; }
+ if (*p == '*' && *(p+1) == '=') { add_token(TOKEN_MULTIPLY_ASSIGN, "*="); p += 2; continue; }
+ if (*p == '/' && *(p+1) == '=') { add_token(TOKEN_DIVIDE_ASSIGN, "/="); p += 2; continue; }
+ if (*p == '%' && *(p+1) == '=') { add_token(TOKEN_MODULO_ASSIGN, "%="); p += 2; continue; }
+ if (*p == '+' && *(p+1) == '+') { add_token(TOKEN_INCREMENT, "++"); p += 2; continue; }
+ if (*p == '-' && *(p+1) == '-') { add_token(TOKEN_DECREMENT, "--"); p += 2; continue; }
+ if (*p == '-' && *(p+1) == '>') { add_token(TOKEN_ARROW, "->"); p += 2; continue; }
+ if (*p == '<' && *(p+1) == '<') { add_token(TOKEN_SHIFT_LEFT, "<<"); p += 2; continue; }
+ if (*p == '>' && *(p+1) == '>') { add_token(TOKEN_SHIFT_RIGHT, ">>"); p += 2; continue; }
+
+ switch (*p) {
+ case '&': add_token(TOKEN_BIT_AND, "&"); break;
+ case '|': add_token(TOKEN_BIT_OR, "|"); break;
+ case '^': add_token(TOKEN_BIT_XOR, "^"); break;
+ case '~': add_token(TOKEN_BIT_NOT, "~"); break;
+ case '(': add_token(TOKEN_LPAREN, "("); break;
+ case ')': add_token(TOKEN_RPAREN, ")"); break;
+ case '{': add_token(TOKEN_LBRACE, "{"); break;
+ case '}': add_token(TOKEN_RBRACE, "}"); break;
+ case '[': add_token(TOKEN_LBRACKET, "["); break;
+ case ']': add_token(TOKEN_RBRACKET, "]"); break;
+ case ',': add_token(TOKEN_COMMA, ","); break;
+ case ';': add_token(TOKEN_SEMICOLON, ";"); break;
+ case '=': add_token(TOKEN_ASSIGN, "="); break;
+ case '>': add_token(TOKEN_GREATER, ">"); break;
+ case '<': add_token(TOKEN_LESS, "<"); break;
+ case '+': add_token(TOKEN_PLUS, "+"); break;
+ case '-': add_token(TOKEN_MINUS, "-"); break;
+ case '*': add_token(TOKEN_MULTIPLY, "*"); break;
+ case '/': add_token(TOKEN_DIVIDE, "/"); break;
+ case '%': add_token(TOKEN_MODULO, "%"); break;
+ case '!': add_token(TOKEN_NOT, "!"); break;
+ case ':': add_token(TOKEN_COLON, ":"); break;
+ case '.': add_token(TOKEN_DOT, "."); break;
+ default: error("Unknown character: '%c'", *p);
+ }
+ p++;
+ }
+
+ add_token(TOKEN_EOF, "");
+}
+
+Token peek() { return tokens[current_token]; }
+Token advance() { return tokens[current_token++]; }
+
+int match(OraTokenType type) {
+ if (peek().type == type) {
+ if (tokens[current_token].line > 0) {
+ current_line = tokens[current_token].line;
+ }
+ advance();
+ return 1;
+ }
+ return 0;
+}
+
+void consume(OraTokenType type, const char* msg) {
+ if (!match(type)) {
+ error("%s (got '%s')", msg, peek().value);
+ }
+}
+
+double evaluate();
+int execute_statement();
+int update_oraset(const char* target_version);
+
+Value* find_variable(const char* name) {
+ for (int i = var_count - 1; i >= 0; i--) {
+ if (strcmp(vars[i].name, name) == 0) {
+ return &vars[i].value;
+ }
+ }
+ return NULL;
+}
+
+int find_function(const char* name) {
+ for (int i = func_count - 1; i >= 0; i--) {
+ if (strcmp(funcs[i].name, name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int find_struct(const char* name) {
+ for (int i = struct_count - 1; i >= 0; i--) {
+ if (strcmp(structs[i].name, name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int find_enum(const char* name) {
+ for (int i = enum_count - 1; i >= 0; i--) {
+ if (strcmp(enums[i].name, name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int find_label(const char* name) {
+ for (int i = label_count - 1; i >= 0; i--) {
+ if (strcmp(labels[i].name, name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+double parse_array_access(Value* arr, int index) {
+ if (arr->type != VAL_ARRAY) {
+ error("Cannot index non-array value");
+ }
+ if (index < 0 || index >= arr->arr_size) {
+ error("Array index out of bounds: %d", index);
+ }
+ return arr->arr_value[index];
+}
+
+double parse_primary();
+
+double parse_call(const char* func_name) {
+ consume(TOKEN_LPAREN, "Expected '(' after function name");
+
+ if (strcmp(func_name, "abs") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return fabs(val);
+ } else if (strcmp(func_name, "sqrt") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return sqrt(val);
+ } else if (strcmp(func_name, "sin") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return sin(val);
+ } else if (strcmp(func_name, "cos") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return cos(val);
+ } else if (strcmp(func_name, "tan") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return tan(val);
+ } else if (strcmp(func_name, "random") == 0) {
+ if (match(TOKEN_RPAREN)) {
+ return (double)rand() / RAND_MAX;
+ }
+ double max = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return fmod((double)rand(), max);
+ } else if (strcmp(func_name, "size") == 0) {
+ if (match(TOKEN_STRING)) {
+ const char* str = tokens[current_token - 1].value;
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return strlen(str);
+ }
+ error("Expected string argument for size()");
+ } else if (strcmp(func_name, "to_num") == 0) {
+ if (match(TOKEN_STRING)) {
+ const char* str = tokens[current_token - 1].value;
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return atof(str);
+ }
+ error("Expected string argument for to_num()");
+ } else if (strcmp(func_name, "to_str") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ char buf[MAX_STRING];
+ sprintf(buf, "%g", val);
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, "__tmp_str_result") == 0) {
+ strncpy(vars[i].value.str_value, buf, MAX_STRING - 1);
+ vars[i].value.str_value[MAX_STRING - 1] = '\0';
+ vars[i].value.type = VAL_STRING;
+ return 0;
+ }
+ }
+ strncpy(vars[var_count].name, "__tmp_str_result", 63);
+ strncpy(vars[var_count].value.str_value, buf, MAX_STRING - 1);
+ vars[var_count].value.str_value[MAX_STRING - 1] = '\0';
+ vars[var_count].value.type = VAL_STRING;
+ var_count++;
+ return 0;
+ } else if (strcmp(func_name, "input") == 0) {
+ const char* prompt = "";
+ if (match(TOKEN_STRING)) {
+ prompt = tokens[current_token - 1].value;
+ }
+ consume(TOKEN_RPAREN, "Expected ')'");
+
+ printf("%s", prompt);
+ fflush(stdout);
+
+ char input[MAX_STRING];
+ if (fgets(input, MAX_STRING, stdin) == NULL) {
+ error("Failed to read input");
+ }
+
+ input[strcspn(input, "\n")] = '\0';
+
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, "__input_result") == 0) {
+ strncpy(vars[i].value.str_value, input, MAX_STRING - 1);
+ vars[i].value.str_value[MAX_STRING - 1] = '\0';
+ vars[i].value.type = VAL_STRING;
+ return 0;
+ }
+ }
+ strncpy(vars[var_count].name, "__input_result", 63);
+ strncpy(vars[var_count].value.str_value, input, MAX_STRING - 1);
+ vars[var_count].value.str_value[MAX_STRING - 1] = '\0';
+ vars[var_count].value.type = VAL_STRING;
+ var_count++;
+ return 0;
+ } else if (strcmp(func_name, "int") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return (int)val;
+ } else if (strcmp(func_name, "float") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return val;
+ } else if (strcmp(func_name, "floor") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return floor(val);
+ } else if (strcmp(func_name, "ceil") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return ceil(val);
+ } else if (strcmp(func_name, "round") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return round(val);
+ } else if (strcmp(func_name, "pow") == 0) {
+ double base = evaluate();
+ consume(TOKEN_COMMA, "Expected ','");
+ double exp = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return pow(base, exp);
+ } else if (strcmp(func_name, "log") == 0) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return log(val);
+ } else if (strcmp(func_name, "time") == 0) {
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return (double)time(NULL);
+ } else if (strcmp(func_name, "array") == 0) {
+ int size = (int)evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, "__tmp_arr_result") == 0) {
+ vars[i].value.type = VAL_ARRAY;
+ vars[i].value.arr_size = size;
+ for (int j = 0; j < size; j++) {
+ vars[i].value.arr_value[j] = 0;
+ }
+ return 0;
+ }
+ }
+ strncpy(vars[var_count].name, "__tmp_arr_result", 63);
+ vars[var_count].value.type = VAL_ARRAY;
+ vars[var_count].value.arr_size = size;
+ for (int j = 0; j < size; j++) {
+ vars[var_count].value.arr_value[j] = 0;
+ }
+ var_count++;
+ return 0;
+ } else if (strcmp(func_name, "arrlen") == 0) {
+ consume(TOKEN_IDENTIFIER, "Expected array variable");
+ const char* name = tokens[current_token - 1].value;
+ Value* v = find_variable(name);
+ if (!v || v->type != VAL_ARRAY) {
+ error("'%s' is not an array", name);
+ }
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return v->arr_size;
+ } else if (strcmp(func_name, "exit") == 0) {
+ int code = (int)evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ exit(code);
+ } else if (strcmp(func_name, "assert") == 0) {
+ double cond = evaluate();
+ consume(TOKEN_COMMA, "Expected ','");
+ if (match(TOKEN_STRING)) {
+ const char* msg = tokens[current_token - 1].value;
+ consume(TOKEN_RPAREN, "Expected ')'");
+ if (cond == 0) {
+ error("Assertion failed: %s", msg);
+ }
+ } else {
+ consume(TOKEN_RPAREN, "Expected ')'");
+ if (cond == 0) {
+ error("Assertion failed");
+ }
+ }
+ return 1;
+ } else if (strcmp(func_name, "strcmp") == 0) {
+ const char* str1 = get_string_value();
+ consume(TOKEN_COMMA, "Expected ','");
+ const char* str2 = get_string_value();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return strcmp(str1, str2);
+ } else if (strcmp(func_name, "strcpy") == 0) {
+ const char* src = get_string_value();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, "__tmp_str_result") == 0) {
+ strncpy(vars[i].value.str_value, src, MAX_STRING - 1);
+ vars[i].value.str_value[MAX_STRING - 1] = '\0';
+ vars[i].value.type = VAL_STRING;
+ return 0;
+ }
+ }
+ strncpy(vars[var_count].name, "__tmp_str_result", 63);
+ strncpy(vars[var_count].value.str_value, src, MAX_STRING - 1);
+ vars[var_count].value.str_value[MAX_STRING - 1] = '\0';
+ vars[var_count].value.type = VAL_STRING;
+ var_count++;
+ return 0;
+ } else if (strcmp(func_name, "strcat") == 0) {
+ const char* str1 = get_string_value();
+ consume(TOKEN_COMMA, "Expected ','");
+ const char* str2 = get_string_value();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, "__tmp_str_result") == 0) {
+ strncpy(vars[i].value.str_value, str1, MAX_STRING - 1);
+ strncat(vars[i].value.str_value, str2, MAX_STRING - strlen(vars[i].value.str_value) - 1);
+ vars[i].value.type = VAL_STRING;
+ return 0;
+ }
+ }
+ strncpy(vars[var_count].name, "__tmp_str_result", 63);
+ strncpy(vars[var_count].value.str_value, str1, MAX_STRING - 1);
+ strncat(vars[var_count].value.str_value, str2, MAX_STRING - strlen(vars[var_count].value.str_value) - 1);
+ vars[var_count].value.type = VAL_STRING;
+ var_count++;
+ return 0;
+ } else if (strcmp(func_name, "sizeof") == 0) {
+ consume(TOKEN_IDENTIFIER, "Expected variable name");
+ const char* name = tokens[current_token - 1].value;
+ consume(TOKEN_RPAREN, "Expected ')'");
+ Value* v = find_variable(name);
+ if (!v) error("Undefined variable: %s", name);
+ if (v->type == VAL_STRING) {
+ return strlen(v->str_value);
+ } else if (v->type == VAL_ARRAY) {
+ return v->arr_size;
+ }
+ return sizeof(double);
+ } else if (strcmp(func_name, "malloc") == 0) {
+ int size = (int)evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, "__tmp_arr_result") == 0) {
+ vars[i].value.type = VAL_ARRAY;
+ vars[i].value.arr_size = size;
+ for (int j = 0; j < size; j++) {
+ vars[i].value.arr_value[j] = 0;
+ }
+ return 0;
+ }
+ }
+ strncpy(vars[var_count].name, "__tmp_arr_result", 63);
+ vars[var_count].value.type = VAL_ARRAY;
+ vars[var_count].value.arr_size = size;
+ for (int j = 0; j < size; j++) {
+ vars[var_count].value.arr_value[j] = 0;
+ }
+ var_count++;
+ return 0;
+ } else if (strcmp(func_name, "memcpy") == 0) {
+ consume(TOKEN_IDENTIFIER, "Expected destination array");
+ const char* dest_name = tokens[current_token - 1].value;
+ consume(TOKEN_COMMA, "Expected ','");
+ consume(TOKEN_IDENTIFIER, "Expected source array");
+ const char* src_name = tokens[current_token - 1].value;
+ consume(TOKEN_COMMA, "Expected ','");
+ int count = (int)evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ Value* dest = find_variable(dest_name);
+ Value* src = find_variable(src_name);
+ if (!dest || dest->type != VAL_ARRAY) error("Invalid destination array");
+ if (!src || src->type != VAL_ARRAY) error("Invalid source array");
+ for (int i = 0; i < count && i < dest->arr_size && i < src->arr_size; i++) {
+ dest->arr_value[i] = src->arr_value[i];
+ }
+ return 0;
+ } else if (strcmp(func_name, "memcmp") == 0) {
+ consume(TOKEN_IDENTIFIER, "Expected first array");
+ const char* name1 = tokens[current_token - 1].value;
+ consume(TOKEN_COMMA, "Expected ','");
+ consume(TOKEN_IDENTIFIER, "Expected second array");
+ const char* name2 = tokens[current_token - 1].value;
+ consume(TOKEN_COMMA, "Expected ','");
+ int count = (int)evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ Value* arr1 = find_variable(name1);
+ Value* arr2 = find_variable(name2);
+ if (!arr1 || arr1->type != VAL_ARRAY) error("Invalid first array");
+ if (!arr2 || arr2->type != VAL_ARRAY) error("Invalid second array");
+ for (int i = 0; i < count && i < arr1->arr_size && i < arr2->arr_size; i++) {
+ if (arr1->arr_value[i] != arr2->arr_value[i]) {
+ return arr1->arr_value[i] - arr2->arr_value[i];
+ }
+ }
+ return 0;
+ } else {
+ int func_idx = find_function(func_name);
+ if (func_idx >= 0) {
+ int saved_var_count = var_count;
+ for (int i = 0; i < funcs[func_idx].param_count; i++) {
+ if (i > 0) consume(TOKEN_COMMA, "Expected ','");
+ strncpy(vars[var_count].name, funcs[func_idx].params[i], 63);
+ vars[var_count].value.num_value = evaluate();
+ vars[var_count].value.type = VAL_NUMBER;
+ var_count++;
+ }
+ consume(TOKEN_RPAREN, "Expected ')'");
+
+ int saved_token = current_token;
+ current_token = funcs[func_idx].body_start;
+ while (current_token < funcs[func_idx].body_end && peek().type != TOKEN_EOF) {
+ if (execute_statement() == 1) break;
+ }
+ current_token = saved_token;
+
+ double result = 0;
+ for (int i = var_count - 1; i >= 0; i--) {
+ if (strcmp(vars[i].name, "__return_value") == 0) {
+ result = vars[i].value.num_value;
+ break;
+ }
+ }
+ var_count = saved_var_count;
+ return result;
+ }
+ error("Undefined function: %s", func_name);
+ }
+ return 0;
+}
+
+double parse_primary() {
+ if (match(TOKEN_NUMBER)) {
+ return atof(tokens[current_token - 1].value);
+ }
+ if (match(TOKEN_STRING)) {
+ error("Cannot use string directly in expression");
+ }
+ if (match(TOKEN_IDENTIFIER)) {
+ const char* name = tokens[current_token - 1].value;
+ if (peek().type == TOKEN_LPAREN) {
+ return parse_call(name);
+ }
+ if (peek().type == TOKEN_LBRACKET) {
+ Value* v = find_variable(name);
+ if (!v) error("Undefined variable: %s", name);
+ advance();
+ int index = (int)evaluate();
+ consume(TOKEN_RBRACKET, "Expected ']'");
+ return parse_array_access(v, index);
+ }
+ if (peek().type == TOKEN_DOT) {
+ Value* v = find_variable(name);
+ if (!v) error("Undefined variable: %s", name);
+ if (v->type != VAL_STRUCT) {
+ error("Cannot access field of non-struct variable");
+ }
+ advance();
+ consume(TOKEN_IDENTIFIER, "Expected field name");
+ const char* field_name = tokens[current_token - 1].value;
+ int struct_idx = v->struct_type;
+ for (int i = 0; i < structs[struct_idx].field_count; i++) {
+ if (strcmp(structs[struct_idx].fields[i], field_name) == 0) {
+ return (double)i;
+ }
+ }
+ error("Undefined field: %s", field_name);
+ }
+ Value* v = find_variable(name);
+ if (!v) error("Undefined variable: %s", name);
+ if (v->type == VAL_STRING) {
+ error("Cannot use string variable in numeric expression");
+ }
+ return v->num_value;
+ }
+ if (match(TOKEN_LPAREN)) {
+ double val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ return val;
+ }
+ error("Expected expression (got '%s')", peek().value);
+ return 0;
+}
+
+double parse_unary() {
+ if (match(TOKEN_NOT)) {
+ return parse_unary() == 0 ? 1 : 0;
+ }
+ if (match(TOKEN_MINUS)) {
+ return -parse_unary();
+ }
+ if (match(TOKEN_PLUS)) {
+ return parse_unary();
+ }
+ if (match(TOKEN_BIT_NOT)) {
+ return ~(int)parse_unary();
+ }
+ return parse_primary();
+}
+
+double parse_factor() {
+ double left = parse_unary();
+ while (match(TOKEN_MULTIPLY) || match(TOKEN_DIVIDE) || match(TOKEN_MODULO)) {
+ OraTokenType op = tokens[current_token - 1].type;
+ double right = parse_unary();
+ if (op == TOKEN_MULTIPLY) left *= right;
+ else if (op == TOKEN_DIVIDE) {
+ if (right == 0) error("Division by zero");
+ left /= right;
+ } else {
+ if (right == 0) error("Modulo by zero");
+ left = fmod(left, right);
+ }
+ }
+ return left;
+}
+
+double parse_term() {
+ double left = parse_factor();
+ while (match(TOKEN_PLUS) || match(TOKEN_MINUS)) {
+ OraTokenType op = tokens[current_token - 1].type;
+ double right = parse_factor();
+ if (op == TOKEN_PLUS) left += right;
+ else left -= right;
+ }
+ return left;
+}
+
+double parse_shift() {
+ double left = parse_term();
+ while (match(TOKEN_SHIFT_LEFT) || match(TOKEN_SHIFT_RIGHT)) {
+ OraTokenType op = tokens[current_token - 1].type;
+ double right = parse_term();
+ if (op == TOKEN_SHIFT_LEFT) left = (int)left << (int)right;
+ else left = (int)left >> (int)right;
+ }
+ return left;
+}
+
+double parse_bit_and() {
+ double left = parse_shift();
+ while (match(TOKEN_BIT_AND)) {
+ double right = parse_shift();
+ left = (int)left & (int)right;
+ }
+ return left;
+}
+
+double parse_bit_xor() {
+ double left = parse_bit_and();
+ while (match(TOKEN_BIT_XOR)) {
+ double right = parse_bit_and();
+ left = (int)left ^ (int)right;
+ }
+ return left;
+}
+
+double parse_bit_or() {
+ double left = parse_bit_xor();
+ while (match(TOKEN_BIT_OR)) {
+ double right = parse_bit_xor();
+ left = (int)left | (int)right;
+ }
+ return left;
+}
+
+double parse_comparison() {
+ double left = parse_bit_or();
+ while (1) {
+ if (match(TOKEN_EQUAL)) {
+ double right = parse_bit_or();
+ left = (left == right) ? 1 : 0;
+ } else if (match(TOKEN_NOT_EQUAL)) {
+ double right = parse_bit_or();
+ left = (left != right) ? 1 : 0;
+ } else if (match(TOKEN_GREATER)) {
+ double right = parse_bit_or();
+ left = (left > right) ? 1 : 0;
+ } else if (match(TOKEN_LESS)) {
+ double right = parse_bit_or();
+ left = (left < right) ? 1 : 0;
+ } else if (match(TOKEN_GREATER_EQUAL)) {
+ double right = parse_bit_or();
+ left = (left >= right) ? 1 : 0;
+ } else if (match(TOKEN_LESS_EQUAL)) {
+ double right = parse_bit_or();
+ left = (left <= right) ? 1 : 0;
+ } else {
+ break;
+ }
+ }
+ return left;
+}
+
+double parse_logic_and() {
+ double left = parse_comparison();
+ while (match(TOKEN_AND)) {
+ double right = parse_comparison();
+ left = (left != 0 && right != 0) ? 1 : 0;
+ }
+ return left;
+}
+
+double parse_logic_or() {
+ double left = parse_logic_and();
+ while (match(TOKEN_OR)) {
+ double right = parse_logic_and();
+ left = (left != 0 || right != 0) ? 1 : 0;
+ }
+ return left;
+}
+
+double evaluate() {
+ return parse_logic_or();
+}
+
+void execute_print() {
+ consume(TOKEN_LPAREN, "Expected '(' after print");
+ int first = 1;
+ int newline = print_newline;
+
+ while (!match(TOKEN_RPAREN)) {
+ if (!first) consume(TOKEN_COMMA, "Expected ',' between arguments");
+
+ if (match(TOKEN_STRING)) {
+ const char* str = tokens[current_token - 1].value;
+ if (strcmp(str, "nel") == 0) {
+ newline = 0;
+ first = 0;
+ continue;
+ }
+ if (!first) printf(" ");
+ printf("%s", str);
+ } else if (match(TOKEN_NUMBER)) {
+ if (!first) printf(" ");
+ printf("%s", tokens[current_token - 1].value);
+ } else if (match(TOKEN_BIT_NOT) || match(TOKEN_MINUS) || match(TOKEN_PLUS) || match(TOKEN_NOT)) {
+ current_token--;
+ double val = evaluate();
+ if (!first) printf(" ");
+ printf("%g", val);
+ } else if (match(TOKEN_IDENTIFIER)) {
+ const char* name = tokens[current_token - 1].value;
+ if (peek().type == TOKEN_PLUS || peek().type == TOKEN_MINUS ||
+ peek().type == TOKEN_MULTIPLY || peek().type == TOKEN_DIVIDE ||
+ peek().type == TOKEN_MODULO || peek().type == TOKEN_BIT_AND ||
+ peek().type == TOKEN_BIT_OR || peek().type == TOKEN_BIT_XOR ||
+ peek().type == TOKEN_SHIFT_LEFT || peek().type == TOKEN_SHIFT_RIGHT) {
+ current_token--;
+ double val = evaluate();
+ if (!first) printf(" ");
+ printf("%g", val);
+ } else if (peek().type == TOKEN_BIT_NOT) {
+ current_token--;
+ double val = evaluate();
+ if (!first) printf(" ");
+ printf("%g", val);
+ } else if (peek().type == TOKEN_LBRACKET) {
+ Value* v = find_variable(name);
+ if (!v) error("Undefined variable: %s", name);
+ advance();
+ int index = (int)evaluate();
+ consume(TOKEN_RBRACKET, "Expected ']'");
+ if (!first) printf(" ");
+ printf("%g", parse_array_access(v, index));
+ } else if (peek().type == TOKEN_LPAREN) {
+ int func_idx = find_function(name);
+ if (func_idx >= 0) {
+ consume(TOKEN_LPAREN, "Expected '('");
+ int saved_var_count = var_count;
+ for (int i = 0; i < funcs[func_idx].param_count; i++) {
+ if (i > 0) consume(TOKEN_COMMA, "Expected ','");
+ strncpy(vars[var_count].name, funcs[func_idx].params[i], 63);
+ vars[var_count].value.num_value = evaluate();
+ vars[var_count].value.type = VAL_NUMBER;
+ var_count++;
+ }
+ consume(TOKEN_RPAREN, "Expected ')'");
+
+ int saved_token = current_token;
+ current_token = funcs[func_idx].body_start;
+ while (current_token < funcs[func_idx].body_end && peek().type != TOKEN_EOF) {
+ execute_statement();
+ }
+ current_token = saved_token;
+ var_count = saved_var_count;
+
+ for (int i = var_count - 1; i >= 0; i--) {
+ if (strcmp(vars[i].name, "__return_value") == 0) {
+ if (!first) printf(" ");
+ printf("%g", vars[i].value.num_value);
+ break;
+ }
+ }
+ } else {
+ if (!first) printf(" ");
+ printf("%g", parse_call(name));
+ }
+ } else {
+ int found = 0;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ if (!first) printf(" ");
+ if (vars[i].value.type == VAL_STRING) {
+ printf("%s", vars[i].value.str_value);
+ } else if (vars[i].value.type == VAL_ARRAY) {
+ printf("[");
+ for (int j = 0; j < vars[i].value.arr_size; j++) {
+ if (j > 0) printf(", ");
+ printf("%g", vars[i].value.arr_value[j]);
+ }
+ printf("]");
+ } else {
+ printf("%g", vars[i].value.num_value);
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (!found) error("Undefined variable: %s", name);
+ }
+ } else {
+ error("Unexpected token in print: '%s'", peek().value);
+ }
+ first = 0;
+ }
+
+ if (newline) {
+ printf("\n");
+ }
+ fflush(stdout);
+}
+
+void execute_var() {
+ consume(TOKEN_IDENTIFIER, "Expected variable name");
+ const char* name = tokens[current_token - 1].value;
+
+ if (var_count >= MAX_VARS) {
+ error("Too many variables (max %d)", MAX_VARS);
+ }
+
+ Variable* v = &vars[var_count];
+ strncpy(v->name, name, 63);
+ v->name[63] = '\0';
+ var_count++;
+
+ if (match(TOKEN_ASSIGN)) {
+ if (match(TOKEN_STRING)) {
+ strncpy(v->value.str_value, tokens[current_token - 1].value, MAX_STRING - 1);
+ v->value.str_value[MAX_STRING - 1] = '\0';
+ v->value.type = VAL_STRING;
+ v->value.num_value = 0;
+ } else if (match(TOKEN_LBRACKET)) {
+ v->value.type = VAL_ARRAY;
+ v->value.arr_size = 0;
+ while (!match(TOKEN_RBRACKET)) {
+ if (v->value.arr_size > 0) consume(TOKEN_COMMA, "Expected ',' between array elements");
+ v->value.arr_value[v->value.arr_size++] = evaluate();
+ if (v->value.arr_size >= MAX_ARRAY_SIZE) {
+ error("Array size exceeds maximum (%d)", MAX_ARRAY_SIZE);
+ }
+ }
+ } else {
+ v->value.num_value = evaluate();
+ v->value.type = VAL_NUMBER;
+ v->value.str_value[0] = '\0';
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, "__tmp_arr_result") == 0) {
+ v->value.type = vars[i].value.type;
+ v->value.arr_size = vars[i].value.arr_size;
+ for (int j = 0; j < vars[i].value.arr_size; j++) {
+ v->value.arr_value[j] = vars[i].value.arr_value[j];
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ v->value.type = VAL_NUMBER;
+ v->value.num_value = 0;
+ v->value.str_value[0] = '\0';
+ }
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after variable declaration");
+ }
+}
+
+static void skip_block() {
+ int depth = 1;
+ while (depth > 0 && peek().type != TOKEN_EOF) {
+ Token t = advance();
+ if (t.type == TOKEN_LBRACE) depth++;
+ if (t.type == TOKEN_RBRACE) depth--;
+ }
+}
+
+int execute_if() {
+ consume(TOKEN_LPAREN, "Expected '(' after 'if'");
+ double cond = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')' after condition");
+
+ if (match(TOKEN_LBRACE)) {
+ if (cond != 0) {
+ while (!match(TOKEN_RBRACE) && peek().type != TOKEN_EOF) {
+ int result = execute_statement();
+ if (result == 2 || result == 3) {
+ return result;
+ }
+ }
+ } else {
+ skip_block();
+ }
+ } else {
+ if (cond != 0) {
+ int result = execute_statement();
+ if (result == 2 || result == 3) {
+ return result;
+ }
+ } else {
+ while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
+ advance();
+ }
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+ }
+ }
+
+ if (match(TOKEN_ELSE)) {
+ if (match(TOKEN_LBRACE)) {
+ if (cond == 0) {
+ while (!match(TOKEN_RBRACE) && peek().type != TOKEN_EOF) {
+ int result = execute_statement();
+ if (result == 2 || result == 3) {
+ return result;
+ }
+ }
+ } else {
+ skip_block();
+ }
+ } else {
+ if (cond == 0) {
+ int result = execute_statement();
+ if (result == 2 || result == 3) {
+ return result;
+ }
+ } else {
+ while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
+ advance();
+ }
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+ }
+ }
+ }
+ return 0;
+}
+
+void execute_while() {
+ consume(TOKEN_LPAREN, "Expected '(' after 'while'");
+
+ int cond_start = current_token;
+ evaluate();
+ consume(TOKEN_RPAREN, "Expected ')' after condition");
+ consume(TOKEN_LBRACE, "Expected '{' after while condition");
+
+ int body_start = current_token;
+ skip_block();
+ int body_end = current_token;
+
+ int saved_loop_depth = loop_depth;
+ loop_depth++;
+
+ while (1) {
+ current_token = cond_start;
+ current_line = tokens[cond_start].line;
+ double cond = evaluate();
+
+ if (cond == 0) {
+ current_token = body_end;
+ break;
+ }
+
+ current_token = body_start;
+ while (current_token < body_end && peek().type != TOKEN_EOF && peek().type != TOKEN_RBRACE) {
+ int result = execute_statement();
+ if (result == 2) {
+ break;
+ }
+ if (result == 3) {
+ break;
+ }
+ if (result == 1) {
+ loop_depth = saved_loop_depth;
+ return;
+ }
+ }
+ }
+
+ loop_depth = saved_loop_depth;
+}
+
+void execute_for() {
+ consume(TOKEN_LPAREN, "Expected '(' after 'for'");
+
+ int init_start = current_token;
+ while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
+ advance();
+ }
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+
+ int cond_start = current_token;
+ while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
+ advance();
+ }
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+
+ int update_start = current_token;
+ while (peek().type != TOKEN_RPAREN && peek().type != TOKEN_EOF) {
+ advance();
+ }
+ consume(TOKEN_RPAREN, "Expected ')'");
+ consume(TOKEN_LBRACE, "Expected '{'");
+
+ int body_start = current_token;
+ skip_block();
+ int body_end = current_token;
+
+ int saved_token = current_token;
+ current_token = init_start;
+ in_for_loop_update = 1;
+ while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
+ execute_statement();
+ }
+ in_for_loop_update = 0;
+ current_token = saved_token;
+
+ int saved_loop_depth = loop_depth;
+ loop_depth++;
+
+ while (1) {
+ double cond = 0;
+ int temp_token = cond_start;
+ current_token = cond_start;
+ current_line = tokens[cond_start].line;
+
+ int paren_count = 0;
+ while (temp_token < token_count) {
+ if (tokens[temp_token].type == TOKEN_LPAREN) paren_count++;
+ if (tokens[temp_token].type == TOKEN_RPAREN) paren_count--;
+ if (tokens[temp_token].type == TOKEN_SEMICOLON && paren_count == 0) break;
+ temp_token++;
+ }
+
+ cond = evaluate();
+
+ if (cond == 0) {
+ break;
+ }
+
+ current_token = body_start;
+ while (current_token < body_end && peek().type != TOKEN_EOF) {
+ int result = execute_statement();
+ if (result == 2) {
+ loop_depth = saved_loop_depth;
+ return;
+ }
+ if (result == 1) {
+ loop_depth = saved_loop_depth;
+ return;
+ }
+ }
+
+ current_token = update_start;
+ in_for_loop_update = 1;
+ while (peek().type != TOKEN_RPAREN && peek().type != TOKEN_EOF) {
+ execute_statement();
+ }
+ in_for_loop_update = 0;
+ }
+
+ loop_depth = saved_loop_depth;
+}
+
+extern int in_for_loop_update;
+
+void execute_function() {
+ consume(TOKEN_IDENTIFIER, "Expected function name");
+ const char* name = tokens[current_token - 1].value;
+ consume(TOKEN_LPAREN, "Expected '(' after function name");
+
+ int func_idx = func_count;
+ strncpy(funcs[func_idx].name, name, 63);
+ funcs[func_idx].param_count = 0;
+
+ while (!match(TOKEN_RPAREN)) {
+ if (funcs[func_idx].param_count > 0) consume(TOKEN_COMMA, "Expected ','");
+ consume(TOKEN_IDENTIFIER, "Expected parameter name");
+ strncpy(funcs[func_idx].params[funcs[func_idx].param_count],
+ tokens[current_token - 1].value, 63);
+ funcs[func_idx].param_count++;
+ if (funcs[func_idx].param_count >= 8) {
+ error("Too many parameters (max 8)");
+ }
+ }
+
+ consume(TOKEN_LBRACE, "Expected '{'");
+ funcs[func_idx].body_start = current_token;
+
+ skip_block();
+ funcs[func_idx].body_end = current_token;
+ func_count++;
+}
+
+void execute_switch() {
+ consume(TOKEN_LPAREN, "Expected '('");
+ double switch_val = evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ consume(TOKEN_LBRACE, "Expected '{'");
+
+ int saved_switch_active = switch_active;
+ switch_active = 1;
+
+ int body_start = current_token;
+ skip_block();
+ int body_end = current_token;
+
+ int saved_token = current_token;
+ current_token = body_start;
+
+ int should_execute = 0;
+ while (current_token < body_end && peek().type != TOKEN_EOF) {
+ if (match(TOKEN_CASE)) {
+ double case_val = evaluate();
+ consume(TOKEN_COLON, "Expected ':' after case");
+ if (!should_execute && case_val == switch_val) {
+ should_execute = 1;
+ }
+ } else if (match(TOKEN_DEFAULT)) {
+ consume(TOKEN_COLON, "Expected ':' after default");
+ if (!should_execute) {
+ should_execute = 1;
+ }
+ } else {
+ if (should_execute) {
+ int result = execute_statement();
+ if (result == 2) {
+ break;
+ }
+ } else {
+ advance();
+ }
+ }
+ }
+
+ current_token = saved_token;
+ switch_active = saved_switch_active;
+}
+
+void execute_do_while() {
+ consume(TOKEN_LBRACE, "Expected '{'");
+
+ int body_start = current_token;
+ skip_block();
+ int body_end = current_token;
+
+ consume(TOKEN_WHILE, "Expected 'while'");
+ consume(TOKEN_LPAREN, "Expected '('");
+
+ int cond_start = current_token;
+ evaluate();
+ consume(TOKEN_RPAREN, "Expected ')'");
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+
+ int saved_loop_depth = loop_depth;
+ loop_depth++;
+
+ current_token = body_start;
+ while (current_token < body_end && peek().type != TOKEN_EOF && peek().type != TOKEN_RBRACE) {
+ int result = execute_statement();
+ if (result == 2) {
+ break;
+ }
+ if (result == 3) {
+ break;
+ }
+ if (result == 1) {
+ loop_depth = saved_loop_depth;
+ return;
+ }
+ }
+
+ while (1) {
+ current_token = cond_start;
+ current_line = tokens[cond_start].line;
+ double cond = evaluate();
+
+ if (cond == 0) {
+ break;
+ }
+
+ current_token = body_start;
+ while (current_token < body_end && peek().type != TOKEN_EOF && peek().type != TOKEN_RBRACE) {
+ int result = execute_statement();
+ if (result == 2) {
+ break;
+ }
+ if (result == 3) {
+ break;
+ }
+ if (result == 1) {
+ loop_depth = saved_loop_depth;
+ return;
+ }
+ }
+ }
+
+ loop_depth = saved_loop_depth;
+}
+
+void execute_struct() {
+ consume(TOKEN_IDENTIFIER, "Expected struct name");
+ const char* name = tokens[current_token - 1].value;
+ consume(TOKEN_LBRACE, "Expected '{'");
+
+ int struct_idx = struct_count;
+ strncpy(structs[struct_idx].name, name, 63);
+ structs[struct_idx].field_count = 0;
+
+ while (peek().type != TOKEN_RBRACE && peek().type != TOKEN_EOF) {
+ if (peek().type == TOKEN_SEMICOLON) {
+ advance();
+ continue;
+ }
+ consume(TOKEN_IDENTIFIER, "Expected field name");
+ strncpy(structs[struct_idx].fields[structs[struct_idx].field_count],
+ tokens[current_token - 1].value, 63);
+ structs[struct_idx].field_count++;
+ if (structs[struct_idx].field_count >= 16) {
+ error("Too many fields in struct (max 16)");
+ }
+ if (peek().type == TOKEN_SEMICOLON) {
+ advance();
+ }
+ }
+
+ consume(TOKEN_RBRACE, "Expected '}'");
+ struct_count++;
+ if (match(TOKEN_SEMICOLON)) {
+ }
+}
+
+void execute_enum() {
+ consume(TOKEN_IDENTIFIER, "Expected enum name");
+ const char* name = tokens[current_token - 1].value;
+ consume(TOKEN_LBRACE, "Expected '{'");
+
+ int enum_idx = enum_count;
+ strncpy(enums[enum_idx].name, name, 63);
+ enums[enum_idx].value_count = 0;
+
+ while (peek().type != TOKEN_RBRACE && peek().type != TOKEN_EOF) {
+ consume(TOKEN_IDENTIFIER, "Expected enum value");
+ strncpy(enums[enum_idx].values[enums[enum_idx].value_count],
+ tokens[current_token - 1].value, 63);
+ enums[enum_idx].value_count++;
+ if (enums[enum_idx].value_count >= 16) {
+ error("Too many values in enum (max 16)");
+ }
+ if (match(TOKEN_COMMA)) {
+ continue;
+ }
+ break;
+ }
+
+ consume(TOKEN_RBRACE, "Expected '}'");
+ enum_count++;
+ if (match(TOKEN_SEMICOLON)) {
+ }
+}
+
+void execute_typedef() {
+ consume(TOKEN_IDENTIFIER, "Expected original type");
+ const char* orig_type = tokens[current_token - 1].value;
+ consume(TOKEN_IDENTIFIER, "Expected new type name");
+ const char* new_name = tokens[current_token - 1].value;
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+
+ int struct_idx = find_struct(orig_type);
+ if (struct_idx >= 0) {
+ strncpy(structs[struct_count].name, new_name, 63);
+ structs[struct_count].field_count = structs[struct_idx].field_count;
+ for (int i = 0; i < structs[struct_idx].field_count; i++) {
+ strncpy(structs[struct_count].fields[i], structs[struct_idx].fields[i], 63);
+ }
+ struct_count++;
+ } else {
+ int enum_idx = find_enum(orig_type);
+ if (enum_idx >= 0) {
+ strncpy(enums[enum_count].name, new_name, 63);
+ enums[enum_count].value_count = enums[enum_idx].value_count;
+ for (int i = 0; i < enums[enum_idx].value_count; i++) {
+ strncpy(enums[enum_count].values[i], enums[enum_idx].values[i], 63);
+ }
+ enum_count++;
+ }
+ }
+}
+
+void execute_goto() {
+ consume(TOKEN_IDENTIFIER, "Expected label name");
+ const char* name = tokens[current_token - 1].value;
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+
+ int label_idx = find_label(name);
+ if (label_idx < 0) {
+ error("Undefined label: %s", name);
+ }
+ current_token = labels[label_idx].token_index;
+}
+
+void execute_new() {
+ consume(TOKEN_IDENTIFIER, "Expected type name");
+ const char* type_name = tokens[current_token - 1].value;
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+
+ int struct_idx = find_struct(type_name);
+ if (struct_idx >= 0) {
+ strncpy(vars[var_count].name, "__tmp_struct_result", 63);
+ vars[var_count].value.type = VAL_STRUCT;
+ vars[var_count].value.struct_type = struct_idx;
+ var_count++;
+ }
+}
+
+void execute_delete() {
+ consume(TOKEN_IDENTIFIER, "Expected variable name");
+ const char* name = tokens[current_token - 1].value;
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ for (int j = i; j < var_count - 1; j++) {
+ vars[j] = vars[j + 1];
+ }
+ var_count--;
+ return;
+ }
+ }
+ error("Undefined variable: %s", name);
+}
+
+void execute_try_catch() {
+ consume(TOKEN_LBRACE, "Expected '{'");
+
+ int try_start = current_token;
+ skip_block();
+ int try_end = current_token;
+
+ consume(TOKEN_CATCH, "Expected 'catch'");
+ consume(TOKEN_LPAREN, "Expected '('");
+ consume(TOKEN_IDENTIFIER, "Expected exception variable name");
+ const char* exc_name = tokens[current_token - 1].value;
+ consume(TOKEN_RPAREN, "Expected ')'");
+ consume(TOKEN_LBRACE, "Expected '{'");
+
+ int catch_start = current_token;
+ skip_block();
+ int catch_end = current_token;
+
+ int saved_var_count = var_count;
+
+ current_token = try_start;
+ while (current_token < try_end && peek().type != TOKEN_EOF && peek().type != TOKEN_RBRACE) {
+ int result = execute_statement();
+ if (result == 1) {
+ var_count = saved_var_count;
+ return;
+ }
+ }
+
+ var_count = saved_var_count;
+}
+
+void execute_throw() {
+ evaluate();
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+}
+
+void execute_return() {
+ if (peek().type == TOKEN_SEMICOLON || peek().type == TOKEN_RBRACE) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after return");
+ return;
+ }
+ double val = evaluate();
+ consume(TOKEN_SEMICOLON, "Expected ';' after return");
+ for (int i = var_count - 1; i >= 0; i--) {
+ if (strcmp(vars[i].name, "__return_value") == 0) {
+ vars[i].value.num_value = val;
+ vars[i].value.type = VAL_NUMBER;
+ return;
+ }
+ }
+ strncpy(vars[var_count].name, "__return_value", 63);
+ vars[var_count].value.num_value = val;
+ vars[var_count].value.type = VAL_NUMBER;
+ var_count++;
+}
+
+int execute_statement() {
+ Token t = peek();
+
+ switch (t.type) {
+ case TOKEN_PRINT:
+ advance();
+ execute_print();
+ consume(TOKEN_SEMICOLON, "Expected ';' after print");
+ return 0;
+
+ case TOKEN_VAR:
+ advance();
+ execute_var();
+ return 0;
+
+ case TOKEN_IF:
+ advance();
+ return execute_if();
+
+ case TOKEN_WHILE:
+ advance();
+ execute_while();
+ return 0;
+
+ case TOKEN_FOR:
+ advance();
+ execute_for();
+ return 0;
+
+ case TOKEN_FUNCTION:
+ advance();
+ execute_function();
+ return 0;
+
+ case TOKEN_SWITCH:
+ advance();
+ execute_switch();
+ return 0;
+
+ case TOKEN_DO:
+ advance();
+ execute_do_while();
+ return 0;
+
+ case TOKEN_BREAK:
+ advance();
+ consume(TOKEN_SEMICOLON, "Expected ';' after break");
+ if (loop_depth == 0 && !switch_active) {
+ error("break outside loop or switch");
+ }
+ return 2;
+
+ case TOKEN_CONTINUE:
+ advance();
+ consume(TOKEN_SEMICOLON, "Expected ';' after continue");
+ if (loop_depth == 0) {
+ error("continue outside loop");
+ }
+ return 3;
+
+ case TOKEN_RETURN:
+ advance();
+ execute_return();
+ return 1;
+
+ case TOKEN_STRUCT:
+ advance();
+ execute_struct();
+ return 0;
+
+ case TOKEN_ENUM:
+ advance();
+ execute_enum();
+ return 0;
+
+ case TOKEN_TYPEDEF:
+ advance();
+ execute_typedef();
+ return 0;
+
+ case TOKEN_GOTO:
+ advance();
+ execute_goto();
+ return 0;
+
+ case TOKEN_NEW:
+ advance();
+ execute_new();
+ return 0;
+
+ case TOKEN_DELETE:
+ advance();
+ execute_delete();
+ return 0;
+
+ case TOKEN_TRY:
+ advance();
+ execute_try_catch();
+ return 0;
+
+ case TOKEN_THROW:
+ advance();
+ execute_throw();
+ return 0;
+
+ case TOKEN_LABEL:
+ advance();
+ return 0;
+
+ case TOKEN_IDENTIFIER: {
+ advance();
+ if (match(TOKEN_ASSIGN)) {
+ const char* name = tokens[current_token - 2].value;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ if (match(TOKEN_STRING)) {
+ strncpy(vars[i].value.str_value, tokens[current_token - 1].value, MAX_STRING - 1);
+ vars[i].value.str_value[MAX_STRING - 1] = '\0';
+ vars[i].value.type = VAL_STRING;
+ } else if (match(TOKEN_LBRACKET)) {
+ vars[i].value.type = VAL_ARRAY;
+ vars[i].value.arr_size = 0;
+ while (!match(TOKEN_RBRACKET)) {
+ if (vars[i].value.arr_size > 0) consume(TOKEN_COMMA, "Expected ','");
+ vars[i].value.arr_value[vars[i].value.arr_size++] = evaluate();
+ }
+ } else {
+ vars[i].value.num_value = evaluate();
+ vars[i].value.type = VAL_NUMBER;
+ }
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
+ }
+ return 0;
+ }
+ }
+ error("Undefined variable: %s", name);
+ } else if (match(TOKEN_PLUS_ASSIGN)) {
+ const char* name = tokens[current_token - 2].value;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ if (vars[i].value.type == VAL_STRING) {
+ const char* str = tokens[current_token].value;
+ strncat(vars[i].value.str_value, str, MAX_STRING - strlen(vars[i].value.str_value) - 1);
+ } else {
+ vars[i].value.num_value += evaluate();
+ }
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
+ }
+ return 0;
+ }
+ }
+ error("Undefined variable: %s", name);
+ } else if (match(TOKEN_MINUS_ASSIGN)) {
+ const char* name = tokens[current_token - 2].value;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ vars[i].value.num_value -= evaluate();
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
+ }
+ return 0;
+ }
+ }
+ error("Undefined variable: %s", name);
+ } else if (match(TOKEN_MULTIPLY_ASSIGN)) {
+ const char* name = tokens[current_token - 2].value;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ vars[i].value.num_value *= evaluate();
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
+ }
+ return 0;
+ }
+ }
+ error("Undefined variable: %s", name);
+ } else if (match(TOKEN_DIVIDE_ASSIGN)) {
+ const char* name = tokens[current_token - 2].value;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ double right = evaluate();
+ if (right == 0) error("Division by zero");
+ vars[i].value.num_value /= right;
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
+ }
+ return 0;
+ }
+ }
+ error("Undefined variable: %s", name);
+ } else if (match(TOKEN_MODULO_ASSIGN)) {
+ const char* name = tokens[current_token - 2].value;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ double right = evaluate();
+ if (right == 0) error("Modulo by zero");
+ vars[i].value.num_value = fmod(vars[i].value.num_value, right);
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
+ }
+ return 0;
+ }
+ }
+ error("Undefined variable: %s", name);
+ } else if (match(TOKEN_INCREMENT)) {
+ const char* name = tokens[current_token - 2].value;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ vars[i].value.num_value++;
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after increment");
+ }
+ return 0;
+ }
+ }
+ error("Undefined variable: %s", name);
+ } else if (match(TOKEN_DECREMENT)) {
+ const char* name = tokens[current_token - 2].value;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ vars[i].value.num_value--;
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';' after decrement");
+ }
+ return 0;
+ }
+ }
+ error("Undefined variable: %s", name);
+ } else if (peek().type == TOKEN_LBRACKET) {
+ const char* name = tokens[current_token - 1].value;
+ for (int i = 0; i < var_count; i++) {
+ if (strcmp(vars[i].name, name) == 0) {
+ advance();
+ int index = (int)evaluate();
+ consume(TOKEN_RBRACKET, "Expected ']'");
+ if (match(TOKEN_ASSIGN)) {
+ vars[i].value.arr_value[index] = evaluate();
+ if (!in_for_loop_update) {
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+ }
+ } else {
+ printf("%g\n", vars[i].value.arr_value[index]);
+ }
+ return 0;
+ }
+ }
+ error("Undefined variable: %s", name);
+ } else if (peek().type == TOKEN_LPAREN) {
+ const char* name = tokens[current_token - 1].value;
+ int func_idx = find_function(name);
+ if (func_idx >= 0) {
+ consume(TOKEN_LPAREN, "Expected '('");
+ int saved_var_count = var_count;
+ for (int i = 0; i < funcs[func_idx].param_count; i++) {
+ if (i > 0) consume(TOKEN_COMMA, "Expected ','");
+ strncpy(vars[var_count].name, funcs[func_idx].params[i], 63);
+ vars[var_count].value.num_value = evaluate();
+ vars[var_count].value.type = VAL_NUMBER;
+ var_count++;
+ }
+ consume(TOKEN_RPAREN, "Expected ')'");
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+
+ int saved_token = current_token;
+ current_token = funcs[func_idx].body_start;
+ while (current_token < funcs[func_idx].body_end && peek().type != TOKEN_EOF) {
+ if (execute_statement() == 1) break;
+ }
+ current_token = saved_token;
+ var_count = saved_var_count;
+ return 0;
+ }
+
+ parse_call(name);
+ consume(TOKEN_SEMICOLON, "Expected ';'");
+ return 0;
+ }
+ error("Unexpected identifier: %s", tokens[current_token - 1].value);
+ return 0;
+ }
+
+ case TOKEN_EOF:
+ break;
+
+ default:
+ error("Unexpected token: %s", t.value);
+ }
+ return 0;
+}
+
+void parse_config(const char* source) {
+ print_newline = 1;
+ const char* p = source;
+
+ while (*p) {
+ if (*p == ' ' || *p == '\t' || *p == '\r') {
+ p++;
+ continue;
+ }
+ if (*p == '\n') break;
+ if (*p == '#') {
+ while (*p && *p != '\n') p++;
+ continue;
+ }
+ if (*p == 's' && *(p+1) == 'g' && *(p+2) == '<') {
+ p += 3;
+ while (*p && *p != '>') {
+ if (strncmp(p, "nel", 3) == 0) {
+ print_newline = 0;
+ break;
+ }
+ p++;
+ }
+ break;
+ }
+ break;
+ }
+}
+
+char* strip_config(const char* source) {
+ const char* p = source;
+
+ while (*p) {
+ if (*p == ' ' || *p == '\t' || *p == '\r') {
+ p++;
+ continue;
+ }
+ if (*p == '\n') {
+ return strdup(source);
+ }
+ if (*p == '#') {
+ while (*p && *p != '\n') p++;
+ if (*p == '\n') p++;
+ continue;
+ }
+ if (*p == 's' && *(p+1) == 'g' && *(p+2) == '<') {
+ const char* start = p;
+ while (*p && *p != '\n') p++;
+ if (*p == '\n') p++;
+
+ size_t prefix_len = start - source;
+ size_t suffix_len = strlen(p);
+ char* result = malloc(prefix_len + suffix_len + 1);
+ if (!result) error("Out of memory");
+
+ memcpy(result, source, prefix_len);
+ memcpy(result + prefix_len, p, suffix_len + 1);
+ return result;
+ }
+ return strdup(source);
+ }
+ return strdup(source);
+}
+
+void run(const char* source) {
+ static int rand_seeded = 0;
+ if (!rand_seeded) {
+ srand(time(NULL));
+ rand_seeded = 1;
+ }
+
+ parse_config(source);
+ char* clean_source = strip_config(source);
+ tokenize(clean_source);
+ current_token = 0;
+
+ while (peek().type != TOKEN_EOF) {
+ execute_statement();
+ }
+
+ free(clean_source);
+}
+
+void run_file(const char* path) {
+ FILE* f = fopen(path, "r");
+ if (!f) {
+ error("Cannot open file: %s", path);
+ }
+
+ fseek(f, 0, SEEK_END);
+ long size = ftell(f);
+ if (size < 0) {
+ fclose(f);
+ error("Cannot read file: %s", path);
+ }
+ fseek(f, 0, SEEK_SET);
+
+ char* source = malloc(size + 1);
+ if (!source) {
+ fclose(f);
+ error("Out of memory");
+ }
+
+ size_t read = fread(source, 1, size, f);
+ fclose(f);
+ source[read] = '\0';
+
+ run(source);
+ free(source);
+}
+
+void run_repl() {
+ in_repl = 1;
+ printf("Oraset B-5 REPL\n");
+ printf("Type 'exit' or 'quit' to exit.\n");
+ printf("> ");
+
+ char line[MAX_LINE];
+ while (fgets(line, MAX_LINE, stdin)) {
+ line[strcspn(line, "\n")] = '\0';
+
+ if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) {
+ break;
+ }
+ if (strcmp(line, "") == 0) {
+ printf("> ");
+ continue;
+ }
+
+ char* source = malloc(strlen(line) + 2);
+ strcpy(source, line);
+ strcat(source, "\n");
+
+ static int rand_seeded = 0;
+ if (!rand_seeded) {
+ srand(time(NULL));
+ rand_seeded = 1;
+ }
+
+ parse_config(source);
+ char* clean_source = strip_config(source);
+ tokenize(clean_source);
+ current_token = 0;
+
+ while (peek().type != TOKEN_EOF) {
+ execute_statement();
+ }
+
+ free(clean_source);
+ free(source);
+ printf("> ");
+ }
+
+ printf("\n");
+ in_repl = 0;
+}
+
+#define VERSION_URL "https://oraset.parlz.com/download/version.txt"
+#define DOWNLOAD_BASE "https://oraset.parlz.com/download"
+
+static char* http_get(const char* url) {
+#ifdef _WIN32
+ HINTERNET hInternet = InternetOpenA("Oraset", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
+ if (!hInternet) return NULL;
+
+ HINTERNET hUrl = InternetOpenUrlA(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
+ if (!hUrl) {
+ InternetCloseHandle(hInternet);
+ return NULL;
+ }
+
+ char* buffer = malloc(4096);
+ if (!buffer) {
+ InternetCloseHandle(hUrl);
+ InternetCloseHandle(hInternet);
+ return NULL;
+ }
+
+ DWORD total_read = 0;
+ DWORD bytes_read;
+ char temp[1024];
+
+ while (InternetReadFile(hUrl, temp, sizeof(temp), &bytes_read) && bytes_read > 0) {
+ if (total_read + bytes_read >= 4095) {
+ char* new_buf = realloc(buffer, total_read + bytes_read + 4096);
+ if (!new_buf) {
+ free(buffer);
+ InternetCloseHandle(hUrl);
+ InternetCloseHandle(hInternet);
+ return NULL;
+ }
+ buffer = new_buf;
+ }
+ memcpy(buffer + total_read, temp, bytes_read);
+ total_read += bytes_read;
+ }
+ buffer[total_read] = '\0';
+
+ InternetCloseHandle(hUrl);
+ InternetCloseHandle(hInternet);
+ return buffer;
+#else
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "curl -s \"%s\" 2>/dev/null", url);
+ FILE* fp = popen(cmd, "r");
+ if (!fp) return NULL;
+
+ char* buffer = malloc(4096);
+ if (!buffer) {
+ pclose(fp);
+ return NULL;
+ }
+
+ size_t total_read = 0;
+ size_t bytes_read;
+ char temp[1024];
+
+ while ((bytes_read = fread(temp, 1, sizeof(temp), fp)) > 0) {
+ if (total_read + bytes_read >= 4095) {
+ char* new_buf = realloc(buffer, total_read + bytes_read + 4096);
+ if (!new_buf) {
+ free(buffer);
+ pclose(fp);
+ return NULL;
+ }
+ buffer = new_buf;
+ }
+ memcpy(buffer + total_read, temp, bytes_read);
+ total_read += bytes_read;
+ }
+ buffer[total_read] = '\0';
+ pclose(fp);
+ return buffer;
+#endif
+}
+
+static int download_file(const char* url, const char* dest_path) {
+#ifdef _WIN32
+ HINTERNET hInternet = InternetOpenA("Oraset", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
+ if (!hInternet) return -1;
+
+ HINTERNET hUrl = InternetOpenUrlA(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
+ if (!hUrl) {
+ InternetCloseHandle(hInternet);
+ return -1;
+ }
+
+ FILE* fp = fopen(dest_path, "wb");
+ if (!fp) {
+ InternetCloseHandle(hUrl);
+ InternetCloseHandle(hInternet);
+ return -1;
+ }
+
+ char temp[4096];
+ DWORD bytes_read;
+
+ while (InternetReadFile(hUrl, temp, sizeof(temp), &bytes_read) && bytes_read > 0) {
+ fwrite(temp, 1, bytes_read, fp);
+ }
+
+ fclose(fp);
+ InternetCloseHandle(hUrl);
+ InternetCloseHandle(hInternet);
+ return 0;
+#else
+ char cmd[1024];
+ snprintf(cmd, sizeof(cmd), "curl -L -o \"%s\" \"%s\" 2>/dev/null", dest_path, url);
+ return system(cmd);
+#endif
+}
+
+static void get_system_info(char* os, char* ext) {
+#ifdef _WIN32
+ strcpy(os, "windows");
+ strcpy(ext, ".exe");
+#elif defined(__APPLE__)
+ strcpy(os, "macos");
+ strcpy(ext, ".pkg");
+#elif defined(__linux__)
+ strcpy(os, "linux");
+ strcpy(ext, ".tar.gz");
+#else
+ strcpy(os, "unknown");
+ strcpy(ext, ".tar.gz");
+#endif
+}
+
+static int compare_versions(const char* v1, const char* v2) {
+ int major1 = 0, minor1 = 0, patch1 = 0, major2 = 0, minor2 = 0, patch2 = 0;
+ char suffix1[64] = "", suffix2[64] = "";
+
+ sscanf(v1, "%d.%d.%d-%63s", &major1, &minor1, &patch1, suffix1);
+ sscanf(v2, "%d.%d.%d-%63s", &major2, &minor2, &patch2, suffix2);
+
+ if (major1 != major2) return major1 - major2;
+ if (minor1 != minor2) return minor1 - minor2;
+ if (patch1 != patch2) return patch1 - patch2;
+
+ int s1 = (strstr(suffix1, "Release") || strlen(suffix1) == 0) ? 3 :
+ (strstr(suffix1, "Beta") ? 2 : 1);
+ int s2 = (strstr(suffix2, "Release") || strlen(suffix2) == 0) ? 3 :
+ (strstr(suffix2, "Beta") ? 2 : 1);
+ return s1 - s2;
+}
+
+static void trim_newline(char* str) {
+ int len = strlen(str);
+ while (len > 0 && (str[len-1] == '\n' || str[len-1] == '\r')) {
+ str[--len] = '\0';
+ }
+}
+
+int update_oraset(const char* target_version) {
+ printf("Checking for updates...\n");
+
+ char* version_info = http_get(VERSION_URL);
+ if (!version_info) {
+ fprintf(stderr, "Error: Cannot fetch version information.\n");
+ fprintf(stderr, "Please check your internet connection.\n");
+ return 1;
+ }
+
+ trim_newline(version_info);
+ char latest_version[128];
+ strncpy(latest_version, version_info, sizeof(latest_version) - 1);
+ free(version_info);
+
+ printf("Current version: %s\n", VERSION);
+ printf("Latest version: %s\n", latest_version);
+
+ const char* version_to_install = target_version ? target_version : latest_version;
+
+ if (target_version) {
+ printf("Target version specified: %s\n", version_to_install);
+ }
+
+ char os[32], ext[16];
+ get_system_info(os, ext);
+ printf("Detected OS: %s\n", os);
+
+ char download_url[512];
+ char filename[128];
+
+ if (strcmp(os, "windows") == 0) {
+ snprintf(filename, sizeof(filename), "Oraset-B5%s", ext);
+ snprintf(download_url, sizeof(download_url), "%s/exe/%s", DOWNLOAD_BASE, filename);
+ } else if (strcmp(os, "macos") == 0) {
+ snprintf(filename, sizeof(filename), "Oraset-B5%s", ext);
+ snprintf(download_url, sizeof(download_url), "%s/pkg/%s", DOWNLOAD_BASE, filename);
+ } else {
+ snprintf(filename, sizeof(filename), "Oraset-B5%s", ext);
+ snprintf(download_url, sizeof(download_url), "%s/deb/%s", DOWNLOAD_BASE, filename);
+ }
+
+ printf("Downloading: %s\n", download_url);
+
+ char temp_path[512];
+#ifdef _WIN32
+ char temp_dir[MAX_PATH];
+ GetTempPathA(MAX_PATH, temp_dir);
+ snprintf(temp_path, sizeof(temp_path), "%s%s", temp_dir, filename);
+#else
+ snprintf(temp_path, sizeof(temp_path), "/tmp/%s", filename);
+#endif
+
+ if (download_file(download_url, temp_path) != 0) {
+ fprintf(stderr, "Error: Failed to download update.\n");
+ return 1;
+ }
+
+ printf("Downloaded to: %s\n", temp_path);
+
+#ifdef _WIN32
+ printf("Please run the installer: %s\n", temp_path);
+#else
+ if (strcmp(os, "macos") == 0) {
+ printf("Installing package...\n");
+ char cmd[1024];
+ snprintf(cmd, sizeof(cmd), "sudo installer -pkg \"%s\" -target /", temp_path);
+ system(cmd);
+ } else if (strcmp(os, "linux") == 0) {
+ printf("Extracting...\n");
+ char cmd[1024];
+ snprintf(cmd, sizeof(cmd), "cd /tmp && tar -xzf \"%s\" && sudo cp oraset /usr/local/bin/", temp_path);
+ system(cmd);
+ }
+ printf("Installation complete!\n");
+#endif
+
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ if (argc == 1) {
+ printf("Oraset B-5\n");
+ printf("Usage: oraset [options]