Category : Miscellaneous Language Source Code
Archive   : XSCHME02.ZIP
Filename : XSCOM.C

 
Output of file : XSCOM.C contained in archive : XSCHME02.ZIP
/* xscom.c - a simple scheme bytecode compiler */
/* Copyright (c) 1988, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use */

#include "xscheme.h"
#include "xsbcode.h"

/* size of code buffer */
#define CMAX 4000

/* continuation types */
#define C_RETURN -1
#define C_NEXT -2

/* macro to check for a lambda list keyword */
#define lambdakey(x) ((x) == lk_optional || (x) == lk_rest)

/* external variables */
extern LVAL lk_optional,lk_rest,true;

/* local variables */
static LVAL info; /* compiler info */

/* code buffer */
static unsigned char cbuff[CMAX]; /* base of code buffer */
static int cbase; /* base for current function */
static int cptr; /* code buffer pointer */

/* forward declarations */
int do_define(),do_set(),do_quote(),do_lambda(),do_delay();
int do_let(),do_letrec(),do_letstar(),do_cond(),do_and(),do_or();
int do_if(),do_begin(),do_while(),do_access();
LVAL make_code_object();

/* integrable function table */
typedef struct { char *nt_name; int nt_code,nt_args; } NTDEF;
static NTDEF *nptr,ntab[] = {
"ATOM", OP_ATOM, 1,
"EQ?", OP_EQ, 2,
"NULL?", OP_NULL, 1,
"NOT", OP_NULL, 1,
"CONS", OP_CONS, 2,
"CAR", OP_CAR, 1,
"CDR", OP_CDR, 1,
"SET-CAR!", OP_SETCAR, 2,
"SET-CDR!", OP_SETCDR, 2,
"+", OP_ADD, -2,
"-", OP_SUB, -2,
"*", OP_MUL, -2,
"QUOTIENT", OP_QUO, -2,
"<", OP_LSS, -2,
"=", OP_EQL, -2,
">", OP_GTR, -2,
0
};

/* special form table */
typedef struct { char *ft_name; int (*ft_fcn)(); } FTDEF;
static FTDEF ftab[] = {
"QUOTE", do_quote,
"LAMBDA", do_lambda,
"DELAY", do_delay,
"LET", do_let,
"LET*", do_letstar,
"LETREC", do_letrec,
"DEFINE", do_define,
"SET!", do_set,
"IF", do_if,
"COND", do_cond,
"BEGIN", do_begin,
"SEQUENCE", do_begin,
"AND", do_and,
"OR", do_or,
"WHILE", do_while,
"ACCESS", do_access,
0
};

/* xlcompile - compile an expression */
LVAL xlcompile(expr,ctenv)
LVAL expr,ctenv;
{
/* initialize the compile time environment */
info = cons(NIL,NIL); cpush(info);
rplaca(info,newframe(ctenv,1));
rplacd(info,cons(NIL,NIL));

/* setup the base of the code for this function */
cbase = cptr = 0;

/* setup the entry code */
putcbyte(OP_FRAME);
putcbyte(1);

/* compile the expression */
do_expr(expr,C_RETURN);

/* build the code object */
settop(make_code_object(NIL));
return (pop());
}

/* xlfunction - compile a function */
LVAL xlfunction(fun,fargs,body,ctenv)
LVAL fun,fargs,body,ctenv;
{
/* initialize the compile time environment */
info = cons(NIL,NIL); cpush(info);
rplaca(info,newframe(ctenv,1));
rplacd(info,cons(NIL,NIL));

/* setup the base of the code for this function */
cbase = cptr = 0;

/* compile the lambda list and the function body */
parse_lambda_list(fargs,body);
do_begin(body,C_RETURN);

/* build the code object */
settop(make_code_object(fun));
return (pop());
}

/* do_expr - compile an expression */
LOCAL do_expr(expr,cont)
LVAL expr; int cont;
{
LVAL fun;
if (consp(expr)) {
fun = car(expr);
if (!symbolp(fun) || (!in_ntab(expr,cont) && !in_ftab(expr,cont)))
do_call(expr,cont);
}
else if (symbolp(expr))
do_identifier(expr,cont);
else
do_literal(expr,cont);
}

/* in_ntab - check for a function in ntab */
LOCAL int in_ntab(expr,cont)
LVAL expr; int cont;
{
unsigned char *pname;
pname = getstring(getpname(car(expr)));
for (nptr = ntab; nptr->nt_name; ++nptr)
if (strcmp(pname,nptr->nt_name) == 0) {
do_nary(nptr->nt_code,nptr->nt_args,expr,cont);
return (TRUE);
}
return (FALSE);
}

