UPdate documentation.

This commit is contained in:
2025-11-23 21:33:07 +01:00
parent 327eeadca4
commit 97fc55f74d
19 changed files with 1247 additions and 10 deletions
+4
View File
@@ -19,3 +19,7 @@ long ax = 0;
int return_flag = 0;
Coroutine coroutines[MAX_COROUTINES];
int coroutine_count = 0;
ClassDef classes[MAX_CLASSES];
int class_count = 0;
Object objects[MAX_OBJECTS];
int object_count = 0;
+80 -3
View File
@@ -69,6 +69,25 @@ void statement() {
if (pc >= MAX_TOK || pc >= tk_idx) {
error("Token index out of bounds in statement");
}
if (tokens[pc].type == Class) {
pc++;
while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != Id) pc++;
if (pc < MAX_TOK) pc++;
if (pc < MAX_TOK && tokens[pc].type == ':') {
pc++;
while (pc < MAX_TOK && tokens[pc].type != '{') pc++;
}
if (pc < MAX_TOK && tokens[pc].type == '{') {
int brace = 1;
pc++;
while (brace > 0 && pc < MAX_TOK && pc < tk_idx) {
if (tokens[pc].type == '{') brace++;
if (tokens[pc].type == '}') brace--;
pc++;
}
}
return;
}
if (tokens[pc].type == '{') {
pc++;
while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != '}' && tokens[pc].type != 0) {
@@ -85,7 +104,8 @@ void statement() {
}
match('}');
}
else if (tokens[pc].type == Int || tokens[pc].type == Char || tokens[pc].type == Double) {
else if (tokens[pc].type == Int || tokens[pc].type == Char || tokens[pc].type == Double ||
(tokens[pc].type == Id && find_class(tokens[pc].text, tokens[pc].val) >= 0)) {
int var_type = tokens[pc].type;
pc++;
while (pc < MAX_TOK && pc < tk_idx && tokens[pc].type != ';') {
@@ -239,8 +259,39 @@ void statement() {
}
void scan_functions() {
char current_class[32] = "";
int in_class = 0;
int i = 0;
while (i < MAX_TOK && i < tk_idx && tokens[i].type != 0) {
if (tokens[i].type == Class) {
i++;
if (i < MAX_TOK && tokens[i].type == Id) {
Token *class_name = &tokens[i];
int name_len = class_name->val;
if (name_len > 31) name_len = 31;
strncpy(current_class, class_name->text, name_len);
current_class[name_len] = 0;
i++;
}
if (i < MAX_TOK && tokens[i].type == ':') {
i++;
if (i < MAX_TOK && tokens[i].type == Id) i++;
}
if (i < MAX_TOK && tokens[i].type == '{') {
in_class = 1;
i++;
}
continue;
}
if (in_class && tokens[i].type == '}') {
in_class = 0;
current_class[0] = 0;
i++;
continue;
}
int is_async = 0;
int offset = 0;
if (tokens[i].type == Async) {
@@ -248,8 +299,25 @@ void scan_functions() {
offset = 1;
}
int is_static = 0;
if (tokens[i + offset].type == Static) {
is_static = 1;
offset++;
}
int is_constructor = 0;
int is_destructor = 0;
if (tokens[i + offset].type == Constructor) {
is_constructor = 1;
offset++;
} else if (tokens[i + offset].type == Destructor) {
is_destructor = 1;
offset++;
}
if (i + 2 + offset < MAX_TOK && i + 2 + offset < tk_idx &&
(tokens[i+offset].type == Int || tokens[i+offset].type == Char || tokens[i+offset].type == Double) &&
(tokens[i+offset].type == Int || tokens[i+offset].type == Char ||
tokens[i+offset].type == Double || tokens[i+offset].type == Void) &&
tokens[i+1+offset].type == Id && tokens[i+2+offset].type == '(') {
if (func_cnt >= 100) {
@@ -257,7 +325,16 @@ void scan_functions() {
}
Func *f = &funcs[func_cnt++];
Token *name = &tokens[i+1+offset];
strncpy(f->name, name->text, name->val); f->name[name->val] = 0;
if (in_class && current_class[0] != 0 && !is_constructor && !is_destructor) {
snprintf(f->name, 31, "%s_%.*s", current_class, name->val, name->text);
} else if (in_class && (is_constructor || is_destructor)) {
snprintf(f->name, 31, "%s_%s", current_class,
is_constructor ? "constructor" : "destructor");
} else {
strncpy(f->name, name->text, name->val);
f->name[name->val] = 0;
}
f->is_async = is_async;
i += 3 + offset;
+7
View File
@@ -9,5 +9,12 @@ int find_native_func(char *name, int len);
void statement();
void skip_block();
void scan_functions();
void scan_classes();
int find_class(char *name, int len);
int find_class_field(int class_idx, char *name, int len);
int find_class_method(int class_idx, char *name, int len);
long allocate_object(int class_idx);
void free_object(long obj_ptr);
void call_destructor(long obj_ptr);
#endif
+3
View File
@@ -7,6 +7,7 @@
#include "interpreter.h"
#include "native_functions.h"
#include "preprocessor.h"
#include "oop.h"
int main(int argc, char **argv) {
if (argc < 2) {
@@ -32,7 +33,9 @@ int main(int argc, char **argv) {
register_native_functions();
tokenize(src_code);
scan_classes();
scan_functions();
link_class_methods();
int main_idx = find_func("main", 4);
if (main_idx == -1 || main_idx >= func_cnt) {
+402
View File
@@ -0,0 +1,402 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "interpreter.h"
int find_class(char *name, int len) {
if (!name || len <= 0 || len > 31) return -1;
for (int i = 0; i < class_count && i < MAX_CLASSES; i++) {
if (strlen(classes[i].name) == (size_t)len &&
strncmp(classes[i].name, name, len) == 0) {
return i;
}
}
return -1;
}
int find_class_field(int class_idx, char *name, int len) {
if (class_idx < 0 || class_idx >= class_count || class_idx >= MAX_CLASSES) return -1;
if (!name || len <= 0 || len > 31) return -1;
ClassDef *cls = &classes[class_idx];
for (int i = 0; i < cls->field_count && i < MAX_CLASS_FIELDS; i++) {
if (strlen(cls->fields[i].name) == (size_t)len &&
strncmp(cls->fields[i].name, name, len) == 0) {
return i;
}
}
if (cls->parent_class_idx >= 0 && cls->parent_class_idx < class_count) {
return find_class_field(cls->parent_class_idx, name, len);
}
return -1;
}
int find_class_method(int class_idx, char *name, int len) {
if (class_idx < 0 || class_idx >= class_count || class_idx >= MAX_CLASSES) return -1;
if (!name || len <= 0 || len > 31) return -1;
ClassDef *cls = &classes[class_idx];
for (int i = 0; i < cls->method_count && i < MAX_CLASS_METHODS; i++) {
if (strlen(cls->methods[i].name) == (size_t)len &&
strncmp(cls->methods[i].name, name, len) == 0) {
return i;
}
}
if (cls->parent_class_idx >= 0 && cls->parent_class_idx < class_count) {
return find_class_method(cls->parent_class_idx, name, len);
}
return -1;
}
long allocate_object(int class_idx) {
if (class_idx < 0 || class_idx >= class_count || class_idx >= MAX_CLASSES) {
return 0;
}
if (object_count >= MAX_OBJECTS) {
error("Maximum number of objects reached");
return 0;
}
ClassDef *cls = &classes[class_idx];
Object *obj = &objects[object_count];
obj->class_idx = class_idx;
obj->ref_count = 1;
obj->marked_for_deletion = 0;
obj->field_data = (long*)malloc(cls->size * sizeof(long));
if (!obj->field_data) {
error("Failed to allocate object memory");
return 0;
}
for (int i = 0; i < cls->field_count && i < MAX_CLASS_FIELDS; i++) {
obj->field_data[cls->fields[i].offset] = cls->fields[i].default_value;
}
if (cls->parent_class_idx >= 0 && cls->parent_class_idx < class_count) {
ClassDef *parent = &classes[cls->parent_class_idx];
for (int i = 0; i < parent->field_count && i < MAX_CLASS_FIELDS; i++) {
obj->field_data[parent->fields[i].offset] = parent->fields[i].default_value;
}
}
object_count++;
return (long)obj;
}
void call_destructor(long obj_ptr) {
if (obj_ptr == 0) return;
Object *obj = (Object*)obj_ptr;
if (obj < objects || obj >= objects + MAX_OBJECTS) return;
if (obj->marked_for_deletion) return;
obj->marked_for_deletion = 1;
int class_idx = obj->class_idx;
if (class_idx < 0 || class_idx >= class_count || class_idx >= MAX_CLASSES) return;
ClassDef *cls = &classes[class_idx];
for (int i = 0; i < cls->method_count && i < MAX_CLASS_METHODS; i++) {
if (cls->methods[i].is_destructor) {
int func_idx = cls->methods[i].func_idx;
if (func_idx >= 0 && func_idx < func_cnt) {
int saved_pc = pc;
int saved_sp = sp;
int saved_bp = bp;
int saved_loc_cnt = loc_cnt;
long saved_ax = ax;
int saved_return_flag = return_flag;
if (sp >= MEM_SIZE || bp < 0 || bp >= MEM_SIZE) return;
memory[sp] = bp;
bp = sp++;
if (sp >= MEM_SIZE) return;
memory[sp++] = 0;
memory[sp++] = saved_loc_cnt;
if (sp >= MEM_SIZE) return;
memory[sp++] = obj_ptr;
int scan_pc = funcs[func_idx].params_start;
if (scan_pc < MAX_TOK && scan_pc < tk_idx && tokens[scan_pc].type != ')') {
if (tokens[scan_pc].type == Id) {
Token *param_name = &tokens[scan_pc];
if (loc_cnt < VAR_MAX) {
Symbol *sym = &locals[loc_cnt++];
int name_len = param_name->val;
if (name_len > 31) name_len = 31;
strncpy(sym->name, param_name->text, name_len);
sym->name[name_len] = 0;
sym->type = Int;
sym->addr = sp - 1;
sym->is_array = 0;
}
}
}
pc = funcs[func_idx].entry_point;
return_flag = 0;
ax = 0;
statement();
pc = saved_pc;
sp = saved_sp;
bp = saved_bp;
loc_cnt = saved_loc_cnt;
ax = saved_ax;
return_flag = saved_return_flag;
}
break;
}
}
}
void free_object(long obj_ptr) {
if (obj_ptr == 0) return;
Object *obj = (Object*)obj_ptr;
if (obj < objects || obj >= objects + MAX_OBJECTS) return;
call_destructor(obj_ptr);
if (obj->field_data) {
free(obj->field_data);
obj->field_data = NULL;
}
obj->class_idx = -1;
obj->ref_count = 0;
obj->marked_for_deletion = 0;
}
void link_class_methods() {
for (int c = 0; c < class_count && c < MAX_CLASSES; c++) {
ClassDef *cls = &classes[c];
for (int m = 0; m < cls->method_count && m < MAX_CLASS_METHODS; m++) {
ClassMethod *method = &cls->methods[m];
char full_name[64];
snprintf(full_name, 63, "%s_%s", cls->name, method->name);
extern int find_func(char *name, int len);
int func_idx = find_func(full_name, strlen(full_name));
if (func_idx >= 0) {
method->func_idx = func_idx;
}
}
}
}
void scan_classes() {
int i = 0;
while (i < MAX_TOK && i < tk_idx && tokens[i].type != 0) {
if (tokens[i].type == Class) {
i++;
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != Id) {
error("Expected class name");
return;
}
if (class_count >= MAX_CLASSES) {
error("Too many classes defined");
return;
}
ClassDef *cls = &classes[class_count];
Token *name = &tokens[i];
int name_len = name->val;
if (name_len > 31) name_len = 31;
strncpy(cls->name, name->text, name_len);
cls->name[name_len] = 0;
cls->parent_class_idx = -1;
cls->field_count = 0;
cls->method_count = 0;
cls->size = 0;
cls->token_start = i + 1;
i++;
if (i < MAX_TOK && i < tk_idx && tokens[i].type == ':') {
i++;
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != Id) {
error("Expected parent class name");
return;
}
Token *parent_name = &tokens[i];
int parent_idx = find_class(parent_name->text, parent_name->val);
if (parent_idx < 0) {
error("Parent class not found");
return;
}
cls->parent_class_idx = parent_idx;
i++;
}
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != '{') {
error("Expected '{' after class name");
return;
}
i++;
int field_offset = 0;
if (cls->parent_class_idx >= 0) {
field_offset = classes[cls->parent_class_idx].size;
}
while (i < MAX_TOK && i < tk_idx && tokens[i].type != '}') {
int is_static = 0;
if (tokens[i].type == Static) {
is_static = 1;
i++;
}
if (tokens[i].type == Constructor || tokens[i].type == Destructor) {
int is_constructor = (tokens[i].type == Constructor);
int is_destructor = (tokens[i].type == Destructor);
i++;
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != '(') {
error("Expected '(' after constructor/destructor");
return;
}
int func_start = i - 1;
int brace_count = 0;
while (i < MAX_TOK && i < tk_idx) {
if (tokens[i].type == '{') brace_count++;
if (tokens[i].type == '}') {
brace_count--;
if (brace_count == 0) {
i++;
break;
}
}
i++;
}
if (cls->method_count < MAX_CLASS_METHODS) {
ClassMethod *method = &cls->methods[cls->method_count];
if (is_constructor) {
strncpy(method->name, "constructor", 31);
} else {
strncpy(method->name, "destructor", 31);
}
method->func_idx = -1;
method->is_static = 0;
method->is_constructor = is_constructor;
method->is_destructor = is_destructor;
cls->method_count++;
}
continue;
}
int type = tokens[i].type;
if (type != Int && type != Char && type != Double && type != Void) {
int class_type_idx = find_class(tokens[i].text, tokens[i].val);
if (class_type_idx >= 0) {
type = Class;
} else {
i++;
continue;
}
}
i++;
while (i < MAX_TOK && i < tk_idx && tokens[i].type == '*') i++;
if (i >= MAX_TOK || i >= tk_idx || tokens[i].type != Id) {
i++;
continue;
}
Token *member_name = &tokens[i];
i++;
if (i < MAX_TOK && i < tk_idx && tokens[i].type == '(') {
if (cls->method_count < MAX_CLASS_METHODS) {
ClassMethod *method = &cls->methods[cls->method_count];
int name_len = member_name->val;
if (name_len > 31) name_len = 31;
strncpy(method->name, member_name->text, name_len);
method->name[name_len] = 0;
method->func_idx = -1;
method->is_static = is_static;
method->is_constructor = 0;
method->is_destructor = 0;
cls->method_count++;
}
int brace_count = 0;
while (i < MAX_TOK && i < tk_idx) {
if (tokens[i].type == '{') brace_count++;
if (tokens[i].type == '}') {
brace_count--;
if (brace_count == 0) {
i++;
break;
}
}
i++;
}
} else {
if (cls->field_count < MAX_CLASS_FIELDS) {
ClassField *field = &cls->fields[cls->field_count];
int name_len = member_name->val;
if (name_len > 31) name_len = 31;
strncpy(field->name, member_name->text, name_len);
field->name[name_len] = 0;
field->type = type;
field->default_value = 0;
field->offset = field_offset++;
if (i < MAX_TOK && i < tk_idx && tokens[i].type == '=') {
i++;
if (i < MAX_TOK && i < tk_idx) {
if (tokens[i].type == Num) {
field->default_value = tokens[i].val;
i++;
} else if (tokens[i].type == Null) {
field->default_value = 0;
i++;
}
}
}
cls->field_count++;
}
if (i < MAX_TOK && i < tk_idx && tokens[i].type == ';') {
i++;
}
}
}
cls->size = field_offset;
if (i < MAX_TOK && i < tk_idx && tokens[i].type == '}') {
i++;
}
class_count++;
} else {
i++;
}
}
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef OOP_H
#define OOP_H
int find_class(char *name, int len);
int find_class_field(int class_idx, char *name, int len);
int find_class_method(int class_idx, char *name, int len);
long allocate_object(int class_idx);
void free_object(long obj_ptr);
void call_destructor(long obj_ptr);
void scan_classes();
void link_class_methods();
#endif
+184 -2
View File
@@ -31,7 +31,59 @@ long factor() {
Token *t = &tokens[pc];
long val = 0;
if (t->type == Await) {
if (t->type == Null) {
pc++;
return 0;
}
else if (t->type == This) {
pc++;
Symbol *sym = find_local("this", 4) >= 0 ? &locals[find_local("this", 4)] : NULL;
if (sym) {
return memory[sym->addr];
}
return 0;
}
else if (t->type == New) {
pc++;
if (pc >= MAX_TOK || tokens[pc].type != Id) {
error("Expected class name after 'new'");
return 0;
}
Token *class_name = &tokens[pc];
pc++;
extern int find_class(char *name, int len);
int class_idx = find_class(class_name->text, class_name->val);
if (class_idx < 0) {
error("Unknown class");
return 0;
}
if (pc >= MAX_TOK || tokens[pc].type != '(') {
error("Expected '(' after class name");
return 0;
}
pc++;
if (pc < MAX_TOK && tokens[pc].type != ')') {
do {
expression();
if (pc >= MAX_TOK) return 0;
} while (tokens[pc].type == ',' && pc++);
}
match(')');
extern long allocate_object(int class_idx);
long obj_ptr = allocate_object(class_idx);
if (obj_ptr == 0) {
error("Failed to allocate object");
return 0;
}
return obj_ptr;
}
else if (t->type == Await) {
pc++;
match('(');
long coro_id = expression();
@@ -263,7 +315,137 @@ long unary() {
pc++;
return -unary();
}
return factor();
long val = factor();
while (pc < MAX_TOK && tokens[pc].type == '.') {
pc++;
if (pc >= MAX_TOK || tokens[pc].type != Id) {
error("Expected field or method name after '.'");
return 0;
}
Token *member = &tokens[pc];
pc++;
if (val == 0) {
error("Null pointer dereference");
return 0;
}
Object *obj = (Object*)val;
if (obj < objects || obj >= objects + MAX_OBJECTS) {
error("Invalid object pointer");
return 0;
}
int class_idx = obj->class_idx;
if (class_idx < 0 || class_idx >= class_count) {
error("Invalid class index");
return 0;
}
if (pc < MAX_TOK && tokens[pc].type == '(') {
extern int find_class_method(int class_idx, char *name, int len);
int method_idx = find_class_method(class_idx, member->text, member->val);
if (method_idx < 0) {
error("Unknown method");
return 0;
}
int func_idx = classes[class_idx].methods[method_idx].func_idx;
if (func_idx < 0 || func_idx >= func_cnt) {
error("Invalid method function index");
return 0;
}
pc++;
long args[10];
int argc = 0;
args[argc++] = val;
if (pc < MAX_TOK && tokens[pc].type != ')') {
do {
if (argc >= 10) break;
args[argc++] = expression();
if (pc >= MAX_TOK) return 0;
} while (tokens[pc].type == ',' && pc++);
}
match(')');
int saved_pc = pc;
int saved_sp = sp;
int saved_bp = bp;
int saved_loc_cnt = loc_cnt;
if (sp >= MEM_SIZE || bp < 0 || bp >= MEM_SIZE) return 0;
memory[sp] = bp;
bp = sp++;
if (sp >= MEM_SIZE) return 0;
memory[sp++] = 0;
memory[sp++] = saved_loc_cnt;
for (int i = 0; i < argc && i < 10; i++) {
if (sp >= MEM_SIZE) break;
memory[sp++] = args[i];
}
int scan_pc = funcs[func_idx].params_start;
int param_idx = 0;
while (scan_pc < MAX_TOK && scan_pc < tk_idx && tokens[scan_pc].type != ')') {
if (tokens[scan_pc].type == Int || tokens[scan_pc].type == Char ||
tokens[scan_pc].type == Double || tokens[scan_pc].type == Id) {
scan_pc++;
while (scan_pc < MAX_TOK && tokens[scan_pc].type == '*') scan_pc++;
if (scan_pc < MAX_TOK && tokens[scan_pc].type == Id && param_idx < argc && loc_cnt < VAR_MAX) {
Token *param_name = &tokens[scan_pc];
Symbol *sym = &locals[loc_cnt++];
int name_len = param_name->val;
if (name_len > 31) name_len = 31;
strncpy(sym->name, param_name->text, name_len);
sym->name[name_len] = 0;
sym->type = Int;
sym->addr = saved_sp + 3 + param_idx;
sym->is_array = 0;
param_idx++;
}
}
scan_pc++;
}
pc = funcs[func_idx].entry_point;
return_flag = 0;
statement();
val = ax;
ax = 0;
return_flag = 0;
pc = saved_pc;
sp = saved_sp;
bp = saved_bp;
loc_cnt = saved_loc_cnt;
} else {
extern int find_class_field(int class_idx, char *name, int len);
int field_idx = find_class_field(class_idx, member->text, member->val);
if (field_idx < 0) {
error("Unknown field");
return 0;
}
int offset = classes[class_idx].fields[field_idx].offset;
if (offset < 0 || offset >= classes[class_idx].size) {
error("Invalid field offset");
return 0;
}
val = obj->field_data[offset];
}
}
return val;
}
long term() {
+9
View File
@@ -44,6 +44,15 @@ void tokenize(char *src) {
else if (!strcmp(buf, "continue")) t->type = Continue;
else if (!strcmp(buf, "async")) t->type = Async;
else if (!strcmp(buf, "await")) t->type = Await;
else if (!strcmp(buf, "class")) t->type = Class;
else if (!strcmp(buf, "new")) t->type = New;
else if (!strcmp(buf, "constructor")) t->type = Constructor;
else if (!strcmp(buf, "destructor")) t->type = Destructor;
else if (!strcmp(buf, "static")) t->type = Static;
else if (!strcmp(buf, "super")) t->type = Super;
else if (!strcmp(buf, "this")) t->type = This;
else if (!strcmp(buf, "void")) t->type = Void;
else if (!strcmp(buf, "null")) t->type = Null;
else t->type = Id;
t->val = len;
+44 -1
View File
@@ -9,7 +9,8 @@
enum {
Num = 128, Dbl, Str, Id, Int, Char, Double, Else, If, While, Return, Printf,
Assign, Eq, Ne, Lt, Gt, Le, Ge, Or, And, Inc, Dec, Break, Continue, Async, Await
Assign, Eq, Ne, Lt, Gt, Le, Ge, Or, And, Inc, Dec, Break, Continue, Async, Await,
Class, New, Constructor, Destructor, Static, Super, This, Void, Null
};
typedef struct {
@@ -59,6 +60,44 @@ typedef struct Coroutine {
long memory_saved[MEM_SIZE];
} Coroutine;
#define MAX_CLASSES 100
#define MAX_CLASS_FIELDS 50
#define MAX_CLASS_METHODS 50
#define MAX_OBJECTS 1000
typedef struct {
char name[32];
int type;
long default_value;
int offset;
} ClassField;
typedef struct {
char name[32];
int func_idx;
int is_static;
int is_constructor;
int is_destructor;
} ClassMethod;
typedef struct {
char name[32];
int parent_class_idx;
ClassField fields[MAX_CLASS_FIELDS];
int field_count;
ClassMethod methods[MAX_CLASS_METHODS];
int method_count;
int size;
int token_start;
} ClassDef;
typedef struct {
int class_idx;
long *field_data;
int ref_count;
int marked_for_deletion;
} Object;
extern Token tokens[MAX_TOK];
extern int tk_idx;
extern int pc;
@@ -78,5 +117,9 @@ extern long ax;
extern int return_flag;
extern Coroutine coroutines[MAX_COROUTINES];
extern int coroutine_count;
extern ClassDef classes[MAX_CLASSES];
extern int class_count;
extern Object objects[MAX_OBJECTS];
extern int object_count;
#endif