/* ---------------------------------------------------------------------- */
/*                   Copyright (C) 1991 by Natrlich!                     */
/*                      This file is copyrighted!                         */
/*                Refer to the documentation for details.                 */
/* ---------------------------------------------------------------------- */
/* Code that tokenizes and differentiates between MACRO calls and */
/* real life 6502 assembler mnemos. Also tokenizes directives     */

#if OS == MSDOS
# define _brk  xbrk
#endif


/* These are all the characters that happen to appear in 6502 mnemos */
extern byte
   _adc[],_and[],_asl[],_bcc[],_bcs[],_beq[],_bit[],_bmi[],_bne[],
   _bpl[],_bra[],_brk[],_bvc[],_bvs[],_clc[],_cld[],_cli[],_clv[],
   _cmp[],_cpx[],_cpy[],_dea[],_dec[],_dex[],_dey[],_eor[],_ina[],
   _inc[],_inx[],_iny[],_jmp[],_jsr[],_lda[],_ldx[],_ldy[],_lsr[],
   _nop[],_ora[],_pha[],_php[],_phx[],_phy[],_pla[],_plp[],_plx[],
   _ply[],_rol[],_ror[],_rti[],_rts[],_sbc[],_sec[],_sed[],_sei[],
   _sta[],_stx[],_sty[],_stz[],_tax[],_tay[],_trb[],_tsb[],_tsx[],
   _txa[],_txs[],_tya[];

/* -------------------------------------------------------------- */
/* We use the first character of the instruction (or macro call)  */
/* to decide on a (struct instr) that happens to keep the remain- */
/* ing two letters. If a match is made, a alphabetically index is */
/* sent over.                                                     */
/*       [this looked pretty fast in the beginning, but...]       */
/* -------------------------------------------------------------- */
#if BIGENDIAN
# define drop( b, a) ( ((word) (a) << 8) | (word) (b))
#else
# define drop( a, b) ( ((word) (a) << 8) | (word) (b))
#endif

#define EOA    { 0, 0 }

struct instr
{
   word        d;
   byte huge   *tab;
};

static struct instr
   a_[] =
   {
      { drop('D','C'), _adc }, { drop('N','D'), _and },
      { drop('S','L'), _asl }, EOA
   },
   b_[] =
   {
      { drop('C','C'), _bcc }, { drop('C','S'), _bcs },
      { drop('E','Q'), _beq }, { drop('I','T'), _bit },
      { drop('M','I'), _bmi }, { drop('N','E'), _bne },
      { drop('P','L'), _bpl }, { drop('R','K'), _brk },
      { drop('R','A'), _bra }, { drop('V','C'), _bvc },
      { drop('V','S'), _bvs }, EOA
   },
   c_[] =
   {
      { drop('L','C'), _clc }, { drop('L','D'), _cld },
      { drop('L','I'), _cli }, { drop('L','V'), _clv },
      { drop('M','P'), _cmp }, { drop('P','X'), _cpx },
      { drop('P','Y'), _cpy }, EOA
   },
   d_[] =
   {
      { drop('E','A'), _dea }, { drop('E','C'), _dec },
      { drop('E','X'), _dex }, { drop('E','Y'), _dey }, EOA
   },
   e_[] =
   {
      { drop('O','R'), _eor }, EOA
   },
   i_[] =
   {
      { drop('N','A'), _ina }, { drop('N','C'), _inc },
      { drop('N','X'), _inx }, { drop('N','Y'), _iny }, EOA
   },
   j_[] =
   {
      { drop('M','P'), _jmp }, { drop('S','R'), _jsr }, EOA
   },
   l_[] =
   {
      { drop('D','A'), _lda }, { drop('D','X'), _ldx },
      { drop('D','Y'), _ldy }, { drop('S','R'), _lsr }, EOA
   },
   n_[] =
   {
      { drop('O','P'), _nop }, EOA
   },
   o_[] =
   {
      { drop('R','A'), _ora }, EOA
   },
   p_[] =
   {
      { drop('H','A'), _pha }, { drop('H','P'), _php },
      { drop('H','X'), _phx }, { drop('H','Y'), _phy },
      { drop('L','A'), _pla }, { drop('L','P'), _plp },
      { drop('L','X'), _plx }, { drop('L','Y'), _ply }, EOA
   },
   r_[] =
   {
      { drop('O','L'), _rol }, { drop('O','R'), _ror },
      { drop('T','I'), _rti }, { drop('T','S'), _rts }, EOA
   },
   s_[] =
   {
      { drop('B','C'), _sbc }, { drop('E','C'), _sec },
      { drop('E','D'), _sed }, { drop('E','I'), _sei },
      { drop('T','A'), _sta }, { drop('T','X'), _stx },
      { drop('T','Y'), _sty }, { drop('T','Z'), _stz }, EOA
   },
   t_[] =
   {
      { drop('A','X'), _tax }, { drop('A','Y'), _tay },
      { drop('R','B'), _trb }, { drop('S','B'), _tsb },
      { drop('S','X'), _tsx }, { drop('X','A'), _txa },
      { drop('X','S'), _txs }, { drop('Y','A'), _tya }, EOA
   },

   *i_arr[] =
   {
      (struct instr *) 0, a_, b_, c_, d_, e_, i_,
      j_, l_, n_, o_, p_, r_, s_, t_
   };

