/* l2xisdcl.c  LTX2X declaration analysis */
/*  Written by: Peter Wilson, CUA  pwilson@cme.nist.gov                */
/*  This code is partly based on algorithms presented by Ronald Mak in */
/*  "Writing Compilers & Interpreters", John Wiley & Sons, 1991        */

#include <stdio.h>
#include "l2xicmon.h"
#include "l2xierr.h"
#include "l2xiscan.h"
#include "l2xisymt.h"
#include "l2xiidbg.h"

/* EXTERNALS */

extern int line_number;
extern TOKEN_CODE token;

/* GLOBALS */

char buffer[MAX_PRINT_LINE_LENGTH];

char *defn_names[] = {
#define dfntc(a, b) b,
#include "l2xidftc.h"
#undef dfntc
};


char *form_names[] = {
#define fotc(a, b, c, d) d,
#define sotc(a, b, c, d)
#define sftc(a, b, c, d) d,
#include "l2xisftc.h"
#undef fotc
#undef sotc
#undef sftc
};



/* ANALYSIS */


/***************************************************************************/
/* analyze_const_defn(idp) Analyze a constant definition                   */

analyze_const_defn(idp)
SYMTAB_NODE_PTR idp;               /* constant id */
{
  char *bp;
  
  if (DEBUG < Danalyze) return;

  /* the name */
  sprintf(buffer, ">> id = %s\n", idp->name);
  debug_print(buffer);
  sprintf(buffer, ">>    address = %d\n", idp);

  /* definition and value */
  sprintf(buffer, ">>    defn = %s, value = ", defn_names[idp->defn.key]);
  bp = buffer + strlen(buffer);

  if ((idp->typep == integer_typep) || (idp->typep->form == ENUM_FORM))
    sprintf(bp, "%d\n", idp->defn.info.constant.value.integer);
  else if (idp->typep == real_typep)
    sprintf(bp, "%g\n", idp->defn.info.constant.value.real);
  else if (idp->typep->form == ARRAY_FORM)  /* ????????????????????????? */
    sprintf(bp, "'%s'\n", idp->defn.info.constant.value.stringp);
  else if (idp->typep->form == STRING_FORM) 
    sprintf(bp, "'%s'\n", idp->defn.info.constant.value.stringp);
  debug_print(buffer);

  /* and type. careful as an enum type will get into an infinite loop */
  if (idp->typep->form != ENUM_FORM) analyze_type(idp->typep, FALSE);

}                                                /* end analyze_const_defn */
/***************************************************************************/



/***************************************************************************/
/* analyze_type_defn(idp) Analyze a type definition                        */

analyze_type_defn(idp)
SYMTAB_NODE_PTR idp;              /* id */
{
  char *bp;

  if (DEBUG < Danalyze) return;

  /* the type's name, definition ... */
  sprintf(buffer, ">>id = %s\n", idp->name);
  debug_print(buffer);
  sprintf(buffer, ">>    address = %d\n", idp);
  debug_print(buffer);

  sprintf(buffer, ">>    defn = %s\n", defn_names[idp->defn.key]);
/*  print_line(buffer); */
  debug_print(buffer);

  /* and type */
  analyze_type(idp->typep, TRUE);
 
}                                                 /* end analyze_type_defn */
/***************************************************************************/



/***************************************************************************/
/* analyze_type(tp, verbose_flag) Analyze a type definition                */

