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;
|
|
|
|
|
}
|
2025-11-23 13:53:36 +01:00
|
|
|
else if (t->type == Dbl) {
|
|
|
|
|
pc++;
|
|
|
|
|
union { double d; long l; } u;
|
|
|
|
|
u.d = t->dval;
|
|
|
|
|
return u.l;
|
|
|
|
|
}
|
2025-11-22 22:22:43 +01:00
|
|
|
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-23 15:07:19 +01:00
|
|
|
int call_pc = pc;
|
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(')');
|
|
|
|
|
|
|
|
|
|
int ret_pc = pc;
|
2025-11-23 15:07:19 +01:00
|
|
|
int old_loc_cnt = loc_cnt;
|
|
|
|
|
int old_bp = bp;
|
|
|
|
|
|
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-23 15:07:19 +01:00
|
|
|
memory[sp++] = old_loc_cnt;
|
|
|
|
|
|
|
|
|
|
int param_base = sp;
|
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
|
|
|
|
2025-11-23 15:07:19 +01:00
|
|
|
int scan_pc = funcs[f_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) {
|
|
|
|
|
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 = param_base + param_idx;
|
|
|
|
|
sym->is_array = 0;
|
|
|
|
|
param_idx++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
scan_pc++;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-22 22:22:43 +01:00
|
|
|
pc = funcs[f_idx].entry_point;
|
2025-11-23 15:07:19 +01:00
|
|
|
return_flag = 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
statement();
|
|
|
|
|
|
|
|
|
|
val = ax;
|
2025-11-23 15:07:19 +01:00
|
|
|
ax = 0;
|
|
|
|
|
return_flag = 0;
|
2025-11-22 22:22:43 +01:00
|
|
|
|
2025-11-23 15:07:19 +01:00
|
|
|
loc_cnt = old_loc_cnt;
|
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];
|
2025-11-23 15:07:19 +01:00
|
|
|
if (sp + 1 < MEM_SIZE) ret_pc = memory[sp + 1];
|
2025-11-22 22:22:43 +01:00
|
|
|
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-23 00:17:01 +01:00
|
|
|
if (pc < MAX_TOK && (tokens[pc].type == Inc || tokens[pc].type == Dec)) {
|
|
|
|
|
long val = memory[sym->addr];
|
|
|
|
|
if (tokens[pc].type == Inc) {
|
|
|
|
|
memory[sym->addr]++;
|
|
|
|
|
} else {
|
|
|
|
|
memory[sym->addr]--;
|
|
|
|
|
}
|
|
|
|
|
pc++;
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
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-23 00:17:01 +01:00
|
|
|
if (tokens[pc].type == Inc || tokens[pc].type == Dec) {
|
|
|
|
|
int op = tokens[pc++].type;
|
|
|
|
|
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++;
|
|
|
|
|
long addr = locals[idx].addr;
|
|
|
|
|
if (op == Inc) {
|
|
|
|
|
memory[addr]++;
|
|
|
|
|
} else {
|
|
|
|
|
memory[addr]--;
|
|
|
|
|
}
|
|
|
|
|
return memory[addr];
|
|
|
|
|
}
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-23 13:53:36 +01:00
|
|
|
long logical_and() {
|
|
|
|
|
long val = relational();
|
|
|
|
|
while (pc < MAX_TOK && tokens[pc].type == And) {
|
|
|
|
|
pc++;
|
|
|
|
|
long val2 = relational();
|
|
|
|
|
val = val && val2;
|
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long logical_or() {
|
|
|
|
|
long val = logical_and();
|
|
|
|
|
while (pc < MAX_TOK && tokens[pc].type == Or) {
|
|
|
|
|
pc++;
|
|
|
|
|
long val2 = logical_and();
|
|
|
|
|
val = val || val2;
|
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-22 22:22:43 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-23 13:53:36 +01:00
|
|
|
return logical_or();
|
2025-11-22 22:22:43 +01:00
|
|
|
}
|