/* in_ftab - check for a function in ftab */
LOCAL int in_ftab(expr,cont)
LVAL expr; int cont;
{
unsigned char *pname;
FTDEF *fptr;
pname = getstring(getpname(car(expr)));
for (fptr = ftab; fptr->ft_name; ++fptr)
if (strcmp(pname,fptr->ft_name) == 0) {
(*fptr->ft_fcn)(cdr(expr),cont);
return (TRUE);
}
return (FALSE);
}

/* do_define - handle the (DEFINE ... ) expression */
LOCAL do_define(form,cont)
LVAL form; int cont;
{
if (atom(form))
xlerror("expecting symbol or function template",form);
define1(car(form),cdr(form),cont);
}

/* define1 - helper routine for do_define */
LOCAL define1(list,body,cont)
LVAL list,body; int cont;
{
LVAL fargs;
int off;

/* handle nested definitions */
if (consp(list)) {
cpush(cons(xlenter("LAMBDA"),NIL)); /* (LAMBDA) */
rplacd(top(),cons(cdr(list),NIL)); /* (LAMBDA args) */
rplacd(cdr(top()),body); /* (LAMBDA args body) */
settop(cons(top(),NIL)); /* ((LAMBDA args body)) */
define1(car(list),top(),cont);
drop(1);
}

/* compile procedure definitions */
else {

/* make sure it's a symbol */
if (!symbolp(list))
xlerror("expecting a symbol",list);

/* check for a procedure definition */
if (consp(body)
&& consp(car(body))
&& car(car(body)) == xlenter("LAMBDA")) {
fargs = car(cdr(car(body)));
body = cdr(cdr(car(body)));
cd_fundefinition(list,fargs,body);
}

/* compile the value expression or procedure body */
else
do_begin(body,C_NEXT);

/* define the variable value */
if (findcvariable(list,&off))
cd_evariable(OP_ESET,0,off);
else
cd_variable(OP_GSET,list);
do_literal(list,cont);
}
}

/* do_set - compile the (SET! ... ) expression */
LOCAL do_set(form,cont)
LVAL form; int cont;
{
if (atom(form))
xlerror("expecting symbol or ACCESS form",form);
else if (symbolp(car(form)))
do_setvar(form,cont);
else if (consp(car(form)))
do_setaccess(form,cont);
else
xlerror("expecting symbol or ACCESS form",form);
}

/* do_setvar - compile the (SET! var value) expression */
LOCAL do_setvar(form,cont)
LVAL form; int cont;
{
int lev,off;
LVAL sym;

/* get the variable name */
sym = car(form);

/* compile the value expression */
form = cdr(form);
if (atom(form))
xlerror("expecting value expression",form);
do_expr(car(form),C_NEXT);

/* set the variable value */
if (findvariable(sym,&lev,&off))
cd_evariable(OP_ESET,lev,off);
else
cd_variable(OP_GSET,sym);
do_continuation(cont);
}

/* do_quote - compile the (QUOTE ... ) expression */
LOCAL do_quote(form,cont)
LVAL form; int cont;
{
if (atom(form))
xlerror("expecting quoted expression",form);
do_literal(car(form),cont);
}

/* do_lambda - compile the (LAMBDA ... ) expression */
LOCAL do_lambda(form,cont)
LVAL form; int cont;
{
if (atom(form))
xlerror("expecting argument list",form);
cd_fundefinition(NIL,car(form),cdr(form));
do_continuation(cont);
}

/* cd_fundefinition - compile the function */
LOCAL cd_fundefinition(fun,fargs,body)
LVAL fun,fargs,body;
{
int oldcbase;

/* establish a new environment frame */
oldcbase = add_level();

/* compile the lambda list and the function body */
parse_lambda_list(fargs,body);
do_begin(body,C_RETURN);

/* build the code object */
cpush(make_code_object(fun));

/* restore the previous environment */
remove_level(oldcbase);

/* compile code to create a closure */
do_literal(pop(),C_NEXT);
putcbyte(OP_CLOSE);
}

