view mc-inline.c @ 510:2bd6ff6ee9a8

inline continue...
author kono
date Sun, 25 Dec 2005 16:29:40 +0900
parents e58848f6ebc1
children 14c7faf78910
line wrap: on
line source

/* Micro-C Partial Evaluator Part */
/* $Id$ */

#include <stdio.h>
#include "mc.h"
#include "mc-parse.h"
#include "mc-codegen.h"
#include "mc-switch.h"
#include "mc-code.h"
#include "mc-inline.h"

static int pvartable;
static int pdisp;

/*
    Basic code generator from parse tree
 */

extern void
st_decl(int e1){
    // NMTBL *n = (NMTBL *)caddr(e1);
    // int stmode = cadddr(e1);
}
 
extern void
st_if(int e1){
    int l1,l2,slfree;
    int e2=caddr(e1),e3;
    // conv->if_();
    slfree=lfree;
    checkret();
    l1 = bexpr(car(e2),0,fwdlabel());
    // conv->if_then_();
    g_expr_u(cadr(e2));
    checkret();
    if ((e3=caddr(e2))) {  // else
        // conv->if_else_();
	if ((l2 = control))
	    gen_jmp(l2=fwdlabel());
	fwddef(l1);
	g_expr_u(e3);
	checkret();
	if (l2) fwddef(l2);
    } else {
	fwddef(l1);
    }
    // conv->if_endif_();
}

 
extern void
st_do(int e1){
    int sbreak,scontinue,l;

    sbreak=blabel;
    scontinue=clabel;
    blabel=fwdlabel();
    clabel=fwdlabel();
    control=1;
    checkret();
    l=backdef();
    // conv->dowhile_();
    g_expr_u(cadddr(e1));
    checkret();
    // conv->dowhile_cond_();
    bexpr(caddr(e1),1,l);
    // conv->dowhile_end_();
    fwddef(blabel);
    clabel=scontinue;
    blabel=sbreak;
}

 
extern void
st_while(int e1){
    int sbreak,scontinue,e;

    sbreak=blabel;
    scontinue=clabel;
    blabel=fwdlabel();
    control=1;
    checkret();
    clabel=backdef();
    // conv->while_();
    // conv->while_body_();
    if(!(e=cadddr(e1))) {
	bexpr(caddr(e1),1,clabel);
        // conv->sm_();
    } else {
	bexpr(caddr(e1),0,blabel);
	g_expr_u(e);
	checkret();
	if(control)
	    gen_jmp(clabel);
    }
    // conv->while_end_();
    fwddef(blabel);
    clabel=scontinue;
    blabel=sbreak;
}

 
extern void
st_for(int e1){
    int p0,p1,p2,body;
    int l,e;
    int sbreak=blabel;
    int scontinue=clabel;

    e = caddr(e1); 
    p0 = car(e); p1 = cadr(e); p2 = caddr(e); body = cadddr(e);

    blabel=fwdlabel();
    // conv->for_();
    if (p0) {
	checkret();
	g_expr_u(p0);
    }
    // conv->for1_();
    control=1;
    checkret();
    l=backdef();
    if (p1) {
	bexpr(p1,0,blabel);
    }
    // conv->for2_();
    // conv->for_body_();
    if (!p2) {
        clabel=l;
	g_expr_u(body);
	checkret();
    } else {
        clabel=fwdlabel();
	g_expr_u(body);
	checkret();
	fwddef(clabel);
	g_expr_u(p2);
    }
    // conv->for_end_();
    gen_jmp(l);
    fwddef(blabel);
    clabel=scontinue;
    blabel=sbreak;
}

 
extern void
st_switch(int e1){
    int sbreak,scase,sdefault,slfree,svalue,slist;

    checkret();
    slist = cslist;
    cslist = 0;
    sbreak=blabel;      /* save parents break label */
    blabel=fwdlabel();
    sdefault=dlabel;    /* save parents default label */
    dlabel=0;
    scase=cslabel;      /* save parents next case label */
    // conv->switch_();
    slfree=lfree;
    svalue=csvalue1;      /* save parents switch value */
    gexpr(caddr(e1),1);   /* switch value */
    csvalue1=csvalue() ;
    // conv->switch_body_();
    cslabel = control = 0;
    g_expr_u(cadddr(e1));
    // conv->switch_end_();
    checkret();
#if CASE_CODE
    if (control) gen_jmp(blabel);
    genswitch(cslist,cslabel);
#else
    if(dlabel) def_label(cslabel,dlabel);
    else fwddef(cslabel);
#endif
    csvalue1=svalue;
    cslabel=scase;
    dlabel=sdefault;
    fwddef(blabel);
    blabel=sbreak;
    cslist = slist;
}

 
extern void
st_comp(int e1){
    g_expr_u(caddr(e1));
}

 
extern void
st_break(int e1){
    checkret();
    // conv->break_();
    if (control)
	gen_jmp(blabel);
}

 
extern void
st_continue(int e1){
    checkret();
    // conv->continue_();
    if (control) gen_jmp(clabel);
}

 
extern void
st_case(int e1){
#if CASE_CODE
    int l,clist=caddr(e1),c;
    l = fwdlabel();
    // conv->case_begin_(0,0);
    // conv->case_(0,0);
    if (retpending) {
        ret(); retpending=0;
    }
    if (!cslabel) {
        if (!control) {
            cmpdimm(car(clist),csvalue1,cslabel=fwdlabel(),1);
            caddr(clist)=0;
        } else {
            error(-1);
        }
    }
    while(clist) {
	caddr(clist) = l;
        clist = cadr(c=clist); cadr(c) = 0;  // insert destroy cadr of clist
        cslist=insert_ascend(cslist,c,docase_eq);
    }
    fwddef(l);
    control=1;
#else
    /* casading branch implementation */
    int c,l;
    c = caddr(e1);
    if (retpending) {
	ret(); retpending=0;
    }
    // conv->case_begin_(0,0);
    // conv->case_(0,0);
    l=fwdlabel();
    if (control) {
        control=0;
        gen_jmp(l);
    }
    if (cslabel) fwddef(cslabel);
    while(cadr(c)) {
        cmpdimm(car(c),csvalue1,l,0);
        c=cadr(c);
    }
    cmpdimm(car(c),csvalue1,cslabel=fwdlabel(),1);
    if (l) fwddef(l);
#endif
}

 
extern void
st_default(int e1){
    control=1;
    checkret();
    if (dlabel) error(STERR);  // double default:
    dlabel = backdef();
    // conv->case_(0,1);
}

 
extern void
st_return(int e1){
    int e;

    if (!cslabel) gen_jmp(cslabel = fwdlabel());
    if(!(e=caddr(e1))) {
        // conv->return_();
        // conv->return_end_();
        retpending = 1;
	g_expr_u(cadr(e1));
        return;
    }
    // conv->return_();
    if (struct_return) {
	if ((car(type)==STRUCT || car(type)==UNION)&&
		size(type)==cadr(struct_return)) {
	    if(car(e)==RSTRUCT && car(cadr(e))==FUNCTION) {
		/* pass the return pointer to the called function */
		replace_return_struct(cadr(e),
		    rvalue_t(car(struct_return),caddr(struct_return)));
		replace_return_struct(cadr(e),
		    rvalue_t(car(struct_return),caddr(struct_return)));
		g_expr_u(cadr(e));
	    } else {
		type = caddr(struct_return);
		// e1 = rvalue_t(cadr(struct_return),INT); /* size */
		e1 = cadr(struct_return); /* size */
		g_expr_u(list4(STASS,rvalue(car(struct_return)),e,e1));
	    }
	} else {
	    error(TYERR); /* should check compatible */
	}
    } else {
	g_expr(correct_type(e,cadr(fnptr->ty)));
    }
    // conv->return_end_();
    retpending = 1;
}

 
extern void
st_goto(int e){
    NMTBL *nlist,*nptr0;
    int t,e1,e2,env;

    checkret();
    // conv->goto_();
    e1 = caddr(e);
    if (car(e1)==RINDIRECT) {
	gen_indirect_goto(cadr(e1));
	return ;
    } else if (car(e1)==FLABEL) {
	nlist = (NMTBL *)cadr(e1);
	nptr0 = name_space_search(nlist,0);
        t = nptr0->sc;
        if (t==EMPTY||t==EXTRN1||t==EXTRN) {
	    nptr0 = make_local_scope(nlist,nptr0,0);
            nptr0->sc = FLABEL;
            nptr0->dsp = fwdlabel();
        } else if (!(t==FLABEL||t==BLABEL)) {
            error(STERR);
        }
	gen_jmp(nptr0->dsp);
        control=0;
        // conv->sm_();
        // conv->goto_label_(nptr0);
        return ;
    } else {
	/*   CbC continuation */
	// conv->jump_(env);
	e2 = cadr(e1);
	env = caddr(e1);
	if (car(e2) == FNAME) {
	    nptr0=(NMTBL *)cadr(e2);
	    if (nptr0->sc==EMPTY)
		nptr0->sc = EXTRN1;
	    else if(nptr0->sc==FUNCTION)
		nptr0->sc = CODE;
	    if (nptr0->ty>0&&car(nptr0->ty)==FUNCTION)
		car(nptr0->ty)=CODE;
	}
	gexpr(list3(CODE,e1,env),0);
	control=0;
	// conv->sm_();
	return ;
    }
}


