/*
 * $Id$
 */

/*
 * Harbour Project source code:
 *    compiler lexer which converts PP tokens to the ones which
 *    grammar parser generated by bison can understand
 *
 * Copyright 2006 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
 * www - http://www.harbour-project.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
 *
 * As a special exception, the Harbour Project gives permission for
 * additional uses of the text contained in its release of Harbour.
 *
 * The exception is that, if you link the Harbour libraries with other
 * files to produce an executable, this does not by itself cause the
 * resulting executable to be covered by the GNU General Public License.
 * Your use of that executable is in no way restricted on account of
 * linking the Harbour library code into it.
 *
 * This exception does not however invalidate any other reasons why
 * the executable file might be covered by the GNU General Public License.
 *
 * This exception applies only to the code released by the Harbour
 * Project under the name Harbour.  If you copy code from other
 * Harbour Project or Free Software Foundation releases into a copy of
 * Harbour, as the General Public License permits, the exception does
 * not apply to the code that you add in this way.  To avoid misleading
 * anyone as to the status of such modified files, you must delete
 * this exception notice from them.
 *
 * If you write modifications of your own for Harbour, it is your choice
 * whether to permit this exception to apply to your modifications.
 * If you do not wish that, delete this exception notice.
 *
 */


#include "hbpp.h"
#include "hbcomp.h"
#include "hbdate.h"
#include "harboury.h"

#define HB_PP_LEX_SELF(t)     ( HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_SEND && \
                                (t)->pNext && (t)->pNext->spaces == 0 && \
                                HB_PP_TOKEN_TYPE((t)->pNext->type) == HB_PP_TOKEN_SEND )

#define HB_PP_LEX_NEEDLEFT(t) ( HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_ASSIGN || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_PLUSEQ || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_MINUSEQ || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_MULTEQ || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_DIVEQ || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_MODEQ || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_EXPEQ || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_EQUAL || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_EQ || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_ALIAS || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_MULT || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_DIV || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_MOD || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_POWER || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_IN || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_AND || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_OR || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_PIPE || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_RIGHT_PB || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_RIGHT_SB || \
                                HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_RIGHT_CB || \
                                ( HB_PP_TOKEN_TYPE((t)->type) == HB_PP_TOKEN_SEND && \
                                  (t)->spaces == 0 && !HB_PP_LEX_SELF(t) ) )

#define LOOKUP           0
#define OPERATOR        -2
#define LSEPARATOR      -3
#define RSEPARATOR      -4
#define LINDEX          -5
#define RINDEX          -6
#define LARRAY          -7
#define RARRAY          -8
#define AS_TYPE         -9
#define DECLARE_TYPE    -10


typedef struct
{
   char *   value;      /* keyword name */
   int      minlen;     /* minimal length */
   int      maxlen;     /* maximal length */
   int      type;       /* terminal symbol code */
}
HB_LEX_KEY, * PHB_LEX_KEY;

static const HB_LEX_KEY s_keytable[] = 
{
   { "ALWAYS",      4,  6, ALWAYS         },
   { "ANNOUNCE",    4,  8, ANNOUNCE       },
   { "AS",          2,  2, AS_TYPE        },
   { "BEGIN",       4,  5, BEGINSEQ       },
   { "BREAK",       4,  5, BREAK          },
   { "CASE",        4,  4, CASE           },
   { "DECLARE",     4,  7, DECLARE        },
   { "DESCEND",     7,  7, DESCEND        },
   { "DO",          2,  2, DO             },
   { "DYNAMIC",     7,  7, DYNAMIC        },
   { "ELSE",        4,  4, ELSE           },
   { "ELSEIF",      5,  6, ELSEIF         },
   { "END",         3,  3, END            },
   { "ENDCASE",     4,  7, ENDCASE        },
   { "ENDDO",       4,  5, ENDDO          },
   { "ENDIF",       4,  5, ENDIF          },
   { "ENDSEQUENCE", 6, 11, ENDSEQ         },
   { "ENDSWITCH",   5,  9, ENDSWITCH      },
   { "ENDWITH",     4,  7, ENDWITH        },
   { "EXIT",        4,  4, EXIT           },
   { "EXTERNAL",    4,  8, EXTERN         },
   { "FIELD",       4,  5, FIELD          },
   { "FOR",         3,  3, FOR            },
   { "FUNCTION",    4,  8, FUNCTION       },
   { "IF",          2,  2, IF             },
   { "IIF",         3,  3, IIF            },
   { "IN",          2,  2, IN             },
   { "INIT",        4,  4, INIT           },
   { "LOCAL",       4,  5, LOCAL          },
   { "LOOP",        4,  4, LOOP           },
   { "MEMVAR",      4,  6, MEMVAR         },
   { "NEXT",        4,  4, NEXT           },
   { "NIL",         3,  3, NIL            },
   { "OPTIONAL",    4,  8, OPTIONAL       },
   { "OTHERWISE",   4,  9, OTHERWISE      },
   { "PARAMETERS",  4, 10, PARAMETERS     },
   { "PRIVATE",     4,  7, PRIVATE        },
   { "PROCEDURE",   4,  9, PROCEDURE      },
   { "PUBLIC",      4,  6, PUBLIC         },
   { "QSELF",       5,  5, SELF           },
   { "RECOVER",     4,  7, RECOVER        },
   { "RETURN",      4,  6, RETURN         },
   { "STATIC",      4,  6, STATIC         },
   { "STEP",        4,  4, STEP           },
   { "SWITCH",      4,  6, DOSWITCH       },
   { "TO",          2,  2, TO             },
   { "WHILE",       4,  5, WHILE          },
   { "WITH",        4,  4, WITH           },
   { "_FIELD",      4,  6, FIELD          },
   { "_HB_CLASS",   9,  9, DECLARE_CLASS  },
   { "_HB_MEMBER", 10, 10, DECLARE_MEMBER },
   { "_PROCREQ_",   9,  9, PROCREQ        }
};

