/* ---------------------------------------------------------------------- */
/*                   Copyright (C) 1991 by Natrlich!                     */
/*                      This file is copyrighted!                         */
/*                Refer to the documentation for details.                 */
/* ---------------------------------------------------------------------- */
#include "defines.h"
#include "nasm.h"
#include "labels.h"
#include "seg.h"
#include "object.h"
#include "debug.h"
#include "code.h"
#include "imm.h"

#if __NSTDC__
static unsigned   cnt_refs( ref huge *),
                  help_tree( expr huge *);
static void       hdump_tree( expr huge *),
                  cnt_tree( expr huge *),
                  dump_tree( expr huge *);
#else
static unsigned   cnt_refs(),
                  help_tree();
static void       hdump_tree(),
                  cnt_tree(),
                  dump_tree();
#endif

static byte  huge *dspace;
extern label huge *h_global[],
             huge *h_macro[];

extern lword    __lx;

#define loop_symbols( p, i, k)                        \
   for( k = 0; k != 2; k++)                           \
      for( i = 0; i != SEP; i++)                      \
         if( p = k ? h_macro[ i] : h_global[ i])


/* ---------------------------------------------------------- */
/* If I weren't so enamored of having all structures kept in  */
/* seperate little file areas,this might be done a bit easier */
/* For clean_labels: Get rid of leftover expression trees     */
/*                   that fix nothing  (--> error ??)         */
/* ---------------------------------------------------------- */
void  clean_labels()
{
   register label huge *p;
   register ref huge   *q, huge *old;
   register expr huge  *e;
   register int         i, j;

   clean_mats();                 /* clean macro @... labels */
   loop_symbols( p, i, j)
      do
         if( dumpable( p) && (q = p->refs))
            for( old = 0; q; q = q->next)
            {
               for( e = q->ref; ! e->fix; e = e->zonk.t);  /* ;; */
               if( e->fix == FIX_NOTHING)
                  if( ! old)
                     p->refs = q->next;
                  else
                     old->next = q->next;
               else
                  old = q;
            }
      while( p = p->next);
}


static unsigned   cnt_refs( p)
register ref huge *p;
{
   register unsigned   i;

   ENTER("cnt_refs");
   for( i = 0; p; i++, p = p->next);
   LEAVE();
   return( i);
}

lword   sym_size()
{
   register lword      x = 0;
   register label huge *p;
   static unsigned     index = 1;
   register int        i;
   int                 j;

   ENTER("sym_size");
   loop_symbols( p, i, j)
      do
         if( dumpable( p) && (! j || (p->refs)))
         {
            x    += sizeof( linksymbol);
            p->no = index++;
         }
      while( p = p->next);
   LEAVE();
   return( x);
}


void  sym_makbuf()
{
   register label huge *p;
   register byte huge  *q = __program;
   register byte huge  *s;
   register int        i, j;
   int                 k;

   ENTER("sym_makbuf");
   loop_symbols( p, i, k)
      do
         if( dumpable( p) && (! k || (p->refs)))
         {
            if( ! p->refs)
            {
               pdbyte( q, p->val);
            }
            else
            {
               pdbyte( q, 0);
            }
            pdbyte( q, p->no);
            pdbyte( q, p->type);
            j = cnt_refs( p->refs);
            pdbyte( q, 0xC002);         /* just a filler    */
            plbyte( q, j);              /* VORSICHT! MACRO  */
            s = (byte *) p->name;
            j = 0;
            while( j++ < SIGNIFICANT && (*q++ = *s++));
            while( j++ < SIGNIFICANT)
               *q++ = 0;
         }
      while( p = p->next);
   LEAVE();
}


lword  rel_size()
{
   register label huge *p;
   register lword      x = 0;
   int                 i, j;

   ENTER("rel_size");
   loop_symbols( p, i, j)
      do
         if( dumpable( p) && p->refs)
            x += (lword) (cnt_refs( p->refs) << 1);
      while( p = p->next);
   LEAVE();
   return( x);
}


