/* interp.c reentrant eval for som3j 22 Dec 2004 som-in-som 30 Dec 2004 */ // system area 1 .. MAXSYS-1 // 1..80 tokstring-som #include "compile.h" // #include "interp.h" #define TRUE 1 #define FALSE 0 #define NIL 0 #define FUDGE 16 /* scratch area+3 check stkovf */ #define TOS SS[sp] #define NEXT SS[sp-1] #define pop2 sp -= 2 #define pop1 sp-- #define push(x) sp++; SS[sp] = (x) #define pop(x) (x) = SS[sp]; sp-- #define PRIVATE static int M[MAXMEM]; // memory int *CS = &M[MAXDS]; // code segment PRIVATE int SS[MAXSS]; // stack segment PRIVATE int sp=1,fp=0; // current state SS int CS_SOM = 0; // start CS of SOM, init by load obj int DP = MAXSYS; // current free data segment void error(char *mess, int ip){ printf("%s at ip %d\n",mess,ip); exit(0); } // static alloc memory of size a int xalloc(int a){ int b; b = DP; if( DP + a >= MAXDS ) error("xalloc: out of memory",0); DP += a; return b; } // gets() and put it in M[ads] void dogets(int ads){ char buf[256], *c; int i; c = gets(buf); if( c != NULL ){ for(i=0; buf[i] != 0; i++, ads++) M[ads] = (int)buf[i] & 255; M[ads] = 0; }else{ M[ads] = EOF_CHAR; M[ads+1] = 0; } } // reentrant eval void eval(int ref){ int runflag; int ip, op, data; // current instruction int a, b, low, hi, var; ip = ref; runflag = 1; while(runflag ) { op = CS[ip] & 255; data = CS[ip] >> 8 ; switch(op){ case icLit: push(data); ip++; break; case icLd: push( M[data]); ip++; break; case icSt: M[data] = TOS; pop1; ip++; break; case icPut: pop(a); SS[fp-data] = a; ip++; break; case icGet: push(SS[fp-data]); ip++; break; case icLdx: a = NEXT + TOS; pop1; TOS = M[a]; ip++; break; case icStx: pop(a); b = NEXT + TOS; pop2; M[b] = a; ip++; break; case icArray: pop(a); push(xalloc(a)); ip++; break; case icJmp: ip += data; break; case icJf: pop(a); if( a == FALSE) ip += data; else ip++; break; case icJt: pop(a); if( a != FALSE) ip += data; else ip++; break; case icCall: var = CS[data] >> 8; // get lv if (sp + var + FUDGE > MAXSS) error("stack overflow",ip); SS[sp+var] = fp; fp = sp + var; sp = fp + 1; SS[sp] = ip + 1; ip = data + 1; break; case icRet: /* return TOS to caller if current stack is not empty */ ip = SS[fp+1]; if ( sp > fp+1 ){ a = TOS; sp = fp - data + 1; fp = SS[fp]; SS[sp] = a; }else{ sp = fp - data; fp = SS[fp]; } break; case icAdd: a = NEXT + TOS; pop1; TOS = a; ip++; break; case icSub: a = NEXT - TOS; pop1; TOS = a; ip++; break; case icMul: a = NEXT * TOS; pop1; TOS = a; ip++; break; case icDiv: a = NEXT / TOS; pop1; TOS = a; ip++; break; case icBand: a = NEXT & TOS; pop1; TOS = a; ip++; break; case icBor: a = NEXT | TOS; pop1; TOS = a; ip++; break; case icBxor: a = NEXT ^ TOS; pop1; TOS = a; ip++; break; case icNot: a = TOS == FALSE; TOS = a; ip++; break; case icMod: a = NEXT % TOS; pop1; TOS = a; ip++; break; case icShl: a = NEXT << TOS; pop1; TOS = a; ip++; break; case icShr: a = NEXT >> TOS; pop1; TOS = a; ip++; break; case icEq: a = NEXT == TOS; pop1; TOS = a; ip++; break; case icNe: a = NEXT != TOS; pop1; TOS = a; ip++; break; case icLt: a = NEXT < TOS; pop1; TOS = a; ip++; break; case icLe: a = NEXT <= TOS; pop1; TOS = a; ip++; break; case icGt: a = NEXT > TOS; pop1; TOS = a; ip++; break; case icGe: a = NEXT >= TOS; pop1; TOS = a; ip++; break; case icInc: SS[fp-data]++; ip++; break; case icDec: SS[fp-data]--; ip++; break; case icCase: low = CS[ip+1] >> 8; hi = CS[ip+2] >> 8; pop(a); if( a < low || a > hi ) ip = ip+3; else ip += a-low+4; break; case icSys: switch(data){ case 1: // print int pop(a); printf("%d",a); break; case 2: // print char pop(a); printf("%c",a); break; case 3: // get char push(getchar()); break; case 4: // gets() pop(a); // som buffer dogets(a); break; case 5: // eval ref pop(a); CS = &M[CS_SOM]; // switch to user space eval(a); CS = &M[MAXDS]; // switch back break; case 7: runflag = 0; // end break; default: error("undefined syscall",ip); } ip++; break; case icEnd: runflag = 0; break; default: printf("op %d\n",op); error("undefined opcode",ip); } // end swich(op) } // end while runflag }