#define _AS_ARRAY       1
#define _AS_BLOCK       2
#define _AS_CHARACTER   3
#define _AS_CLASS       4
#define _AS_DATE        5
#define _AS_LOGICAL     6
#define _AS_NUMERIC     7
#define _AS_OBJECT      8
#define _AS_VARIANT     9

static const int s_asTypes[] =
{ 
   0,
   AS_ARRAY,
   AS_BLOCK,
   AS_CHARACTER,
   AS_CLASS,
   AS_DATE,
   AS_LOGICAL,
   AS_NUMERIC,
   AS_OBJECT,
   AS_VARIANT
};

static const int s_asArrayTypes[] =
{ 
   0,
   AS_ARRAY_ARRAY,
   AS_BLOCK_ARRAY,
   AS_CHARACTER_ARRAY,
   AS_CLASS_ARRAY,
   AS_DATE_ARRAY,
   AS_LOGICAL_ARRAY,
   AS_NUMERIC_ARRAY,
   AS_OBJECT_ARRAY,
   AS_ARRAY
};

static const HB_LEX_KEY s_typetable[] = 
{
   { "ANYTYPE",     4,  7, _AS_VARIANT    },
   { "ARRAY",       4,  5, _AS_ARRAY      },
   { "CHARACTER",   4,  9, _AS_CHARACTER  },
   { "CLASS",       4,  5, _AS_CLASS      },
   { "CODEBLOCK",   4,  9, _AS_BLOCK      },
   { "DATE",        4,  4, _AS_DATE       },
   { "LOGICAL",     4,  7, _AS_LOGICAL    },
   { "NUMERIC",     4,  7, _AS_NUMERIC    },
   { "OBJECT",      4,  6, _AS_OBJECT     },
   { "STRING",      4,  6, _AS_CHARACTER  },
   { "USUAL",       4,  5, _AS_VARIANT    }
};

static int hb_comp_asType( PHB_PP_TOKEN pToken, BOOL fArray )
{
   if( pToken && HB_PP_TOKEN_TYPE( pToken->type ) == HB_PP_TOKEN_KEYWORD )
   {
      PHB_LEX_KEY pKey = ( PHB_LEX_KEY ) s_typetable;
      int i = sizeof( s_typetable ) / sizeof( HB_LEX_KEY );

      hb_pp_tokenUpper( pToken );
      do
      {
         if( pKey->minlen <= pToken->len && pToken->len <= pKey->maxlen &&
             memcmp( pKey->value, pToken->value, pToken->len ) == 0 )
            return ( fArray ? s_asArrayTypes : s_asTypes ) [ pKey->type ];
         ++pKey;
      }
      while( --i );
   }
   return 0;
}

static int hb_comp_keywordType( PHB_PP_TOKEN pToken )
{
   PHB_LEX_KEY pKey = ( PHB_LEX_KEY ) s_keytable;
   int i = sizeof( s_keytable ) / sizeof( HB_LEX_KEY );

   do
   {
      if( pKey->minlen <= pToken->len && pToken->len <= pKey->maxlen &&
          memcmp( pKey->value, pToken->value, pToken->len ) == 0 )
      {
         if( HB_PP_TOKEN_ALLOC( pToken->type ) && pToken->len == pKey->maxlen )
         {
            hb_xfree( pToken->value );
            pToken->value = pKey->value;
            pToken->type |= HB_PP_TOKEN_STATIC;
         }
         return pKey->type;
      }
      ++pKey;
   }
   while( --i );
   return IDENTIFIER;
}

static char * hb_comp_tokenIdentifer( HB_COMP_DECL, PHB_PP_TOKEN pToken )
{
   if( HB_PP_TOKEN_ALLOC( pToken->type ) )
   {
      pToken->value = hb_compIdentifierNew( HB_COMP_PARAM, pToken->value, HB_IDENT_FREE );
      pToken->type |= HB_PP_TOKEN_STATIC;
   }

   return pToken->value;
}

static char * hb_comp_tokenString( YYSTYPE *yylval_ptr, HB_COMP_DECL, PHB_PP_TOKEN pToken )
{
   yylval_ptr->valChar.length = pToken->len;
   yylval_ptr->valChar.string = pToken->value;
   yylval_ptr->valChar.dealloc = FALSE;
   if( HB_PP_TOKEN_ALLOC( pToken->type ) )
   {
      yylval_ptr->valChar.dealloc = ( ULONG ) pToken->len != strlen( pToken->value );
      pToken->value = hb_compIdentifierNew( HB_COMP_PARAM, pToken->value,
               yylval_ptr->valChar.dealloc ? HB_IDENT_COPY : HB_IDENT_FREE );
      if( !yylval_ptr->valChar.dealloc )
         yylval_ptr->valChar.string = pToken->value;
      pToken->type |= HB_PP_TOKEN_STATIC;
   }
   return pToken->value;
}

