mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
278 lines
7.9 KiB
R
278 lines
7.9 KiB
R
#include "Machine.h"
|
|
#include "Cons.h"
|
|
#include "Lambda.h"
|
|
#include "Boolean.h"
|
|
#include "Nil.h"
|
|
#include "defs.h"
|
|
#include "string.h"
|
|
#include "Error.h"
|
|
//#include "debug.h"
|
|
|
|
string GlobalGetKey (void *ele, void *data)
|
|
{
|
|
return [[((Cons*) ele) car] printForm];
|
|
}
|
|
|
|
void GlobalFree (void *ele, void *data)
|
|
{
|
|
return;
|
|
}
|
|
|
|
@implementation Machine
|
|
|
|
- (id) init
|
|
{
|
|
self = [super init];
|
|
state.program = nil;
|
|
state.pc = 0;
|
|
value = nil;
|
|
state.cont = nil;
|
|
state.env = nil;
|
|
state.literals = nil;
|
|
state.proc = nil;
|
|
state.stack = [Nil nil];
|
|
state.lineinfo = nil;
|
|
globals = Hash_NewTable(1024, GlobalGetKey, GlobalFree, nil);
|
|
all_globals = [Nil nil];
|
|
return self;
|
|
}
|
|
|
|
- (void) addGlobal: (Symbol*) sym value: (SchemeObject*) val
|
|
{
|
|
local Cons *c = cons(sym, val);
|
|
Hash_Add(globals, c);
|
|
all_globals = cons(c, all_globals);
|
|
}
|
|
|
|
- (void) loadCode: (CompiledCode*) code
|
|
{
|
|
state.program = [code code];
|
|
state.literals = [code literals];
|
|
state.lineinfo = [code lineinfo];
|
|
state.pc = 0;
|
|
}
|
|
|
|
- (void) environment: (Frame*) e
|
|
{
|
|
state.env = e;
|
|
}
|
|
|
|
- (void) continuation: (Continuation*) c
|
|
{
|
|
state.cont = c;
|
|
}
|
|
|
|
- (void) value: (SchemeObject*) v
|
|
{
|
|
value = v;
|
|
}
|
|
|
|
- (SchemeObject*) value
|
|
{
|
|
return value;
|
|
}
|
|
|
|
- (Continuation*) continuation
|
|
{
|
|
return state.cont;
|
|
}
|
|
|
|
- (SchemeObject*) stack
|
|
{
|
|
return state.stack;
|
|
}
|
|
|
|
- (void) stack: (SchemeObject*) o
|
|
{
|
|
state.stack = o;
|
|
}
|
|
|
|
- (state_t *) state
|
|
{
|
|
return &state;
|
|
}
|
|
|
|
- (void) state: (state_t *) st
|
|
{
|
|
state.program = st.program;
|
|
state.pc = st.pc;
|
|
state.literals = st.literals;
|
|
state.stack = st.stack;
|
|
state.cont = st.cont;
|
|
state.env = st.env;
|
|
state.proc = st.proc;
|
|
state.lineinfo = st.lineinfo;
|
|
}
|
|
|
|
- (void) procedure: (Procedure*) pr
|
|
{
|
|
state.proc = pr;
|
|
}
|
|
|
|
- (SchemeObject*) run
|
|
{
|
|
local int opcode;
|
|
local int operand;
|
|
local SchemeObject *res;
|
|
while (1) {
|
|
if (value && [value isError]) {
|
|
dprintf("Error: %s[%s]\n", [value description], [value printForm]);
|
|
return value;
|
|
}
|
|
opcode = state.program[state.pc].opcode;
|
|
operand = state.program[state.pc].operand;
|
|
state.pc = state.pc + 1;
|
|
|
|
|
|
switch (opcode) {
|
|
case PUSH:
|
|
if (value) {
|
|
dprintf("Push: %s\n", [value printForm]);
|
|
} else {
|
|
dprintf("Push: NULL!!!!\n");
|
|
}
|
|
state.stack = cons(value, state.stack);
|
|
break;
|
|
case POP:
|
|
value = [(Cons*) state.stack car];
|
|
if (value) {
|
|
dprintf("Pop: %s\n", [value printForm]);
|
|
} else {
|
|
dprintf("Pop: NULL!!!!\n");
|
|
}
|
|
state.stack = [(Cons*) state.stack cdr];
|
|
break;
|
|
case MAKECLOSURE:
|
|
dprintf("Makeclosure\n");
|
|
value = [Lambda newWithCode: (CompiledCode*) value
|
|
environment: state.env];
|
|
break;
|
|
case MAKECONT:
|
|
dprintf("Makecont\n");
|
|
state.cont = [Continuation newWithState: &state
|
|
pc: operand];
|
|
state.stack = [Nil nil];
|
|
break;
|
|
case LOADENV:
|
|
dprintf("Loadenv\n");
|
|
value = state.env;
|
|
break;
|
|
case LOADLITS:
|
|
dprintf("Loadlits\n");
|
|
value = state.literals;
|
|
break;
|
|
case MAKEENV:
|
|
dprintf("Makeenv\n");
|
|
state.env = [Frame newWithSize: operand link: state.env];
|
|
break;
|
|
case POPENV:
|
|
dprintf("Popenv\n");
|
|
state.env = [state.env getLink];
|
|
case GET:
|
|
value = [(Frame*) value get: operand];
|
|
dprintf("Get: %i --> %s\n", operand, [value printForm]);
|
|
break;
|
|
case SET:
|
|
[(Frame*) value set: operand to: [(Cons*) state.stack car]];
|
|
dprintf("Set: %i --> %s\n", operand, [[(Cons*) state.stack car] printForm]);
|
|
state.stack = [(Cons*) state.stack cdr];
|
|
break;
|
|
case SETREST:
|
|
[(Frame*) value set: operand to: state.stack];
|
|
dprintf("Setrest: %i --> %s\n", operand, [state.stack printForm]);
|
|
state.stack = [Nil nil];
|
|
break;
|
|
case SETSTACK:
|
|
dprintf("Setstack: %s\n", [value printForm]);
|
|
state.stack = value;
|
|
break;
|
|
case GETLINK:
|
|
dprintf("Getlink\n");
|
|
value = [(Frame*) value getLink];
|
|
break;
|
|
case GETGLOBAL:
|
|
dprintf("Getglobal: %s\n", [value printForm]);
|
|
res = [((Cons*) Hash_Find(globals, [value printForm])) cdr];
|
|
if (!res) {
|
|
return [Error type: "binding"
|
|
message: sprintf("Undefined binding: %s",
|
|
[value printForm])
|
|
by: self];
|
|
}
|
|
value = res;
|
|
dprintf(" --> %s\n", [value printForm]);
|
|
break;
|
|
case SETGLOBAL:
|
|
dprintf("Setglobal: %s\n", [value printForm]);
|
|
[self addGlobal: (Symbol*) value value: [(Cons*) state.stack car]];
|
|
state.stack = [(Cons*) state.stack cdr];
|
|
break;
|
|
case CALL:
|
|
dprintf("Call\n");
|
|
[SchemeObject collectCheckPoint];
|
|
if (![value isKindOfClass: [Procedure class]]) {
|
|
return [Error type: "call"
|
|
message:
|
|
sprintf("Attempted to apply non-procedure: %s. Arguments were: %s",
|
|
[value printForm], [state.stack printForm])
|
|
by: self];
|
|
}
|
|
[(Procedure*) value invokeOnMachine: self];
|
|
break;
|
|
case RETURN:
|
|
dprintf("Return: %s\n", [value printForm]);
|
|
if (!state.cont) {
|
|
return value;
|
|
} else {
|
|
[state.cont restoreOnMachine: self];
|
|
}
|
|
break;
|
|
case IFFALSE:
|
|
dprintf("Iffalse: %s\n", [value printForm]);
|
|
if (value == [Boolean falseConstant]) {
|
|
state.pc = operand;
|
|
}
|
|
break;
|
|
case GOTO:
|
|
dprintf("Goto: %i\n", operand);
|
|
state.pc = operand;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (string) source
|
|
{
|
|
if (state.lineinfo) {
|
|
return [state.lineinfo[state.pc-1].sourcefile stringValue];
|
|
} else {
|
|
return [super source];
|
|
}
|
|
}
|
|
|
|
- (int) line
|
|
{
|
|
if (state.lineinfo) {
|
|
return state.lineinfo[state.pc-1].linenumber;
|
|
} else {
|
|
return [super line];
|
|
}
|
|
}
|
|
|
|
- (void) markReachable
|
|
{
|
|
[state.literals mark];
|
|
[state.stack mark];
|
|
[state.cont mark];
|
|
[state.env mark];
|
|
[state.proc mark];
|
|
[value mark];
|
|
[all_globals mark];
|
|
}
|
|
|
|
- (void) reset
|
|
{
|
|
state.stack = [Nil nil];
|
|
}
|
|
@end
|
|
|