Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 37ae3280e8 |
@@ -28,12 +28,14 @@ A modern, C++-style scripting language designed for ease of use and powerful fun
|
||||
- Logical: `&&`, `||`, `!`
|
||||
- Compound: `+=`, `-=`, `*=`, `/=`, `%=`
|
||||
- Increment/Decrement: `++`, `--`
|
||||
- Ternary: `condition ? true_value : false_value`
|
||||
|
||||
### Built-in Functions
|
||||
- **Mathematical**: `abs`, `sqrt`, `sin`, `cos`, `tan`, `pow`, `log`, `floor`, `ceil`, `round`
|
||||
- **String**: `strcmp`, `strcpy`, `strcat`, `sizeof`
|
||||
- **Array**: `arrlen`, `memcpy`, `memcmp`, `malloc`
|
||||
- **Utility**: `echo`, `input`, `time`, `random`, `exit`, `assert`
|
||||
- **Mathematical**: `abs`, `sqrt`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2`, `pow`, `log`, `log10`, `exp`, `floor`, `ceil`, `round`
|
||||
- **String**: `strcmp`, `strcpy`, `strcat`, `strlen`, `strchr`, `strstr`, `tolower`, `toupper`, `sizeof`
|
||||
- **Array**: `arrlen`, `memcpy`, `memcmp`, `malloc`, `push`, `pop`, `insert`, `remove`
|
||||
- **File IO**: `fopen`, `fclose`, `fread`, `fwrite`, `fgets`, `fputs`
|
||||
- **System**: `echo`, `input`, `time`, `random`, `exit`, `assert`, `system`, `getenv`, `sleep`
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
||||
Binary file not shown.
+280
-2
@@ -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() {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Hello World
|
||||
@@ -0,0 +1,72 @@
|
||||
echo("=== 新功能测试 ===");
|
||||
|
||||
echo("");
|
||||
echo("=== 三元运算符测试 ===");
|
||||
let a = 10;
|
||||
let b = 20;
|
||||
let max = (a > b) ? a : b;
|
||||
echo("max =", max);
|
||||
let min = (a < b) ? a : b;
|
||||
echo("min =", min);
|
||||
|
||||
echo("");
|
||||
echo("=== 文件IO测试 ===");
|
||||
fopen("test_io.txt", "w");
|
||||
fputs("Hello World\n", __tmp_file_result);
|
||||
fclose(__tmp_file_result);
|
||||
|
||||
fopen("test_io.txt", "r");
|
||||
fgets(__tmp_file_result);
|
||||
echo("读取第一行:", __tmp_str_result);
|
||||
fclose(__tmp_file_result);
|
||||
|
||||
echo("");
|
||||
echo("=== 字符串函数测试 ===");
|
||||
let s = "Hello World";
|
||||
echo("strlen(s) =", strlen(s));
|
||||
echo("strchr(s, 'W') =", strchr(s, 87));
|
||||
echo("strstr(s, 'World') =", strstr(s, "World"));
|
||||
|
||||
toupper(s);
|
||||
echo("toupper:", __tmp_str_result);
|
||||
|
||||
tolower(__tmp_str_result);
|
||||
echo("tolower:", __tmp_str_result);
|
||||
|
||||
echo("");
|
||||
echo("=== 数学函数测试 ===");
|
||||
echo("sin(0) =", sin(0));
|
||||
echo("cos(0) =", cos(0));
|
||||
echo("asin(0) =", asin(0));
|
||||
echo("acos(1) =", acos(1));
|
||||
echo("atan(0) =", atan(0));
|
||||
echo("atan2(1, 0) =", atan2(1, 0));
|
||||
echo("log10(100) =", log10(100));
|
||||
echo("exp(1) =", exp(1));
|
||||
|
||||
echo("");
|
||||
echo("=== 数组操作测试 ===");
|
||||
let arr = [1, 2, 3];
|
||||
echo("初始数组:", arr);
|
||||
|
||||
push(arr, 4);
|
||||
echo("push后:", arr);
|
||||
|
||||
let popped = pop(arr);
|
||||
echo("pop出:", popped);
|
||||
echo("pop后:", arr);
|
||||
|
||||
insert(arr, 1, 99);
|
||||
echo("insert后:", arr);
|
||||
|
||||
let removed = remove(arr, 1);
|
||||
echo("remove出:", removed);
|
||||
echo("remove后:", arr);
|
||||
|
||||
echo("");
|
||||
echo("=== 系统函数测试 ===");
|
||||
getenv("PATH");
|
||||
echo("PATH长度:", strlen(__tmp_str_result));
|
||||
|
||||
echo("");
|
||||
echo("所有新功能测试完成!");
|
||||
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() {
|
||||
|
||||
Reference in New Issue
Block a user