#if 0
static BOOL hb_comp_timeDecode( PHB_PP_TOKEN pTime, LONG * plTime )
{
   HB_LONG lHour, lMinute, lMilliSec;
   double dNumber;
   int iDec, iWidth;

   if( !pTime || HB_PP_TOKEN_TYPE( pTime->type ) != HB_PP_TOKEN_NUMBER ||
       hb_compStrToNum( pTime->value, pTime->len, &lHour, &dNumber,
                        &iDec, &iWidth ) || lHour < 0 || lHour >= 24 )
      return FALSE;

   pTime = pTime->pNext;
   if( !pTime || HB_PP_TOKEN_TYPE( pTime->type ) != HB_PP_TOKEN_SEND )
      return FALSE;

   pTime = pTime->pNext;
   if( !pTime || HB_PP_TOKEN_TYPE( pTime->type ) != HB_PP_TOKEN_NUMBER ||
       hb_compStrToNum( pTime->value, pTime->len, &lMinute, &dNumber,
                        &iDec, &iWidth ) || lMinute < 0 || lMinute >= 60 )
      return FALSE;

   pTime = pTime->pNext;
   if( !pTime )
      return FALSE;

   if( HB_PP_TOKEN_TYPE( pTime->type ) == HB_PP_TOKEN_SEND )
   {
      pTime = pTime->pNext;
      if( !pTime || HB_PP_TOKEN_TYPE( pTime->type ) != HB_PP_TOKEN_NUMBER )
         return FALSE;

      if( hb_compStrToNum( pTime->value, pTime->len, &lMilliSec, &dNumber,
                           &iDec, &iWidth ) )
      {
         if( dNumber < 0.0 || dNumber >= 60.0 )
            return FALSE;
         lMilliSec = ( HB_LONG ) ( dNumber * 1000 );
      }
      else if( lMilliSec < 0 || lMilliSec >= 60 )
         return FALSE;
      else
         lMilliSec *= 1000;
      pTime = pTime->pNext;
   }
   else
      lMilliSec = 0;

   if( HB_PP_TOKEN_TYPE( pTime->type ) == HB_PP_TOKEN_KEYWORD &&
       lHour > 0 && lHour <= 12 )
   {
      if( ( pTime->len == 1 &&
            ( pTime->value[0] == 'A' || pTime->value[0] == 'a' ) ) ||
          ( pTime->len == 2 && hb_stricmp( pTime->value, "AM" ) == 0 ) )
      {
         if( lHour == 12 )
            lHour = 0;
         pTime = pTime->pNext;
      }
      else if( ( pTime->len == 1 &&
                 ( pTime->value[0] == 'P' || pTime->value[0] == 'p' ) ) ||
               ( pTime->len == 2 && hb_stricmp( pTime->value, "PM" ) == 0 ) )
      {
         if( lHour < 12 )
            lHour += 12;
         pTime = pTime->pNext;
      }
   }

   if( !pTime || HB_PP_TOKEN_TYPE( pTime->type ) != HB_PP_TOKEN_RIGHT_CB )
      return FALSE;

   *plTime = ( lHour * 60 + lMinute ) * 60000 + lMilliSec;

   return TRUE;
}

static BOOL hb_comp_dayTimeDecode( PHB_COMP_LEX pLex, PHB_PP_TOKEN pToken,
                                   YYSTYPE *yylval_ptr )
{
   /* TODO: decode datetime in VFP strict date form:
    *    {^YYYY/MM/DD[,][HH[:MM[:SS][.CCC]][A|P]]}
    * VFP accepts slash, dot or hyphen as date delimiter and
    * 12 or 24-hour formatted time,
    * If only hours are included in time part then comma have to
    * be used to separate date and time parts or it's necesary
    * to follow the hours with a colon.
    *    { ^ <YEAR> <sep:/.-> <MONTH> <sep:/.-> <DAY> [[<sep2:,>]
    *      [ <HOUR> [ : <MIN> [ : <SEC> [ . <FRAQ> ] ] ] [A|P] ] }
    * We will not accept dot as date delimiter to avoid possible
    * conflicts with PP.
    */

   /* Now support for dates constatns: {^YYYY/MM/DD} or {^YYYY-MM-DD} */
   PHB_PP_TOKEN pYear, pMonth, pDay;
   HB_LONG lYear, lMonth, lDay;
   LONG lDate = 0, lTime = 0;
   double dNumber;
   int iDec, iWidth;

   pYear = pToken->pNext->pNext;
   if( pYear && HB_PP_TOKEN_TYPE( pYear->type ) == HB_PP_TOKEN_NUMBER &&
       pYear->pNext )
   {
      if( ( HB_PP_TOKEN_TYPE( pYear->pNext->type ) == HB_PP_TOKEN_DIV ||
            HB_PP_TOKEN_TYPE( pYear->pNext->type ) == HB_PP_TOKEN_MINUS ) &&
          !hb_compStrToNum( pYear->value, pYear->len, &lYear, &dNumber,
                            &iDec, &iWidth ) )
      {
         pMonth = pYear->pNext->pNext;
         if( pMonth && HB_PP_TOKEN_TYPE( pMonth->type ) == HB_PP_TOKEN_NUMBER &&
             pMonth->pNext && HB_PP_TOKEN_TYPE( pYear->pNext->type ) ==
                              HB_PP_TOKEN_TYPE( pMonth->pNext->type ) &&
             !hb_compStrToNum( pMonth->value, pMonth->len, &lMonth, &dNumber,
                               &iDec, &iWidth ) )
         {
            pDay = pMonth->pNext->pNext;
            if( pDay && HB_PP_TOKEN_TYPE( pDay->type ) == HB_PP_TOKEN_NUMBER &&
                pDay->pNext &&
                !hb_compStrToNum( pDay->value, pDay->len, &lDay, &dNumber,
                                  &iDec, &iWidth ) )
            {
               pDay = pDay->pNext;
               if( HB_PP_TOKEN_TYPE( pDay->type ) != HB_PP_TOKEN_RIGHT_CB )
               {
                  if( HB_PP_TOKEN_TYPE( pDay->type ) == HB_PP_TOKEN_COMMA )
                     pDay = pDay->pNext;
                  if( !hb_comp_timeDecode( pDay, &lTime ) )
                     return 0;
               }
               lDate = hb_dateEncode( lYear, lMonth, lDay );
               if( lDate != 0 || ( lYear == 0 && lMonth == 0 && lDay == 0 ) )
               {
                  while( HB_PP_TOKEN_TYPE( pToken->type ) != HB_PP_TOKEN_RIGHT_CB )
                     pToken = hb_pp_tokenGet( pLex->pPP );
                  yylval_ptr->valLong.lNumber = lDate;
                  pLex->iState = LITERAL;
                  return NUM_DATE;
               }
            }
         }
      }
      else if( hb_comp_timeDecode( pDay, &lTime ) )
      {
         ;
      }
   }

   return 0;
}
#endif

