#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]