#if ASM_CODE
extern void
st_asm(int e1){
    checkret();
    g_expr_u(list3(ASM,caddr(e1),cadddr(e1)));
}
#endif

 
extern void
st_label(int e1){
    NMTBL *nptr,*nlist;
    nlist = (NMTBL *)caddr(e1);
    nptr = name_space_search(nlist,0);
    control=1;
    checkret();
    if(nptr->sc == FLABEL) {
	fwddef(nptr->dsp);
    } else if(nptr->sc != EMPTY && nptr->sc != EXTRN1 && nptr->sc !=BLABEL) {
	error(TYERR);
    } else {
	nptr->sc=EMPTY;
	nptr = make_local_scope(nlist,nptr,0);
	nptr->sc = BLABEL;
	nptr->dsp = backdef();
    }
    // conv->label_();
}

extern void
st_comment(int e1){
    gen_comment((char *)caddr(e1));
}

/* 
   partial evaluator
 */

static int
p_vartable(int e,int adisp,int ldisp)
{
    int i;
    int pvartable = getfree(adisp-ldisp); // have to be local heap
    pdisp = pvartable-ldisp;
    for(i=ldisp;i<0;i++) {
	heap[pdisp+i] = 0;
    }
    return pvartable;
}

static int
p_lvar(int e1)
{
    int sz = is_memory(e1);
    int d = cadr(e1);
    int d1;
    if ((d1=(heap[pdisp+d]))) return d1;
    return (heap[pdisp+d]=list3(LVAR,new_lvar(sz),0));
}