/* parse_lambda_list - parse the formal argument list */
LOCAL parse_lambda_list(fargs,body)
LVAL fargs,body;
{
LVAL arg,restarg,new,last;
int frame,slotn;

/* setup the entry code */
putcbyte(OP_FRAME);
frame = putcbyte(0);

/* initialize the argument name list and slot number */
restarg = last = NIL;
slotn = 1;

/* handle each required argument */
while (consp(fargs) && (arg = car(fargs)) && !lambdakey(arg)) {

/* make sure the argument is a symbol */
if (!symbolp(arg))
xlerror("variable must be a symbol",arg);

/* add the argument name to the name list */
new = cons(arg,NIL);
if (last) rplacd(last,new);
else setelement(car(car(info)),0,new);
last = new;

/* generate an instruction to move the argument into the frame */
putcbyte(OP_MVARG);
putcbyte(slotn++);

/* move the formal argument list pointer ahead */
fargs = cdr(fargs);
}

/* check for the '#!optional' argument */
if (consp(fargs) && car(fargs) == lk_optional) {
fargs = cdr(fargs);

/* handle each optional argument */
while (consp(fargs) && (arg = car(fargs)) && !lambdakey(arg)) {

/* make sure the argument is a symbol */
if (!symbolp(arg))
xlerror("#!optional variable must be a symbol",arg);

/* add the argument name to the name list */
new = cons(arg,NIL);
if (last) rplacd(last,new);
else setelement(car(car(info)),0,new);
last = new;

/* move the argument into the frame */
putcbyte(OP_MVOARG);
putcbyte(slotn++);

/* move the formal argument list pointer ahead */
fargs = cdr(fargs);
}
}

/* check for the '#!rest' argument */
if (consp(fargs) && car(fargs) == lk_rest) {
fargs = cdr(fargs);

/* handle the rest argument */
if (consp(fargs) && (restarg = car(fargs)) && !lambdakey(restarg)) {

/* make sure the argument is a symbol */
if (!symbolp(restarg))
xlerror("#!rest variable must be a symbol",restarg);

/* add the argument name to the name list */
new = cons(restarg,NIL);
if (last) rplacd(last,new);
else setelement(car(car(info)),0,new);
last = new;

/* make the #!rest argument list */
putcbyte(OP_MVRARG);
putcbyte(slotn++);

/* move the formal argument list pointer ahead */
fargs = cdr(fargs);
}
else
xlerror("expecting the #!rest variable");
}

/* check for the a dotted tail */
if (restarg == NIL && symbolp(fargs)) {
restarg = fargs;

/* add the argument name to the name list */
new = cons(restarg,NIL);
if (last) rplacd(last,new);
else setelement(car(car(info)),0,new);
last = new;

/* make the #!rest argument list */
putcbyte(OP_MVRARG);
putcbyte(slotn++);
fargs = NIL;
}

/* check for the end of the argument list */
if (fargs != NIL)
xlerror("bad argument list tail",fargs);

/* make sure the user didn't supply too many arguments */
if (restarg == NIL)
putcbyte(OP_ALAST);

/* scan the body for internal definitions */
slotn += find_internal_definitions(body,last);

/* fixup the frame instruction */
cbuff[cbase+frame] = slotn;
}

/* find_internal_definitions - find internal definitions */
LOCAL int find_internal_definitions(body,last)
LVAL body,last;
{
LVAL define,sym,new;
int n=0;

/* look for all (define...) forms */
for (define = xlenter("DEFINE"); consp(body); body = cdr(body))
if (consp(car(body)) && car(car(body)) == define) {
sym = cdr(car(body)); /* the rest of the (define...) form */
if (consp(sym)) { /* make sure there is a second subform */
sym = car(sym); /* get the second subform */
while (consp(sym))/* check for a procedure definition */
sym = car(sym);
if (symbolp(sym)) {
new = cons(sym,NIL);
if (last) rplacd(last,new);
else setelement(car(car(info)),0,new);
last = new;
++n;
}
}
}
return (n);
}

/* do_delay - compile the (DELAY ... ) expression */
LOCAL do_delay(form,cont)
LVAL form; int cont;
{
int oldcbase;

/* check argument list */
if (atom(form))
xlerror("expecting delay expression",form);

/* establish a new environment frame */
oldcbase = add_level();

/* setup the entry code */
putcbyte(OP_FRAME);
putcbyte(1);

/* compile the expression */
do_expr(car(form),C_RETURN);

/* build the code object */
cpush(make_code_object(NIL));

/* restore the previous environment */
remove_level(oldcbase);

/* compile code to create a closure */
do_literal(pop(),C_NEXT);
putcbyte(OP_DELAY);
do_continuation(cont);
}

/* do_let - compile the (LET ... ) expression */
LOCAL do_let(form,cont)
LVAL form; int cont;
{
/* handle named let */
if (consp(form) && symbolp(car(form)))
do_named_let(form,cont);

/* handle unnamed let */
else
cd_let(NIL,form,cont);
}

/* do_named_let - compile the (LET name ... ) expression */
LOCAL do_named_let(form,cont)
LVAL form; int cont;
{
int oldcbase,nxt;

/* save a continuation */
if (cont != C_RETURN) {
putcbyte(OP_SAVE);
nxt = putcword(0);
}

/* establish a new environment frame */
oldcbase = add_level();
setelement(car(car(info)),0,cons(car(form),NIL));

/* setup the entry code */
putcbyte(OP_FRAME);
putcbyte(2);

/* compile the let expression */
cd_let(car(form),cdr(form),C_RETURN);

/* build the code object */
cpush(make_code_object(NIL));

/* restore the previous environment */
remove_level(oldcbase);

/* compile code to create a closure */
do_literal(pop(),C_NEXT);
putcbyte(OP_CLOSE);

/* apply the function */
putcbyte(OP_CALL);
putcbyte(1);

/* target for the continuation */
if (cont != C_RETURN)
fixup(nxt);
}

