view mc-tree.c @ 935:7672a37e7545 default tip

Raspbery PI ARM support begin
author kono
date Sat, 24 Dec 2016 03:02:57 +0000
parents f7803d618f36
children
line wrap: on
line source

/* Micro-C tree print routine */

/************************************************************************
** Copyright (C) 2006 Shinji Kono
** 連絡先: 琉球大学情報工学科 河野 真治  
** (E-Mail Address: kono@ie.u-ryukyu.ac.jp)
**
**    このソースのいかなる複写,改変,修正も許諾します。ただし、
**    その際には、誰が貢献したを示すこの部分を残すこと。
**    再配布や雑誌の付録などの問い合わせも必要ありません。
**    営利利用も上記に反しない範囲で許可します。
**    バイナリの配布の際にはversion messageを保存することを条件とします。
**    このプログラムについては特に何の保証もしない、悪しからず。
**
**    Everyone is permitted to do anything on this program 
**    including copying, modifying, improving,
**    as long as you don't try to pretend that you wrote it.
**    i.e., the above copyright notice has to appear in all copies.  
**    Binary distribution requires original version messages.
**    You don't have to ask before copying, redistribution or publishing.
**    THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.
***********************************************************************/

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

extern void tree_print(int e);
extern void tree_parse(int e);
extern void tree_print_t(int e,int t);
extern void type_print(int type,NMTBL *n,FILE *out);
extern void type_print1(int type,NMTBL *n,FILE *out,int cont);
extern void sym_print(int type,FILE *out);
static void print_function_call(int e, FILE *out);
static void print_operator(int e, FILE *vout);
static void print_statement(int e, FILE *vout);

/* ascendant order for binary search */

typedef
struct tree_node {
    int tree_type;
    char *tree_name;
    char *tree_args;
    int tree_order;
} tree_node_type;