int hb_complex( YYSTYPE *yylval_ptr, HB_COMP_DECL )
{
   PHB_COMP_LEX pLex = HB_COMP_PARAM->pLex;
   PHB_PP_TOKEN pToken = hb_pp_tokenGet( pLex->pPP );

   if( pLex->fEol )
   {
      pLex->fEol = FALSE;
      HB_COMP_PARAM->currLine++;
   }

   if( !pToken || HB_COMP_PARAM->fExit )
   {
      pLex->lasttok = NULL;
      return 0;
   }

   pLex->lasttok = pToken->value;

   switch( HB_PP_TOKEN_TYPE( pToken->type ) )
   {
      case HB_PP_TOKEN_NUMBER:
      {
         HB_LONG lNumber;
         double dNumber;
         int iDec, iWidth;

         pLex->iState = LITERAL;
         if( hb_compStrToNum( pToken->value, pToken->len, &lNumber, &dNumber, &iDec, &iWidth ) )
         {
            yylval_ptr->valDouble.dNumber = dNumber;
            yylval_ptr->valDouble.bDec    = ( UCHAR ) iDec;
            yylval_ptr->valDouble.bWidth  = ( UCHAR ) iWidth;
            return NUM_DOUBLE;
         }
         else
         {
            yylval_ptr->valLong.lNumber = lNumber;
            yylval_ptr->valLong.bWidth  = ( UCHAR ) iWidth;
            return NUM_LONG;
         }
      }
      case HB_PP_TOKEN_DATE:
         pLex->iState = LITERAL;
         if( pToken->len == 10 )
         {
            int year, month, day;
            hb_dateStrGet( pToken->value + 2, &year, &month, &day );
            yylval_ptr->valLong.lNumber = hb_dateEncode( year, month, day );
         }
         else
            yylval_ptr->valLong.lNumber = 0;

         if( yylval_ptr->valLong.lNumber == 0 &&
             strcmp( pToken->value + 2, "0" ) != 0 &&
             strcmp( pToken->value + 2, "00000000" ) != 0 )
         {
            hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_INVALID_DATE, pToken->value, NULL );
         }
         return NUM_DATE;

      case HB_PP_TOKEN_STRING:
         pLex->iState = LITERAL;
         pLex->lasttok = hb_comp_tokenString( yylval_ptr, HB_COMP_PARAM, pToken );
         return LITERAL;

      case HB_PP_TOKEN_LOGICAL:
         pLex->iState = LITERAL;
         return pToken->value[ 1 ] == 'T' ? TRUEVALUE : FALSEVALUE;

      case HB_PP_TOKEN_MACROVAR:
         pLex->iState = MACROVAR;
         hb_pp_tokenUpper( pToken );
         pLex->lasttok = yylval_ptr->string =
                              hb_comp_tokenIdentifer( HB_COMP_PARAM, pToken );
         return MACROVAR;

      case HB_PP_TOKEN_MACROTEXT:
         pLex->iState = MACROTEXT;
         hb_pp_tokenUpper( pToken );
         pLex->lasttok = yylval_ptr->string =
                              hb_comp_tokenIdentifer( HB_COMP_PARAM, pToken );
         return MACROTEXT;

      case HB_PP_TOKEN_LEFT_SB:
         switch( pLex->iState )
         {
            case OPERATOR:
            case LSEPARATOR:
            case LARRAY:
            case IF:
            case ELSEIF:
            case CASE:
            case BREAK:
            case RETURN:
            case WITH:
            case WHILE:
            case DECLARE_TYPE:
               pLex->iState = LITERAL;
               hb_pp_tokenToString( pLex->pPP, pToken );
               pLex->lasttok = hb_comp_tokenString( yylval_ptr, HB_COMP_PARAM,
                                                    pToken );
               return LITERAL;

            default:
               pLex->iState = LINDEX;
               return '[';
         }

      case HB_PP_TOKEN_RIGHT_SB:
         pLex->iState = RINDEX;
         return ']';

      case HB_PP_TOKEN_LEFT_CB:
         if( pToken->pNext )
         {
            if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_PIPE )
            {
               yylval_ptr->asCodeblock.string = hb_strdup( 
                  hb_pp_tokenBlockString( pLex->pPP, pToken,
                                          &yylval_ptr->asCodeblock.flags,
                                          &yylval_ptr->asCodeblock.length ) );
               hb_pp_tokenGet( pLex->pPP );
               return CBSTART;
            }
#if 0
            else if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_POWER )
            {
               int iType = hb_comp_dayTimeDecode( pLex, pToken, yylval_ptr );
               if( iType )
                  return iType;
            }
