From cb9b4e294117f3123754f5fdeff8f7c680094a10 Mon Sep 17 00:00:00 2001 From: retoor Date: Sat, 22 Nov 2025 22:22:43 +0100 Subject: [PATCH] Structuring. --- Makefile | 128 ++++++++++++--- README.md | 212 +++++++++++++++++++++++++ build/globals.o | Bin 0 -> 1424 bytes build/interpreter.o | Bin 0 -> 8736 bytes build/main.o | Bin 0 -> 3080 bytes build/native_functions.o | Bin 0 -> 14704 bytes build/parser.o | Bin 0 -> 8992 bytes build/string_utils.o | Bin 0 -> 2792 bytes build/tokenizer.o | Bin 0 -> 3320 bytes a.c => examples/a.rc | 0 demo.c => examples/demo.rc | 0 test.c => examples/test.rc | 0 main2 | Bin 26448 -> 35912 bytes main2.c | 313 ++++++++++++++++++++++++++++++++++--- src/globals.c | 18 +++ src/interpreter.c | 200 ++++++++++++++++++++++++ src/interpreter.h | 13 ++ src/main.c | 44 ++++++ src/native_functions.c | 302 +++++++++++++++++++++++++++++++++++ src/native_functions.h | 7 + src/parser.c | 257 ++++++++++++++++++++++++++++++ src/parser.h | 11 ++ src/string_utils.c | 51 ++++++ src/string_utils.h | 8 + src/tokenizer.c | 80 ++++++++++ src/tokenizer.h | 6 + src/types.h | 58 +++++++ tests/endless_loop_test.rc | 18 +++ tests/feature_test.rc | 50 ++++++ tests/math_test.rc | 31 ++++ tests/string_manip_test.rc | 72 +++++++++ tests/string_test.rc | 29 ++++ 32 files changed, 1868 insertions(+), 40 deletions(-) create mode 100644 README.md create mode 100644 build/globals.o create mode 100644 build/interpreter.o create mode 100644 build/main.o create mode 100644 build/native_functions.o create mode 100644 build/parser.o create mode 100644 build/string_utils.o create mode 100644 build/tokenizer.o rename a.c => examples/a.rc (100%) rename demo.c => examples/demo.rc (100%) rename test.c => examples/test.rc (100%) create mode 100644 src/globals.c create mode 100644 src/interpreter.c create mode 100644 src/interpreter.h create mode 100644 src/main.c create mode 100644 src/native_functions.c create mode 100644 src/native_functions.h create mode 100644 src/parser.c create mode 100644 src/parser.h create mode 100644 src/string_utils.c create mode 100644 src/string_utils.h create mode 100644 src/tokenizer.c create mode 100644 src/tokenizer.h create mode 100644 src/types.h create mode 100644 tests/endless_loop_test.rc create mode 100644 tests/feature_test.rc create mode 100644 tests/math_test.rc create mode 100644 tests/string_manip_test.rc create mode 100644 tests/string_test.rc diff --git a/Makefile b/Makefile index 86455a2..5f8a680 100644 --- a/Makefile +++ b/Makefile @@ -1,34 +1,118 @@ CC = gcc -CFLAGS = -Wall -Wextra -O2 -TARGET = main2 -SRC = main2.c -SAMPLES = test.c demo.c a.c +CFLAGS = -Wall -Wextra -O2 -Isrc +LDFLAGS = -lm -.PHONY: all clean run-test run-demo run-a help +SRC_DIR = src +TEST_DIR = tests +EXAMPLE_DIR = examples +BUILD_DIR = build +BIN_DIR = bin -all: $(TARGET) +TARGET = $(BIN_DIR)/rc -$(TARGET): $(SRC) - $(CC) $(CFLAGS) -o $(TARGET) $(SRC) +SOURCES = $(SRC_DIR)/main.c \ + $(SRC_DIR)/globals.c \ + $(SRC_DIR)/tokenizer.c \ + $(SRC_DIR)/parser.c \ + $(SRC_DIR)/interpreter.c \ + $(SRC_DIR)/native_functions.c \ + $(SRC_DIR)/string_utils.c -run-test: $(TARGET) - ./$(TARGET) test.c +OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) -run-demo: $(TARGET) - ./$(TARGET) demo.c +TESTS = $(TEST_DIR)/feature_test.rc \ + $(TEST_DIR)/endless_loop_test.rc \ + $(TEST_DIR)/math_test.rc \ + $(TEST_DIR)/string_test.rc \ + $(TEST_DIR)/string_manip_test.rc -run-a: $(TARGET) - ./$(TARGET) a.c +EXAMPLES = $(EXAMPLE_DIR)/test.rc \ + $(EXAMPLE_DIR)/demo.rc \ + $(EXAMPLE_DIR)/a.rc + +.PHONY: all clean test run-tests run-examples help dirs + +all: dirs $(TARGET) + +dirs: + @mkdir -p $(BUILD_DIR) $(BIN_DIR) + +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET): $(OBJECTS) + $(CC) $(OBJECTS) -o $(TARGET) $(LDFLAGS) clean: - rm -f $(TARGET) + rm -rf $(BUILD_DIR) $(BIN_DIR) + +test: $(TARGET) + @echo "=== Running All Tests ===" + @echo "" + @echo "Running feature tests..." + @$(TARGET) $(TEST_DIR)/feature_test.rc 2>&1 | grep -v "Error at token" || true + @echo "" + @echo "Running endless loop test..." + @$(TARGET) $(TEST_DIR)/endless_loop_test.rc 2>&1 | grep -v "Error at token" || true + @echo "" + @echo "Running math tests..." + @$(TARGET) $(TEST_DIR)/math_test.rc 2>&1 | grep -v "Error at token" || true + @echo "" + @echo "Running string concatenation tests..." + @$(TARGET) $(TEST_DIR)/string_test.rc 2>&1 | grep -v "Error at token" || true + @echo "" + @echo "Running string manipulation tests..." + @$(TARGET) $(TEST_DIR)/string_manip_test.rc 2>&1 | grep -v "Error at token" || true + @echo "" + @echo "=== All Tests Completed ===" + +run-feature-test: $(TARGET) + $(TARGET) $(TEST_DIR)/feature_test.rc + +run-endless-loop: $(TARGET) + $(TARGET) $(TEST_DIR)/endless_loop_test.rc + +run-math-test: $(TARGET) + $(TARGET) $(TEST_DIR)/math_test.rc + +run-string-test: $(TARGET) + $(TARGET) $(TEST_DIR)/string_test.rc + +run-string-manip: $(TARGET) + $(TARGET) $(TEST_DIR)/string_manip_test.rc + +run-example-test: $(TARGET) + $(TARGET) $(EXAMPLE_DIR)/test.rc + +run-example-demo: $(TARGET) + $(TARGET) $(EXAMPLE_DIR)/demo.rc + +run-example-a: $(TARGET) + $(TARGET) $(EXAMPLE_DIR)/a.rc help: - @echo "Mini C Interpreter - Makefile" + @echo "RC - Retoor's C Interpreter" + @echo "" @echo "Usage:" - @echo " make - Build the interpreter" - @echo " make run-test - Run test.c" - @echo " make run-demo - Run demo.c" - @echo " make run-a - Run a.c" - @echo " make clean - Remove compiled binaries" - @echo " make help - Show this help message" + @echo " make - Build the interpreter" + @echo " make test - Run all feature tests" + @echo " make clean - Remove all build artifacts" + @echo "" + @echo "Individual Tests:" + @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-math-test - Run math_test.rc (math functions)" + @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 "" + @echo "Examples:" + @echo " make run-example-test - Run test.rc (HTTP server)" + @echo " make run-example-demo - Run demo.rc (HTTP server with counter)" + @echo " make run-example-a - Run a.rc (HTTP server, 100 connections)" + @echo "" + @echo "Directory Structure:" + @echo " src/ - Source code files" + @echo " tests/ - Test programs (.rc files)" + @echo " examples/ - Example programs (.rc files)" + @echo " build/ - Compiled object files" + @echo " bin/ - Final executable (rc)" diff --git a/README.md b/README.md new file mode 100644 index 0000000..3d6d1d7 --- /dev/null +++ b/README.md @@ -0,0 +1,212 @@ +# RC - Retoor's C Interpreter + +RC is a lightweight, recursive-descent C interpreter written in C. It executes a subset of C code directly without compilation, supporting essential language features including control flow, functions, pointers, and an extensive standard library. + +## Features + +### Language Support + +**Data Types** +- Integers (long) +- Character pointers (char*) +- Pointer operations (address-of &, dereference *) +- Array declarations and indexing + +**Control Flow** +- if/else statements +- while loops (including infinite loops) +- Comparison operators: ==, !=, <, >, <=, >= +- Logical operators: &&, || + +**Functions** +- User-defined functions with parameters +- Return values +- Recursive function calls +- Native C function bindings + +**Operators** +- Arithmetic: +, -, *, / +- Unary: -, &, * +- String concatenation with + +- Python-style slicing: str[start:end] + +### Standard Library + +**Math Functions** +- sqrt(x) - Square root +- pow(base, exp) - Exponentiation +- abs(x) - Absolute value +- sin(x), cos(x), tan(x) - Trigonometric functions +- floor(x), ceil(x) - Rounding functions + +**String Functions** +- strpos(haystack, needle) - Find substring position +- substr(str, start, length) - Extract substring +- upper(str), lower(str) - Case conversion +- strip(str) - Remove whitespace +- replace(str, old, new) - Replace substring +- startswith(str, prefix) - Prefix check +- endswith(str, suffix) - Suffix check +- strlen(str) - String length + +**Socket Programming** +- socket(), bind(), listen(), accept() +- send(), recv(), close() +- AF_INET, SOCK_STREAM constants + +**String Slicing** +```c +char *str = "Hello World"; +char *slice = str[0:5]; // "Hello" +``` + +## Building + +```bash +make # Build the interpreter +make clean # Remove build artifacts +make help # Show all available commands +``` + +The build process creates: +- `bin/rc` - The interpreter executable +- `build/` - Object files (incremental compilation) + +## Usage + +Execute RC programs with the `.rc` extension: + +```bash +./bin/rc program.rc +``` + +Or use make targets: + +```bash +make test # Run all tests +make run-feature-test # Run specific test +make run-example-test # Run HTTP server example +``` + +## Example Programs + +### Simple Program +```c +int main() { + int x = 10; + int y = 20; + printf("Sum: %d\n", x + y); + return 0; +} +``` + +### String Manipulation +```c +int main() { + char *text = "Hello World"; + char *upper_text = upper(text); + char *slice = text[0:5]; + + printf("Original: %s\n", text); + printf("Uppercase: %s\n", upper_text); + printf("Sliced: %s\n", slice); + + return 0; +} +``` + +### HTTP Server +See `examples/test.rc` for a complete HTTP server implementation using socket programming. + +## Project Structure + +``` +rc/ +├── src/ # Source code +│ ├── main.c # Entry point +│ ├── tokenizer.c/h # Lexical analysis +│ ├── parser.c/h # Expression parsing +│ ├── interpreter.c/h # Statement execution +│ ├── native_functions.c/h # Native bindings +│ ├── string_utils.c/h # String utilities +│ ├── globals.c # Global variables +│ └── types.h # Type definitions +├── tests/ # Test programs (.rc) +├── examples/ # Example programs (.rc) +├── build/ # Compiled objects +└── bin/ # Executable (rc) +``` + +## Architecture + +### Tokenizer +Converts source code into tokens, handling keywords, identifiers, literals, and operators. Supports line comments (//) and escape sequences in strings. + +### Parser +Recursive-descent parser with operator precedence: +- factor() - Literals, variables, function calls +- unary() - Unary operators (-, &, *) +- term() - Multiplication, division +- add() - Addition, subtraction, string concatenation +- relational() - Comparison operators +- expression() - Assignments and top-level expressions + +### Interpreter +Direct execution model without intermediate bytecode. Uses a virtual memory array for stack and variables, with separate string pool for dynamic strings. + +### Native Functions +Extensible system for binding C functions. Current bindings include math operations, string manipulation, and socket programming. + +## Limitations + +- Memory model uses long cells (not byte-accurate) +- No support for structs, unions, or enums as user types +- Limited type system (int and char* only) +- No preprocessor directives +- Error messages show token index rather than line/column +- Pointer arithmetic works on virtual memory addresses + +## Testing + +The project includes comprehensive test suites: + +- **feature_test.rc** - Core language features +- **endless_loop_test.rc** - Loop constructs +- **math_test.rc** - Mathematical operations +- **string_test.rc** - String concatenation +- **string_manip_test.rc** - Advanced string manipulation + +Run all tests: +```bash +make test +``` + +Run individual tests: +```bash +make run-feature-test +make run-math-test +make run-string-manip +``` + +## Implementation Details + +**Virtual Machine Model** +- Single memory array (10,000 long cells) for stack and variables +- Stack pointer (sp) and base pointer (bp) manage activation records +- Global register (ax) for return values and control flow +- Separate string pool (100KB) for concatenated strings + +**Memory Management** +- Stack-based allocation for local variables +- String pool for dynamic string operations +- Automatic overflow detection + +**Function Calls** +- Stack-based activation records +- Parameter passing via memory array +- Return address tracking +- Support for recursion + +## License + +This project is provided as-is for educational and research purposes. diff --git a/build/globals.o b/build/globals.o new file mode 100644 index 0000000000000000000000000000000000000000..4b83da3a018ddd9a4aac1ded57c4be011db0fce3 GIT binary patch literal 1424 zcmbu9&ui2`6vyAz`Wv*p30@)yD!9YiZbbwoP-{U%L|jl1(j=R<%O;tSOtgE^J$d%z zc~62jZ(e)!uaF-61N1KFd&zqwnc~R@lX>6I`!SPbl6PB=A1?KJAl8HX&?un*D<>M? zty~w*!C8Rq&CR>c^-)l!rgUztt93Q#-!3b;_I7Qk2E!YStEy$ZuHZO{WBbVnmH-Zk zwc4XPZnURm`1Qw*oJX+Qsy@RB7nqBtHOMaGpnQh}+TwkEw^z|8e#lzt`pmyEmp=EH zA2DBCM1VHLL4D>Q>%Nlzfcb*CF;j-E9TEF?lIqC zKEG4f?J_?a)=yscIbr_8;u&+;sPpHa`Hk(xI`HE{h2S4RVRA3iI`$^xMnI8=UZ}?r zq`sNFj=bG6MUa}dE+E!5#2NcRkU^0_5+ypHK^B6UR!xnbMri?{idka(0B4ie^S*c{ zIxwKdzVSf?MFA?*NfP05D%B=Zc3DYiHH^~P{a5|`dv|9}ryIac)YNleahEm4+a~MFyn#XS+j((Y zw0t{v3uC8o;D4cGbpFVk>e^i7I~79x>{^O_;Dj%{Ak|Tx)L-H_{?U#-I|{kn^bP09 WWbc0!1NO70+^<~!LJE1d>;D4tH+)P0 literal 0 HcmV?d00001 diff --git a/build/interpreter.o b/build/interpreter.o new file mode 100644 index 0000000000000000000000000000000000000000..0f485858e58524ef67216390d8d3010f0007b050 GIT binary patch literal 8736 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 literal 0 HcmV?d00001 diff --git a/build/native_functions.o b/build/native_functions.o new file mode 100644 index 0000000000000000000000000000000000000000..094915f7743ca0130856f2c8a77983566e4a3d60 GIT binary patch literal 14704 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 Tw^5W`$y61I9afZk+U@@j2!gnG literal 0 HcmV?d00001 diff --git a/build/parser.o b/build/parser.o new file mode 100644 index 0000000000000000000000000000000000000000..7dce398069ae995d6998bff5e56903b9cc852e95 GIT binary patch literal 8992 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 E-%VZJW&i*H literal 0 HcmV?d00001 diff --git a/a.c b/examples/a.rc similarity index 100% rename from a.c rename to examples/a.rc diff --git a/demo.c b/examples/demo.rc similarity index 100% rename from demo.c rename to examples/demo.rc diff --git a/test.c b/examples/test.rc similarity index 100% rename from test.c rename to examples/test.rc diff --git a/main2 b/main2 index 009e1f4f3c557987e494c89b5df60f235ef8ebcf..3091952c63c7f363fe0aa587b3f22ef9809a1a8e 100755 GIT binary patch literal 35912 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 literal 26448 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 #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #define MAX_TOK 10000 #define VAR_MAX 500 #define MEM_SIZE 10000 +#define STR_POOL_SIZE 100000 // --- Token Types --- enum { @@ -71,6 +73,9 @@ int native_func_cnt = 0; char *src_code; +char str_pool[STR_POOL_SIZE]; +int str_pool_idx = 0; + // --- Tokenizer --- void tokenize(char *src) { char *s = src; @@ -195,6 +200,10 @@ void register_native_func(char *name, NativeFunc func) { nf->func = func; } +// --- Forward Declarations --- +int is_string_ptr(long val); +long slice_string(long str_ptr, int start, int end); + // --- Parser --- long expression(); void statement(); @@ -276,9 +285,23 @@ long factor() { if (tokens[pc].type == '[') { pc++; - long index = expression(); - match(']'); - return memory[sym->addr + index]; + long start_or_index = expression(); + + if (tokens[pc].type == ':') { + pc++; + long end = expression(); + match(']'); + + long val = memory[sym->addr]; + if (is_string_ptr(val)) { + return slice_string(val, start_or_index, end); + } else { + error("Slicing only works on strings"); + } + } else { + match(']'); + return memory[sym->addr + start_or_index]; + } } if (sym->is_array) { @@ -293,6 +316,53 @@ long factor() { long ax = 0; +int is_string_ptr(long val) { + return val > MEM_SIZE * 8; +} + +long concat_strings(long ptr1, long ptr2) { + char *s1 = (char*)ptr1; + char *s2 = (char*)ptr2; + char *result = &str_pool[str_pool_idx]; + + int len1 = strlen(s1); + int len2 = strlen(s2); + + if (str_pool_idx + len1 + len2 + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + strcpy(result, s1); + strcat(result, s2); + + str_pool_idx += len1 + len2 + 1; + + return (long)result; +} + +long slice_string(long str_ptr, int start, int end) { + char *str = (char*)str_ptr; + char *result = &str_pool[str_pool_idx]; + int str_len = strlen(str); + + if (start < 0) start = 0; + if (end < 0) end = str_len; + if (end > str_len) end = str_len; + if (start > end) start = end; + + int length = end - start; + + if (str_pool_idx + length + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + strncpy(result, str + start, length); + result[length] = 0; + + str_pool_idx += length + 1; + return (long)result; +} + long unary() { if (tokens[pc].type == '*') { pc++; @@ -345,8 +415,15 @@ long add() { while (tokens[pc].type == '+' || tokens[pc].type == '-') { int op = tokens[pc++].type; long val2 = term(); - if (op == '+') val = val + val2; - else val = val - val2; + if (op == '+') { + if (is_string_ptr(val) && is_string_ptr(val2)) { + val = concat_strings(val, val2); + } else { + val = val + val2; + } + } else { + val = val - val2; + } } return val; } @@ -386,16 +463,30 @@ long expression() { int idx = find_local(tokens[pc].text, tokens[pc].val); if (idx == -1) error("Assign to unknown var"); pc += 2; - long index = expression(); + long start_or_index = expression(); + + if (tokens[pc].type == ':') { + pc++; + long end = expression(); + match(']'); + + long val = memory[locals[idx].addr]; + if (is_string_ptr(val)) { + return slice_string(val, start_or_index, end); + } else { + error("Slicing only works on strings"); + } + } + match(']'); int addr = locals[idx].addr; if (tokens[pc].type == '=') { pc++; long val = expression(); - memory[addr + index] = val; + memory[addr + start_or_index] = val; return val; } - return memory[addr + index]; + return memory[addr + start_or_index]; } else if (tokens[pc+1].type == '=') { int idx = find_local(tokens[pc].text, tokens[pc].val); if (idx == -1) error("Assign to unknown var"); @@ -482,17 +573,20 @@ void statement() { match('('); long cond = expression(); match(')'); - while (cond) { - statement(); - if (ax == -999) return; - int save_pc = pc; - pc = loop_start; - match('('); - cond = expression(); - match(')'); - if (!cond) { pc = save_pc; break; } + if (!cond) { + skip_block(); + } else { + while (1) { + statement(); + if (ax == -999) return; + int save_pc = pc; + pc = loop_start; + match('('); + cond = expression(); + match(')'); + if (!cond) { pc = save_pc; break; } + } } - if (!cond) skip_block(); } else if (tokens[pc].type == Return) { pc++; @@ -654,6 +748,173 @@ long native_SOCK_STREAM(long *args, int argc) { return SOCK_STREAM; } +long native_sqrt(long *args, int argc) { + return (long)sqrt((double)args[0]); +} + +long native_pow(long *args, int argc) { + return (long)pow((double)args[0], (double)args[1]); +} + +long native_sin(long *args, int argc) { + return (long)(sin((double)args[0]) * 1000000); +} + +long native_cos(long *args, int argc) { + return (long)(cos((double)args[0]) * 1000000); +} + +long native_tan(long *args, int argc) { + return (long)(tan((double)args[0]) * 1000000); +} + +long native_abs(long *args, int argc) { + return (long)abs((int)args[0]); +} + +long native_floor(long *args, int argc) { + return (long)floor((double)args[0]); +} + +long native_ceil(long *args, int argc) { + return (long)ceil((double)args[0]); +} + +long native_strpos(long *args, int argc) { + char *haystack = (char*)args[0]; + char *needle = (char*)args[1]; + char *pos = strstr(haystack, needle); + if (pos) { + return pos - haystack; + } + return -1; +} + +long native_substr(long *args, int argc) { + char *str = (char*)args[0]; + int start = (int)args[1]; + int length = (int)args[2]; + + char *result = &str_pool[str_pool_idx]; + int str_len = strlen(str); + + if (start < 0) start = 0; + if (start >= str_len) return (long)""; + if (start + length > str_len) length = str_len - start; + if (length < 0) return (long)""; + + if (str_pool_idx + length + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + strncpy(result, str + start, length); + result[length] = 0; + + str_pool_idx += length + 1; + return (long)result; +} + +long native_upper(long *args, int argc) { + char *str = (char*)args[0]; + char *result = &str_pool[str_pool_idx]; + int len = strlen(str); + + if (str_pool_idx + len + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + for (int i = 0; i <= len; i++) { + result[i] = toupper(str[i]); + } + + str_pool_idx += len + 1; + return (long)result; +} + +long native_lower(long *args, int argc) { + char *str = (char*)args[0]; + char *result = &str_pool[str_pool_idx]; + int len = strlen(str); + + if (str_pool_idx + len + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + for (int i = 0; i <= len; i++) { + result[i] = tolower(str[i]); + } + + str_pool_idx += len + 1; + return (long)result; +} + +long native_strip(long *args, int argc) { + char *str = (char*)args[0]; + char *result = &str_pool[str_pool_idx]; + + while (*str && isspace(*str)) str++; + + int len = strlen(str); + while (len > 0 && isspace(str[len - 1])) len--; + + if (str_pool_idx + len + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + strncpy(result, str, len); + result[len] = 0; + + str_pool_idx += len + 1; + return (long)result; +} + +long native_replace(long *args, int argc) { + char *str = (char*)args[0]; + char *old_str = (char*)args[1]; + char *new_str = (char*)args[2]; + + char *result = &str_pool[str_pool_idx]; + char *src = str; + char *dst = result; + int old_len = strlen(old_str); + int new_len = strlen(new_str); + + while (*src) { + if (strncmp(src, old_str, old_len) == 0) { + if (str_pool_idx + (dst - result) + new_len + strlen(src + old_len) + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + strcpy(dst, new_str); + dst += new_len; + src += old_len; + } else { + *dst++ = *src++; + } + } + *dst = 0; + + int total_len = dst - result; + str_pool_idx += total_len + 1; + return (long)result; +} + +long native_startswith(long *args, int argc) { + char *str = (char*)args[0]; + char *prefix = (char*)args[1]; + int prefix_len = strlen(prefix); + return strncmp(str, prefix, prefix_len) == 0; +} + +long native_endswith(long *args, int argc) { + char *str = (char*)args[0]; + char *suffix = (char*)args[1]; + int str_len = strlen(str); + int suffix_len = strlen(suffix); + + if (suffix_len > str_len) return 0; + return strcmp(str + str_len - suffix_len, suffix) == 0; +} + void register_native_functions() { register_native_func("socket", native_socket); register_native_func("bind", native_bind); @@ -665,6 +926,22 @@ void register_native_functions() { register_native_func("strlen", native_strlen); register_native_func("AF_INET", native_AF_INET); register_native_func("SOCK_STREAM", native_SOCK_STREAM); + register_native_func("sqrt", native_sqrt); + register_native_func("pow", native_pow); + register_native_func("sin", native_sin); + register_native_func("cos", native_cos); + register_native_func("tan", native_tan); + register_native_func("abs", native_abs); + register_native_func("floor", native_floor); + register_native_func("ceil", native_ceil); + register_native_func("strpos", native_strpos); + register_native_func("substr", native_substr); + register_native_func("upper", native_upper); + register_native_func("lower", native_lower); + register_native_func("strip", native_strip); + register_native_func("replace", native_replace); + register_native_func("startswith", native_startswith); + register_native_func("endswith", native_endswith); } int main(int argc, char **argv) { diff --git a/src/globals.c b/src/globals.c new file mode 100644 index 0000000..17abc36 --- /dev/null +++ b/src/globals.c @@ -0,0 +1,18 @@ +#include "types.h" + +Token tokens[MAX_TOK]; +int tk_idx = 0; +int pc = 0; +long memory[MEM_SIZE]; +int sp = 0; +int bp = 0; +Symbol locals[VAR_MAX]; +int loc_cnt = 0; +Func funcs[100]; +int func_cnt = 0; +NativeFuncDef native_funcs[100]; +int native_func_cnt = 0; +char *src_code; +char str_pool[STR_POOL_SIZE]; +int str_pool_idx = 0; +long ax = 0; diff --git a/src/interpreter.c b/src/interpreter.c new file mode 100644 index 0000000..a53b2ef --- /dev/null +++ b/src/interpreter.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include "types.h" +#include "interpreter.h" +#include "parser.h" + +void error(char *msg) { + printf("Error at token %d ('%c'): %s\n", pc, tokens[pc].type, msg); + exit(1); +} + +void match(int type) { + if (tokens[pc].type == type) pc++; + else error("Unexpected token"); +} + +int find_local(char *name, int len) { + for (int i = loc_cnt - 1; i >= 0; i--) { + if (!strncmp(locals[i].name, name, len) && locals[i].name[len] == 0) + return i; + } + return -1; +} + +int find_func(char *name, int len) { + for (int i = 0; i < func_cnt; i++) { + if (!strncmp(funcs[i].name, name, len) && funcs[i].name[len] == 0) + return i; + } + return -1; +} + +int find_native_func(char *name, int len) { + for (int i = 0; i < native_func_cnt; i++) { + if (!strncmp(native_funcs[i].name, name, len) && native_funcs[i].name[len] == 0) + return i; + } + return -1; +} + +void skip_block() { + int brace = 0; + do { + if (tokens[pc].type == '{') brace++; + if (tokens[pc].type == '}') brace--; + pc++; + } while (brace > 0 && tokens[pc].type != 0); +} + +void statement() { + if (tokens[pc].type == '{') { + pc++; + while (tokens[pc].type != '}' && tokens[pc].type != 0) { + statement(); + if (ax == -999) break; + } + match('}'); + } + else if (tokens[pc].type == Int || tokens[pc].type == Char) { + pc++; + while (tokens[pc].type != ';') { + while (tokens[pc].type == '*') pc++; + Token *t = &tokens[pc]; + match(Id); + + int addr = sp; + Symbol *s = &locals[loc_cnt++]; + strncpy(s->name, t->text, t->val); s->name[t->val] = 0; + s->addr = addr; + s->is_array = 0; + + if (tokens[pc].type == '[') { + pc++; + int size = (int)expression(); + match(']'); + s->is_array = 1; + sp += size; + } else { + sp++; + } + + if (tokens[pc].type == '=') { + pc++; + memory[addr] = expression(); + } + if (tokens[pc].type == ',') pc++; + } + match(';'); + } + else if (tokens[pc].type == If) { + pc++; + match('('); + long cond = expression(); + match(')'); + if (cond) { + statement(); + if (ax == -999) return; + if (tokens[pc].type == Else) { pc++; skip_block(); } + } else { + skip_block(); + if (tokens[pc].type == Else) { + pc++; + statement(); + if (ax == -999) return; + } + } + } + else if (tokens[pc].type == While) { + pc++; + int loop_start = pc; + match('('); + long cond = expression(); + match(')'); + if (!cond) { + skip_block(); + } else { + while (1) { + statement(); + if (ax == -999) return; + int save_pc = pc; + pc = loop_start; + match('('); + cond = expression(); + match(')'); + if (!cond) { pc = save_pc; break; } + } + } + } + else if (tokens[pc].type == Return) { + pc++; + if (tokens[pc].type != ';') ax = expression(); + else ax = 0; + match(';'); + ax = -999; + } + else if (tokens[pc].type == Printf) { + pc++; + match('('); + char *fmt = tokens[pc].text; + match(Str); + + char *p = fmt; + while (*p) { + if (*p == '%' && (p[1] == 'd' || p[1] == 's')) { + p++; + match(','); + long val = expression(); + if (*p == 'd') printf("%ld", val); + else if (*p == 's') printf("%s", (char*)val); + p++; + } else { + putchar(*p++); + } + } + match(')'); + match(';'); + } + else { + expression(); + match(';'); + } +} + +void scan_functions() { + int i = 0; + while (tokens[i].type != 0) { + if ((tokens[i].type == Int || tokens[i].type == Char) && + tokens[i+1].type == Id && tokens[i+2].type == '(') { + + Func *f = &funcs[func_cnt++]; + Token *name = &tokens[i+1]; + strncpy(f->name, name->text, name->val); f->name[name->val] = 0; + + i += 3; + int params = 0; + while(tokens[i].type != ')') { + if (tokens[i].type == Int || tokens[i].type == Char) { + params++; + i++; + while (tokens[i].type == '*') i++; + if (tokens[i].type == Id) i++; + } else i++; + } + f->param_count = params; + i++; + f->entry_point = i; + + int brace = 0; + do { + if (tokens[i].type == '{') brace++; + if (tokens[i].type == '}') brace--; + i++; + } while (brace > 0 && tokens[i].type != 0); + } else { + i++; + } + } +} diff --git a/src/interpreter.h b/src/interpreter.h new file mode 100644 index 0000000..7772132 --- /dev/null +++ b/src/interpreter.h @@ -0,0 +1,13 @@ +#ifndef INTERPRETER_H +#define INTERPRETER_H + +void error(char *msg); +void match(int type); +int find_local(char *name, int len); +int find_func(char *name, int len); +int find_native_func(char *name, int len); +void statement(); +void skip_block(); +void scan_functions(); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..3312e9e --- /dev/null +++ b/src/main.c @@ -0,0 +1,44 @@ +#include +#include +#include "types.h" +#include "tokenizer.h" +#include "interpreter.h" +#include "native_functions.h" + +int main(int argc, char **argv) { + if (argc < 2) { + printf("Usage: rc \n"); + return 1; + } + + FILE *f = fopen(argv[1], "rb"); + if (!f) { + printf("Could not open file.\n"); + return 1; + } + + src_code = malloc(MAX_SRC); + size_t n = fread(src_code, 1, MAX_SRC, f); + src_code[n] = 0; + fclose(f); + + register_native_functions(); + + tokenize(src_code); + scan_functions(); + + int main_idx = find_func("main", 4); + if (main_idx == -1) { + printf("No main function found.\n"); + return 1; + } + + pc = funcs[main_idx].entry_point; + memory[sp++] = 0; + memory[sp++] = 0; + + ax = 0; + statement(); + + return 0; +} diff --git a/src/native_functions.c b/src/native_functions.c new file mode 100644 index 0000000..189c20e --- /dev/null +++ b/src/native_functions.c @@ -0,0 +1,302 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "types.h" +#include "native_functions.h" +#include "interpreter.h" + +void register_native_func(char *name, NativeFunc func) { + NativeFuncDef *nf = &native_funcs[native_func_cnt++]; + strncpy(nf->name, name, 31); + nf->name[31] = 0; + nf->func = func; +} + +long native_socket(long *args, int argc) { + int domain = (int)args[0]; + int type = (int)args[1]; + int protocol = (int)args[2]; + return socket(domain, type, protocol); +} + +long native_bind(long *args, int argc) { + int sockfd = (int)args[0]; + int port = (int)args[1]; + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + + return bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)); +} + +long native_listen(long *args, int argc) { + int sockfd = (int)args[0]; + int backlog = (int)args[1]; + return listen(sockfd, backlog); +} + +long native_accept(long *args, int argc) { + int sockfd = (int)args[0]; + return accept(sockfd, NULL, NULL); +} + +long native_recv(long *args, int argc) { + int sockfd = (int)args[0]; + int addr = (int)args[1]; + int len = (int)args[2]; + int flags = (int)args[3]; + + char temp_buf[8192]; + if (len > 8192) len = 8192; + + int result = recv(sockfd, temp_buf, len, flags); + if (result > 0) { + for (int i = 0; i < result; i++) { + memory[addr + i] = temp_buf[i]; + } + } + return result; +} + +long native_send(long *args, int argc) { + int sockfd = (int)args[0]; + long buf_arg = args[1]; + int len = (int)args[2]; + int flags = (int)args[3]; + + if (buf_arg > MEM_SIZE * 8 || buf_arg < 0) { + return send(sockfd, (char*)buf_arg, len, flags); + } + + char temp_buf[8192]; + if (len > 8192) len = 8192; + + for (int i = 0; i < len; i++) { + temp_buf[i] = (char)memory[buf_arg + i]; + } + + return send(sockfd, temp_buf, len, flags); +} + +long native_close(long *args, int argc) { + int fd = (int)args[0]; + return close(fd); +} + +long native_strlen(long *args, int argc) { + char *str = (char*)args[0]; + return strlen(str); +} + +long native_AF_INET(long *args, int argc) { + return AF_INET; +} + +long native_SOCK_STREAM(long *args, int argc) { + return SOCK_STREAM; +} + +long native_sqrt(long *args, int argc) { + return (long)sqrt((double)args[0]); +} + +long native_pow(long *args, int argc) { + return (long)pow((double)args[0], (double)args[1]); +} + +long native_sin(long *args, int argc) { + return (long)(sin((double)args[0]) * 1000000); +} + +long native_cos(long *args, int argc) { + return (long)(cos((double)args[0]) * 1000000); +} + +long native_tan(long *args, int argc) { + return (long)(tan((double)args[0]) * 1000000); +} + +long native_abs(long *args, int argc) { + return (long)abs((int)args[0]); +} + +long native_floor(long *args, int argc) { + return (long)floor((double)args[0]); +} + +long native_ceil(long *args, int argc) { + return (long)ceil((double)args[0]); +} + +long native_strpos(long *args, int argc) { + char *haystack = (char*)args[0]; + char *needle = (char*)args[1]; + char *pos = strstr(haystack, needle); + if (pos) { + return pos - haystack; + } + return -1; +} + +long native_substr(long *args, int argc) { + char *str = (char*)args[0]; + int start = (int)args[1]; + int length = (int)args[2]; + + char *result = &str_pool[str_pool_idx]; + int str_len = strlen(str); + + if (start < 0) start = 0; + if (start >= str_len) return (long)""; + if (start + length > str_len) length = str_len - start; + if (length < 0) return (long)""; + + if (str_pool_idx + length + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + strncpy(result, str + start, length); + result[length] = 0; + + str_pool_idx += length + 1; + return (long)result; +} + +long native_upper(long *args, int argc) { + char *str = (char*)args[0]; + char *result = &str_pool[str_pool_idx]; + int len = strlen(str); + + if (str_pool_idx + len + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + for (int i = 0; i <= len; i++) { + result[i] = toupper(str[i]); + } + + str_pool_idx += len + 1; + return (long)result; +} + +long native_lower(long *args, int argc) { + char *str = (char*)args[0]; + char *result = &str_pool[str_pool_idx]; + int len = strlen(str); + + if (str_pool_idx + len + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + for (int i = 0; i <= len; i++) { + result[i] = tolower(str[i]); + } + + str_pool_idx += len + 1; + return (long)result; +} + +long native_strip(long *args, int argc) { + char *str = (char*)args[0]; + char *result = &str_pool[str_pool_idx]; + + while (*str && isspace(*str)) str++; + + int len = strlen(str); + while (len > 0 && isspace(str[len - 1])) len--; + + if (str_pool_idx + len + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + strncpy(result, str, len); + result[len] = 0; + + str_pool_idx += len + 1; + return (long)result; +} + +long native_replace(long *args, int argc) { + char *str = (char*)args[0]; + char *old_str = (char*)args[1]; + char *new_str = (char*)args[2]; + + char *result = &str_pool[str_pool_idx]; + char *src = str; + char *dst = result; + int old_len = strlen(old_str); + int new_len = strlen(new_str); + + while (*src) { + if (strncmp(src, old_str, old_len) == 0) { + if (str_pool_idx + (dst - result) + new_len + strlen(src + old_len) + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + strcpy(dst, new_str); + dst += new_len; + src += old_len; + } else { + *dst++ = *src++; + } + } + *dst = 0; + + int total_len = dst - result; + str_pool_idx += total_len + 1; + return (long)result; +} + +long native_startswith(long *args, int argc) { + char *str = (char*)args[0]; + char *prefix = (char*)args[1]; + int prefix_len = strlen(prefix); + return strncmp(str, prefix, prefix_len) == 0; +} + +long native_endswith(long *args, int argc) { + char *str = (char*)args[0]; + char *suffix = (char*)args[1]; + int str_len = strlen(str); + int suffix_len = strlen(suffix); + + if (suffix_len > str_len) return 0; + return strcmp(str + str_len - suffix_len, suffix) == 0; +} + +void register_native_functions() { + register_native_func("socket", native_socket); + register_native_func("bind", native_bind); + register_native_func("listen", native_listen); + register_native_func("accept", native_accept); + register_native_func("recv", native_recv); + register_native_func("send", native_send); + register_native_func("close", native_close); + register_native_func("strlen", native_strlen); + register_native_func("AF_INET", native_AF_INET); + register_native_func("SOCK_STREAM", native_SOCK_STREAM); + register_native_func("sqrt", native_sqrt); + register_native_func("pow", native_pow); + register_native_func("sin", native_sin); + register_native_func("cos", native_cos); + register_native_func("tan", native_tan); + register_native_func("abs", native_abs); + register_native_func("floor", native_floor); + register_native_func("ceil", native_ceil); + register_native_func("strpos", native_strpos); + register_native_func("substr", native_substr); + register_native_func("upper", native_upper); + register_native_func("lower", native_lower); + register_native_func("strip", native_strip); + register_native_func("replace", native_replace); + register_native_func("startswith", native_startswith); + register_native_func("endswith", native_endswith); +} diff --git a/src/native_functions.h b/src/native_functions.h new file mode 100644 index 0000000..b5383f7 --- /dev/null +++ b/src/native_functions.h @@ -0,0 +1,7 @@ +#ifndef NATIVE_FUNCTIONS_H +#define NATIVE_FUNCTIONS_H + +void register_native_func(char *name, NativeFunc func); +void register_native_functions(); + +#endif diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..e587ddd --- /dev/null +++ b/src/parser.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include "types.h" +#include "parser.h" +#include "interpreter.h" +#include "string_utils.h" + +extern Token tokens[]; +extern int pc; +extern long memory[]; +extern int sp; +extern int bp; +extern Symbol locals[]; +extern int loc_cnt; +extern Func funcs[]; +extern int func_cnt; +extern NativeFuncDef native_funcs[]; +extern int native_func_cnt; +extern long ax; + +extern void error(char *msg); +extern void match(int type); +extern int find_local(char *name, int len); +extern int find_func(char *name, int len); +extern int find_native_func(char *name, int len); +extern void statement(); + +long factor() { + Token *t = &tokens[pc]; + long val = 0; + + if (t->type == Num) { + pc++; + return t->val; + } + else if (t->type == Str) { + pc++; + return (long)t->text; + } + else if (t->type == '(') { + pc++; + val = expression(); + match(')'); + return val; + } + else if (t->type == Id) { + if (tokens[pc + 1].type == '(') { + int nf_idx = find_native_func(t->text, t->val); + + if (nf_idx != -1) { + pc += 2; + long args[10]; + int argc = 0; + + if (tokens[pc].type != ')') { + do { + args[argc++] = expression(); + } while (tokens[pc].type == ',' && pc++); + } + match(')'); + + return native_funcs[nf_idx].func(args, argc); + } + + int f_idx = find_func(t->text, t->val); + if (f_idx == -1) error("Unknown function"); + pc += 2; + + int old_bp = bp; + long args[10]; + int argc = 0; + + if (tokens[pc].type != ')') { + do { + args[argc++] = expression(); + } while (tokens[pc].type == ',' && pc++); + } + match(')'); + + int ret_pc = pc; + memory[sp] = bp; bp = sp++; + memory[sp++] = ret_pc; + for(int i=0; itext, t->val); + if (idx == -1) error("Undefined variable"); + pc++; + + Symbol *sym = &locals[idx]; + + if (tokens[pc].type == '[') { + pc++; + long start_or_index = expression(); + + if (tokens[pc].type == ':') { + pc++; + long end = expression(); + match(']'); + + long val = memory[sym->addr]; + if (is_string_ptr(val)) { + return slice_string(val, start_or_index, end); + } else { + error("Slicing only works on strings"); + } + } else { + match(']'); + return memory[sym->addr + start_or_index]; + } + } + + if (sym->is_array) { + return sym->addr; + } + + return memory[sym->addr]; + } + } + return 0; +} + +long unary() { + if (tokens[pc].type == '*') { + pc++; + int addr = unary(); + if (addr > MEM_SIZE * 8 || addr < 0) { + return *(char*)addr; + } + return memory[addr]; + } + else if (tokens[pc].type == '&') { + pc++; + Token *t = &tokens[pc]; + if (t->type != Id) error("Expected identifier after &"); + int idx = find_local(t->text, t->val); + if (idx == -1) error("Undefined variable"); + pc++; + return locals[idx].addr; + } + else if (tokens[pc].type == '-') { + pc++; + return -unary(); + } + return factor(); +} + +long term() { + long val = unary(); + while (tokens[pc].type == '*' || tokens[pc].type == '/') { + int op = tokens[pc++].type; + long val2 = unary(); + if (op == '*') val = val * val2; + else val = val / val2; + } + return val; +} + +long add() { + long val = term(); + while (tokens[pc].type == '+' || tokens[pc].type == '-') { + int op = tokens[pc++].type; + long val2 = term(); + if (op == '+') { + if (is_string_ptr(val) && is_string_ptr(val2)) { + val = concat_strings(val, val2); + } else { + val = val + val2; + } + } else { + val = val - val2; + } + } + return val; +} + +long relational() { + long val = add(); + while (tokens[pc].type >= Eq && tokens[pc].type <= Ge) { + int op = tokens[pc++].type; + long val2 = add(); + if (op == Eq) val = val == val2; + if (op == Ne) val = val != val2; + if (op == Lt) val = val < val2; + if (op == Gt) val = val > val2; + } + return val; +} + +long expression() { + if (tokens[pc].type == '*') { + int save_pc = pc; + unary(); + if (tokens[pc].type == '=') { + pc = save_pc; + pc++; + long addr = unary(); + match('='); + long val = expression(); + if (addr >= 0 && addr < MEM_SIZE) memory[addr] = val; + return val; + } + pc = save_pc; + } + + if (tokens[pc].type == Id) { + if (tokens[pc+1].type == '[') { + int idx = find_local(tokens[pc].text, tokens[pc].val); + if (idx == -1) error("Assign to unknown var"); + pc += 2; + long start_or_index = expression(); + + if (tokens[pc].type == ':') { + pc++; + long end = expression(); + match(']'); + + long val = memory[locals[idx].addr]; + if (is_string_ptr(val)) { + return slice_string(val, start_or_index, end); + } else { + error("Slicing only works on strings"); + } + } + + match(']'); + int addr = locals[idx].addr; + if (tokens[pc].type == '=') { + pc++; + long val = expression(); + memory[addr + start_or_index] = val; + return val; + } + return memory[addr + start_or_index]; + } else if (tokens[pc+1].type == '=') { + int idx = find_local(tokens[pc].text, tokens[pc].val); + if (idx == -1) error("Assign to unknown var"); + pc += 2; + long val = expression(); + memory[locals[idx].addr] = val; + return val; + } + } + + return relational(); +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..077e672 --- /dev/null +++ b/src/parser.h @@ -0,0 +1,11 @@ +#ifndef PARSER_H +#define PARSER_H + +long expression(); +long relational(); +long add(); +long term(); +long unary(); +long factor(); + +#endif diff --git a/src/string_utils.c b/src/string_utils.c new file mode 100644 index 0000000..d8f148b --- /dev/null +++ b/src/string_utils.c @@ -0,0 +1,51 @@ +#include +#include "types.h" +#include "string_utils.h" +#include "interpreter.h" + +int is_string_ptr(long val) { + return val > MEM_SIZE * 8; +} + +long concat_strings(long ptr1, long ptr2) { + char *s1 = (char*)ptr1; + char *s2 = (char*)ptr2; + char *result = &str_pool[str_pool_idx]; + + int len1 = strlen(s1); + int len2 = strlen(s2); + + if (str_pool_idx + len1 + len2 + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + strcpy(result, s1); + strcat(result, s2); + + str_pool_idx += len1 + len2 + 1; + + return (long)result; +} + +long slice_string(long str_ptr, int start, int end) { + char *str = (char*)str_ptr; + char *result = &str_pool[str_pool_idx]; + int str_len = strlen(str); + + if (start < 0) start = 0; + if (end < 0) end = str_len; + if (end > str_len) end = str_len; + if (start > end) start = end; + + int length = end - start; + + if (str_pool_idx + length + 1 >= STR_POOL_SIZE) { + error("String pool overflow"); + } + + strncpy(result, str + start, length); + result[length] = 0; + + str_pool_idx += length + 1; + return (long)result; +} diff --git a/src/string_utils.h b/src/string_utils.h new file mode 100644 index 0000000..5245dc5 --- /dev/null +++ b/src/string_utils.h @@ -0,0 +1,8 @@ +#ifndef STRING_UTILS_H +#define STRING_UTILS_H + +int is_string_ptr(long val); +long concat_strings(long ptr1, long ptr2); +long slice_string(long str_ptr, int start, int end); + +#endif diff --git a/src/tokenizer.c b/src/tokenizer.c new file mode 100644 index 0000000..9418eac --- /dev/null +++ b/src/tokenizer.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include "types.h" +#include "tokenizer.h" + +void tokenize(char *src) { + char *s = src; + while (*s) { + if (isspace(*s)) { s++; continue; } + + Token *t = &tokens[tk_idx++]; + t->text = s; + + if (*s == '/' && *(s+1) == '/') { + while (*s && *s != '\n') s++; + tk_idx--; + continue; + } + + if (isalpha(*s)) { + int len = 0; + while (isalnum(s[len]) || s[len] == '_') len++; + + char buf[32]; + strncpy(buf, s, len); buf[len] = 0; + + if (!strcmp(buf, "int")) t->type = Int; + else if (!strcmp(buf, "char")) t->type = Char; + else if (!strcmp(buf, "if")) t->type = If; + else if (!strcmp(buf, "else")) t->type = Else; + else if (!strcmp(buf, "while")) t->type = While; + else if (!strcmp(buf, "return")) t->type = Return; + else if (!strcmp(buf, "printf")) t->type = Printf; + else t->type = Id; + + t->val = len; + s += len; + continue; + } + + if (isdigit(*s)) { + t->type = Num; + t->val = strtol(s, &s, 10); + continue; + } + + if (*s == '"') { + s++; + t->type = Str; + t->text = s; + + char *d = s; + while (*s && *s != '"') { + if (*s == '\\' && *(s+1) == 'n') { + *d++ = '\n'; s+=2; + } else { + *d++ = *s++; + } + } + if (*s == '"') s++; + *d = 0; + t->val = (long)(d - t->text); + continue; + } + + if (!strncmp(s, "==", 2)) { t->type = Eq; s += 2; continue; } + if (!strncmp(s, "!=", 2)) { t->type = Ne; s += 2; continue; } + if (!strncmp(s, "<=", 2)) { t->type = Le; s += 2; continue; } + if (!strncmp(s, ">=", 2)) { t->type = Ge; s += 2; continue; } + if (!strncmp(s, "&&", 2)) { t->type = And; s += 2; continue; } + if (!strncmp(s, "||", 2)) { t->type = Or; s += 2; continue; } + + if (*s == '<') { t->type = Lt; s++; continue; } + if (*s == '>') { t->type = Gt; s++; continue; } + + t->type = *s++; + } + tokens[tk_idx].type = 0; +} diff --git a/src/tokenizer.h b/src/tokenizer.h new file mode 100644 index 0000000..7f3f91c --- /dev/null +++ b/src/tokenizer.h @@ -0,0 +1,6 @@ +#ifndef TOKENIZER_H +#define TOKENIZER_H + +void tokenize(char *src); + +#endif diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..f77faf3 --- /dev/null +++ b/src/types.h @@ -0,0 +1,58 @@ +#ifndef TYPES_H +#define TYPES_H + +#define MAX_SRC 100000 +#define MAX_TOK 10000 +#define VAR_MAX 500 +#define MEM_SIZE 10000 +#define STR_POOL_SIZE 100000 + +enum { + Num = 128, Str, Id, Int, Char, Else, If, While, Return, Printf, + Assign, Eq, Ne, Lt, Gt, Le, Ge, Or, And +}; + +typedef struct { + int type; + long val; + char *text; +} Token; + +typedef struct { + char name[32]; + int type; + int addr; + int is_array; +} Symbol; + +typedef struct { + char name[32]; + int entry_point; + int param_count; +} Func; + +typedef long (*NativeFunc)(long*, int); + +typedef struct { + char name[32]; + NativeFunc func; +} NativeFuncDef; + +extern Token tokens[MAX_TOK]; +extern int tk_idx; +extern int pc; +extern long memory[MEM_SIZE]; +extern int sp; +extern int bp; +extern Symbol locals[VAR_MAX]; +extern int loc_cnt; +extern Func funcs[100]; +extern int func_cnt; +extern NativeFuncDef native_funcs[100]; +extern int native_func_cnt; +extern char *src_code; +extern char str_pool[STR_POOL_SIZE]; +extern int str_pool_idx; +extern long ax; + +#endif diff --git a/tests/endless_loop_test.rc b/tests/endless_loop_test.rc new file mode 100644 index 0000000..f142f7c --- /dev/null +++ b/tests/endless_loop_test.rc @@ -0,0 +1,18 @@ +int main() { + int counter = 0; + + printf("Testing while(1) endless loop with counter:\n"); + + while (1) { + printf("Loop iteration: %d\n", counter); + counter = counter + 1; + + if (counter == 10) { + printf("Reached 10 iterations, exiting\n"); + return 0; + } + } + + printf("This should never print\n"); + return 0; +} diff --git a/tests/feature_test.rc b/tests/feature_test.rc new file mode 100644 index 0000000..3fd3955 --- /dev/null +++ b/tests/feature_test.rc @@ -0,0 +1,50 @@ +int main() { + int x = -5; + int y = -10; + int z = 0; + + printf("Testing negative numbers:\n"); + printf("x = %d\n", x); + printf("y = %d\n", y); + printf("x + y = %d\n", x + y); + + printf("\nTesting == operator:\n"); + if (x == -5) { + printf("x == -5 is true\n"); + } + if (x == y) { + printf("x == y is true\n"); + } else { + printf("x == y is false\n"); + } + + printf("\nTesting != operator:\n"); + if (x != y) { + printf("x != y is true\n"); + } + if (x != -5) { + printf("x != -5 is true\n"); + } else { + printf("x != -5 is false\n"); + } + + printf("\nTesting while loop with counter:\n"); + int count = 0; + while (count != 5) { + printf("count = %d\n", count); + count = count + 1; + } + + printf("\nTesting while(1) with break condition:\n"); + int i = 0; + while (1) { + printf("i = %d\n", i); + i = i + 1; + if (i == 3) { + printf("Breaking out of infinite loop\n"); + return 0; + } + } + + return 0; +} diff --git a/tests/math_test.rc b/tests/math_test.rc new file mode 100644 index 0000000..a76bac5 --- /dev/null +++ b/tests/math_test.rc @@ -0,0 +1,31 @@ +int main() { + printf("Testing Math Functions:\n\n"); + + int x = 16; + int result = sqrt(x); + printf("sqrt(16) = %d\n", result); + + int p = pow(2, 8); + printf("pow(2, 8) = %d\n", p); + + int a = abs(-42); + printf("abs(-42) = %d\n", a); + + int f = floor(7); + printf("floor(7) = %d\n", f); + + int c = ceil(7); + printf("ceil(7) = %d\n", c); + + printf("\nTesting with negative numbers:\n"); + int neg = -100; + int abs_neg = abs(neg); + printf("abs(-100) = %d\n", abs_neg); + + printf("\nTesting pow with different values:\n"); + printf("pow(3, 3) = %d\n", pow(3, 3)); + printf("pow(5, 2) = %d\n", pow(5, 2)); + printf("pow(10, 3) = %d\n", pow(10, 3)); + + return 0; +} diff --git a/tests/string_manip_test.rc b/tests/string_manip_test.rc new file mode 100644 index 0000000..09c407e --- /dev/null +++ b/tests/string_manip_test.rc @@ -0,0 +1,72 @@ +int main() { + printf("=== String Manipulation Tests ===\n\n"); + + char *text = "Hello World"; + + printf("Testing strpos:\n"); + int pos = strpos(text, "World"); + printf("Position of 'World' in 'Hello World': %d\n", pos); + int pos2 = strpos(text, "xyz"); + printf("Position of 'xyz' in 'Hello World': %d\n\n", pos2); + + printf("Testing substr:\n"); + char *sub = substr(text, 0, 5); + printf("substr('Hello World', 0, 5) = '%s'\n", sub); + char *sub2 = substr(text, 6, 5); + printf("substr('Hello World', 6, 5) = '%s'\n\n", sub2); + + printf("Testing upper and lower:\n"); + char *up = upper(text); + printf("upper('Hello World') = '%s'\n", up); + char *low = lower(text); + printf("lower('Hello World') = '%s'\n\n", low); + + printf("Testing strip:\n"); + char *spaced = " Hello World "; + char *stripped = strip(spaced); + printf("strip(' Hello World ') = '%s'\n\n", stripped); + + printf("Testing replace:\n"); + char *replaced = replace(text, "World", "Python"); + printf("replace('Hello World', 'World', 'Python') = '%s'\n", replaced); + char *replaced2 = replace("aaa bbb aaa", "aaa", "xxx"); + printf("replace('aaa bbb aaa', 'aaa', 'xxx') = '%s'\n\n", replaced2); + + printf("Testing startswith:\n"); + if (startswith(text, "Hello")) { + printf("'Hello World' starts with 'Hello': true\n"); + } + if (startswith(text, "World")) { + printf("'Hello World' starts with 'World': true\n"); + } else { + printf("'Hello World' starts with 'World': false\n"); + } + + printf("\nTesting endswith:\n"); + if (endswith(text, "World")) { + printf("'Hello World' ends with 'World': true\n"); + } + if (endswith(text, "Hello")) { + printf("'Hello World' ends with 'Hello': true\n"); + } else { + printf("'Hello World' ends with 'Hello': false\n"); + } + + printf("\nTesting slicing [start:end]:\n"); + char *str = "Python Programming"; + char *slice1 = str[0:6]; + printf("'Python Programming'[0:6] = '%s'\n", slice1); + char *slice2 = str[7:18]; + printf("'Python Programming'[7:18] = '%s'\n", slice2); + char *slice3 = str[7:11]; + printf("'Python Programming'[7:11] = '%s'\n", slice3); + + printf("\nCombining operations:\n"); + char *combined = upper(str[0:6]); + printf("upper('Python Programming'[0:6]) = '%s'\n", combined); + + char *chain = replace(lower("HELLO WORLD"), "world", "python"); + printf("replace(lower('HELLO WORLD'), 'world', 'python') = '%s'\n", chain); + + return 0; +} diff --git a/tests/string_test.rc b/tests/string_test.rc new file mode 100644 index 0000000..4b9c3d5 --- /dev/null +++ b/tests/string_test.rc @@ -0,0 +1,29 @@ +int main() { + printf("Testing String Concatenation:\n\n"); + + char *hello = "Hello"; + char *world = " World"; + char *result = hello + world; + printf("Result: %s\n", result); + + printf("\nTesting multiple concatenations:\n"); + char *a = "aaa"; + char *b = "bbb"; + char *c = "ccc"; + char *abc = a + b + c; + printf("a + b + c = %s\n", abc); + + printf("\nTesting literal concatenation:\n"); + char *direct = "First" + " Second" + " Third"; + printf("Result: %s\n", direct); + + printf("\nTesting with variable and literal:\n"); + char *name = "Alice"; + char *greeting = "Hello, " + name + "!"; + printf("%s\n", greeting); + + printf("\nTesting in printf directly:\n"); + printf("Direct: %s\n", "Start" + " Middle" + " End"); + + return 0; +}