void  rel_makbuf()
{
   register label huge *p;
   register byte huge  *q = __program;
   register ref huge   *s;
   int                 i, k;

   ENTER("rel_makbuf");
   loop_symbols( p, i, k)
      do
         if( dumpable( p) && (s = p->refs))
            do
            {
               pdbyte( q, s->ref->no);
            }
            while( s = s->next);
      while( p = p->next);
   LEAVE();
}


static unsigned   fixes;

lword    fix_size()
{
   return( (lword) fixes * sizeof( f_dropped));
}


void  fix_makbuf()
{
   register label huge *p;
   register ref huge   *q;
   register expr huge  *e;
   register int        i, k;

   ENTER("fix_makbuf");
   dspace =  __program;
   loop_symbols( p, i, k)
      do
         if( dumpable( p) && (q = p->refs))
            do
            {
               register byte huge *x = dspace;

               for( e = q->ref; ! e->fix; e = e->zonk.t);
               dspace += sizeof( f_dropped);
               if( e->fix == FIX_LABEL)
               {
                  pdbyte( x, e->zonk.fixp->poof.label->no);
                  pdclr( x);
                  dclr( x);
               }
               else
               {
                  register fix huge  *f = e->zonk.fixp;
                  
                  pdbyte( x, f->poof.block->no);
                  if( f->imm)
                  {
                     pdbyte( x, f->imm->no);
                  }
                  else
                  {
                     pdclr( x);
                  } 
                  dbyte( x, f->index);
               }  
            }
            while( q = q->next);
      while( p = p->next);
   LEAVE();
}

/* ---------------------------------------------------------- */
/*                     Can do this only ONCE!!                */
/* ---------------------------------------------------------- */
static unsigned   xindex = 1;

static unsigned   help_tree( p)
register expr huge *p;
{
   p->no = xindex++;
   if( p->l)
   {
      help_tree( p->l);
      if( p->r)
         help_tree( p->r);
   }
}

static void cnt_tree( p)
expr huge *p;
{
   ENTER("cnt_tree");
   if( ! p->no)
   {
      while( ! p->fix)    /* walk to the top */
         p = p->zonk.t;
      p->zonk.fixp->no = fixes++;
      help_tree( p);
   }
}


lword    exp_size()
{
   register label huge *p;
   register ref huge   *q;
   int                 i, k;

   ENTER("exp_size");
   loop_symbols( p, i, k)
      do
         if( dumpable( p) && (q = p->refs))
            do
               cnt_tree( q->ref);
            while( q = q->next);
      while( p = p->next);
   LEAVE();
   return( (lword) (xindex - 1) * sizeof( e_dropped));
}


static void   hdump_tree( x)
expr huge *x;
{
   ENTER("hdump_tree");
   {  /* ; */
      register expr huge *p = x;
      register byte huge *q = dspace;

      dspace += sizeof( e_dropped);

      pdbyte( q, p->val);
      pdbyte( q, p->aux);
      pdbyte( q, p->label ? p->label->no : 0);
      *q++ = p->op;
      if( *q++ = p->fix)
         if( p->fix == FIX_LABEL)
         {
            pdbyte( q, ((label *) p->zonk.t)->no);
         }
         else
         {
            pdbyte( q, p->zonk.fixp->no);
         }
      else
      {
         pdbyte( q, p->zonk.t ? p->zonk.t->no : 0);
      }
      pdbyte( q, p->l ? p->l->no : 0);
      dbyte( q,  p->r ? p->r->no : 0);
   }

   if( x->l)
   {
      hdump_tree( x->l);
      if( x->r)
         hdump_tree( x->r);
   }
   x->no = 0;                             /* clear >no< so that expr */
   LEAVE();                               /* won't be dumped again   */
}