analyze_type(tp, verbose_flag)
TYPE_STRUCT_PTR tp;              /* pointer to type structure */
BOOLEAN verbose_flag;            /* TRUE for verbose analysis */
{
  char *bp;

  if (DEBUG < Danalyze) return;

  if (tp == NULL) return;

  /* the form, byte size (and name) */
  sprintf(buffer, ">>    form = %s, size = %d bytes, type id = ",
                         form_names[tp->form], tp->size);
  bp = buffer + strlen(buffer);
  if (tp->type_idp != NULL)
    sprintf(bp, "%s\n", tp->type_idp->name);
  else {
    sprintf(bp, "<unnamed type>\n");
    verbose_flag = TRUE;
  }
  debug_print(buffer);

  /* do the appropriate analysus */
  switch (tp->form) {
    case ENUM_FORM: {
      analyze_enum_type(tp, verbose_flag);
      break;
    }
    case SUBRANGE_FORM: {
      analyze_subrange_type(tp, verbose_flag);
      break;
    }
    case ARRAY_FORM: {
      analyze_array_type(tp, verbose_flag);
      break;
    }
    case STRING_FORM: {      
      verbose_flag = TRUE;
      analyze_string_type(tp, verbose_flag);
      break;
    }
    case BOUND_FORM: {       
      analyze_bound_type(tp, verbose_flag);
      break;
    }
    case ENTITY_FORM: {
      analyze_entity_type(tp, verbose_flag);
      break;
    }
    case BAG_FORM:
    case LIST_FORM:
    case SET_FORM: {
      analyze_bls_type(tp, verbose_flag);
      break;
    }
    default: {
      break;
    }
  } /* end switch */

}                                                      /* end analyze_type */
/***************************************************************************/



/***************************************************************************/
/* analyze_enum_type(tp, verbose_flag) Analyze an enumeration type         */

analyze_enum_type(tp, verbose_flag)
TYPE_STRUCT_PTR tp;              /* pointer to type structure */
BOOLEAN verbose_flag;            /* TRUE for verbose analysis */
{
  SYMTAB_NODE_PTR idp;              /* id */

  if (DEBUG < Danalyze) return;

  if (!verbose_flag) return;

  /* loop to analyze each enum constant as a constant defn */
  debug_print(">>    -- Enum Constants --\n"); 
  for (idp = tp->info.enumeration.const_idp; idp != NULL; idp = idp->next) {
    analyze_const_defn(idp);
  }

}                                                 /* end analyze_enum_type */
/***************************************************************************/



/***************************************************************************/
/* analyze_subrange_type(tp, verbose_flag) Analyze a subrange type */

analyze_subrange_type(tp, verbose_flag)
TYPE_STRUCT_PTR tp;              /* pointer to type structure */
BOOLEAN verbose_flag;            /* TRUE for verbose analysis */
{
  SYMTAB_NODE_PTR idp;              /* id */

  if (DEBUG < Danalyze) return;

  if (!verbose_flag) return;

  sprintf(buffer, ">>    min value = %d, max value = %d\n",
                    tp->info.subrange.min, tp->info.subrange.max);
  debug_print(buffer);

  debug_print(">>    -- Range Type -- \n"); 
  analyze_type(tp->info.subrange.range_typep, FALSE);

}                                             /* end analyze_subrange_type */
/***************************************************************************/



/***************************************************************************/
/* analyze_bound_type(tp, verbose_flag) Analyze a bound               type */

analyze_bound_type(tp, verbose_flag)
TYPE_STRUCT_PTR tp;              /* pointer to type structure */
BOOLEAN verbose_flag;            /* TRUE for verbose analysis */
{
  SYMTAB_NODE_PTR idp;              /* id */

  if (DEBUG < Danalyze) return;

  if (!verbose_flag) return;

  sprintf(buffer, ">>    min value = %d, max value = %d\n",
                    tp->info.bound.min, tp->info.bound.max);
  debug_print(buffer);

  debug_print(">>    -- Bound Type -- \n"); 
  analyze_type(tp->info.bound.bound_typep, FALSE);

}                                                /* end analyze_bound_type */
/***************************************************************************/



/***************************************************************************/
/* analyze_array_type(tp, verbose_flag) Analyze an array type              */

analyze_array_type(tp, verbose_flag)
TYPE_STRUCT_PTR tp;              /* pointer to type structure */
BOOLEAN verbose_flag;            /* TRUE for verbose analysis */
{
  SYMTAB_NODE_PTR idp;              /* id */

  if (DEBUG < Danalyze) return;

  if (!verbose_flag) return;

  sprintf(buffer, ">>    element count = %d\n",
                    tp->info.array.elmt_count);
  debug_print(buffer);
  sprintf(buffer, ">>    index limits = %d to %d\n",
                    tp->info.array.min_index, tp->info.array.max_index);
  debug_print(buffer);

  debug_print(">>    -- INDEX TYPE -- \n"); 
  analyze_type(tp->info.array.index_typep, FALSE);

  debug_print(">>    -- ELEMENT TYPE -- \n"); 
  analyze_type(tp->info.array.elmt_typep, FALSE);

}                                                /* end analyze_array_type */
/***************************************************************************/