static int
pfunction(int e)
{
    // list4(INLINE,e1,arglist,ftype);
    // include code segement case
    int e1 = pexpr(cadr(e));
    int arglist = caddr(e);
    int newargs = 0;
    int ftype = cadddr(e);
    int e3;
    for (e3 = arglist; e3; e3 = cadr(e3)) {
	newargs = list3( pexpr(car(e3)), cadr(e3), caddr(e3));
    }
    newargs = reverse0(newargs);
    return list4(INLINE,e1,newargs,ftype);
}

static int
prindirect(int e)
{
    return list3(car(e),pexpr(cadr(e)),caddr(e));
}

static int
paddress(int e)
{
    return list2(car(e),pexpr(cadr(e)));
}

static int
p_conv(int e1,int e2)
{
    return list3(CONV,pexpr(e1),e2);
}

static int
pbinop(int op,int e1,int e2)
{
    return list3(op,pexpr(e1),pexpr(e2));
}

static int
prexpr(int op,int e1,int e2)
{
    return list3(op,pexpr(e1),pexpr(e2));
}

static int
psassign(int e)
{
    return list4(car(e),pexpr(cadr(e)),pexpr(caddr(e)),cadddr(e));
}

static int
passign(int e)
{
    return list3(car(e),pexpr(cadr(e)),pexpr(caddr(e)));
}

