Compare commits

..

5 Commits

Author SHA1 Message Date
2dae3f98e9 Added build file.
All checks were successful
Build and Test / build (push) Successful in 28s
2025-11-23 15:45:39 +01:00
0ec0590ad0 Added include functionallity. 2025-11-23 15:23:59 +01:00
6c8a15272a Implemented tests. 2025-11-23 15:07:19 +01:00
5828aa8622 Async implementation. 2025-11-23 14:30:46 +01:00
050e85b72a Break loop. 2025-11-23 13:53:36 +01:00
38 changed files with 2376 additions and 64 deletions

13
.gitea/workflows/main.yml Normal file
View File

@ -0,0 +1,13 @@
name: Build and Test
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build
run: make
- name: Test
run: make test

135
Makefile
View File

@ -1,6 +1,6 @@
CC = gcc CC = gcc
CFLAGS = -Wall -Wextra -O2 -Isrc CFLAGS = -Wall -Wextra -O2 -Isrc
LDFLAGS = -lm LDFLAGS = -lm -lpthread
SRC_DIR = src SRC_DIR = src
TEST_DIR = tests TEST_DIR = tests
@ -16,7 +16,8 @@ SOURCES = $(SRC_DIR)/main.c \
$(SRC_DIR)/parser.c \ $(SRC_DIR)/parser.c \
$(SRC_DIR)/interpreter.c \ $(SRC_DIR)/interpreter.c \
$(SRC_DIR)/native_functions.c \ $(SRC_DIR)/native_functions.c \
$(SRC_DIR)/string_utils.c $(SRC_DIR)/string_utils.c \
$(SRC_DIR)/preprocessor.c
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
@ -25,11 +26,25 @@ TESTS = $(TEST_DIR)/feature_test.rc \
$(TEST_DIR)/math_test.rc \ $(TEST_DIR)/math_test.rc \
$(TEST_DIR)/string_test.rc \ $(TEST_DIR)/string_test.rc \
$(TEST_DIR)/string_manip_test.rc \ $(TEST_DIR)/string_manip_test.rc \
$(TEST_DIR)/increment_decrement_test.rc $(TEST_DIR)/increment_decrement_test.rc \
$(TEST_DIR)/file_io_test.rc \
$(TEST_DIR)/double_test.rc \
$(TEST_DIR)/break_continue_test.rc \
$(TEST_DIR)/async_io_test.rc \
$(TEST_DIR)/array_test.rc \
$(TEST_DIR)/pointer_test.rc \
$(TEST_DIR)/logical_test.rc \
$(TEST_DIR)/comparison_test.rc \
$(TEST_DIR)/functions_test.rc \
$(TEST_DIR)/trig_test.rc \
$(TEST_DIR)/file_seek_test.rc \
$(TEST_DIR)/include_test.rc \
$(TEST_DIR)/nested_include_test.rc
EXAMPLES = $(EXAMPLE_DIR)/http_simple.rc \ EXAMPLES = $(EXAMPLE_DIR)/http_simple.rc \
$(EXAMPLE_DIR)/http_persistent.rc \ $(EXAMPLE_DIR)/http_persistent.rc \
$(EXAMPLE_DIR)/http_multi.rc $(EXAMPLE_DIR)/http_multi.rc \
$(EXAMPLE_DIR)/async_demo.rc
.PHONY: all clean test run-tests run-examples help .PHONY: all clean test run-tests run-examples help
@ -68,6 +83,45 @@ test: $(TARGET)
@echo "Running increment decrement tests..." @echo "Running increment decrement tests..."
@$(TARGET) $(TEST_DIR)/increment_decrement_test.rc 2>&1 | grep -v "Error at token" || true @$(TARGET) $(TEST_DIR)/increment_decrement_test.rc 2>&1 | grep -v "Error at token" || true
@echo "" @echo ""
@echo "Running file I/O tests..."
@$(TARGET) $(TEST_DIR)/file_io_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running double tests..."
@$(TARGET) $(TEST_DIR)/double_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running break/continue tests..."
@$(TARGET) $(TEST_DIR)/break_continue_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running async I/O tests..."
@$(TARGET) $(TEST_DIR)/async_io_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running array tests..."
@$(TARGET) $(TEST_DIR)/array_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running pointer tests..."
@$(TARGET) $(TEST_DIR)/pointer_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running logical operators tests..."
@$(TARGET) $(TEST_DIR)/logical_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running comparison operators tests..."
@$(TARGET) $(TEST_DIR)/comparison_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running functions tests..."
@$(TARGET) $(TEST_DIR)/functions_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running trigonometry tests..."
@$(TARGET) $(TEST_DIR)/trig_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running file seek tests..."
@$(TARGET) $(TEST_DIR)/file_seek_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running include tests..."
@$(TARGET) $(TEST_DIR)/include_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "Running nested include tests..."
@$(TARGET) $(TEST_DIR)/nested_include_test.rc 2>&1 | grep -v "Error at token" || true
@echo ""
@echo "=== All Tests Completed ===" @echo "=== All Tests Completed ==="
run-feature-test: $(TARGET) run-feature-test: $(TARGET)
@ -88,6 +142,45 @@ run-string-manip: $(TARGET)
run-increment-decrement-test: $(TARGET) run-increment-decrement-test: $(TARGET)
$(TARGET) $(TEST_DIR)/increment_decrement_test.rc $(TARGET) $(TEST_DIR)/increment_decrement_test.rc
run-file-io-test: $(TARGET)
$(TARGET) $(TEST_DIR)/file_io_test.rc
run-double-test: $(TARGET)
$(TARGET) $(TEST_DIR)/double_test.rc
run-break-continue-test: $(TARGET)
$(TARGET) $(TEST_DIR)/break_continue_test.rc
run-async-io-test: $(TARGET)
$(TARGET) $(TEST_DIR)/async_io_test.rc
run-array-test: $(TARGET)
$(TARGET) $(TEST_DIR)/array_test.rc
run-pointer-test: $(TARGET)
$(TARGET) $(TEST_DIR)/pointer_test.rc
run-logical-test: $(TARGET)
$(TARGET) $(TEST_DIR)/logical_test.rc
run-comparison-test: $(TARGET)
$(TARGET) $(TEST_DIR)/comparison_test.rc
run-functions-test: $(TARGET)
$(TARGET) $(TEST_DIR)/functions_test.rc
run-trig-test: $(TARGET)
$(TARGET) $(TEST_DIR)/trig_test.rc
run-file-seek-test: $(TARGET)
$(TARGET) $(TEST_DIR)/file_seek_test.rc
run-include-test: $(TARGET)
$(TARGET) $(TEST_DIR)/include_test.rc
run-nested-include-test: $(TARGET)
$(TARGET) $(TEST_DIR)/nested_include_test.rc
run-http-simple: $(TARGET) run-http-simple: $(TARGET)
$(TARGET) $(EXAMPLE_DIR)/http_simple.rc $(TARGET) $(EXAMPLE_DIR)/http_simple.rc
@ -97,6 +190,9 @@ run-http-persistent: $(TARGET)
run-http-multi: $(TARGET) run-http-multi: $(TARGET)
$(TARGET) $(EXAMPLE_DIR)/http_multi.rc $(TARGET) $(EXAMPLE_DIR)/http_multi.rc
run-async-demo: $(TARGET)
$(TARGET) $(EXAMPLE_DIR)/async_demo.rc
help: help:
@echo "RC - Retoor's C Interpreter" @echo "RC - Retoor's C Interpreter"
@echo "" @echo ""
@ -106,16 +202,31 @@ help:
@echo " make clean - Remove all build artifacts" @echo " make clean - Remove all build artifacts"
@echo "" @echo ""
@echo "Individual Tests:" @echo "Individual Tests:"
@echo " make run-feature-test - Run feature_test.rc (negative numbers, ==, !=)" @echo " make run-feature-test - Run feature_test.rc (negative numbers, ==, !=)"
@echo " make run-endless-loop - Run endless_loop_test.rc (while(1) test)" @echo " make run-endless-loop - Run endless_loop_test.rc (while(1) test)"
@echo " make run-math-test - Run math_test.rc (math functions)" @echo " make run-math-test - Run math_test.rc (math functions)"
@echo " make run-string-test - Run string_test.rc (string concatenation)" @echo " make run-string-test - Run string_test.rc (string concatenation)"
@echo " make run-string-manip - Run string_manip_test.rc (string manipulation & slicing)" @echo " make run-string-manip - Run string_manip_test.rc (string manipulation & slicing)"
@echo " make run-increment-decrement-test - Run increment_decrement_test.rc (++/--)"
@echo " make run-file-io-test - Run file_io_test.rc (file I/O operations)"
@echo " make run-double-test - Run double_test.rc (double data type)"
@echo " make run-break-continue-test - Run break_continue_test.rc (break/continue)"
@echo " make run-async-io-test - Run async_io_test.rc (async I/O)"
@echo " make run-array-test - Run array_test.rc (arrays)"
@echo " make run-pointer-test - Run pointer_test.rc (pointers & dereference)"
@echo " make run-logical-test - Run logical_test.rc (&&, ||)"
@echo " make run-comparison-test - Run comparison_test.rc (<, >, <=, >=)"
@echo " make run-functions-test - Run functions_test.rc (function calls & recursion)"
@echo " make run-trig-test - Run trig_test.rc (sin, cos, tan)"
@echo " make run-file-seek-test - Run file_seek_test.rc (fseek, ftell)"
@echo " make run-include-test - Run include_test.rc (#include directive)"
@echo " make run-nested-include-test - Run nested_include_test.rc (nested includes)"
@echo "" @echo ""
@echo "Examples:" @echo "Examples:"
@echo " make run-http-simple - Run http_simple.rc (single connection HTTP server)" @echo " make run-http-simple - Run http_simple.rc (single connection HTTP server)"
@echo " make run-http-persistent - Run http_persistent.rc (persistent HTTP server)" @echo " make run-http-persistent - Run http_persistent.rc (persistent HTTP server)"
@echo " make run-http-multi - Run http_multi.rc (HTTP server, 100 connections)" @echo " make run-http-multi - Run http_multi.rc (HTTP server, 100 connections)"
@echo " make run-async-demo - Run async_demo.rc (comprehensive async I/O demo)"
@echo "" @echo ""
@echo "Directory Structure:" @echo "Directory Structure:"
@echo " src/ - Source code files" @echo " src/ - Source code files"

View File