#endif
         }
         pLex->iState = LARRAY;
         return '{';

      case HB_PP_TOKEN_RIGHT_CB:
         pLex->iState = RARRAY;
         return '}';

      case HB_PP_TOKEN_LEFT_PB:
         pLex->iState = LSEPARATOR;
         return '(';

      case HB_PP_TOKEN_RIGHT_PB:
         pLex->iState = RSEPARATOR;
         return ')';

      case HB_PP_TOKEN_EPSILON:
         pLex->iState = OPERATOR;
         return EPSILON;

      case HB_PP_TOKEN_HASH:
      case HB_PP_TOKEN_DIRECTIVE:
         if( pLex->iState == LOOKUP && pToken->pNext &&
             HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD &&
             hb_stricmp( "LINE", pToken->pNext->value ) == 0 )
         {
            hb_pp_tokenGet( pLex->pPP );
            return LINE;
         }
         pLex->iState = OPERATOR;
         return NE1;

      case HB_PP_TOKEN_NE:
         pLex->iState = OPERATOR;
         return NE2;

      case HB_PP_TOKEN_ASSIGN:
         pLex->iState = OPERATOR;
         return INASSIGN;

      case HB_PP_TOKEN_EQUAL:
         pLex->iState = OPERATOR;
         return EQ;

      case HB_PP_TOKEN_INC:
         pLex->iState = OPERATOR;
         return INC;

      case HB_PP_TOKEN_DEC:
         pLex->iState = OPERATOR;
         return DEC;

      case HB_PP_TOKEN_ALIAS:
         pLex->iState = OPERATOR;
         return ALIASOP;

      case HB_PP_TOKEN_LE:
         pLex->iState = OPERATOR;
         return LE;

      case HB_PP_TOKEN_GE:
         pLex->iState = OPERATOR;
         return GE;

      case HB_PP_TOKEN_PLUSEQ:
         pLex->iState = OPERATOR;
         return PLUSEQ;

      case HB_PP_TOKEN_MINUSEQ:
         pLex->iState = OPERATOR;
         return MINUSEQ;

      case HB_PP_TOKEN_MULTEQ:
         pLex->iState = OPERATOR;
         return MULTEQ;

      case HB_PP_TOKEN_DIVEQ:
         pLex->iState = OPERATOR;
         return DIVEQ;

      case HB_PP_TOKEN_MODEQ:
         pLex->iState = OPERATOR;
         return MODEQ;

      case HB_PP_TOKEN_EXPEQ:
         pLex->iState = OPERATOR;
         return EXPEQ;

      case HB_PP_TOKEN_POWER:
         pLex->iState = OPERATOR;
         return POWER;

      case HB_PP_TOKEN_AND:
         pLex->iState = OPERATOR;
         return AND;

      case HB_PP_TOKEN_OR:
         pLex->iState = OPERATOR;
         return OR;

      case HB_PP_TOKEN_NOT:
         pLex->iState = OPERATOR;
         return NOT;

      case HB_PP_TOKEN_SEND:
         if( HB_PP_LEX_SELF( pToken ) )
         {
            pLex->lasttok = yylval_ptr->string = "SELF";
            pLex->iState = IDENTIFIER;
            return IDENTIFIER;
         }
         pLex->iState = OPERATOR;
         return ( UCHAR ) pToken->value[ 0 ];

      case HB_PP_TOKEN_EQ:
         if( HB_SUPPORT_HARBOUR && pToken->pNext && pToken->pNext->spaces == 0 &&
             HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_GT )
         {
            hb_pp_tokenGet( pLex->pPP );
            pLex->iState = OPERATOR;
            return HASHOP;
         }
         /* no break */
      case HB_PP_TOKEN_PLUS:
      case HB_PP_TOKEN_MINUS:
      case HB_PP_TOKEN_MULT:
      case HB_PP_TOKEN_DIV:
      case HB_PP_TOKEN_MOD:
      case HB_PP_TOKEN_IN:
      case HB_PP_TOKEN_COMMA:
      case HB_PP_TOKEN_PIPE:
      case HB_PP_TOKEN_AMPERSAND:
      case HB_PP_TOKEN_DOT:
      case HB_PP_TOKEN_LT:
      case HB_PP_TOKEN_GT:
      case HB_PP_TOKEN_REFERENCE:
         pLex->iState = OPERATOR;
         return ( UCHAR ) pToken->value[ 0 ];

      case HB_PP_TOKEN_EOL:
         pLex->fEol = TRUE;
      case HB_PP_TOKEN_EOC:
         pLex->iState = LOOKUP;
         return ( UCHAR ) pToken->value[ 0 ];

      case HB_PP_TOKEN_KEYWORD:
      {
         int iType;
         hb_pp_tokenUpper( pToken );
         iType = hb_comp_keywordType( pToken );
         pLex->lasttok = yylval_ptr->string =
                              hb_comp_tokenIdentifer( HB_COMP_PARAM, pToken );
         switch( iType )
         {
            case FUNCTION:
            case PROCEDURE:
               if( HB_SUPPORT_HARBOUR && ( pLex->iState != LOOKUP ||
                   ( !HB_PP_TOKEN_ISEOC( pToken->pNext ) &&
                     HB_PP_LEX_NEEDLEFT( pToken->pNext ) ) ) &&
                   pLex->iState != INIT && pLex->iState != EXIT &&
                   pLex->iState != STATIC )
               {
                  iType = IDENTIFIER;
                  break;
               }
               /* Clipper accepts FUNCTION and PROCEDURE in one context only */
               if( !pToken->pNext ||
                   HB_PP_TOKEN_TYPE( pToken->pNext->type ) != HB_PP_TOKEN_KEYWORD )
                  hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                   HB_COMP_ERR_SYNTAX, pToken->value, NULL );
               pLex->iState = iType;
               return pLex->iState;

            case BEGINSEQ:
               if( pLex->iState == LOOKUP && pToken->pNext &&
                   HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD )
               {
                  if( pToken->pNext->len >= 4 && pToken->pNext->len <= 8 &&
                      hb_strnicmp( "SEQUENCE", pToken->pNext->value, pToken->pNext->len ) == 0 )
                  {
                     hb_pp_tokenGet( pLex->pPP );
                     break;
                  }
               }
               iType = IDENTIFIER;
               break;

            case RECOVER:
               if( pLex->iState == LOOKUP )
               {
                  if( HB_PP_TOKEN_ISEOC( pToken->pNext ) )
                  {
                     pLex->iState = RECOVER;
                     return RECOVER;
                  }
                  else if( pToken->pNext &&
                           HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD &&
                           pToken->pNext->len >= 4 && pToken->pNext->len <= 5 &&
                           hb_strnicmp( "USING", pToken->pNext->value, pToken->pNext->len ) == 0 )
                  {
                     hb_pp_tokenGet( pLex->pPP );
                     pLex->iState = RECOVERUSING;
                     return RECOVERUSING;
                  }
               }
               iType = IDENTIFIER;
               break;

            case ALWAYS:
               if( pLex->iState == LOOKUP && HB_PP_TOKEN_ISEOC( pToken->pNext ) )
               {
                  pLex->iState = ALWAYS;
                  return ALWAYS;
               }
               iType = IDENTIFIER;
               break;

            case END:
               if( pLex->iState == LOOKUP )
               {
                  if( pToken->pNext &&
                      HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD &&
                      pToken->pNext->len >= 4 && pToken->pNext->len <= 8 &&
                      hb_strnicmp( "SEQUENCE", pToken->pNext->value, pToken->pNext->len ) == 0 )
                  {
                     if( HB_COMP_PARAM->functions.pLast->wSeqCounter == 0 )
                        hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                         HB_COMP_ERR_ENDIF, NULL, NULL );
                     hb_pp_tokenGet( pLex->pPP );
                     pLex->iState = ENDSEQ;
                     return ENDSEQ;
                  }
                  else if( HB_PP_TOKEN_ISEOC( pToken->pNext ) ||
                           HB_PP_TOKEN_TYPE( pToken->pNext->type ) ==
                                                         HB_PP_TOKEN_KEYWORD )
                  {
                     pLex->iState = END;
                     return END;
                  }
                  if( !HB_SUPPORT_HARBOUR )
                  {
                     /* Clipper does not like end[], end(), end->, end-- & end++ at
                        the begining of line */
                     if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_PB ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_SB ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_INC ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_DEC ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_ALIAS )
                        hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                         HB_COMP_ERR_ENDIF, NULL, NULL );
                  }
               }
               iType = IDENTIFIER;
               break;

            case ELSE:
               if( HB_SUPPORT_HARBOUR )
               {
                  if( pLex->iState != LOOKUP ||
                      !HB_PP_TOKEN_ISEOC( pToken->pNext ) )
                  {
                     iType = IDENTIFIER;
                     break;
                  }
               }
               /* Clipper accepts ELSE in one context only */
               if( HB_COMP_PARAM->functions.pLast->wIfCounter == 0 )
                  hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                   HB_COMP_ERR_UNMATCHED_ELSE, NULL, NULL );
               pLex->iState = ELSE;
               return ELSE;

            case ELSEIF:
               if( HB_SUPPORT_HARBOUR )
               {
                  if( pLex->iState != LOOKUP ||
                      ( !HB_PP_TOKEN_ISEOC( pToken->pNext ) &&
                        HB_PP_LEX_NEEDLEFT( pToken->pNext ) ) )
                  {
                     iType = IDENTIFIER;
                     break;
                  }
               }
               /* Clipper accepts ELSEIF in one context only */
               if( HB_COMP_PARAM->functions.pLast->wIfCounter == 0 )
                  hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                   HB_COMP_ERR_UNMATCHED_ELSEIF, NULL, NULL );
               pLex->iState = ELSEIF;
               return ELSEIF;

            case ENDIF:
               if( HB_SUPPORT_HARBOUR )
               {
                  if( pLex->iState != LOOKUP ||
                      !HB_PP_TOKEN_ISEOC( pToken->pNext ) )
                  {
                     iType = IDENTIFIER;
                     break;
                  }
               }
               /* Clipper accepts ENDIF in one context only */
               if( HB_COMP_PARAM->functions.pLast->wIfCounter == 0 )
                  hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                   HB_COMP_ERR_ENDIF, NULL, NULL );
               break;

            case ENDCASE:
               if( HB_SUPPORT_HARBOUR )
               {
                  if( pLex->iState != LOOKUP ||
                      !HB_PP_TOKEN_ISEOC( pToken->pNext ) )
                  {
                     iType = IDENTIFIER;
                     break;
                  }
               }
               /* Clipper accepts ENDCASE in one context only */
               if( HB_COMP_PARAM->functions.pLast->wCaseCounter == 0 )
                  hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                   HB_COMP_ERR_ENDCASE, NULL, NULL );
               break;

            case ENDDO:
               if( HB_SUPPORT_HARBOUR )
               {
                  if( pLex->iState != LOOKUP ||
                      !HB_PP_TOKEN_ISEOC( pToken->pNext ) )
                  {
                     iType = IDENTIFIER;
                     break;
                  }
               }
               /* Clipper accepts ENDDO in one context only */
               if( HB_COMP_PARAM->functions.pLast->wWhileCounter == 0 )
                  hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                   HB_COMP_ERR_ENDDO, NULL, NULL );
               break;

            case ENDSEQ:
            case ENDSWITCH:
            case ENDWITH:
               if( pLex->iState != LOOKUP || !HB_PP_TOKEN_ISEOC( pToken->pNext ) )
                  iType = IDENTIFIER;
               break;

            case INIT:
               if( pLex->iState == LOOKUP && pToken->pNext &&
                   HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD &&
                   pToken->pNext->len >= 4 &&
                   ( hb_strnicmp( "FUNCTION", pToken->pNext->value,
                                  pToken->pNext->len ) == 0 ||
                     hb_strnicmp( "PROCEDURE", pToken->pNext->value,
                                  pToken->pNext->len ) == 0 ) )
               {
                  pLex->iState = INIT;
                  return INIT;
               }
               iType = IDENTIFIER;
               break;

            case FIELD:
               if( pToken->pNext && 
                   ( ( pLex->iState == LOOKUP &&
                       HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD ) ||
                     HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_ALIAS ) )
               {
                  pLex->iState = FIELD;
                  return FIELD;
               }
               iType = IDENTIFIER;
               break;

            case BREAK:
               /* NOTE: Clipper does not like break[] in any context
                *       There are no resons to limit this use in Harbour.
                */
               if( pLex->iState == LOOKUP &&
                   ( HB_PP_TOKEN_ISEOC( pToken->pNext ) ||
                     !( HB_PP_LEX_NEEDLEFT( pToken->pNext ) ||
                        HB_PP_TOKEN_TYPE( pToken->pNext->type ) ==
                                                      HB_PP_TOKEN_LEFT_PB ) ) )
               {
                  pLex->iState = BREAK;
                  return BREAK;
               }
               iType = IDENTIFIER;
               break;

            case CASE:
            case OTHERWISE:
               if( pLex->iState == LOOKUP &&
                   ( HB_PP_TOKEN_ISEOC( pToken->pNext ) ||
                     ( iType == CASE && !HB_PP_LEX_NEEDLEFT( pToken->pNext ) ) ) )
               {
                  if( HB_COMP_PARAM->functions.pLast->wCaseCounter == 0 &&
                      HB_COMP_PARAM->functions.pLast->wSwitchCounter == 0 )
                     hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                      HB_COMP_ERR_CASE, NULL, NULL );
                  pLex->iState = iType;
                  return iType;
               }
               iType = IDENTIFIER;
               break;

            case FOR:
               if( pLex->iState == LOOKUP &&
                   !HB_PP_TOKEN_ISEOC( pToken->pNext ) &&
                   ( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD ||
                     /* Clipper always assume FOR (somevar):=1 TO ... here */
                     HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_PB ) )
               {
                  if( pToken->pNext->pNext &&
                      HB_PP_TOKEN_TYPE( pToken->pNext->pNext->type ) != HB_PP_TOKEN_ASSIGN &&
                      HB_PP_TOKEN_TYPE( pToken->pNext->pNext->type ) != HB_PP_TOKEN_EQ &&
                      HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD &&
                      hb_stricmp( "EACH", pToken->pNext->value ) == 0 )
                  {
                     hb_pp_tokenGet( pLex->pPP );
                     pLex->iState = FOREACH;
                     return FOREACH;
                  }
                  pLex->iState = FOR;
                  return FOR;
               }
               iType = IDENTIFIER;
               break;

            case NEXT:
               if( pLex->iState == LOOKUP )
               {
                  if( HB_PP_TOKEN_ISEOC( pToken->pNext ) ||
                      HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD )
                  {
                     if( HB_COMP_PARAM->functions.pLast->wForCounter == 0 )
                        hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                         HB_COMP_ERR_NEXTFOR, NULL, NULL );
                     pLex->iState = iType;
                     return iType;
                  }
                  if( ! HB_SUPPORT_HARBOUR )
                  {
                     /* Clipper does not like NEXT[], NEXT(), NEXT->,
                        NEXT++ & NEXT-- at the begining of line */
                     if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_PB ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_SB ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_INC ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_DEC ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_ALIAS )
                        hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                         HB_COMP_ERR_NEXTFOR, NULL, NULL );
                  }
               }
               iType = IDENTIFIER;
               break;

            case RETURN:
            case DOSWITCH:
               if( pLex->iState == LOOKUP &&
                   ( HB_PP_TOKEN_ISEOC( pToken->pNext ) ||
                     !HB_PP_LEX_NEEDLEFT( pToken->pNext ) ) )
               {
                  pLex->iState = iType;
                  return iType;
               }
               iType = IDENTIFIER;
               break;

            case DECLARE:
               if( pLex->iState == LOOKUP &&
                   !HB_PP_TOKEN_ISEOC( pToken->pNext ) )
               {
                  if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_MACROVAR ||
                      HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_MACROTEXT )
                  {
                     pLex->iState = PRIVATE;
                     return PRIVATE;
                  }
                  else if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD )
                  {
                     if( HB_PP_TOKEN_ISEOC( pToken->pNext->pNext ) ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->pNext->type ) == HB_PP_TOKEN_LEFT_SB ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->pNext->type ) == HB_PP_TOKEN_COMMA ||
                         HB_PP_TOKEN_TYPE( pToken->pNext->pNext->type ) == HB_PP_TOKEN_ASSIGN ||
                         ( HB_PP_TOKEN_TYPE( pToken->pNext->pNext->type ) == HB_PP_TOKEN_KEYWORD &&
                           hb_stricmp( "AS", pToken->pNext->pNext->value ) == 0 ) )
                     {
                        pLex->iState = PRIVATE;
                        return PRIVATE;
                     }
                     pLex->iState = DECLARE;
                     return DECLARE;
                  }
               }
               iType = IDENTIFIER;
               break;

            case DO:
               if( pLex->iState == LOOKUP && !HB_PP_TOKEN_ISEOC( pToken->pNext ) )
               {
                  if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD )
                  {
                     if( pToken->pNext->len == 4 &&
                         hb_stricmp( "CASE", pToken->pNext->value ) == 0 )
                     {
                        if( HB_PP_TOKEN_ISEOC( pToken->pNext->pNext ) )
                        {
                           hb_pp_tokenGet( pLex->pPP );
                           pLex->iState = DOCASE;
                           return DOCASE;
                        }
                     }
                     else if( pToken->pNext->len >= 4 &&
                              pToken->pNext->len <= 5 &&
                              hb_strnicmp( "WHILE", pToken->pNext->value,
                                           pToken->pNext->len ) == 0 &&
                        /* check if it's not DO while [WITH <args>] */
                        !HB_PP_TOKEN_ISEOC( pToken->pNext->pNext ) &&
                        ( HB_PP_TOKEN_TYPE( pToken->pNext->pNext->type ) != HB_PP_TOKEN_KEYWORD ||
                          pToken->pNext->pNext->len != 4 ||
                          hb_stricmp( "WITH", pToken->pNext->pNext->value ) != 0 ) )
                     {
                        /* DO WHILE <exp> */
                        hb_pp_tokenGet( pLex->pPP );
                        pLex->iState = WHILE;
                        return WHILE;
                     }
                     /* DO identifier [WITH <args>] */
                     pToken = hb_pp_tokenGet( pLex->pPP );
                     /* do not upper next token for case sensitive file systems */
                     /* hb_pp_tokenUpper( pToken ); */
                     pLex->lasttok = yylval_ptr->string =
                              hb_comp_tokenIdentifer( HB_COMP_PARAM, pToken );
                     pLex->iState = IDENTIFIER;
                     return DOIDENT;
                  }
                  else if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_MACROVAR ||
                           HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_MACROTEXT )
                  {
                     /* DO &id WITH */
                     pLex->iState = DO;
                     return DO;
                  }
               }
               iType = IDENTIFIER;
               break;

            case WHILE:
               if( pLex->iState == LOOKUP &&
                   !HB_PP_TOKEN_ISEOC( pToken->pNext ) &&
                   !HB_PP_LEX_NEEDLEFT( pToken->pNext ) )
               {
                  pLex->iState = WHILE;
                  return WHILE;
               }
               iType = IDENTIFIER;
               break;

            case WITH:
               if( !HB_PP_TOKEN_ISEOC( pToken->pNext ) )
               {
                  if( pLex->iState == LOOKUP &&
                      HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD &&
                      pToken->pNext->len >= 4 &&
                      hb_strnicmp( "OBJECT", pToken->pNext->value,
                                   pToken->pNext->len ) == 0 )
                  {
                     hb_pp_tokenGet( pLex->pPP );
                     pLex->iState = WITHOBJECT;
                     return WITHOBJECT;
                  }
                  else if( pLex->iState == MACROVAR ||
                           pLex->iState == MACROTEXT ||
                           pLex->iState == IDENTIFIER )
                  {
                     pLex->iState = WITH;
                     return WITH;
                  }
               }
               iType = IDENTIFIER;
               break;

            case IIF:
               if( pLex->iState == FUNCTION || pLex->iState == PROCEDURE ||
                   ( !HB_SUPPORT_HARBOUR && HB_PP_TOKEN_ISEOC( pToken->pNext ) ) )
                  hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                   HB_COMP_ERR_SYNTAX, "IIF", NULL );
               else if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_PB )
               {
                  pLex->iState = IIF;
                  return IIF;
               }
               else if( ! HB_SUPPORT_HARBOUR )
                  hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                   HB_COMP_ERR_SYNTAX, pToken->pNext->value, NULL );
               else
               iType = IDENTIFIER;
               break;

            case IF:
               if( pLex->iState == FUNCTION || pLex->iState == PROCEDURE ||
                   ( !HB_SUPPORT_HARBOUR && HB_PP_TOKEN_ISEOC( pToken->pNext ) ) )
                  hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                   HB_COMP_ERR_SYNTAX, "IF", NULL );
               else if( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_PB )
               {
                  if( pLex->iState == LOOKUP )
                  {
                     PHB_PP_TOKEN pNext = pToken->pNext->pNext;   /* COND EXP */

                     pLex->iState = IF;
                     if( hb_pp_tokenNextExp( &pNext ) )  /* TRUE EXP */
                     {
                        if( hb_pp_tokenNextExp( &pNext ) )  /* FALSE EXP */
                        {
                           if( !hb_pp_tokenNextExp( &pNext ) && pNext &&
                               HB_PP_TOKEN_TYPE( pNext->type ) == HB_PP_TOKEN_RIGHT_PB )
                              pLex->iState = IIF;
                        }
                     }
                  }
                  else
                     pLex->iState = IIF;
   
                  return pLex->iState;
               }
               else if( HB_PP_LEX_NEEDLEFT( pToken->pNext ) || pLex->iState != LOOKUP )
               {
                  if( !HB_SUPPORT_HARBOUR )
                     hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E',
                                      HB_COMP_ERR_SYNTAX2, pToken->pNext->value, "IF" );
               }
               else
               {
                  pLex->iState = IF;
                  return IF;
               }
               iType = IDENTIFIER;
               break;

            case PROCREQ:
               if( pToken->pNext &&
                   HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_PB )
               {
                  hb_pp_tokenGet( pLex->pPP );
                  pLex->iState = LSEPARATOR;
                  return PROCREQ;
               }
               iType = IDENTIFIER;
               break;

            case SELF:
               if( pToken->pNext && pToken->pNext->pNext &&
                   HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_PB &&
                   HB_PP_TOKEN_TYPE( pToken->pNext->pNext->type ) == HB_PP_TOKEN_RIGHT_PB )
               {
                  hb_pp_tokenGet( pLex->pPP );
                  hb_pp_tokenGet( pLex->pPP );
                  pLex->iState = RSEPARATOR;
                  return SELF;
               }
               iType = IDENTIFIER;
               break;

            case AS_TYPE:
            {
               int iAs = hb_comp_asType( pToken->pNext, FALSE );
               if( iAs )
               {
                  pLex->iState = DECLARE_TYPE;
                  pToken = hb_pp_tokenGet( pLex->pPP );
                  if( iAs == AS_ARRAY && pToken->pNext &&
                      HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD &&
                      hb_stricmp( "OF", pToken->pNext->value ) == 0 )
                  {
                     int iAsArray = hb_comp_asType( pToken->pNext->pNext, TRUE );
                     if( iAsArray )
                     {
                        hb_pp_tokenGet( pLex->pPP );
                        hb_pp_tokenGet( pLex->pPP );
                        return iAsArray;
                     }
                  }
                  return iAs;
               }
               iType = IDENTIFIER;
               break;
            }
            case DECLARE_CLASS:
               if( pLex->iState == LOOKUP && !HB_PP_TOKEN_ISEOC( pToken->pNext ) &&
                   HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD )
               {
                  pLex->iState = DECLARE_TYPE;
                  return DECLARE_CLASS;
               }
               iType = IDENTIFIER;
               break;
            case DECLARE_MEMBER:
               if( pLex->iState == LOOKUP && !HB_PP_TOKEN_ISEOC( pToken->pNext ) &&
                   ( HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_KEYWORD ||
                     HB_PP_TOKEN_TYPE( pToken->pNext->type ) == HB_PP_TOKEN_LEFT_CB ) )
               {
                  pLex->iState = OPERATOR;
                  return DECLARE_MEMBER;
               }
               iType = IDENTIFIER;
               break;

            case EXIT:
            case STATIC:
               if( pLex->iState == LOOKUP )
               {
                  pLex->iState = iType;
                  return iType;
               }
               break;

            case NIL:
               if( pLex->iState == DECLARE_TYPE )
                  iType = IDENTIFIER;
               break;
            case IN:
            case LOOP:
            case STEP:
            case TO:
            case ANNOUNCE:
            case OPTIONAL:
            case DESCEND:
            case DYNAMIC:
            case EXTERN:
            case LOCAL:
            case MEMVAR:
            case PARAMETERS:
            case PRIVATE:
            case PUBLIC:
               break;
         }
         pLex->iState = IDENTIFIER;
         return iType;
      }
      default:
         return ( UCHAR ) pToken->value[ 0 ];
   }
}

void hb_compParserStop( HB_COMP_DECL )
{
   HB_SYMBOL_UNUSED( HB_COMP_PARAM );
}
