home *** CD-ROM | disk | FTP | other *** search
- /* bobint.c - bytecode interpreter */
- /*
- Copyright (c) 1991, by David Michael Betz
- All rights reserved
- */
-
- #include <setjmp.h>
- #include "bob.h"
-
- #define iszero(x) ((x)->v_type == DT_INTEGER && (x)->v.v_integer == 0)
- #define istrue(x) ((x)->v_type != DT_NIL && !iszero(x))
-
- /* global variables */
- unsigned char *cbase; /* the base code address */
- unsigned char *pc; /* the program counter */
- VECTOR *code; /* the current code vector */
- VALUE *stkbase; /* the runtime stack */
- VALUE *stktop; /* the top of the stack */
- VALUE *sp; /* the stack pointer */
- VALUE *fp; /* the frame pointer */
- int trace=0; /* variable to control tracing */
-
- /* external variables */
- extern VALUE symbols;
- extern jmp_buf error_trap;
-
- /* forward declarations */
- char *typename();
-
- /* execute - execute a bytecode function */
- int execute(name)
- char *name;
- {
- DICT_ENTRY *sym;
-
- /* setup an error trap handler */
- if (setjmp(error_trap) != 0)
- return (FALSE);
-
- /* lookup the symbol */
- if ((sym = findentry(&symbols,name)) == NULL)
- return (FALSE);
-
- /* dispatch on its data type */
- switch (sym->de_value.v_type) {
- case DT_CODE:
- (*sym->de_value.v.v_code)(0);
- return (TRUE);
- case DT_BYTECODE:
- interpret(sym->de_value.v.v_vector);
- return (TRUE);
- }
- return (FALSE);
- }
-
- /* interpret - interpret bytecode instructions */
- int interpret(fcn)
- VECTOR *fcn;
- {
- register int pcoff,n;
- register OBJECT *obj;
- VALUE *topframe,val;
- STRING *s1,*s2,*sn;
-
- /* initialize */
- sp = fp = stktop;
- cbase = pc = fcn->vec_data[0].v.v_string->str_data;
- code = fcn;
-
- /* make a dummy call frame */
- check(4);
- push_bytecode(code);
- push_integer(0);
- push_integer(0);
- push_integer(0);
- fp = topframe = sp;
-
- /* execute each instruction */
- for (;;) {
- if (trace) {
- check(1);
- push_bytecode(code);
- decode_instruction(sp,pc-strgetdata(vecgetelement(sp,0)));
- ++sp;
- }
- switch (*pc++) {
- case OP_CALL:
- n = *pc++;
- switch (sp[n].v_type) {
- case DT_CODE:
- (*sp[n].v.v_code)(n);
- break;
- case DT_BYTECODE:
- check(3);
- code = sp[n].v.v_vector;
- push_integer(n);
- push_integer(stktop - fp);
- push_integer(pc - cbase);
- cbase = pc = code->vec_data[0].v.v_string->str_data;
- fp = sp;
- break;
- default:
- error("Call to non-procedure, Type %s",
- typename(sp[n].v_type));
- return;
- }
- break;
- case OP_RETURN:
- if (fp == topframe) return;
- val = *sp;
- sp = fp;
- pcoff = fp[0].v.v_integer;
- n = fp[2].v.v_integer;
- fp = stktop - fp[1].v.v_integer;
- code = fp[fp[2].v.v_integer+3].v.v_vector;
- cbase = code->vec_data[0].v.v_string->str_data;
- pc = cbase + pcoff;
- sp += n + 3;
- *sp = val;
- break;
- case OP_REF:
- *sp = code->vec_data[*pc++].v.v_var->de_value;
- break;
- case OP_SET:
- code->vec_data[*pc++].v.v_var->de_value = *sp;
- break;
- case OP_VREF:
- chktype(0,DT_INTEGER);
- switch (sp[1].v_type) {
- case DT_VECTOR: vectorref(); break;
- case DT_STRING: stringref(); break;
- default: badtype(1,DT_VECTOR); break;
- }
- break;
- case OP_VSET:
- chktype(1,DT_INTEGER);
- switch (sp[2].v_type) {
- case DT_VECTOR: vectorset(); break;
- case DT_STRING: stringset(); break;
- default: badtype(1,DT_VECTOR); break;
- }
- break;
- case OP_MREF:
- obj = fp[fp[2].v.v_integer+2].v.v_object;
- *sp = obj->obj_members[*pc++];
- break;
- case OP_MSET:
- obj = fp[fp[2].v.v_integer+2].v.v_object;
- obj->obj_members[*pc++] = *sp;
- break;
- case OP_AREF:
- n = *pc++;
- if (n >= fp[2].v.v_integer)
- error("Too few arguments");
- *sp = fp[n+3];
- break;
- case OP_ASET:
- n = *pc++;
- if (n >= fp[2].v.v_integer)
- error("Too few arguments");
- fp[n+3] = *sp;
- break;
- case OP_TREF:
- n = *pc++;
- *sp = fp[-n-1];
- break;
- case OP_TSET:
- n = *pc++;
- fp[-n-1] = *sp;
- break;
- case OP_TSPACE:
- n = *pc++;
- check(n);
- while (--n >= 0) {
- --sp;
- set_nil(sp);
- }
- break;
- case OP_BRT:
- if (istrue(sp))
- pc = cbase + getwoperand();
- else
- pc += 2;
- break;
- case OP_BRF:
- if (istrue(sp))
- pc += 2;
- else
- pc = cbase + getwoperand();
- break;
- case OP_BR:
- pc = cbase + getwoperand();
- break;
- case OP_NIL:
- set_nil(sp);
- break;
- case OP_PUSH:
- check(1);
- push_integer(FALSE);
- break;
- case OP_NOT:
- if (istrue(sp))
- set_integer(sp,FALSE);
- else
- set_integer(sp,TRUE);
- break;
- case OP_NEG:
- chktype(0,DT_INTEGER);
- sp->v.v_integer = -sp->v.v_integer;
- break;
- case OP_ADD:
- switch (sp[1].v_type) {
- case DT_INTEGER:
- switch (sp[0].v_type) {
- case DT_INTEGER:
- sp[1].v.v_integer += sp->v.v_integer;
- break;
- case DT_STRING:
- sn = newstring(1 + sp[0].v.v_string->str_size);
- s2 = sp[0].v.v_string;
- sn->str_data[0] = sp[1].v.v_integer;
- memcpy(&sn->str_data[1],
- s2->str_data,
- s2->str_size);
- set_string(&sp[1],sn);
- break;
- default:
- break;
- }
- break;
- case DT_STRING:
- switch (sp[0].v_type) {
- case DT_INTEGER:
- sn = newstring(sp[1].v.v_string->str_size + 1);
- s1 = sp[1].v.v_string;
- memcpy(sn->str_data,
- s1->str_data,
- s1->str_size);
- sn->str_data[s1->str_size] = sp[0].v.v_integer;
- set_string(&sp[1],sn);
- break;
- case DT_STRING:
- sn = newstring(sp[1].v.v_string->str_size
- + sp[0].v.v_string->str_size);
- s1 = sp[1].v.v_string;
- s2 = sp[0].v.v_string;
- memcpy(sn->str_data,
- s1->str_data,s1->str_size);
- memcpy(&sn->str_data[s1->str_size],
- s2->str_data,s2->str_size);
- set_string(&sp[1],sn);
- break;
- default:
- break;
- }
- break;
- default:
- badtype(1,DT_VECTOR);
- break;
- }
- ++sp;
- break;
- case OP_SUB:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- sp[1].v.v_integer -= sp->v.v_integer;
- ++sp;
- break;
- case OP_MUL:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- sp[1].v.v_integer *= sp->v.v_integer;
- ++sp;
- break;
- case OP_DIV:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- if (sp->v.v_integer != 0) {
- int x=sp->v.v_integer;
- sp[1].v.v_integer /= x;
- }
- else
- sp[1].v.v_integer = 0;
- ++sp;
- break;
- case OP_REM:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- if (sp->v.v_integer != 0) {
- int x=sp->v.v_integer;
- sp[1].v.v_integer %= x;
- }
- else
- sp[1].v.v_integer = 0;
- ++sp;
- break;
- case OP_INC:
- chktype(0,DT_INTEGER);
- ++sp->v.v_integer;
- break;
- case OP_DEC:
- chktype(0,DT_INTEGER);
- --sp->v.v_integer;
- break;
- case OP_BAND:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- sp[1].v.v_integer &= sp->v.v_integer;
- ++sp;
- break;
- case OP_BOR:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- sp[1].v.v_integer |= sp->v.v_integer;
- ++sp;
- break;
- case OP_XOR:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- sp[1].v.v_integer ^= sp->v.v_integer;
- ++sp;
- break;
- case OP_BNOT:
- chktype(0,DT_INTEGER);
- sp->v.v_integer = ~sp->v.v_integer;
- break;
- case OP_SHL:
- switch (sp[1].v_type) {
- case DT_INTEGER:
- chktype(0,DT_INTEGER);
- sp[1].v.v_integer <<= sp->v.v_integer;
- break;
- case DT_FILE:
- print1(sp[1].v.v_fp,FALSE,&sp[0]);
- break;
- default:
- break;
- }
- ++sp;
- break;
- case OP_SHR:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- sp[1].v.v_integer >>= sp->v.v_integer;
- ++sp;
- break;
- case OP_LT:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- n = sp[1].v.v_integer < sp->v.v_integer;
- ++sp;
- set_integer(sp,n ? TRUE : FALSE);
- break;
- case OP_LE:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- n = sp[1].v.v_integer <= sp->v.v_integer;
- ++sp;
- set_integer(sp,n ? TRUE : FALSE);
- break;
- case OP_EQ:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- n = sp[1].v.v_integer == sp->v.v_integer;
- ++sp;
- set_integer(sp,n ? TRUE : FALSE);
- break;
- case OP_NE:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- n = sp[1].v.v_integer != sp->v.v_integer;
- ++sp;
- set_integer(sp,n ? TRUE : FALSE);
- break;
- case OP_GE:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- n = sp[1].v.v_integer >= sp->v.v_integer;
- ++sp;
- set_integer(sp,n ? TRUE : FALSE);
- break;
- case OP_GT:
- chktype(0,DT_INTEGER);
- chktype(1,DT_INTEGER);
- n = sp[1].v.v_integer > sp->v.v_integer;
- ++sp;
- set_integer(sp,n ? TRUE : FALSE);
- break;
- case OP_LIT:
- *sp = code->vec_data[*pc++];
- break;
- case OP_SEND:
- n = *pc++;
- chktype(n,DT_OBJECT);
- chktype(n-1,DT_STRING);
- send(n);
- break;
- case OP_DUP2:
- check(2);
- sp -= 2;
- *sp = sp[2];
- sp[1] = sp[3];
- break;
- case OP_NEW:
- chktype(0,DT_CLASS);
- set_object(sp,newobject(sp));
- break;
- default:
- error("Bad opcode %02x",pc[-1]);
- break;
- }
- }
- }
-
- /* send - send a message to an object */
- static send(n)
- int n;
- {
- char selector[TKNSIZE+1];
- DICT_ENTRY *de;
- VALUE *class;
- class = objgetclass(&sp[n]);
- getcstring(selector,sizeof(selector),&sp[n-1]);
- sp[n-1] = sp[n];
- do {
- if ((de = findentry(clgetfunctions(class),selector)) != NULL) {
- switch (de->de_value.v_type) {
- case DT_CODE:
- (*de->de_value.v.v_code)(n);
- return;
- case DT_BYTECODE:
- check(3);
- code = de->de_value.v.v_vector;
- set_bytecode(&sp[n],code);
- push_integer(n);
- push_integer(stktop - fp);
- push_integer(pc - cbase);
- cbase = pc = code->vec_data[0].v.v_string->str_data;
- fp = sp;
- return;
- default:
- error("Bad method, Selector '%s', Type %d",
- selector,
- de->de_value.v_type);
- }
- }
- class = clgetbase(class);
- } while (!isnil(class));
- nomethod(selector);
- }
-
- /* vectorref - load a vector element */
- static vectorref()
- {
- VECTOR *vect;
- int i;
- vect = sp[1].v.v_vector;
- i = sp[0].v.v_integer;
- if (i < 0 || i >= vect->vec_size)
- error("subscript out of bounds: %d",i);
- sp[1] = vect->vec_data[i];
- ++sp;
- }
-
- /* vectorset - set a vector element */
- static vectorset()
- {
- VECTOR *vect;
- int i;
- vect = sp[2].v.v_vector;
- i = sp[1].v.v_integer;
- if (i < 0 || i >= vect->vec_size)
- error("subscript out of bounds: %d",i);
- vect->vec_data[i] = sp[2] = *sp;
- sp += 2;
- }
-
- /* stringref - load a string element */
- static stringref()
- {
- STRING *str;
- int i;
- str = sp[1].v.v_string;
- i = sp[0].v.v_integer;
- if (i < 0 || i >= str->str_size)
- error("subscript out of bounds: %d",i);
- set_integer(&sp[1],str->str_data[i]);
- ++sp;
- }
-
- /* stringset - set a string element */
- static stringset()
- {
- STRING *str;
- int i;
- chktype(0,DT_INTEGER);
- str = sp[2].v.v_string;
- i = sp[1].v.v_integer;
- if (i < 0 || i >= str->str_size)
- error("subscript out of bounds: %d",i);
- str->str_data[i] = sp[0].v.v_integer;
- set_integer(&sp[2],str->str_data[i]);
- sp += 2;
- }
-
- /* getwoperand - get data word */
- static int getwoperand()
- {
- int b;
- b = *pc++;
- return ((*pc++ << 8) | b);
- }
-
- /* type names */
- static char *tnames[] = {
- "NIL","CLASS","OBJECT","VECTOR","INTEGER","STRING","BYTECODE",
- "CODE","DICTIONARY","VAR","FILE"
- };
-
- /* typename - get the name of a type */
- static char *typename(type)
- int type;
- {
- static char buf[20];
- if (type >= _DTMIN && type <= _DTMAX)
- return (tnames[type]);
- sprintf(buf,"(%d)",type);
- return (buf);
- }
-
- /* badtype - report a bad operand type */
- badtype(off,type)
- int off,type;
- {
- char tn1[20];
- strcpy(tn1,typename(sp[off].v_type));
- info("PC: %04x, Offset %d, Type %s, Expected %s",
- pc-cbase,off,tn1,typename(type));
- error("Bad argument type");
- }
-
- /* nomethod - report a failure to find a method for a selector */
- static nomethod(selector)
- char *selector;
- {
- error("No method for selector '%s'",selector);
- }
-
- /* stackover - report a stack overflow error */
- stackover()
- {
- error("Stack overflow");
- }