@ -8,6 +8,7 @@ RC is a lightweight, recursive-descent C interpreter written in C. It executes a
**Data Types** **Data Types**
- Integers (long) - Integers (long)
- Doubles (floating-point numbers)
- Character pointers (char*) - Character pointers (char*)
- Pointer operations (address-of &, dereference *) - Pointer operations (address-of &, dereference *)
- Array declarations and indexing - Array declarations and indexing
@ -15,6 +16,7 @@ RC is a lightweight, recursive-descent C interpreter written in C. It executes a
**Control Flow** **Control Flow**
- if/else statements - if/else statements
- while loops (including infinite loops) - while loops (including infinite loops)
- break and continue statements
- Comparison operators: ==, !=, <, >, <=, >= - Comparison operators: ==, !=, <, >, <=, >=
- Logical operators: &&, || - Logical operators: &&, ||
@ -39,6 +41,13 @@ RC is a lightweight, recursive-descent C interpreter written in C. It executes a
- sin(x), cos(x), tan(x) - Trigonometric functions - sin(x), cos(x), tan(x) - Trigonometric functions
- floor(x), ceil(x) - Rounding functions - floor(x), ceil(x) - Rounding functions
**Double Type Functions**
- int_to_double(i) - Convert int to double
- double_to_int(d) - Convert double to int
- double_add(a, b), double_sub(a, b) - Double arithmetic
- double_mul(a, b), double_div(a, b) - Double arithmetic
- printf with %f format for doubles
**String Functions** **String Functions**
- strpos(haystack, needle) - Find substring position - strpos(haystack, needle) - Find substring position
- substr(str, start, length) - Extract substring - substr(str, start, length) - Extract substring
@ -49,6 +58,27 @@ RC is a lightweight, recursive-descent C interpreter written in C. It executes a
- endswith(str, suffix) - Suffix check - endswith(str, suffix) - Suffix check
- strlen(str) - String length - strlen(str) - String length
**File I/O**
- fopen(filename, mode) - Open a file
- fclose(file) - Close a file
- fread(file, buffer, size) - Read from file
- fwrite(file, buffer, size) - Write to file
- fgets(file, max_size) - Read a line
- fputs(file, string) - Write a string
- feof(file) - Check end of file
- ftell(file), fseek(file, offset, whence) - File positioning
- fremove(filename), frename(old, new) - File operations
- SEEK_SET, SEEK_CUR, SEEK_END constants
**Async I/O (Multi-threaded)**
- async_fread(file, buffer, size) - Async file read
- async_fwrite(file, buffer, size) - Async file write
- async_recv(socket, buffer, len, flags) - Async socket receive
- async_send(socket, buffer, len, flags) - Async socket send
- async_wait(handle) - Wait for async operation to complete
- async_poll(handle) - Check if async operation is complete
- async_result(handle) - Get result of completed async operation
**Socket Programming** **Socket Programming**
- socket(), bind(), listen(), accept() - socket(), bind(), listen(), accept()
- send(), recv(), close() - send(), recv(), close()
@ -169,10 +199,12 @@ Extensible system for binding C functions. Current bindings include math operati
- Memory model uses long cells (not byte-accurate) - Memory model uses long cells (not byte-accurate)
- No support for structs, unions, or enums as user types - No support for structs, unions, or enums as user types
- Limited type system (int and char* only) - Limited type system (int, double, and char*)
- Double arithmetic requires explicit helper functions
- No preprocessor directives - No preprocessor directives
- Error messages show token index rather than line/column - Error messages show token index rather than line/column
- Pointer arithmetic works on virtual memory addresses - Pointer arithmetic works on virtual memory addresses
- Maximum 100 concurrent async operations
## Testing ## Testing

20
TODO2.md Normal file
View File

@ -0,0 +1,20 @@
# TO BUILD
1. Read the whole source code in src.
2. Add File I/O Functions to the scripting language
2.1 Add working tests within the tests directory.
3. Implement async I/O functions for File I/O / Socket I/O / Async I/O. The basic asyncio for methods should be we working using threads so it's a multicore application. It must be a safe way of threading but still performance.
3.1 Add working tests within the tests directory.
3.2 Add a nice example script source file (.rc) to the examples directory that shows file I/O, async I/O, and socket I/O.
4. Add double data type to the language
4.1 Add working tests within the tests directory.
5. Implement break and continue statements in the language
5.1 Add working tests within the tests directory.
6. Update Makefile, README.md, and TUTORIAL.md.
# IMPORTANT
1. Consistency (By researching how other things are implemented)
2. Performance (But readability is also important)
3. Ease of use for the user of the new language (No weird caveats)
4. Safety (for using the langauge by defensive coding)

View File