/* cd_let - code a let expression */
LOCAL cd_let(name,form,cont)
LVAL name,form; int cont;
{
int oldcbase,nxt,lev,off,n;

/* make sure there is a binding list */
if (atom(form) || !listp(car(form)))
xlerror("expecting binding list",form);

/* save a continuation */
if (cont != C_RETURN) {
putcbyte(OP_SAVE);
nxt = putcword(0);
}

/* push the initialization expressions */
n = push_init_expressions(car(form));

/* establish a new environment frame */
oldcbase = add_level();

/* compile the binding list */
parse_let_variables(car(form),cdr(form));

/* compile the body of the let/letrec */
do_begin(cdr(form),C_RETURN);

/* build the code object */
cpush(make_code_object(NIL));

/* restore the previous environment */
remove_level(oldcbase);

/* compile code to create a closure */
do_literal(pop(),C_NEXT);
putcbyte(OP_CLOSE);

/* store the procedure */
if (name && findvariable(name,&lev,&off))
cd_evariable(OP_ESET,lev,off);

/* apply the function */
putcbyte(OP_CALL);
putcbyte(n);

/* target for the continuation */
if (cont != C_RETURN)
fixup(nxt);
}

/* do_letrec - compile the (LETREC ... ) expression */
LOCAL do_letrec(form,cont)
LVAL form; int cont;
{
int oldcbase,nxt,n;

/* make sure there is a binding list */
if (atom(form) || !listp(car(form)))
xlerror("expecting binding list",form);

/* save a continuation */
if (cont != C_RETURN) {
putcbyte(OP_SAVE);
nxt = putcword(0);
}

/* push the initialization expressions */
n = push_dummy_values(car(form));

/* establish a new environment frame */
oldcbase = add_level();

/* compile the binding list */
parse_let_variables(car(form),cdr(form));

/* compile instructions to set the bound variables */
set_bound_variables(car(form));

/* compile the body of the let/letrec */
do_begin(cdr(form),C_RETURN);

/* build the code object */
cpush(make_code_object(NIL));

/* restore the previous environment */
remove_level(oldcbase);

/* compile code to create a closure */
do_literal(pop(),C_NEXT);
putcbyte(OP_CLOSE);

/* apply the function */
putcbyte(OP_CALL);
putcbyte(n);

/* target for the continuation */
if (cont != C_RETURN)
fixup(nxt);
}

/* do_letstar - compile the (LET* ... ) expression */
LOCAL do_letstar(form,cont)
LVAL form; int cont;
{
int nxt;

/* make sure there is a binding list */
if (atom(form) || !listp(car(form)))
xlerror("expecting binding list",form);

/* handle the case where there are bindings */
if (consp(car(form))) {

/* save a continuation */
if (cont != C_RETURN) {
putcbyte(OP_SAVE);
nxt = putcword(0);
}

/* build the nested lambda expressions */
letstar1(car(form),cdr(form));

/* target for the continuation */
if (cont != C_RETURN)
fixup(nxt);
}

/* handle the case where there are no bindings */
else
do_begin(cdr(form),cont);
}

/* letstar1 - helper routine for let* */
LOCAL letstar1(blist,body)
LVAL blist,body;
{
int oldcbase,n;

/* push the next initialization expressions */
cpush(cons(car(blist),NIL));
n = push_init_expressions(top());

/* establish a new environment frame */
oldcbase = add_level();

/* handle the case where there are more bindings */
if (consp(cdr(blist))) {
parse_let_variables(top(),NIL);
letstar1(cdr(blist),body);
}

/* handle the last binding */
else {
parse_let_variables(top(),body);
do_begin(body,C_RETURN);

}

/* build the code object */
settop(make_code_object(NIL));

/* restore the previous environment */
remove_level(oldcbase);

/* compile code to create a closure */
do_literal(pop(),C_NEXT);
putcbyte(OP_CLOSE);

/* apply the function */
putcbyte(OP_CALL);
putcbyte(n);
}

/* push_dummy_values - push dummy values for a 'letrec' expression */
LOCAL int push_dummy_values(blist)
LVAL blist;
{
int n=0;
if (consp(blist)) {
putcbyte(OP_NIL);
for (; consp(blist); blist = cdr(blist), ++n)
putcbyte(OP_PUSH);
}
return (n);
}