/* Indexes for the Instruction_ARRay, note that    i_arr[0] = 0   */
static int       
   starters[] = 
   {     
   /* 0 1 2 3 4 5 6 7 8 9 :         ? @                        */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   /* A B C D E F G H I J K L M N  O  P Q  R  S  T U V W X Y Z */
      1,2,3,4,5,0,0,0,6,7,0,8,0,9,10,11,0,12,13,14,0,0,0,0,0,0,
   /*         _ */   
      0,0,0,0,0 
   };

macro_suckin()
{
   register byte  *p = (byte *) yytext,
                  c_ = c,
                  *p_table = is_what;
   register word  i = 1;

   ENTER("macro_suckin");
#if VERSION && FINPUT_IO && QINPUT_IO && QMACRO
   {
      register byte huge   *pt  = bp->p;
      register byte        *tab = _uptable; 
      register lword       rem  = bp->remain;
   
      while( tis_ident( c_))
      {
         *p++ = c_;
         c_   = quinput( rem, pt, tab);
         i++;
      }
      if( bp)
      {
         bp->remain = rem;
         bp->p      = pt;
      }
    }
#else
   while( tis_ident(c_))                     /* Suck in macro call or   */
   {                                         /* instruction             */
      *p++ = c_;                             /* convert to upper & save */
      c_   = uinput();                       /* get fresh input         */
      i++;
   }
#endif
   *p = 0;
   c  = c_;
   p  = (byte *) yytext;                     /* (*) */
   IMESS("Macro/Instr.: %s", (lword) p, 4);

   if( i == 4)
   {
      register struct instr huge *q;

      if( q = i_arr[ starters[ *p - '0']])   /* instr ? */
      {
#if WORD_EVEN
         p++;
         c_ = p[1];                          /* looks very possible al- */
         i  = ((word) *p << 8) | c_;         /* beit not certain        */
#else
         i  = *(word *) &yytext[ 1];
#endif
         IMESS("two chars together %4lX", (lword) i, 4);
         do
            if( i == q->d)
            {
               yylval = (lword) q->tab;      /* Yup. Send index & token */
               LEAVE();
               return( T_INSTR);
            }
         while( (++q)->d);
         i = 4;
      }
   }
   yy_txt2val( i);
   state  = AFTERELSE;
   LEAVE();
   return( T_IDENT);                         /* It's a MACRO call */
}

/* -------------------------------------------------------------------- */
/*   There are only that few people who use directives often. So here   */
/*   speed isn't of that much importance.                               */
/* -------------------------------------------------------------------- */
#define AF  AFTERFLOAT
#define AI  AFTERINCLUDE
#define AO  AFTEROPTION
#undef  EOA
#define EOA { "", 0, 0 }

struct direc
{
   char  *string;
   int   token, state;
};  

