Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (04/15/90)
Submitted-by: rusty@fe2o3.UUCP (Rusty Haddock) Posting-number: Volume 90, Issue 143 Archive-name: applications/xscheme-0.20/part05 #!/bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 5 (of 7)." # Contents: Src/xscom.c # Wrapped by tadguy@xanth on Sat Apr 14 17:07:28 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Src/xscom.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Src/xscom.c'\" else echo shar: Extracting \"'Src/xscom.c'\" \(33402 characters\) sed "s/^X//" >'Src/xscom.c' <<'END_OF_FILE' X/* xscom.c - a simple scheme bytecode compiler */ X/* Copyright (c) 1988, by David Michael Betz X All Rights Reserved X Permission is granted for unrestricted non-commercial use */ X X#include "xscheme.h" X#include "xsbcode.h" X X/* size of code buffer */ X#define CMAX 4000 X X/* continuation types */ X#define C_RETURN -1 X#define C_NEXT -2 X X/* macro to check for a lambda list keyword */ X#define lambdakey(x) ((x) == lk_optional || (x) == lk_rest) X X/* external variables */ Xextern LVAL lk_optional,lk_rest,true; X X/* local variables */ Xstatic LVAL info; /* compiler info */ X X/* code buffer */ Xstatic unsigned char cbuff[CMAX]; /* base of code buffer */ Xstatic int cbase; /* base for current function */ Xstatic int cptr; /* code buffer pointer */ X X/* forward declarations */ Xint do_define(),do_set(),do_quote(),do_lambda(),do_delay(); Xint do_let(),do_letrec(),do_letstar(),do_cond(),do_and(),do_or(); Xint do_if(),do_begin(),do_while(),do_access(); XLVAL make_code_object(); X X/* integrable function table */ Xtypedef struct { char *nt_name; int nt_code,nt_args; } NTDEF; Xstatic NTDEF *nptr,ntab[] = { X "ATOM", OP_ATOM, 1, X "EQ?", OP_EQ, 2, X "NULL?", OP_NULL, 1, X "NOT", OP_NULL, 1, X "CONS", OP_CONS, 2, X "CAR", OP_CAR, 1, X "CDR", OP_CDR, 1, X "SET-CAR!", OP_SETCAR, 2, X "SET-CDR!", OP_SETCDR, 2, X "+", OP_ADD, -2, X "-", OP_SUB, -2, X "*", OP_MUL, -2, X "QUOTIENT", OP_QUO, -2, X "<", OP_LSS, -2, X "=", OP_EQL, -2, X ">", OP_GTR, -2, X 0 X}; X X/* special form table */ Xtypedef struct { char *ft_name; int (*ft_fcn)(); } FTDEF; Xstatic FTDEF ftab[] = { X "QUOTE", do_quote, X "LAMBDA", do_lambda, X "DELAY", do_delay, X "LET", do_let, X "LET*", do_letstar, X "LETREC", do_letrec, X "DEFINE", do_define, X "SET!", do_set, X "IF", do_if, X "COND", do_cond, X "BEGIN", do_begin, X "SEQUENCE", do_begin, X "AND", do_and, X "OR", do_or, X "WHILE", do_while, X "ACCESS", do_access, X 0 X}; X X/* xlcompile - compile an expression */ XLVAL xlcompile(expr,ctenv) X LVAL expr,ctenv; X{ X /* initialize the compile time environment */ X info = cons(NIL,NIL); cpush(info); X rplaca(info,newframe(ctenv,1)); X rplacd(info,cons(NIL,NIL)); X X /* setup the base of the code for this function */ X cbase = cptr = 0; X X /* setup the entry code */ X putcbyte(OP_FRAME); X putcbyte(1); X X /* compile the expression */ X do_expr(expr,C_RETURN); X X /* build the code object */ X settop(make_code_object(NIL)); X return (pop()); X} X X/* xlfunction - compile a function */ XLVAL xlfunction(fun,fargs,body,ctenv) X LVAL fun,fargs,body,ctenv; X{ X /* initialize the compile time environment */ X info = cons(NIL,NIL); cpush(info); X rplaca(info,newframe(ctenv,1)); X rplacd(info,cons(NIL,NIL)); X X /* setup the base of the code for this function */ X cbase = cptr = 0; X X /* compile the lambda list and the function body */ X parse_lambda_list(fargs,body); X do_begin(body,C_RETURN); X X /* build the code object */ X settop(make_code_object(fun)); X return (pop()); X} X X/* do_expr - compile an expression */ XLOCAL do_expr(expr,cont) X LVAL expr; int cont; X{ X LVAL fun; X if (consp(expr)) { X fun = car(expr); X if (!symbolp(fun) || (!in_ntab(expr,cont) && !in_ftab(expr,cont))) X do_call(expr,cont); X } X else if (symbolp(expr)) X do_identifier(expr,cont); X else X do_literal(expr,cont); X} X X/* in_ntab - check for a function in ntab */ XLOCAL int in_ntab(expr,cont) X LVAL expr; int cont; X{ X unsigned char *pname; X pname = getstring(getpname(car(expr))); X for (nptr = ntab; nptr->nt_name; ++nptr) X if (strcmp(pname,nptr->nt_name) == 0) { X do_nary(nptr->nt_code,nptr->nt_args,expr,cont); X return (TRUE); X } X return (FALSE); X} X X/* in_ftab - check for a function in ftab */ XLOCAL int in_ftab(expr,cont) X LVAL expr; int cont; X{ X unsigned char *pname; X FTDEF *fptr; X pname = getstring(getpname(car(expr))); X for (fptr = ftab; fptr->ft_name; ++fptr) X if (strcmp(pname,fptr->ft_name) == 0) { X (*fptr->ft_fcn)(cdr(expr),cont); X return (TRUE); X } X return (FALSE); X} X X/* do_define - handle the (DEFINE ... ) expression */ XLOCAL do_define(form,cont) X LVAL form; int cont; X{ X if (atom(form)) X xlerror("expecting symbol or function template",form); X define1(car(form),cdr(form),cont); X} X X/* define1 - helper routine for do_define */ XLOCAL define1(list,body,cont) X LVAL list,body; int cont; X{ X LVAL fargs; X int off; X X /* handle nested definitions */ X if (consp(list)) { X cpush(cons(xlenter("LAMBDA"),NIL)); /* (LAMBDA) */ X rplacd(top(),cons(cdr(list),NIL)); /* (LAMBDA args) */ X rplacd(cdr(top()),body); /* (LAMBDA args body) */ X settop(cons(top(),NIL)); /* ((LAMBDA args body)) */ X define1(car(list),top(),cont); X drop(1); X } X X /* compile procedure definitions */ X else { X X /* make sure it's a symbol */ X if (!symbolp(list)) X xlerror("expecting a symbol",list); X X /* check for a procedure definition */ X if (consp(body) X && consp(car(body)) X && car(car(body)) == xlenter("LAMBDA")) { X fargs = car(cdr(car(body))); X body = cdr(cdr(car(body))); X cd_fundefinition(list,fargs,body); X } X X /* compile the value expression or procedure body */ X else X do_begin(body,C_NEXT); X X /* define the variable value */ X if (findcvariable(list,&off)) X cd_evariable(OP_ESET,0,off); X else X cd_variable(OP_GSET,list); X do_literal(list,cont); X } X} X X/* do_set - compile the (SET! ... ) expression */ XLOCAL do_set(form,cont) X LVAL form; int cont; X{ X if (atom(form)) X xlerror("expecting symbol or ACCESS form",form); X else if (symbolp(car(form))) X do_setvar(form,cont); X else if (consp(car(form))) X do_setaccess(form,cont); X else X xlerror("expecting symbol or ACCESS form",form); X} X X/* do_setvar - compile the (SET! var value) expression */ XLOCAL do_setvar(form,cont) X LVAL form; int cont; X{ X int lev,off; X LVAL sym; X X /* get the variable name */ X sym = car(form); X X /* compile the value expression */ X form = cdr(form); X if (atom(form)) X xlerror("expecting value expression",form); X do_expr(car(form),C_NEXT); X X /* set the variable value */ X if (findvariable(sym,&lev,&off)) X cd_evariable(OP_ESET,lev,off); X else X cd_variable(OP_GSET,sym); X do_continuation(cont); X} X X/* do_quote - compile the (QUOTE ... ) expression */ XLOCAL do_quote(form,cont) X LVAL form; int cont; X{ X if (atom(form)) X xlerror("expecting quoted expression",form); X do_literal(car(form),cont); X} X X/* do_lambda - compile the (LAMBDA ... ) expression */ XLOCAL do_lambda(form,cont) X LVAL form; int cont; X{ X if (atom(form)) X xlerror("expecting argument list",form); X cd_fundefinition(NIL,car(form),cdr(form)); X do_continuation(cont); X} X X/* cd_fundefinition - compile the function */ XLOCAL cd_fundefinition(fun,fargs,body) X LVAL fun,fargs,body; X{ X int oldcbase; X X /* establish a new environment frame */ X oldcbase = add_level(); X X /* compile the lambda list and the function body */ X parse_lambda_list(fargs,body); X do_begin(body,C_RETURN); X X /* build the code object */ X cpush(make_code_object(fun)); X X /* restore the previous environment */ X remove_level(oldcbase); X X /* compile code to create a closure */ X do_literal(pop(),C_NEXT); X putcbyte(OP_CLOSE); X} X X/* parse_lambda_list - parse the formal argument list */ XLOCAL parse_lambda_list(fargs,body) X LVAL fargs,body; X{ X LVAL arg,restarg,new,last; X int frame,slotn; X X /* setup the entry code */ X putcbyte(OP_FRAME); X frame = putcbyte(0); X X /* initialize the argument name list and slot number */ X restarg = last = NIL; X slotn = 1; X X /* handle each required argument */ X while (consp(fargs) && (arg = car(fargs)) && !lambdakey(arg)) { X X /* make sure the argument is a symbol */ X if (!symbolp(arg)) X xlerror("variable must be a symbol",arg); X X /* add the argument name to the name list */ X new = cons(arg,NIL); X if (last) rplacd(last,new); X else setelement(car(car(info)),0,new); X last = new; X X /* generate an instruction to move the argument into the frame */ X putcbyte(OP_MVARG); X putcbyte(slotn++); X X /* move the formal argument list pointer ahead */ X fargs = cdr(fargs); X } X X /* check for the '#!optional' argument */ X if (consp(fargs) && car(fargs) == lk_optional) { X fargs = cdr(fargs); X X /* handle each optional argument */ X while (consp(fargs) && (arg = car(fargs)) && !lambdakey(arg)) { X X /* make sure the argument is a symbol */ X if (!symbolp(arg)) X xlerror("#!optional variable must be a symbol",arg); X X /* add the argument name to the name list */ X new = cons(arg,NIL); X if (last) rplacd(last,new); X else setelement(car(car(info)),0,new); X last = new; X X /* move the argument into the frame */ X putcbyte(OP_MVOARG); X putcbyte(slotn++); X X /* move the formal argument list pointer ahead */ X fargs = cdr(fargs); X } X } X X /* check for the '#!rest' argument */ X if (consp(fargs) && car(fargs) == lk_rest) { X fargs = cdr(fargs); X X /* handle the rest argument */ X if (consp(fargs) && (restarg = car(fargs)) && !lambdakey(restarg)) { X X /* make sure the argument is a symbol */ X if (!symbolp(restarg)) X xlerror("#!rest variable must be a symbol",restarg); X X /* add the argument name to the name list */ X new = cons(restarg,NIL); X if (last) rplacd(last,new); X else setelement(car(car(info)),0,new); X last = new; X X /* make the #!rest argument list */ X putcbyte(OP_MVRARG); X putcbyte(slotn++); X X /* move the formal argument list pointer ahead */ X fargs = cdr(fargs); X } X else X xlerror("expecting the #!rest variable"); X } X X /* check for the a dotted tail */ X if (restarg == NIL && symbolp(fargs)) { X restarg = fargs; X X /* add the argument name to the name list */ X new = cons(restarg,NIL); X if (last) rplacd(last,new); X else setelement(car(car(info)),0,new); X last = new; X X /* make the #!rest argument list */ X putcbyte(OP_MVRARG); X putcbyte(slotn++); X fargs = NIL; X } X X /* check for the end of the argument list */ X if (fargs != NIL) X xlerror("bad argument list tail",fargs); X X /* make sure the user didn't supply too many arguments */ X if (restarg == NIL) X putcbyte(OP_ALAST); X X /* scan the body for internal definitions */ X slotn += find_internal_definitions(body,last); X X /* fixup the frame instruction */ X cbuff[cbase+frame] = slotn; X} X X/* find_internal_definitions - find internal definitions */ XLOCAL int find_internal_definitions(body,last) X LVAL body,last; X{ X LVAL define,sym,new; X int n=0; X X /* look for all (define...) forms */ X for (define = xlenter("DEFINE"); consp(body); body = cdr(body)) X if (consp(car(body)) && car(car(body)) == define) { X sym = cdr(car(body)); /* the rest of the (define...) form */ X if (consp(sym)) { /* make sure there is a second subform */ X sym = car(sym); /* get the second subform */ X while (consp(sym))/* check for a procedure definition */ X sym = car(sym); X if (symbolp(sym)) { X new = cons(sym,NIL); X if (last) rplacd(last,new); X else setelement(car(car(info)),0,new); X last = new; X ++n; X } X } X } X return (n); X} X X/* do_delay - compile the (DELAY ... ) expression */ XLOCAL do_delay(form,cont) X LVAL form; int cont; X{ X int oldcbase; X X /* check argument list */ X if (atom(form)) X xlerror("expecting delay expression",form); X X /* establish a new environment frame */ X oldcbase = add_level(); X X /* setup the entry code */ X putcbyte(OP_FRAME); X putcbyte(1); X X /* compile the expression */ X do_expr(car(form),C_RETURN); X X /* build the code object */ X cpush(make_code_object(NIL)); X X /* restore the previous environment */ X remove_level(oldcbase); X X /* compile code to create a closure */ X do_literal(pop(),C_NEXT); X putcbyte(OP_DELAY); X do_continuation(cont); X} X X/* do_let - compile the (LET ... ) expression */ XLOCAL do_let(form,cont) X LVAL form; int cont; X{ X /* handle named let */ X if (consp(form) && symbolp(car(form))) X do_named_let(form,cont); X X /* handle unnamed let */ X else X cd_let(NIL,form,cont); X} X X/* do_named_let - compile the (LET name ... ) expression */ XLOCAL do_named_let(form,cont) X LVAL form; int cont; X{ X int oldcbase,nxt; X X /* save a continuation */ X if (cont != C_RETURN) { X putcbyte(OP_SAVE); X nxt = putcword(0); X } X X /* establish a new environment frame */ X oldcbase = add_level(); X setelement(car(car(info)),0,cons(car(form),NIL)); X X /* setup the entry code */ X putcbyte(OP_FRAME); X putcbyte(2); X X /* compile the let expression */ X cd_let(car(form),cdr(form),C_RETURN); X X /* build the code object */ X cpush(make_code_object(NIL)); X X /* restore the previous environment */ X remove_level(oldcbase); X X /* compile code to create a closure */ X do_literal(pop(),C_NEXT); X putcbyte(OP_CLOSE); X X /* apply the function */ X putcbyte(OP_CALL); X putcbyte(1); X X /* target for the continuation */ X if (cont != C_RETURN) X fixup(nxt); X} X X/* cd_let - code a let expression */ XLOCAL cd_let(name,form,cont) X LVAL name,form; int cont; X{ X int oldcbase,nxt,lev,off,n; X X /* make sure there is a binding list */ X if (atom(form) || !listp(car(form))) X xlerror("expecting binding list",form); X X /* save a continuation */ X if (cont != C_RETURN) { X putcbyte(OP_SAVE); X nxt = putcword(0); X } X X /* push the initialization expressions */ X n = push_init_expressions(car(form)); X X /* establish a new environment frame */ X oldcbase = add_level(); X X /* compile the binding list */ X parse_let_variables(car(form),cdr(form)); X X /* compile the body of the let/letrec */ X do_begin(cdr(form),C_RETURN); X X /* build the code object */ X cpush(make_code_object(NIL)); X X /* restore the previous environment */ X remove_level(oldcbase); X X /* compile code to create a closure */ X do_literal(pop(),C_NEXT); X putcbyte(OP_CLOSE); X X /* store the procedure */ X if (name && findvariable(name,&lev,&off)) X cd_evariable(OP_ESET,lev,off); X X /* apply the function */ X putcbyte(OP_CALL); X putcbyte(n); X X /* target for the continuation */ X if (cont != C_RETURN) X fixup(nxt); X} X X/* do_letrec - compile the (LETREC ... ) expression */ XLOCAL do_letrec(form,cont) X LVAL form; int cont; X{ X int oldcbase,nxt,n; X X /* make sure there is a binding list */ X if (atom(form) || !listp(car(form))) X xlerror("expecting binding list",form); X X /* save a continuation */ X if (cont != C_RETURN) { X putcbyte(OP_SAVE); X nxt = putcword(0); X } X X /* push the initialization expressions */ X n = push_dummy_values(car(form)); X X /* establish a new environment frame */ X oldcbase = add_level(); X X /* compile the binding list */ X parse_let_variables(car(form),cdr(form)); X X /* compile instructions to set the bound variables */ X set_bound_variables(car(form)); X X /* compile the body of the let/letrec */ X do_begin(cdr(form),C_RETURN); X X /* build the code object */ X cpush(make_code_object(NIL)); X X /* restore the previous environment */ X remove_level(oldcbase); X X /* compile code to create a closure */ X do_literal(pop(),C_NEXT); X putcbyte(OP_CLOSE); X X /* apply the function */ X putcbyte(OP_CALL); X putcbyte(n); X X /* target for the continuation */ X if (cont != C_RETURN) X fixup(nxt); X} X X/* do_letstar - compile the (LET* ... ) expression */ XLOCAL do_letstar(form,cont) X LVAL form; int cont; X{ X int nxt; X X /* make sure there is a binding list */ X if (atom(form) || !listp(car(form))) X xlerror("expecting binding list",form); X X /* handle the case where there are bindings */ X if (consp(car(form))) { X X /* save a continuation */ X if (cont != C_RETURN) { X putcbyte(OP_SAVE); X nxt = putcword(0); X } X X /* build the nested lambda expressions */ X letstar1(car(form),cdr(form)); X X /* target for the continuation */ X if (cont != C_RETURN) X fixup(nxt); X } X X /* handle the case where there are no bindings */ X else X do_begin(cdr(form),cont); X} X X/* letstar1 - helper routine for let* */ XLOCAL letstar1(blist,body) X LVAL blist,body; X{ X int oldcbase,n; X X /* push the next initialization expressions */ X cpush(cons(car(blist),NIL)); X n = push_init_expressions(top()); X X /* establish a new environment frame */ X oldcbase = add_level(); X X /* handle the case where there are more bindings */ X if (consp(cdr(blist))) { X parse_let_variables(top(),NIL); X letstar1(cdr(blist),body); X } X X /* handle the last binding */ X else { X parse_let_variables(top(),body); X do_begin(body,C_RETURN); X } X X /* build the code object */ X settop(make_code_object(NIL)); X X /* restore the previous environment */ X remove_level(oldcbase); X X /* compile code to create a closure */ X do_literal(pop(),C_NEXT); X putcbyte(OP_CLOSE); X X /* apply the function */ X putcbyte(OP_CALL); X putcbyte(n); X} X X/* push_dummy_values - push dummy values for a 'letrec' expression */ XLOCAL int push_dummy_values(blist) X LVAL blist; X{ X int n=0; X if (consp(blist)) { X putcbyte(OP_NIL); X for (; consp(blist); blist = cdr(blist), ++n) X putcbyte(OP_PUSH); X } X return (n); X} X X/* push_init_expressions - push init expressions for a 'let' expression */ XLOCAL int push_init_expressions(blist) X LVAL blist; X{ X int n; X if (consp(blist)) { X n = push_init_expressions(cdr(blist)); X if (consp(car(blist)) && consp(cdr(car(blist)))) X do_expr(car(cdr(car(blist))),C_NEXT); X else X putcbyte(OP_NIL); X putcbyte(OP_PUSH); X return (n+1); X } X return (0); X} X X/* parse_let_variables - parse the binding list */ XLOCAL parse_let_variables(blist,body) X LVAL blist,body; X{ X LVAL arg,new,last; X int frame,slotn; X X /* setup the entry code */ X putcbyte(OP_FRAME); X frame = putcbyte(0); X X /* initialize the argument name list and slot number */ X last = NIL; X slotn = 1; X X /* handle each required argument */ X while (consp(blist) && (arg = car(blist))) { X X /* make sure the argument is a symbol */ X if (symbolp(arg)) X new = cons(arg,NIL); X else if (consp(arg) && symbolp(car(arg))) X new = cons(car(arg),NIL); X else X xlerror("invalid binding",arg); X X /* add the argument name to the name list */ X if (last) rplacd(last,new); X else setelement(car(car(info)),0,new); X last = new; X X /* generate an instruction to move the argument into the frame */ X putcbyte(OP_MVARG); X putcbyte(slotn++); X X /* move the formal argument list pointer ahead */ X blist = cdr(blist); X } X putcbyte(OP_ALAST); X X /* scan the body for internal definitions */ X slotn += find_internal_definitions(body,last); X X /* fixup the frame instruction */ X cbuff[cbase+frame] = slotn; X} X X/* set_bound_variables - set bound variables in a 'letrec' expression */ XLOCAL set_bound_variables(blist) X LVAL blist; X{ X int lev,off; X for (; consp(blist); blist = cdr(blist)) { X if (consp(car(blist)) && consp(cdr(car(blist)))) { X do_expr(car(cdr(car(blist))),C_NEXT); X if (findvariable(car(car(blist)),&lev,&off)) X cd_evariable(OP_ESET,lev,off); X else X xlerror("compiler error -- can't find",car(car(blist))); X } X } X} X X/* make_code_object - build a code object */ XLOCAL LVAL make_code_object(fun) X LVAL fun; X{ X unsigned char *cp; X LVAL code,p; X int i; X X /* create a code object */ X code = newcode(FIRSTLIT + length(car(cdr(info)))); cpush(code); X setbcode(code,newstring(cptr - cbase)); X setcname(code,fun); /* function name */ X setvnames(code,getelement(car(car(info)),0));/* lambda list variables */ X X /* copy the literals into the code object */ X for (i = FIRSTLIT, p = car(cdr(info)); consp(p); p = cdr(p), ++i) X setelement(code,i,car(p)); X X /* copy the byte codes */ X for (i = cbase, cp = getstring(getbcode(code)); i < cptr; ) X *cp++ = cbuff[i++]; X X /* return the new code object */ X return (pop()); X} X X/* do_cond - compile the (COND ... ) expression */ XLOCAL do_cond(form,cont) X LVAL form; int cont; X{ X int nxt,end; X if (consp(form)) { X for (end = 0; consp(form); form = cdr(form)) { X if (atom(car(form))) X xlerror("expecting a cond clause",form); X do_expr(car(car(form)),C_NEXT); X putcbyte(OP_BRF); X nxt = putcword(0); X if (cdr(car(form))) X do_begin(cdr(car(form)),cont); X else X do_continuation(cont); X if (cont == C_NEXT) { X putcbyte(OP_BR); X end = putcword(end); X } X fixup(nxt); X } X fixup(end); X } X else X putcbyte(OP_NIL); X do_continuation(cont); X} X X/* do_and - compile the (AND ... ) expression */ XLOCAL do_and(form,cont) X LVAL form; int cont; X{ X int end; X if (consp(form)) { X for (end = 0; consp(form); form = cdr(form)) { X if (cdr(form)) { X do_expr(car(form),C_NEXT); X putcbyte(OP_BRF); X end = putcword(end); X } X else X do_expr(car(form),cont); X } X fixup(end); X } X else X putcbyte(OP_T); X do_continuation(cont); X} X X/* do_or - compile the (OR ... ) expression */ XLOCAL do_or(form,cont) X LVAL form; int cont; X{ X int end; X if (consp(form)) { X for (end = 0; consp(form); form = cdr(form)) { X if (cdr(form)) { X do_expr(car(form),C_NEXT); X putcbyte(OP_BRT); X end = putcword(end); X } X else X do_expr(car(form),cont); X } X fixup(end); X } X else X putcbyte(OP_NIL); X do_continuation(cont); X} X X/* do_if - compile the (IF ... ) expression */ XLOCAL do_if(form,cont) X LVAL form; int cont; X{ X int nxt,end; X X /* compile the test expression */ X if (atom(form)) X xlerror("expecting test expression",form); X do_expr(car(form),C_NEXT); X X /* skip around the 'then' clause if the expression is false */ X putcbyte(OP_BRF); X nxt = putcword(0); X X /* skip to the 'then' clause */ X form = cdr(form); X if (atom(form)) X xlerror("expecting then clause",form); X X /* compile the 'then' and 'else' clauses */ X if (consp(cdr(form))) { X if (cont == C_NEXT) { X do_expr(car(form),C_NEXT); X putcbyte(OP_BR); X end = putcword(0); X } X else { X do_expr(car(form),cont); X end = -1; X } X fixup(nxt); X do_expr(car(cdr(form)),cont); X nxt = end; X } X X /* compile just a 'then' clause */ X else X do_expr(car(form),cont); X X /* handle the end of the statement */ X if (nxt >= 0) { X fixup(nxt); X do_continuation(cont); X } X} X X/* do_begin - compile the (BEGIN ... ) expression */ XLOCAL do_begin(form,cont) X LVAL form; int cont; X{ X if (consp(form)) X for (; consp(form); form = cdr(form)) X if (consp(cdr(form))) X do_expr(car(form),C_NEXT); X else X do_expr(car(form),cont); X else { X putcbyte(OP_NIL); X do_continuation(cont); X } X} X X/* do_while - compile the (WHILE ... ) expression */ XLOCAL do_while(form,cont) X LVAL form; int cont; X{ X int loop,nxt; X X /* make sure there is a test expression */ X if (atom(form)) X xlerror("expecting test expression",form); X X /* skip around the 'body' to the test expression */ X putcbyte(OP_BR); X nxt = putcword(0); X X /* compile the loop body */ X loop = cptr - cbase; X do_begin(cdr(form),C_NEXT); X X /* label for the first iteration */ X fixup(nxt); X X /* compile the test expression */ X nxt = cptr - cbase; X do_expr(car(form),C_NEXT); X X /* skip around the 'body' if the expression is false */ X putcbyte(OP_BRT); X putcword(loop); X X /* compile the continuation */ X do_continuation(cont); X} X X/* do_access - compile the (ACCESS var env) expression */ XLOCAL do_access(form,cont) X LVAL form; int cont; X{ X LVAL sym; X X /* get the variable name */ X if (atom(form) || !symbolp(car(form))) X xlerror("expecting symbol",form); X sym = car(form); X X /* compile the environment expression */ X form = cdr(form); X if (atom(form)) X xlerror("expecting environment expression",form); X do_expr(car(form),C_NEXT); X X /* get the variable value */ X cd_variable(OP_AREF,sym); X do_continuation(cont); X} X X/* do_setaccess - compile the (SET! (ACCESS var env) value) expression */ XLOCAL do_setaccess(form,cont) X LVAL form; int cont; X{ X LVAL aform,sym; X X /* make sure this is an access form */ X aform = car(form); X if (atom(aform) || car(aform) != xlenter("ACCESS")) X xlerror("expecting an ACCESS form",aform); X X /* get the variable name */ X aform = cdr(aform); X if (atom(aform) || !symbolp(car(aform))) X xlerror("expecting symbol",aform); X sym = car(aform); X X /* compile the environment expression */ X aform = cdr(aform); X if (atom(aform)) X xlerror("expecting environment expression",aform); X do_expr(car(aform),C_NEXT); X putcbyte(OP_PUSH); X X /* compile the value expression */ X form = cdr(form); X if (atom(form)) X xlerror("expecting value expression",form); X do_expr(car(form),C_NEXT); X X /* set the variable value */ X cd_variable(OP_ASET,sym); X do_continuation(cont); X} X X/* do_call - compile a function call */ XLOCAL do_call(form,cont) X LVAL form; int cont; X{ X int nxt,n; X X /* save a continuation */ X if (cont != C_RETURN) { X putcbyte(OP_SAVE); X nxt = putcword(0); X } X X /* compile each argument expression */ X n = push_args(cdr(form)); X X /* compile the function itself */ X do_expr(car(form),C_NEXT); X X /* apply the function */ X putcbyte(OP_CALL); X putcbyte(n); X X /* target for the continuation */ X if (cont != C_RETURN) X fixup(nxt); X} X X/* push_args - compile the arguments for a function call */ XLOCAL int push_args(form) X LVAL form; X{ X int n; X if (consp(form)) { X n = push_args(cdr(form)); X do_expr(car(form),C_NEXT); X putcbyte(OP_PUSH); X return (n+1); X } X return (0); X} X X/* do_nary - compile nary operator expressions */ XLOCAL do_nary(op,n,form,cont) X int op,n; LVAL form; int cont; X{ X if (n < 0 && (n = (-n)) != length(cdr(form))) X do_call(form,cont); X else { X push_nargs(cdr(form),n); X putcbyte(op); X do_continuation(cont); X } X} X X/* push_nargs - compile the arguments for an inline function call */ XLOCAL int push_nargs(form,n) X LVAL form; int n; X{ X if (consp(form)) { X if (n == 0) X xlerror("too many arguments",form); X if (push_nargs(cdr(form),n-1)) X putcbyte(OP_PUSH); X do_expr(car(form),C_NEXT); X return (TRUE); X } X if (n) X xlerror("too few arguments",form); X return (FALSE); X} X X/* do_literal - compile a literal */ XLOCAL do_literal(lit,cont) X LVAL lit; int cont; X{ X cd_literal(lit); X do_continuation(cont); X} X X/* do_identifier - compile an identifier */ XLOCAL do_identifier(sym,cont) X LVAL sym; int cont; X{ X int lev,off; X if (sym == true) X putcbyte(OP_T); X else if (findvariable(sym,&lev,&off)) X cd_evariable(OP_EREF,lev,off); X else X cd_variable(OP_GREF,sym); X do_continuation(cont); X} X X/* do_continuation - compile a continuation */ XLOCAL do_continuation(cont) X int cont; X{ X switch (cont) { X case C_RETURN: X putcbyte(OP_RETURN); X break; X case C_NEXT: X break; X } X} X X/* add_level - add a nesting level */ XLOCAL int add_level() X{ X int oldcbase; X X /* establish a new environment frame */ X rplaca(info,newframe(car(info),1)); X rplacd(info,cons(NIL,cdr(info))); X X /* setup the base of the code for this function */ X oldcbase = cbase; X cbase = cptr; X X /* return the old code base */ X return (oldcbase); X} X X/* remove_level - remove a nesting level */ XLOCAL remove_level(oldcbase) X int oldcbase; X{ X /* restore the previous environment */ X rplaca(info,cdr(car(info))); X rplacd(info,cdr(cdr(info))); X X /* restore the base and code pointer */ X cptr = cbase; X cbase = oldcbase; X} X X/* findvariable - find an environment variable */ XLOCAL int findvariable(sym,plev,poff) X LVAL sym; int *plev,*poff; X{ X int lev,off; X LVAL e,a; X for (e = car(info), lev = 0; envp(e); e = cdr(e), ++lev) X for (a = getelement(car(e),0), off = 1; consp(a); a = cdr(a), ++off) X if (sym == car(a)) { X *plev = lev; X *poff = off; X return (TRUE); X } X return (FALSE); X} X X/* findcvariable - find an environment variable in the current frame */ XLOCAL int findcvariable(sym,poff) X LVAL sym; int *poff; X{ X int off; X LVAL a; X a = getelement(car(car(info)),0); X for (off = 1; consp(a); a = cdr(a), ++off) X if (sym == car(a)) { X *poff = off; X return (TRUE); X } X return (FALSE); X} X X/* findliteral - find a literal in the literal frame */ XLOCAL int findliteral(lit) X LVAL lit; X{ X int o = FIRSTLIT; X LVAL t,p; X if (t = car(cdr(info))) { X for (p = NIL; consp(t); p = t, t = cdr(t), ++o) X if (equal(lit,car(t))) X return (o); X rplacd(p,cons(lit,NIL)); X } X else X rplaca(cdr(info),cons(lit,NIL)); X return (o); X} X X/* cd_variable - compile a variable reference */ XLOCAL cd_variable(op,sym) X int op; LVAL sym; X{ X putcbyte(op); X putcbyte(findliteral(sym)); X} X X/* cd_evariable - compile an environment variable reference */ XLOCAL cd_evariable(op,lev,off) X int op,lev,off; X{ X putcbyte(op); X putcbyte(lev); X putcbyte(off); X} X X/* cd_literal - compile a literal reference */ XLOCAL cd_literal(lit) X LVAL lit; X{ X if (lit == NIL) X putcbyte(OP_NIL); X else if (lit == true) X putcbyte(OP_T); X else { X putcbyte(OP_LIT); X putcbyte(findliteral(lit)); X } X} X X/* putcbyte - put a code byte into data space */ XLOCAL int putcbyte(b) X int b; X{ X int adr; X if (cptr >= CMAX) X xlabort("insufficient code space"); X adr = (cptr - cbase); X cbuff[cptr++] = b; X return (adr); X} X X/* putcword - put a code word into data space */ XLOCAL int putcword(w) X int w; X{ X int adr; X adr = putcbyte(w >> 8); X putcbyte(w); X return (adr); X} X X/* fixup - fixup a reference chain */ XLOCAL fixup(chn) X int chn; X{ X int val,hval,nxt; X X /* store the value into each location in the chain */ X val = cptr - cbase; hval = val >> 8; X for (; chn; chn = nxt) { X nxt = (cbuff[cbase+chn] << 8) | (cbuff[cbase+chn+1]); X cbuff[cbase+chn] = hval; X cbuff[cbase+chn+1] = val; X } X} X X/* length - find the length of a list */ Xint length(list) X LVAL list; X{ X int len; X for (len = 0; consp(list); list = cdr(list)) X ++len; X return (len); X} X X/* instruction output formats */ X#define FMT_NONE 0 X#define FMT_BYTE 1 X#define FMT_LOFF 2 X#define FMT_WORD 3 X#define FMT_EOFF 4 X Xtypedef struct { int ot_code; char *ot_name; int ot_fmt; } OTDEF; XOTDEF otab[] = { X{ OP_BRT, "BRT", FMT_WORD }, X{ OP_BRF, "BRF", FMT_WORD }, X{ OP_BR, "BR", FMT_WORD }, X{ OP_LIT, "LIT", FMT_LOFF }, X{ OP_GREF, "GREF", FMT_LOFF }, X{ OP_GSET, "GSET", FMT_LOFF }, X{ OP_EREF, "EREF", FMT_EOFF }, X{ OP_ESET, "ESET", FMT_EOFF }, X{ OP_SAVE, "SAVE", FMT_WORD }, X{ OP_CALL, "CALL", FMT_BYTE }, X{ OP_RETURN, "RETURN", FMT_NONE }, X{ OP_T, "T", FMT_NONE }, X{ OP_NIL, "NIL", FMT_NONE }, X{ OP_PUSH, "PUSH", FMT_NONE }, X{ OP_CLOSE, "CLOSE", FMT_NONE }, X{ OP_DELAY, "DELAY", FMT_NONE }, X X{ OP_FRAME, "FRAME", FMT_BYTE }, X{ OP_MVARG, "MVARG", FMT_BYTE }, X{ OP_MVOARG, "MVOARG", FMT_BYTE }, X{ OP_MVRARG, "MVRARG", FMT_BYTE }, X{ OP_ADROP, "ADROP", FMT_NONE }, X{ OP_ALAST, "ALAST", FMT_NONE }, X X{ OP_AREF, "AREF", FMT_LOFF }, X{ OP_ASET, "ASET", FMT_LOFF }, X X{0,0,0} X}; X X/* decode_procedure - decode the instructions in a code object */ Xdecode_procedure(fptr,fun) X LVAL fptr,fun; X{ X int len,lc,n; X LVAL code,env; X code = getcode(fun); X env = getenv(fun); X len = getslength(getbcode(code)); X for (lc = 0; lc < len; lc += n) X n = decode_instruction(fptr,code,lc,env); X} X X/* decode_instruction - decode a single bytecode instruction */ Xint decode_instruction(fptr,code,lc,env) X LVAL fptr,code; int lc; LVAL env; X{ X unsigned char *cp; X char buf[100]; X OTDEF *op; X NTDEF *np; X int i,n=1; X LVAL tmp; X X /* get a pointer to the bytecodes for this instruction */ X cp = getstring(getbcode(code)) + lc; X X /* show the address and opcode */ X if (tmp = getcname(code)) X sprintf(buf,"%s:%04x %02x ",getstring(getpname(tmp)),lc,*cp); X else { X sprintf(buf,AFMT,code); xlputstr(fptr,buf); X sprintf(buf,":%04x %02x ",lc,*cp); X } X xlputstr(fptr,buf); X X /* display the operands */ X for (op = otab; op->ot_name; ++op) X if (*cp == op->ot_code) { X switch (op->ot_fmt) { X case FMT_NONE: X sprintf(buf," %s\n",op->ot_name); X xlputstr(fptr,buf); X break; X case FMT_BYTE: X sprintf(buf,"%02x %s %02x\n",cp[1],op->ot_name,cp[1]); X xlputstr(fptr,buf); X n += 1; X break; X case FMT_LOFF: X sprintf(buf,"%02x %s %02x ; ",cp[1],op->ot_name,cp[1]); X xlputstr(fptr,buf); X xlprin1(getelement(code,cp[1]),fptr); X xlterpri(fptr); X n += 1; X break; X case FMT_WORD: X sprintf(buf,"%02x %02x %s %02x%02x\n",cp[1],cp[2], X op->ot_name,cp[1],cp[2]); X xlputstr(fptr,buf); X n += 2; X break; X case FMT_EOFF: X if ((i = cp[1]) == 0) X tmp = getvnames(code); X else { X for (tmp = env; i > 1; --i) tmp = cdr(tmp); X tmp = getelement(car(tmp),0); X } X for (i = cp[2]; i > 1; --i) tmp = cdr(tmp); X sprintf(buf,"%02x %02x %s %02x %02x ; ",cp[1],cp[2], X op->ot_name,cp[1],cp[2]); X xlputstr(fptr,buf); X xlprin1(car(tmp),fptr); X xlterpri(fptr); X n += 2; X break; X } X return (n); X } X X /* check for an integrable function */ X for (np = ntab; np->nt_name; ++np) X if (*cp == np->nt_code) { X sprintf(buf," %s\n",np->nt_name); X xlputstr(fptr,buf); X return (n); X } X X /* unknown opcode */ X sprintf(buf," <UNKNOWN>\n"); X xlputstr(fptr,buf); X return (n); X} END_OF_FILE if test 33402 -ne `wc -c <'Src/xscom.c'`; then echo shar: \"'Src/xscom.c'\" unpacked with wrong size! fi # end of 'Src/xscom.c' fi echo shar: End of archive 5 \(of 7\). cp /dev/null ark5isdone MISSING="" for I in 1 2 3 4 5 6 7 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 7 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Mail submissions (sources or binaries) to <amiga@cs.odu.edu>. Mail comments to the moderator at <amiga-request@cs.odu.edu>. Post requests for sources, and general discussion to comp.sys.amiga.