/* push_init_expressions - push init expressions for a 'let' expression */
LOCAL int push_init_expressions(blist)
LVAL blist;
{
int n;
if (consp(blist)) {
n = push_init_expressions(cdr(blist));
if (consp(car(blist)) && consp(cdr(car(blist))))
do_expr(car(cdr(car(blist))),C_NEXT);
else
putcbyte(OP_NIL);
putcbyte(OP_PUSH);
return (n+1);
}
return (0);

}

/* parse_let_variables - parse the binding list */
LOCAL parse_let_variables(blist,body)
LVAL blist,body;
{
LVAL arg,new,last;
int frame,slotn;

/* setup the entry code */
putcbyte(OP_FRAME);
frame = putcbyte(0);

/* initialize the argument name list and slot number */
last = NIL;
slotn = 1;

/* handle each required argument */
while (consp(blist) && (arg = car(blist))) {

/* make sure the argument is a symbol */
if (symbolp(arg))
new = cons(arg,NIL);
else if (consp(arg) && symbolp(car(arg)))
new = cons(car(arg),NIL);
else
xlerror("invalid binding",arg);

/* add the argument name to the name list */
if (last) rplacd(last,new);
else setelement(car(car(info)),0,new);
last = new;

/* generate an instruction to move the argument into the frame */
putcbyte(OP_MVARG);
putcbyte(slotn++);

/* move the formal argument list pointer ahead */
blist = cdr(blist);
}
putcbyte(OP_ALAST);

/* scan the body for internal definitions */
slotn += find_internal_definitions(body,last);

/* fixup the frame instruction */
cbuff[cbase+frame] = slotn;
}

/* set_bound_variables - set bound variables in a 'letrec' expression */
LOCAL set_bound_variables(blist)
LVAL blist;
{
int lev,off;
for (; consp(blist); blist = cdr(blist)) {
if (consp(car(blist)) && consp(cdr(car(blist)))) {
do_expr(car(cdr(car(blist))),C_NEXT);
if (findvariable(car(car(blist)),&lev,&off))
cd_evariable(OP_ESET,lev,off);
else
xlerror("compiler error -- can't find",car(car(blist)));
}
}
}

/* make_code_object - build a code object */
LOCAL LVAL make_code_object(fun)
LVAL fun;
{
unsigned char *cp;
LVAL code,p;
int i;

/* create a code object */
code = newcode(FIRSTLIT + length(car(cdr(info)))); cpush(code);
setbcode(code,newstring(cptr - cbase));
setcname(code,fun); /* function name */
setvnames(code,getelement(car(car(info)),0));/* lambda list variables */

/* copy the literals into the code object */
for (i = FIRSTLIT, p = car(cdr(info)); consp(p); p = cdr(p), ++i)
setelement(code,i,car(p));

/* copy the byte codes */
for (i = cbase, cp = getstring(getbcode(code)); i < cptr; )
*cp++ = cbuff[i++];

/* return the new code object */
return (pop());
}

/* do_cond - compile the (COND ... ) expression */
LOCAL do_cond(form,cont)
LVAL form; int cont;
{
int nxt,end;
if (consp(form)) {
for (end = 0; consp(form); form = cdr(form)) {
if (atom(car(form)))
xlerror("expecting a cond clause",form);
do_expr(car(car(form)),C_NEXT);
putcbyte(OP_BRF);
nxt = putcword(0);
if (cdr(car(form)))
do_begin(cdr(car(form)),cont);
else
do_continuation(cont);
if (cont == C_NEXT) {
putcbyte(OP_BR);
end = putcword(end);
}
fixup(nxt);
}
fixup(end);
}
else
putcbyte(OP_NIL);
do_continuation(cont);
}

/* do_and - compile the (AND ... ) expression */
LOCAL do_and(form,cont)
LVAL form; int cont;
{
int end;
if (consp(form)) {
for (end = 0; consp(form); form = cdr(form)) {
if (cdr(form)) {
do_expr(car(form),C_NEXT);
putcbyte(OP_BRF);
end = putcword(end);
}
else
do_expr(car(form),cont);
}
fixup(end);
}
else
putcbyte(OP_T);
do_continuation(cont);
}

/* do_or - compile the (OR ... ) expression */
LOCAL do_or(form,cont)
LVAL form; int cont;
{
int end;
if (consp(form)) {
for (end = 0; consp(form); form = cdr(form)) {
if (cdr(form)) {
do_expr(car(form),C_NEXT);
putcbyte(OP_BRT);
end = putcword(end);
}
else
do_expr(car(form),cont);
}
fixup(end);
}
else
putcbyte(OP_NIL);
do_continuation(cont);
}

