Compare commits
42
Commits
master
..
f310788168
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f310788168 | ||
|
|
e17b235ecc | ||
|
|
4dc33c81b4 | ||
|
|
c08fa0cc6a | ||
|
|
3252560f94 | ||
|
|
ded2448ebd | ||
|
|
fc05199a76 | ||
|
|
863434f9af | ||
|
|
f61c15061d | ||
|
|
e7b8f7f68c | ||
|
|
cecbdc4053 | ||
|
|
1b57b479bb | ||
|
|
b3b117d3a5 | ||
|
|
6aa82a613e | ||
|
|
dfba1c40c4 | ||
|
|
46c18308b8 | ||
|
|
0474c958fe | ||
|
|
d0fc94f0c0 | ||
|
|
2f20998f22 | ||
|
|
0db921cfa3 | ||
|
|
a1eb00caff | ||
|
|
8f175b3563 | ||
|
|
eacf4f3e36 | ||
|
|
3cbf684dad | ||
|
|
e75ccec309 | ||
|
|
97fc55f74d | ||
|
|
327eeadca4 | ||
|
|
e5f6f89764 | ||
|
|
2dae3f98e9 | ||
|
|
0ec0590ad0 | ||
|
|
6c8a15272a | ||
|
|
5828aa8622 | ||
|
|
050e85b72a | ||
|
|
63f9eb48a4 | ||
|
|
5e1901105a | ||
|
|
f315874236 | ||
|
|
bd8d9d819e | ||
|
|
e6d75958c8 | ||
|
|
d087be7ab3 | ||
|
|
e691b109f2 | ||
|
|
cb9b4e2941 | ||
|
|
ab71aa9999 |
@@ -22,8 +22,6 @@ SOURCES = $(SRC_DIR)/main.c \
|
||||
$(SRC_DIR)/error.c \
|
||||
$(SRC_DIR)/context.c \
|
||||
$(SRC_DIR)/debug.c \
|
||||
$(SRC_DIR)/memory.c \
|
||||
$(SRC_DIR)/scope.c \
|
||||
$(SRC_DIR)/stdlib/stdlib.c \
|
||||
$(SRC_DIR)/stdlib/string/string_stdlib.c \
|
||||
$(SRC_DIR)/stdlib/math/math_stdlib.c \
|
||||
@@ -32,7 +30,6 @@ SOURCES = $(SRC_DIR)/main.c \
|
||||
$(SRC_DIR)/stdlib/async/async_stdlib.c \
|
||||
$(SRC_DIR)/stdlib/constants/constants_stdlib.c \
|
||||
$(SRC_DIR)/stdlib/eval/eval_stdlib.c \
|
||||
$(SRC_DIR)/stdlib/benchmark/benchmark_stdlib.c \
|
||||
|
||||
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
|
||||
|
||||
@@ -44,7 +41,6 @@ TESTS = $(TEST_DIR)/unittest.rc \
|
||||
$(TEST_DIR)/test_stdlib_socket.rc \
|
||||
$(TEST_DIR)/test_stdlib_async.rc \
|
||||
$(TEST_DIR)/test_stdlib_constants.rc \
|
||||
$(TEST_DIR)/test_stdlib_benchmark.rc \
|
||||
$(TEST_DIR)/test_oop.rc \
|
||||
$(TEST_DIR)/test_preprocessor.rc \
|
||||
$(TEST_DIR)/test_eval.rc \
|
||||
@@ -68,7 +64,6 @@ dirs:
|
||||
@mkdir -p $(BUILD_DIR)/stdlib/async
|
||||
@mkdir -p $(BUILD_DIR)/stdlib/constants
|
||||
@mkdir -p $(BUILD_DIR)/stdlib/eval
|
||||
@mkdir -p $(BUILD_DIR)/stdlib/benchmark
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
@mkdir -p $(dir $@)
|
||||
@@ -85,40 +80,37 @@ test: $(TARGET)
|
||||
@echo " RC LANGUAGE - COMPREHENSIVE TEST SUITE"
|
||||
@echo "================================================================"
|
||||
@echo ""
|
||||
@echo "[1/12] Running Language Features Tests..."
|
||||
@echo "[1/11] Running Language Features Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_language_features.rc
|
||||
@echo ""
|
||||
@echo "[2/12] Running String Standard Library Tests..."
|
||||
@echo "[2/11] Running String Standard Library Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_stdlib_string.rc
|
||||
@echo ""
|
||||
@echo "[3/12] Running Math Standard Library Tests..."
|
||||
@echo "[3/11] Running Math Standard Library Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_stdlib_math.rc
|
||||
@echo ""
|
||||
@echo "[4/12] Running I/O Standard Library Tests..."
|
||||
@echo "[4/11] Running I/O Standard Library Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_stdlib_io.rc
|
||||
@echo ""
|
||||
@echo "[5/12] Running Socket Standard Library Tests..."
|
||||
@echo "[5/11] Running Socket Standard Library Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_stdlib_socket.rc
|
||||
@echo ""
|
||||
@echo "[6/12] Running Async Standard Library Tests..."
|
||||
@echo "[6/11] Running Async Standard Library Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_stdlib_async.rc
|
||||
@echo ""
|
||||
@echo "[7/12] Running Constants Standard Library Tests..."
|
||||
@echo "[7/11] Running Constants Standard Library Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_stdlib_constants.rc
|
||||
@echo ""
|
||||
@echo "[8/12] Running Benchmark Standard Library Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_stdlib_benchmark.rc
|
||||
@echo ""
|
||||
@echo "[9/12] Running OOP Features Tests..."
|
||||
@echo "[8/11] Running OOP Features Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_oop.rc
|
||||
@echo ""
|
||||
@echo "[10/12] Running Preprocessor Tests..."
|
||||
@echo "[9/11] Running Preprocessor Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_preprocessor.rc
|
||||
@echo ""
|
||||
@echo "[11/12] Running Eval Function Tests..."
|
||||
@echo "[10/11] Running Eval Function Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_eval.rc
|
||||
@echo ""
|
||||
@echo "[12/12] Running Input Validation Tests..."
|
||||
@echo "[11/11] Running Input Validation Tests..."
|
||||
@$(TARGET) $(TEST_DIR)/test_input_validation.rc
|
||||
@echo ""
|
||||
@echo "================================================================"
|
||||
@@ -161,9 +153,6 @@ test-validation: $(TARGET)
|
||||
test-constants: $(TARGET)
|
||||
$(TARGET) $(TEST_DIR)/test_stdlib_constants.rc
|
||||
|
||||
test-benchmark: $(TARGET)
|
||||
$(TARGET) $(TEST_DIR)/test_stdlib_benchmark.rc
|
||||
|
||||
test-robustness: $(TARGET)
|
||||
$(TARGET) $(TEST_DIR)/test_robustness.rc
|
||||
|
||||
@@ -198,7 +187,7 @@ help:
|
||||
@echo ""
|
||||
@echo "Usage:"
|
||||
@echo " make - Build the interpreter"
|
||||
@echo " make test - Run ALL comprehensive tests (300+ tests)"
|
||||
@echo " make test - Run ALL comprehensive tests (250+ tests)"
|
||||
@echo " make test-smoke - Run quick smoke test (31 tests)"
|
||||
@echo " make clean - Remove all build artifacts"
|
||||
@echo ""
|
||||
@@ -210,7 +199,6 @@ help:
|
||||
@echo " make test-socket - Socket stdlib (19 tests)"
|
||||
@echo " make test-async - Async stdlib (37 tests)"
|
||||
@echo " make test-constants - Constants stdlib (13 tests)"
|
||||
@echo " make test-benchmark - Benchmark stdlib (50 tests)"
|
||||
@echo " make test-oop - OOP features (31 tests)"
|
||||
@echo " make test-preprocessor - Preprocessor (2 tests)"
|
||||
@echo " make test-eval - Eval function (30 tests)"
|
||||
@@ -236,7 +224,6 @@ help:
|
||||
@echo " stdlib/io/ - I/O functions"
|
||||
@echo " stdlib/async/ - Async functions"
|
||||
@echo " stdlib/eval/ - Eval function"
|
||||
@echo " stdlib/benchmark/ - Benchmarking functions"
|
||||
@echo " tests/ - Test programs (unittest framework)"
|
||||
@echo " examples/ - Example programs (.rc files)"
|
||||
@echo " build/ - Compiled object files"
|
||||
|
||||
+1
-330
@@ -31,7 +31,6 @@ Complete guide to the RC (Retoor's C) programming language - a C-like interprete
|
||||
20. [Async/Await (Python-like)](#asyncawait-python-like)
|
||||
21. [Object-Oriented Programming](#object-oriented-programming)
|
||||
22. [Async I/O (Low-level)](#async-io-low-level)
|
||||
23. [Benchmarking](#benchmarking)
|
||||
|
||||
---
|
||||
|
||||
@@ -623,33 +622,6 @@ int main() {
|
||||
}
|
||||
```
|
||||
|
||||
### Random Number Functions
|
||||
|
||||
**rand()** - Returns a pseudo-random integer.
|
||||
|
||||
**srand(seed)** - Seeds the random number generator.
|
||||
|
||||
**rand_range(min, max)** - Returns a random integer in the range [min, max].
|
||||
|
||||
**time()** - Returns current Unix timestamp (seconds since epoch).
|
||||
|
||||
```c
|
||||
int main() {
|
||||
srand(time());
|
||||
|
||||
printf("Random: %d\n", rand());
|
||||
printf("Random: %d\n", rand());
|
||||
printf("Random: %d\n", rand());
|
||||
|
||||
printf("Range [1-10]: %d\n", rand_range(1, 10));
|
||||
printf("Range [1-10]: %d\n", rand_range(1, 10));
|
||||
|
||||
printf("Timestamp: %d\n", time());
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## String Manipulation Functions
|
||||
|
||||
### strpos(haystack, needle) - Find Substring
|
||||
@@ -1404,7 +1376,7 @@ Assignment: =
|
||||
|
||||
**String:** strlen, strpos, substr, upper, lower, strip, replace, startswith, endswith
|
||||
|
||||
**Math:** sqrt, pow, sin, cos, tan, abs, floor, ceil, rand, srand, rand_range, time
|
||||
**Math:** sqrt, pow, sin, cos, tan, abs, floor, ceil
|
||||
|
||||
**File I/O:** fopen, fclose, fread, fwrite, fgets, fputs, fseek, ftell, feof, fremove, frename
|
||||
|
||||
@@ -1418,8 +1390,6 @@ Assignment: =
|
||||
|
||||
**Constants:** AF_INET, SOCK_STREAM, SEEK_SET, SEEK_CUR, SEEK_END
|
||||
|
||||
**Benchmarking:** bench_start, bench_end, bench_format, bench_format_auto, bench_reset
|
||||
|
||||
## File I/O
|
||||
|
||||
### Writing to a File
|
||||
@@ -2124,302 +2094,3 @@ int main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Benchmarking
|
||||
|
||||
RC provides a high-precision benchmarking system for measuring code execution time with nanosecond accuracy.
|
||||
|
||||
### Starting a Timer
|
||||
|
||||
Use `bench_start()` to begin timing code execution:
|
||||
|
||||
```c
|
||||
int main() {
|
||||
int timer = bench_start();
|
||||
|
||||
int i = 0;
|
||||
int sum = 0;
|
||||
while (i < 1000) {
|
||||
sum = sum + i;
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int elapsed = bench_end(timer);
|
||||
printf("Elapsed: %d nanoseconds\n", elapsed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Formatting Time
|
||||
|
||||
Use `bench_format()` to format time in specific units:
|
||||
|
||||
```c
|
||||
int main() {
|
||||
int timer = bench_start();
|
||||
|
||||
int result = fibonacci(20);
|
||||
|
||||
int elapsed = bench_end(timer);
|
||||
|
||||
printf("Nanoseconds: %s\n", bench_format(elapsed, 0));
|
||||
printf("Microseconds: %s\n", bench_format(elapsed, 1));
|
||||
printf("Milliseconds: %s\n", bench_format(elapsed, 2));
|
||||
printf("Seconds: %s\n", bench_format(elapsed, 3));
|
||||
printf("Minutes: %s\n", bench_format(elapsed, 4));
|
||||
printf("Hours: %s\n", bench_format(elapsed, 5));
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**Time Units:**
|
||||
- 0 = nanoseconds (ns)
|
||||
- 1 = microseconds (us)
|
||||
- 2 = milliseconds (ms)
|
||||
- 3 = seconds (s)
|
||||
- 4 = minutes (min)
|
||||
- 5 = hours (h)
|
||||
|
||||
### Automatic Formatting
|
||||
|
||||
Use `bench_format_auto()` to automatically select the best time unit:
|
||||
|
||||
```c
|
||||
int main() {
|
||||
int timer = bench_start();
|
||||
|
||||
int i = 0;
|
||||
while (i < 10000) {
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int elapsed = bench_end(timer);
|
||||
char* formatted = bench_format_auto(elapsed);
|
||||
|
||||
printf("Time: %s\n", formatted);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Multiple Timers
|
||||
|
||||
You can use multiple timers concurrently:
|
||||
|
||||
```c
|
||||
int main() {
|
||||
int timer1 = bench_start();
|
||||
int timer2 = bench_start();
|
||||
int timer3 = bench_start();
|
||||
|
||||
int result1 = compute_task1();
|
||||
int elapsed1 = bench_end(timer1);
|
||||
|
||||
int result2 = compute_task2();
|
||||
int elapsed2 = bench_end(timer2);
|
||||
|
||||
int result3 = compute_task3();
|
||||
int elapsed3 = bench_end(timer3);
|
||||
|
||||
printf("Task 1: %s\n", bench_format_auto(elapsed1));
|
||||
printf("Task 2: %s\n", bench_format_auto(elapsed2));
|
||||
printf("Task 3: %s\n", bench_format_auto(elapsed3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Nested Timing
|
||||
|
||||
Timers can be nested to measure sub-operations:
|
||||
|
||||
```c
|
||||
int main() {
|
||||
int outer_timer = bench_start();
|
||||
|
||||
printf("Starting outer operation\n");
|
||||
|
||||
int inner_timer = bench_start();
|
||||
int partial_result = compute_part1();
|
||||
int inner_elapsed = bench_end(inner_timer);
|
||||
printf("Part 1: %s\n", bench_format_auto(inner_elapsed));
|
||||
|
||||
int final_result = compute_part2(partial_result);
|
||||
|
||||
int outer_elapsed = bench_end(outer_timer);
|
||||
printf("Total: %s\n", bench_format_auto(outer_elapsed));
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Comparing Algorithms
|
||||
|
||||
Benchmark different approaches:
|
||||
|
||||
```c
|
||||
int approach1(int n) {
|
||||
int sum = 0;
|
||||
int i = 0;
|
||||
while (i < n) {
|
||||
sum = sum + i;
|
||||
i = i + 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int approach2(int n) {
|
||||
return (n * (n - 1)) / 2;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int runs = 100;
|
||||
|
||||
int timer1 = bench_start();
|
||||
int i = 0;
|
||||
while (i < runs) {
|
||||
int result = approach1(1000);
|
||||
i = i + 1;
|
||||
}
|
||||
int time1 = bench_end(timer1);
|
||||
|
||||
int timer2 = bench_start();
|
||||
i = 0;
|
||||
while (i < runs) {
|
||||
int result = approach2(1000);
|
||||
i = i + 1;
|
||||
}
|
||||
int time2 = bench_end(timer2);
|
||||
|
||||
printf("Approach 1: %s\n", bench_format_auto(time1));
|
||||
printf("Approach 2: %s\n", bench_format_auto(time2));
|
||||
|
||||
int ratio = time1 / time2;
|
||||
printf("Approach 2 is %dx faster\n", ratio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Resetting Timers
|
||||
|
||||
Use `bench_reset()` to reset all timers:
|
||||
|
||||
```c
|
||||
int main() {
|
||||
int timer1 = bench_start();
|
||||
int timer2 = bench_start();
|
||||
|
||||
bench_reset();
|
||||
|
||||
int timer3 = bench_start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Profiling
|
||||
|
||||
Create a performance profile of your application:
|
||||
|
||||
```c
|
||||
int main() {
|
||||
printf("=== Performance Profile ===\n");
|
||||
|
||||
int init_timer = bench_start();
|
||||
initialize_data();
|
||||
int init_time = bench_end(init_timer);
|
||||
printf("Initialization: %s\n", bench_format_auto(init_time));
|
||||
|
||||
int process_timer = bench_start();
|
||||
process_data();
|
||||
int process_time = bench_end(process_timer);
|
||||
printf("Processing: %s\n", bench_format_auto(process_time));
|
||||
|
||||
int save_timer = bench_start();
|
||||
save_results();
|
||||
int save_time = bench_end(save_timer);
|
||||
printf("Saving: %s\n", bench_format_auto(save_time));
|
||||
|
||||
int total = init_time + process_time + save_time;
|
||||
printf("Total: %s\n", bench_format_auto(total));
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Run multiple iterations** for more accurate measurements
|
||||
2. **Warm up** before benchmarking to account for caching effects
|
||||
3. **Use nested timers** to identify bottlenecks
|
||||
4. **Compare relative performance** rather than absolute numbers
|
||||
5. **Document benchmark conditions** (input size, hardware, etc.)
|
||||
|
||||
### Limitations
|
||||
|
||||
- Maximum 1000 concurrent timers
|
||||
- Nanosecond precision depends on system clock
|
||||
- Timers use CLOCK_MONOTONIC for accuracy
|
||||
- Thread-safe timer management
|
||||
|
||||
### Complete Example
|
||||
|
||||
```c
|
||||
int fibonacci(int n) {
|
||||
if (n <= 1) {
|
||||
return n;
|
||||
}
|
||||
return fibonacci(n - 1) + fibonacci(n - 2);
|
||||
}
|
||||
|
||||
int compute_sum_of_squares(int limit) {
|
||||
int sum = 0;
|
||||
int i = 1;
|
||||
while (i <= limit) {
|
||||
sum = sum + (i * i);
|
||||
i = i + 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("=== Benchmarking Demo ===\n\n");
|
||||
|
||||
printf("Test 1: Simple Loop\n");
|
||||
int timer1 = bench_start();
|
||||
int i = 0;
|
||||
int sum = 0;
|
||||
while (i < 1000) {
|
||||
sum = sum + i;
|
||||
i = i + 1;
|
||||
}
|
||||
int elapsed1 = bench_end(timer1);
|
||||
printf("Result: %d\n", sum);
|
||||
printf("Time: %s\n\n", bench_format_auto(elapsed1));
|
||||
|
||||
printf("Test 2: Fibonacci\n");
|
||||
int timer2 = bench_start();
|
||||
int fib_result = fibonacci(20);
|
||||
int elapsed2 = bench_end(timer2);
|
||||
printf("Result: %d\n", fib_result);
|
||||
printf("Time: %s\n\n", bench_format_auto(elapsed2));
|
||||
|
||||
printf("Test 3: Sum of Squares\n");
|
||||
int timer3 = bench_start();
|
||||
int sum_result = compute_sum_of_squares(100);
|
||||
int elapsed3 = bench_end(timer3);
|
||||
printf("Result: %d\n", sum_result);
|
||||
printf("Time: %s\n\n", bench_format_auto(elapsed3));
|
||||
|
||||
printf("=== Complete ===\n");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
For more benchmarking examples, see `examples/benchmark_demo.rc`.
|
||||
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
int modulo(int a, int b) {
|
||||
return a - (a / b) * b;
|
||||
}
|
||||
|
||||
int fibonacci_recursive(int n) {
|
||||
if (n <= 1) { return n; }
|
||||
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2);
|
||||
}
|
||||
|
||||
int loop_iteration(int iterations) {
|
||||
int total = 0;
|
||||
int i = 0;
|
||||
while (i < iterations) {
|
||||
total = total + i * 2;
|
||||
i = i + 1;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
int list_operations(int iterations) {
|
||||
int sum = 0;
|
||||
int i = 0;
|
||||
int val = 0;
|
||||
while (i < iterations) {
|
||||
if (modulo(i, 3) == 0) {
|
||||
val = i * 2;
|
||||
sum = sum + val;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int string_concatenation(int iterations) {
|
||||
char *result = "";
|
||||
int i = 0;
|
||||
while (i < iterations) {
|
||||
result = result + "x";
|
||||
i = i + 1;
|
||||
}
|
||||
return strlen(result);
|
||||
}
|
||||
|
||||
class BenchItem {
|
||||
int id = 0;
|
||||
int value = 0;
|
||||
int active = 0;
|
||||
}
|
||||
|
||||
int dict_creation(int iterations) {
|
||||
int sum = 0;
|
||||
int i = 0;
|
||||
int obj = 0;
|
||||
while (i < iterations) {
|
||||
obj = new BenchItem();
|
||||
obj.id = i;
|
||||
obj.value = i * 2;
|
||||
obj.active = modulo(i, 2);
|
||||
sum = sum + obj.value;
|
||||
i = i + 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int sorting_algorithm(int iterations) {
|
||||
int arr[1000];
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int limit = 0;
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
if (iterations > 1000) { iterations = 1000; }
|
||||
while (i < iterations) {
|
||||
arr[i] = rand_range(0, 1000);
|
||||
i = i + 1;
|
||||
}
|
||||
i = 0;
|
||||
while (i < iterations - 1) {
|
||||
j = 0;
|
||||
limit = iterations - i - 1;
|
||||
while (j < limit) {
|
||||
left = arr[j];
|
||||
right = arr[j + 1];
|
||||
if (left > right) {
|
||||
arr[j] = right;
|
||||
arr[j + 1] = left;
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return arr[0];
|
||||
}
|
||||
|
||||
int math_operations(int iterations) {
|
||||
int total = 0;
|
||||
int i = 0;
|
||||
int sq = 0;
|
||||
int s = 0;
|
||||
int c = 0;
|
||||
while (i < iterations) {
|
||||
sq = sqrt(i);
|
||||
s = sin(i);
|
||||
c = cos(i);
|
||||
total = total + sq * s / 1000000 * c / 1000000;
|
||||
i = i + 1;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
int main() {
|
||||
srand(time());
|
||||
int iterations = 1000;
|
||||
int fib_n = 20;
|
||||
int timer = 0;
|
||||
int t = 0;
|
||||
int r = 0;
|
||||
int total_time = 0;
|
||||
|
||||
int durations[7];
|
||||
char *names[7];
|
||||
int min_idx = 0;
|
||||
int max_idx = 0;
|
||||
int min_val = 0;
|
||||
int max_val = 0;
|
||||
int i = 0;
|
||||
int d = 0;
|
||||
|
||||
names[0] = "Fibonacci Recursive";
|
||||
names[1] = "Loop Iteration";
|
||||
names[2] = "List Operations";
|
||||
names[3] = "String Concatenation";
|
||||
names[4] = "Dict Creation";
|
||||
names[5] = "Sorting Algorithm";
|
||||
names[6] = "Math Operations";
|
||||
|
||||
printf("\n======================================================================\n");
|
||||
printf("RC PERFORMANCE BENCHMARK\n");
|
||||
printf("======================================================================\n");
|
||||
printf("Iterations: %d | Fibonacci N: %d\n", iterations, fib_n);
|
||||
printf("======================================================================\n\n");
|
||||
|
||||
printf("Running: Fibonacci Recursive... ");
|
||||
timer = bench_start();
|
||||
r = fibonacci_recursive(fib_n);
|
||||
t = bench_end(timer);
|
||||
durations[0] = t;
|
||||
total_time = total_time + t;
|
||||
printf("%s\n", bench_format(t, 2));
|
||||
printf(" Result: %d\n\n", r);
|
||||
|
||||
printf("Running: Loop Iteration... ");
|
||||
timer = bench_start();
|
||||
r = loop_iteration(iterations);
|
||||
t = bench_end(timer);
|
||||
durations[1] = t;
|
||||
total_time = total_time + t;
|
||||
printf("%s\n", bench_format(t, 2));
|
||||
printf(" Result: %d\n\n", r);
|
||||
|
||||
printf("Running: List Operations... ");
|
||||
timer = bench_start();
|
||||
r = list_operations(iterations);
|
||||
t = bench_end(timer);
|
||||
durations[2] = t;
|
||||
total_time = total_time + t;
|
||||
printf("%s\n", bench_format(t, 2));
|
||||
printf(" Result: %d\n\n", r);
|
||||
|
||||
printf("Running: String Concatenation... ");
|
||||
timer = bench_start();
|
||||
r = string_concatenation(iterations);
|
||||
t = bench_end(timer);
|
||||
durations[3] = t;
|
||||
total_time = total_time + t;
|
||||
printf("%s\n", bench_format(t, 2));
|
||||
printf(" Result: %d\n\n", r);
|
||||
|
||||
printf("Running: Dict Creation... ");
|
||||
timer = bench_start();
|
||||
r = dict_creation(iterations);
|
||||
t = bench_end(timer);
|
||||
durations[4] = t;
|
||||
total_time = total_time + t;
|
||||
printf("%s\n", bench_format(t, 2));
|
||||
printf(" Result: %d\n\n", r);
|
||||
|
||||
printf("Running: Sorting Algorithm... ");
|
||||
timer = bench_start();
|
||||
r = sorting_algorithm(iterations);
|
||||
t = bench_end(timer);
|
||||
durations[5] = t;
|
||||
total_time = total_time + t;
|
||||
printf("%s\n", bench_format(t, 2));
|
||||
printf(" Result: %d\n\n", r);
|
||||
|
||||
printf("Running: Math Operations... ");
|
||||
timer = bench_start();
|
||||
r = math_operations(iterations);
|
||||
t = bench_end(timer);
|
||||
durations[6] = t;
|
||||
total_time = total_time + t;
|
||||
printf("%s\n", bench_format(t, 2));
|
||||
printf(" Result: %d\n\n", r);
|
||||
|
||||
min_idx = 0;
|
||||
max_idx = 0;
|
||||
min_val = durations[0];
|
||||
max_val = durations[0];
|
||||
i = 1;
|
||||
while (i < 7) {
|
||||
d = durations[i];
|
||||
if (d < min_val) {
|
||||
min_val = d;
|
||||
min_idx = i;
|
||||
}
|
||||
if (d > max_val) {
|
||||
max_val = d;
|
||||
max_idx = i;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
printf("======================================================================\n");
|
||||
printf("SUMMARY\n");
|
||||
printf("======================================================================\n");
|
||||
printf("Total Time: %s\n", bench_format(total_time, 2));
|
||||
printf("Fastest Test: %s (%s)\n", names[min_idx], bench_format(durations[min_idx], 2));
|
||||
printf("Slowest Test: %s (%s)\n", names[max_idx], bench_format(durations[max_idx], 2));
|
||||
printf("======================================================================\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
int fibonacci(int n) {
|
||||
if (n <= 1) {
|
||||
return n;
|
||||
}
|
||||
return fibonacci(n - 1) + fibonacci(n - 2);
|
||||
}
|
||||
|
||||
int compute_sum_of_squares(int limit) {
|
||||
int sum = 0;
|
||||
int i = 1;
|
||||
while (i <= limit) {
|
||||
sum = sum + (i * i);
|
||||
i = i + 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("=================================================\n");
|
||||
printf(" RC Language - Benchmarking Demo\n");
|
||||
printf("=================================================\n\n");
|
||||
|
||||
printf("This demo shows how to use the benchmarking stdlib\n");
|
||||
printf("to measure execution time of different operations.\n\n");
|
||||
|
||||
printf("=================================================\n");
|
||||
printf("Test 1: Simple Loop (1000 iterations)\n");
|
||||
printf("=================================================\n");
|
||||
|
||||
int timer1 = bench_start();
|
||||
|
||||
int i = 0;
|
||||
int sum = 0;
|
||||
while (i < 1000) {
|
||||
sum = sum + i;
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int elapsed1 = bench_end(timer1);
|
||||
char* formatted1 = bench_format_auto(elapsed1);
|
||||
|
||||
printf("Result: sum = %d\n", sum);
|
||||
printf("Time: %s (%d nanoseconds)\n\n", formatted1, elapsed1);
|
||||
|
||||
printf("=================================================\n");
|
||||
printf("Test 2: Fibonacci Calculation (fib(20))\n");
|
||||
printf("=================================================\n");
|
||||
|
||||
int timer2 = bench_start();
|
||||
int fib_result = fibonacci(20);
|
||||
int elapsed2 = bench_end(timer2);
|
||||
|
||||
char* formatted2 = bench_format_auto(elapsed2);
|
||||
|
||||
printf("Result: fibonacci(20) = %d\n", fib_result);
|
||||
printf("Time: %s (%d nanoseconds)\n\n", formatted2, elapsed2);
|
||||
|
||||
printf("=================================================\n");
|
||||
printf("Test 3: Sum of Squares (1 to 100)\n");
|
||||
printf("=================================================\n");
|
||||
|
||||
int timer3 = bench_start();
|
||||
int sum_result = compute_sum_of_squares(100);
|
||||
int elapsed3 = bench_end(timer3);
|
||||
|
||||
char* formatted3 = bench_format_auto(elapsed3);
|
||||
|
||||
printf("Result: Sum of squares = %d\n", sum_result);
|
||||
printf("Time: %s (%d nanoseconds)\n\n", formatted3, elapsed3);
|
||||
|
||||
printf("=================================================\n");
|
||||
printf("Test 4: Nested Timers\n");
|
||||
printf("=================================================\n");
|
||||
|
||||
int outer_timer = bench_start();
|
||||
|
||||
printf("Outer operation started...\n");
|
||||
|
||||
int inner_timer = bench_start();
|
||||
int k = 0;
|
||||
int product = 1;
|
||||
while (k < 50) {
|
||||
product = product + k;
|
||||
k = k + 1;
|
||||
}
|
||||
int inner_elapsed = bench_end(inner_timer);
|
||||
|
||||
printf("Inner operation completed in: %s\n", bench_format_auto(inner_elapsed));
|
||||
|
||||
int m = 0;
|
||||
while (m < 100) {
|
||||
m = m + 1;
|
||||
}
|
||||
|
||||
int outer_elapsed = bench_end(outer_timer);
|
||||
|
||||
printf("Outer operation completed in: %s\n\n", bench_format_auto(outer_elapsed));
|
||||
|
||||
printf("=================================================\n");
|
||||
printf("Test 5: Manual Format with Different Units\n");
|
||||
printf("=================================================\n");
|
||||
|
||||
int sample_time = 1234567890;
|
||||
|
||||
printf("Time: %d nanoseconds\n", sample_time);
|
||||
printf(" As nanoseconds: %s\n", bench_format(sample_time, 0));
|
||||
printf(" As microseconds: %s\n", bench_format(sample_time, 1));
|
||||
printf(" As milliseconds: %s\n", bench_format(sample_time, 2));
|
||||
printf(" As seconds: %s\n", bench_format(sample_time, 3));
|
||||
printf(" As minutes: %s\n", bench_format(sample_time, 4));
|
||||
printf(" As hours: %s\n", bench_format(sample_time, 5));
|
||||
printf(" Auto format: %s\n\n", bench_format_auto(sample_time));
|
||||
|
||||
printf("=================================================\n");
|
||||
printf("Test 6: Comparison of Algorithms\n");
|
||||
printf("=================================================\n");
|
||||
|
||||
printf("Computing fibonacci(15) multiple times...\n");
|
||||
|
||||
int timer_a = bench_start();
|
||||
int result_a = fibonacci(15);
|
||||
int elapsed_a = bench_end(timer_a);
|
||||
|
||||
int timer_b = bench_start();
|
||||
int result_b = fibonacci(15);
|
||||
int elapsed_b = bench_end(timer_b);
|
||||
|
||||
int timer_c = bench_start();
|
||||
int result_c = fibonacci(15);
|
||||
int elapsed_c = bench_end(timer_c);
|
||||
|
||||
printf("Run 1: %s (result: %d)\n", bench_format_auto(elapsed_a), result_a);
|
||||
printf("Run 2: %s (result: %d)\n", bench_format_auto(elapsed_b), result_b);
|
||||
printf("Run 3: %s (result: %d)\n", bench_format_auto(elapsed_c), result_c);
|
||||
|
||||
int avg_time = (elapsed_a + elapsed_b + elapsed_c) / 3;
|
||||
printf("Average time: %s\n\n", bench_format_auto(avg_time));
|
||||
|
||||
printf("=================================================\n");
|
||||
printf("Benchmarking Complete!\n");
|
||||
printf("=================================================\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "scope.h"
|
||||
|
||||
extern long memory[MEM_SIZE];
|
||||
extern int sp;
|
||||
|
||||
+19
-31
@@ -7,7 +7,6 @@
|
||||
#include "parser.h"
|
||||
#include "error.h"
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
|
||||
void error(char *msg) {
|
||||
error_with_context("ParseError", msg, NULL);
|
||||
@@ -112,38 +111,29 @@ void statement() {
|
||||
Token *t = &tokens[pc];
|
||||
match(Id);
|
||||
|
||||
char var_name[64];
|
||||
int name_len = t->val;
|
||||
if (name_len < 0) name_len = 0;
|
||||
if (name_len > 31) name_len = 31;
|
||||
strncpy(var_name, t->text, name_len);
|
||||
var_name[name_len] = 0;
|
||||
|
||||
char alloc_ctx[128];
|
||||
snprintf(alloc_ctx, sizeof(alloc_ctx), "declare variable '%s'", var_name);
|
||||
|
||||
if (!mem_check_loc_cnt(loc_cnt + 1, alloc_ctx)) {
|
||||
if (loc_cnt >= VAR_MAX) {
|
||||
DEBUG_LOG("ERROR: Too many local variables: loc_cnt=%d (max=%d)", loc_cnt, VAR_MAX);
|
||||
error("Too many local variables");
|
||||
}
|
||||
if (!mem_check_sp(sp + 1, alloc_ctx)) {
|
||||
if (sp >= MEM_SIZE) {
|
||||
DEBUG_LOG("ERROR: Stack overflow: sp=%d (max=%d)", sp, MEM_SIZE);
|
||||
DEBUG_STACK_STATE();
|
||||
error("Stack overflow");
|
||||
}
|
||||
|
||||
int addr = sp;
|
||||
Symbol *s = &locals[loc_cnt++];
|
||||
if (!t->text) {
|
||||
error("Invalid token text");
|
||||
}
|
||||
strncpy(s->name, var_name, 32);
|
||||
s->name[31] = 0;
|
||||
int name_len = t->val;
|
||||
if (name_len < 0) name_len = 0;
|
||||
if (name_len > 31) name_len = 31;
|
||||
strncpy(s->name, t->text, name_len);
|
||||
s->name[name_len] = 0;
|
||||
s->type = var_type;
|
||||
s->addr = addr;
|
||||
s->is_array = 0;
|
||||
|
||||
if (loc_cnt > mem_stats.loc_cnt_high_water) {
|
||||
mem_stats.loc_cnt_high_water = loc_cnt;
|
||||
}
|
||||
|
||||
if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == '[') {
|
||||
pc++;
|
||||
long size_val = expression();
|
||||
@@ -158,29 +148,27 @@ void statement() {
|
||||
|
||||
int size = (int)size_val;
|
||||
s->is_array = 1;
|
||||
|
||||
snprintf(alloc_ctx, sizeof(alloc_ctx), "allocate array '%s[%d]'", var_name, size);
|
||||
if (!mem_check_sp(sp + size, alloc_ctx)) {
|
||||
if (sp + size >= MEM_SIZE) {
|
||||
error("Stack overflow during array allocation");
|
||||
}
|
||||
if (sp + size < sp) {
|
||||
error("Integer overflow in array allocation");
|
||||
}
|
||||
sp += size;
|
||||
mem_stats.total_allocations += size;
|
||||
} else {
|
||||
if (sp + 1 >= MEM_SIZE) {
|
||||
error("Stack overflow during variable allocation");
|
||||
}
|
||||
sp++;
|
||||
mem_stats.total_allocations++;
|
||||
}
|
||||
|
||||
if (sp > mem_stats.sp_high_water) {
|
||||
mem_stats.sp_high_water = sp;
|
||||
}
|
||||
|
||||
if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == '=') {
|
||||
pc++;
|
||||
snprintf(alloc_ctx, sizeof(alloc_ctx), "initialize '%s'", var_name);
|
||||
mem_write(addr, expression(), alloc_ctx);
|
||||
if (addr >= 0 && addr < MEM_SIZE) {
|
||||
memory[addr] = expression();
|
||||
} else {
|
||||
error("Memory access out of bounds");
|
||||
}
|
||||
}
|
||||
if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == ',') pc++;
|
||||
}
|
||||
|
||||
@@ -10,14 +10,10 @@
|
||||
#include "preprocessor.h"
|
||||
#include "oop.h"
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
#include "scope.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
DEBUG_INIT();
|
||||
DEBUG_LOG("RC Interpreter starting");
|
||||
mem_init();
|
||||
scope_init();
|
||||
|
||||
pthread_rwlock_init(&tokens_rwlock, NULL);
|
||||
pthread_mutex_init(&str_pool_mutex, NULL);
|
||||
@@ -78,7 +74,6 @@ int main(int argc, char **argv) {
|
||||
statement();
|
||||
|
||||
free(src_code);
|
||||
scope_cleanup();
|
||||
pthread_rwlock_destroy(&tokens_rwlock);
|
||||
pthread_mutex_destroy(&str_pool_mutex);
|
||||
pthread_mutex_destroy(&memory_mutex);
|
||||
|
||||
-267
@@ -1,267 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "memory.h"
|
||||
#include "types.h"
|
||||
#include "error.h"
|
||||
|
||||
MemoryStats mem_stats = {0, 0, 0, 0, 0, 0};
|
||||
|
||||
extern long memory[];
|
||||
extern int sp;
|
||||
extern int bp;
|
||||
extern Symbol locals[];
|
||||
extern int loc_cnt;
|
||||
extern int pc;
|
||||
extern long ax;
|
||||
|
||||
static void mem_error(const char *msg, const char *context) {
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
|
||||
fprintf(stderr, "║ MEMORY ERROR DETECTED ║\n");
|
||||
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
|
||||
fprintf(stderr, "\n Error: %s\n", msg);
|
||||
fprintf(stderr, " Context: %s\n", context);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
|
||||
fprintf(stderr, "║ MEMORY STATE ║\n");
|
||||
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
|
||||
fprintf(stderr, " Stack Pointer (sp): %d\n", sp);
|
||||
fprintf(stderr, " Base Pointer (bp): %d\n", bp);
|
||||
fprintf(stderr, " Program Counter (pc): %d\n", pc);
|
||||
fprintf(stderr, " Local Count (loc_cnt): %d\n", loc_cnt);
|
||||
fprintf(stderr, " Accumulator (ax): %ld\n", ax);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
|
||||
fprintf(stderr, "║ MEMORY LIMITS ║\n");
|
||||
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
|
||||
fprintf(stderr, " MEM_SIZE: %d\n", MEM_SIZE);
|
||||
fprintf(stderr, " VAR_MAX: %d\n", VAR_MAX);
|
||||
fprintf(stderr, " MAX_TOK: %d\n", MAX_TOK);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
|
||||
fprintf(stderr, "║ MEMORY STATISTICS ║\n");
|
||||
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
|
||||
fprintf(stderr, " SP High Water Mark: %d\n", mem_stats.sp_high_water);
|
||||
fprintf(stderr, " LOC_CNT High Water: %d\n", mem_stats.loc_cnt_high_water);
|
||||
fprintf(stderr, " Current Call Depth: %d\n", mem_stats.call_depth);
|
||||
fprintf(stderr, " Max Call Depth: %d\n", mem_stats.max_call_depth);
|
||||
fprintf(stderr, " Total Allocations: %d\n", mem_stats.total_allocations);
|
||||
fprintf(stderr, " Total Deallocations: %d\n", mem_stats.total_deallocations);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (loc_cnt > 0 && loc_cnt <= VAR_MAX) {
|
||||
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
|
||||
fprintf(stderr, "║ LOCAL VARIABLES ║\n");
|
||||
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
|
||||
int show_count = loc_cnt < 20 ? loc_cnt : 20;
|
||||
for (int i = 0; i < show_count; i++) {
|
||||
fprintf(stderr, " [%3d] %-20s addr=%5d is_array=%d",
|
||||
i, locals[i].name, locals[i].addr, locals[i].is_array);
|
||||
if (locals[i].addr >= 0 && locals[i].addr < MEM_SIZE) {
|
||||
fprintf(stderr, " value=%ld", memory[locals[i].addr]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
if (loc_cnt > 20) {
|
||||
fprintf(stderr, " ... and %d more variables\n", loc_cnt - 20);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
if (sp > 0 && sp <= MEM_SIZE) {
|
||||
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
|
||||
fprintf(stderr, "║ STACK CONTENTS ║\n");
|
||||
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
|
||||
int start = sp > 20 ? sp - 20 : 0;
|
||||
for (int i = start; i < sp && i < MEM_SIZE; i++) {
|
||||
fprintf(stderr, " memory[%5d] = %ld", i, memory[i]);
|
||||
if (i == bp) fprintf(stderr, " <-- bp");
|
||||
if (i == sp - 1) fprintf(stderr, " <-- sp-1 (top)");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void mem_init(void) {
|
||||
mem_stats.sp_high_water = 0;
|
||||
mem_stats.loc_cnt_high_water = 0;
|
||||
mem_stats.call_depth = 0;
|
||||
mem_stats.max_call_depth = 0;
|
||||
mem_stats.total_allocations = 0;
|
||||
mem_stats.total_deallocations = 0;
|
||||
}
|
||||
|
||||
void mem_dump_stats(void) {
|
||||
fprintf(stderr, "\n=== Memory Statistics ===\n");
|
||||
fprintf(stderr, "SP High Water: %d / %d (%.1f%%)\n",
|
||||
mem_stats.sp_high_water, MEM_SIZE,
|
||||
100.0 * mem_stats.sp_high_water / MEM_SIZE);
|
||||
fprintf(stderr, "LOC_CNT High: %d / %d (%.1f%%)\n",
|
||||
mem_stats.loc_cnt_high_water, VAR_MAX,
|
||||
100.0 * mem_stats.loc_cnt_high_water / VAR_MAX);
|
||||
fprintf(stderr, "Max Call Depth: %d\n", mem_stats.max_call_depth);
|
||||
fprintf(stderr, "Allocations: %d\n", mem_stats.total_allocations);
|
||||
fprintf(stderr, "Deallocations: %d\n", mem_stats.total_deallocations);
|
||||
fprintf(stderr, "=========================\n");
|
||||
}
|
||||
|
||||
int mem_check_sp(int required_sp, const char *context) {
|
||||
if (required_sp < 0) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Stack underflow: required sp=%d", required_sp);
|
||||
mem_error(msg, context);
|
||||
return 0;
|
||||
}
|
||||
if (required_sp >= MEM_SIZE) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Stack overflow: required sp=%d >= MEM_SIZE=%d",
|
||||
required_sp, MEM_SIZE);
|
||||
mem_error(msg, context);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mem_check_addr(int addr, const char *context) {
|
||||
if (addr < 0) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Negative memory address: addr=%d", addr);
|
||||
mem_error(msg, context);
|
||||
return 0;
|
||||
}
|
||||
if (addr >= MEM_SIZE) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Memory address out of bounds: addr=%d >= MEM_SIZE=%d",
|
||||
addr, MEM_SIZE);
|
||||
mem_error(msg, context);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int mem_check_loc_cnt(int required_cnt, const char *context) {
|
||||
if (required_cnt < 0) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Negative local count: loc_cnt=%d", required_cnt);
|
||||
mem_error(msg, context);
|
||||
return 0;
|
||||
}
|
||||
if (required_cnt >= VAR_MAX) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Too many local variables: loc_cnt=%d >= VAR_MAX=%d",
|
||||
required_cnt, VAR_MAX);
|
||||
mem_error(msg, context);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
long mem_read(int addr, const char *context) {
|
||||
if (!mem_check_addr(addr, context)) {
|
||||
return 0;
|
||||
}
|
||||
return memory[addr];
|
||||
}
|
||||
|
||||
void mem_write(int addr, long value, const char *context) {
|
||||
if (!mem_check_addr(addr, context)) {
|
||||
return;
|
||||
}
|
||||
memory[addr] = value;
|
||||
}
|
||||
|
||||
int mem_push(long value, const char *context) {
|
||||
if (!mem_check_sp(sp + 1, context)) {
|
||||
return 0;
|
||||
}
|
||||
memory[sp++] = value;
|
||||
mem_stats.total_allocations++;
|
||||
if (sp > mem_stats.sp_high_water) {
|
||||
mem_stats.sp_high_water = sp;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
long mem_pop(const char *context) {
|
||||
if (sp <= 0) {
|
||||
mem_error("Stack underflow on pop", context);
|
||||
return 0;
|
||||
}
|
||||
mem_stats.total_deallocations++;
|
||||
return memory[--sp];
|
||||
}
|
||||
|
||||
void mem_alloc_var(int size, const char *var_name) {
|
||||
char context[256];
|
||||
snprintf(context, sizeof(context), "Allocating variable '%s' (size=%d)", var_name, size);
|
||||
|
||||
if (!mem_check_sp(sp + size, context)) {
|
||||
return;
|
||||
}
|
||||
if (!mem_check_loc_cnt(loc_cnt + 1, context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sp += size;
|
||||
mem_stats.total_allocations += size;
|
||||
|
||||
if (sp > mem_stats.sp_high_water) {
|
||||
mem_stats.sp_high_water = sp;
|
||||
}
|
||||
if (loc_cnt > mem_stats.loc_cnt_high_water) {
|
||||
mem_stats.loc_cnt_high_water = loc_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
void mem_free_frame(int old_sp, int old_loc_cnt, const char *context) {
|
||||
if (old_sp < 0 || old_sp > sp) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Invalid frame restoration: old_sp=%d, current sp=%d",
|
||||
old_sp, sp);
|
||||
mem_error(msg, context);
|
||||
return;
|
||||
}
|
||||
if (old_loc_cnt < 0 || old_loc_cnt > loc_cnt) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Invalid loc_cnt restoration: old_loc_cnt=%d, current loc_cnt=%d",
|
||||
old_loc_cnt, loc_cnt);
|
||||
mem_error(msg, context);
|
||||
return;
|
||||
}
|
||||
|
||||
mem_stats.total_deallocations += (sp - old_sp);
|
||||
sp = old_sp;
|
||||
loc_cnt = old_loc_cnt;
|
||||
}
|
||||
|
||||
void mem_enter_call(const char *func_name) {
|
||||
mem_stats.call_depth++;
|
||||
if (mem_stats.call_depth > mem_stats.max_call_depth) {
|
||||
mem_stats.max_call_depth = mem_stats.call_depth;
|
||||
}
|
||||
|
||||
if (mem_stats.call_depth > MAX_CALL_STACK) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Call stack overflow entering '%s'", func_name);
|
||||
mem_error(msg, "mem_enter_call");
|
||||
}
|
||||
}
|
||||
|
||||
void mem_exit_call(const char *func_name) {
|
||||
if (mem_stats.call_depth <= 0) {
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Call stack underflow exiting '%s'", func_name);
|
||||
mem_error(msg, "mem_exit_call");
|
||||
return;
|
||||
}
|
||||
mem_stats.call_depth--;
|
||||
}
|
||||
|
||||
void mem_trace_state(const char *label) {
|
||||
fprintf(stderr, "[TRACE:%s] sp=%d bp=%d loc_cnt=%d call_depth=%d\n",
|
||||
label, sp, bp, loc_cnt, mem_stats.call_depth);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct {
|
||||
int sp_high_water;
|
||||
int loc_cnt_high_water;
|
||||
int call_depth;
|
||||
int max_call_depth;
|
||||
int total_allocations;
|
||||
int total_deallocations;
|
||||
} MemoryStats;
|
||||
|
||||
extern MemoryStats mem_stats;
|
||||
|
||||
void mem_init(void);
|
||||
void mem_dump_stats(void);
|
||||
|
||||
int mem_check_sp(int required_sp, const char *context);
|
||||
int mem_check_addr(int addr, const char *context);
|
||||
int mem_check_loc_cnt(int required_cnt, const char *context);
|
||||
|
||||
long mem_read(int addr, const char *context);
|
||||
void mem_write(int addr, long value, const char *context);
|
||||
|
||||
int mem_push(long value, const char *context);
|
||||
long mem_pop(const char *context);
|
||||
|
||||
void mem_alloc_var(int size, const char *var_name);
|
||||
void mem_free_frame(int old_sp, int old_loc_cnt, const char *context);
|
||||
|
||||
void mem_enter_call(const char *func_name);
|
||||
void mem_exit_call(const char *func_name);
|
||||
|
||||
void mem_trace_state(const char *label);
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "interpreter.h"
|
||||
#include "scope.h"
|
||||
|
||||
int find_class(char *name, int len) {
|
||||
if (!name || len <= 0 || len > 31) return -1;
|
||||
@@ -114,15 +113,23 @@ void call_destructor(long obj_ptr) {
|
||||
int func_idx = cls->methods[i].func_idx;
|
||||
if (func_idx >= 0 && func_idx < func_cnt) {
|
||||
int saved_pc = pc;
|
||||
int saved_sp = sp;
|
||||
int saved_bp = bp;
|
||||
int saved_loc_cnt = loc_cnt;
|
||||
long saved_ax = ax;
|
||||
int saved_return_flag = return_flag;
|
||||
|
||||
scope_push();
|
||||
if (sp >= MEM_SIZE || bp < 0 || bp >= MEM_SIZE) return;
|
||||
|
||||
int param_base = sp;
|
||||
if (sp < MEM_SIZE) {
|
||||
memory[sp++] = obj_ptr;
|
||||
}
|
||||
memory[sp] = bp;
|
||||
bp = sp++;
|
||||
if (sp >= MEM_SIZE) return;
|
||||
|
||||
memory[sp++] = 0;
|
||||
memory[sp++] = saved_loc_cnt;
|
||||
|
||||
if (sp >= MEM_SIZE) return;
|
||||
memory[sp++] = obj_ptr;
|
||||
|
||||
int scan_pc = funcs[func_idx].params_start;
|
||||
if (scan_pc < MAX_TOK && scan_pc < tk_idx && tokens[scan_pc].type != ')') {
|
||||
@@ -135,7 +142,7 @@ void call_destructor(long obj_ptr) {
|
||||
strncpy(sym->name, param_name->text, name_len);
|
||||
sym->name[name_len] = 0;
|
||||
sym->type = Int;
|
||||
sym->addr = param_base;
|
||||
sym->addr = sp - 1;
|
||||
sym->is_array = 0;
|
||||
}
|
||||
}
|
||||
@@ -147,9 +154,10 @@ void call_destructor(long obj_ptr) {
|
||||
|
||||
statement();
|
||||
|
||||
scope_pop();
|
||||
|
||||
pc = saved_pc;
|
||||
sp = saved_sp;
|
||||
bp = saved_bp;
|
||||
loc_cnt = saved_loc_cnt;
|
||||
ax = saved_ax;
|
||||
return_flag = saved_return_flag;
|
||||
}
|
||||
|
||||
+44
-38
@@ -7,8 +7,6 @@
|
||||
#include "string_utils.h"
|
||||
#include "error.h"
|
||||
#include "debug.h"
|
||||
#include "memory.h"
|
||||
#include "scope.h"
|
||||
|
||||
extern Token tokens[];
|
||||
extern int pc;
|
||||
@@ -178,20 +176,20 @@ long factor() {
|
||||
}
|
||||
|
||||
int ret_pc = pc;
|
||||
int saved_return_flag = return_flag;
|
||||
int old_loc_cnt = loc_cnt;
|
||||
int old_bp = bp;
|
||||
|
||||
mem_enter_call(funcs[f_idx].name);
|
||||
|
||||
scope_push();
|
||||
|
||||
char call_ctx[128];
|
||||
snprintf(call_ctx, sizeof(call_ctx), "call %s: push frame", funcs[f_idx].name);
|
||||
if (sp >= MEM_SIZE) return 0;
|
||||
if (bp < 0 || bp >= MEM_SIZE) return 0;
|
||||
memory[sp] = bp; bp = sp++;
|
||||
if (sp >= MEM_SIZE) return 0;
|
||||
memory[sp++] = ret_pc;
|
||||
memory[sp++] = old_loc_cnt;
|
||||
|
||||
int param_base = sp;
|
||||
for(int i=0; i<argc; i++) {
|
||||
if (sp < MEM_SIZE) {
|
||||
memory[sp++] = args[i];
|
||||
}
|
||||
if (sp >= MEM_SIZE) break;
|
||||
memory[sp++] = args[i];
|
||||
}
|
||||
|
||||
int scan_pc = funcs[f_idx].params_start;
|
||||
@@ -200,19 +198,17 @@ long factor() {
|
||||
if (tokens[scan_pc].type == Int || tokens[scan_pc].type == Char || tokens[scan_pc].type == Double) {
|
||||
scan_pc++;
|
||||
while (scan_pc < MAX_TOK && tokens[scan_pc].type == '*') scan_pc++;
|
||||
if (scan_pc < MAX_TOK && tokens[scan_pc].type == Id && param_idx < argc) {
|
||||
if (loc_cnt < VAR_MAX) {
|
||||
Token *param_name = &tokens[scan_pc];
|
||||
Symbol *sym = &locals[loc_cnt++];
|
||||
int name_len = param_name->val;
|
||||
if (name_len > 31) name_len = 31;
|
||||
strncpy(sym->name, param_name->text, name_len);
|
||||
sym->name[name_len] = 0;
|
||||
sym->type = Int;
|
||||
sym->addr = param_base + param_idx;
|
||||
sym->is_array = 0;
|
||||
param_idx++;
|
||||
}
|
||||
if (scan_pc < MAX_TOK && tokens[scan_pc].type == Id && param_idx < argc && loc_cnt < VAR_MAX) {
|
||||
Token *param_name = &tokens[scan_pc];
|
||||
Symbol *sym = &locals[loc_cnt++];
|
||||
int name_len = param_name->val;
|
||||
if (name_len > 31) name_len = 31;
|
||||
strncpy(sym->name, param_name->text, name_len);
|
||||
sym->name[name_len] = 0;
|
||||
sym->type = Int;
|
||||
sym->addr = param_base + param_idx;
|
||||
sym->is_array = 0;
|
||||
param_idx++;
|
||||
}
|
||||
}
|
||||
scan_pc++;
|
||||
@@ -235,12 +231,14 @@ long factor() {
|
||||
return_flag = 0;
|
||||
|
||||
pop_call_frame();
|
||||
mem_exit_call(funcs[f_idx].name);
|
||||
|
||||
scope_pop();
|
||||
|
||||
loc_cnt = old_loc_cnt;
|
||||
if (bp < 0 || bp >= MEM_SIZE) return 0;
|
||||
sp = bp;
|
||||
if (sp < 0 || sp >= MEM_SIZE) return 0;
|
||||
bp = memory[sp];
|
||||
if (sp + 1 < MEM_SIZE) ret_pc = memory[sp + 1];
|
||||
pc = ret_pc;
|
||||
return_flag = saved_return_flag;
|
||||
return val;
|
||||
}
|
||||
else {
|
||||
@@ -429,15 +427,22 @@ long unary() {
|
||||
match(')');
|
||||
|
||||
int saved_pc = pc;
|
||||
int saved_return_flag = return_flag;
|
||||
int saved_sp = sp;
|
||||
int saved_bp = bp;
|
||||
int saved_loc_cnt = loc_cnt;
|
||||
|
||||
scope_push();
|
||||
if (sp >= MEM_SIZE || bp < 0 || bp >= MEM_SIZE) return 0;
|
||||
|
||||
memory[sp] = bp;
|
||||
bp = sp++;
|
||||
if (sp >= MEM_SIZE) return 0;
|
||||
|
||||
memory[sp++] = 0;
|
||||
memory[sp++] = saved_loc_cnt;
|
||||
|
||||
int param_base = sp;
|
||||
for (int i = 0; i < argc && i < 10; i++) {
|
||||
if (sp < MEM_SIZE) {
|
||||
memory[sp++] = args[i];
|
||||
}
|
||||
if (sp >= MEM_SIZE) break;
|
||||
memory[sp++] = args[i];
|
||||
}
|
||||
|
||||
int scan_pc = funcs[func_idx].params_start;
|
||||
@@ -455,7 +460,7 @@ long unary() {
|
||||
strncpy(sym->name, param_name->text, name_len);
|
||||
sym->name[name_len] = 0;
|
||||
sym->type = Int;
|
||||
sym->addr = param_base + param_idx;
|
||||
sym->addr = saved_sp + 3 + param_idx;
|
||||
sym->is_array = 0;
|
||||
param_idx++;
|
||||
}
|
||||
@@ -471,9 +476,10 @@ long unary() {
|
||||
ax = 0;
|
||||
return_flag = 0;
|
||||
|
||||
scope_pop();
|
||||
pc = saved_pc;
|
||||
return_flag = saved_return_flag;
|
||||
sp = saved_sp;
|
||||
bp = saved_bp;
|
||||
loc_cnt = saved_loc_cnt;
|
||||
} else {
|
||||
extern int find_class_field(int class_idx, char *name, int len);
|
||||
int field_idx = find_class_field(class_idx, member->text, member->val);
|
||||
|
||||
-363
@@ -1,363 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "scope.h"
|
||||
#include "types.h"
|
||||
#include "interpreter.h"
|
||||
|
||||
Scope *current_scope = NULL;
|
||||
Scope *root_scope = NULL;
|
||||
|
||||
Scope* scope_create(Scope *parent) {
|
||||
Scope *scope = (Scope*)calloc(1, sizeof(Scope));
|
||||
if (!scope) return NULL;
|
||||
|
||||
scope->parent = parent;
|
||||
scope->mem_size = SCOPE_MEM_SIZE;
|
||||
scope->loc_capacity = SCOPE_VAR_MAX;
|
||||
|
||||
scope->memory = (long*)calloc(SCOPE_MEM_SIZE, sizeof(long));
|
||||
if (!scope->memory) {
|
||||
free(scope);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scope->locals = (Symbol*)calloc(SCOPE_VAR_MAX, sizeof(Symbol));
|
||||
if (!scope->locals) {
|
||||
free(scope->memory);
|
||||
free(scope);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scope->sp = 0;
|
||||
scope->bp = 0;
|
||||
scope->loc_cnt = 0;
|
||||
scope->depth = parent ? parent->depth + 1 : 0;
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
void scope_destroy(Scope *scope) {
|
||||
if (!scope) return;
|
||||
if (scope->memory) free(scope->memory);
|
||||
if (scope->locals) free(scope->locals);
|
||||
free(scope);
|
||||
}
|
||||
|
||||
Scope* scope_push(void) {
|
||||
extern long memory[];
|
||||
extern Symbol locals[];
|
||||
extern int sp, bp, loc_cnt;
|
||||
|
||||
if (current_scope) {
|
||||
int copy_sp = sp < current_scope->mem_size ? sp : current_scope->mem_size;
|
||||
for (int i = 0; i < copy_sp; i++) {
|
||||
current_scope->memory[i] = memory[i];
|
||||
}
|
||||
int copy_loc = loc_cnt < current_scope->loc_capacity ? loc_cnt : current_scope->loc_capacity;
|
||||
for (int i = 0; i < copy_loc; i++) {
|
||||
current_scope->locals[i] = locals[i];
|
||||
}
|
||||
current_scope->sp = sp;
|
||||
current_scope->bp = bp;
|
||||
current_scope->loc_cnt = loc_cnt;
|
||||
}
|
||||
|
||||
Scope *new_scope = scope_create(current_scope);
|
||||
if (!new_scope) {
|
||||
error("Failed to create new scope");
|
||||
return NULL;
|
||||
}
|
||||
current_scope = new_scope;
|
||||
|
||||
sp = 0;
|
||||
bp = 0;
|
||||
loc_cnt = 0;
|
||||
|
||||
return new_scope;
|
||||
}
|
||||
|
||||
Scope* scope_pop(void) {
|
||||
extern long memory[];
|
||||
extern Symbol locals[];
|
||||
extern int sp, bp, loc_cnt;
|
||||
|
||||
if (!current_scope || !current_scope->parent) {
|
||||
return current_scope;
|
||||
}
|
||||
|
||||
Scope *old = current_scope;
|
||||
current_scope = current_scope->parent;
|
||||
scope_destroy(old);
|
||||
|
||||
if (current_scope) {
|
||||
int copy_sp = current_scope->sp < MEM_SIZE ? current_scope->sp : MEM_SIZE;
|
||||
for (int i = 0; i < copy_sp; i++) {
|
||||
memory[i] = current_scope->memory[i];
|
||||
}
|
||||
int copy_loc = current_scope->loc_cnt < VAR_MAX ? current_scope->loc_cnt : VAR_MAX;
|
||||
for (int i = 0; i < copy_loc; i++) {
|
||||
locals[i] = current_scope->locals[i];
|
||||
}
|
||||
sp = current_scope->sp;
|
||||
bp = current_scope->bp;
|
||||
loc_cnt = current_scope->loc_cnt;
|
||||
}
|
||||
|
||||
return current_scope;
|
||||
}
|
||||
|
||||
int scope_find_local_current_only(const char *name, int len) {
|
||||
if (!current_scope || !name || len <= 0 || len >= 32) return -1;
|
||||
|
||||
Scope *scope = current_scope;
|
||||
for (int i = scope->loc_cnt - 1; i >= 0; i--) {
|
||||
if (!strncmp(scope->locals[i].name, name, len) && scope->locals[i].name[len] == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int scope_find_local_in_scope(Scope *scope, const char *name, int len) {
|
||||
if (!scope || !name || len <= 0 || len >= 32) return -1;
|
||||
|
||||
for (int i = scope->loc_cnt - 1; i >= 0; i--) {
|
||||
if (!strncmp(scope->locals[i].name, name, len) && scope->locals[i].name[len] == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int scope_find_local(const char *name, int len) {
|
||||
if (!name || len <= 0 || len >= 32) return -1;
|
||||
|
||||
Scope *scope = current_scope;
|
||||
while (scope) {
|
||||
int idx = scope_find_local_in_scope(scope, name, len);
|
||||
if (idx >= 0) {
|
||||
return idx;
|
||||
}
|
||||
scope = scope->parent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Symbol* scope_get_local(int idx) {
|
||||
if (!current_scope || idx < 0) return NULL;
|
||||
|
||||
Scope *scope = current_scope;
|
||||
while (scope) {
|
||||
if (idx < scope->loc_cnt) {
|
||||
return &scope->locals[idx];
|
||||
}
|
||||
scope = scope->parent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Symbol* scope_add_local(const char *name, int len, int type, int addr, int is_array) {
|
||||
if (!current_scope) return NULL;
|
||||
if (current_scope->loc_cnt >= current_scope->loc_capacity) {
|
||||
error("Too many local variables in scope");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Symbol *sym = ¤t_scope->locals[current_scope->loc_cnt++];
|
||||
int name_len = len > 31 ? 31 : len;
|
||||
strncpy(sym->name, name, name_len);
|
||||
sym->name[name_len] = 0;
|
||||
sym->type = type;
|
||||
sym->addr = addr;
|
||||
sym->is_array = is_array;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
long scope_mem_read(int addr) {
|
||||
if (!current_scope) return 0;
|
||||
if (addr < 0) return 0;
|
||||
|
||||
Scope *scope = current_scope;
|
||||
while (scope) {
|
||||
if (addr < scope->mem_size && addr < scope->sp) {
|
||||
return scope->memory[addr];
|
||||
}
|
||||
if (addr < scope->mem_size) {
|
||||
return scope->memory[addr];
|
||||
}
|
||||
scope = scope->parent;
|
||||
}
|
||||
|
||||
if (addr < current_scope->mem_size) {
|
||||
return current_scope->memory[addr];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scope_mem_write(int addr, long value) {
|
||||
if (!current_scope) return;
|
||||
if (addr < 0 || addr >= current_scope->mem_size) return;
|
||||
current_scope->memory[addr] = value;
|
||||
}
|
||||
|
||||
int scope_mem_alloc(int size) {
|
||||
if (!current_scope || size <= 0) return -1;
|
||||
if (current_scope->sp + size > current_scope->mem_size) {
|
||||
error("Scope stack overflow");
|
||||
return -1;
|
||||
}
|
||||
int addr = current_scope->sp;
|
||||
current_scope->sp += size;
|
||||
return addr;
|
||||
}
|
||||
|
||||
int scope_check_sp(int required) {
|
||||
if (!current_scope) return 0;
|
||||
return required >= 0 && required < current_scope->mem_size;
|
||||
}
|
||||
|
||||
int scope_check_addr(int addr) {
|
||||
if (!current_scope) return 0;
|
||||
return addr >= 0 && addr < current_scope->mem_size;
|
||||
}
|
||||
|
||||
void scope_init(void) {
|
||||
extern int sp, bp, loc_cnt;
|
||||
|
||||
if (root_scope) {
|
||||
scope_cleanup();
|
||||
}
|
||||
root_scope = scope_create(NULL);
|
||||
current_scope = root_scope;
|
||||
|
||||
sp = 0;
|
||||
bp = 0;
|
||||
loc_cnt = 0;
|
||||
}
|
||||
|
||||
void scope_cleanup(void) {
|
||||
while (current_scope && current_scope != root_scope) {
|
||||
scope_pop();
|
||||
}
|
||||
if (root_scope) {
|
||||
scope_destroy(root_scope);
|
||||
root_scope = NULL;
|
||||
current_scope = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void scope_save_state(int *out_sp, int *out_bp, int *out_loc_cnt) {
|
||||
if (!current_scope) {
|
||||
*out_sp = 0;
|
||||
*out_bp = 0;
|
||||
*out_loc_cnt = 0;
|
||||
return;
|
||||
}
|
||||
*out_sp = current_scope->sp;
|
||||
*out_bp = current_scope->bp;
|
||||
*out_loc_cnt = current_scope->loc_cnt;
|
||||
}
|
||||
|
||||
void scope_restore_state(int saved_sp, int saved_bp, int saved_loc_cnt) {
|
||||
if (!current_scope) return;
|
||||
current_scope->sp = saved_sp;
|
||||
current_scope->bp = saved_bp;
|
||||
current_scope->loc_cnt = saved_loc_cnt;
|
||||
}
|
||||
|
||||
void scope_sync_to_globals(void) {
|
||||
if (!current_scope) return;
|
||||
|
||||
extern long memory[];
|
||||
extern Symbol locals[];
|
||||
extern int sp, bp, loc_cnt;
|
||||
|
||||
int copy_sp = current_scope->sp < MEM_SIZE ? current_scope->sp : MEM_SIZE;
|
||||
for (int i = 0; i < copy_sp; i++) {
|
||||
memory[i] = current_scope->memory[i];
|
||||
}
|
||||
|
||||
int copy_loc = current_scope->loc_cnt < VAR_MAX ? current_scope->loc_cnt : VAR_MAX;
|
||||
for (int i = 0; i < copy_loc; i++) {
|
||||
locals[i] = current_scope->locals[i];
|
||||
}
|
||||
|
||||
sp = current_scope->sp;
|
||||
bp = current_scope->bp;
|
||||
loc_cnt = current_scope->loc_cnt;
|
||||
}
|
||||
|
||||
void scope_sync_from_globals(void) {
|
||||
if (!current_scope) return;
|
||||
|
||||
extern long memory[];
|
||||
extern Symbol locals[];
|
||||
extern int sp, bp, loc_cnt;
|
||||
|
||||
int copy_sp = sp < current_scope->mem_size ? sp : current_scope->mem_size;
|
||||
for (int i = 0; i < copy_sp; i++) {
|
||||
current_scope->memory[i] = memory[i];
|
||||
}
|
||||
|
||||
int copy_loc = loc_cnt < current_scope->loc_capacity ? loc_cnt : current_scope->loc_capacity;
|
||||
for (int i = 0; i < copy_loc; i++) {
|
||||
current_scope->locals[i] = locals[i];
|
||||
}
|
||||
|
||||
current_scope->sp = sp;
|
||||
current_scope->bp = bp;
|
||||
current_scope->loc_cnt = loc_cnt;
|
||||
}
|
||||
|
||||
Symbol* scope_find_local_symbol(const char *name, int len) {
|
||||
if (!name || len <= 0 || len >= 32) return NULL;
|
||||
|
||||
Scope *scope = current_scope;
|
||||
while (scope) {
|
||||
for (int i = scope->loc_cnt - 1; i >= 0; i--) {
|
||||
if (!strncmp(scope->locals[i].name, name, len) && scope->locals[i].name[len] == 0) {
|
||||
return &scope->locals[i];
|
||||
}
|
||||
}
|
||||
scope = scope->parent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int scope_find_local_with_scope(const char *name, int len, Scope **out_scope) {
|
||||
if (!name || len <= 0 || len >= 32) return -1;
|
||||
|
||||
Scope *scope = current_scope;
|
||||
while (scope) {
|
||||
for (int i = scope->loc_cnt - 1; i >= 0; i--) {
|
||||
if (!strncmp(scope->locals[i].name, name, len) && scope->locals[i].name[len] == 0) {
|
||||
if (out_scope) *out_scope = scope;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
scope = scope->parent;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
long scope_read_var(const char *name, int len) {
|
||||
Scope *scope = NULL;
|
||||
int idx = scope_find_local_with_scope(name, len, &scope);
|
||||
if (idx < 0 || !scope) return 0;
|
||||
|
||||
Symbol *sym = &scope->locals[idx];
|
||||
if (sym->addr < 0 || sym->addr >= scope->mem_size) return 0;
|
||||
return scope->memory[sym->addr];
|
||||
}
|
||||
|
||||
void scope_write_var(const char *name, int len, long value) {
|
||||
Scope *scope = NULL;
|
||||
int idx = scope_find_local_with_scope(name, len, &scope);
|
||||
if (idx < 0 || !scope) return;
|
||||
|
||||
Symbol *sym = &scope->locals[idx];
|
||||
if (sym->addr < 0 || sym->addr >= scope->mem_size) return;
|
||||
scope->memory[sym->addr] = value;
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
#ifndef SCOPE_H
|
||||
#define SCOPE_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define SCOPE_MEM_SIZE 10000
|
||||
#define SCOPE_VAR_MAX 500
|
||||
|
||||
typedef struct Scope {
|
||||
struct Scope *parent;
|
||||
long *memory;
|
||||
int mem_size;
|
||||
Symbol *locals;
|
||||
int loc_capacity;
|
||||
int sp;
|
||||
int bp;
|
||||
int loc_cnt;
|
||||
int depth;
|
||||
} Scope;
|
||||
|
||||
extern Scope *current_scope;
|
||||
extern Scope *root_scope;
|
||||
|
||||
Scope* scope_create(Scope *parent);
|
||||
void scope_destroy(Scope *scope);
|
||||
Scope* scope_push(void);
|
||||
Scope* scope_pop(void);
|
||||
|
||||
int scope_find_local(const char *name, int len);
|
||||
int scope_find_local_current_only(const char *name, int len);
|
||||
Symbol* scope_get_local(int idx);
|
||||
Symbol* scope_add_local(const char *name, int len, int type, int addr, int is_array);
|
||||
|
||||
long scope_mem_read(int addr);
|
||||
void scope_mem_write(int addr, long value);
|
||||
int scope_mem_alloc(int size);
|
||||
int scope_check_sp(int required);
|
||||
int scope_check_addr(int addr);
|
||||
|
||||
void scope_init(void);
|
||||
void scope_cleanup(void);
|
||||
|
||||
void scope_save_state(int *out_sp, int *out_bp, int *out_loc_cnt);
|
||||
void scope_restore_state(int saved_sp, int saved_bp, int saved_loc_cnt);
|
||||
|
||||
void scope_sync_to_globals(void);
|
||||
void scope_sync_from_globals(void);
|
||||
|
||||
Symbol* scope_find_local_symbol(const char *name, int len);
|
||||
int scope_find_local_with_scope(const char *name, int len, Scope **out_scope);
|
||||
long scope_read_var(const char *name, int len);
|
||||
void scope_write_var(const char *name, int len, long value);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
# RC Standard Library
|
||||
|
||||
The RC language standard library is organized into modular categories for easy maintenance and extensibility.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
src/stdlib/
|
||||
├── stdlib.h # Main registration header
|
||||
├── stdlib.c # Registers all stdlib modules
|
||||
├── string/ # String manipulation functions
|
||||
│ ├── string_stdlib.h
|
||||
│ └── string_stdlib.c
|
||||
├── math/ # Mathematical functions
|
||||
│ ├── math_stdlib.h
|
||||
│ └── math_stdlib.c
|
||||
├── io/ # Input/Output operations
|
||||
│ ├── file_stdlib.h
|
||||
│ ├── file_stdlib.c # File I/O functions
|
||||
│ ├── socket_stdlib.h
|
||||
│ └── socket_stdlib.c # Network socket functions
|
||||
├── async/ # Asynchronous operations
|
||||
│ ├── async_stdlib.h
|
||||
│ └── async_stdlib.c # Async I/O and coroutines
|
||||
└── constants/ # System constants
|
||||
├── constants_stdlib.h
|
||||
└── constants_stdlib.c
|
||||
```
|
||||
|
||||
## Available Functions
|
||||
|
||||
### String Functions (string/)
|
||||
- `strlen(str)` - Get string length
|
||||
- `strpos(haystack, needle)` - Find substring position
|
||||
- `substr(str, start, length)` - Extract substring
|
||||
- `upper(str)` - Convert to uppercase
|
||||
- `lower(str)` - Convert to lowercase
|
||||
- `strip(str)` - Trim whitespace
|
||||
- `replace(str, old, new)` - Replace substring
|
||||
- `startswith(str, prefix)` - Check if starts with prefix
|
||||
- `endswith(str, suffix)` - Check if ends with suffix
|
||||
|
||||
### Math Functions (math/)
|
||||
- `sqrt(x)` - Square root
|
||||
- `pow(base, exp)` - Power function
|
||||
- `sin(x)`, `cos(x)`, `tan(x)` - Trigonometric functions
|
||||
- `abs(x)` - Absolute value
|
||||
- `floor(x)`, `ceil(x)` - Rounding functions
|
||||
- `int_to_double(x)` - Convert int to double
|
||||
- `double_to_int(x)` - Convert double to int
|
||||
- `double_add(a, b)`, `double_sub(a, b)`, `double_mul(a, b)`, `double_div(a, b)` - Double arithmetic
|
||||
|
||||
### File I/O Functions (io/file_stdlib.c)
|
||||
- `fopen(filename, mode)` - Open file
|
||||
- `fclose(file)` - Close file
|
||||
- `fread(file, addr, size)` - Read from file
|
||||
- `fwrite(file, buf, size)` - Write to file
|
||||
- `fgets(file, max_size)` - Read line from file
|
||||
- `fputs(file, str)` - Write string to file
|
||||
- `feof(file)` - Check end of file
|
||||
- `ftell(file)` - Get file position
|
||||
- `fseek(file, offset, whence)` - Seek in file
|
||||
- `fremove(filename)` - Delete file
|
||||
- `frename(oldname, newname)` - Rename file
|
||||
|
||||
### Socket Functions (io/socket_stdlib.c)
|
||||
- `socket(domain, type, protocol)` - Create socket
|
||||
- `bind(sockfd, port)` - Bind socket to port
|
||||
- `listen(sockfd, backlog)` - Listen for connections
|
||||
- `accept(sockfd)` - Accept connection
|
||||
- `recv(sockfd, addr, len, flags)` - Receive data
|
||||
- `send(sockfd, buf, len, flags)` - Send data
|
||||
- `close(fd)` - Close file descriptor
|
||||
|
||||
### Async Functions (async/)
|
||||
- `async_fread(file, addr, size)` - Async file read
|
||||
- `async_fwrite(file, buf, size)` - Async file write
|
||||
- `async_recv(sockfd, addr, len, flags)` - Async socket receive
|
||||
- `async_send(sockfd, buf, len, flags)` - Async socket send
|
||||
- `async_wait(id)` - Wait for async operation
|
||||
- `async_poll(id)` - Poll async operation status
|
||||
- `async_result(id)` - Get async operation result
|
||||
- `await(coroutine_id)` - Await coroutine completion
|
||||
- `gather(coro1, coro2, ...)` - Wait for multiple coroutines
|
||||
|
||||
### Constants (constants/)
|
||||
- `AF_INET()` - IPv4 address family
|
||||
- `SOCK_STREAM()` - TCP socket type
|
||||
- `SEEK_SET()` - Seek from beginning
|
||||
- `SEEK_CUR()` - Seek from current position
|
||||
- `SEEK_END()` - Seek from end
|
||||
|
||||
## Adding New Functions
|
||||
|
||||
### 1. Add to Existing Category
|
||||
|
||||
To add a new function to an existing category (e.g., a new math function):
|
||||
|
||||
1. Open the appropriate category file: `src/stdlib/math/math_stdlib.c`
|
||||
2. Add your function implementation:
|
||||
```c
|
||||
long native_my_function(long *args, int argc) {
|
||||
if (!args || argc < 1) {
|
||||
return 0;
|
||||
}
|
||||
// Your implementation here
|
||||
return result;
|
||||
}
|
||||
```
|
||||
3. Register it in the category's registration function:
|
||||
```c
|
||||
void register_math_stdlib() {
|
||||
// ... existing registrations ...
|
||||
register_native_func("my_function", native_my_function);
|
||||
}
|
||||
```
|
||||
4. Rebuild: `make clean && make`
|
||||
|
||||
### 2. Add New Category
|
||||
|
||||
To add a new category (e.g., `datetime`):
|
||||
|
||||
1. Create directory: `mkdir -p src/stdlib/datetime`
|
||||
2. Create header file: `src/stdlib/datetime/datetime_stdlib.h`
|
||||
```c
|
||||
#ifndef DATETIME_STDLIB_H
|
||||
#define DATETIME_STDLIB_H
|
||||
|
||||
void register_datetime_stdlib();
|
||||
|
||||
#endif
|
||||
```
|
||||
3. Create implementation: `src/stdlib/datetime/datetime_stdlib.c`
|
||||
```c
|
||||
#include <time.h>
|
||||
#include "../../types.h"
|
||||
#include "datetime_stdlib.h"
|
||||
|
||||
extern void register_native_func(char *name, NativeFunc func);
|
||||
|
||||
long native_time(long *args, int argc) {
|
||||
return (long)time(NULL);
|
||||
}
|
||||
|
||||
void register_datetime_stdlib() {
|
||||
register_native_func("time", native_time);
|
||||
}
|
||||
```
|
||||
4. Add to `src/stdlib/stdlib.c`:
|
||||
```c
|
||||
#include "datetime/datetime_stdlib.h"
|
||||
|
||||
void register_stdlib() {
|
||||
// ... existing registrations ...
|
||||
register_datetime_stdlib();
|
||||
}
|
||||
```
|
||||
5. Add to Makefile SOURCES:
|
||||
```makefile
|
||||
SOURCES = ... \
|
||||
$(SRC_DIR)/stdlib/datetime/datetime_stdlib.c
|
||||
```
|
||||
6. Create build directory in Makefile dirs target:
|
||||
```makefile
|
||||
dirs:
|
||||
# ... existing directories ...
|
||||
@mkdir -p $(BUILD_DIR)/stdlib/datetime
|
||||
```
|
||||
7. Rebuild: `make clean && make`
|
||||
|
||||
## Function Signature
|
||||
|
||||
All native functions must follow this signature:
|
||||
```c
|
||||
long native_function_name(long *args, int argc)
|
||||
```
|
||||
|
||||
Where:
|
||||
- `args` - Array of long arguments passed from RC code
|
||||
- `argc` - Number of arguments
|
||||
- Returns a `long` value
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Always validate arguments (check argc and args pointer)
|
||||
2. Use appropriate error handling
|
||||
3. Document your functions with comments
|
||||
4. Test your functions thoroughly
|
||||
5. Keep functions focused and single-purpose
|
||||
6. Use the string pool for string allocations (str_pool)
|
||||
7. Check bounds when accessing memory array
|
||||
8. Follow the existing code style
|
||||
|
||||
## Testing
|
||||
|
||||
After making changes:
|
||||
1. Build: `make clean && make`
|
||||
2. Run all tests: `make test`
|
||||
3. Run specific category tests (e.g., `make run-math-test`)
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
- All stdlib modules are automatically registered when `register_stdlib()` is called from `src/native_functions.c`
|
||||
- The registration happens during interpreter initialization in `src/main.c`
|
||||
- Native functions are stored in the global `native_funcs` array
|
||||
- Function lookup is performed by name during parsing
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <sys/socket.h>
|
||||
#include "../../types.h"
|
||||
#include "../../interpreter.h"
|
||||
#include "../../scope.h"
|
||||
#include "async_stdlib.h"
|
||||
#include "../../debug.h"
|
||||
|
||||
@@ -565,11 +564,23 @@ static long execute_function_sync(int func_idx, long *args, int argc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int saved_sp = sp;
|
||||
int saved_bp = bp;
|
||||
int saved_pc = pc;
|
||||
int saved_loc_cnt = loc_cnt;
|
||||
long saved_ax = ax;
|
||||
int saved_return_flag = return_flag;
|
||||
|
||||
scope_push();
|
||||
if (sp >= MEM_SIZE) return 0;
|
||||
memory[sp] = bp;
|
||||
bp = sp++;
|
||||
|
||||
if (sp >= MEM_SIZE - 1) {
|
||||
sp = saved_sp;
|
||||
bp = saved_bp;
|
||||
return 0;
|
||||
}
|
||||
memory[sp++] = 0;
|
||||
memory[sp++] = 0;
|
||||
|
||||
int param_base = sp;
|
||||
for (int i = 0; i < argc && i < 10 && sp < MEM_SIZE; i++) {
|
||||
@@ -610,11 +621,11 @@ static long execute_function_sync(int func_idx, long *args, int argc) {
|
||||
|
||||
long result = ax;
|
||||
|
||||
scope_pop();
|
||||
|
||||
sp = saved_sp;
|
||||
bp = saved_bp;
|
||||
pc = saved_pc;
|
||||
loc_cnt = saved_loc_cnt;
|
||||
ax = saved_ax;
|
||||
return_flag = saved_return_flag;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "../../types.h"
|
||||
#include "benchmark_stdlib.h"
|
||||
|
||||
extern void register_native_func(char *name, NativeFunc func);
|
||||
extern pthread_mutex_t str_pool_mutex;
|
||||
extern char str_pool[STR_POOL_SIZE];
|
||||
extern int str_pool_idx;
|
||||
|
||||
#define MAX_TIMERS 1000
|
||||
|
||||
typedef struct {
|
||||
struct timespec start_time;
|
||||
int active;
|
||||
} BenchTimer;
|
||||
|
||||
static BenchTimer timers[MAX_TIMERS];
|
||||
static pthread_mutex_t timers_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int next_timer_id = 0;
|
||||
|
||||
long native_bench_start(long *args, int argc) {
|
||||
pthread_mutex_lock(&timers_mutex);
|
||||
|
||||
int timer_id = -1;
|
||||
for (int i = 0; i < MAX_TIMERS; i++) {
|
||||
if (!timers[i].active) {
|
||||
timer_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (timer_id == -1) {
|
||||
if (next_timer_id < MAX_TIMERS) {
|
||||
timer_id = next_timer_id++;
|
||||
} else {
|
||||
pthread_mutex_unlock(&timers_mutex);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
timers[timer_id].active = 1;
|
||||
clock_gettime(CLOCK_MONOTONIC, &timers[timer_id].start_time);
|
||||
|
||||
pthread_mutex_unlock(&timers_mutex);
|
||||
return timer_id;
|
||||
}
|
||||
|
||||
long native_bench_end(long *args, int argc) {
|
||||
if (!args || argc < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int timer_id = (int)args[0];
|
||||
|
||||
if (timer_id < 0 || timer_id >= MAX_TIMERS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct timespec end_time;
|
||||
clock_gettime(CLOCK_MONOTONIC, &end_time);
|
||||
|
||||
pthread_mutex_lock(&timers_mutex);
|
||||
|
||||
if (!timers[timer_id].active) {
|
||||
pthread_mutex_unlock(&timers_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
long elapsed_ns = (end_time.tv_sec - timers[timer_id].start_time.tv_sec) * 1000000000L +
|
||||
(end_time.tv_nsec - timers[timer_id].start_time.tv_nsec);
|
||||
|
||||
timers[timer_id].active = 0;
|
||||
|
||||
pthread_mutex_unlock(&timers_mutex);
|
||||
|
||||
return elapsed_ns;
|
||||
}
|
||||
|
||||
long native_bench_format(long *args, int argc) {
|
||||
static char empty_str[] = "";
|
||||
|
||||
if (!args || argc < 2) {
|
||||
return (long)empty_str;
|
||||
}
|
||||
|
||||
long nanoseconds = args[0];
|
||||
int unit = (int)args[1];
|
||||
|
||||
pthread_mutex_lock(&str_pool_mutex);
|
||||
|
||||
if (str_pool_idx >= STR_POOL_SIZE - 256) {
|
||||
pthread_mutex_unlock(&str_pool_mutex);
|
||||
return (long)empty_str;
|
||||
}
|
||||
|
||||
char *result = &str_pool[str_pool_idx];
|
||||
int len = 0;
|
||||
|
||||
switch (unit) {
|
||||
case 0:
|
||||
len = snprintf(result, 256, "%ld ns", nanoseconds);
|
||||
break;
|
||||
case 1: {
|
||||
double microseconds = nanoseconds / 1000.0;
|
||||
len = snprintf(result, 256, "%.3f us", microseconds);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
double milliseconds = nanoseconds / 1000000.0;
|
||||
len = snprintf(result, 256, "%.3f ms", milliseconds);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
double seconds = nanoseconds / 1000000000.0;
|
||||
len = snprintf(result, 256, "%.6f s", seconds);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
double minutes = nanoseconds / 60000000000.0;
|
||||
len = snprintf(result, 256, "%.6f min", minutes);
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
double hours = nanoseconds / 3600000000000.0;
|
||||
len = snprintf(result, 256, "%.6f h", hours);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
len = snprintf(result, 256, "%ld ns", nanoseconds);
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > 0 && len < 256) {
|
||||
str_pool_idx += len + 1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&str_pool_mutex);
|
||||
|
||||
return (long)result;
|
||||
}
|
||||
|
||||
long native_bench_format_auto(long *args, int argc) {
|
||||
if (!args || argc < 1) {
|
||||
static char empty_str[] = "";
|
||||
return (long)empty_str;
|
||||
}
|
||||
|
||||
long nanoseconds = args[0];
|
||||
int unit = 0;
|
||||
|
||||
if (nanoseconds >= 3600000000000L) {
|
||||
unit = 5;
|
||||
} else if (nanoseconds >= 60000000000L) {
|
||||
unit = 4;
|
||||
} else if (nanoseconds >= 1000000000L) {
|
||||
unit = 3;
|
||||
} else if (nanoseconds >= 1000000L) {
|
||||
unit = 2;
|
||||
} else if (nanoseconds >= 1000L) {
|
||||
unit = 1;
|
||||
} else {
|
||||
unit = 0;
|
||||
}
|
||||
|
||||
long format_args[2] = {nanoseconds, unit};
|
||||
return native_bench_format(format_args, 2);
|
||||
}
|
||||
|
||||
long native_bench_reset(long *args, int argc) {
|
||||
pthread_mutex_lock(&timers_mutex);
|
||||
|
||||
for (int i = 0; i < MAX_TIMERS; i++) {
|
||||
timers[i].active = 0;
|
||||
}
|
||||
next_timer_id = 0;
|
||||
|
||||
pthread_mutex_unlock(&timers_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void register_benchmark_stdlib() {
|
||||
register_native_func("bench_start", native_bench_start);
|
||||
register_native_func("bench_end", native_bench_end);
|
||||
register_native_func("bench_format", native_bench_format);
|
||||
register_native_func("bench_format_auto", native_bench_format_auto);
|
||||
register_native_func("bench_reset", native_bench_reset);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef BENCHMARK_STDLIB_H
|
||||
#define BENCHMARK_STDLIB_H
|
||||
|
||||
void register_benchmark_stdlib();
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include "../../types.h"
|
||||
#include "math_stdlib.h"
|
||||
|
||||
@@ -129,35 +128,6 @@ long native_double_div(long *args, int argc) {
|
||||
return result.l;
|
||||
}
|
||||
|
||||
long native_rand(long *args, int argc) {
|
||||
return (long)rand();
|
||||
}
|
||||
|
||||
long native_srand(long *args, int argc) {
|
||||
if (!args || argc < 1) {
|
||||
srand(1);
|
||||
} else {
|
||||
srand((unsigned int)args[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long native_rand_range(long *args, int argc) {
|
||||
if (!args || argc < 2) {
|
||||
return 0;
|
||||
}
|
||||
long min = args[0];
|
||||
long max = args[1];
|
||||
if (max <= min) {
|
||||
return min;
|
||||
}
|
||||
return min + (rand() % (max - min + 1));
|
||||
}
|
||||
|
||||
long native_time(long *args, int argc) {
|
||||
return (long)time(NULL);
|
||||
}
|
||||
|
||||
void register_math_stdlib() {
|
||||
register_native_func("sqrt", native_sqrt);
|
||||
register_native_func("pow", native_pow);
|
||||
@@ -173,8 +143,4 @@ void register_math_stdlib() {
|
||||
register_native_func("double_sub", native_double_sub);
|
||||
register_native_func("double_mul", native_double_mul);
|
||||
register_native_func("double_div", native_double_div);
|
||||
register_native_func("rand", native_rand);
|
||||
register_native_func("srand", native_srand);
|
||||
register_native_func("rand_range", native_rand_range);
|
||||
register_native_func("time", native_time);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "async/async_stdlib.h"
|
||||
#include "constants/constants_stdlib.h"
|
||||
#include "eval/eval_stdlib.h"
|
||||
#include "benchmark/benchmark_stdlib.h"
|
||||
|
||||
void register_stdlib() {
|
||||
register_string_stdlib();
|
||||
@@ -16,5 +15,4 @@ void register_stdlib() {
|
||||
register_async_stdlib();
|
||||
register_constants_stdlib();
|
||||
register_eval_stdlib();
|
||||
register_benchmark_stdlib();
|
||||
}
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
#include "unittest.rc"
|
||||
|
||||
int main() {
|
||||
int tc = new TestCase();
|
||||
tc.init("Benchmark Standard Library");
|
||||
|
||||
printf("\n=== Testing bench_start/bench_end ===\n");
|
||||
|
||||
int timer1 = bench_start();
|
||||
tc.assertGreaterEqual(timer1, 0, "bench_start returns valid timer ID");
|
||||
|
||||
int i = 0;
|
||||
int sum = 0;
|
||||
while (i < 1000) {
|
||||
sum = sum + i;
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int elapsed1 = bench_end(timer1);
|
||||
tc.assertGreater(elapsed1, 0, "bench_end returns positive elapsed time");
|
||||
tc.assertLess(elapsed1, 1000000000, "elapsed time is less than 1 second");
|
||||
|
||||
printf("\n=== Testing multiple timers ===\n");
|
||||
|
||||
int timer2 = bench_start();
|
||||
int timer3 = bench_start();
|
||||
tc.assertNotEqual(timer2, timer3, "Multiple timers have different IDs");
|
||||
|
||||
int elapsed2 = bench_end(timer2);
|
||||
int elapsed3 = bench_end(timer3);
|
||||
tc.assertGreater(elapsed2, 0, "Timer 2 has positive elapsed time");
|
||||
tc.assertGreater(elapsed3, 0, "Timer 3 has positive elapsed time");
|
||||
|
||||
printf("\n=== Testing bench_format with nanoseconds ===\n");
|
||||
|
||||
char* formatted_ns = bench_format(12345, 0);
|
||||
tc.assertNotNull(formatted_ns, "bench_format(ns) returns non-null");
|
||||
tc.assertStringContains(formatted_ns, "ns", "Formatted string contains 'ns'");
|
||||
tc.assertStringContains(formatted_ns, "12345", "Formatted string contains value");
|
||||
|
||||
printf("\n=== Testing bench_format with microseconds ===\n");
|
||||
|
||||
char* formatted_us = bench_format(123456, 1);
|
||||
tc.assertNotNull(formatted_us, "bench_format(us) returns non-null");
|
||||
tc.assertStringContains(formatted_us, "us", "Formatted string contains 'us'");
|
||||
|
||||
printf("\n=== Testing bench_format with milliseconds ===\n");
|
||||
|
||||
char* formatted_ms = bench_format(1234567, 2);
|
||||
tc.assertNotNull(formatted_ms, "bench_format(ms) returns non-null");
|
||||
tc.assertStringContains(formatted_ms, "ms", "Formatted string contains 'ms'");
|
||||
|
||||
printf("\n=== Testing bench_format with seconds ===\n");
|
||||
|
||||
char* formatted_s = bench_format(1234567890, 3);
|
||||
tc.assertNotNull(formatted_s, "bench_format(s) returns non-null");
|
||||
tc.assertStringContains(formatted_s, "s", "Formatted string contains 's'");
|
||||
|
||||
printf("\n=== Testing bench_format with minutes ===\n");
|
||||
|
||||
char* formatted_min = bench_format(123456789000, 4);
|
||||
tc.assertNotNull(formatted_min, "bench_format(min) returns non-null");
|
||||
tc.assertStringContains(formatted_min, "min", "Formatted string contains 'min'");
|
||||
|
||||
printf("\n=== Testing bench_format with hours ===\n");
|
||||
|
||||
char* formatted_h = bench_format(7412345678900, 5);
|
||||
tc.assertNotNull(formatted_h, "bench_format(h) returns non-null");
|
||||
tc.assertStringContains(formatted_h, "h", "Formatted string contains 'h'");
|
||||
|
||||
printf("\n=== Testing bench_format_auto with nanoseconds ===\n");
|
||||
|
||||
char* auto_ns = bench_format_auto(500);
|
||||
tc.assertNotNull(auto_ns, "bench_format_auto(500ns) returns non-null");
|
||||
tc.assertStringContains(auto_ns, "ns", "Auto-format chooses nanoseconds for small values");
|
||||
|
||||
printf("\n=== Testing bench_format_auto with microseconds ===\n");
|
||||
|
||||
char* auto_us = bench_format_auto(5000);
|
||||
tc.assertNotNull(auto_us, "bench_format_auto(5000ns) returns non-null");
|
||||
tc.assertStringContains(auto_us, "us", "Auto-format chooses microseconds");
|
||||
|
||||
printf("\n=== Testing bench_format_auto with milliseconds ===\n");
|
||||
|
||||
char* auto_ms = bench_format_auto(5000000);
|
||||
tc.assertNotNull(auto_ms, "bench_format_auto(5ms) returns non-null");
|
||||
tc.assertStringContains(auto_ms, "ms", "Auto-format chooses milliseconds");
|
||||
|
||||
printf("\n=== Testing bench_format_auto with seconds ===\n");
|
||||
|
||||
char* auto_s = bench_format_auto(5000000000);
|
||||
tc.assertNotNull(auto_s, "bench_format_auto(5s) returns non-null");
|
||||
tc.assertStringContains(auto_s, "s", "Auto-format chooses seconds");
|
||||
|
||||
printf("\n=== Testing bench_format_auto with minutes ===\n");
|
||||
|
||||
char* auto_min = bench_format_auto(300000000000);
|
||||
tc.assertNotNull(auto_min, "bench_format_auto(5min) returns non-null");
|
||||
tc.assertStringContains(auto_min, "min", "Auto-format chooses minutes");
|
||||
|
||||
printf("\n=== Testing bench_format_auto with hours ===\n");
|
||||
|
||||
char* auto_h = bench_format_auto(18000000000000);
|
||||
tc.assertNotNull(auto_h, "bench_format_auto(5h) returns non-null");
|
||||
tc.assertStringContains(auto_h, "h", "Auto-format chooses hours");
|
||||
|
||||
printf("\n=== Testing practical benchmarking scenario ===\n");
|
||||
|
||||
int timer_practical = bench_start();
|
||||
|
||||
int j = 0;
|
||||
int factorial = 1;
|
||||
while (j < 100) {
|
||||
factorial = factorial + j;
|
||||
j = j + 1;
|
||||
}
|
||||
|
||||
int elapsed_practical = bench_end(timer_practical);
|
||||
char* practical_formatted = bench_format_auto(elapsed_practical);
|
||||
|
||||
tc.assertGreater(elapsed_practical, 0, "Practical benchmark measured time");
|
||||
tc.assertNotNull(practical_formatted, "Practical benchmark formatted correctly");
|
||||
|
||||
printf(" Practical test took: %s\n", practical_formatted);
|
||||
|
||||
printf("\n=== Testing bench_reset ===\n");
|
||||
|
||||
int reset_result = bench_reset();
|
||||
tc.assertEqual(reset_result, 0, "bench_reset returns 0");
|
||||
|
||||
int timer_after_reset = bench_start();
|
||||
tc.assertGreaterEqual(timer_after_reset, 0, "Timer ID valid after reset");
|
||||
|
||||
printf("\n=== Testing error cases ===\n");
|
||||
|
||||
int invalid_end = bench_end(9999);
|
||||
tc.assertEqual(invalid_end, -1, "bench_end with invalid timer returns -1");
|
||||
|
||||
int negative_timer = bench_end(-1);
|
||||
tc.assertEqual(negative_timer, -1, "bench_end with negative timer returns -1");
|
||||
|
||||
printf("\n=== Testing nested timing ===\n");
|
||||
|
||||
int outer_timer = bench_start();
|
||||
int inner_timer = bench_start();
|
||||
|
||||
int k = 0;
|
||||
while (k < 50) {
|
||||
k = k + 1;
|
||||
}
|
||||
|
||||
int inner_elapsed = bench_end(inner_timer);
|
||||
int outer_elapsed = bench_end(outer_timer);
|
||||
|
||||
tc.assertGreater(inner_elapsed, 0, "Inner timer measured time");
|
||||
tc.assertGreater(outer_elapsed, 0, "Outer timer measured time");
|
||||
tc.assertGreaterEqual(outer_elapsed, inner_elapsed, "Outer timer >= inner timer");
|
||||
|
||||
printf("\n=== Summary ===\n");
|
||||
printf("Total Passed: %d\n", tc.passed);
|
||||
printf("Total Failed: %d\n", tc.failed);
|
||||
|
||||
if (tc.failed == 0) {
|
||||
printf("All benchmark stdlib tests PASSED!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -61,35 +61,6 @@ int main() {
|
||||
result_int = double_to_int(d_quot);
|
||||
tc.assertEqual(result_int, 1, "Double division: 5.0 / 3.0 = 1.666... (truncated to 1)");
|
||||
|
||||
printf("\n=== Testing Random Functions ===\n");
|
||||
srand(42);
|
||||
int r1 = rand();
|
||||
int r2 = rand();
|
||||
tc.assertNotEqual(r1, r2, "Two consecutive rand() calls should give different values");
|
||||
tc.assertGreaterEqual(r1, 0, "rand() returns non-negative");
|
||||
tc.assertGreaterEqual(r2, 0, "rand() returns non-negative");
|
||||
|
||||
srand(42);
|
||||
int r3 = rand();
|
||||
tc.assertEqual(r1, r3, "Same seed produces same first value");
|
||||
|
||||
printf("\n=== Testing rand_range ===\n");
|
||||
srand(time());
|
||||
int i = 0;
|
||||
int range_ok = 1;
|
||||
while (i < 100) {
|
||||
int val = rand_range(10, 20);
|
||||
if (val < 10 || val > 20) {
|
||||
range_ok = 0;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
tc.assertTrue(range_ok, "rand_range(10, 20) returns values in [10, 20]");
|
||||
|
||||
printf("\n=== Testing time ===\n");
|
||||
int t1 = time();
|
||||
tc.assertGreater(t1, 0, "time() returns positive timestamp");
|
||||
|
||||
printf("\n=== Summary ===\n");
|
||||
printf("Total Passed: %d\n", tc.passed);
|
||||
printf("Total Failed: %d\n", tc.failed);
|
||||
|
||||
Reference in New Issue
Block a user