static int
tree_nodes(int id, char **name, char **args, int *order) {
    int found = 1;
    switch(id%SOP) {
    case DOTS: *name = "..."; *args=""; *order=-1; break;
    case LMACRO: *name = "lmacro"; *args=""; *order=-1; break;
    case FMACRO: *name = "fmacro"; *args=""; *order=-1; break;
    case KONST: *name = "const"; *args=""; *order=-1; break;
    case DEFINED: *name = "defined"; *args=""; *order=14; break;
    case ENVIRONMENT: *name = "environment"; *args=""; *order=14; break;
    case CODE: *name = "code"; *args=""; *order=-1; break;
    case C_FILE: *name = "__FILE__"; *args=""; *order=14; break;
    case C_FUNCTION: *name = "__FUNCTION__"; *args=""; *order=14; break;
    case C_LINE: *name = "__LINE__"; *args=""; *order=14; break;
    case REGISTER: *name = "register"; *args=""; *order=-1; break;
    case CAST: *name = "cast"; *args="e"; *order=14; break;
    case ASM: *name = "__asm__"; *args="eeee"; *order=-1; break;
    case ST_ASM: *name = "__asm__"; *args="eeee"; *order=-1; break;
    case VOID: *name = "void"; *args=""; *order=-1; break;
    case EXTRN: *name = "extern"; *args=""; *order=14; break;
    case EXTRN1: *name = "extern"; *args=""; *order=14; break;
    case SHORT: *name = "short"; *args=""; *order=-1; break;
    case USHORT: *name = "unsigned short"; *args=""; *order=-1; break;
    case LONG: *name = "long"; *args=""; *order=-1; break;
    case TYPE: *name = "type"; *args=""; *order=-1; break;
    case VOLATILE: *name = "volatile"; *args=""; *order=-1; break;
    case SIZEOF: *name = "sizeof"; *args="e"; *order=13; break;
    case TYPEDEF: *name = "typedef"; *args=""; *order=-1; break;
    case FLABEL: *name = "flabel"; *args=""; *order=-1; break;
    case BLABEL: *name = "blabel"; *args=""; *order=-1; break;
    case LABEL: *name = "label"; *args="e"; *order=-1; break;
    case ST_LABEL: *name = "label"; *args="e"; *order=-1; break;
    case MACRO: *name = "macro"; *args=""; *order=-1; break;
    case STRING: *name = "string"; *args=""; *order=14; break;
    case IDENT: *name = "ident"; *args=""; *order=14; break;
    case ENUM: *name = "enum"; *args=""; *order=14; break;
    case FIELD: *name = "field"; *args=""; *order=-1; break;
    case TAG: *name = "tag"; *args=""; *order=-1; break;
    case RESERVE: *name = "reserve"; *args=""; *order=-1; break;
    case ST_DEFAULT: *name = "default"; *args=""; *order=-1; break;
    case ATTRIBUTE: *name = "__attribute__"; *args=""; *order=-1; break;
    case ST_CASE: *name = "case"; *args=""; *order=-1; break;
    case ST_SWITCH: *name = "switch"; *args=""; *order=-1; break;
    case ST_WHILE: *name = "while"; *args=""; *order=-1; break;
    case ST_DO: *name = "do"; *args=""; *order=-1; break;
    case ST_FOR: *name = "for"; *args=""; *order=-1; break;
    case ELSE: *name = "else"; *args=""; *order=-1; break;
    case ST_IF: *name = "if"; *args=""; *order=-1; break;
    case CONTINUE: *name = "continue"; *args=""; *order=-1; break;
    case BREAK: *name = "break"; *args=""; *order=-1; break;
    case ST_RETURN: *name = "return"; *args="e"; *order=-1; break;
    case RETURN: *name = "return"; *args=""; *order=14; break;
    case ST_GOTO: *name = "goto"; *args=""; *order=-1; break;
    case JUMP: *name = "goto"; *args=""; *order=-1; break;
    case STATIC: *name = "static"; *args=""; *order=14; break;
    case EMPTY: *name = "empty"; *args=""; *order=-1; break;
    case FUNCTION: *name = "function"; *args="t"; *order=15; break;
    case UNION: *name = "union"; *args=""; *order=-1; break;
    case STRUCT: *name = "struct"; *args="vt"; *order=-1; break;
    case ARRAY: *name = "array"; *args="tv"; *order=16; break;
    case POINTER: *name = "*"; *args="t"; *order=-1; break;
    case UNSIGNED: *name = "unsigned"; *args=""; *order=-1; break;
    case INLINE: *name = "inline"; *args=""; *order=-1; break;
    case SIGNED: *name = "signed"; *args=""; *order=-1; break;
    case CHAR: *name = "char"; *args=""; *order=-1; break;
    case UCHAR: *name = "unsigned char"; *args=""; *order=-1; break;
    case INT: *name = "int"; *args=""; *order=-1; break;
    case FLOAT: *name = "float"; *args=""; *order=-1; break;
    case DOUBLE: *name = "double"; *args=""; *order=-1; break;
    case LONGLONG: *name = "long long"; *args=""; *order=-1; break;
    case ULONGLONG: *name = "unsigned long long"; *args=""; *order=-1; break;

    case GVAR: *name = "gvar"; *args="vs"; *order=14; break;
    case IVAR: *name = "ivar"; *args="vs"; *order=14; break;
    case RGVAR: *name = "rgvar"; *args="vs"; *order=14; break;
    case CRGVAR: *name = "crgvar"; *args="vs"; *order=14; break;
    case LVAR: *name = "lvar"; *args="v"; *order=14; break;
    case RLVAR: *name = "rlvar"; *args="v"; *order=14; break;
    case CRLVAR: *name = "crlvar"; *args="v"; *order=14; break;
    case CONST: *name = "const"; *args="v"; *order=14; break;
    case FNAME: *name = "fname"; *args="n"; *order=14; break;
    case MUL: *name = "*"; *args="e"; *order=-1; break;
    case RINDIRECT: *name = "*"; *args="e"; *order=13; break;
    case CRINDIRECT: *name = "*"; *args="e"; *order=13; break;
    case ADDRESS: *name = "&"; *args="e"; *order=13; break;
    case BAND: *name = "&"; *args="e"; *order=7; break;
    case MINUS: *name = "-"; *args="e"; *order=13; break;
    case LNOT: *name = "!"; *args="e"; *order=13; break;
    case BNOT: *name = "~"; *args="e"; *order=13; break;
    case INC: *name = "++"; *args=""; *order=13; break;
    case ALLOCA: *name = "alloca"; *args="e"; *order=13; break;
    case BUILTINP: *name = "__builtinp"; *args="e"; *order=13; break;
    case BUILTIN_EXPECT: *name = "__builtin_expect"; *args="ee"; *order=13; break;
    case BUILTIN_FABSF: *name = "__builtin_fabsf"; *args="e"; *order=13; break;
    case BUILTIN_FABS: *name = "__builtin_fbas"; *args="e"; *order=13; break;
    case BUILTIN_FABSL: *name = "__builtin_fbasl"; *args="e"; *order=13; break;
    case BUILTIN_INFF: *name = "__builtin_inff"; *args=""; *order=13; break;
    case BUILTIN_INF: *name = "__builtin_inf"; *args=""; *order=13; break;
    case BUILTIN_INFL: *name = "__builtin_infl"; *args=""; *order=13; break;
    case POSTINC: *name = "++"; *args="ee"; *order=13; break;
    case BPOSTINC: *name = "++"; *args="ee"; *order=13; break;
    case PREINC: *name = "++"; *args="ee"; *order=13; break;
    case CPOSTINC: *name = "++"; *args="ee"; *order=13; break;
    case CPREINC: *name = "++"; *args="ee"; *order=13; break;
    case DEC: *name = "--"; *args="e"; *order=13; break;
    case DIV: *name = "/"; *args="ee"; *order=12; break;
    case UDIV: *name = "/"; *args="ee"; *order=12; break;

    case UMUL: *name = "*"; *args="ee"; *order=12; break;
    case MOD: *name = "%"; *args="ee"; *order=12; break;
    case UMOD: *name = "%"; *args="ee"; *order=12; break;
    case ADD: *name = "+"; *args="ee"; *order=11; break;
    case SUB: *name = "-"; *args="ee"; *order=11; break;
    case RSHIFT: *name = ">>"; *args="ee"; *order=10; break;
    case URSHIFT: *name = ">>"; *args="ee"; *order=10; break;
    case LSHIFT: *name = "<<"; *args="ee"; *order=10; break;
    case ULSHIFT: *name = "<<"; *args="ee"; *order=10; break;
    case GT: *name = ">"; *args="ee"; *order=9; break;
    case UGT: *name = ">"; *args="ee"; *order=9; break;
    case GE: *name = ">="; *args="ee"; *order=9; break;
    case UGE: *name = ">="; *args="ee"; *order=9; break;
    case LT: *name = "<"; *args="ee"; *order=9; break;
    case ULT: *name = "<"; *args="ee"; *order=9; break;
    case LE: *name = "<="; *args="ee"; *order=9; break;
    case ULE: *name = "<="; *args="ee"; *order=9; break;
    case EQ: *name = "=="; *args="ee"; *order=8; break;
    case NEQ: *name = "!="; *args="ee"; *order=8; break;

    case EOR: *name = "^"; *args="ee"; *order=6; break;
    case BOR: *name = "|"; *args="ee"; *order=5; break;
    case LAND: *name = "&&"; *args="ee"; *order=4; break;
    case LOR: *name = "||"; *args="ee"; *order=-1; break;
    case COND: *name = "?"; *args="eee"; *order=2; break;
    case ASS: *name = "="; *args="ee"; *order=1; break;
    case ASSOP: *name = "assop"; *args="eev"; *order=1; break;
    case CASSOP: *name = "cassop"; *args="eev"; *order=1; break;
    case COMMA: *name = ","; *args="ee"; *order=0; break;
    case LPAR: *name = "("; *args=""; *order=-1; break;
    case RPAR: *name = ")"; *args=""; *order=-1; break;
    case LBRA: *name = "["; *args=""; *order=-1; break;
    case RBRA: *name = "]"; *args=""; *order=-1; break;
    case LC: *name = "{"; *args=""; *order=-1; break;
    case RC: *name = "}"; *args=""; *order=-1; break;
    case COLON: *name = ":"; *args="ee"; *order=-1; break;
    case SM: *name = ";"; *args=""; *order=-1; break;
    case PERIOD: *name = "."; *args=""; *order=16; break;
    case ARROW: *name = "->"; *args=""; *order=16; break;
    case SASS: *name = "sass"; *args=""; *order=-1; break;
    case AS+MUL: *name = "*="; *args="ee"; *order=1; break;
    case AS+UMUL: *name = "*="; *args="ee"; *order=1; break;
    case AS+DIV: *name = "/="; *args="ee"; *order=1; break;
    case AS+UDIV: *name = "/="; *args="ee"; *order=1; break;
    case AS+MOD: *name = "%="; *args="ee"; *order=1; break;
    case AS+UMOD: *name = "%="; *args="ee"; *order=1; break;
    case AS+ADD: *name = "+="; *args="ee"; *order=1; break;
    case AS+MINUS: *name = "-="; *args="ee"; *order=1; break;
    case AS+RSHIFT: *name = ">>="; *args="ee"; *order=1; break;
    case AS+URSHIFT: *name = ">>="; *args="ee"; *order=1; break;
    case AS+LSHIFT: *name = "<<="; *args="ee"; *order=1; break;
    case AS+ULSHIFT: *name = "<<="; *args="ee"; *order=1; break;
    case AS+BAND: *name = "&="; *args="ee"; *order=1; break;
    case AS+EOR: *name = "^="; *args="ee"; *order=1; break;
    case AS+BOR: *name = "|="; *args="ee"; *order=1; break;
    case RESTRICT: *name = "restrict"; *args=""; *order=1; break;
    case TYPEOF: *name = "typeof"; *args="e"; *order=1; break;
    case BUILTIN_TYPES_COMPATIBLE_P: *name = "__builtin_types_compatible_p"; *args="e"; *order=1; break;
    case FOR: *name = "for"; *args="eee"; *order=1; break;
    case IF: *name = "if"; *args="ee"; *order=1; break;
    case SWITCH: *name = "switch"; *args="ee"; *order=1; break;
    case CASE: *name = "case"; *args="e"; *order=1; break;
    case DEFAULT: *name = "default"; *args=""; *order=1; break;
    case WHILE: *name = "while"; *args="ee"; *order=1; break;
    case GOTO: *name = "goto"; *args="e"; *order=1; break;
    case DO: *name = "do"; *args="ee"; *order=1; break;

    default: 
    found = 0;

fprintf(stderr,"Unknown ID %d [%d]in find node\n",id,OP(id));

    }
    return found;
}

