Structuring.

This commit is contained in:
2025-11-22 22:22:43 +01:00
parent ab71aa9999
commit cb9b4e2941
32 changed files with 1868 additions and 40 deletions
+106 -22
View File
@@ -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)"
+212
View File
@@ -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.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
View File
View File
View File
BIN
View File
Binary file not shown.
+295 -18
View File
@@ -9,6 +9,7 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
@@ -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) {
+18
View File
@@ -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;
+200
View File
@@ -0,0 +1,200 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#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++;
}
}
}
+13
View File
@@ -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
+44
View File
@@ -0,0 +1,44 @@
#include <stdio.h>
#include <stdlib.h>
#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 <file.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;
}
+302
View File
@@ -0,0 +1,302 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#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);
}
+7
View File
@@ -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
+257
View File
@@ -0,0 +1,257 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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; i<argc; i++) memory[sp++] = args[i];
pc = funcs[f_idx].entry_point;
statement();
val = ax;
sp = bp;
bp = memory[sp];
pc = ret_pc;
return val;
}
else {
int idx = find_local(t->text, 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();
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef PARSER_H
#define PARSER_H
long expression();
long relational();
long add();
long term();
long unary();
long factor();
#endif
+51
View File
@@ -0,0 +1,51 @@
#include <string.h>
#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;
}
+8
View File
@@ -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
+80
View File
@@ -0,0 +1,80 @@
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#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;
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef TOKENIZER_H
#define TOKENIZER_H
void tokenize(char *src);
#endif
+58
View File
@@ -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
+18
View File
@@ -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;
}
+50
View File
@@ -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;
}
+31
View File
@@ -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;
}
+72
View File
@@ -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;
}
+29
View File
@@ -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;
}