#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() {
if (pc >= MAX_TOK) return 0;
Token *t = &tokens[pc];
long val = 0;
if (t->type == Num) {
pc++;
return t->val;
}
else if (t->type == Dbl) {
pc++;
union { double d; long l; } u;
u.d = t->dval;
return u.l;
}
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 (pc + 1 >= MAX_TOK) return 0;
if (tokens[pc + 1].type == '(') {
int nf_idx = find_native_func(t->text, t->val);
if (nf_idx != -1) {
if (nf_idx < 0 || nf_idx >= native_func_cnt) return 0;
pc += 2;
long args[10];
int argc = 0;
if (pc >= MAX_TOK) return 0;
if (tokens[pc].type != ')') {
do {
if (argc >= 10) break;
args[argc++] = expression();
if (pc >= MAX_TOK) return 0;
} 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");
if (f_idx < 0 || f_idx >= func_cnt) return 0;
int call_pc = pc;
pc += 2;
long args[10];
int argc = 0;
if (pc >= MAX_TOK) return 0;
if (tokens[pc].type != ')') {
do {
if (argc >= 10) break;
args[argc++] = expression();
if (pc >= MAX_TOK) return 0;
} while (tokens[pc].type == ',' && pc++);
}
match(')');
int ret_pc = pc;
int old_loc_cnt = loc_cnt;
int old_bp = bp;
if (sp >= MEM_SIZE) return 0;
if (bp < 0 || bp >= MEM_SIZE) return 0;
memory[sp] = bp; bp = sp++;
if (sp >= MEM_SIZE) return 0;
memory[sp++] = ret_pc;
memory[sp++] = old_loc_cnt;
int param_base = sp;
for(int i=0; i<argc; i++) {
if (sp >= MEM_SIZE) break;
memory[sp++] = args[i];
}
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++;
}
pc = funcs[f_idx].entry_point;
return_flag = 0;
statement();
val = ax;
ax = 0;
return_flag = 0;
loc_cnt = old_loc_cnt;
if (bp < 0 || bp >= MEM_SIZE) return 0;
sp = bp;
if (sp < 0 || sp >= MEM_SIZE) return 0;
bp = memory[sp];
if (sp + 1 < MEM_SIZE) ret_pc = memory[sp + 1];
pc = ret_pc;
return val;
}
else {
int idx = find_local(t->text, t->val);
if (idx == -1) error("Undefined variable");
if (idx < 0 || idx >= loc_cnt) return 0;
pc++;
Symbol *sym = &locals[idx];
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;
}
if (pc >= MAX_TOK) return 0;
if (tokens[pc].type == '[') {
pc++;
long start_or_index = expression();
if (pc >= MAX_TOK) return 0;
if (tokens[pc].type == ':') {
pc++;
long end = expression();
match(']');
if (sym->addr < 0 || sym->addr >= MEM_SIZE) return 0;
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(']');
long addr = sym->addr + start_or_index;
if (addr < 0 || addr >= MEM_SIZE) return 0;
return memory[addr];
}
}
if (sym->is_array) {
return sym->addr;
}
if (sym->addr < 0 || sym->addr >= MEM_SIZE) return 0;
return memory[sym->addr];
}
}
return 0;
}
long unary() {
if (pc >= MAX_TOK) return 0;
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];
}
if (tokens[pc].type == '*') {
pc++;
int addr = unary();
if (addr > MEM_SIZE * 8 || addr < 0) {
return *(char*)addr;
}
if (addr < 0 || addr >= MEM_SIZE) return 0;
return memory[addr];
}
else if (tokens[pc].type == '&') {
pc++;
if (pc >= MAX_TOK) return 0;
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");
if (idx < 0 || idx >= loc_cnt) return 0;
pc++;
return locals[idx].addr;
}
else if (tokens[pc].type == '-') {
pc++;
return -unary();
}
return factor();
}
long term() {
long val = unary();
while (pc < MAX_TOK && (tokens[pc].type == '*' || tokens[pc].type == '/')) {
int op = tokens[pc++].type;
long val2 = unary();
if (op == '*') val = val * val2;
else {
if (val2 != 0) val = val / val2;
else val = 0;
}
}
return val;
}
long add() {
long val = term();
while (pc < MAX_TOK && (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 (pc < MAX_TOK && 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 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;
}
long expression() {
if (pc >= MAX_TOK) return 0;
if (tokens[pc].type == '*') {
int save_pc = pc;
unary();
if (pc >= MAX_TOK) return 0;
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 (pc >= MAX_TOK) return 0;
if (tokens[pc].type == Id) {
if (pc + 1 >= MAX_TOK) return 0;
if (tokens[pc+1].type == '[') {
int idx = find_local(tokens[pc].text, tokens[pc].val);
if (idx == -1) error("Assign to unknown var");
if (idx < 0 || idx >= loc_cnt) return 0;
pc += 2;
long start_or_index = expression();
if (pc >= MAX_TOK) return 0;
if (tokens[pc].type == ':') {
pc++;
long end = expression();
match(']');
if (locals[idx].addr < 0 || locals[idx].addr >= MEM_SIZE) return 0;
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 (pc >= MAX_TOK) return 0;
if (tokens[pc].type == '=') {
pc++;
long val = expression();
long target_addr = addr + start_or_index;
if (target_addr >= 0 && target_addr < MEM_SIZE) {
memory[target_addr] = val;
}
return val;
}
long read_addr = addr + start_or_index;
if (read_addr < 0 || read_addr >= MEM_SIZE) return 0;
return memory[read_addr];
} else if (tokens[pc+1].type == '=') {
int idx = find_local(tokens[pc].text, tokens[pc].val);
if (idx == -1) error("Assign to unknown var");
if (idx < 0 || idx >= loc_cnt) return 0;
pc += 2;
long val = expression();
if (locals[idx].addr >= 0 && locals[idx].addr < MEM_SIZE) {
memory[locals[idx].addr] = val;
}
return val;
}
}
return logical_or();
}