static int
attr_print(int t)
{
    while (t>0 && car(t)==ATTRIBUTE) {
        switch (caddr(t)) {
        case KONST: printf( "const"); break;
        case VOLATILE: printf( "volatile"); break;
        case RESTRICT: printf( "restrict"); break;
        case INLINE: printf( "inline"); break;
        }
        t = cadr(t);
    }
    return t;
}

void
tree_print_t(int e,int t)
{
    printf("# type: ");
    tree_print(t);
    printf("expr: ");
    tree_print(e);
    printf("\n");
}

void
tree_print(int e)
{
    printf("* generate code on type:\n* ");
    tree_parse(type);
    printf("\n* expr:\n* ");
    tree_parse(e);
    printf("\n");
}

static
int tree_level;

void
tree_parse(int e)
{
    tree_node_type node_type,*t;
    int i,j;
    char *s, **p;
    NMTBL **n;

    t = &node_type; t->tree_type=e;

    if(e<0) {
        if (tree_nodes(e,&t->tree_name,&t->tree_args,&t->tree_order)) {
            for(j=0;j<tree_level;j++) putchar(' ');
            printf("list(%s)",t->tree_name);
        }
    } else {
        i = car(e);
        if (tree_nodes(e,&t->tree_name,&t->tree_args,&t->tree_order)) {
            tree_level++;
            for(j=0;j<tree_level;j++) putchar(' ');
            printf("list(%s",t->tree_name);
            for(i=1,s=t->tree_args;*s;s++,i++) {
                switch(*s) {
                case 'e':
                case 't':
                    printf(",\n*");
                    tree_parse(heap[e+i]); break;
                case 'v':
                    printf(",%d",heap[e+i]); break;
                case 'n':
                    n = (NMTBL**)&(heap[e+i]);
                    printf(",%s",(*n)->nm); break;
                case 's':
                    p = (char**)&(heap[e+i]);
                    printf(",%s",*p); break;
                case 'i':
                    printf(",%d",heap[e+i]); break;
                }
            }
            tree_level--;
            printf(")");
        }
    }
}

