Add new features: ternary operator, file IO, string ops, math functions, array ops, system functions
Build and Package Oraset / build (macos-latest) (push) Waiting to run
Build and Package Oraset / build (ubuntu-latest) (push) Waiting to run
Build and Package Oraset / build (windows-latest) (push) Waiting to run
Build and Package Oraset / release (push) Blocked by required conditions

This commit is contained in:
JGZ_YES
2026-07-23 15:43:44 +08:00
parent 87bd711079
commit 37ae3280e8
7 changed files with 639 additions and 8 deletions
Binary file not shown.
@@ -92,7 +92,8 @@ typedef enum {
TOKEN_CATCH,
TOKEN_THROW,
TOKEN_ASTERISK,
TOKEN_LABEL
TOKEN_LABEL,
TOKEN_QUESTION
} OraTokenType;
typedef struct {
@@ -409,6 +410,7 @@ void tokenize(const char* source) {
case '!': add_token(TOKEN_NOT, "!"); break;
case ':': add_token(TOKEN_COLON, ":"); break;
case '.': add_token(TOKEN_DOT, "."); break;
case '?': add_token(TOKEN_QUESTION, "?"); break;
default: error("Unknown character: '%c'", *p);
}
p++;
@@ -786,6 +788,271 @@ double parse_call(const char* func_name) {
}
}
return 0;
} else if (strcmp(func_name, "fopen") == 0) {
const char* filename = get_string_value();
consume(TOKEN_COMMA, "Expected ','");
const char* mode = get_string_value();
consume(TOKEN_RPAREN, "Expected ')'");
for (int i = 0; i < var_count; i++) {
if (strcmp(vars[i].name, "__tmp_file_result") == 0) {
FILE* fp = fopen(filename, mode);
vars[i].value.num_value = (double)(intptr_t)fp;
vars[i].value.type = VAL_NUMBER;
return 0;
}
}
strncpy(vars[var_count].name, "__tmp_file_result", 63);
FILE* fp = fopen(filename, mode);
vars[var_count].value.num_value = (double)(intptr_t)fp;
vars[var_count].value.type = VAL_NUMBER;
var_count++;
return 0;
} else if (strcmp(func_name, "fclose") == 0) {
double fp_val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
FILE* fp = (FILE*)(intptr_t)fp_val;
return (double)fclose(fp);
} else if (strcmp(func_name, "fgets") == 0) {
double fp_val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
FILE* fp = (FILE*)(intptr_t)fp_val;
char buf[MAX_STRING];
if (fgets(buf, MAX_STRING, fp)) {
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, "fputs") == 0) {
const char* str = get_string_value();
consume(TOKEN_COMMA, "Expected ','");
double fp_val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
FILE* fp = (FILE*)(intptr_t)fp_val;
return (double)fputs(str, fp);
} else if (strcmp(func_name, "fread") == 0) {
consume(TOKEN_IDENTIFIER, "Expected array variable");
const char* name = tokens[current_token - 1].value;
consume(TOKEN_COMMA, "Expected ','");
int count = (int)evaluate();
consume(TOKEN_COMMA, "Expected ','");
double fp_val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
FILE* fp = (FILE*)(intptr_t)fp_val;
Value* arr = find_variable(name);
if (!arr) error("Undefined variable: %s", name);
if (arr->type != VAL_ARRAY) {
arr->type = VAL_ARRAY;
arr->arr_size = 0;
}
double buf[MAX_ARRAY_SIZE];
size_t read = fread(buf, sizeof(double), count, fp);
for (int i = 0; i < read && arr->arr_size + i < MAX_ARRAY_SIZE; i++) {
arr->arr_value[arr->arr_size + i] = buf[i];
}
arr->arr_size += read;
return (double)read;
} else if (strcmp(func_name, "fwrite") == 0) {
consume(TOKEN_IDENTIFIER, "Expected array variable");
const char* name = tokens[current_token - 1].value;
consume(TOKEN_COMMA, "Expected ','");
int count = (int)evaluate();
consume(TOKEN_COMMA, "Expected ','");
double fp_val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
FILE* fp = (FILE*)(intptr_t)fp_val;
Value* arr = find_variable(name);
if (!arr || arr->type != VAL_ARRAY) error("Invalid array");
size_t written = fwrite(arr->arr_value, sizeof(double), count, fp);
return (double)written;
} else if (strcmp(func_name, "strlen") == 0) {
const char* str = get_string_value();
consume(TOKEN_RPAREN, "Expected ')'");
return strlen(str);
} else if (strcmp(func_name, "strchr") == 0) {
const char* str = get_string_value();
consume(TOKEN_COMMA, "Expected ','");
double ch = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
const char* found = strchr(str, (int)ch);
return found ? (double)(found - str) : -1;
} else if (strcmp(func_name, "strstr") == 0) {
const char* str = get_string_value();
consume(TOKEN_COMMA, "Expected ','");
const char* substr = get_string_value();
consume(TOKEN_RPAREN, "Expected ')'");
const char* found = strstr(str, substr);
return found ? (double)(found - str) : -1;
} else if (strcmp(func_name, "tolower") == 0) {
const char* str = 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, str, MAX_STRING - 1);
for (int j = 0; vars[i].value.str_value[j]; j++) {
vars[i].value.str_value[j] = tolower(vars[i].value.str_value[j]);
}
vars[i].value.type = VAL_STRING;
return 0;
}
}
strncpy(vars[var_count].name, "__tmp_str_result", 63);
strncpy(vars[var_count].value.str_value, str, MAX_STRING - 1);
for (int j = 0; vars[var_count].value.str_value[j]; j++) {
vars[var_count].value.str_value[j] = tolower(vars[var_count].value.str_value[j]);
}
vars[var_count].value.type = VAL_STRING;
var_count++;
return 0;
} else if (strcmp(func_name, "toupper") == 0) {
const char* str = 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, str, MAX_STRING - 1);
for (int j = 0; vars[i].value.str_value[j]; j++) {
vars[i].value.str_value[j] = toupper(vars[i].value.str_value[j]);
}
vars[i].value.type = VAL_STRING;
return 0;
}
}
strncpy(vars[var_count].name, "__tmp_str_result", 63);
strncpy(vars[var_count].value.str_value, str, MAX_STRING - 1);
for (int j = 0; vars[var_count].value.str_value[j]; j++) {
vars[var_count].value.str_value[j] = toupper(vars[var_count].value.str_value[j]);
}
vars[var_count].value.type = VAL_STRING;
var_count++;
return 0;
} else if (strcmp(func_name, "asin") == 0) {
double val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
return asin(val);
} else if (strcmp(func_name, "acos") == 0) {
double val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
return acos(val);
} else if (strcmp(func_name, "atan") == 0) {
double val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
return atan(val);
} else if (strcmp(func_name, "atan2") == 0) {
double y = evaluate();
consume(TOKEN_COMMA, "Expected ','");
double x = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
return atan2(y, x);
} else if (strcmp(func_name, "log10") == 0) {
double val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
return log10(val);
} else if (strcmp(func_name, "exp") == 0) {
double val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
return exp(val);
} else if (strcmp(func_name, "system") == 0) {
const char* cmd = get_string_value();
consume(TOKEN_RPAREN, "Expected ')'");
return (double)system(cmd);
} else if (strcmp(func_name, "getenv") == 0) {
const char* name = get_string_value();
consume(TOKEN_RPAREN, "Expected ')'");
const char* val = getenv(name);
if (val) {
for (int i = 0; i < var_count; i++) {
if (strcmp(vars[i].name, "__tmp_str_result") == 0) {
strncpy(vars[i].value.str_value, val, 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, val, 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, "sleep") == 0) {
double seconds = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
#ifdef OS_WINDOWS
Sleep((DWORD)(seconds * 1000));
#else
sleep((unsigned int)seconds);
#endif
return 0;
} else if (strcmp(func_name, "push") == 0) {
consume(TOKEN_IDENTIFIER, "Expected array variable");
const char* name = tokens[current_token - 1].value;
consume(TOKEN_COMMA, "Expected ','");
double val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
Value* arr = find_variable(name);
if (!arr) error("Undefined variable: %s", name);
if (arr->type != VAL_ARRAY) {
arr->type = VAL_ARRAY;
arr->arr_size = 0;
}
if (arr->arr_size >= MAX_ARRAY_SIZE) {
error("Array size exceeds maximum (%d)", MAX_ARRAY_SIZE);
}
arr->arr_value[arr->arr_size++] = val;
return 0;
} else if (strcmp(func_name, "pop") == 0) {
consume(TOKEN_IDENTIFIER, "Expected array variable");
const char* name = tokens[current_token - 1].value;
consume(TOKEN_RPAREN, "Expected ')'");
Value* arr = find_variable(name);
if (!arr || arr->type != VAL_ARRAY || arr->arr_size == 0) {
error("Cannot pop from empty array");
}
return arr->arr_value[--arr->arr_size];
} else if (strcmp(func_name, "insert") == 0) {
consume(TOKEN_IDENTIFIER, "Expected array variable");
const char* name = tokens[current_token - 1].value;
consume(TOKEN_COMMA, "Expected ','");
int index = (int)evaluate();
consume(TOKEN_COMMA, "Expected ','");
double val = evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
Value* arr = find_variable(name);
if (!arr || arr->type != VAL_ARRAY) error("Invalid array");
if (index < 0 || index > arr->arr_size) error("Array index out of bounds");
if (arr->arr_size >= MAX_ARRAY_SIZE) error("Array full");
for (int i = arr->arr_size; i > index; i--) {
arr->arr_value[i] = arr->arr_value[i - 1];
}
arr->arr_value[index] = val;
arr->arr_size++;
return 0;
} else if (strcmp(func_name, "remove") == 0) {
consume(TOKEN_IDENTIFIER, "Expected array variable");
const char* name = tokens[current_token - 1].value;
consume(TOKEN_COMMA, "Expected ','");
int index = (int)evaluate();
consume(TOKEN_RPAREN, "Expected ')'");
Value* arr = find_variable(name);
if (!arr || arr->type != VAL_ARRAY) error("Invalid array");
if (index < 0 || index >= arr->arr_size) error("Array index out of bounds");
double result = arr->arr_value[index];
for (int i = index; i < arr->arr_size - 1; i++) {
arr->arr_value[i] = arr->arr_value[i + 1];
}
arr->arr_size--;
return result;
} else {
int func_idx = find_function(func_name);
if (func_idx >= 0) {
@@ -1002,8 +1269,19 @@ double parse_logic_or() {
return left;
}
double parse_ternary() {
double cond = parse_logic_or();
if (match(TOKEN_QUESTION)) {
double true_val = parse_ternary();
consume(TOKEN_COLON, "Expected ':' in ternary expression");
double false_val = parse_ternary();
return cond != 0 ? true_val : false_val;
}
return cond;
}
double evaluate() {
return parse_logic_or();
return parse_ternary();
}
void execute_print() {