Structuring.
This commit is contained in:
parent
ab71aa9999
commit
cb9b4e2941
128
Makefile
128
Makefile
@ -1,34 +1,118 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -Wall -Wextra -O2
|
CFLAGS = -Wall -Wextra -O2 -Isrc
|
||||||
TARGET = main2
|
LDFLAGS = -lm
|
||||||
SRC = main2.c
|
|
||||||
SAMPLES = test.c demo.c a.c
|
|
||||||
|
|
||||||
.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)
|
SOURCES = $(SRC_DIR)/main.c \
|
||||||
$(CC) $(CFLAGS) -o $(TARGET) $(SRC)
|
$(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)
|
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
|
||||||
./$(TARGET) test.c
|
|
||||||
|
|
||||||
run-demo: $(TARGET)
|
TESTS = $(TEST_DIR)/feature_test.rc \
|
||||||
./$(TARGET) demo.c
|
$(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)
|
EXAMPLES = $(EXAMPLE_DIR)/test.rc \
|
||||||
./$(TARGET) a.c
|
$(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:
|
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:
|
help:
|
||||||
@echo "Mini C Interpreter - Makefile"
|
@echo "RC - Retoor's C Interpreter"
|
||||||
|
@echo ""
|
||||||
@echo "Usage:"
|
@echo "Usage:"
|
||||||
@echo " make - Build the interpreter"
|
@echo " make - Build the interpreter"
|
||||||
@echo " make run-test - Run test.c"
|
@echo " make test - Run all feature tests"
|
||||||
@echo " make run-demo - Run demo.c"
|
@echo " make clean - Remove all build artifacts"
|
||||||
@echo " make run-a - Run a.c"
|
@echo ""
|
||||||
@echo " make clean - Remove compiled binaries"
|
@echo "Individual Tests:"
|
||||||
@echo " make help - Show this help message"
|
@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
README.md
Normal file
212
README.md
Normal 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
build/globals.o
Normal file
BIN
build/globals.o
Normal file
Binary file not shown.
BIN
build/interpreter.o
Normal file
BIN
build/interpreter.o
Normal file
Binary file not shown.
BIN
build/main.o
Normal file
BIN
build/main.o
Normal file
Binary file not shown.
BIN
build/native_functions.o
Normal file
BIN
build/native_functions.o
Normal file
Binary file not shown.
BIN
build/parser.o
Normal file
BIN
build/parser.o
Normal file
Binary file not shown.
BIN
build/string_utils.o
Normal file
BIN
build/string_utils.o
Normal file
Binary file not shown.
BIN
build/tokenizer.o
Normal file
BIN
build/tokenizer.o
Normal file
Binary file not shown.
313
main2.c
313
main2.c
@ -9,6 +9,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -18,6 +19,7 @@
|
|||||||
#define MAX_TOK 10000
|
#define MAX_TOK 10000
|
||||||
#define VAR_MAX 500
|
#define VAR_MAX 500
|
||||||
#define MEM_SIZE 10000
|
#define MEM_SIZE 10000
|
||||||
|
#define STR_POOL_SIZE 100000
|
||||||
|
|
||||||
// --- Token Types ---
|
// --- Token Types ---
|
||||||
enum {
|
enum {
|
||||||
@ -71,6 +73,9 @@ int native_func_cnt = 0;
|
|||||||
|
|
||||||
char *src_code;
|
char *src_code;
|
||||||
|
|
||||||
|
char str_pool[STR_POOL_SIZE];
|
||||||
|
int str_pool_idx = 0;
|
||||||
|
|
||||||
// --- Tokenizer ---
|
// --- Tokenizer ---
|
||||||
void tokenize(char *src) {
|
void tokenize(char *src) {
|
||||||
char *s = src;
|
char *s = src;
|
||||||
@ -195,6 +200,10 @@ void register_native_func(char *name, NativeFunc func) {
|
|||||||
nf->func = func;
|
nf->func = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Forward Declarations ---
|
||||||
|
int is_string_ptr(long val);
|
||||||
|
long slice_string(long str_ptr, int start, int end);
|
||||||
|
|
||||||
// --- Parser ---
|
// --- Parser ---
|
||||||
long expression();
|
long expression();
|
||||||
void statement();
|
void statement();
|
||||||
@ -276,9 +285,23 @@ long factor() {
|
|||||||
|
|
||||||
if (tokens[pc].type == '[') {
|
if (tokens[pc].type == '[') {
|
||||||
pc++;
|
pc++;
|
||||||
long index = expression();
|
long start_or_index = expression();
|
||||||
match(']');
|
|
||||||
return memory[sym->addr + index];
|
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) {
|
if (sym->is_array) {
|
||||||
@ -293,6 +316,53 @@ long factor() {
|
|||||||
|
|
||||||
long ax = 0;
|
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() {
|
long unary() {
|
||||||
if (tokens[pc].type == '*') {
|
if (tokens[pc].type == '*') {
|
||||||
pc++;
|
pc++;
|
||||||
@ -345,8 +415,15 @@ long add() {
|
|||||||
while (tokens[pc].type == '+' || tokens[pc].type == '-') {
|
while (tokens[pc].type == '+' || tokens[pc].type == '-') {
|
||||||
int op = tokens[pc++].type;
|
int op = tokens[pc++].type;
|
||||||
long val2 = term();
|
long val2 = term();
|
||||||
if (op == '+') val = val + val2;
|
if (op == '+') {
|
||||||
else val = val - val2;
|
if (is_string_ptr(val) && is_string_ptr(val2)) {
|
||||||
|
val = concat_strings(val, val2);
|
||||||
|
} else {
|
||||||
|
val = val + val2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val = val - val2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -386,16 +463,30 @@ long expression() {
|
|||||||
int idx = find_local(tokens[pc].text, tokens[pc].val);
|
int idx = find_local(tokens[pc].text, tokens[pc].val);
|
||||||
if (idx == -1) error("Assign to unknown var");
|
if (idx == -1) error("Assign to unknown var");
|
||||||
pc += 2;
|
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(']');
|
match(']');
|
||||||
int addr = locals[idx].addr;
|
int addr = locals[idx].addr;
|
||||||
if (tokens[pc].type == '=') {
|
if (tokens[pc].type == '=') {
|
||||||
pc++;
|
pc++;
|
||||||
long val = expression();
|
long val = expression();
|
||||||
memory[addr + index] = val;
|
memory[addr + start_or_index] = val;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
return memory[addr + index];
|
return memory[addr + start_or_index];
|
||||||
} else if (tokens[pc+1].type == '=') {
|
} else if (tokens[pc+1].type == '=') {
|
||||||
int idx = find_local(tokens[pc].text, tokens[pc].val);
|
int idx = find_local(tokens[pc].text, tokens[pc].val);
|
||||||
if (idx == -1) error("Assign to unknown var");
|
if (idx == -1) error("Assign to unknown var");
|
||||||
@ -482,17 +573,20 @@ void statement() {
|
|||||||
match('(');
|
match('(');
|
||||||
long cond = expression();
|
long cond = expression();
|
||||||
match(')');
|
match(')');
|
||||||
while (cond) {
|
if (!cond) {
|
||||||
statement();
|
skip_block();
|
||||||
if (ax == -999) return;
|
} else {
|
||||||
int save_pc = pc;
|
while (1) {
|
||||||
pc = loop_start;
|
statement();
|
||||||
match('(');
|
if (ax == -999) return;
|
||||||
cond = expression();
|
int save_pc = pc;
|
||||||
match(')');
|
pc = loop_start;
|
||||||
if (!cond) { pc = save_pc; break; }
|
match('(');
|
||||||
|
cond = expression();
|
||||||
|
match(')');
|
||||||
|
if (!cond) { pc = save_pc; break; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!cond) skip_block();
|
|
||||||
}
|
}
|
||||||
else if (tokens[pc].type == Return) {
|
else if (tokens[pc].type == Return) {
|
||||||
pc++;
|
pc++;
|
||||||
@ -654,6 +748,173 @@ long native_SOCK_STREAM(long *args, int argc) {
|
|||||||
return SOCK_STREAM;
|
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() {
|
void register_native_functions() {
|
||||||
register_native_func("socket", native_socket);
|
register_native_func("socket", native_socket);
|
||||||
register_native_func("bind", native_bind);
|
register_native_func("bind", native_bind);
|
||||||
@ -665,6 +926,22 @@ void register_native_functions() {
|
|||||||
register_native_func("strlen", native_strlen);
|
register_native_func("strlen", native_strlen);
|
||||||
register_native_func("AF_INET", native_AF_INET);
|
register_native_func("AF_INET", native_AF_INET);
|
||||||
register_native_func("SOCK_STREAM", native_SOCK_STREAM);
|
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) {
|
int main(int argc, char **argv) {
|
||||||
|
|||||||
18
src/globals.c
Normal file
18
src/globals.c
Normal 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
src/interpreter.c
Normal file
200
src/interpreter.c
Normal 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
src/interpreter.h
Normal file
13
src/interpreter.h
Normal 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
src/main.c
Normal file
44
src/main.c
Normal 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
src/native_functions.c
Normal file
302
src/native_functions.c
Normal 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
src/native_functions.h
Normal file
7
src/native_functions.h
Normal 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
src/parser.c
Normal file
257
src/parser.c
Normal 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
src/parser.h
Normal file
11
src/parser.h
Normal 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
src/string_utils.c
Normal file
51
src/string_utils.c
Normal 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
src/string_utils.h
Normal file
8
src/string_utils.h
Normal 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
src/tokenizer.c
Normal file
80
src/tokenizer.c
Normal 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
src/tokenizer.h
Normal file
6
src/tokenizer.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef TOKENIZER_H
|
||||||
|
#define TOKENIZER_H
|
||||||
|
|
||||||
|
void tokenize(char *src);
|
||||||
|
|
||||||
|
#endif
|
||||||
58
src/types.h
Normal file
58
src/types.h
Normal 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
tests/endless_loop_test.rc
Normal file
18
tests/endless_loop_test.rc
Normal 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
tests/feature_test.rc
Normal file
50
tests/feature_test.rc
Normal 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
tests/math_test.rc
Normal file
31
tests/math_test.rc
Normal 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
tests/string_manip_test.rc
Normal file
72
tests/string_manip_test.rc
Normal 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
tests/string_test.rc
Normal file
29
tests/string_test.rc
Normal 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;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user