void struct_type_print(int type,FILE *out)
{
    NMTBL *n;
    int tags;
    if((n=ncadddr(type))) {
        fprintf(out,"%s ",n->nm);
        return;
    }
    if((tags=caddr(type))) {
        fprintf(out,"{");
        while(tags) {
            n=ncaddr(tags);
            type_print(car(tags),n,out);
            fprintf(out,";");
            tags = cadr(tags);
        }
        fprintf(out,"}");
    }
}

void function_type_print1(int type,NMTBL *n,FILE *out,int cont)
{
    int args;
    type_print1(cadr(type),0,out,cont);
    if(n) fprintf(out," %s",n->nm);
    fprintf(out,"(");
    if((args=caddr(type))) {
        while (args) {
            type_print(car(args),0,out);
            args=cadr(args);
            if (args) fprintf(out,",");
        }
    }
    fprintf(out,")");
}

void function_type_print(int type,NMTBL *n,FILE *out)
{
    function_type_print1(type,n,out,0);
}

void sym_print(int sym,FILE *out)
{
    tree_node_type tn;
    if (!(tree_nodes(sym,&tn.tree_name,&tn.tree_args,&tn.tree_order))) { error(-1); return; }
    fprintf(out,"%s",tn.tree_name);
}

NMTBL *
typedef_search(int t,int type) 
{
    while(t) {
        if ((ncaddr(t))->ty==type)
            return ncaddr(t);
        t=cadr(t);
    }
    return 0;
}