static int
passop(int e)
{
    return list4(car(e),pexpr(cadr(e)),pexpr(caddr(e)),cadddr(e));
}

static int
pdassign(int e)
{
    return list3(car(e),pexpr(cadr(e)),pexpr(caddr(e)));
}

static int
pdassop(int e)
{
    return list4(car(e),pexpr(cadr(e)),pexpr(caddr(e)),cadddr(e));
}

static int
plassign(int e)
{
    return list3(car(e),pexpr(cadr(e)),pexpr(caddr(e)));
}

static int
plassop(int e)
{
    return list4(car(e),pexpr(cadr(e)),pexpr(caddr(e)),cadddr(e));
}

static int
palloc(int e)
{
    return list2(car(e),pexpr(cadr(e)));
}

static int
pcomma(int e1,int e2)
{
    return list3(COMMA,pexpr(e1),pexpr(e2));
}

static int
prbit_field(int e)
{
    return list3(car(e),pexpr(cadr(e)),caddr(e));
}

static int
pbassign(int e)
{
    return list4(car(e),pexpr(cadr(e)),pexpr(caddr(e)),cadddr(e));
}

static int
pbassop(int e)
{
    return list4(car(e),pexpr(cadr(e)),pexpr(caddr(e)),cadddr(e));
}

static int
p_decl(int e)
{
    // list4(ST_DECL,parse,(int)n,stmode);
    int stmode=cadddr(e);
    NMTBL *n=(NMTBL*)caddr(e);
    int dsp = n->dsp;
    int v;
    // in real partial evaluation, we have to check whether this variable
    // is used or not.
    switch(stmode) {
    case REGISTER:
	switch(n->ty) {
	case ULONGLONG: case LONGLONG:
	    v = get_lregister_var(n); break;
	case FLOAT: 
	    v = get_dregister_var(n,0); break;
	case DOUBLE: 
	    v = get_dregister_var(n,1); break;
	default:
	    if (scalar(n->ty)) 
		v = get_dregister_var(n,1);
	    else
		error(TYERR);
	}
    case EXTRN: case EXTRN1: case STATIC:
	    return pexpr(cadr(e));
    default:
	v = list3(LVAR,new_lvar(size(n->dsp)),(int)n);
    }
    if (heap[pdisp+dsp]) error(-1);
    heap[pdisp+dsp]=v;
    return pexpr(cadr(e));
}

static int
p_if(int e1)
{
    int cond,l1,l2;
    int e2=caddr(e1),e3;
    cond = pexpr(car(e2));
    // conv->if_then_();
    l1 = pexpr(cadr(e2));
    if ((e3=caddr(e2))) {  // else
	l2 = pexpr(e3);
    } else {
	l2 = 0;
    }
    return list3(ST_IF,pexpr(cadr(e1)),list3(cond,l1,l2));
}

static int
p_do(int e)
{
    return list4(ST_DO,pexpr(cadr(e)),pexpr(caddr(e)),pexpr(cadddr(e)));
}

static int
p_while(int e)
{
    return list4(ST_WHILE,pexpr(cadr(e)),pexpr(caddr(e)),pexpr(cadddr(e)));
}

static int
p_for(int e)
{
    int e1=caddr(e);
    int p0=car(e1);
    int p1=cadr(e1);
    int p2=caddr(e1);
    int p3=cadddr(e1);
    return list3(ST_FOR,pexpr(cadr(e)),
	list4(pexpr(p0),pexpr(p1),pexpr(p2),pexpr(p3)));
}

static int
p_switch(int e)
{
    return list4(ST_SWITCH,pexpr(cadr(e)),pexpr(caddr(e)),pexpr(cadddr(e)));
}

static int
p_comp(int e)
{
    return list3(ST_COMP,pexpr(cadr(e)),pexpr(caddr(e)));
}

static int
p_break(int e)
{
    return list2(ST_BREAK,pexpr(cadr(e)));
}

static int
p_continue(int e)
{
    return list2(ST_CONTINUE,pexpr(cadr(e)));
}

