/* ---------------------------------------------------------------------- */
/*                   Copyright (C) 1991 by Natrlich!                     */
/*                      This file is copyrighted!                         */
/*                Refer to the documentation for details.                 */
/* ---------------------------------------------------------------------- */
#define LOCALDEBUG   0
#include "defines.h"
#include "nasm.h"
#include "labels.h"
#include "y_tab.h"
#include "debug.h"
#include "buffer.h"
#if LOCALDEBUG
#include <stdio.h>
#endif

#define STKSIZE  1024       /* nesting depth */

#if __NSTDC__
static void   ignore( void);
#else
static void   ignore();
#endif

int            _in_if;
static char    stack[ STKSIZE],
               *s = stack,
               nest[] = "Too many nested .IFs",
               spls[] = ".ELSE or .ENDIF w/o a leading .IF";
extern buffer huge   *bp;

#if ! VERSION
void vpushchk()
{
   if( s == stack + STKSIZE)
      nferror( nest);
}

int push( v)
int   v;
{
   ENTER("push");
   IMESS("Pushing %d", (lword) v, 2);
   LEAVE();
   return( (int) (*s++ = v));
}

#define vpush( v)    vpushchk(); push( v)

void vpopchk()
{
   if( s == stack)
   {
      *(s = stack+1) = 1;
      nerror( spls);
   }
}

char pop()
{
   ENTER("pop");
   IMESS("returning %d", (lword) s[-1], 2);
   LEAVE();
   return( *--s);
}

void dpop()
{
   ENTER("dpop");
   MESS("just adjusting the stack");
   s--;
   LEAVE();
}

char look()
{
   ENTER("look");
   IMESS("returning %d", (lword) s[-1], 2);
   LEAVE();
   return( s[-1]);
}

void mark()
{
   ENTER("mark");
   s[-1] |= 0x80;
   LEAVE();
}

int ismarked()
{
   ENTER("ismarked");
   IMESS("returning %d", (lword) s[-1] < 0, 2);
   LEAVE();
   return( s[-1] < 0);
}

#if LOCALDEBUG
void  dump_stack()
{
   char  *p = stack;

   if( p == s)
      fprintf( ESTREAM, "Stack empty\n");
   else
   {
      do
        putc( '0' + *p, ESTREAM);
      while( ++p < s);
      putc( '\n', ESTREAM);
   }
}
#endif
# else
#define vpushchk()   if( s == stack + STKSIZE) nferror( nest)
#define push( v)     *s++ = v
#define vpush( v)    vpushchk(); push( v)

#define vpopchk()    if( s == stack) { *(s = stack+1) = 1; nerror( spls); return; }
#define pop()        *--s
#define dpop()       s--

#define look()       s[-1]
#define mark()       s[-1] |= 0x80
#define ismarked()   s[-1] < 0

#define dump_stack()
#endif



void   if_treat( e)
register expr  *e;
{
   ENTER("if_treat");
   vpushchk();
   if( unvalued( e))
   {
      nerror("Forward ref in .IF <expression>");
      push( 0);     /* for a following possible .ELSE */
      LEAVE();
      return;
   }
   if( ! (push( e->val ? 1 : 0)))
      ignore();
   LEAVE();
}

void   else_treat()
{
   ENTER("else_treat");
   if( ismarked())
      nerror(".ELSE belonging to noone found");
   else
   {
      mark();
      ignore();
   }
   LEAVE();
}


void   endif_treat()
{
   ENTER("endif_treat");
   vpopchk();
   dpop();
   LEAVE();
}


static void    ignore()
{
   extern word freshflag;
#if LOCALDEBUG
   register int   tok;
#endif

   ENTER("ignore");
   _in_if = 1;
   for(;;)
   {
#if LOCALDEBUG
      dump_stack();
      tok = yylex();
      prtname( tok);
      switch( tok)
#else
      freshflag = 1;
      switch( yylex())
#endif
      {
         case 0    :
            nwarning("Matching .ENDIF not encountered");
            _in_if = 0;
            LEAVE();
            return;

         case T_EOL:
            inc_line();
            break;

         case T_IF :
            vpush( 2);
            break;

         case T_ELSE :
            if( ismarked())
               nwarning("Garbage .ELSE ignored");
            else
            {
               if( look() != 2)
               {
                  mark();
                  _in_if = 0;
                  LEAVE();
                  freshflag = 1;
                  return;
               }
               mark();
            }
            break;

         case T_ENDIF :
            vpopchk();
            if( (pop() & 0x3) != 2)
            {
               _in_if = 0;
               LEAVE();
               return;
            }
      }
   }
}