static void n_attr_print(int attr, FILE *out)
{
    for(;attr;attr=cadr(attr)) {
        switch(car(attr)) {
        case INLINE: fprintf(out,"inline "); break;
        case CONST: fprintf(out,"const "); break;
        case VOLATILE: fprintf(out,"const "); break;
        case RESTRICT: fprintf(out,"const "); break;
        }
    }
}

void type_print1(int type,NMTBL *n,FILE *out,int cont)
{
    int t; 
    tree_node_type *tn,tn0;
    NMTBL *td;
    int args;
    tn = &tn0;

    if (n) {
        if (n->attr) n_attr_print(n->attr,out);
        while(type>0 && car(type)==ATTRIBUTE) type=cadr(type);
    } else
        type = attr_print(type);
    if(type>0&&(td=typedef_search(typedefed,type))) {
        if (!cont)
            fprintf(out,"%s ",td->nm);
    } else if(type>0&&(td=typedef_search(gtypedefed,type))) {
        if (!cont)
            fprintf(out,"%s ",td->nm);
    } else if (type<0) {
        t=type;
        if (!(tree_nodes(t,&tn->tree_name,&tn->tree_args,&tn->tree_order))) { error(-1); return; }
        if (!cont)
            fprintf(out,"%s ",tn->tree_name);
    } else if ((t=car(type))) {
        if (!(tree_nodes(t,&tn->tree_name,&tn->tree_args,&tn->tree_order))) { error(-1); return; }
        if(t==STRUCT||t==UNION) {
            if (!cont) {
                fprintf(out,"%s ",tn->tree_name);
                struct_type_print(type,out);
            }
        } else if(t==CODE) {
            // if (!cont) { fprintf(out,"%s ",tn->tree_name); }
            function_type_print1(type,n,out,cont);
            return;
        } else if(t==FUNCTION) {
            function_type_print1(type,n,out,cont);
            return;
        } else if(t==ARRAY) {
            type_print1(cadr(type),n,out,cont);
            if (caddr(type))
                fprintf(out,"[%d]",caddr(type));
            else
                fprintf(out,"[]");
            return;
        } else if(t==POINTER) {
            t=cadr(type);
            if(t<0) {
                type_print1(t,0,out,cont);
                fprintf(out,"*");
            } else if(car(t)==FUNCTION) {
                type_print1(cadr(t),0,out,cont);
                fprintf(out,"(*");
                if(n) fprintf(out,"%s",n->nm);
                fprintf(out,")");
                fprintf(out,"(");
                if((args=caddr(t))) {
                    while (args) {
                        type_print(car(args),0,out);
                        args=cadr(args);
                        if (args) fprintf(out,",");
                    }
                }
                fprintf(out,")");
                return;
            } else if(car(t)==CODE) {
                type_print1(cadr(t),0,out,cont);
                fprintf(out,"(*");
                if(n) fprintf(out,"%s",n->nm);
                fprintf(out,")");
                fprintf(out,"(");
                if((args=caddr(t))) {
                    while (args) {
                        type_print(car(args),0,out);
                        args=cadr(args);
                        if (args) fprintf(out,",");
                    }
                }
                fprintf(out,")");
                return;
            } else if(car(t)==ARRAY) {
                fprintf(out,"(*");
                type_print(cadr(t),n,out);
                if (caddr(type))
                    fprintf(out,")[%d]",caddr(type));
                else
                    fprintf(out,")[]");
                return;
            } else {
                type_print1(t,0,out,cont);
                fprintf(out,"*");
            }
        }
    }
    if(n) fprintf(out,"%s",n->nm);
}