static int
p_case(int e)
{
    int new=0,clist = caddr(e);
    // insert destory clist, we have to copy it now
    for(;clist;clist=cadr(clist))
	new=glist3(car(clist),new,0);
    return list3(ST_CASE,pexpr(cadr(e)),reverse0(new));
}

static int
p_default(int e)
{
    return list2(ST_DEFAULT,pexpr(cadr(e)));
}

static int
p_return(int e)
{
    return list3(ST_RETURN,pexpr(cadr(e)),pexpr(caddr(e)));
}

static int
p_goto(int e)
{
    int e1;
    if ((e1=caddr(e))) {
	switch(car(e1)) {
	case RINDIRECT: e1=pexpr(e1); break;
	case CODE: e1=list3(CODE,pexpr(cadr(e1)),pexpr(caddr(e1))); break;
	case FLABEL: break;
	}
    }
    return list3(ST_GOTO,pexpr(cadr(e)),e1);
}

static int
p_list_expr(int e)
{
    int e3,new = 0;
    for (e3 = e; e3; e3 = cadr(e3)) {
	new= list2( pexpr(car(e3)), new);
    }
    return reverse0(new);
}

static int
p_asm(int e)
{
    int param=caddr(e);
    int e1 = p_list_expr(cadddr(e));
    return list4(ST_ASM,pexpr(cadr(e)),param,e1);
}

static int
p_label(int e)
{
    return list3(ST_LABEL,pexpr(cadr(e)),caddr(e));
}

static int
p_bool(int e)
{
    error(-1);
    return e;
}

static int
p_comment(int e)
{
    return list3(ST_COMMENT,pexpr(cadr(e)),caddr(e));
}

static int
pgen_inline(int e)
{
    int e3;
    int narg;

    /* inline function arguments */
    narg = 0;
    for (e3 = caddr(e); e3; e3 = cadr(e3)) {
	narg=list3(pexpr(car(e3)),narg,caddr(e3));
    }
    return list4(INLINE,cadr(e),reverse0(narg),cadddr(e));
}

extern int
pexpr(int e1)
{
    int e2,e3;

    // if (inmode) error(-1);
    if (e1==0) return 0;
    e2 = cadr(e1);
    switch (car(e1)){
    case GVAR: case RGVAR: case CRGVAR: case CURGVAR: case SRGVAR:
    case SURGVAR: case REGISTER:
#if FLOAT_CODE
    case DREGISTER: case FREGISTER:
    case FRGVAR: case  DRGVAR:
#endif
#if LONGLONG_CODE
    case LREGISTER:
    case LRGVAR: case LURGVAR:
#endif
    case LABEL: case CONST: 
#if FLOAT_CODE
    case DCONST: case FCONST:
#endif
#if LONGLONG_CODE
    case LCONST:
#endif
    case STRING:
    case FNAME:
    case FLABEL:
    case RSTRUCT:
	return e1;
    case LVAR:
    case RLVAR: case CRLVAR: case CURLVAR: case SRLVAR: case SURLVAR:
#if FLOAT_CODE
    case FRLVAR: case DRLVAR: 
#endif
#if LONGLONG_CODE
    case LRLVAR: case LURLVAR: 
#endif
	return e1;
    case IVAR:
	return p_lvar(e1);
    case FUNCTION:
	return pfunction(e1);
    case CODE:
	return list2(car(e1),pexpr(e2));
    case INLINE:
	return pgen_inline(e1);
    case INDIRECT:
	return prindirect(e1);
    case RINDIRECT:  case URINDIRECT:  
    case CRINDIRECT: case CURINDIRECT:
    case SRINDIRECT: case SURINDIRECT:
#if FLOAT_CODE
    case FRINDIRECT: case DRINDIRECT: 
#endif
#if LONGLONG_CODE
    case LRINDIRECT: case LURINDIRECT:
#endif
	return prindirect(e1);
    case ADDRESS:
	return paddress(e1);
    case MINUS:
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==CONST) return list2(CONST,-cadr(e3));
	return list2(car(e1),e3);
#if LONGLONG_CODE
    case LMINUS: 
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==LCONST) return llist2(LCONST,-lcadr(e3));
	return list2(car(e1),e3);
