/*
 * C compiler
 * ==========
 *
 * Copyright 1989, 1990, 1991 Christoph van Wuellen.
 * Credits to Matthew Brandt.
 * All commercial rights reserved.
 *
 * This compiler may be redistributed as long there is no
 * commercial interest. The compiler must not be redistributed
 * without its full sources. This notice must stay intact.
 *
 * History:
 *
 * 1989   starting an 68000 C compiler, starting with material
 *        originally by M. Brandt
 * 1990   68000 C compiler further bug fixes
 *        started i386 port (December)
 * 1991   i386 port finished (January)
 *        further corrections in the front end and in the 68000
 *        code generator.
 *        The next port will be a SPARC port
 */

#include "chdr.h"
#ifdef LIST
#include "expr.h"
#include "cglbdec.h"
#include "proto.h"

#if defined(__STDC__) || defined(__cplusplus)
#define P_(s) s
#else
#define P_(s) ()
#endif

static	void	put_sc		P_(( STORAGE));
static	void	put_def		P_(( STATUS));
static	void	put_ty		P_(( TYP *,  LEVEL));
static	void	list_var	P_(( SYM *,  LEVEL));
static	void	list_table	P_(( TABLE *,  LEVEL));
static	void	list_block	P_(( BLOCK *,  LEVEL));

#undef P_

static void
put_def P1( STATUS, status)
{
    lprintf (status & (SYM_DEFINED) ? "D" : " ");
    lprintf (status & (SYM_SET)     ? "S" : " ");
    lprintf (status & (SYM_USED)    ? "U" : " ");
    lprintf (status & (SYM_OUTSCOPE)? "O" : " ");
    lprintf (status & (SYM_OUTPUT)  ? "P" : " ");
    lprintf (" ");
}

static void
put_sc P1( STORAGE, scl)
{
    switch (scl) {
      case sc_static:
	lprintf("Static      ");
	break;
      case sc_auto:
	lprintf("Auto        ");
	break;
      case sc_global:
	lprintf("Global      ");
	break;
      case sc_external:
	lprintf("External    ");
	break;
      case sc_tag:
	lprintf("Tag         ");
	break;
      case sc_typedef:
	lprintf("Typedef     ");
	break;
      case sc_const:
	lprintf("Constant    ");
	break;
      case sc_member:
	lprintf("Member      ");
	break;
      case sc_label:
	lprintf("Label       ");
	break;
      case sc_parms:
	lprintf("Parameter   ");
	break;
      case sc_register:
	lprintf("Register   ");
	break;
      default:
	CANNOT_REACH_HERE();
	break;
    }
}

static void
put_ty P2( TYP *, tp,  LEVEL, indent)
{
    if (tp == 0)
	return;
    if (tp->size != UNKNOWN_SIZE)
	lprintf("%lx:", tp->size);
    if (is_const_qualified(tp))
	lprintf("const ");
    if (is_volatile_qualified(tp))
	lprintf("volatile ");
    switch (tp->type) {
      case bt_void:
	lprintf("void ");
	break;
      case bt_schar:
	lprintf("signed char");
	break;
      case bt_uchar:
	lprintf("unsigned ");
	/*FALLTHRU*/
      case bt_char:
      case bt_charu:
	lprintf("char");
	break;
      case bt_ushort:
	lprintf("unsigned ");
	/*FALLTHRU*/
      case bt_short:
	lprintf("short");
	break;
      case bt_uint16:
      case bt_uint32:
	lprintf("unsigned ");
	/*FALLTHRU*/
      case bt_int16:
      case bt_int32:
	lprintf("int");
	break;
      case bt_ulong:
	lprintf("unsigned ");
	/*FALLTHRU*/
      case bt_long:
	lprintf("long");
	break;
      case bt_float:
	lprintf("float");
	break;
      case bt_double:
	lprintf("double");
	break;
      case bt_longdouble:
	lprintf("long double");
	break;
      case bt_pointer16:
      case bt_pointer32:
	if (is_array_type(tp))
	    lprintf("array of ");
	else
	    lprintf("pointer to ");
	put_ty(referenced_type(tp), indent);
	break;
      case bt_union:
	lprintf("union ");
	goto ucont;
      case bt_struct:
	lprintf("struct ");
ucont:	if (tp->sname == 0)
	    lprintf("<no name> ");
	else
	    lprintf("%s ", tp->sname);
	break;
      case bt_func:
	lprintf("function returning ");
	put_ty(returned_type(tp), indent);
	break;
      case bt_ubitfield:
	lprintf("unsigned ");
	/*FALLTHRU*/
      case bt_bitfield:
	lprintf("bitfield offset=%d width=%d",
		(int) bitfield_offset(tp),
		(int) bitfield_width(tp));
	break;
      case bt_ellipsis:
	lprintf("...");
	break;
      default:
	FATAL ((__FILE__,"put_ty","illegal type %d",tp->type));
    }
}

static void
list_var P2( SYM *, sp,  LEVEL, indent)
{
    LEVEL		 j;
#if 0
    if (sp->tp == 0)
	return;	/* sp->tp==0 if generated by call_library */
#endif

    for (j = indent; j; --j)
	lprintf("    ");
    lprintf("%-12s =%08lx ", sp->name, sp->value.u);
    put_sc(sp->storage_class);
    put_def(sp->status);
    put_ty(sp->tp, indent);
    lprintf("%s", newline);
    if (sp->tp) {
	switch (sp->tp->type) {
	  case bt_struct:
	  case bt_union:
	    if (sp->storage_class == sc_tag)
		list_block(members(sp->tp), indent + (LEVEL)1);
	    break;
	  case bt_func:
	    list_block (parameters(sp->tp), indent + (LEVEL)1);
	    break;
	  default:
	    break;
	}
    }
}

static void
list_table P2( TABLE *, t,  LEVEL, indent)
{
     SYM	*sp;
    if (t != NULL) {
	for (sp = t->head; sp != NULL; sp = sp->next)
	    list_var(sp, indent);
    }
}

static void
list_block P2( BLOCK * , block,  LEVEL, indent)
{
    if (block != NULL) {
	list_table(&(block->symbols), indent);
	list_table(&(block->tags), indent);
    }
}

void
summary P2( BLOCK *, block,  LEVEL, indent)
{
    if (list_option) {
	list_block(block, indent);
    }
}
#endif /* LIST */