static struct direc
   da_[] =
   {
      { "AND",    T_AND,   0 },  EOA
   },
   db_[] =
   {
      { "BYTE",   T_BYTE,  0 },  EOA
   },
   dc_[] =
   {
      { "CALL",   T_CALL,  0 },  { "CBYTE",  T_CBYTE, 0 },  EOA
   },
   dd_[] =
   {
      { "DBYTE",  T_DBYTE, 0 },  { "DEF",     T_DEF,   0 },
      { "DS",     T_DS,    0 },  EOA
   },
   de_[] =
   {
      { "ELSE",   T_ELSE,  0 },  { "END",    T_END,   0 },
      { "ENDIF",  T_ENDIF, 0 },  { "ENDM",   T_ENDM,  0 },
      { "EQU",    '=',     0 },  { "ERROR",  T_ERROR, 0 },    EOA
   },
   df_[] =
   {
      { "FLOAT",  T_FLOAT, AF }, EOA
   },
   di_[] =
   {
      { "IF",     T_IF,    0 },  { "INCLUDE",T_INCLUDE, AI }, EOA
   },
   dl_[] =
   {
      { "LOCAL",  T_LOCAL, 0 },  EOA
   },
   dm_[] =
   {
      { "MACRO",  T_MACRO, 0 },  EOA
   },
   dn_[] =
   {
      { "NOT",    T_NOT,   0 },  EOA
   },
   do_[] =
   {
      { "OPT",    T_OPT,   AO},  { "OR",     T_OR, 0 },  
      { "ORG",    T_ORG,   0 },  EOA
   },
   dp_[] =
   {
      { "PAGE",   T_PAGE,  0 },  EOA
   },
   dr_[] =
   {
      { "REF",    T_REF,   0 },  { "REPT",   T_REPT,  0 },  EOA
   },
   ds_[] =
   {
      { "SBYTE",  T_SBYTE, 0 },  { "SET",    T_SET,   0 },  EOA
   },
   dt_[] =
   {
      { "TAB",    T_TAB,   0 },  { "TITLE",  T_TITLE, 0 },  EOA
   },
   du_[] =
   {
      { "UNDEF",  T_UNDEF, 0 },  EOA
   },
   dv_[] =
   {
      { "VFL_BOCHUM", T_ZEXT, 0},EOA
   },
   dw_[] =
   {
      { "WARNING",   T_WARN, 0 }, { "WORD",   T_WORD,  0 },  EOA
   },
   dz_[] =
   {
      { "ZEXT",   T_ZEXT,  0 },  EOA
   },

   *d_arr[] =
   {
      (struct direc *) 0, da_, db_, dc_, dd_, de_, df_, di_, dl_, 
      dm_, dn_, do_, dp_, dr_, ds_, dt_, du_, dv_, dw_, dz_
   };

/* Indexes for the Instruction_ARRay, note that    i_arr[0] = 0   */
static int       
   dstarters[] =
   {     
   /* 0 1 2 3 4 5 6 7 8 9 :         ? @                        */
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
   /* A B C D E F G H I J K L M  N  O  P Q  R  S  T  U  V  W X Y  Z */
      1,2,3,4,5,6,0,0,7,0,0,8,9,10,11,12,0,13,14,15,16,17,18,0,0,19,
   /*         _ */   
      0,0,0,0,0 
   };

directive_suckin()
{
   register char  *p = yytext,
                  c_ = c,
                  *p_table = (char *) is_what;
   
   ENTER("directive_suckin");
   if( (c_ = uinput()) == '=')       /* is .= ?? */
      fdreturn( T_DOTEQ);
   *p++ = '.';
#if VERSION && FINPUT_IO && QINPUT_IO && QDIRECT
   {
      register byte huge   *pt  = bp->p;
      registe byte         *tab = _uptable;
      register lword       rem  = bp->remain;

      do
         *p++ = c_;
      while( tis_ident( c_ = quinput( rem, pt, tab)));
      if( bp)
      {
         bp->remain = rem;
         bp->p      = pt;
      }
    }
#else
   do
      *p++ = c_;                             /* convert to upper & save */
   while( tis_ident(c_ = uinput()));
#endif 
   c  = c_;
   *p = 0;
   p  = yytext + 1;     
   {
      register struct direc   *q;
      
      if( q = d_arr[ dstarters[ *p - '0']])      /* get directive start */
         do
            if( ! strcmp( q->string, p))
            {
               if( q->state)
                  state = q->state;
               dreturn( q->token);
            }
         while( (++q)->string);
   }
   lsyntax("unknown directive");
}


struct opt
{
   char   *name;
   int    token;
};

static struct  opt
   options[] =
   {
      { "NO",         T_NO    },
      { "OBJ",        T_OBJ   },
      { "LIST",       T_LIST  },
      { "MLIST",      T_MLIST },
      { "CLIST",      T_CLIST },
      { "EJECT",      T_EJECT },
      { "ERR",        T_ERR   },
      { "NUM",        T_NUM   },
      { "XREF",       T_XREF  },
      { "",           0       }
   };


option_suckin()
{
   register struct opt huge   *q = options;
   register char              *p = yytext;

   while( is_letter(c))
   {
      *p++ = c;
      c    = uinput();
   }
   *p = 0;

   while( q->token)
   {
      if( ! strcmp( yytext, q->name))
         return( q->token);
      q++;
   }
   lsyntax("unknown option");
}

/* (*)
   Turbo-C very cleverly (no irony this time) compiles the "-'0'" as a
   negative offset for the LEA. Therefore this isn't wasting any time 
   at least on the ST. Else a 256 word array would be better
*/