#endif
#if FLOAT_CODE
    case DMINUS: 
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==DCONST) return dlist2(DCONST,-dcadr(e3));
	if (car(e3)==FCONST) return dlist2(FCONST,-dcadr(e3));
	return list2(car(e1),e3);
    case FMINUS: 
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==DCONST) return dlist2(DCONST,-dcadr(e3));
	if (car(e3)==FCONST) return dlist2(FCONST,-dcadr(e3));
	return list2(car(e1),e3);
#endif
    case CONV: 
	return p_conv(caddr(e1),e2);
    case BNOT:   /* ~ */
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==CONST) return list2(CONST,~cadr(e3));
	return list2(BNOT,e3);
    case LNOT:   /* !  */
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==CONST) return list2(CONST,!cadr(e3));
	return list2(LNOT,e3);
    case PREINC:
    case UPREINC:
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==CONST) return list2(CONST,cadr(e3)+1);
	return list4(car(e1),e3,caddr(e1),cadddr(e1));
    case POSTINC:
    case UPOSTINC:
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==CONST) return e3;
	return list4(car(e1),e3,caddr(e1),cadddr(e1));
#if FLOAT_CODE
    case DPREINC:   /* ++d */
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==FCONST) return dlist2(FCONST,dcadr(e3)+cadr(e2));
	if (car(e3)==DCONST) return dlist2(DCONST,dcadr(e3)+cadr(e2));
	return list4(car(e1),e3,caddr(e1),cadddr(e1));
    case DPOSTINC:  /* d++ */
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==FCONST||car(e3)==DCONST) return e3;
	return list4(car(e1),e3,caddr(e1),cadddr(e1));
    case FPREINC:   /* ++f */
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==FCONST) return dlist2(FCONST,dcadr(e3)+cadr(e2));
	if (car(e3)==DCONST) return dlist2(DCONST,dcadr(e3)+cadr(e2));
	return list4(car(e1),e3,caddr(e1),cadddr(e1));
    case FPOSTINC:  /* f++ */
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==FCONST||car(e3)==DCONST) return e3;
	return list4(car(e1),e3,caddr(e1),cadddr(e1));
#endif
#if LONGLONG_CODE
    case LPREINC:   /* ++d */
    case LUPREINC:   /* ++d */
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==LCONST) return llist2(LCONST,lcadr(e3)+cadr(e2));
	return list4(car(e1),e3,caddr(e1),cadddr(e1));
    case LPOSTINC:  /* d++ */
    case LUPOSTINC:  /* d++ */
	if ((e3 = pexpr(e2))==e2) return e1;
	if (car(e3)==LCONST) return e3;
	return list4(car(e1),e3,caddr(e1),cadddr(e1));
#endif
    case MUL: case UMUL:
    case DIV: case UDIV:	   
    case MOD: case UMOD:
    case LSHIFT: case ULSHIFT: case RSHIFT: case URSHIFT:
    case ADD: case SUB: case BAND: case EOR: case BOR: case CMP: case CMPGE:
    case UCMP: case CMPEQ: case CMPNEQ: case UCMPGE:
#if FLOAT_CODE
    case DMUL: case DDIV:
    case DADD: case DSUB:
    case DCMP: case DCMPGE: case DCMPEQ: case DCMPNEQ:
    case FMUL: case FDIV:
    case FADD: case FSUB:
    case FCMP: case FCMPGE: case FCMPEQ: case FCMPNEQ:
#endif
#if LONGLONG_CODE
    case LMUL: case LUMUL:
    case LDIV: case LUDIV:	   
    case LMOD: case LUMOD:
    case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT:
    case LADD: case LSUB: case LBAND: case LEOR: case LBOR: case LCMP:
#endif
	return pbinop(car(e1),e2,caddr(e1));
    case LCOND: case DCOND: case FCOND: case COND:
	e3 = pexpr(e2);
	if (car(e3)==CONST) return pexpr(cadr(e3)?caddr(e1):cadddr(e1));
	return list4(car(e1),e3,pexpr(cadr(e1)),pexpr(cadr(e2)));
    case STASS: 
	return psassign(e1);
    case ASS: case CASS: case SASS:
	return passign(e1);
    case SASSOP: case SUASSOP:
    case ASSOP: case CASSOP: case CUASSOP:
	return passop(e1);