/* do_if - compile the (IF ... ) expression */
LOCAL do_if(form,cont)
LVAL form; int cont;
{
int nxt,end;

/* compile the test expression */
if (atom(form))
xlerror("expecting test expression",form);
do_expr(car(form),C_NEXT);

/* skip around the 'then' clause if the expression is false */
putcbyte(OP_BRF);
nxt = putcword(0);

/* skip to the 'then' clause */
form = cdr(form);
if (atom(form))
xlerror("expecting then clause",form);

/* compile the 'then' and 'else' clauses */
if (consp(cdr(form))) {
if (cont == C_NEXT) {
do_expr(car(form),C_NEXT);
putcbyte(OP_BR);
end = putcword(0);
}
else {
do_expr(car(form),cont);
end = -1;
}
fixup(nxt);
do_expr(car(cdr(form)),cont);
nxt = end;
}

/* compile just a 'then' clause */
else
do_expr(car(form),cont);

/* handle the end of the statement */
if (nxt >= 0) {
fixup(nxt);
do_continuation(cont);
}
}

/* do_begin - compile the (BEGIN ... ) expression */
LOCAL do_begin(form,cont)
LVAL form; int cont;
{
if (consp(form))
for (; consp(form); form = cdr(form))
if (consp(cdr(form)))
do_expr(car(form),C_NEXT);
else
do_expr(car(form),cont);
else {
putcbyte(OP_NIL);
do_continuation(cont);
}
}

/* do_while - compile the (WHILE ... ) expression */
LOCAL do_while(form,cont)
LVAL form; int cont;
{
int loop,nxt;

/* make sure there is a test expression */
if (atom(form))
xlerror("expecting test expression",form);

/* skip around the 'body' to the test expression */
putcbyte(OP_BR);
nxt = putcword(0);

/* compile the loop body */
loop = cptr - cbase;
do_begin(cdr(form),C_NEXT);

/* label for the first iteration */
fixup(nxt);

/* compile the test expression */
nxt = cptr - cbase;
do_expr(car(form),C_NEXT);

/* skip around the 'body' if the expression is false */
putcbyte(OP_BRT);
putcword(loop);

/* compile the continuation */
do_continuation(cont);
}

/* do_access - compile the (ACCESS var env) expression */
LOCAL do_access(form,cont)
LVAL form; int cont;
{
LVAL sym;

/* get the variable name */
if (atom(form) || !symbolp(car(form)))
xlerror("expecting symbol",form);
sym = car(form);

/* compile the environment expression */
form = cdr(form);
if (atom(form))
xlerror("expecting environment expression",form);
do_expr(car(form),C_NEXT);

/* get the variable value */
cd_variable(OP_AREF,sym);
do_continuation(cont);
}

/* do_setaccess - compile the (SET! (ACCESS var env) value) expression */
LOCAL do_setaccess(form,cont)
LVAL form; int cont;
{
LVAL aform,sym;

/* make sure this is an access form */
aform = car(form);
if (atom(aform) || car(aform) != xlenter("ACCESS"))
xlerror("expecting an ACCESS form",aform);

/* get the variable name */
aform = cdr(aform);
if (atom(aform) || !symbolp(car(aform)))
xlerror("expecting symbol",aform);
sym = car(aform);

/* compile the environment expression */
aform = cdr(aform);
if (atom(aform))
xlerror("expecting environment expression",aform);
do_expr(car(aform),C_NEXT);
putcbyte(OP_PUSH);

/* compile the value expression */
form = cdr(form);
if (atom(form))
xlerror("expecting value expression",form);
do_expr(car(form),C_NEXT);

/* set the variable value */
cd_variable(OP_ASET,sym);
do_continuation(cont);
}

/* do_call - compile a function call */
LOCAL do_call(form,cont)
LVAL form; int cont;
{
int nxt,n;

/* save a continuation */
if (cont != C_RETURN) {
putcbyte(OP_SAVE);
nxt = putcword(0);
}

/* compile each argument expression */
n = push_args(cdr(form));

/* compile the function itself */
do_expr(car(form),C_NEXT);

/* apply the function */
putcbyte(OP_CALL);
putcbyte(n);

/* target for the continuation */
if (cont != C_RETURN)
fixup(nxt);
}

/* push_args - compile the arguments for a function call */
LOCAL int push_args(form)
LVAL form;
{
int n;
if (consp(form)) {
n = push_args(cdr(form));
do_expr(car(form),C_NEXT);
putcbyte(OP_PUSH);
return (n+1);
}
return (0);
}

/* do_nary - compile nary operator expressions */
LOCAL do_nary(op,n,form,cont)
int op,n; LVAL form; int cont;
{
if (n < 0 && (n = (-n)) != length(cdr(form)))
do_call(form,cont);
else {
push_nargs(cdr(form),n);
putcbyte(op);
do_continuation(cont);
}
}

/* push_nargs - compile the arguments for an inline function call */
LOCAL int push_nargs(form,n)
LVAL form; int n;
{
if (consp(form)) {
if (n == 0)
xlerror("too many arguments",form);
if (push_nargs(cdr(form),n-1))
putcbyte(OP_PUSH);
do_expr(car(form),C_NEXT);
return (TRUE);
}
if (n)
xlerror("too few arguments",form);
return (FALSE);
}