/***************************************************************************/
/* analyze_bls_type(tp, verbose_flag) Analyze a bag, etc type              */

analyze_bls_type(tp, verbose_flag)
TYPE_STRUCT_PTR tp;              /* pointer to type structure */
BOOLEAN verbose_flag;            /* TRUE for verbose analysis */
{
  SYMTAB_NODE_PTR idp;              /* id */

  if (DEBUG < Danalyze) return;

  if (!verbose_flag) return;

  sprintf(buffer, ">>    element count = %d\n",
                    tp->info.dynagg.elmt_count);
  debug_print(buffer);
  sprintf(buffer, ">>    index limits = %d to %d\n",
                    tp->info.dynagg.min_index, tp->info.dynagg.max_index);
  debug_print(buffer);

  debug_print(">>    -- INDEX TYPE -- \n"); 
  analyze_type(tp->info.dynagg.index_typep, FALSE);

  debug_print(">>    -- ELEMENT TYPE -- \n"); 
  analyze_type(tp->info.dynagg.elmt_typep, FALSE);

}                                                /* end analyze_bls_type */
/***************************************************************************/



/***************************************************************************/
/* analyze_string_type(tp, verbose_flag) Analyze a string type              */

analyze_string_type(tp, verbose_flag)
TYPE_STRUCT_PTR tp;              /* pointer to type structure */
BOOLEAN verbose_flag;            /* TRUE for verbose analysis */
{
  SYMTAB_NODE_PTR idp;              /* id */

  if (DEBUG < Danalyze) return;

  if (!verbose_flag) return;

  sprintf(buffer, ">>    maximum length = %d\n",
                    tp->info.string.max_length);
  debug_print(buffer);

  sprintf(buffer, ">>            length = %d\n",
                    tp->info.string.length);
  debug_print(buffer);
  return;

}                                                /* end analyze_string_type */
/***************************************************************************/



/***************************************************************************/
/* analyze_entity_type(tp, verbose_flag) Analyze an entity type            */

analyze_entity_type(tp, verbose_flag)
TYPE_STRUCT_PTR tp;              /* pointer to type structure */
BOOLEAN verbose_flag;            /* TRUE for verbose analysis */
{
  SYMTAB_NODE_PTR idp;              /* id */

  if (DEBUG < Danalyze) return;

  if (!verbose_flag) return;

  /* loop to analyze each attribute as a variable decl */
  debug_print(">>    -- Attributes -- \n");
  for (idp = tp->info.entity.attribute_symtab; idp != NULL; idp = idp->next) {
    analyze_var_decl(idp);
  }

}                                               /* end analyze_entity_type */
/***************************************************************************/



/***************************************************************************/
/* analyze_var_decl(idp) Analyze a variable declaration                    */

analyze_var_decl(idp)
SYMTAB_NODE_PTR idp;              /* id */
{

  if (DEBUG < Danalyze) return;

  /* the name, definition and offset */
  sprintf(buffer, ">>  id = %s\n", idp->name);
  debug_print(buffer);
  sprintf(buffer, ">>    address = %d\n", idp);
  debug_print(buffer);

  sprintf(buffer, ">>    defn = %s, offset = %d\n", 
                     defn_names[idp->defn.key], idp->defn.info.data.offset);
/*  print_line(buffer); */
  debug_print(buffer);

  /* and type */
  analyze_type(idp->typep, FALSE);

}                                                  /* end analyze_var_decl */
/***************************************************************************/



/***************************************************************************/
/* analyze_block(code_segment)   a dummy procedure                         */

analyze_block(code_segment)
char *code_segment;
{
  return;
}                                                     /* end analyze_block */
/***************************************************************************/



/***************************************************************************/
/* analyze_routine_header(rtn_idp)  a dummy procedure                      */

analyze_routine_header(rtn_idp)
SYMTAB_NODE_PTR rtn_idp;

{
  return;
}                                           /* end analyze_routine_header */
/***************************************************************************/



/***************************************************************************/