#if FLOAT_CODE
    case FASS: case DASS: 
	return pdassign(e1);
    case DASSOP: case FASSOP:
	return pdassop(e1);
#endif
#if LONGLONG_CODE
    case LASS: 
	return plassign(e1);
    case LASSOP: case LUASSOP:
	return plassop(e1);
#endif
    case ALLOCA:
	return palloc(e2);
    case BUILTINP:
	return list2(CONST,is_const(pexpr(e2)));
    case COMMA:
	return pcomma(pexpr(e2),pexpr(caddr(e1)));
    case RETURN:
    case ENVIRONMENT:
    case LCALL:
	return e1;
// relational operator
    case GT: case UGT: case GE: case UGE: case LT:
    case ULT: case LE: case ULE:
    case DOP+GT: case DOP+GE: case DOP+LT: case DOP+LE:
    case FOP+GT: case FOP+GE: case FOP+LT: case FOP+LE:
    case FOP+EQ: case FOP+NEQ:
    case EQ: case NEQ: case DOP+EQ: case DOP+NEQ:
	return prexpr(car(e1),cadr(e1),caddr(e1));
#if BIT_FIELD_CODE
    case RBIT_FIELD:
	return prbit_field(e1);
    case BASS:
	return pbassign(e1);
    case BPREINC:
    case BPOSTINC:
    case BASSOP:
	return pbassop(e1);
#endif
#if ASM_CODE
    case ASM:
	return list3(ASM,list4(
	    car(e2),cadr(e2),caddr(e2),cadddr(e2)),
		caddr(e1));
#endif
    case ST_DECL:         return p_decl(e1);
    case ST_IF:           return p_if(e1);
    case ST_DO:           return p_do(e1);
    case ST_WHILE:        return p_while(e1);
    case ST_FOR:          return p_for(e1);
    case ST_SWITCH:       return p_switch(e1);
    case ST_COMP:         return p_comp(e1);
    case ST_BREAK:        return p_break(e1);
    case ST_CONTINUE:     return p_continue(e1);
    case ST_CASE:         return p_case(e1);
    case ST_DEFAULT:      return p_default(e1);
    case ST_RETURN:       return p_return(e1);
    case ST_GOTO:         return p_goto(e1);
    case ST_ASM:          return p_asm(e1);
    case ST_LABEL:        return p_label(e1);
    case ST_COMMENT:      return p_comment(e1);
    default:
	return p_bool(e1);
  }
  return VOID;
}

#define round4(i)   ((i+(SIZE_OF_INT-1))&~(SIZE_OF_INT-1))

extern int
gen_inline(int e)
{
    int svartable = pvartable;
    NMTBL *sfnptr = fnptr;
    int sdisp = pdisp;
    int narg,arg;
    NMTBL *n = (NMTBL*)cadr(cadr(e));
    int e1 = attr_value(n,INLINE);
    int parse = car(e1);      // inline parse tree
    int arg_disp = cadr(e1);  // size of local variable
    int e3,t,e4,dots;
    int ret_type = function_type(cadddr(e),&dots);

    fnptr = n;   // st_return see this
    pvartable = p_vartable(e,arg_disp,caddr(e1));
    /* inline function arguments */
    narg = 0;
    for (e3 = e1 = reverse0(caddr(e)); e3; e3 = cadr(e3)) {
        t=caddr(e3);  // type
	e4 = car(e3);
	if (is_const(e4) /* ||(is_memory(e3)&&is_readonly(e3)) */ ) {
	    heap[pdisp+narg]=e4;
	} else {
	    arg = heap[pdisp+narg]=list3(LVAR,new_lvar(size(t)),0);
	    //  should contain correct argument variable name
	    g_expr_u(assign_expr0(arg,e4,t,t));
	}
	narg ++;
    }
    caddr(e) = reverse0(e1);  // make it normal
    e = pexpr(parse);
    pdisp = sdisp;
    pvartable = svartable;
    // how to handle return value?
    g_expr_u(e);
    fnptr = sfnptr;

    return ret_type;
}

/* end */