void type_print(int type,NMTBL *n,FILE *out)
{
    type_print1(type,n,out,0);
}

/*
    parse tree を印刷する

    正しく括弧とかを付けるアルゴリズムが不明...
    先読みして、優先順位を判別する必要があるはず。

    そういえば、cast とかは、落ちて変換コードに変わっている
    はず。cast を木にしないとだめか。
 */

void
print_expr(int e, FILE *vout)
{
    NMTBL *nptr,*n;

    if (e==0) {
        // can't happen in normal C language
        fprintf(vout,"#");
        return;
    }
    switch (car(e)%SOP) {
    case LVAR:
    case RLVAR:
    case URLVAR:
        if ((nptr = ncaddr(e))) {
            fprintf(vout,"%s",nptr->nm);
        } else {
            // anonymous variable
            fprintf(vout,"_%d",caddr(e));
        }
        break;
    case GVAR:
    case RGVAR:
    case URGVAR:
        if ((nptr = ncaddr(e))) {
            fprintf(vout,"%s",nptr->nm);
        } else {
            // anonymous variable
            fprintf(vout,"_%d",caddr(e));
        }
        if (cadr(e)) {
            // offset
            // certainly this is wrong
            fprintf(vout,"+%d",caddr(e));
        }
        break;
    case REGISTER:
        if ((nptr = ncaddr(e))) {
            fprintf(vout,"%s",nptr->nm);
        } else {
            // anonymous register variable
            fprintf(vout,"_%d",caddr(e));
        }
        break;
    case IDENT:
        nptr = ncaddr(e);
        fprintf(vout,"%s",nptr->nm); break;
    case CONST:
        switch(car(e)) {
        case CONST:
            fprintf(vout,"%d",cadr(e)); break;
#if FLOAT_CODE
        case FCONST:
            fprintf(vout,"%g",dcadr(e)); break;
        case DCONST:
            fprintf(vout,"%g",dcadr(e)); break;
#endif
#if LONGLONG_CODE
        case LCONST:
            fprintf(vout,"%lld",lcadr(e)); break;
#endif
        }
        break;
    case ADDRESS:
        if (car(cadr(e))!=STRING) {
            fprintf(vout,"&");
            print_expr(cadr(e),vout);
            break;
        }
    case STRING:
        { 
            int c; char *s; int i;
            nptr = ncaddr(e); s = nptr->nm;i=nptr->dsp;
            fprintf(vout,"\"");
            while(--i>0) {
                c=*s++;
                if(c=='\n') fprintf(vout,"\\n");
                else if(c=='\r') fprintf(vout,"\\r");
                else if(c=='\t') fprintf(vout,"\\t");
                else if(c=='\e') fprintf(vout,"\\e");
                else if(c=='"') fprintf(vout,"\\\"");
                else if(c=='\\') fprintf(vout,"\\\\");
                else if(!(' '<=c&&c<=0x7f)) fprintf(vout,"\\%03o",c);
                else fprintf(vout,"%c",c);
            }   
            fprintf(vout,"\"");
        }
        break;
    case ARRAY:
        print_expr(cadr(e),vout);
        fprintf(vout,"[");
        print_expr(caddr(e),vout);
        fprintf(vout,"]");
        break;
    case PERIOD:
        print_expr(cadr(e),vout);
        n = ncaddr(e);
        fprintf(vout,".%s",n->nm);
        break;
    case ARROW:
        print_expr(cadr(e),vout);
        n = ncaddr(e);
        fprintf(vout,"->%s",n->nm);
        break;
    case INDIRECT:
    case RINDIRECT:
    case URINDIRECT:
        fprintf(vout,"*");
        print_expr(cadr(e),vout);
        break;
    case FNAME:
        n = ncaddr(e);
        fprintf(vout,"%s",n->nm);
        break;
    case FUNCTION:
        print_function_call(e,vout);
        break;
/*
    case ADD:
        fprintf(vout,"(");
        print_expr(cadr(e),vout);
        fprintf(vout,"+");
        print_expr(caddr(e),vout);
        fprintf(vout,")");
        break;
  */
    default:
        print_operator(e, vout);
    }
}