/* do_literal - compile a literal */
LOCAL do_literal(lit,cont)
LVAL lit; int cont;
{
cd_literal(lit);
do_continuation(cont);
}

/* do_identifier - compile an identifier */
LOCAL do_identifier(sym,cont)
LVAL sym; int cont;
{
int lev,off;
if (sym == true)
putcbyte(OP_T);
else if (findvariable(sym,&lev,&off))
cd_evariable(OP_EREF,lev,off);
else
cd_variable(OP_GREF,sym);
do_continuation(cont);
}

/* do_continuation - compile a continuation */
LOCAL do_continuation(cont)
int cont;
{
switch (cont) {
case C_RETURN:
putcbyte(OP_RETURN);
break;
case C_NEXT:
break;
}
}

/* add_level - add a nesting level */
LOCAL int add_level()
{
int oldcbase;

/* establish a new environment frame */
rplaca(info,newframe(car(info),1));
rplacd(info,cons(NIL,cdr(info)));

/* setup the base of the code for this function */
oldcbase = cbase;
cbase = cptr;

/* return the old code base */
return (oldcbase);
}

/* remove_level - remove a nesting level */
LOCAL remove_level(oldcbase)
int oldcbase;
{
/* restore the previous environment */
rplaca(info,cdr(car(info)));
rplacd(info,cdr(cdr(info)));

/* restore the base and code pointer */
cptr = cbase;
cbase = oldcbase;
}

/* findvariable - find an environment variable */
LOCAL int findvariable(sym,plev,poff)
LVAL sym; int *plev,*poff;
{
int lev,off;
LVAL e,a;
for (e = car(info), lev = 0; envp(e); e = cdr(e), ++lev)
for (a = getelement(car(e),0), off = 1; consp(a); a = cdr(a), ++off)
if (sym == car(a)) {
*plev = lev;
*poff = off;
return (TRUE);
}
return (FALSE);
}

/* findcvariable - find an environment variable in the current frame */
LOCAL int findcvariable(sym,poff)
LVAL sym; int *poff;
{
int off;
LVAL a;
a = getelement(car(car(info)),0);
for (off = 1; consp(a); a = cdr(a), ++off)
if (sym == car(a)) {
*poff = off;
return (TRUE);
}
return (FALSE);
}

/* findliteral - find a literal in the literal frame */
LOCAL int findliteral(lit)
LVAL lit;
{
int o = FIRSTLIT;
LVAL t,p;
if (t = car(cdr(info))) {

for (p = NIL; consp(t); p = t, t = cdr(t), ++o)
if (equal(lit,car(t)))
return (o);
rplacd(p,cons(lit,NIL));
}
else
rplaca(cdr(info),cons(lit,NIL));
return (o);
}

/* cd_variable - compile a variable reference */
LOCAL cd_variable(op,sym)
int op; LVAL sym;
{
putcbyte(op);
putcbyte(findliteral(sym));
}

/* cd_evariable - compile an environment variable reference */
LOCAL cd_evariable(op,lev,off)
int op,lev,off;
{
putcbyte(op);
putcbyte(lev);
putcbyte(off);
}

/* cd_literal - compile a literal reference */
LOCAL cd_literal(lit)
LVAL lit;
{
if (lit == NIL)
putcbyte(OP_NIL);
else if (lit == true)
putcbyte(OP_T);
else {
putcbyte(OP_LIT);
putcbyte(findliteral(lit));
}
}

/* putcbyte - put a code byte into data space */
LOCAL int putcbyte(b)
int b;
{
int adr;
if (cptr >= CMAX)
xlabort("insufficient code space");
adr = (cptr - cbase);
cbuff[cptr++] = b;
return (adr);
}


/* putcword - put a code word into data space */
LOCAL int putcword(w)
int w;
{
int adr;
adr = putcbyte(w >> 8);
putcbyte(w);
return (adr);
}

/* fixup - fixup a reference chain */
LOCAL fixup(chn)
int chn;
{
int val,hval,nxt;

/* store the value into each location in the chain */
val = cptr - cbase; hval = val >> 8;
for (; chn; chn = nxt) {
nxt = (cbuff[cbase+chn] << 8) | (cbuff[cbase+chn+1]);
cbuff[cbase+chn] = hval;
cbuff[cbase+chn+1] = val;
}
}

/* length - find the length of a list */
int length(list)
LVAL list;
{
int len;
for (len = 0; consp(list); list = cdr(list))
++len;
return (len);
}

/* instruction output formats */
#define FMT_NONE 0
#define FMT_BYTE 1
#define FMT_LOFF 2
#define FMT_WORD 3
#define FMT_EOFF 4