@ -986,3 +986,174 @@ int main() {
--- ---
For more examples, see the `tests/` and `examples/` directories in the RC repository. For more examples, see the `tests/` and `examples/` directories in the RC repository.
## File I/O
### Writing to a File
```c
int main() {
int f = fopen("output.txt", "w");
fputs(f, "Hello, File!\n");
fputs(f, "Second line\n");
fclose(f);
return 0;
}
```
### Reading from a File
```c
int main() {
int f = fopen("output.txt", "r");
char *line = fgets(f, 256);
while (strlen(line) > 0 && feof(f) == 0) {
printf("%s", line);
line = fgets(f, 256);
}
fclose(f);
return 0;
}
```
## Double Data Type
### Using Doubles
```c
int main() {
double pi = 3.14159;
double radius = 5.0;
printf("Pi: %f\n", pi);
printf("Radius: %f\n", radius);
double area = double_mul(pi, double_mul(radius, radius));
printf("Circle area: %f\n", area);
return 0;
}
```
### Type Conversions
```c
int main() {
int x = 42;
double dx = int_to_double(x);
printf("Int %d as double: %f\n", x, dx);
double y = 99.9;
int iy = double_to_int(y);
printf("Double %f as int: %d\n", y, iy);
return 0;
}
```
## Break and Continue
### Break Statement
```c
int main() {
int i = 0;
while (i < 10) {
i = i + 1;
if (i == 5) {
printf("Breaking at %d\n", i);
break;
}
printf("%d ", i);
}
printf("\nDone\n");
return 0;
}
```
### Continue Statement
```c
int main() {
int i = 0;
while (i < 10) {
i = i + 1;
if (i == 3 || i == 7) {
continue;
}
printf("%d ", i);
}
printf("\n");
return 0;
}
```
## Async I/O
### Async File Operations
```c
int main() {
int f = fopen("async_file.txt", "w");
int write_handle = async_fwrite(f, "Async write!", 12);
printf("Write started, handle: %d\n", write_handle);
int result = async_wait(write_handle);
printf("Write completed, bytes: %d\n", result);
fclose(f);
return 0;
}
```
### Polling for Completion
```c
int main() {
int f = fopen("data.txt", "r");
int buffer[1024];
int read_handle = async_fread(f, &buffer, 1024);
printf("Reading asynchronously...\n");
while (async_poll(read_handle) == 0) {
printf(".");
}
printf("\nRead complete!\n");
int bytes = async_result(read_handle);
printf("Bytes read: %d\n", bytes);
fclose(f);
return 0;
}
```
### Async Socket I/O
```c
int main() {
int server = socket(AF_INET(), SOCK_STREAM(), 0);
bind(server, 8080);
listen(server, 5);
int client = accept(server);
int buffer[1024];
int recv_handle = async_recv(client, &buffer, 1024, 0);
printf("Async receive started...\n");
int bytes = async_wait(recv_handle);
printf("Received %d bytes\n", bytes);
char *response = "HTTP/1.1 200 OK\r\n\r\nOK";
int send_handle = async_send(client, response, strlen(response), 0);
async_wait(send_handle);
close(client);
close(server);
return 0;
}
```

86
examples/async_demo.rc Normal file
View File

@ -0,0 +1,86 @@
int main() {
printf("=== Async I/O Demo: File I/O + Async I/O + Socket I/O ===\n\n");
printf("Step 1: Synchronous File I/O\n");
int log_file = fopen("demo_log.txt", "w");
fputs(log_file, "Server Log Started\n");
fclose(log_file);
printf("Created log file\n\n");
printf("Step 2: Async File Operations\n");
log_file = fopen("demo_log.txt", "a");
int write_op1 = async_fwrite(log_file, "Initializing server...\n", 24);
int write_op2 = async_fwrite(log_file, "Binding to port 8080...\n", 25);
printf("Multiple async writes queued\n");
async_wait(write_op1);
async_wait(write_op2);
printf("All async writes completed\n\n");
printf("Step 3: Socket Server Setup\n");
int server_socket = socket(AF_INET(), SOCK_STREAM(), 0);
if (server_socket < 0) {
printf("ERROR: Could not create socket\n");
return 1;
}
printf("Socket created: %d\n", server_socket);
int bind_result = bind(server_socket, 8080);
if (bind_result < 0) {
printf("ERROR: Could not bind to port\n");
return 1;
}
printf("Bound to port 8080\n");
listen(server_socket, 5);
printf("Listening for connections...\n\n");
printf("Step 4: Log async write while waiting for connection\n");
int log_op = async_fwrite(log_file, "Waiting for client...\n", 23);
printf("Accepting client (this will wait for a connection)\n");
printf("In another terminal, run: curl http://localhost:8080/\n\n");
int client = accept(server_socket);
async_wait(log_op);
printf("Client connected: %d\n\n", client);
printf("Step 5: Handle client with async socket I/O\n");
int buffer[1024];
int recv_op = async_recv(client, &buffer, 1024, 0);
printf("Async receive started...\n");
while (async_poll(recv_op) == 0) {
printf(".");
}
printf("\n");
int bytes = async_result(recv_op);
printf("Received %d bytes\n", bytes);
char *response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nAsync I/O Demo Success!\n";
int send_op = async_send(client, response, strlen(response), 0);
async_wait(send_op);
printf("Response sent asynchronously\n\n");
printf("Step 6: Final log entry\n");
int final_log = async_fwrite(log_file, "Client served successfully\n", 28);
async_wait(final_log);
close(client);
close(server_socket);
fclose(log_file);
printf("\nStep 7: Read log file\n");
log_file = fopen("demo_log.txt", "r");
char *line = fgets(log_file, 256);
while (strlen(line) > 0 && feof(log_file) == 0) {
printf("LOG: %s", line);
line = fgets(log_file, 256);
}
fclose(log_file);
printf("\n=== Demo Complete ===\n");
printf("Demonstrated: Sync File I/O, Async File I/O, Socket I/O, and Async Socket I/O\n");
return 0;
}

View File

@ -16,3 +16,4 @@ char *src_code;
char str_pool[STR_POOL_SIZE]; char str_pool[STR_POOL_SIZE];
int str_pool_idx = 0; int str_pool_idx = 0;
long ax = 0; long ax = 0;
int return_flag = 0;

View File

@ -73,11 +73,20 @@ void statement() {
pc++; pc++;
while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != '}' && tokens[pc].type != 0) { while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != '}' && tokens[pc].type != 0) {
statement(); statement();
if (ax == -999) break; if (return_flag || ax == -998 || ax == -997) {
int brace = 1;
while (brace > 0 && pc < MAX_TOK && pc < tk_idx && tokens[pc].type != 0) {
if (tokens[pc].type == '{') brace++;
if (tokens[pc].type == '}') brace--;
pc++;
}
return;
}
} }
match('}'); match('}');
} }
else if (tokens[pc].type == Int || tokens[pc].type == Char) { else if (tokens[pc].type == Int || tokens[pc].type == Char || tokens[pc].type == Double) {
int var_type = tokens[pc].type;
pc++; pc++;
while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != ';') { while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != ';') {
while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == '*') pc++; while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == '*') pc++;
@ -94,6 +103,7 @@ void statement() {
int addr = sp; int addr = sp;
Symbol *s = &locals[loc_cnt++]; Symbol *s = &locals[loc_cnt++];
strncpy(s->name, t->text, t->val); s->name[t->val] = 0; strncpy(s->name, t->text, t->val); s->name[t->val] = 0;
s->type = var_type;
s->addr = addr; s->addr = addr;
s->is_array = 0; s->is_array = 0;
@ -129,42 +139,45 @@ void statement() {
match(')'); match(')');
if (cond) { if (cond) {
statement(); statement();
if (ax == -999) return; if (return_flag || ax == -998 || ax == -997) return;
if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == Else) { pc++; skip_block(); } if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == Else) { pc++; skip_block(); }
} else { } else {
skip_block(); skip_block();
if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == Else) { if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type == Else) {
pc++; pc++;
statement(); statement();
if (ax == -999) return; if (return_flag || ax == -998 || ax == -997) return;
} }
} }
} }
else if (tokens[pc].type == While) { else if (tokens[pc].type == While) {
pc++; pc++;
int loop_start = pc; int loop_start = pc;
match('('); int body_start;
long cond = expression(); int iteration_count = 0;
match(')'); while (1) {
if (!cond) { if (++iteration_count > 1000000) {
skip_block(); error("Potential infinite loop detected");
} else { }
int iteration_count = 0; pc = loop_start;
while (1) { match('(');
if (++iteration_count > 1000000) { long cond = expression();
error("Potential infinite loop detected"); match(')');
} if (!cond) {
statement(); skip_block();
if (ax == -999) return; break;
int save_pc = pc; }
if (loop_start >= MAX_TOK || loop_start >= tk_idx) { body_start = pc;
error("Loop start out of bounds"); statement();
} if (return_flag) return;
pc = loop_start; if (ax == -998) {
match('('); ax = 0;
cond = expression(); pc = body_start;
match(')'); skip_block();
if (!cond) { pc = save_pc; break; } break;
}
if (ax == -997) {
ax = 0;
} }
} }
} }
@ -173,7 +186,17 @@ void statement() {
if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != ';') ax = expression(); if (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != ';') ax = expression();
else ax = 0; else ax = 0;
match(';'); match(';');
ax = -999; return_flag = 1;
}
else if (tokens[pc].type == Break) {
pc++;
match(';');
ax = -998;
}
else if (tokens[pc].type == Continue) {
pc++;
match(';');
ax = -997;
} }
else if (tokens[pc].type == Printf) { else if (tokens[pc].type == Printf) {
pc++; pc++;
@ -187,11 +210,16 @@ void statement() {
char *p = fmt; char *p = fmt;
while (*p) { while (*p) {
if (*p == '%' && (p[1] == 'd' || p[1] == 's')) { if (*p == '%' && (p[1] == 'd' || p[1] == 's' || p[1] == 'f')) {
p++; p++;
match(','); match(',');
long val = expression(); long val = expression();
if (*p == 'd') printf("%ld", val); if (*p == 'd') printf("%ld", val);
else if (*p == 'f') {
union { double d; long l; } u;
u.l = val;
printf("%f", u.d);
}
else if (*p == 's') { else if (*p == 's') {
char *str = (char*)val; char *str = (char*)val;
if (str) printf("%s", str); if (str) printf("%s", str);
@ -214,7 +242,7 @@ void scan_functions() {
int i = 0; int i = 0;
while (i < MAX_TOK && i < tk_idx && tokens[i].type != 0) { while (i < MAX_TOK && i < tk_idx && tokens[i].type != 0) {
if (i + 2 < MAX_TOK && i + 2 < tk_idx && if (i + 2 < MAX_TOK && i + 2 < tk_idx &&
(tokens[i].type == Int || tokens[i].type == Char) && (tokens[i].type == Int || tokens[i].type == Char || tokens[i].type == Double) &&
tokens[i+1].type == Id && tokens[i+2].type == '(') { tokens[i+1].type == Id && tokens[i+2].type == '(') {
if (func_cnt >= 100) { if (func_cnt >= 100) {
@ -225,9 +253,10 @@ void scan_functions() {
strncpy(f->name, name->text, name->val); f->name[name->val] = 0; strncpy(f->name, name->text, name->val); f->name[name->val] = 0;
i += 3; i += 3;
f->params_start = i;
int params = 0; int params = 0;
while(i < MAX_TOK && i < tk_idx && tokens[i].type != ')') { while(i < MAX_TOK && i < tk_idx && tokens[i].type != ')') {
if (tokens[i].type == Int || tokens[i].type == Char) { if (tokens[i].type == Int || tokens[i].type == Char || tokens[i].type == Double) {
params++; params++;
i++; i++;
while (i < MAX_TOK && i < tk_idx && tokens[i].type == '*') i++; while (i < MAX_TOK && i < tk_idx && tokens[i].type == '*') i++;

View File

@ -1,9 +1,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <libgen.h>
#include <string.h>
#include "types.h" #include "types.h"
#include "tokenizer.h" #include "tokenizer.h"
#include "interpreter.h" #include "interpreter.h"
#include "native_functions.h" #include "native_functions.h"
#include "preprocessor.h"
int main(int argc, char **argv) { int main(int argc, char **argv) {
if (argc < 2) { if (argc < 2) {
@ -11,24 +14,21 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
FILE *f = fopen(argv[1], "rb"); char file_path[512];
if (!f) { strncpy(file_path, argv[1], 511);
printf("Could not open file.\n"); file_path[511] = 0;
return 1;
}
src_code = malloc(MAX_SRC + 1); char dir_path[512];
strncpy(dir_path, argv[1], 511);
dir_path[511] = 0;
char *dir = dirname(dir_path);
src_code = preprocess(file_path, dir);
if (!src_code) { if (!src_code) {
printf("Memory allocation failed.\n"); printf("Preprocessing failed.\n");
fclose(f);
return 1; return 1;
} }
size_t n = fread(src_code, 1, MAX_SRC, f);
if (n >= MAX_SRC) n = MAX_SRC - 1;
src_code[n] = 0;
fclose(f);
register_native_functions(); register_native_functions();
tokenize(src_code); tokenize(src_code);

View File

@ -7,10 +7,193 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <unistd.h> #include <unistd.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <pthread.h>
#include "types.h" #include "types.h"
#include "native_functions.h" #include "native_functions.h"
#include "interpreter.h" #include "interpreter.h"
#define MAX_ASYNC_OPS 100
typedef struct {
int active;
int complete;
long result;
pthread_t thread;
void *data;
} AsyncOp;
static AsyncOp async_ops[MAX_ASYNC_OPS];
static pthread_mutex_t async_mutex = PTHREAD_MUTEX_INITIALIZER;
static int async_initialized = 0;
typedef struct {
FILE *f;
int addr;
int size;
} AsyncFileReadData;
typedef struct {
FILE *f;
long buf_arg;
int size;
} AsyncFileWriteData;
typedef struct {
int sockfd;
int addr;
int len;
int flags;
} AsyncRecvData;
typedef struct {
int sockfd;
long buf_arg;
int len;
int flags;
} AsyncSendData;
void init_async() {
if (!async_initialized) {
for (int i = 0; i < MAX_ASYNC_OPS; i++) {
async_ops[i].active = 0;
async_ops[i].complete = 0;
async_ops[i].result = 0;
async_ops[i].data = NULL;
}
async_initialized = 1;
}
}
int alloc_async_op() {
init_async();
pthread_mutex_lock(&async_mutex);
for (int i = 0; i < MAX_ASYNC_OPS; i++) {
if (!async_ops[i].active) {
async_ops[i].active = 1;
async_ops[i].complete = 0;
async_ops[i].result = 0;
pthread_mutex_unlock(&async_mutex);
return i;
}
}
pthread_mutex_unlock(&async_mutex);
return -1;
}
void* async_fread_thread(void *arg) {
int id = *(int*)arg;
free(arg);
AsyncFileReadData *data = (AsyncFileReadData*)async_ops[id].data;
char temp_buf[8192];
int size = data->size;
if (size > 8192) size = 8192;
int result = fread(temp_buf, 1, size, data->f);
if (result > 0) {
for (int i = 0; i < result && data->addr + i < MEM_SIZE; i++) {
memory[data->addr + i] = temp_buf[i];
}
}
pthread_mutex_lock(&async_mutex);
async_ops[id].result = result;
async_ops[id].complete = 1;
pthread_mutex_unlock(&async_mutex);
free(data);
async_ops[id].data = NULL;
return NULL;
}
void* async_fwrite_thread(void *arg) {
int id = *(int*)arg;
free(arg);
AsyncFileWriteData *data = (AsyncFileWriteData*)async_ops[id].data;
long result = -1;
if (data->buf_arg > MEM_SIZE * 8 || data->buf_arg < 0) {
result = fwrite((char*)data->buf_arg, 1, data->size, data->f);
} else if (data->buf_arg < MEM_SIZE) {
char temp_buf[8192];
int size = data->size;
if (size > 8192) size = 8192;
if (data->buf_arg + size > MEM_SIZE) {
size = MEM_SIZE - data->buf_arg;
}
for (int i = 0; i < size; i++) {
temp_buf[i] = (char)memory[data->buf_arg + i];
}
result = fwrite(temp_buf, 1, size, data->f);
}
pthread_mutex_lock(&async_mutex);
async_ops[id].result = result;
async_ops[id].complete = 1;
pthread_mutex_unlock(&async_mutex);
free(data);
async_ops[id].data = NULL;
return NULL;
}
void* async_recv_thread(void *arg) {
int id = *(int*)arg;
free(arg);
AsyncRecvData *data = (AsyncRecvData*)async_ops[id].data;
char temp_buf[8192];
int len = data->len;
if (len > 8192) len = 8192;
int result = recv(data->sockfd, temp_buf, len, data->flags);
if (result > 0) {
for (int i = 0; i < result && data->addr + i < MEM_SIZE; i++) {
memory[data->addr + i] = temp_buf[i];
}
}
pthread_mutex_lock(&async_mutex);
async_ops[id].result = result;
async_ops[id].complete = 1;
pthread_mutex_unlock(&async_mutex);
free(data);
async_ops[id].data = NULL;
return NULL;
}
void* async_send_thread(void *arg) {
int id = *(int*)arg;
free(arg);
AsyncSendData *data = (AsyncSendData*)async_ops[id].data;
long result = -1;
if (data->buf_arg > MEM_SIZE * 8 || data->buf_arg < 0) {
result = send(data->sockfd, (char*)data->buf_arg, data->len, data->flags);
} else if (data->buf_arg < MEM_SIZE) {
char temp_buf[8192];
int len = data->len;
if (len > 8192) len = 8192;
if (data->buf_arg + len > MEM_SIZE) {
len = MEM_SIZE - data->buf_arg;
}
for (int i = 0; i < len; i++) {
temp_buf[i] = (char)memory[data->buf_arg + i];
}
result = send(data->sockfd, temp_buf, len, data->flags);
}
pthread_mutex_lock(&async_mutex);
async_ops[id].result = result;
async_ops[id].complete = 1;
pthread_mutex_unlock(&async_mutex);
free(data);
async_ops[id].data = NULL;
return NULL;
}
void register_native_func(char *name, NativeFunc func) { void register_native_func(char *name, NativeFunc func) {
if (!name || !func || native_func_cnt >= 100) { if (!name || !func || native_func_cnt >= 100) {
return; return;
@ -28,7 +211,12 @@ long native_socket(long *args, int argc) {
int domain = (int)args[0]; int domain = (int)args[0];
int type = (int)args[1]; int type = (int)args[1];
int protocol = (int)args[2]; int protocol = (int)args[2];
return socket(domain, type, protocol); int sockfd = socket(domain, type, protocol);
if (sockfd >= 0) {
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
}
return sockfd;
} }
long native_bind(long *args, int argc) { long native_bind(long *args, int argc) {
@ -448,6 +636,405 @@ long native_endswith(long *args, int argc) {
return strcmp(str + str_len - suffix_len, suffix) == 0; return strcmp(str + str_len - suffix_len, suffix) == 0;
} }
long native_fopen(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
char *filename = (char*)args[0];
char *mode = (char*)args[1];
if (!filename || !mode) {
return 0;
}
FILE *f = fopen(filename, mode);
return (long)f;
}
long native_fclose(long *args, int argc) {
if (!args || argc < 1) {
return -1;
}
FILE *f = (FILE*)args[0];
if (!f) {
return -1;
}
return fclose(f);
}
long native_fread(long *args, int argc) {
if (!args || argc < 3) {
return -1;
}
FILE *f = (FILE*)args[0];
int addr = (int)args[1];
int size = (int)args[2];
if (!f || addr < 0 || addr >= MEM_SIZE || size <= 0) {
return -1;
}
if (addr + size > MEM_SIZE) {
size = MEM_SIZE - addr;
}
char temp_buf[8192];
if (size > 8192) size = 8192;
int result = fread(temp_buf, 1, size, f);
if (result > 0) {
for (int i = 0; i < result && addr + i < MEM_SIZE; i++) {
memory[addr + i] = temp_buf[i];
}
}
return result;
}
long native_fwrite(long *args, int argc) {
if (!args || argc < 3) {
return -1;
}
FILE *f = (FILE*)args[0];
long buf_arg = args[1];
int size = (int)args[2];
if (!f || size <= 0) {
return -1;
}
if (buf_arg > MEM_SIZE * 8 || buf_arg < 0) {
return fwrite((char*)buf_arg, 1, size, f);
}
if (buf_arg >= MEM_SIZE) {
return -1;
}
char temp_buf[8192];
if (size > 8192) size = 8192;
if (buf_arg + size > MEM_SIZE) {
size = MEM_SIZE - buf_arg;
}
for (int i = 0; i < size && buf_arg + i < MEM_SIZE; i++) {
temp_buf[i] = (char)memory[buf_arg + i];
}
return fwrite(temp_buf, 1, size, f);
}
long native_fgets(long *args, int argc) {
static char empty_str[] = "";
if (!args || argc < 2) {
return (long)empty_str;
}
FILE *f = (FILE*)args[0];
int max_size = (int)args[1];
if (!f || max_size <= 0) {
return (long)empty_str;
}
if (str_pool_idx >= STR_POOL_SIZE) {
error("String pool overflow");
return (long)empty_str;
}
char *result = &str_pool[str_pool_idx];
if (max_size > STR_POOL_SIZE - str_pool_idx) {
max_size = STR_POOL_SIZE - str_pool_idx;
}
if (fgets(result, max_size, f) == NULL) {
return (long)empty_str;
}
int len = strlen(result);
str_pool_idx += len + 1;
return (long)result;
}
long native_fputs(long *args, int argc) {
if (!args || argc < 2) {
return -1;
}
FILE *f = (FILE*)args[0];
char *str = (char*)args[1];
if (!f || !str) {
return -1;
}
return fputs(str, f);
}
long native_feof(long *args, int argc) {
if (!args || argc < 1) {
return 1;
}
FILE *f = (FILE*)args[0];
if (!f) {
return 1;
}
return feof(f);
}
long native_ftell(long *args, int argc) {
if (!args || argc < 1) {
return -1;
}
FILE *f = (FILE*)args[0];
if (!f) {
return -1;
}
return ftell(f);
}
long native_fseek(long *args, int argc) {
if (!args || argc < 3) {
return -1;
}
FILE *f = (FILE*)args[0];
long offset = args[1];
int whence = (int)args[2];
if (!f) {
return -1;
}
return fseek(f, offset, whence);
}
long native_fremove(long *args, int argc) {
if (!args || argc < 1) {
return -1;
}
char *filename = (char*)args[0];
if (!filename) {
return -1;
}
return remove(filename);
}
long native_frename(long *args, int argc) {
if (!args || argc < 2) {
return -1;
}
char *oldname = (char*)args[0];
char *newname = (char*)args[1];
if (!oldname || !newname) {
return -1;
}
return rename(oldname, newname);
}
long native_SEEK_SET(long *args, int argc) {
return SEEK_SET;
}
long native_SEEK_CUR(long *args, int argc) {
return SEEK_CUR;
}
long native_SEEK_END(long *args, int argc) {
return SEEK_END;
}
long native_int_to_double(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
union { double d; long l; } u;
u.d = (double)args[0];
return u.l;
}
long native_double_to_int(long *args, int argc) {
if (!args || argc < 1) {
return 0;
}
union { double d; long l; } u;
u.l = args[0];
return (long)u.d;
}
long native_double_add(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
union { double d; long l; } u1, u2, result;
u1.l = args[0];
u2.l = args[1];
result.d = u1.d + u2.d;
return result.l;
}
long native_double_sub(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
union { double d; long l; } u1, u2, result;
u1.l = args[0];
u2.l = args[1];
result.d = u1.d - u2.d;
return result.l;
}
long native_double_mul(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
union { double d; long l; } u1, u2, result;
u1.l = args[0];
u2.l = args[1];
result.d = u1.d * u2.d;
return result.l;
}
long native_double_div(long *args, int argc) {
if (!args || argc < 2) {
return 0;
}
union { double d; long l; } u1, u2, result;
u1.l = args[0];
u2.l = args[1];
if (u2.d != 0.0) {
result.d = u1.d / u2.d;
} else {
result.d = 0.0;
}
return result.l;
}
long native_async_fread(long *args, int argc) {
if (!args || argc < 3) return -1;
FILE *f = (FILE*)args[0];
int addr = (int)args[1];
int size = (int)args[2];
if (!f || addr < 0 || addr >= MEM_SIZE || size <= 0) return -1;
int id = alloc_async_op();
if (id < 0) return -1;
AsyncFileReadData *data = malloc(sizeof(AsyncFileReadData));
data->f = f;
data->addr = addr;
data->size = size;
async_ops[id].data = data;
int *id_ptr = malloc(sizeof(int));
*id_ptr = id;
pthread_create(&async_ops[id].thread, NULL, async_fread_thread, id_ptr);
return id;
}
long native_async_fwrite(long *args, int argc) {
if (!args || argc < 3) return -1;
FILE *f = (FILE*)args[0];
long buf_arg = args[1];
int size = (int)args[2];
if (!f || size <= 0) return -1;
int id = alloc_async_op();
if (id < 0) return -1;
AsyncFileWriteData *data = malloc(sizeof(AsyncFileWriteData));
data->f = f;
data->buf_arg = buf_arg;
data->size = size;
async_ops[id].data = data;
int *id_ptr = malloc(sizeof(int));
*id_ptr = id;
pthread_create(&async_ops[id].thread, NULL, async_fwrite_thread, id_ptr);
return id;
}
long native_async_recv(long *args, int argc) {
if (!args || argc < 4) return -1;
int sockfd = (int)args[0];
int addr = (int)args[1];
int len = (int)args[2];
int flags = (int)args[3];
if (addr < 0 || addr >= MEM_SIZE) return -1;
int id = alloc_async_op();
if (id < 0) return -1;
AsyncRecvData *data = malloc(sizeof(AsyncRecvData));
data->sockfd = sockfd;
data->addr = addr;
data->len = len;
data->flags = flags;
async_ops[id].data = data;
int *id_ptr = malloc(sizeof(int));
*id_ptr = id;
pthread_create(&async_ops[id].thread, NULL, async_recv_thread, id_ptr);
return id;
}
long native_async_send(long *args, int argc) {
if (!args || argc < 4) return -1;
int sockfd = (int)args[0];
long buf_arg = args[1];
int len = (int)args[2];
int flags = (int)args[3];
int id = alloc_async_op();
if (id < 0) return -1;
AsyncSendData *data = malloc(sizeof(AsyncSendData));
data->sockfd = sockfd;
data->buf_arg = buf_arg;
data->len = len;
data->flags = flags;
async_ops[id].data = data;
int *id_ptr = malloc(sizeof(int));
*id_ptr = id;
pthread_create(&async_ops[id].thread, NULL, async_send_thread, id_ptr);
return id;
}
long native_async_wait(long *args, int argc) {
if (!args || argc < 1) return -1;
int id = (int)args[0];
if (id < 0 || id >= MAX_ASYNC_OPS || !async_ops[id].active) return -1;
pthread_join(async_ops[id].thread, NULL);
pthread_mutex_lock(&async_mutex);
long result = async_ops[id].result;
async_ops[id].active = 0;
pthread_mutex_unlock(&async_mutex);
return result;
}
long native_async_poll(long *args, int argc) {
if (!args || argc < 1) return 0;
int id = (int)args[0];
if (id < 0 || id >= MAX_ASYNC_OPS || !async_ops[id].active) return 0;
pthread_mutex_lock(&async_mutex);
int complete = async_ops[id].complete;
pthread_mutex_unlock(&async_mutex);
return complete;
}
long native_async_result(long *args, int argc) {
if (!args || argc < 1) return -1;
int id = (int)args[0];
if (id < 0 || id >= MAX_ASYNC_OPS || !async_ops[id].active) return -1;
pthread_mutex_lock(&async_mutex);
long result = async_ops[id].result;
async_ops[id].active = 0;
pthread_mutex_unlock(&async_mutex);
return result;
}
void register_native_functions() { void register_native_functions() {
register_native_func("socket", native_socket); register_native_func("socket", native_socket);
register_native_func("bind", native_bind); register_native_func("bind", native_bind);
@ -475,4 +1062,31 @@ void register_native_functions() {
register_native_func("replace", native_replace); register_native_func("replace", native_replace);
register_native_func("startswith", native_startswith); register_native_func("startswith", native_startswith);
register_native_func("endswith", native_endswith); register_native_func("endswith", native_endswith);
register_native_func("fopen", native_fopen);
register_native_func("fclose", native_fclose);
register_native_func("fread", native_fread);
register_native_func("fwrite", native_fwrite);
register_native_func("fgets", native_fgets);
register_native_func("fputs", native_fputs);
register_native_func("feof", native_feof);
register_native_func("ftell", native_ftell);
register_native_func("fseek", native_fseek);
register_native_func("fremove", native_fremove);
register_native_func("frename", native_frename);
register_native_func("SEEK_SET", native_SEEK_SET);
register_native_func("SEEK_CUR", native_SEEK_CUR);
register_native_func("SEEK_END", native_SEEK_END);
register_native_func("int_to_double", native_int_to_double);
register_native_func("double_to_int", native_double_to_int);
register_native_func("double_add", native_double_add);
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("async_fread", native_async_fread);
register_native_func("async_fwrite", native_async_fwrite);
register_native_func("async_recv", native_async_recv);
register_native_func("async_send", native_async_send);
register_native_func("async_wait", native_async_wait);
register_native_func("async_poll", native_async_poll);
register_native_func("async_result", native_async_result);
} }

View File

@ -35,6 +35,12 @@ long factor() {
pc++; pc++;
return t->val; return t->val;
} }
else if (t->type == Dbl) {
pc++;
union { double d; long l; } u;
u.d = t->dval;
return u.l;
}
else if (t->type == Str) { else if (t->type == Str) {
pc++; pc++;
return (long)t->text; return (long)t->text;
@ -72,9 +78,9 @@ long factor() {
int f_idx = find_func(t->text, t->val); int f_idx = find_func(t->text, t->val);
if (f_idx == -1) error("Unknown function"); if (f_idx == -1) error("Unknown function");
if (f_idx < 0 || f_idx >= func_cnt) return 0; if (f_idx < 0 || f_idx >= func_cnt) return 0;
int call_pc = pc;
pc += 2; pc += 2;
int old_bp = bp;
long args[10]; long args[10];
int argc = 0; int argc = 0;
@ -89,25 +95,58 @@ long factor() {
match(')'); match(')');
int ret_pc = pc; int ret_pc = pc;
int old_loc_cnt = loc_cnt;
int old_bp = bp;
if (sp >= MEM_SIZE) return 0; if (sp >= MEM_SIZE) return 0;
if (bp < 0 || bp >= MEM_SIZE) return 0; if (bp < 0 || bp >= MEM_SIZE) return 0;
memory[sp] = bp; bp = sp++; memory[sp] = bp; bp = sp++;
if (sp >= MEM_SIZE) return 0; if (sp >= MEM_SIZE) return 0;
memory[sp++] = ret_pc; memory[sp++] = ret_pc;
memory[sp++] = old_loc_cnt;
int param_base = sp;
for(int i=0; i<argc; i++) { for(int i=0; i<argc; i++) {
if (sp >= MEM_SIZE) break; if (sp >= MEM_SIZE) break;
memory[sp++] = args[i]; memory[sp++] = args[i];
} }
int scan_pc = funcs[f_idx].params_start;
int param_idx = 0;
while (scan_pc < MAX_TOK && scan_pc < tk_idx && tokens[scan_pc].type != ')') {
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 && 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++;
}
pc = funcs[f_idx].entry_point; pc = funcs[f_idx].entry_point;
return_flag = 0;
statement(); statement();
val = ax; val = ax;
ax = 0;
return_flag = 0;
loc_cnt = old_loc_cnt;
if (bp < 0 || bp >= MEM_SIZE) return 0; if (bp < 0 || bp >= MEM_SIZE) return 0;
sp = bp; sp = bp;
if (sp < 0 || sp >= MEM_SIZE) return 0; if (sp < 0 || sp >= MEM_SIZE) return 0;
bp = memory[sp]; bp = memory[sp];
if (sp + 1 < MEM_SIZE) ret_pc = memory[sp + 1];
pc = ret_pc; pc = ret_pc;
return val; return val;
} }
@ -256,6 +295,26 @@ long relational() {
return val; return val;
} }
long logical_and() {
long val = relational();
while (pc < MAX_TOK && tokens[pc].type == And) {
pc++;
long val2 = relational();
val = val && val2;
}
return val;
}
long logical_or() {
long val = logical_and();
while (pc < MAX_TOK && tokens[pc].type == Or) {
pc++;
long val2 = logical_and();
val = val || val2;
}
return val;
}
long expression() { long expression() {
if (pc >= MAX_TOK) return 0; if (pc >= MAX_TOK) return 0;
if (tokens[pc].type == '*') { if (tokens[pc].type == '*') {
@ -327,5 +386,5 @@ long expression() {
} }
} }
return relational(); return logical_or();
} }

View File

@ -2,6 +2,8 @@
#define PARSER_H #define PARSER_H
long expression(); long expression();
long logical_or();
long logical_and();
long relational(); long relational();
long add(); long add();
long term(); long term();

247
src/preprocessor.c Normal file
View File

@ -0,0 +1,247 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <libgen.h>
#include <unistd.h>
#include <sys/stat.h>
#include "preprocessor.h"
static IncludedFile included_files[MAX_INCLUDED_FILES];
static int included_count = 0;
static int include_depth = 0;
static void normalize_path(const char *path, char *normalized) {
strncpy(normalized, path, 255);
normalized[255] = 0;
}
static int is_already_included(const char *path) {
char normalized[256];
normalize_path(path, normalized);
for (int i = 0; i < included_count; i++) {
if (strcmp(included_files[i].path, normalized) == 0) {
return 1;
}
}
return 0;
}
static void mark_as_included(const char *path) {
if (included_count >= MAX_INCLUDED_FILES) {
fprintf(stderr, "Error: Too many included files (max %d)\n", MAX_INCLUDED_FILES);
return;
}
char normalized[256];
normalize_path(path, normalized);
strncpy(included_files[included_count].path, normalized, 255);
included_files[included_count].path[255] = 0;
included_files[included_count].included = 1;
included_count++;
}
static char* read_file(const char *filename) {
FILE *f = fopen(filename, "rb");
if (!f) {
return NULL;
}
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
if (size <= 0 || size > MAX_PREPROCESSED_SIZE) {
fclose(f);
return NULL;
}
char *content = malloc(size + 1);
if (!content) {
fclose(f);
return NULL;
}
size_t read_size = fread(content, 1, size, f);
content[read_size] = 0;
fclose(f);
return content;
}
static void resolve_include_path(const char *current_dir, const char *include_file, char *resolved_path) {
if (include_file[0] == '/') {
strncpy(resolved_path, include_file, 511);
resolved_path[511] = 0;
return;
}
snprintf(resolved_path, 512, "%s/%s", current_dir, include_file);
}
static char* process_includes(const char *filename, const char *content, const char *current_dir);
static char* extract_include_filename(const char *line) {
const char *p = line;
while (*p && isspace(*p)) p++;
if (*p != '#') return NULL;
p++;
while (*p && isspace(*p)) p++;
if (strncmp(p, "include", 7) != 0) return NULL;
p += 7;
while (*p && isspace(*p)) p++;
if (*p != '"' && *p != '<') return NULL;
char quote = (*p == '"') ? '"' : '>';
p++;
static char filename[256];
int i = 0;
while (*p && *p != quote && i < 255) {
filename[i++] = *p++;
}
filename[i] = 0;
if (*p != quote) return NULL;
return filename;
}
static char* process_includes(const char *filename, const char *content, const char *current_dir) {
if (include_depth >= MAX_INCLUDE_DEPTH) {
fprintf(stderr, "Error: Include depth exceeded (max %d) in file: %s\n",
MAX_INCLUDE_DEPTH, filename);
exit(1);
}
include_depth++;
size_t result_size = MAX_PREPROCESSED_SIZE;
char *result = malloc(result_size);
if (!result) {
fprintf(stderr, "Error: Memory allocation failed\n");
exit(1);
}
result[0] = 0;
size_t result_len = 0;
const char *p = content;
char line[1024];
while (*p) {
int line_len = 0;
while (*p && *p != '\n' && line_len < 1023) {
line[line_len++] = *p++;
}
line[line_len] = 0;
if (*p == '\n') {
p++;
}
char *include_file = extract_include_filename(line);
if (include_file) {
char resolved_path[512];
resolve_include_path(current_dir, include_file, resolved_path);
if (is_already_included(resolved_path)) {
continue;
}
mark_as_included(resolved_path);
char *included_content = read_file(resolved_path);
if (!included_content) {
fprintf(stderr, "Error: Cannot open included file: %s\n", resolved_path);
fprintf(stderr, " Included from: %s\n", filename);
free(result);
exit(1);
}
char include_dir[512];
char temp_path[512];
strncpy(temp_path, resolved_path, 511);
temp_path[511] = 0;
char *dir = dirname(temp_path);
strncpy(include_dir, dir, 511);
include_dir[511] = 0;
char *processed = process_includes(resolved_path, included_content, include_dir);
free(included_content);
size_t processed_len = strlen(processed);
if (result_len + processed_len + 2 >= result_size) {
fprintf(stderr, "Error: Preprocessed output too large (max %d bytes)\n",
MAX_PREPROCESSED_SIZE);
free(processed);
free(result);
exit(1);
}
memcpy(result + result_len, processed, processed_len);
result_len += processed_len;
result[result_len++] = '\n';
result[result_len] = 0;
free(processed);
} else {
size_t line_total = line_len + 1;
if (result_len + line_total >= result_size) {
fprintf(stderr, "Error: Preprocessed output too large (max %d bytes)\n",
MAX_PREPROCESSED_SIZE);
free(result);
exit(1);
}
if (line_len > 0) {
memcpy(result + result_len, line, line_len);
result_len += line_len;
}
result[result_len++] = '\n';
result[result_len] = 0;
}
}
include_depth--;
return result;
}
char* preprocess(const char *filename, const char *source_dir) {
included_count = 0;
include_depth = 0;
memset(included_files, 0, sizeof(included_files));
mark_as_included(filename);
char *content = read_file(filename);
if (!content) {
fprintf(stderr, "Error: Cannot read file: %s\n", filename);
return NULL;
}
char dir_path[512];
if (source_dir) {
strncpy(dir_path, source_dir, 511);
dir_path[511] = 0;
} else {
char temp_path[512];
strncpy(temp_path, filename, 511);
temp_path[511] = 0;
char *dir = dirname(temp_path);
strncpy(dir_path, dir, 511);
dir_path[511] = 0;
}
char *result = process_includes(filename, content, dir_path);
free(content);
return result;
}

15
src/preprocessor.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef PREPROCESSOR_H
#define PREPROCESSOR_H
#define MAX_INCLUDE_DEPTH 32
#define MAX_INCLUDED_FILES 256
#define MAX_PREPROCESSED_SIZE 500000
typedef struct {
char path[256];
int included;
} IncludedFile;
char* preprocess(const char *filename, const char *source_dir);
#endif

View File

@ -34,11 +34,14 @@ void tokenize(char *src) {
if (!strcmp(buf, "int")) t->type = Int; if (!strcmp(buf, "int")) t->type = Int;
else if (!strcmp(buf, "char")) t->type = Char; else if (!strcmp(buf, "char")) t->type = Char;
else if (!strcmp(buf, "double")) t->type = Double;
else if (!strcmp(buf, "if")) t->type = If; else if (!strcmp(buf, "if")) t->type = If;
else if (!strcmp(buf, "else")) t->type = Else; else if (!strcmp(buf, "else")) t->type = Else;
else if (!strcmp(buf, "while")) t->type = While; else if (!strcmp(buf, "while")) t->type = While;
else if (!strcmp(buf, "return")) t->type = Return; else if (!strcmp(buf, "return")) t->type = Return;
else if (!strcmp(buf, "printf")) t->type = Printf; else if (!strcmp(buf, "printf")) t->type = Printf;
else if (!strcmp(buf, "break")) t->type = Break;
else if (!strcmp(buf, "continue")) t->type = Continue;
else t->type = Id; else t->type = Id;
t->val = len; t->val = len;
@ -46,9 +49,20 @@ void tokenize(char *src) {
continue; continue;
} }
if (isdigit(*s)) { if (isdigit(*s) || (*s == '.' && s[1] && isdigit(s[1]))) {
t->type = Num; char *start = s;
t->val = strtol(s, &s, 10); int has_dot = 0;
while (*s && (isdigit(*s) || (*s == '.' && !has_dot))) {
if (*s == '.') has_dot = 1;
s++;
}
if (has_dot) {
t->type = Dbl;
t->dval = strtod(start, NULL);
} else {
t->type = Num;
t->val = strtol(start, NULL, 10);
}
continue; continue;
} }

View File

@ -8,13 +8,14 @@
#define STR_POOL_SIZE 100000 #define STR_POOL_SIZE 100000
enum { enum {
Num = 128, Str, Id, Int, Char, Else, If, While, Return, Printf, Num = 128, Dbl, Str, Id, Int, Char, Double, Else, If, While, Return, Printf,
Assign, Eq, Ne, Lt, Gt, Le, Ge, Or, And, Inc, Dec Assign, Eq, Ne, Lt, Gt, Le, Ge, Or, And, Inc, Dec, Break, Continue
}; };
typedef struct { typedef struct {
int type; int type;
long val; long val;
double dval;
char *text; char *text;
} Token; } Token;
@ -29,6 +30,7 @@ typedef struct {
char name[32]; char name[32];
int entry_point; int entry_point;
int param_count; int param_count;
int params_start;
} Func; } Func;
typedef long (*NativeFunc)(long*, int); typedef long (*NativeFunc)(long*, int);
@ -54,5 +56,6 @@ extern char *src_code;
extern char str_pool[STR_POOL_SIZE]; extern char str_pool[STR_POOL_SIZE];
extern int str_pool_idx; extern int str_pool_idx;
extern long ax; extern long ax;
extern int return_flag;
#endif #endif

63
tests/array_test.rc Normal file
View File

@ -0,0 +1,63 @@
int main() {
printf("=== Array Tests ===\n");
printf("Test 1: Array declaration and initialization\n");
int arr[5];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;
printf("arr[0] = %d\n", arr[0]);
printf("arr[1] = %d\n", arr[1]);
printf("arr[2] = %d\n", arr[2]);
printf("arr[3] = %d\n", arr[3]);
printf("arr[4] = %d\n", arr[4]);
printf("PASS: Array indexing works\n");
printf("Test 2: Array modification\n");
arr[2] = 100;
printf("After arr[2] = 100: arr[2] = %d\n", arr[2]);
printf("PASS: Array element modification works\n");
printf("Test 3: Loop through array\n");
int i = 0;
int sum = 0;
while (i < 5) {
sum = sum + arr[i];
i = i + 1;
}
printf("Sum of array elements: %d\n", sum);
printf("PASS: Array iteration works\n");
printf("Test 4: Array with calculations\n");
int nums[3];
nums[0] = 5;
nums[1] = 10;
nums[2] = 15;
int total = 0;
total = total + nums[0];
total = total + nums[1];
total = total + nums[2];
printf("nums[0] + nums[1] + nums[2] = %d\n", total);
printf("PASS: Array arithmetic works\n");
printf("Test 5: Larger array\n");
int big[10];
int j = 0;
while (j < 10) {
big[j] = j * j;
j = j + 1;
}
printf("Squares (0-9): ");
int k = 0;
while (k < 10) {
printf("%d ", big[k]);
k = k + 1;
}
printf("\n");
printf("PASS: Larger arrays work\n");
printf("\n=== All Array Tests Completed ===\n");
return 0;
}

44
tests/async_io_test.rc Normal file
View File

@ -0,0 +1,44 @@
int main() {
printf("=== Async I/O Tests ===\n");
printf("Test 1: Async file write\n");
int f = fopen("async_test.txt", "w");
if (f == 0) {
printf("ERROR: Could not open file\n");
return 1;
}
int write_handle = async_fwrite(f, "Hello from async I/O!", 21);
printf("Write started, handle: %d\n", write_handle);
int result = async_wait(write_handle);
printf("Write completed, bytes written: %d\n", result);
fclose(f);
printf("PASS: Async write works\n");
printf("Test 2: Async file read\n");
f = fopen("async_test.txt", "r");
if (f == 0) {
printf("ERROR: Could not open file\n");
return 1;
}
int buffer[256];
int read_handle = async_fread(f, &buffer, 256);
printf("Read started, handle: %d\n", read_handle);
printf("Polling for completion...\n");
while (async_poll(read_handle) == 0) {
printf(".");
}
printf("\nRead complete!\n");
result = async_result(read_handle);
printf("Bytes read: %d\n", result);
fclose(f);
printf("PASS: Async read works\n");
printf("Test 3: Cleanup\n");
fremove("async_test.txt");
printf("PASS: File removed\n");
printf("\n=== All Async I/O Tests Completed ===\n");
return 0;
}

View File

@ -0,0 +1,81 @@
int main() {
printf("=== Break and Continue Tests ===\n");
printf("Test 1: Break statement\n");
int count = 0;
while (count < 10) {
count = count + 1;
if (count == 5) {
printf("Breaking at count = %d\n", count);
break;
}
printf("count = %d\n", count);
}
printf("Final count after break: %d\n", count);
printf("PASS: Break works\n");
printf("Test 2: Continue statement\n");
int i = 0;
int sum = 0;
while (i < 10) {
i = i + 1;
if (i == 3 || i == 7) {
printf("Skipping i = %d\n", i);
continue;
}
sum = sum + i;
printf("Adding i = %d, sum = %d\n", i, sum);
}
printf("Final sum (skipped 3 and 7): %d\n", sum);
printf("PASS: Continue works\n");
printf("Test 3: Break in nested if\n");
int j = 0;
while (j < 10) {
j = j + 1;
if (j > 3) {
if (j == 6) {
printf("Breaking at j = %d (nested if)\n", j);
break;
}
}
printf("j = %d\n", j);
}
printf("Final j: %d\n", j);
printf("PASS: Nested break works\n");
printf("Test 4: Continue in nested if\n");
int k = 0;
int even_sum = 0;
while (k < 10) {
k = k + 1;
if (k > 0) {
int rem = k - (k / 2) * 2;
if (rem == 1) {
continue;
}
}
even_sum = even_sum + k;
}
printf("Sum of even numbers 1-10: %d\n", even_sum);
printf("PASS: Nested continue works\n");
printf("Test 5: Multiple breaks and continues\n");
int n = 0;
int result = 0;
while (n < 20) {
n = n + 1;
if (n < 5) {
continue;
}
if (n > 15) {
break;
}
result = result + 1;
}
printf("Numbers counted between 5 and 15: %d\n", result);
printf("PASS: Multiple break/continue works\n");
printf("\n=== All Break/Continue Tests Completed ===\n");
return 0;
}

14
tests/break_test1.rc Normal file
View File

@ -0,0 +1,14 @@
int main() {
printf("=== Break Test ===\n");
int count = 0;
while (count < 10) {
count = count + 1;
if (count == 5) {
printf("Breaking at count = %d\n", count);
break;
}
printf("count = %d\n", count);
}
printf("Final count: %d\n", count);
return 0;
}

13
tests/break_test2.rc Normal file
View File

@ -0,0 +1,13 @@
int main() {
printf("=== Break Test ===\n");
int count = 0;
while (count < 10) {
count = count + 1;
if (count == 5) {
break;
}
printf("count = %d\n", count);
}
printf("Final count: %d\n", count);
return 0;
}

91
tests/comparison_test.rc Normal file
View File

@ -0,0 +1,91 @@
int main() {
printf("=== Comparison Operators Tests ===\n");
int a = 10;
int b = 20;
int c = 10;
printf("Test 1: Less than (<)\n");
if (a < b) {
printf("10 < 20 = true\n");
}
if (b < a) {
printf("20 < 10 = true (SHOULD NOT PRINT)\n");
} else {
printf("20 < 10 = false\n");
}
if (a < c) {
printf("10 < 10 = true (SHOULD NOT PRINT)\n");
} else {
printf("10 < 10 = false\n");
}
printf("PASS: Less than operator works\n");
printf("Test 2: Greater than (>)\n");
if (b > a) {
printf("20 > 10 = true\n");
}
if (a > b) {
printf("10 > 20 = true (SHOULD NOT PRINT)\n");
} else {
printf("10 > 20 = false\n");
}
if (a > c) {
printf("10 > 10 = true (SHOULD NOT PRINT)\n");
} else {
printf("10 > 10 = false\n");
}
printf("PASS: Greater than operator works\n");
printf("Test 3: Less than or equal (<=)\n");
if (a <= b) {
printf("10 <= 20 = true\n");
}
if (a <= c) {
printf("10 <= 10 = true\n");
}
if (b <= a) {
printf("20 <= 10 = true (SHOULD NOT PRINT)\n");
} else {
printf("20 <= 10 = false\n");
}
printf("PASS: Less than or equal operator works\n");
printf("Test 4: Greater than or equal (>=)\n");
if (b >= a) {
printf("20 >= 10 = true\n");
}
if (a >= c) {
printf("10 >= 10 = true\n");
}
if (a >= b) {
printf("10 >= 20 = true (SHOULD NOT PRINT)\n");
} else {
printf("10 >= 20 = false\n");
}
printf("PASS: Greater than or equal operator works\n");
printf("Test 5: Negative number comparisons\n");
int neg1 = -5;
int neg2 = -10;
if (neg1 > neg2) {
printf("-5 > -10 = true\n");
}
if (neg2 < neg1) {
printf("-10 < -5 = true\n");
}
if (neg1 < 0) {
printf("-5 < 0 = true\n");
}
printf("PASS: Negative number comparisons work\n");
printf("Test 6: Comparisons in expressions\n");
int result = a < b;
printf("result of (10 < 20) = %d\n", result);
int result2 = a > b;
printf("result of (10 > 20) = %d\n", result2);
printf("PASS: Comparisons as expressions work\n");
printf("\n=== All Comparison Operators Tests Completed ===\n");
return 0;
}

14
tests/continue_or_test.rc Normal file
View File

@ -0,0 +1,14 @@
int main() {
printf("Test OR with continue\n");
int i = 0;
while (i < 10) {
i = i + 1;
if (i == 3 || i == 7) {
printf("Skip %d\n", i);
continue;
}
printf("i = %d\n", i);
}
printf("Done\n");
return 0;
}

View File

@ -0,0 +1,14 @@
int main() {
printf("Start\n");
int i = 0;
while (i < 5) {
i = i + 1;
if (i == 3) {
printf("Skipping i = %d\n", i);
continue;
}
printf("i = %d\n", i);
}
printf("Done\n");
return 0;
}

53
tests/double_test.rc Normal file
View File

@ -0,0 +1,53 @@
int main() {
printf("=== Double Data Type Tests ===\n");
printf("Test 1: Double variable declaration and assignment\n");
double pi = 3.14159;
printf("pi = %f\n", pi);
printf("PASS: Double variable works\n");
printf("Test 2: Double arithmetic using helper functions\n");
double a = 10.5;
double b = 2.5;
printf("a = %f, b = %f\n", a, b);
double sum = double_add(a, b);
printf("a + b = %f\n", sum);
double diff = double_sub(a, b);
printf("a - b = %f\n", diff);
double prod = double_mul(a, b);
printf("a * b = %f\n", prod);
double quot = double_div(a, b);
printf("a / b = %f\n", quot);
printf("PASS: Double arithmetic works\n");
printf("Test 3: Type conversions\n");
int x = 42;
double dx = int_to_double(x);
printf("int %d converted to double: %f\n", x, dx);
double y = 99.9;
int iy = double_to_int(y);
printf("double %f converted to int: %d\n", y, iy);
printf("PASS: Type conversions work\n");
printf("Test 4: Double with mathematical functions\n");
double num = 16.0;
double sq = sqrt(double_to_int(num));
double sq_double = int_to_double(sq);
printf("sqrt(%f) = %f\n", num, sq_double);
printf("PASS: Math functions work with doubles\n");
printf("Test 5: Complex calculation\n");
double radius = 5.0;
double pi2 = 3.14159;
double area = double_mul(pi2, double_mul(radius, radius));
printf("Circle area (r=%f): %f\n", radius, area);
printf("PASS: Complex calculations work\n");
printf("\n=== All Double Tests Completed ===\n");
return 0;
}

82
tests/file_io_test.rc Normal file
View File

@ -0,0 +1,82 @@
int main() {
printf("=== File I/O Tests ===\n");
printf("Test 1: Writing to a file\n");
int f = fopen("test_output.txt", "w");
if (f == 0) {
printf("ERROR: Could not open file for writing\n");
return 1;
}
fputs(f, "Hello, File I/O!\n");
fputs(f, "This is line 2.\n");
fputs(f, "Testing file operations.\n");
fclose(f);
printf("PASS: File written successfully\n");
printf("Test 2: Reading from file using fgets\n");
f = fopen("test_output.txt", "r");
if (f == 0) {
printf("ERROR: Could not open file for reading\n");
return 1;
}
char *line1 = fgets(f, 256);
printf("Line 1: %s", line1);
char *line2 = fgets(f, 256);
printf("Line 2: %s", line2);
char *line3 = fgets(f, 256);
printf("Line 3: %s", line3);
fclose(f);
printf("PASS: File read successfully\n");
printf("Test 3: File position operations\n");
f = fopen("test_output.txt", "r");
if (f == 0) {
printf("ERROR: Could not open file\n");
return 1;
}
int pos = ftell(f);
printf("Initial position: %d\n", pos);
fseek(f, 7, SEEK_SET());
pos = ftell(f);
printf("Position after seek: %d\n", pos);
char *partial = fgets(f, 256);
printf("Read after seek: %s", partial);
fclose(f);
printf("PASS: File positioning works\n");
printf("Test 4: End of file detection\n");
f = fopen("test_output.txt", "r");
if (f == 0) {
printf("ERROR: Could not open file\n");
return 1;
}
int line_count = 0;
while (feof(f) == 0) {
char *line = fgets(f, 256);
if (strlen(line) > 0) {
line_count = line_count + 1;
}
}
printf("Total lines read: %d\n", line_count);
fclose(f);
printf("PASS: EOF detection works\n");
printf("Test 5: File rename operation\n");
int result = frename("test_output.txt", "test_renamed.txt");
if (result == 0) {
printf("PASS: File renamed successfully\n");
} else {
printf("ERROR: File rename failed\n");
}
printf("Test 6: File removal\n");
result = fremove("test_renamed.txt");
if (result == 0) {
printf("PASS: File removed successfully\n");
} else {
printf("ERROR: File removal failed\n");
}
printf("\n=== All File I/O Tests Completed ===\n");
return 0;
}

77
tests/file_seek_test.rc Normal file
View File

@ -0,0 +1,77 @@
int main() {
printf("=== File Seek Operations Tests ===\n");
printf("Test 1: Create test file\n");
int f = fopen("seek_test.txt", "w");
if (f == 0) {
printf("ERROR: Could not create file\n");
return 1;
}
fputs(f, "0123456789ABCDEFGHIJ");
fclose(f);
printf("PASS: File created with content\n");
printf("Test 2: ftell() - get current position\n");
f = fopen("seek_test.txt", "r");
int pos = ftell(f);
printf("Initial position: %d\n", pos);
char *line = fgets(f, 5);
printf("Read: '%s'\n", line);
pos = ftell(f);
printf("Position after reading 5 bytes: %d\n", pos);
fclose(f);
printf("PASS: ftell() works\n");
printf("Test 3: fseek() with SEEK_SET\n");
f = fopen("seek_test.txt", "r");
fseek(f, 10, SEEK_SET());
pos = ftell(f);
printf("Position after fseek(10, SEEK_SET): %d\n", pos);
line = fgets(f, 5);
printf("Read from position 10: '%s'\n", line);
fclose(f);
printf("PASS: fseek with SEEK_SET works\n");
printf("Test 4: fseek() with SEEK_CUR\n");
f = fopen("seek_test.txt", "r");
line = fgets(f, 5);
printf("First read: '%s'\n", line);
fseek(f, 3, SEEK_CUR());
pos = ftell(f);
printf("Position after fseek(3, SEEK_CUR): %d\n", pos);
line = fgets(f, 5);
printf("Read after seek: '%s'\n", line);
fclose(f);
printf("PASS: fseek with SEEK_CUR works\n");
printf("Test 5: fseek() with SEEK_END\n");
f = fopen("seek_test.txt", "r");
fseek(f, -5, SEEK_END());
pos = ftell(f);
printf("Position after fseek(-5, SEEK_END): %d\n", pos);
line = fgets(f, 10);
printf("Read from near end: '%s'\n", line);
fclose(f);
printf("PASS: fseek with SEEK_END works\n");
printf("Test 6: Random access pattern\n");
f = fopen("seek_test.txt", "r");
fseek(f, 5, SEEK_SET());
line = fgets(f, 3);
printf("Position 5: '%s'\n", line);
fseek(f, 0, SEEK_SET());
line = fgets(f, 3);
printf("Position 0: '%s'\n", line);
fseek(f, 15, SEEK_SET());
line = fgets(f, 3);
printf("Position 15: '%s'\n", line);
fclose(f);
printf("PASS: Random access works\n");
printf("Test 7: Cleanup\n");
fremove("seek_test.txt");
printf("PASS: File removed\n");
printf("\n=== All File Seek Tests Completed ===\n");
return 0;
}

45
tests/functions_test.rc Normal file
View File

@ -0,0 +1,45 @@
int getValue() {
return 42;
}
int add(int a, int b) {
return a + b;
}
int square(int x) {
int result = x * x;
return result;
}
int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}
int main() {
printf("=== Functions Tests ===\n");
printf("Testing no-parameter functions...\n");
int val = getValue();
printf("getValue() = %d\n", val);
printf("Testing two-parameter functions...\n");
int sum = add(5, 3);
printf("add(5, 3) = %d\n", sum);
printf("Testing functions with local variables...\n");
int sq = square(7);
printf("square(7) = %d\n", sq);
printf("Testing conditional functions...\n");
int m1 = max(15, 20);
printf("max(15, 20) = %d\n", m1);
printf("Testing nested function calls...\n");
int nested = add(square(3), getValue());
printf("add(square(3), getValue()) = %d\n", nested);
printf("\n=== All Tests Completed ===\n");
return 0;
}

27
tests/include_test.rc Normal file
View File

@ -0,0 +1,27 @@
#include "includes/math_lib.rc"
int main() {
printf("=== Include Directive Tests ===\n");
printf("Test 1: Basic include\n");
int sum = add(10, 5);
printf("add(10, 5) = %d\n", sum);
printf("PASS: Included function works\n");
printf("Test 2: Multiple functions from include\n");
int diff = subtract(20, 7);
printf("subtract(20, 7) = %d\n", diff);
int prod = multiply(6, 4);
printf("multiply(6, 4) = %d\n", prod);
int quot = divide(15, 3);
printf("divide(15, 3) = %d\n", quot);
printf("PASS: All included functions work\n");
printf("Test 3: Using included functions in expressions\n");
int result = add(multiply(3, 4), subtract(10, 5));
printf("add(multiply(3, 4), subtract(10, 5)) = %d\n", result);
printf("PASS: Included functions in expressions work\n");
printf("\n=== All Include Tests Completed ===\n");
return 0;
}

View File

@ -0,0 +1,18 @@
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int multiply(int a, int b) {
return a * b;
}
int divide(int a, int b) {
if (b == 0) {
return 0;
}
return a / b;
}

View File

@ -0,0 +1,19 @@
int string_length(char *s) {
return strlen(s);
}
char* string_upper(char *s) {
return upper(s);
}
char* string_lower(char *s) {
return lower(s);
}
int string_contains(char *haystack, char *needle) {
int pos = strpos(haystack, needle);
if (pos >= 0) {
return 1;
}
return 0;
}

14
tests/includes/utils.rc Normal file
View File

@ -0,0 +1,14 @@
#include "math_lib.rc"
#include "string_lib.rc"
int is_even(int n) {
int half = divide(n, 2);
return multiply(half, 2) == n;
}
int is_odd(int n) {
if (is_even(n)) {
return 0;
}
return 1;
}

84
tests/logical_test.rc Normal file
View File

@ -0,0 +1,84 @@
int main() {
printf("=== Logical Operators Tests ===\n");
printf("Test 1: AND operator (&&)\n");
int a = 1;
int b = 1;
if (a && b) {
printf("1 && 1 = true\n");
}
int c = 1;
int d = 0;
if (c && d) {
printf("1 && 0 = true (SHOULD NOT PRINT)\n");
} else {
printf("1 && 0 = false\n");
}
int e = 0;
int f = 0;
if (e && f) {
printf("0 && 0 = true (SHOULD NOT PRINT)\n");
} else {
printf("0 && 0 = false\n");
}
printf("PASS: AND operator works\n");
printf("Test 2: OR operator (||)\n");
if (a || b) {
printf("1 || 1 = true\n");
}
if (c || d) {
printf("1 || 0 = true\n");
}
if (e || f) {
printf("0 || 0 = true (SHOULD NOT PRINT)\n");
} else {
printf("0 || 0 = false\n");
}
printf("PASS: OR operator works\n");
printf("Test 3: Combined logical operations\n");
int x = 5;
int y = 10;
int z = 15;
if (x < y && y < z) {
printf("5 < 10 && 10 < 15 = true\n");
}
if (x > y || y < z) {
printf("5 > 10 || 10 < 15 = true\n");
}
if (x > y && y > z) {
printf("5 > 10 && 10 > 15 = true (SHOULD NOT PRINT)\n");
} else {
printf("5 > 10 && 10 > 15 = false\n");
}
printf("PASS: Combined logical operations work\n");
printf("Test 4: Logical operators in while loops\n");
int i = 0;
int j = 10;
while (i < 5 && j > 5) {
i = i + 1;
j = j - 1;
}
printf("After loop with &&: i = %d, j = %d\n", i, j);
printf("PASS: Logical operators in loops work\n");
printf("Test 5: Complex conditions\n");
int age = 25;
int hasLicense = 1;
int hasInsurance = 1;
if ((age >= 18 && hasLicense) && hasInsurance) {
printf("Can drive: age >= 18, has license and insurance\n");
}
int temp = 30;
if (temp < 0 || temp > 35) {
printf("Extreme temperature (SHOULD NOT PRINT)\n");
} else {
printf("Normal temperature range\n");
}
printf("PASS: Complex conditions work\n");
printf("\n=== All Logical Operators Tests Completed ===\n");
return 0;
}

View File

@ -0,0 +1,22 @@
#include "includes/utils.rc"
int main() {
printf("=== Nested Include Tests ===\n");
printf("Test 1: Functions from nested includes\n");
int sum = add(5, 3);
printf("add(5, 3) = %d\n", sum);
printf("PASS: Functions from first-level include work\n");
printf("Test 2: Utility functions using nested includes\n");
if (is_even(10)) {
printf("is_even(10) = true\n");
}
if (is_odd(7)) {
printf("is_odd(7) = true\n");
}
printf("PASS: Utility functions using nested includes work\n");
printf("\n=== All Nested Include Tests Completed ===\n");
return 0;
}

9
tests/or_test.rc Normal file
View File

@ -0,0 +1,9 @@
int main() {
printf("Test OR\n");
int i = 3;
if (i == 3 || i == 7) {
printf("Match\n");
}
printf("Done\n");
return 0;
}

49
tests/pointer_test.rc Normal file
View File

@ -0,0 +1,49 @@
int main() {
printf("=== Pointer Tests ===\n");
printf("Test 1: Address-of operator (&)\n");
int x = 42;
int addr = &x;
printf("x = %d\n", x);
printf("&x = %d\n", addr);
printf("PASS: Address-of operator works\n");
printf("Test 2: Dereference operator (*)\n");
int y = 100;
int *ptr = &y;
int val = *ptr;
printf("y = %d\n", y);
printf("*ptr = %d\n", val);
printf("PASS: Dereference operator works\n");
printf("Test 3: Modify through pointer\n");
int z = 50;
int *p = &z;
*p = 75;
printf("After *p = 75, z = %d\n", z);
printf("PASS: Pointer modification works\n");
printf("Test 4: Multiple pointers\n");
int a = 10;
int b = 20;
int *pa = &a;
int *pb = &b;
printf("a = %d, b = %d\n", a, b);
printf("*pa = %d, *pb = %d\n", *pa, *pb);
int sum = *pa + *pb;
printf("*pa + *pb = %d\n", sum);
printf("PASS: Multiple pointers work\n");
printf("Test 5: Pointer with arrays\n");
int arr[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
printf("arr[0] = %d, arr[1] = %d, arr[2] = %d\n", arr[0], arr[1], arr[2]);
int *arrptr = &arr;
printf("Array base address: %d\n", arrptr);
printf("PASS: Pointers with arrays work\n");
printf("\n=== All Pointer Tests Completed ===\n");
return 0;
}

View File

@ -0,0 +1,13 @@
int main() {
printf("Start\n");
int i = 0;
while (i < 5) {
i = i + 1;
printf("i = %d\n", i);
if (i == 3) {
break;
}
}
printf("After loop, i = %d\n", i);
return 0;
}

49
tests/trig_test.rc Normal file
View File

@ -0,0 +1,49 @@
int main() {
printf("=== Trigonometric Functions Tests ===\n");
printf("Note: Results are scaled by 1,000,000\n");
printf("Test 1: sin() function\n");
int sin0 = sin(0);
printf("sin(0) * 1000000 = %d\n", sin0);
int sin1 = sin(1);
printf("sin(1) * 1000000 = %d\n", sin1);
int sin2 = sin(2);
printf("sin(2) * 1000000 = %d\n", sin2);
printf("PASS: sin() function works\n");
printf("Test 2: cos() function\n");
int cos0 = cos(0);
printf("cos(0) * 1000000 = %d\n", cos0);
int cos1 = cos(1);
printf("cos(1) * 1000000 = %d\n", cos1);
int cos2 = cos(2);
printf("cos(2) * 1000000 = %d\n", cos2);
printf("PASS: cos() function works\n");
printf("Test 3: tan() function\n");
int tan0 = tan(0);
printf("tan(0) * 1000000 = %d\n", tan0);
int tan1 = tan(1);
printf("tan(1) * 1000000 = %d\n", tan1);
printf("PASS: tan() function works\n");
printf("Test 4: Multiple angles\n");
int i = 0;
while (i < 4) {
int s = sin(i);
int c = cos(i);
printf("Angle %d: sin = %d, cos = %d\n", i, s, c);
i = i + 1;
}
printf("PASS: Multiple angle calculations work\n");
printf("Test 5: Trig with negative values\n");
int sinNeg = sin(-1);
printf("sin(-1) * 1000000 = %d\n", sinNeg);
int cosNeg = cos(-1);
printf("cos(-1) * 1000000 = %d\n", cosNeg);
printf("PASS: Negative angle calculations work\n");
printf("\n=== All Trigonometric Tests Completed ===\n");
return 0;
}