void  dump_tree( p)
expr huge *p;
{
   ENTER("dump_tree");
   if( p->no)
   {
      while( ! p->fix)    /* walk to the top */
         p = p->zonk.t;
      hdump_tree( p);
   }
   LEAVE();
}


void  exp_makbuf()
{
   register label huge *p;
   register ref huge   *q;
   int                 i, k;

   ENTER("exp_makbuf");
   dspace =  __program;
   loop_symbols( p, i, k)
      do
         if( dumpable( p) && (q = p->refs))
            do
               dump_tree( q->ref);
            while( q = q->next);
      while( p = p->next);
   LEAVE();
}

extern imm huge *hip, huge *cip;

lword   imm_size()
{
   register imm huge *p;
   register word     i = 1;

   ENTER("imm_size");
   for( p = hip; p; p = p->next)
      p->no = i++;
   LEAVE();
   return( (lword) (i - 1) * sizeof( i_dropped));
}


void  imm_makbuf()
{
   register imm huge  *p;
   register byte huge *q = __program;

   ENTER("imm_makbuf");
   for( p = hip; p; p = p->next)
   {
      pdbyte( q, p->block->no);
      pdbyte( q, p->type);
      pdbyte( q, p->offset);
      pdbyte( q, p->val);
   }
   LEAVE();
}


extern seg huge *h_seg, *sp;

lword    seg_size()
{
   register seg huge *p;
   register word  i;

   for( p = h_seg, i = 0;  p; i++, p = p->next)
      p->no = i;
   return( (lword) i * sizeof( s_dropped));
}


void  seg_makbuf()
{
   register seg huge  *p;
   register byte huge *q;

   for( p = h_seg, q = __program; p ; p = p->next)
   {
      pdbyte( q, p->type);
      pdbyte( q, p->index);
      pdbyte( q, p->size);
   }
}



/* ;
   -- "This looks exceptionally braindead, son. What where you dreaming
      about, when you wrote this ??"
   -- "Well ackshually *hic* there ish a shertain rashional behind
      *hic* all shat."
   -- <slap> "Swine! Have you been drinking again ? Well I just gonna
      have to teach you some ... <slap><slap> ..manners <slap> <*crack*>
                                 <WAAAAH!!>
   -- <Sob> "No need <Sob-whine> to break my arm, I was just kidding.."
                                 <Waaah>
   -- "Well that'll teach you to make fun of your old dad, now son
       about this piece of shit up there..."
   --  <Sob>
   -- "Well!!" <slap>
   -- <WAAH!> "Don't hit me again! <Sob> I am telling you, I am telling
      <Sob> you!!" <SNEEEZE> <Sob>
   -- "I am listening son, and I am getting impatient" [and so do we...]
   -- "Ok just <Sob> assume for a moment, that we have some really large
      expression and some compiler that rather prefers to not use registers,
      for parameter passing (as there are some). Now for the little
      piece enclosed in the { } it would be preferable, to have
      this executed with register variables, but we certainly don't want
      those to be stacked when the recursive calls take place."
   -- "Oh son, why didn't you say so in the first place. I needn't have to
      hit you then. Lets be good again, shall we ?"
   -- "Oh yes <whimper>. -- uh Dad ??
   -- "..Yes.."
   -- "Could you -er- drive me to the hospital? My arm is hurting pretty
       <sob> badly."
   -- "Don't push your luck again son!"
   -- <whimper>
   
   (later: That was when I was still learning to write C-programs. Of 
           course this doesn't make sense on a more profound level of
           understanding.)
   (much later: I must have dropped down a level of profoundness again)
*/

/* ;;
   If the top fix is FIX_NOTHING, that means it is an assembler internal
   expression, that wasn't used anywhere. Presently this only happenes
   when macros are started. -> LEXPR -> COPYEXPR ... lexpr->expr remains
   unused  except for copying.
   (later: well not completely true anymore, still "about right")
*/
