#include "m.h" #define PROC_RET 1 #define FUNC_RET 2 int got_return = 0; int got_break = 0; int got_continue = 0; void execute( Instptr p) /* run the machine */ { for( pc = p; *pc; ) { #ifdef DEBUG if( trace) disasm( pc, pc+1); #endif (*(*pc++))(); } #ifdef DEBUG if( stack_dump) s_dump(); #endif } void fn( void) { (*(*pc++))(); } void m_while( void) { Symbolptr cptr; /* *savepc == offset to loop body */ Instptr savepc = pc; /* *(savepc+1) == offset to next statement */ Symbolptr *savesp = sp; int cond; execute(savepc+2); /* condition */ cptr = pop(); n_check( cptr, "`while' condition"); cond = (int) VAL(cptr); while( cond) { execute( savepc + (int)*savepc); /* body */ if( got_return) return; if( got_break) { sp = savesp; /* unstack any local vars */ got_break = 0; break; } else if( got_continue) { sp = savesp; got_continue = 0; } execute(savepc+2); /* condition */ cptr = pop(); n_check( cptr, "`while' condition"); cond = (int) VAL(cptr); cleanup(0); } pc = savepc + (int)*(savepc+1); /* next stmt */ } void m_do( void) { Symbolptr cptr; /* *savepc == offset to condition */ Instptr savepc = pc; /* *(savepc+1) == offset to next stmt */ Symbolptr *savesp = sp; int cond; do { execute( savepc+2); /* body */ if( got_return) return; if( got_break) { sp = savesp; /* unstack any local vars */ got_break = 0; break; } else if( got_continue) { sp = savesp; got_continue = 0; } execute( savepc + (int)*savepc); /* condition */ cptr = pop(); n_check( cptr, "`do' condition"); cond = (int) VAL(cptr); cleanup(0); } while( cond); pc = savepc + (int)*(savepc+1); /* next stmt */ } void m_if( void) { /* *savepc == offset to then part */ Symbolptr cond; /* *(savepc+1) == offset to else part */ Instptr savepc = pc; /* *(savepc+2) == offset to next stmt */ execute(savepc+3); /* condition */ cond = pop(); n_check( cond, "`if' condition"); if( VAL(cond)) execute( savepc + (int)*savepc); /* then part */ else if( *(savepc+1)) /* else part? */ execute( savepc + (int)*(savepc+1)); /* * if we got `break', `continue', or `return' * leave pc pointing to the following NULL */ if( !got_break && !got_continue && !got_return) pc = savepc + (int)*(savepc+2); /* next stmt */ } void m_for( void) { /* *savepc == offset to condition */ Symbolptr cptr; /* *(savepc+1) == offset to ending */ int cond; /* *(savepc+2) == offset to loop body */ Instptr savepc = pc; /* *(savepc+3) == offset to next stmt */ Symbolptr *savesp = sp; execute( savepc+4); /* init part */ if( *(savepc + (int)*savepc) ) { /* condition */ execute( savepc + (int)*savepc); cptr = pop(); n_check( cptr, "`for' condition"); cond = (int) VAL(cptr); } else cond = 1; while( cond) { execute( savepc + (int)*(savepc+2) ); /* body */ if( got_return) return; if( got_break) { sp = savesp; /* unstack any local vars */ got_break = 0; break; } else if( got_continue) { sp = savesp; got_continue = 0; } execute( savepc + (int)*(savepc+1) ); /* ending */ if( *(savepc + (int)*savepc) ) { /* condition */ execute( savepc + (int)*savepc); cptr = pop(); n_check( cptr, "`for' condition"); cond = (int) VAL(cptr); } cleanup(0); } pc = savepc + (int)*(savepc+3); /* next stmt */ } void m_break( void) { got_break = 1; } void m_continue( void) { got_continue = 1; } void proc_ret( void) { got_return = PROC_RET; } void func_ret( void) { got_return = FUNC_RET; } void m_and( void) /* e1 && e2; e1 is on stack, code for e2 is at savepc+1 */ { Symbolptr e1, e2; Instptr savepc = pc; /* *savepc == offset to next stmt */ e1 = pop(); check( e1); if( SCALAR(e1) && !VAL(e1)) /* 0 && e2 -->> 0 */ push( m_create( 1, 1)); else { /* !0 && e2 -->> dyadic AND_OP */ execute( savepc+1); /* e2 -->> stack */ e2 = pop(); push( dyadic( e1, e2, AND_OP) ); } pc = savepc + (int)*savepc; /* next stmt */ } void m_or( void) /* e1 || e2; e1 is on stack, code for e2 is at savepc+1 */ { Symbolptr e1, e2; Instptr savepc = pc; /* *savepc == offset to next stmt */ e1 = pop(); check( e1); if( SCALAR(e1) && VAL(e1)) { /* 1 || e2 -->> 1 */ e1 = m_create( 1, 1); VAL(e1) = 1.0; push(e1); } else { /* 1 || e2 -->> dyadic OR_OP */ execute( savepc+1); /* e2 -->> stack */ e2 = pop(); push( dyadic( e1, e2, OR_OP) ); } pc = savepc + (int)*savepc; /* next stmt */ } void m_cond( void) /* e1 ? e2 : e3; e1 on stack, code for e2 is at savepc+2 */ { Symbolptr e1; Instptr savepc = pc; /* *savepc == offset to e3 */ /* *(savepc+1) == offset to next stmt */ e1 = pop(); n_check( e1, "?:"); if( VAL(e1)) /* result is e2 */ execute( savepc+2); else /* result is e3 */ execute( savepc + (int)*savepc ); pc = savepc + (int)*(savepc+1); /* next stmt */ } static void m_skip( Instptr next) /* find next case or default */ /*** better update with m_install, etc..... ****/ { while( ++pc < next && *pc != m_case && *pc != m_default) if( *pc == m_switch || *pc == m_while || *pc == m_do || *pc == m_cond) pc += (int)*(pc+2); else if( *pc == m_for) pc += (int)*(pc+4); else if( *pc == m_if) pc += (int)*(pc+3); else if( *pc == m_and || *pc == m_or) pc += (int)*(pc+1); } void m_switch( void) { Symbolptr e1, e2; /* *savepc == offset to body */ Instptr savepc = pc; /* *(savepc+1) == offset to next stmt */ Symbolptr *savesp = sp; Instptr next; Instptr def = NULL; /* location of default: */ int cond; execute( savepc+2); /* condition */ n_check( e1 = pop(), "switch"); cond = (int) VAL(e1); next = savepc + (int)*(savepc+1); ++pc; while( pc < next) if( *pc == m_default) { def = pc + 1; /* default expr */ #ifdef DEBUG if( prog_debug) dprint("switch: got default @ %p\n", def); #endif m_skip(next); } else if( *pc == m_case) { e2 = (Symbolptr)(*++pc); /* case expr */ if( cond == (int) VAL(e2)) { #ifdef DEBUG if( prog_debug) dprint("switch: matched case, executing stmt @ %p\n", pc+1); #endif execute( ++pc); break; } else m_skip(next); } else { #ifdef DEBUG if( prog_debug) dprint("switch: executing non-case/default statement @ %p\n", pc); #endif while( pc < next && *pc && *pc != m_case && *pc != m_default && !got_return) (*(*pc++))(); if( got_break) break; if( !*pc) ++pc; } if( pc >= next && def) { #ifdef DEBUG if( prog_debug) dprint("switch: executing default @ %p\n", def); #endif execute(def); } if( got_return) return; if( got_break) { /* or continue ??? */ sp = savesp; /* unstack any local vars */ got_break = 0; } pc = next; } void m_case( void) /* skip to next statement */ { ++pc; } void m_default( void) /* skip to next NULL **** this is wrong!!! ****/ { while( *pc++) ; } void call( void) { Symbolptr f, a; int narg, i, type; Instptr savepc; Instptr p; f = (Symbolptr)*pc++; narg = (int)*pc++; savepc = pc; if( !f) error("null argument",""); else if( f->type == UNDEF) error("undefined function ", NAME(f) ); else if( f->type != FUNCTION && f->type != PROCEDURE) error( NAME(f), " is not a function"); else if( SIZE(f) == 3 + NARG(f)) dprint("warning: function %s() has no body\n", NAME(f)); npop( narg); fpush(); /* start new frame */ sp += narg; a = install( NULL, NUMBER, AUTO, 1, 1); /* for narg */ VAL(a) = narg; /* * make sure exactly NARG(f) arguments are stacked */ while( narg > NARG(f)) { (void) pop(); /* trash extra args */ --narg; } while( narg < NARG(f)) { push(NULL); /* push NULL for missing args */ ++narg; } sp -= NARG(f); for( p = f->u.fptr + 1, i = 0; i < NARG(f); ++i ) { type = (int)*p++; if( sp[i]) if( type == INT || type == DOUBLE) /* call by value */ sp[i] = copy( install( NULL, UNDEF, AUTO, 0, 0), sp[i]); else if( sp[i]->class == CONST) sp[i]->class = LOOP; /* to prevent cleanup() erasing it */ } sp += NARG(f); push( a); /* narg */ execute( p); if( got_return == PROC_RET) { if( f->type != PROCEDURE) error( "function returned no value: ", NAME(f)); a = NULL; } else if( got_return == FUNC_RET) { if( f->type != FUNCTION) error( "void function returned a value: ", NAME(f)); a = pop(); } else error("got wierd return in call()",""); got_return = 0; fpop(); for( p = f->u.fptr + 1, i = 0; i < NARG(f); ++i ) { type = (int)*p++; if( sp[i] && sp[i] != a && (type == INT || type == DOUBLE)) sp[i]->type = CONST; /* will be cleared by cleanup() */ } if( f->type == FUNCTION) if( f->class == INT || f->class == DOUBLE) push( copy( NULL, a) ); else push(a); pc = savepc; } #ifdef DEBUG #ifdef YYDEBUG const char *bison_translate( int); #endif /* YYDEBUG */ extern Symbolptr cmd_head; /* from symbol.c */ static struct { /* machine instructions */ char *name; Inst fn; int narg; } inst[] = { { "and", m_and, 1 }, { "assign", m_assign, 1 }, { "break", m_break, 0 }, { "call", call, 2 }, { "case", m_case, 1 }, { "cond", m_cond, 2 }, { "colon", m_colon, 0 }, { "continue", m_continue, 0 }, { "copy", m_copy, 0 }, { "default", m_default, 0 }, { "do", m_do, 2 }, { "dyadic", m_dyadic, 1 }, { "fn", fn, 2 }, { "for", m_for, 4 }, { "func_ret", func_ret, 0 }, { "if", m_if, 3 }, { "index", m_index, 1 }, { "install", m_install, 0 }, { "local_push", local_push, 1 }, { "matpop", matpop, 0 }, { "matrix", m_matrix, 0 }, { "mul", m_mul, 0 }, { "or", m_or, 1 }, { "+\\", m_pbs, 0 }, { "*\\", m_tbs, 0 }, #ifdef __POWERC { "pop", pop, 0 }, /* PowerC compiler bug ? */ #else { "pop", (Inst)pop, 0 }, #endif { "pp", m_pp, 1 }, { "pp2", m_pp2, 2 }, { "proc_ret", proc_ret, 0 }, { "print", m_print, 0 }, { "reduce", m_reduce, 1 }, { "string", m_string, 0 }, { "swap", swap, 0 }, { "switch", m_switch, 2 }, { "sympush", sympush, 1 }, { "transpose", m_transpose, 0 }, { "unary", m_unary, 1 }, { "uninstall", m_uninstall, 1 }, { "while", m_while, 2 }, { "NULL", NULL, 0 }, { NULL, NULL, 0 } }; void disasm( Instptr p, Instptr pp) /* disassemble the program */ { int i, narg; while( p < pp) { dprint("%p ", p); for( i = 0; inst[i].name; i++) if( *p == inst[i].fn) break; if( inst[i].name) { dprint("%s ", inst[i].name); narg = inst[i].narg; if( inst[i].fn == sympush) display( (Symbolptr)*++p, ""); else if( inst[i].fn == local_push) { dprint("offset = %d\n", (int)*++p); } else if( inst[i].fn == m_case) { dprint("%d\n", (int) VAL(((Symbolptr)*++p)) ); } else if( inst[i].fn == m_while || inst[i].fn == m_switch) { dprint("body = %p, ", p + 1 + (int)*(p+1) ); dprint("next = %p\n", p + 1 + (int)*(p+2) ); p += 2; } else if( inst[i].fn == m_do) { dprint("cond = %p, ", p + 1 + (int)*(p+1) ); dprint("next = %p\n", p + 1 + (int)*(p+2) ); p += 2; } else if( inst[i].fn == m_if) { dprint("then = %p, ", p + 1 + (int)*(p+1) ); dprint("else = %p, ", *(p+2) ? p + 1 + (int)*(p+2) : NULL); dprint("next = %p\n", p + 1 + (int)*(p+3) ); p += 3; } else if( inst[i].fn == m_for) { dprint("cond = %p, ", p + 1 + (int)*(p+1) ); dprint("ending = %p, ", p + 1 + (int)*(p+2) ); dprint("body = %p, ", p + 1 + (int)*(p+3) ); dprint("next = %p\n", p + 1 + (int)*(p+4) ); p += 4; } else if( inst[i].fn == m_and || inst[i].fn == m_or) { dprint("next = %p\n", p + 1 + (int)*(p+1) ); ++p; } else if( inst[i].fn == m_cond) { dprint("e3 = %p, ", p + 1 + (int)*(p+1) ); dprint("next = %p\n", p + 1 + (int)*(p+2) ); p += 2; } else if( inst[i].fn == call) { dprint("%s(%d)\n", ((Symbolptr)*(p+1))->name, (int)*(p+2)); p += 2; } else if( inst[i].fn == m_uninstall) { dprint("%d\n", (int)*++p); } else if( inst[i].fn == fn) { Symbolptr s = cmd_head; ++p; /* * typedef's are at end of init_symlist in init.h */ while( s->u.fn != *p && s->type != TYPE_NAME) s = s->next; if( s->u.fn != *p) { /* shouldn't happen */ dprint("%p ",*p); dprint("(%d)\n", (int)*++p); } else dprint("%s(%d)\n", s->name, (int)*++p); } else if( narg == 1) { #ifdef YYDEBUG const char *b = bison_translate( (int) *++p); if( b == NULL) dprint( "%d\n", (int) *p); else dprint("%s\n", b); #else dprint( "%d\n", (int) *++p); #endif /* YYDEBUG */ } else { while( narg-- > 0) dprint("%d ", (int) *++p); dprint("\n"); } } else dprint("unknown (%p)\n", *p); ++p; } } #endif /* DEBUG */