typedef struct { int ot_code; char *ot_name; int ot_fmt; } OTDEF;
OTDEF otab[] = {
{ OP_BRT, "BRT", FMT_WORD },
{ OP_BRF, "BRF", FMT_WORD },
{ OP_BR, "BR", FMT_WORD },
{ OP_LIT, "LIT", FMT_LOFF },
{ OP_GREF, "GREF", FMT_LOFF },
{ OP_GSET, "GSET", FMT_LOFF },
{ OP_EREF, "EREF", FMT_EOFF },
{ OP_ESET, "ESET", FMT_EOFF },
{ OP_SAVE, "SAVE", FMT_WORD },
{ OP_CALL, "CALL", FMT_BYTE },
{ OP_RETURN, "RETURN", FMT_NONE },
{ OP_T, "T", FMT_NONE },
{ OP_NIL, "NIL", FMT_NONE },
{ OP_PUSH, "PUSH", FMT_NONE },
{ OP_CLOSE, "CLOSE", FMT_NONE },
{ OP_DELAY, "DELAY", FMT_NONE },

{ OP_FRAME, "FRAME", FMT_BYTE },
{ OP_MVARG, "MVARG", FMT_BYTE },
{ OP_MVOARG, "MVOARG", FMT_BYTE },
{ OP_MVRARG, "MVRARG", FMT_BYTE },
{ OP_ADROP, "ADROP", FMT_NONE },
{ OP_ALAST, "ALAST", FMT_NONE },

{ OP_AREF, "AREF", FMT_LOFF },
{ OP_ASET, "ASET", FMT_LOFF },

{0,0,0}
};

/* decode_procedure - decode the instructions in a code object */
decode_procedure(fptr,fun)
LVAL fptr,fun;
{
int len,lc,n;
LVAL code,env;
code = getcode(fun);
env = getenv(fun);
len = getslength(getbcode(code));
for (lc = 0; lc < len; lc += n)
n = decode_instruction(fptr,code,lc,env);
}

/* decode_instruction - decode a single bytecode instruction */
int decode_instruction(fptr,code,lc,env)
LVAL fptr,code; int lc; LVAL env;
{
unsigned char *cp;
char buf[100];
OTDEF *op;
NTDEF *np;
int i,n=1;
LVAL tmp;

/* get a pointer to the bytecodes for this instruction */
cp = getstring(getbcode(code)) + lc;

/* show the address and opcode */
if (tmp = getcname(code))
sprintf(buf,"%s:%04x %02x ",getstring(getpname(tmp)),lc,*cp);
else {
sprintf(buf,AFMT,code); xlputstr(fptr,buf);
sprintf(buf,":%04x %02x ",lc,*cp);
}
xlputstr(fptr,buf);

/* display the operands */
for (op = otab; op->ot_name; ++op)
if (*cp == op->ot_code) {
switch (op->ot_fmt) {
case FMT_NONE:
sprintf(buf," %s\n",op->ot_name);
xlputstr(fptr,buf);
break;
case FMT_BYTE:
sprintf(buf,"%02x %s %02x\n",cp[1],op->ot_name,cp[1]);
xlputstr(fptr,buf);
n += 1;
break;
case FMT_LOFF:
sprintf(buf,"%02x %s %02x ; ",cp[1],op->ot_name,cp[1]);
xlputstr(fptr,buf);
xlprin1(getelement(code,cp[1]),fptr);
xlterpri(fptr);
n += 1;
break;
case FMT_WORD:
sprintf(buf,"%02x %02x %s %02x%02x\n",cp[1],cp[2],
op->ot_name,cp[1],cp[2]);
xlputstr(fptr,buf);
n += 2;
break;
case FMT_EOFF:
if ((i = cp[1]) == 0)
tmp = getvnames(code);
else {
for (tmp = env; i > 1; --i) tmp = cdr(tmp);
tmp = getelement(car(tmp),0);
}
for (i = cp[2]; i > 1; --i) tmp = cdr(tmp);
sprintf(buf,"%02x %02x %s %02x %02x ; ",cp[1],cp[2],
op->ot_name,cp[1],cp[2]);
xlputstr(fptr,buf);
xlprin1(car(tmp),fptr);
xlterpri(fptr);
n += 2;
break;
}
return (n);
}

/* check for an integrable function */
for (np = ntab; np->nt_name; ++np)
if (*cp == np->nt_code) {
sprintf(buf," %s\n",np->nt_name);
xlputstr(fptr,buf);
return (n);
}

/* unknown opcode */
sprintf(buf," \n");
xlputstr(fptr,buf);
return (n);
}


  3 Responses to “Category : Miscellaneous Language Source Code
Archive   : XSCHME02.ZIP
Filename : XSCOM.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/