static void
print_expr_paren(int order,char *args,int e)
{
}

static void
print_operator(int e, FILE *vout)
{
    char *name; char *args; int order ;
    if (tree_nodes(car(e), &name, &args, &order) ) {
        if (order>0) {
            int i = 0;
            for(;*args;args++,i++) {
                print_expr_paren(order,args,heap[e+i]);
            }
        } else {
            print_statement(e, vout);
        }
    }
}

static void
print_decl(int e, FILE *vout)
{
    NMTBL *n = ncaddr(e);
    int e1 = cadddr(e);
    // int mode = car(e1);
    int stmode = cadr(e1);
    int ctmode = caddr(e1);

    if (n==&null_nptr) {
        error(-1); // can't happen
        return;
    }
    if (stmode==STATIC) {
        fprintf(vout,"static "); 
    } else if (stmode==EXTRN||stmode==EXTRN1) {
        fprintf(vout,"extern "); 
    }
    type_print(n->ty,n,vout);
    if (ctmode & KONST_BIT) {
        fprintf(vout,"const "); 
    }
    if (ctmode & VOLATILE_BIT) {
        fprintf(vout,"volatile "); 
    }
    if (ctmode & RESTRICT_BIT) {
        fprintf(vout,"restrict "); 
    }
    fprintf(vout,"%s; ",nptr->nm); 
}

static void
print_statement(int e, FILE *vout)
{
    int e1;
    NMTBL *n;
    for (;e!=0; e = cadr(e)) {
        switch (car(e)) {
        case ST_DECL:
            print_decl(e, vout); break;
        case ST_IF:
            fprintf(vout,"if "); break;
        case ST_DO:
            fprintf(vout,"do "); break;
        case ST_WHILE:
            fprintf(vout,"while "); break;
        case ST_FOR:
            fprintf(vout,"for "); break;
        case ST_SWITCH:
            fprintf(vout,"switch "); break;
        case ST_COMP:
            fprintf(vout,"{");
            fprintf(vout,"}");
            break;
        case ST_BREAK:
            fprintf(vout,"break; "); break;
        case ST_CONTINUE:
            fprintf(vout,"continue; "); break;
        case ST_CASE:
            for(e1 = caddr(e);e1;e1 = cadr(e1)) {
                fprintf(vout,"case "); 
                fprintf(vout,"%d: ",car(e1)); 
            }
            break;
        case ST_DEFAULT:
            fprintf(vout,"default: "); break;
        case ST_RETURN:
            fprintf(vout,"return "); 
            if (( e1 = caddr(e))) {
                print_expr(e1,vout);
            }
            fprintf(vout,"; "); 
            break;
        case ST_GOTO:
            fprintf(vout,"goto "); break;
        case ST_ASM:
            fprintf(vout,"__asm__ "); break;
        case ST_LABEL:
            n = ncaddr(caddr(e));
            fprintf(vout,"%s:", n->nm); break;
        case ST_OP:
            e1 = caddr(e);
            print_expr(list3(cadr(e),car(e1),cadr(e1)),vout);
            break;
        case ST_COMMENT:
            fprintf(vout,"\n# %s\n",scaddr(e)); 
            break;
        default:
            fprintf(stderr,"Unknown Statement ID %d\n",car(e));
        }
    }
}

static void
print_function_call(int e1,FILE *vout)
{
    int e2,e3;
    NMTBL *fn = 0;

    e2 = cadr(e1);
    if (car(e2) == FNAME) {     
        fn=ncaddr(e2);
        fprintf(vout,"%s",fn->nm);
    } else {    
        if (car(e2)==INDIRECT) e2=cadr(e2); // (*func)(i) case
        fprintf(vout,"(");
        print_expr(e2,vout);
        fprintf(vout,")");
    }

    fprintf(vout,"(");
    for (e3 = e1 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) {    
        print_expr(car(e3),vout);
        if (cadr(e3)) {
            fprintf(vout,",");
        }
    }
    fprintf(vout,")");
    reverse0(e1); // make it normal order

}


/* end */