2025-11-22 22:22:43 +01:00
|
|
|
#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() {
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
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) {
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc + 1 >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc + 1].type == '(') {
|
|
|
|
|
int nf_idx = find_native_func(t->text, t->val);
|
|
|
|
|
|
|
|
|
|
if (nf_idx != -1) {
|
2025-11-22 23:15:15 +01:00
|
|
|
if (nf_idx < 0 || nf_idx >= native_func_cnt) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
pc += 2;
|
|
|
|
|
long args[10];
|
|
|
|
|
int argc = 0;
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc].type != ')') {
|
|
|
|
|
do {
|
2025-11-22 23:15:15 +01:00
|
|
|
if (argc >= 10) break;
|
2025-11-22 22:22:43 +01:00
|
|
|
args[argc++] = expression();
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
} 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");
|
2025-11-22 23:15:15 +01:00
|
|
|
if (f_idx < 0 || f_idx >= func_cnt) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
pc += 2;
|
|
|
|
|
|
|
|
|
|
int old_bp = bp;
|
|
|
|
|
long args[10];
|
|
|
|
|
int argc = 0;
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc].type != ')') {
|
|
|
|
|
do {
|
2025-11-22 23:15:15 +01:00
|
|
|
if (argc >= 10) break;
|
2025-11-22 22:22:43 +01:00
|
|
|
args[argc++] = expression();
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
} while (tokens[pc].type == ',' && pc++);
|
|
|
|
|
}
|
|
|
|
|
match(')');
|
|
|
|
|
|
|
|
|
|
int ret_pc = pc;
|
2025-11-22 23:15:15 +01:00
|
|
|
if (sp >= MEM_SIZE) return 0;
|
|
|
|
|
if (bp < 0 || bp >= MEM_SIZE) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
memory[sp] = bp; bp = sp++;
|
2025-11-22 23:15:15 +01:00
|
|
|
if (sp >= MEM_SIZE) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
memory[sp++] = ret_pc;
|
2025-11-22 23:15:15 +01:00
|
|
|
for(int i=0; i<argc; i++) {
|
|
|
|
|
if (sp >= MEM_SIZE) break;
|
|
|
|
|
memory[sp++] = args[i];
|
|
|
|
|
}
|
2025-11-22 22:22:43 +01:00
|
|
|
|
|
|
|
|
pc = funcs[f_idx].entry_point;
|
|
|
|
|
statement();
|
|
|
|
|
|
|
|
|
|
val = ax;
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (bp < 0 || bp >= MEM_SIZE) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
sp = bp;
|
2025-11-22 23:15:15 +01:00
|
|
|
if (sp < 0 || sp >= MEM_SIZE) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
bp = memory[sp];
|
|
|
|
|
pc = ret_pc;
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int idx = find_local(t->text, t->val);
|
|
|
|
|
if (idx == -1) error("Undefined variable");
|
2025-11-22 23:15:15 +01:00
|
|
|
if (idx < 0 || idx >= loc_cnt) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
pc++;
|
|
|
|
|
|
|
|
|
|
Symbol *sym = &locals[idx];
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc].type == '[') {
|
|
|
|
|
pc++;
|
|
|
|
|
long start_or_index = expression();
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc].type == ':') {
|
|
|
|
|
pc++;
|
|
|
|
|
long end = expression();
|
|
|
|
|
match(']');
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (sym->addr < 0 || sym->addr >= MEM_SIZE) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
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(']');
|
2025-11-22 23:15:15 +01:00
|
|
|
long addr = sym->addr + start_or_index;
|
|
|
|
|
if (addr < 0 || addr >= MEM_SIZE) return 0;
|
|
|
|
|
return memory[addr];
|
2025-11-22 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sym->is_array) {
|
|
|
|
|
return sym->addr;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (sym->addr < 0 || sym->addr >= MEM_SIZE) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
return memory[sym->addr];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long unary() {
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc].type == '*') {
|
|
|
|
|
pc++;
|
|
|
|
|
int addr = unary();
|
|
|
|
|
if (addr > MEM_SIZE * 8 || addr < 0) {
|
|
|
|
|
return *(char*)addr;
|
|
|
|
|
}
|
2025-11-22 23:15:15 +01:00
|
|
|
if (addr < 0 || addr >= MEM_SIZE) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
return memory[addr];
|
|
|
|
|
}
|
|
|
|
|
else if (tokens[pc].type == '&') {
|
|
|
|
|
pc++;
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
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");
|
2025-11-22 23:15:15 +01:00
|
|
|
if (idx < 0 || idx >= loc_cnt) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
pc++;
|
|
|
|
|
return locals[idx].addr;
|
|
|
|
|
}
|
|
|
|
|
else if (tokens[pc].type == '-') {
|
|
|
|
|
pc++;
|
|
|
|
|
return -unary();
|
|
|
|
|
}
|
|
|
|
|
return factor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long term() {
|
|
|
|
|
long val = unary();
|
2025-11-22 23:15:15 +01:00
|
|
|
while (pc < MAX_TOK && (tokens[pc].type == '*' || tokens[pc].type == '/')) {
|
2025-11-22 22:22:43 +01:00
|
|
|
int op = tokens[pc++].type;
|
|
|
|
|
long val2 = unary();
|
|
|
|
|
if (op == '*') val = val * val2;
|
2025-11-22 23:15:15 +01:00
|
|
|
else {
|
|
|
|
|
if (val2 != 0) val = val / val2;
|
|
|
|
|
else val = 0;
|
|
|
|
|
}
|
2025-11-22 22:22:43 +01:00
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long add() {
|
|
|
|
|
long val = term();
|
2025-11-22 23:15:15 +01:00
|
|
|
while (pc < MAX_TOK && (tokens[pc].type == '+' || tokens[pc].type == '-')) {
|
2025-11-22 22:22:43 +01:00
|
|
|
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();
|
2025-11-22 23:15:15 +01:00
|
|
|
while (pc < MAX_TOK && tokens[pc].type >= Eq && tokens[pc].type <= Ge) {
|
2025-11-22 22:22:43 +01:00
|
|
|
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() {
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc].type == '*') {
|
|
|
|
|
int save_pc = pc;
|
|
|
|
|
unary();
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc].type == Id) {
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc + 1 >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc+1].type == '[') {
|
|
|
|
|
int idx = find_local(tokens[pc].text, tokens[pc].val);
|
|
|
|
|
if (idx == -1) error("Assign to unknown var");
|
2025-11-22 23:15:15 +01:00
|
|
|
if (idx < 0 || idx >= loc_cnt) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
pc += 2;
|
|
|
|
|
long start_or_index = expression();
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc].type == ':') {
|
|
|
|
|
pc++;
|
|
|
|
|
long end = expression();
|
|
|
|
|
match(']');
|
|
|
|
|
|
2025-11-22 23:15:15 +01:00
|
|
|
if (locals[idx].addr < 0 || locals[idx].addr >= MEM_SIZE) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
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;
|
2025-11-22 23:15:15 +01:00
|
|
|
if (pc >= MAX_TOK) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
if (tokens[pc].type == '=') {
|
|
|
|
|
pc++;
|
|
|
|
|
long val = expression();
|
2025-11-22 23:15:15 +01:00
|
|
|
long target_addr = addr + start_or_index;
|
|
|
|
|
if (target_addr >= 0 && target_addr < MEM_SIZE) {
|
|
|
|
|
memory[target_addr] = val;
|
|
|
|
|
}
|
2025-11-22 22:22:43 +01:00
|
|
|
return val;
|
|
|
|
|
}
|
2025-11-22 23:15:15 +01:00
|
|
|
long read_addr = addr + start_or_index;
|
|
|
|
|
if (read_addr < 0 || read_addr >= MEM_SIZE) return 0;
|
|
|
|
|
return memory[read_addr];
|
2025-11-22 22:22:43 +01:00
|
|
|
} else if (tokens[pc+1].type == '=') {
|
|
|
|
|
int idx = find_local(tokens[pc].text, tokens[pc].val);
|
|
|
|
|
if (idx == -1) error("Assign to unknown var");
|
2025-11-22 23:15:15 +01:00
|
|
|
if (idx < 0 || idx >= loc_cnt) return 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
pc += 2;
|
|
|
|
|
long val = expression();
|
2025-11-22 23:15:15 +01:00
|
|
|
if (locals[idx].addr >= 0 && locals[idx].addr < MEM_SIZE) {
|
|
|
|
|
memory[locals[idx].addr] = val;
|
|
|
|
|
}
|
2025-11-22 22:22:43 +01:00
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return relational();
|
|
|
|
|
}
|