/*
 * Compiler main file
 *
 * Copyright 1999 Antonio Linares <alinares@fivetechsoft.com>
 * Copyright 2000 Ron Pinkas <Ron@Profit-Master.com>
 *   (hb_compPrepareJumps(), hb_compOptimizeJumps(), hb_compOptimizeFrames(),
 *   hb_compDeclaredParameterAdd(), hb_compClassAdd(), hb_compClassFind(),
 *   hb_compMethodAdd(), hb_compMethodFind(), hb_compDeclaredAdd())
 *
 * 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 of the License, 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * (or visit their website at https://www.gnu.org/licenses/).
 *
 */

/* Avoid tracing in preprocessor/compiler. */
#if ! defined( HB_TRACE_UTILS )
   #if defined( HB_TRACE_LEVEL )
      #undef HB_TRACE_LEVEL
   #endif
#endif

#include "hbcomp.h"
#include "hbset.h"

static int hb_compCompile( HB_COMP_DECL, const char * szPrg, const char * szBuffer, int iStartLine );
static HB_BOOL hb_compRegisterFunc( HB_COMP_DECL, PHB_HFUNC pFunc, HB_BOOL fError );

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

int hb_compMainExt( int argc, const char * const argv[],
                    HB_BYTE ** pBufPtr, HB_SIZE * pnSize,
                    const char * szSource, int iStartLine,
                    void * cargo, PHB_PP_OPEN_FUNC pOpenFunc,
                                  PHB_PP_MSG_FUNC pMsgFunc )
{
   HB_COMP_DECL;
   int iStatus = EXIT_SUCCESS, iFileCount = 0;
   int iFileCase, iDirCase, iDirSep;
   HB_BOOL fTrimFN;

   HB_TRACE( HB_TR_DEBUG, ( "hb_compMain()" ) );

   iFileCase = hb_setGetFileCase();
   iDirCase = hb_setGetDirCase();
   iDirSep = hb_setGetDirSeparator();
   fTrimFN = hb_setGetTrimFileName();

   if( pBufPtr && pnSize )
   {
      *pBufPtr = NULL;
      *pnSize  = 0;
   }

   HB_COMP_PARAM = hb_comp_new();
   HB_COMP_PARAM->cargo = cargo;
   if( pMsgFunc )
      HB_COMP_PARAM->outMsgFunc = pMsgFunc;

   HB_COMP_PARAM->pOutPath = NULL;

   /* First check the environment variables */
   hb_compChkEnvironment( HB_COMP_PARAM );

   /* Then check command-line arguments
      This will override duplicated environment settings */
   hb_compChkCommandLine( HB_COMP_PARAM, argc, argv );

   if( ! HB_COMP_PARAM->fExit )
   {
      if( HB_COMP_PARAM->iTraceInclude == 0 &&
          HB_COMP_PARAM->iSyntaxCheckOnly == 2 )
         HB_COMP_PARAM->iTraceInclude = 1;

      if( pBufPtr && pnSize )
      {
         if( HB_COMP_PARAM->iTraceInclude > 0 &&
             HB_COMP_PARAM->iSyntaxCheckOnly > 0 )
            HB_COMP_PARAM->iTraceInclude |= 0x100;
         else
            HB_COMP_PARAM->iLanguage = HB_LANG_PORT_OBJ_BUF;
      }

      if( HB_COMP_PARAM->fLogo )
         hb_compPrintLogo( HB_COMP_PARAM );

      if( HB_COMP_PARAM->fBuildInfo )
      {
         hb_compOutStd( HB_COMP_PARAM, "\n" );
         hb_verBuildInfo();
      }

      if( HB_COMP_PARAM->fCredits )
         hb_compPrintCredits( HB_COMP_PARAM );

      /* Set Search Path */
      if( HB_COMP_PARAM->fINCLUDE )
         hb_compChkAddIncPaths( HB_COMP_PARAM );

      /* Set standard rules */
      hb_compInitPP( HB_COMP_PARAM, pOpenFunc );

      /* Prepare the table of identifiers */
      hb_compIdentifierOpen( HB_COMP_PARAM );
   }

   if( szSource )
   {
      const char * pszFileName = "{SOURCE}";
      int i;
      /* Look for file name if any */
      for( i = 1; i < argc && ! HB_COMP_PARAM->fExit; i++ )
      {
         if( ! HB_ISOPTSEP( argv[ i ][ 0 ] ) )
         {
            pszFileName = argv[ i ];
            break;
         }
      }
      iFileCount++;
      iStatus = hb_compCompile( HB_COMP_PARAM, pszFileName, szSource, iStartLine );
   }
   else
   {
      int i;
      /* Process all files passed via the command-line. */
      for( i = 1; i < argc && ! HB_COMP_PARAM->fExit; i++ )
      {
         HB_TRACE( HB_TR_DEBUG, ( "main LOOP(%i,%s)", i, argv[ i ] ) );
         if( ! HB_ISOPTSEP( argv[ i ][ 0 ] ) )
         {
            iFileCount++;
            iStatus = hb_compCompile( HB_COMP_PARAM, argv[ i ], NULL, 0 );
            if( iStatus != EXIT_SUCCESS )
               break;
         }
      }
   }

   if( iFileCount == 0 && ! HB_COMP_PARAM->fQuiet && ! HB_COMP_PARAM->fExit &&
       ! HB_COMP_PARAM->fBuildInfo && ! HB_COMP_PARAM->fCredits )
   {
      hb_compPrintUsage( HB_COMP_PARAM, argv[ 0 ] );
      iStatus = EXIT_FAILURE;
   }
   else if( HB_COMP_PARAM->iErrorCount > 0 )
      iStatus = EXIT_FAILURE;

   if( iFileCount > 0 && iStatus == EXIT_SUCCESS )
   {
      hb_compI18nSave( HB_COMP_PARAM, HB_TRUE );

      if( pBufPtr && pnSize && iStatus == EXIT_SUCCESS )
      {
         *pBufPtr = HB_COMP_PARAM->pOutBuf;
         *pnSize  = HB_COMP_PARAM->nOutBufSize;
         HB_COMP_PARAM->pOutBuf = NULL;
         HB_COMP_PARAM->nOutBufSize = 0;
      }
   }

   hb_comp_free( HB_COMP_PARAM );

   hb_setSetFileCase( iFileCase );
   hb_setSetDirCase( iDirCase );
   hb_setSetDirSeparator( iDirSep );
   hb_setSetTrimFileName( fTrimFN );

   return iStatus;
}

int hb_compMain( int argc, const char * const argv[] )
{
   return hb_compMainExt( argc, argv, NULL, NULL, NULL, 0, NULL, NULL, NULL );
}

static int hb_compReadClpFile( HB_COMP_DECL, const char * szClpFile )
{
   char buffer[ HB_PATH_MAX + 80 ];
   char szFile[ HB_PATH_MAX ];
   int iStatus = EXIT_SUCCESS;
   PHB_FNAME pFileName;
   FILE *inFile;

   pFileName = hb_fsFNameSplit( szClpFile );
   if( ! pFileName->szExtension )
   {
      pFileName->szExtension = ".clp";
      hb_fsFNameMerge( szFile, pFileName );
      szClpFile = szFile;
   }

   HB_COMP_PARAM->szFile = hb_compIdentifierNew( HB_COMP_PARAM, szClpFile, HB_IDENT_COPY );
   if( ! HB_COMP_PARAM->pFileName )
      HB_COMP_PARAM->pFileName = pFileName;
   else
      hb_xfree( pFileName );

   inFile = hb_fopen( szClpFile, "r" );
   if( ! inFile )
   {
      /* TODO: Clipper compatible error */
      hb_snprintf( buffer, sizeof( buffer ),
                   "Cannot open input file: %s\n", szClpFile );
      hb_compOutErr( HB_COMP_PARAM, buffer );
      iStatus = EXIT_FAILURE;
   }
   else
   {
      int i = 0, ch;

      hb_snprintf( buffer, sizeof( buffer ), "Reading '%s'...\n", szClpFile );
      hb_compOutStd( HB_COMP_PARAM, buffer );

      do
      {
         ch = fgetc( inFile );

         /* '"' - quoting file names is Harbour extension.
          * Clipper does not serve it, [druzus]
          */
         if( ch == '"' )
         {
            while( ( ch = fgetc( inFile ) ) != EOF && ch != '"' && ch != '\n' )
            {
               if( i < ( HB_PATH_MAX - 1 ) )
                  szFile[ i++ ] = ( char ) ch;
            }
            if( ch == '"' )
               continue;
         }

         while( i == 0 && HB_ISSPACE( ch ) )
            ch = fgetc( inFile );

         if( ch == EOF || HB_ISSPACE( ch ) || ch == '#' )
         {
            szFile[ i ] = '\0';
            if( i > 0 )
               hb_compModuleAdd( HB_COMP_PARAM,
                                 hb_compIdentifierNew( HB_COMP_PARAM, szFile, HB_IDENT_COPY ),
                                 HB_TRUE );
            i = 0;
            while( ch != EOF && ch != '\n' )
               ch = fgetc( inFile );
         }
         else if( i < ( HB_PATH_MAX - 1 ) )
            szFile[ i++ ] = ( char ) ch;
      }
      while( ch != EOF );

      fclose( inFile );
   }

   return iStatus;
}


/* --- ACTIONS --- */


static PHB_HSYMBOL hb_compSymbolAdd( HB_COMP_DECL, const char * szSymbolName, HB_USHORT * pwPos, HB_BOOL bFunction )
{
   PHB_HSYMBOL pSym;

   pSym = ( PHB_HSYMBOL ) hb_xgrab( sizeof( HB_HSYMBOL ) );

   pSym->szName = szSymbolName;
   pSym->cScope = 0;
   pSym->iFunc = bFunction ? HB_COMP_PARAM->iModulesCount : 0;
   pSym->pFunc = NULL;
   pSym->pNext = NULL;

   if( ! HB_COMP_PARAM->symbols.iCount )
   {
      HB_COMP_PARAM->symbols.pFirst =
      HB_COMP_PARAM->symbols.pLast  = pSym;
   }
   else
   {
      HB_COMP_PARAM->symbols.pLast->pNext = pSym;
      HB_COMP_PARAM->symbols.pLast = pSym;
   }
   HB_COMP_PARAM->symbols.iCount++;

   if( pwPos )
      *pwPos = ( HB_USHORT ) ( HB_COMP_PARAM->symbols.iCount - 1 );  /* position number starts form 0 */

   return pSym;
}

static PHB_HSYMBOL hb_compSymbolFind( HB_COMP_DECL, const char * szSymbolName, HB_USHORT * pwPos, HB_BOOL bFunction )
{
   PHB_HSYMBOL pSym = HB_COMP_PARAM->symbols.pFirst;
   HB_USHORT wCnt = 0;
   int iFunc = bFunction ? HB_COMP_PARAM->iModulesCount : 0;

   while( pSym )
   {
      if( ! strcmp( pSym->szName, szSymbolName ) )
      {
         if( iFunc == pSym->iFunc )
         {
            if( pwPos )
               *pwPos = wCnt;
            return pSym;
         }
      }
      pSym = pSym->pNext;
      ++wCnt;
   }

   if( pwPos )
      *pwPos = 0;

   return NULL;
}

/* returns a symbol name based on its index on the symbol table
 * index starts from 0
 */
const char * hb_compSymbolName( HB_COMP_DECL, HB_USHORT uiSymbol )
{
   PHB_HSYMBOL pSym = HB_COMP_PARAM->symbols.pFirst;

   while( pSym )
   {
      if( uiSymbol-- == 0 )
         return pSym->szName;
      pSym = pSym->pNext;
   }
   return NULL;
}

static void hb_compCheckDuplVars( HB_COMP_DECL, PHB_HVAR pVar, const char * szVarName )
{
   while( pVar )
   {
      if( ! strcmp( pVar->szName, szVarName ) )
      {
         HB_COMP_ERROR_DUPLVAR( szVarName );
         break;
      }
      else
         pVar = pVar->pNext;
   }
}

static HB_USHORT hb_compVarListAdd( PHB_HVAR * pVarLst, PHB_HVAR pVar )
{
   HB_USHORT uiVar = 1;

   while( *pVarLst )
   {
      pVarLst = &( *pVarLst )->pNext;
      ++uiVar;
   }
   *pVarLst = pVar;

   return uiVar;
}

void hb_compVariableAdd( HB_COMP_DECL, const char * szVarName, PHB_VARTYPE pVarType )
{
   PHB_HFUNC pFunc = HB_COMP_PARAM->functions.pLast;
   PHB_HVAR pVar;
   HB_BOOL bFreeVar = HB_TRUE;

   if( ( pFunc->funFlags & HB_FUNF_FILE_DECL ) != 0 &&
       ( HB_COMP_PARAM->iVarScope == HB_VSCOMP_LOCAL ||
         HB_COMP_PARAM->iVarScope == ( HB_VSCOMP_PRIVATE | HB_VSCOMP_PARAMETER ) ) )
   {
      if( HB_COMP_PARAM->iStartProc == 2 && pFunc->szName[ 0 ] &&
          hb_compRegisterFunc( HB_COMP_PARAM, pFunc, HB_FALSE ) )
         pFunc->funFlags &= ~HB_FUNF_FILE_DECL;
      else
      {
         /* Variable declaration is outside of function/procedure body.
            In this case only STATICs, MEMVARs and FIELDs declarations are allowed. */
         hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_OUTSIDE, NULL, NULL );
         return;
      }
   }

   /* check if we are declaring local/static variable after some
    * executable statements
    */
   if( pFunc->funFlags & HB_FUNF_STATEMENTS )
   {
      const char * szVarScope;
      switch( HB_COMP_PARAM->iVarScope )
      {
         case HB_VSCOMP_LOCAL:
            szVarScope = "LOCAL";
            break;
         case HB_VSCOMP_STATIC:
         case HB_VSCOMP_TH_STATIC:
            szVarScope = "STATIC";
            break;
         case HB_VSCOMP_FIELD:
            szVarScope = "FIELD";
            break;
         case HB_VSCOMP_MEMVAR:
            szVarScope = "MEMVAR";
            break;
         default:
            szVarScope = NULL;
      }
      if( szVarScope )
      {
         hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_FOLLOWS_EXEC, szVarScope, NULL );
         return;
      }
   }

   /* Check if a declaration of duplicated variable name is requested */
   if( pFunc->szName )
   {
      /* variable defined in a function/procedure */
      hb_compCheckDuplVars( HB_COMP_PARAM, pFunc->pFields, szVarName );
      hb_compCheckDuplVars( HB_COMP_PARAM, pFunc->pStatics, szVarName );
      /* NOTE: Clipper warns if PARAMETER variable duplicates the MEMVAR
       * declaration
       */
      if( ! ( HB_COMP_PARAM->iVarScope == HB_VSCOMP_PRIVATE ||
              HB_COMP_PARAM->iVarScope == HB_VSCOMP_PUBLIC ) )
         hb_compCheckDuplVars( HB_COMP_PARAM, pFunc->pMemvars, szVarName );
   }
   else if( pFunc->funFlags & HB_FUNF_EXTBLOCK )
   {
      /* variable defined in an extended codeblock */
      hb_compCheckDuplVars( HB_COMP_PARAM, pFunc->pFields, szVarName );
      hb_compCheckDuplVars( HB_COMP_PARAM, pFunc->pStatics, szVarName );
   }
   else if( HB_COMP_PARAM->iVarScope != HB_VSCOMP_PARAMETER )
   {
      char buffer[ 80 ];
      hb_snprintf( buffer, sizeof( buffer ),
                   "Wrong type of codeblock parameter, is: %d, should be: %d\n",
                   HB_COMP_PARAM->iVarScope, HB_VSCOMP_PARAMETER );
      hb_compOutErr( HB_COMP_PARAM, buffer );
      /* variable defined in a codeblock */
      HB_COMP_PARAM->iVarScope = HB_VSCOMP_PARAMETER;
   }

   hb_compCheckDuplVars( HB_COMP_PARAM, pFunc->pLocals, szVarName );

   pVar = ( PHB_HVAR ) hb_xgrab( sizeof( HB_HVAR ) );
   pVar->szName = szVarName;
   pVar->szAlias = NULL;
   pVar->uiFlags = 0;
   pVar->cType = pVarType->cVarType;
   pVar->iUsed = HB_VU_NOT_USED;
   pVar->pNext = NULL;
   pVar->iDeclLine = HB_COMP_PARAM->currLine;

   if( HB_TOUPPER( pVarType->cVarType ) == 'S' )
   {
      #if 0
      printf( "\nVariable %s is of Class: %s\n", szVarName, pVarType->szFromClass );
      #endif
      pVar->pClass = hb_compClassFind( HB_COMP_PARAM, pVarType->szFromClass );
      if( ! pVar->pClass )
      {
         hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_CLASS_NOT_FOUND, pVarType->szFromClass, szVarName );
         pVar->cType = 'O';
      }
   }

   if( HB_COMP_PARAM->iVarScope & HB_VSCOMP_PARAMETER )
      pVar->iUsed = HB_VU_INITIALIZED;

   if( HB_COMP_PARAM->iVarScope & HB_VSCOMP_MEMVAR )
   {
      PHB_HSYMBOL pSym;
      HB_USHORT wPos;

      if( HB_COMP_PARAM->fAutoMemvarAssume || HB_COMP_PARAM->iVarScope == HB_VSCOMP_MEMVAR )
      {
         /* add this variable to the list of MEMVAR variables
          */
         if( pFunc->pMemvars )
            hb_compCheckDuplVars( HB_COMP_PARAM, pFunc->pMemvars, szVarName );

         hb_compVarListAdd( &pFunc->pMemvars, pVar );
         bFreeVar = HB_FALSE;
      }

      switch( HB_COMP_PARAM->iVarScope )
      {
         case HB_VSCOMP_MEMVAR:
            /* variable declared in MEMVAR statement */
            break;

         case ( HB_VSCOMP_PARAMETER | HB_VSCOMP_PRIVATE ):
            if( ++pFunc->wParamNum > pFunc->wParamCount )
               pFunc->wParamCount = pFunc->wParamNum;

            pSym = hb_compSymbolFind( HB_COMP_PARAM, szVarName, &wPos, HB_SYM_MEMVAR ); /* check if symbol exists already */
            if( ! pSym )
               pSym = hb_compSymbolAdd( HB_COMP_PARAM, szVarName, &wPos, HB_SYM_MEMVAR );
            pSym->cScope |= HB_FS_MEMVAR;

            hb_compGenPCode4( HB_P_PARAMETER, HB_LOBYTE( wPos ), HB_HIBYTE( wPos ), HB_LOBYTE( pFunc->wParamNum ), HB_COMP_PARAM );

            if( HB_COMP_PARAM->iWarnings >= 3 && bFreeVar )
            {
               PHB_HVAR pMemVar = pFunc->pMemvars;
               while( pMemVar && strcmp( pMemVar->szName, pVar->szName ) != 0 )
                  pMemVar = pMemVar->pNext;
               /* Not declared as memvar. */
               if( pMemVar == NULL )
               {
                  /* add this variable to the list of PRIVATE variables. */
                  hb_compVarListAdd( &pFunc->pPrivates, pVar );
                  bFreeVar = HB_FALSE;
               }
            }
            if( bFreeVar )
               hb_xfree( pVar );
            break;

         case HB_VSCOMP_PRIVATE:
            pSym = hb_compSymbolFind( HB_COMP_PARAM, szVarName, &wPos, HB_SYM_MEMVAR ); /* check if symbol exists already */
            if( ! pSym )
               pSym = hb_compSymbolAdd( HB_COMP_PARAM, szVarName, &wPos, HB_SYM_MEMVAR );
            pSym->cScope |= HB_FS_MEMVAR;

            if( HB_COMP_PARAM->iWarnings >= 3 && bFreeVar )
            {
               PHB_HVAR pMemVar = pFunc->pMemvars;
               while( pMemVar && strcmp( pMemVar->szName, pVar->szName ) != 0 )
                  pMemVar = pMemVar->pNext;
               /* Not declared as memvar. */
               if( pMemVar == NULL )
               {
                  /* add this variable to the list of PRIVATE variables. */
                  hb_compVarListAdd( &pFunc->pPrivates, pVar );
                  bFreeVar = HB_FALSE;
               }
            }
            if( bFreeVar )
               hb_xfree( pVar );
            break;

         case HB_VSCOMP_PUBLIC:
            pSym = hb_compSymbolFind( HB_COMP_PARAM, szVarName, &wPos, HB_SYM_MEMVAR ); /* check if symbol exists already */
            if( ! pSym )
               pSym = hb_compSymbolAdd( HB_COMP_PARAM, szVarName, &wPos, HB_SYM_MEMVAR );
            pSym->cScope |= HB_FS_MEMVAR;
            if( bFreeVar )
               hb_xfree( pVar );
            break;
      }
   }
   else
   {
      switch( HB_COMP_PARAM->iVarScope )
      {
         case HB_VSCOMP_LOCAL:
         case HB_VSCOMP_PARAMETER:
         {
            HB_USHORT wLocal = hb_compVarListAdd( &pFunc->pLocals, pVar );

            if( HB_COMP_PARAM->iVarScope == HB_VSCOMP_PARAMETER )
            {
               ++pFunc->wParamCount;
               pFunc->funFlags |= HB_FUNF_USES_LOCAL_PARAMS;
            }
            if( HB_COMP_PARAM->fDebugInfo )
            {
               hb_compGenPCode3( HB_P_LOCALNAME, HB_LOBYTE( wLocal ), HB_HIBYTE( wLocal ), HB_COMP_PARAM );
               hb_compGenPCodeN( ( const HB_BYTE * ) szVarName, strlen( szVarName ) + 1, HB_COMP_PARAM );
            }
            break;
         }

         case HB_VSCOMP_TH_STATIC:
            pVar->uiFlags = HB_VSCOMP_THREAD;
            /* fallthrough */
         case HB_VSCOMP_STATIC:
            ++HB_COMP_PARAM->iStaticCnt;
            hb_compVarListAdd( &pFunc->pStatics, pVar );
            break;

         case HB_VSCOMP_FIELD:
            hb_compVarListAdd( &pFunc->pFields, pVar );
            break;
      }
   }
}

/* Set the name of an alias for the list of previously declared FIELDs
 *
 * szAlias -> name of the alias
 * iField  -> position of the first FIELD name to change
 */
void hb_compFieldSetAlias( HB_COMP_DECL, const char * szAlias, int iField )
{
   PHB_HVAR pVar;

   pVar = HB_COMP_PARAM->functions.pLast->pFields;
   while( iField-- && pVar )
      pVar = pVar->pNext;

   while( pVar )
   {
      pVar->szAlias = szAlias;
      pVar = pVar->pNext;
   }
}

/* This functions counts the number of FIELD declaration in a function
 * We will required this information in hb_compFieldSetAlias function
 */
int hb_compFieldsCount( HB_COMP_DECL )
{
   int iFields = 0;
   PHB_HVAR pVar = HB_COMP_PARAM->functions.pLast->pFields;

   while( pVar )
   {
      ++iFields;
      pVar = pVar->pNext;
   }

   return iFields;
}

static PHB_HVAR hb_compVariableGet( PHB_HVAR pVars, const char * szVarName, int * piPos )
{
   int iVar = 1;

   while( pVars )
   {
      if( pVars->szName && ! strcmp( pVars->szName, szVarName ) )
      {
         pVars->iUsed |= HB_VU_USED;
         *piPos = iVar;
         return pVars;
      }
      pVars = pVars->pNext;
      ++iVar;
   }
   return NULL;
}

/* returns variable pointer if defined or NULL */
static PHB_HVAR hb_compVariableGetVar( PHB_HVAR pVars, HB_USHORT wOrder )
{
   while( pVars && --wOrder )
      pVars = pVars->pNext;
   return pVars;
}

/* returns the order + 1 of a variable if defined or zero */
static HB_USHORT hb_compVariableGetPos( PHB_HVAR pVars, const char * szVarName )
{
   HB_USHORT wVar = 1;

   while( pVars )
   {
      if( pVars->szName && ! strcmp( pVars->szName, szVarName ) )
      {
         pVars->iUsed |= HB_VU_USED;
         return wVar;
      }
      pVars = pVars->pNext;
      ++wVar;
   }
   return 0;
}

PHB_HVAR hb_compVariableFind( HB_COMP_DECL, const char * szVarName, int * piPos, int * piScope )
{
   PHB_HFUNC pFunc, pGlobal, pOutBlock = NULL;
   HB_BOOL fStatic = HB_FALSE, fBlock = HB_FALSE, fGlobal = HB_FALSE;
   PHB_HVAR pVar = NULL;
   int iPos = 0, iScope = 0, iLevel = 0;

   if( piPos )
      *piPos = 0;
   else
      piPos = &iPos;
   if( piScope )
      *piScope = HB_VS_UNDECLARED;
   else
      piScope = &iScope;

   /* check current function/codeblock variables */
   pFunc = HB_COMP_PARAM->functions.pLast;
   pGlobal = ( HB_COMP_PARAM->pDeclFunc &&
               HB_COMP_PARAM->pDeclFunc != pFunc &&
               ( HB_COMP_PARAM->pDeclFunc->funFlags & HB_FUNF_FILE_DECL ) )
             ? HB_COMP_PARAM->pDeclFunc : NULL;

   while( pFunc )
   {
      if( ( pFunc->cScope & HB_FS_INITEXIT ) == HB_FS_INITEXIT )
      {
         /* static initialization function */
         fStatic = HB_TRUE;
      }
      else if( pFunc->szName )
      {
         /* normal function/procedure */
         /* check local parameters */
         pVar = hb_compVariableGet( pFunc->pLocals, szVarName, piPos );
         if( pVar )
         {
            *piScope = HB_VS_LOCAL_VAR;
            if( fStatic )
            {
               /* local variable was referenced in a codeblock during
                * initialization of static variable. This cannot be supported
                * because static variables are initialized at program
                * startup when there is no local variables yet - hence we
                * cannot detach this local variable
                * For example:
                * LOCAL locvar
                * STATIC stavar := {| x | locvar }
                *
                * NOTE: Clipper creates such a codeblock however at the
                * time of codeblock evaluation it generates a runtime error:
                * 'bound error: array access'
                * Called from: (b)STATICS$(0)
                */
               hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_ILLEGAL_INIT, "(b)", szVarName );
            }
            else if( fBlock && HB_COMP_PARAM->functions.pLast->iEarlyEvalPass < 2 )
            {
               /* We want to access a local variable defined in a function
                * that owns this codeblock. We cannot access this variable in
                * a normal way because at runtime the stack base will point
                * to local variables of EVAL function.
                */
               /* NOTE: The list of local variables defined in a function
                * and referenced in a codeblock will be stored in a outer
                * codeblock only. This makes sure that all variables will be
                * detached properly - the inner codeblock can be created
                * outside of a function where it was defined when the local
                * variables are not accessible.
                */
               *piPos = - hb_compVariableGetPos( pOutBlock->pDetached, szVarName );
               if( *piPos == 0 )
               {
                  /* szVarName may point to dynamic buffer,
                   * make sure it's static one.
                   */
                  szVarName = pVar->szName;

                  /* this variable was not referenced yet - add it to the list */
                  pVar = ( PHB_HVAR ) hb_xgrab( sizeof( HB_HVAR ) );

                  pVar->szName = szVarName;
                  pVar->szAlias = NULL;
                  pVar->cType = ' ';
                  pVar->iUsed = HB_VU_NOT_USED;
                  pVar->pNext  = NULL;
                  pVar->iDeclLine = HB_COMP_PARAM->currLine;
                  /* Use negative order to signal that we are accessing a local
                   * variable from a codeblock
                   */
                  *piPos = - hb_compVarListAdd( &pOutBlock->pDetached, pVar );
               }
               *piScope = HB_VS_CBLOCAL_VAR;
            }
         }
         else
         {
            /* check static variables */
            pVar = hb_compVariableGet( pFunc->pStatics, szVarName, piPos );
            if( pVar )
            {
               *piScope = HB_VS_STATIC_VAR;
               *piPos += pFunc->iStaticsBase;
            }
            else
            {
               /* check FIELDs */
               pVar = hb_compVariableGet( pFunc->pFields, szVarName, piPos );
               if( pVar )
                  *piScope = HB_VS_LOCAL_FIELD;
               else
               {
                  /* check MEMVARs */
                  pVar = hb_compVariableGet( pFunc->pMemvars, szVarName, piPos );
                  if( pVar )
                     *piScope = HB_VS_LOCAL_MEMVAR;
               }
            }
         }
      }
      else
      {
         /* codeblock */
         fBlock = HB_TRUE;
         /* check local parameters */
         pVar = hb_compVariableGet( pFunc->pLocals, szVarName, piPos );
         if( pVar )
         {
            *piScope = HB_VS_LOCAL_VAR;
            if( iLevel )
            {
               /* this variable is defined in a parent codeblock
                * It is not possible to access a parameter of a codeblock
                * in which the current codeblock is defined
                */
               hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_OUTER_VAR, szVarName, NULL );
            }
         }
         else if( pFunc->funFlags & HB_FUNF_EXTBLOCK )
         {
            /* extended codeblock */
            /* check static variables */
            pVar = hb_compVariableGet( pFunc->pStatics, szVarName, piPos );
            if( pVar )
            {
               *piScope = HB_VS_STATIC_VAR;
               *piPos += pFunc->iStaticsBase;
            }
            else
            {
               /* check FIELDs */
               pVar = hb_compVariableGet( pFunc->pFields, szVarName, piPos );
               if( pVar )
                  *piScope = HB_VS_LOCAL_FIELD;
               else
               {
                  /* check MEMVARs */
                  pVar = hb_compVariableGet( pFunc->pMemvars, szVarName, piPos );
                  if( pVar )
                     *piScope = HB_VS_LOCAL_MEMVAR;
               }
            }
         }
      }

      if( pVar )
         break;

      pOutBlock = pFunc;
      pFunc = pFunc->pOwner;
      if( ! pFunc && ! fGlobal )
      {
         /* instead of making this trick with pGlobal switching it will be
          * much cleaner to set pOwner in each compiled function to first
          * global pseudo function created when -n compiler switch is used
          * [druzus]
          */
         pFunc = pGlobal;
         fGlobal = HB_TRUE;
      }
      ++iLevel;
   }

   if( pVar && fGlobal )
      *piScope |= HB_VS_FILEWIDE;

   return pVar;
}

/* return local variable name using its order after final fixing */
const char * hb_compLocalVariableName( PHB_HFUNC pFunc, HB_USHORT wVar )
{
   PHB_HVAR pVar;

   if( pFunc->wParamCount && ! ( pFunc->funFlags & HB_FUNF_USES_LOCAL_PARAMS ) )
      wVar -= pFunc->wParamCount;
   pVar = hb_compVariableGetVar( pFunc->pLocals, wVar );

   return pVar ? pVar->szName : NULL;
}

const char * hb_compStaticVariableName( HB_COMP_DECL, HB_USHORT wVar )
{
   PHB_HVAR pVar;
   PHB_HFUNC pTmp = HB_COMP_PARAM->functions.pFirst;

   while( pTmp->pNext && pTmp->pNext->iStaticsBase < wVar )
      pTmp = pTmp->pNext;
   pVar = hb_compVariableGetVar( pTmp->pStatics, ( HB_USHORT ) ( wVar - pTmp->iStaticsBase ) );

   return pVar ? pVar->szName : NULL;
}

static int hb_compVariableScope( HB_COMP_DECL, const char * szVarName )
{
   int iScope;

   hb_compVariableFind( HB_COMP_PARAM, szVarName, NULL, &iScope );

   return iScope;
}

void hb_compPushMacroVar( HB_COMP_DECL, const char * szVarName )
{
   /* save and restore iEarlyEvalPass to not disable early
      evaluation when only macrovar and/or macrotext is used */
   int iEarlyEvalPass = HB_COMP_PARAM->functions.pLast->iEarlyEvalPass;

   hb_compGenPushVar( szVarName, HB_COMP_PARAM );

   HB_COMP_PARAM->functions.pLast->iEarlyEvalPass = iEarlyEvalPass;
}

void hb_compPushMacroText( HB_COMP_DECL, const char * szText, HB_SIZE nLen, HB_BOOL fMacro )
{
   int iEarlyEvalPass = HB_COMP_PARAM->functions.pLast->iEarlyEvalPass;
   HB_BOOL fFound = HB_FALSE;
   HB_SIZE n = 0;
   int iParts = 0;

   while( n < nLen )
   {
      if( szText[ n++ ] == '&' )
      {
         char szSymName[ HB_SYMBOL_NAME_LEN + 1 ];
         int iSize = 0;

         /* Check if macro operator is used inside a string
          * Macro operator is ignored if it is the last char or
          * next char is '(' e.g. "this is &(ignored)"
          * (except if strict Clipper compatibility mode is enabled)
          *
          * NOTE: This uses _a-zA-Z pattern to check for
          * beginning of a variable name
          */

         while( n < nLen && iSize < HB_SYMBOL_NAME_LEN )
         {
            char ch = szText[ n ];
            if( ch >= 'a' && ch <= 'z' )
               szSymName[ iSize++ ] = ch - ( 'a' - 'A' );
            else if( ch == '_' || ( ch >= 'A' && ch <= 'Z' ) ||
                     ( iSize > 0 && ch >= '0' && ch <= '9' ) )
               szSymName[ iSize++ ] = ch;
            else
               break;
            ++n;
         }

         if( iSize )
         {
            int iScope;

            szSymName[ iSize ] = '\0';

            /* NOTE: All variables are assumed memvars in macro compiler -
             * there is no need to check for a valid name but to be Clipper
             * compatible we should check if macrotext variable does not refer
             * to local, static or field and generate error in such case.
             * Only MEMVAR or undeclared (memvar will be assumed)
             * variables can be used in macro text.
             */
            iScope = hb_compVariableScope( HB_COMP_PARAM, szSymName );
            if( iScope == HB_VS_UNDECLARED || ( iScope & HB_VS_LOCAL_MEMVAR ) )
            {
               fFound = HB_TRUE;
               if( fMacro && iScope == HB_VS_UNDECLARED /* && HB_SUPPORT_MACRODECL */ )
                  hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_AMBIGUOUS_VAR, szSymName, NULL );
            }
            else if( HB_SUPPORT_MACRODECL )
            {
               HB_SIZE nPrefix = n - iSize - 1;
               if( nPrefix > 0 )
               {
                  char * pszPrefix = ( char * ) hb_xgrab( nPrefix + 1 );
                  memcpy( pszPrefix, szText, nPrefix );
                  pszPrefix[ nPrefix ] = '\0';
                  hb_compGenPushString( pszPrefix, nPrefix + 1, HB_COMP_PARAM );
                  hb_xfree( pszPrefix );
                  if( iParts++ > 0 )
                     hb_compGenPCode1( HB_P_PLUS, HB_COMP_PARAM );
               }
               hb_compGenPushVar( szSymName, HB_COMP_PARAM );
               if( iParts++ > 0 )
                  hb_compGenPCode1( HB_P_PLUS, HB_COMP_PARAM );
               if( n < nLen && szText[ n ] == '.' )
                  ++n;
               szText += n;
               nLen -= n;
               n = 0;
            }
            else
            {
               hb_compErrorMacro( HB_COMP_PARAM, szText );
               break;
            }
         }
         else if( ! HB_SUPPORT_HARBOUR )
            fFound = HB_TRUE;    /* always macro substitution in Clipper */
      }
   }

   if( nLen > 0 || iParts == 0 )
   {
      hb_compGenPushString( szText, nLen + 1, HB_COMP_PARAM );
      if( iParts > 0 )
         hb_compGenPCode1( HB_P_PLUS, HB_COMP_PARAM );
   }

   if( fFound )
      hb_compGenPCode1( HB_P_MACROTEXT, HB_COMP_PARAM );

   HB_COMP_PARAM->functions.pLast->iEarlyEvalPass = iEarlyEvalPass;
}



/*
 * DECLARATIONS
 */

static void hb_compDeclaredReset( HB_COMP_DECL )
{
   while( HB_COMP_PARAM->pFirstDeclared )
   {
      PHB_HDECLARED pDeclared = HB_COMP_PARAM->pFirstDeclared;
      HB_COMP_PARAM->pFirstDeclared = pDeclared->pNext;
      if( pDeclared->cParamTypes )
         hb_xfree( pDeclared->cParamTypes );
      if( pDeclared->pParamClasses )
         hb_xfree( pDeclared->pParamClasses );
      hb_xfree( pDeclared );
   }
   HB_COMP_PARAM->pLastDeclared = NULL;

   while( HB_COMP_PARAM->pFirstClass )
   {
      PHB_HCLASS pClass = HB_COMP_PARAM->pFirstClass;
      HB_COMP_PARAM->pFirstClass = pClass->pNext;
      while( pClass->pMethod )
      {
         PHB_HDECLARED pDeclared = pClass->pMethod;
         pClass->pMethod = pDeclared->pNext;
         if( pDeclared->cParamTypes )
            hb_xfree( pDeclared->cParamTypes );
         if( pDeclared->pParamClasses )
            hb_xfree( pDeclared->pParamClasses );
         hb_xfree( pDeclared );
      }
      hb_xfree( pClass );
   }
   HB_COMP_PARAM->pLastClass = NULL;
   HB_COMP_PARAM->pLastMethod = NULL;
}

PHB_HCLASS hb_compClassFind( HB_COMP_DECL, const char * szClassName )
{
   PHB_HCLASS pClass = HB_COMP_PARAM->pFirstClass;

   if( HB_COMP_PARAM->iWarnings < 3 )
      return NULL;

   while( pClass )
   {
      if( ! strcmp( pClass->szName, szClassName ) )
         return pClass;
      pClass = pClass->pNext;
   }
   return NULL;
}

PHB_HCLASS hb_compClassAdd( HB_COMP_DECL, const char * szClassName, const char * szClassFunc )
{
   PHB_HCLASS pClass;
   PHB_HDECLARED pDeclared;

   #if 0
   printf( "Declaring Class: %s\n", szClassName );
   #endif

   if( HB_COMP_PARAM->iWarnings < 3 )
      return NULL;

   if( ( pClass = hb_compClassFind( HB_COMP_PARAM, szClassName ) ) != NULL )
   {
      hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_DUP_DECLARATION, "class", szClassName );
      return pClass;
   }

   pClass = ( PHB_HCLASS ) hb_xgrab( sizeof( HB_HCLASS ) );

   pClass->szName = szClassName;
   pClass->pMethod = NULL;
   pClass->pNext = NULL;

   if( HB_COMP_PARAM->pFirstClass == NULL )
      HB_COMP_PARAM->pFirstClass = pClass;
   else
      HB_COMP_PARAM->pLastClass->pNext = pClass;

   HB_COMP_PARAM->pLastClass = pClass;

   /* Auto declaration for the Class Function. */
   pDeclared = hb_compDeclaredAdd( HB_COMP_PARAM, szClassFunc ? szClassFunc : szClassName );
   pDeclared->cType = 'S';
   pDeclared->pClass = pClass;

   return pClass;
}

PHB_HDECLARED hb_compMethodFind( PHB_HCLASS pClass, const char * szMethodName )
{
   if( pClass )
   {
      PHB_HDECLARED pMethod = pClass->pMethod;

      while( pMethod )
      {
         if( ! strcmp( pMethod->szName, szMethodName ) )
            return pMethod;
         pMethod = pMethod->pNext;
      }
   }

   return NULL;
}

PHB_HDECLARED hb_compMethodAdd( HB_COMP_DECL, PHB_HCLASS pClass, const char * szMethodName )
{
   PHB_HDECLARED pMethod;

   if( HB_COMP_PARAM->iWarnings < 3 )
      return NULL;

   if( ! pClass )
   {
      char buffer[ 80 ];
      hb_snprintf( buffer, sizeof( buffer ),
                   "Class member '%s' declaration without class definition.\n", szMethodName );
      hb_compOutErr( HB_COMP_PARAM, buffer );
      HB_COMP_PARAM->iErrorCount++;
      HB_COMP_PARAM->fError = HB_TRUE;
      return NULL;
   }

   #if 0
   printf( "\nDeclaring Method: %s of Class: %s Pointer: %li\n", szMethodName, pClass->szName, pClass );
   #endif

   if( ( pMethod = hb_compMethodFind( pClass, szMethodName ) ) != NULL )
   {
      hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_DUP_DECLARATION, "method", szMethodName );

      /* Last Declaration override previous declarations */
      pMethod->iParamCount = 0;
      if( pMethod->cParamTypes )
         hb_xfree( pMethod->cParamTypes );
      pMethod->cParamTypes = NULL;
      if( pMethod->pParamClasses )
         hb_xfree( pMethod->pParamClasses );
      pMethod->pParamClasses = NULL;

      return pMethod;
   }

   pMethod = ( PHB_HDECLARED ) hb_xgrab( sizeof( HB_HDECLARED ) );

   pMethod->szName = szMethodName;
   pMethod->cType = ' '; /* Not known yet */
   pMethod->cParamTypes = NULL;
   pMethod->iParamCount = 0;
   pMethod->pParamClasses = NULL;
   pMethod->pNext = NULL;

   if( pClass->pMethod == NULL )
      pClass->pMethod = pMethod;
   else
      pClass->pLastMethod->pNext = pMethod;

   pClass->pLastMethod = pMethod;

   HB_COMP_PARAM->pLastMethod = pMethod;

   return pMethod;
}

/* returns a symbol pointer from the symbol table
 * and sets its position in the symbol table.
 * NOTE: symbol's position number starts from 0
 */
static PHB_HDECLARED hb_compDeclaredFind( HB_COMP_DECL, const char * szDeclaredName )
{
   PHB_HDECLARED pSym = HB_COMP_PARAM->pFirstDeclared;

   while( pSym )
   {
      if( ! strcmp( pSym->szName, szDeclaredName ) )
         return pSym;
      pSym = pSym->pNext;
   }
   return NULL;
}

PHB_HDECLARED hb_compDeclaredAdd( HB_COMP_DECL, const char * szDeclaredName )
{
   PHB_HDECLARED pDeclared;

   if( HB_COMP_PARAM->iWarnings < 3 )
      return NULL;

   #if 0
   printf( "\nDeclaring Function: %s\n", szDeclaredName, NULL );
   #endif

   if( ( pDeclared = hb_compDeclaredFind( HB_COMP_PARAM, szDeclaredName ) ) != NULL )
   {
      hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_DUP_DECLARATION, "function", szDeclaredName );

      /* Last declaration will take effect. */
      pDeclared->cType = ' '; /* Not known yet */
      pDeclared->iParamCount = 0;
      if( pDeclared->cParamTypes )
         hb_xfree( pDeclared->cParamTypes );
      pDeclared->cParamTypes = NULL;
      if( pDeclared->pParamClasses )
         hb_xfree( pDeclared->pParamClasses );
      pDeclared->pParamClasses = NULL;

      return pDeclared;
   }

   pDeclared = ( PHB_HDECLARED ) hb_xgrab( sizeof( HB_HDECLARED ) );

   pDeclared->szName = szDeclaredName;
   pDeclared->cType = ' '; /* Not known yet */
   pDeclared->cParamTypes = NULL;
   pDeclared->iParamCount = 0;
   pDeclared->pParamClasses = NULL;
   pDeclared->pNext = NULL;

   if( HB_COMP_PARAM->pFirstDeclared == NULL )
      HB_COMP_PARAM->pFirstDeclared = pDeclared;
   else
      HB_COMP_PARAM->pLastDeclared->pNext = pDeclared;

   HB_COMP_PARAM->pLastDeclared = pDeclared;

   return pDeclared;
}

void hb_compDeclaredParameterAdd( HB_COMP_DECL, const char * szVarName, PHB_VARTYPE pVarType )
{
   /* Nothing to do since no warnings requested.*/
   if( HB_COMP_PARAM->iWarnings < 3 )
   {
      HB_SYMBOL_UNUSED( szVarName );
      return;
   }

   /* Either a Declared Function Parameter or a Declared Method Parameter. */
   if( HB_COMP_PARAM->szDeclaredFun )
   {
      /* Find the Declared Function owner of this parameter. */
      PHB_HDECLARED pDeclared = hb_compDeclaredFind( HB_COMP_PARAM, HB_COMP_PARAM->szDeclaredFun );

      if( pDeclared )
      {
         pDeclared->iParamCount++;

         if( pDeclared->cParamTypes )
         {
            pDeclared->cParamTypes = ( HB_BYTE * ) hb_xrealloc( pDeclared->cParamTypes, pDeclared->iParamCount );
            pDeclared->pParamClasses = ( PHB_HCLASS * ) hb_xrealloc( pDeclared->pParamClasses, pDeclared->iParamCount * sizeof( PHB_HCLASS ) );
         }
         else
         {
            pDeclared->cParamTypes = ( HB_BYTE * ) hb_xgrab( 1 );
            pDeclared->pParamClasses = ( PHB_HCLASS * ) hb_xgrab( sizeof( PHB_HCLASS ) );
         }

         pDeclared->cParamTypes[ pDeclared->iParamCount - 1 ] = pVarType->cVarType;

         if( HB_TOUPPER( pVarType->cVarType ) == 'S' )
         {
            pDeclared->pParamClasses[ pDeclared->iParamCount - 1 ] = hb_compClassFind( HB_COMP_PARAM, pVarType->szFromClass );
         }
      }
   }
   else if( ! HB_COMP_PARAM->pLastMethod )
   {
      char buffer[ 80 ];
      hb_snprintf( buffer, sizeof( buffer ),
                   "Message parameter '%s' declaration without class/message definition.\n", szVarName );
      hb_compOutErr( HB_COMP_PARAM, buffer );
      HB_COMP_PARAM->iErrorCount++;
      HB_COMP_PARAM->fError = HB_TRUE;
   }
   else /* Declared Method Parameter */
   {
      #if 0
      printf( "\nAdding parameter: %s Type: %c In Method: %s Class: %s FROM CLASS: %s\n", szVarName, pVarType->cVarType, HB_COMP_PARAM->pLastMethod->szName, HB_COMP_PARAM->pLastClass->szName, pVarType->szFromClass );
      #endif

      HB_COMP_PARAM->pLastMethod->iParamCount++;

      if( HB_COMP_PARAM->pLastMethod->cParamTypes )
      {
         HB_COMP_PARAM->pLastMethod->cParamTypes = ( HB_BYTE * ) hb_xrealloc( HB_COMP_PARAM->pLastMethod->cParamTypes, HB_COMP_PARAM->pLastMethod->iParamCount );
         HB_COMP_PARAM->pLastMethod->pParamClasses = ( PHB_HCLASS * ) hb_xrealloc( HB_COMP_PARAM->pLastMethod->pParamClasses, HB_COMP_PARAM->pLastMethod->iParamCount * sizeof( HB_HCLASS ) );
      }
      else
      {
         HB_COMP_PARAM->pLastMethod->cParamTypes = ( HB_BYTE * ) hb_xgrab( 1 );
         HB_COMP_PARAM->pLastMethod->pParamClasses = ( PHB_HCLASS * ) hb_xgrab( sizeof( HB_HCLASS ) );
      }

      HB_COMP_PARAM->pLastMethod->cParamTypes[ HB_COMP_PARAM->pLastMethod->iParamCount - 1 ] = pVarType->cVarType;

      if( HB_TOUPPER( pVarType->cVarType ) == 'S' )
      {
         HB_COMP_PARAM->pLastMethod->pParamClasses[ HB_COMP_PARAM->pLastMethod->iParamCount - 1 ] = hb_compClassFind( HB_COMP_PARAM, pVarType->szFromClass );

         #if 0
         printf( "\nParameter: %s FROM CLASS: %s\n", szVarName, HB_COMP_PARAM->pLastMethod->pParamClasses[ HB_COMP_PARAM->pLastMethod->iParamCount - 1 ]->szName );
         #endif
      }
   }
}

PHB_VARTYPE hb_compVarTypeNew( HB_COMP_DECL, HB_BYTE cVarType, const char* szFromClass )
{
   PHB_VARTYPE   pVT = HB_COMP_PARAM->pVarType;
   PHB_VARTYPE*  ppVT = &( HB_COMP_PARAM->pVarType );

   while( pVT )
   {
      if( pVT->cVarType == cVarType &&
          ( ( ! pVT->szFromClass && ! szFromClass ) ||
            ( pVT->szFromClass && szFromClass && ! strcmp( pVT->szFromClass, szFromClass ) ) ) )
         return pVT;

      ppVT = &pVT->pNext;
      pVT = pVT->pNext;
   }

   /* Add to the end of list. I hope it will help the most usual type (' ', NULL)
      to be in the beginning of the list, and it will be found faster. [Mindaugas] */
   pVT = ( PHB_VARTYPE ) hb_xgrab( sizeof( HB_VARTYPE ) );
   pVT->pNext = NULL;
   pVT->cVarType = cVarType;
   pVT->szFromClass = szFromClass;
   *ppVT = pVT;
   return pVT;
}


/*
 * Functions
 */

static int hb_compSort_HB_SIZE( const void * pLeft, const void * pRight )
{
   HB_SIZE nLeft  = *( ( const HB_SIZE * ) ( pLeft ) );
   HB_SIZE nRight = *( ( const HB_SIZE * ) ( pRight ) );

   if( nLeft == nRight )
      return 0;
   else if( nLeft < nRight )
      return -1;
   else
      return 1;
}

/* Jump Optimizer and dummy code eliminator */
static void hb_compOptimizeJumps( HB_COMP_DECL )
{
   HB_BYTE * pCode = HB_COMP_PARAM->functions.pLast->pCode;
   HB_SIZE * pNOOPs, * pJumps;
   HB_SIZE nOptimized, nNextByte, nBytes2Copy, nJumpAddr, nNOOP, nJump;
   HB_BOOL fLineStrip = HB_COMP_PARAM->fLineNumbers;
   int iPass;

   if( ! HB_COMP_ISSUPPORTED( HB_COMPFLAG_OPTJUMP ) )
      return;

   hb_compOptimizePCode( HB_COMP_PARAM, HB_COMP_PARAM->functions.pLast );
   hb_compCodeTraceMarkDead( HB_COMP_PARAM, HB_COMP_PARAM->functions.pLast );

   for( iPass = 0; iPass < 4 && ! HB_COMP_PARAM->fExit; ++iPass )
   {
      HB_ISIZ nOffset;

      if( iPass == 3 && fLineStrip )
      {
         hb_compStripFuncLines( HB_COMP_PARAM, HB_COMP_PARAM->functions.pLast );
         fLineStrip = HB_FALSE;
      }

      if( HB_COMP_PARAM->functions.pLast->nJumps > 0 )
      {
         pJumps = HB_COMP_PARAM->functions.pLast->pJumps;
         nJump = HB_COMP_PARAM->functions.pLast->nJumps - 1;

         do
         {
            nJumpAddr = pJumps[ nJump ];

            /*
             * optimize existing jumps, it will be good to also join
             * unconditional jump chain calculating total jump offset but
             * it will be necessary to add some code to protect against
             * infinite loop which will appear when we add optimization
             * for the PCODE sequences like:
             *
             *    HB_P_{FALSE|TRUE},
             * [ no jump targets or stack modification here ]
             *    HB_P_JUMP{FALSE|TRUE}*,
             *
             * I'll think about something like that later, [druzus]
             */
            switch( pCode[ nJumpAddr ] )
            {
               case HB_P_JUMPNEAR:
                  if( ( signed char ) pCode[ nJumpAddr + 1 ] == 2 )
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr, 2, HB_FALSE, HB_FALSE );
                  break;

               case HB_P_JUMPFALSENEAR:
               case HB_P_JUMPTRUENEAR:
                  if( ( signed char ) pCode[ nJumpAddr + 1 ] == 2 )
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr, 2, HB_TRUE, HB_FALSE );
                  break;

               case HB_P_JUMP:
                  nOffset = HB_PCODE_MKSHORT( &pCode[ nJumpAddr + 1 ] );
                  if( nOffset == 3 )
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr, 3, HB_FALSE, HB_FALSE );
                  else if( HB_LIM_INT8( nOffset ) )
                  {
                     pCode[ nJumpAddr ] = HB_P_JUMPNEAR;
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr + 2, 1, HB_FALSE, HB_FALSE );
                  }
                  break;

               case HB_P_JUMPFALSE:
                  nOffset = HB_PCODE_MKSHORT( &pCode[ nJumpAddr + 1 ] );
                  if( nOffset == 3 )
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr, 3, HB_TRUE, HB_FALSE );
                  else if( HB_LIM_INT8( nOffset ) )
                  {
                     pCode[ nJumpAddr ] = HB_P_JUMPFALSENEAR;
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr + 2, 1, HB_FALSE, HB_FALSE );
                  }
                  break;

               case HB_P_JUMPTRUE:
                  nOffset = HB_PCODE_MKSHORT( &pCode[ nJumpAddr + 1 ] );
                  if( nOffset == 3 )
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr, 3, HB_TRUE, HB_FALSE );
                  else if( HB_LIM_INT8( nOffset ) )
                  {
                     pCode[ nJumpAddr ] = HB_P_JUMPTRUENEAR;
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr + 2, 1, HB_FALSE, HB_FALSE );
                  }
                  break;

               case HB_P_JUMPFAR:
                  nOffset = HB_PCODE_MKINT24( &pCode[ nJumpAddr + 1 ] );
                  if( nOffset == 4 )
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr, 4, HB_FALSE, HB_FALSE );
                  else if( iPass > 0 && HB_LIM_INT16( nOffset ) )
                  {
                     if( HB_LIM_INT8( nOffset ) )
                     {
                        pCode[ nJumpAddr ] = HB_P_JUMPNEAR;
                        hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr + 2, 2, HB_FALSE, HB_FALSE );
                     }
                     else
                     {
                        pCode[ nJumpAddr ] = HB_P_JUMP;
                        hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr + 3, 1, HB_FALSE, HB_FALSE );
                     }
                  }
                  break;

               case HB_P_JUMPFALSEFAR:
                  nOffset = HB_PCODE_MKINT24( &pCode[ nJumpAddr + 1 ] );
                  if( nOffset == 4 )
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr, 4, HB_TRUE, HB_FALSE );
                  else if( iPass > 0 && HB_LIM_INT16( nOffset ) )
                  {
                     if( HB_LIM_INT8( nOffset ) )
                     {
                        pCode[ nJumpAddr ] = HB_P_JUMPFALSENEAR;
                        hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr + 2, 2, HB_FALSE, HB_FALSE );
                     }
                     else
                     {
                        pCode[ nJumpAddr ] = HB_P_JUMPFALSE;
                        hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr + 3, 1, HB_FALSE, HB_FALSE );
                     }
                  }
                  break;

               case HB_P_JUMPTRUEFAR:
                  nOffset = HB_PCODE_MKINT24( &pCode[ nJumpAddr + 1 ] );
                  if( nOffset == 4 )
                     hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr, 4, HB_TRUE, HB_FALSE );
                  else if( iPass > 0 && HB_LIM_INT16( nOffset ) )
                  {
                     if( HB_LIM_INT8( nOffset ) )
                     {
                        pCode[ nJumpAddr ] = HB_P_JUMPTRUENEAR;
                        hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr + 2, 2, HB_FALSE, HB_FALSE );
                     }
                     else
                     {
                        pCode[ nJumpAddr ] = HB_P_JUMPTRUE;
                        hb_compNOOPfill( HB_COMP_PARAM->functions.pLast, nJumpAddr + 3, 1, HB_FALSE, HB_FALSE );
                     }
                  }
                  break;
            }

            /* remove dummy jumps (over dead code) */
            if( pCode[ nJumpAddr ] == HB_P_NOOP ||
                pCode[ nJumpAddr ] == HB_P_POP )
            {
               if( HB_COMP_PARAM->functions.pLast->nJumps > nJump + 1 )
                  memmove( &pJumps[ nJump ], &pJumps[ nJump + 1 ],
                           ( HB_COMP_PARAM->functions.pLast->nJumps - nJump - 1 ) *
                           sizeof( HB_SIZE ) );
               HB_COMP_PARAM->functions.pLast->nJumps--;
            }
         }
         while( nJump-- );

         if( HB_COMP_PARAM->functions.pLast->nJumps == 0 )
         {
            hb_xfree( HB_COMP_PARAM->functions.pLast->pJumps );
            HB_COMP_PARAM->functions.pLast->pJumps = NULL;
         }
      }

      if( HB_COMP_PARAM->functions.pLast->nNOOPs == 0 )
      {
         if( iPass == 0 )
            continue;
         if( fLineStrip )
            hb_compStripFuncLines( HB_COMP_PARAM, HB_COMP_PARAM->functions.pLast );
         if( HB_COMP_PARAM->functions.pLast->nNOOPs == 0 )
            return;
      }

      pNOOPs = HB_COMP_PARAM->functions.pLast->pNOOPs;

      /* Needed so the pasting of PCODE pieces below will work correctly */
      qsort( ( void * ) pNOOPs, HB_COMP_PARAM->functions.pLast->nNOOPs, sizeof( HB_SIZE ), hb_compSort_HB_SIZE );

      if( HB_COMP_PARAM->functions.pLast->nJumps )
      {
         HB_ISIZ * plSizes, * plShifts;
         HB_SIZE nSize;

         pJumps = HB_COMP_PARAM->functions.pLast->pJumps;
         nSize = sizeof( HB_ISIZ ) * HB_COMP_PARAM->functions.pLast->nJumps;
         plSizes = ( HB_ISIZ * ) hb_xgrab( nSize );
         plShifts = ( HB_ISIZ * ) hb_xgrab( nSize );

         for( nJump = 0; nJump < HB_COMP_PARAM->functions.pLast->nJumps; nJump++ )
            plSizes[ nJump ] = plShifts[ nJump ] = 0;

         /* First Scan NOOPS - Adjust Jump addresses. */
         for( nNOOP = 0; nNOOP < HB_COMP_PARAM->functions.pLast->nNOOPs; nNOOP++ )
         {
            /* Adjusting preceding jumps that point to code beyond the current NOOP
               or trailing backward jumps pointing to lower address. */
            for( nJump = 0; nJump < HB_COMP_PARAM->functions.pLast->nJumps; nJump++ )
            {
               nJumpAddr = pJumps[ nJump ];
               switch( pCode[ nJumpAddr ] )
               {
                  case HB_P_JUMPNEAR:
                  case HB_P_JUMPFALSENEAR:
                  case HB_P_JUMPTRUENEAR:
                     nOffset = ( signed char ) pCode[ nJumpAddr + 1 ];
                     break;

                  case HB_P_JUMP:
                  case HB_P_JUMPFALSE:
                  case HB_P_JUMPTRUE:
                     nOffset = HB_PCODE_MKSHORT( &pCode[ nJumpAddr + 1 ] );
                     break;

                  case HB_P_JUMPFAR:
                  case HB_P_JUMPTRUEFAR:
                  case HB_P_JUMPFALSEFAR:
                  case HB_P_ALWAYSBEGIN:
                  case HB_P_SEQALWAYS:
                  case HB_P_SEQBEGIN:
                  case HB_P_SEQEND:
                     nOffset = HB_PCODE_MKINT24( &pCode[ nJumpAddr + 1 ] );
                     break;

                  default:
                     hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'F', HB_COMP_ERR_JUMP_NOT_FOUND, NULL, NULL );
                     continue;
               }

               /* update jump size */
               if( nOffset > 0 ) /* forward (positive) jump */
               {
                  /* Only if points to code beyond the current fix. */
                  if( pNOOPs[ nNOOP ] > nJumpAddr &&
                      pNOOPs[ nNOOP ] < ( HB_SIZE ) ( nJumpAddr + nOffset ) )
                     plSizes[ nJump ]--;
               }
               else /* if( nOffset < 0 ) - backward (negative) jump */
               {
                  /* Only if points to code prior the current fix. */
                  if( pNOOPs[ nNOOP ] < nJumpAddr &&
                      pNOOPs[ nNOOP ] >= ( HB_SIZE ) ( nJumpAddr + nOffset ) )
                     plSizes[ nJump ]++;
               }

               /* update jump address */
               if( pNOOPs[ nNOOP ] < nJumpAddr )
                  plShifts[ nJump ]++;
            }
         }

         for( nJump = 0; nJump < HB_COMP_PARAM->functions.pLast->nJumps; nJump++ )
         {
            nOffset = plSizes[ nJump ];
            if( nOffset != 0 )
            {
               nJumpAddr = pJumps[ nJump ];
               switch( pCode[ nJumpAddr ] )
               {
                  case HB_P_JUMPNEAR:
                  case HB_P_JUMPFALSENEAR:
                  case HB_P_JUMPTRUENEAR:
                     nOffset += ( signed char ) pCode[ nJumpAddr + 1 ];
                     pCode[ nJumpAddr + 1 ] = HB_LOBYTE( nOffset );
                     break;

                  case HB_P_JUMP:
                  case HB_P_JUMPFALSE:
                  case HB_P_JUMPTRUE:
                     nOffset += HB_PCODE_MKSHORT( &pCode[ nJumpAddr + 1 ] );
                     HB_PUT_LE_UINT16( &pCode[ nJumpAddr + 1 ], nOffset );
                     break;

                  default:
                     nOffset += HB_PCODE_MKINT24( &pCode[ nJumpAddr + 1 ] );
                     HB_PUT_LE_UINT24( &pCode[ nJumpAddr + 1 ], nOffset );
                     break;
               }
            }
            pJumps[ nJump ] -= plShifts[ nJump ];
         }
         hb_xfree( plSizes );
         hb_xfree( plShifts );
      }

      nOptimized = nNextByte = 0;
      /* Second Scan, after all adjustments been made, we can copy the optimized code. */
      for( nNOOP = 0; nNOOP < HB_COMP_PARAM->functions.pLast->nNOOPs; nNOOP++ )
      {
         nBytes2Copy = ( pNOOPs[ nNOOP ] - nNextByte );

         memmove( pCode + nOptimized, pCode + nNextByte, nBytes2Copy );

         nOptimized += nBytes2Copy;
         nNextByte  += nBytes2Copy;

         /* Skip the NOOP and point to next valid byte */
         nNextByte++;
      }

      nBytes2Copy = ( HB_COMP_PARAM->functions.pLast->nPCodePos - nNextByte );
      memmove( pCode + nOptimized, pCode + nNextByte, nBytes2Copy );
      nOptimized += nBytes2Copy;

      HB_COMP_PARAM->functions.pLast->nPCodePos  = nOptimized;
      HB_COMP_PARAM->functions.pLast->nPCodeSize = nOptimized;

      hb_xfree( HB_COMP_PARAM->functions.pLast->pNOOPs );
      HB_COMP_PARAM->functions.pLast->pNOOPs = NULL;
      HB_COMP_PARAM->functions.pLast->nNOOPs = 0;

      if( iPass <= 1 )
      {
         hb_compOptimizePCode( HB_COMP_PARAM, HB_COMP_PARAM->functions.pLast );
         hb_compCodeTraceMarkDead( HB_COMP_PARAM, HB_COMP_PARAM->functions.pLast );
      }
   }
}

static void hb_compOptimizeFrames( HB_COMP_DECL, PHB_HFUNC pFunc )
{
   HB_USHORT w;

   if( pFunc == NULL )
      return;

   if( pFunc == HB_COMP_PARAM->pInitFunc )
   {
      if( pFunc->pCode[ 0 ] == HB_P_STATICS &&
          pFunc->pCode[ 5 ] == HB_P_SFRAME )
      {
         hb_compSymbolFind( HB_COMP_PARAM, pFunc->szName, &w, HB_SYM_FUNCNAME );
         pFunc->pCode[ 1 ] = HB_LOBYTE( w );
         pFunc->pCode[ 2 ] = HB_HIBYTE( w );
         pFunc->pCode[ 6 ] = HB_LOBYTE( w );
         pFunc->pCode[ 7 ] = HB_HIBYTE( w );

         /* Remove the SFRAME pcode if there's no global static
            initialization: */

         /* NOTE: For some reason this will not work for the static init
            function, so I'm using an ugly hack instead. [vszakats] */
         #if 0
         if( !( pFunc->funFlags & HB_FUNF_USES_STATICS ) )
         #endif
         if( pFunc->pCode[ 8 ] == HB_P_ENDPROC )
         {
            pFunc->nPCodePos -= 3;
            memmove( pFunc->pCode + 5, pFunc->pCode + 8, pFunc->nPCodePos - 5 );
         }
         else /* Check Global Statics. */
         {
            #if 0
            PHB_HVAR pVar = pFunc->pStatics;
            #endif
            PHB_HVAR pVar = HB_COMP_PARAM->functions.pFirst->pStatics;

            while( pVar )
            {
               #if 0
               printf( "\nChecking: %s Used: %i\n", pVar->szName, pVar->iUsed );
               #endif

               if( ! ( pVar->iUsed & HB_VU_USED ) && ( pVar->iUsed & HB_VU_INITIALIZED ) )
                  hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_VAL_NOT_USED, pVar->szName, NULL );

               /* May have been initialized in previous execution of the function.
                  else if( ( pVar->iUsed & HB_VU_USED ) && ! ( pVar->iUsed & HB_VU_INITIALIZED ) )
                  hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_NOT_INITIALIZED, pVar->szName, NULL );
                */
               pVar = pVar->pNext;
            }
         }
      }
   }
   else if( pFunc->pCode[ 0 ] == HB_P_FRAME && pFunc->pCode[ 3 ] == HB_P_SFRAME )
   {
      PHB_HVAR pLocal;
      int iLocals = 0, iOffset = 0;
      HB_BOOL bSkipFRAME;
      HB_BOOL bSkipSFRAME;

      pLocal = pFunc->pLocals;

      while( pLocal )
      {
         pLocal = pLocal->pNext;
         iLocals++;
      }

      if( pFunc->funFlags & HB_FUNF_USES_STATICS )
      {
         hb_compSymbolFind( HB_COMP_PARAM, HB_COMP_PARAM->pInitFunc->szName, &w, HB_SYM_FUNCNAME );
         pFunc->pCode[ 4 ] = HB_LOBYTE( w );
         pFunc->pCode[ 5 ] = HB_HIBYTE( w );
         bSkipSFRAME = HB_FALSE;
      }
      else
         bSkipSFRAME = HB_TRUE;

      if( iLocals || pFunc->wParamCount )
      {
         /* Parameters declared with PARAMETERS statement are not
          * placed in the local variable list.
          */
         if( pFunc->funFlags & HB_FUNF_USES_LOCAL_PARAMS )
            iLocals -= pFunc->wParamCount;

         if( iLocals > 255 )
         {
            /* more then 255 local variables,
             * make a room for HB_P_LARGE[V]FRAME
             */
            hb_compGenPCode1( 0, HB_COMP_PARAM );
            memmove( pFunc->pCode + 4, pFunc->pCode + 3, pFunc->nPCodePos - 4 );
            pFunc->pCode[ 0 ] = HB_P_LARGEFRAME;
            pFunc->pCode[ 1 ] = HB_LOBYTE( iLocals );
            pFunc->pCode[ 2 ] = HB_HIBYTE( iLocals );
            pFunc->pCode[ 3 ] = ( HB_BYTE ) pFunc->wParamCount;
            iOffset = 1;
         }
         else
         {
            pFunc->pCode[ 1 ] = ( HB_BYTE ) iLocals;
            pFunc->pCode[ 2 ] = ( HB_BYTE ) pFunc->wParamCount;
         }
         bSkipFRAME = HB_FALSE;
      }
      else
         /* Skip LOCALs frame only when function is not declared with
          * variable number of parameters (HB_P_[LARGE]VFRAME)
          */
         bSkipFRAME = ! pFunc->fVParams;

      /* Remove the frame pcodes if they are not needed */
      if( bSkipFRAME )
      {
         if( bSkipSFRAME )
         {
            pFunc->nPCodePos -= 6;
            memmove( pFunc->pCode, pFunc->pCode + 6, pFunc->nPCodePos );
         }
         else
         {
            pFunc->nPCodePos -= 3;
            memmove( pFunc->pCode, pFunc->pCode + 3, pFunc->nPCodePos );
         }
      }
      else
      {
         if( pFunc->fVParams )
            pFunc->pCode[ 0 ] = ( HB_BYTE ) ( iOffset ? HB_P_LARGEVFRAME : HB_P_VFRAME );

         if( bSkipSFRAME )
         {
            pFunc->nPCodePos -= 3;
            memmove( pFunc->pCode + 3 + iOffset, pFunc->pCode + 6 + iOffset,
                     pFunc->nPCodePos - 3 - iOffset );
         }
      }
   }
}

static void hb_compWarnUnusedVar( HB_COMP_DECL, const char * szFuncName,
                                  const char * szVarName, int iDeclLine )
{
   char szFun[ HB_SYMBOL_NAME_LEN + 17 ];

   if( HB_COMP_PARAM->iErrorFmt == HB_ERRORFMT_CLIPPER )
      hb_snprintf( szFun, sizeof( szFun ), "%s(%i)", szFuncName, iDeclLine );
   else
      hb_snprintf( szFun, sizeof( szFun ), "%i:%s", iDeclLine, szFuncName );
   hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W',
                      HB_COMP_WARN_VAR_NOT_USED, szVarName, szFun );
}

static void hb_compFinalizeFunction( HB_COMP_DECL ) /* fixes all last defined function returns jumps offsets */
{
   PHB_HFUNC pFunc = HB_COMP_PARAM->functions.pLast;

   if( pFunc )
   {
      if( ( pFunc->funFlags & HB_FUNF_WITH_RETURN ) == 0 )
      {
         /* The last statement in a function/procedure was not a RETURN
          * Generate end-of-procedure pcode
          */
         hb_compGenPCode1( HB_P_ENDPROC, HB_COMP_PARAM );
      }

      hb_compCheckUnclosedStru( HB_COMP_PARAM, pFunc );

      hb_compRTVariableKill( HB_COMP_PARAM, pFunc );
      hb_compSwitchKill( HB_COMP_PARAM, pFunc );
      hb_compElseIfKill( pFunc );
      hb_compLoopKill( pFunc );

      if( HB_COMP_PARAM->iWarnings &&
          ( pFunc->funFlags & HB_FUNF_FILE_DECL ) == 0 )
      {
         PHB_HVAR pVar;

         pVar = pFunc->pLocals;
         while( pVar )
         {
            if( pVar->szName && ( pVar->iUsed & HB_VU_USED ) == 0 )
               hb_compWarnUnusedVar( HB_COMP_PARAM, pFunc->szName, pVar->szName, pVar->iDeclLine );
            pVar = pVar->pNext;
         }

         pVar = pFunc->pStatics;
         while( pVar )
         {
            if( pVar->szName && ( pVar->iUsed & HB_VU_USED ) == 0 )
               hb_compWarnUnusedVar( HB_COMP_PARAM, pFunc->szName, pVar->szName, pVar->iDeclLine );
            pVar = pVar->pNext;
         }

         /* Check if the function returned some value
          */
         if( ( pFunc->funFlags & HB_FUNF_WITH_RETURN ) == 0 &&
             ( pFunc->funFlags & HB_FUNF_PROCEDURE ) == 0 )
            hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_FUN_WITH_NO_RETURN,
                               pFunc->szName, NULL );
      }

      if( ! pFunc->bError )
      {
         if( pFunc->wParamCount && ( pFunc->funFlags & HB_FUNF_USES_LOCAL_PARAMS ) == 0 )
         {
            /* There was a PARAMETERS statement used.
             * NOTE: This fixes local variables references in a case when
             * there is PARAMETERS statement after a LOCAL variable declarations.
             * All local variables are numbered from 1 - which means use first
             * item from the eval stack. However if PARAMETERS statement is used
             * then there are additional items on the eval stack - the
             * function arguments. Then first local variable is at the position
             * (1 + <number of arguments>). We cannot fix this numbering
             * because the PARAMETERS statement can be used even at the end
             * of function body when all local variables are already created.
             */
            hb_compFixFuncPCode( HB_COMP_PARAM, pFunc );
         }

         hb_compPCodeTraceOptimizer( HB_COMP_PARAM );
         hb_compOptimizeJumps( HB_COMP_PARAM );
      }
   }
}

/*
 * This function creates and initializes the HB_HFUNC structure
 */
static PHB_HFUNC hb_compFunctionNew( HB_COMP_DECL, const char * szName, HB_SYMBOLSCOPE cScope )
{
   PHB_HFUNC pFunc = ( PHB_HFUNC ) hb_xgrabz( sizeof( HB_HFUNC ) );

   pFunc->szName         = szName;
   pFunc->cScope         = cScope;
   pFunc->iStaticsBase   = HB_COMP_PARAM->iStaticCnt;
   pFunc->iEarlyEvalPass = 0;
   pFunc->fVParams       = HB_FALSE;
   pFunc->bError         = HB_FALSE;

   return pFunc;
}

static PHB_HINLINE hb_compInlineNew( HB_COMP_DECL, const char * szName, int iLine )
{
   PHB_HINLINE pInline = ( PHB_HINLINE ) hb_xgrab( sizeof( HB_HINLINE ) );

   pInline->szName     = szName;
   pInline->pCode      = NULL;
   pInline->nPCodeSize = 0;
   pInline->pNext      = NULL;
   pInline->szFileName = hb_compIdentifierNew( HB_COMP_PARAM,
                  hb_pp_fileName( HB_COMP_PARAM->pLex->pPP ), HB_IDENT_COPY );
   pInline->iLine      = iLine;

   return pInline;
}

/* NOTE: Names of variables and functions are released in hbident.c on exit */
static PHB_HFUNC hb_compFunctionKill( HB_COMP_DECL, PHB_HFUNC pFunc )
{
   PHB_HFUNC pNext = pFunc->pNext;
   PHB_ENUMERATOR pEVar;
   PHB_HVAR pVar;

   hb_compRTVariableKill( HB_COMP_PARAM, pFunc );
   hb_compSwitchKill( HB_COMP_PARAM, pFunc );
   hb_compElseIfKill( pFunc );
   hb_compLoopKill( pFunc );

   while( pFunc->pLocals )
   {
      pVar = pFunc->pLocals;
      pFunc->pLocals = pVar->pNext;
      hb_xfree( pVar );
   }

   while( pFunc->pStatics )
   {
      pVar = pFunc->pStatics;
      pFunc->pStatics = pVar->pNext;
      hb_xfree( pVar );
   }

   while( pFunc->pFields )
   {
      pVar = pFunc->pFields;
      pFunc->pFields = pVar->pNext;
      hb_xfree( pVar );
   }

   while( pFunc->pMemvars )
   {
      pVar = pFunc->pMemvars;
      pFunc->pMemvars = pVar->pNext;
      hb_xfree( pVar );
   }

   while( pFunc->pDetached )
   {
      pVar = pFunc->pDetached;
      pFunc->pDetached = pVar->pNext;
      hb_xfree( pVar );
   }

   while( pFunc->pPrivates )
   {
      pVar = pFunc->pPrivates;
      pFunc->pPrivates = pVar->pNext;
      hb_xfree( pVar );
   }

   while( pFunc->pEnum )
   {
      pEVar = pFunc->pEnum;
      pFunc->pEnum = pEVar->pNext;
      hb_xfree( pEVar );
   }

   /* Release the NOOP array. */
   if( pFunc->pNOOPs )
      hb_xfree( pFunc->pNOOPs );

   /* Release the Jumps array. */
   if( pFunc->pJumps )
      hb_xfree( pFunc->pJumps );

   if( pFunc->pCode )
      hb_xfree( pFunc->pCode );

   hb_xfree( pFunc );

   return pNext;
}

/*
 * This function adds the name of external symbol into the list of externals
 * as they have to be placed on the symbol table later than the first
 * public symbol
 */
void hb_compExternAdd( HB_COMP_DECL, const char * szExternName, HB_SYMBOLSCOPE cScope ) /* defines a new extern name */
{
   PHB_HEXTERN * pExtern;

   if( strcmp( "_GET_", szExternName ) == 0 )
   {
      /* special function to implement @ GET statement */
      hb_compExternAdd( HB_COMP_PARAM, "__GETA", 0 );
      szExternName = "__GET";
   }

   pExtern = &HB_COMP_PARAM->externs;
   while( *pExtern )
   {
      if( strcmp( ( *pExtern )->szName, szExternName ) == 0 )
         break;
      pExtern = &( *pExtern )->pNext;
   }
   if( *pExtern )
      ( *pExtern )->cScope |= cScope;
   else
   {
      *pExtern = ( PHB_HEXTERN ) hb_xgrab( sizeof( HB_HEXTERN ) );
      ( *pExtern )->szName = szExternName;
      ( *pExtern )->cScope = cScope;
      ( *pExtern )->pNext  = NULL;
   }
}

static void hb_compAddFunc( HB_COMP_DECL, PHB_HFUNC pFunc )
{
   while( HB_COMP_PARAM->functions.pLast &&
          ! HB_COMP_PARAM->functions.pLast->szName )
   {
      PHB_HFUNC pBlock = HB_COMP_PARAM->functions.pLast;
      HB_COMP_PARAM->functions.pLast = pBlock->pOwner;
      hb_compFunctionKill( HB_COMP_PARAM, pBlock );
   }

   if( HB_COMP_PARAM->functions.iCount == 0 )
      HB_COMP_PARAM->functions.pFirst = pFunc;
   else
      HB_COMP_PARAM->functions.pLast->pNext = pFunc;
   HB_COMP_PARAM->functions.pLast = pFunc;
   HB_COMP_PARAM->functions.iCount++;
}

static PHB_HFUNC hb_compFunctionFind( HB_COMP_DECL, const char * szName, HB_BOOL fLocal )
{
   PHB_HFUNC pFunc;

   if( HB_COMP_PARAM->iModulesCount <= 1 )
   {
      pFunc = HB_COMP_PARAM->functions.pFirst;
      fLocal = HB_TRUE;
   }
   else
      pFunc = fLocal ? HB_COMP_PARAM->pDeclFunc :
                       HB_COMP_PARAM->functions.pFirst;
   while( pFunc )
   {
      if( pFunc == HB_COMP_PARAM->pDeclFunc )
         fLocal = HB_TRUE;

      if( ( pFunc->funFlags & HB_FUNF_FILE_DECL ) == 0 &&
          ( fLocal || ( pFunc->cScope & ( HB_FS_STATIC | HB_FS_INITEXIT ) ) == 0 ) &&
          strcmp( pFunc->szName, szName ) == 0 )
         break;

      pFunc = pFunc->pNext;
   }
   return pFunc;
}

static HB_BOOL hb_compIsModuleFunc( HB_COMP_DECL, const char * szFunctionName )
{
   PHB_HFUNC pFunc = HB_COMP_PARAM->functions.pFirst;

   while( pFunc )
   {
      if( ( pFunc->cScope & HB_FS_STATIC ) == 0 &&
          hb_stricmp( pFunc->szName, szFunctionName ) == 0 )
         break;
      pFunc = pFunc->pNext;
   }
   return pFunc != NULL;
}

static void hb_compUpdateFunctionNames( HB_COMP_DECL )
{
   if( HB_COMP_PARAM->iModulesCount > 1 )
   {
      PHB_HFUNC pFunc = HB_COMP_PARAM->functions.pFirst;

      while( pFunc )
      {
         if( ( pFunc->cScope & ( HB_FS_STATIC | HB_FS_INITEXIT ) ) != 0 )
         {
            PHB_HSYMBOL pSym = HB_COMP_PARAM->symbols.pFirst, pFuncSym = NULL;
            HB_BOOL fExists = HB_FALSE;

            while( pSym )
            {
               if( pSym->iFunc )
               {
                  if( pSym->pFunc == pFunc )
                     pFuncSym = pSym;
                  else if( ( ( pSym->cScope & HB_FS_LOCAL ) != 0 ||
                        ( pSym->cScope & HB_FS_DEFERRED ) == 0 ) &&
                      strcmp( pFunc->szName, pSym->szName ) == 0 )
                     fExists = HB_TRUE;

                  if( pFuncSym && fExists )
                  {
                     pFunc->iFuncSuffix = pFuncSym->iFunc;
                     break;
                  }
               }
               pSym = pSym->pNext;
            }
         }
         pFunc = pFunc->pNext;
      }
   }
}

static HB_BOOL hb_compCheckReservedNames( HB_COMP_DECL, const char * szFunName, HB_BOOL fError )
{
   const char * szFunction;
   HB_FUNC_ID funcID;
   int iFlags;

   szFunction = hb_compGetFuncID( szFunName, &funcID, &iFlags );
   if( iFlags & HB_FN_RESERVED )
   {
      if( fError )
         hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_FUNC_RESERVED, szFunction, szFunName );
      return HB_TRUE;
   }
   else
      return HB_FALSE;
}

static HB_BOOL hb_compRegisterFunc( HB_COMP_DECL, PHB_HFUNC pFunc, HB_BOOL fError )
{
   if( hb_compFunctionFind( HB_COMP_PARAM, pFunc->szName,
                            ( pFunc->cScope & HB_FS_STATIC ) != 0 ) )
   {
      /* The name of a function/procedure is already defined */
      if( fError )
         hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_FUNC_DUPL, pFunc->szName, NULL );
   }
   else if( ! hb_compCheckReservedNames( HB_COMP_PARAM, pFunc->szName, fError ) )
   {
      PHB_HSYMBOL pSym = hb_compSymbolFind( HB_COMP_PARAM, pFunc->szName, NULL, HB_SYM_FUNCNAME );
      if( ! pSym )
         pSym = hb_compSymbolAdd( HB_COMP_PARAM, pFunc->szName, NULL, HB_SYM_FUNCNAME );
      pSym->cScope |= pFunc->cScope | HB_FS_LOCAL;
      pSym->pFunc = pFunc;
      return HB_TRUE;
   }
   return HB_FALSE;
}

/*
 * Stores a Clipper defined function/procedure
 * szFunName - name of a function
 * cScope    - scope of a function
 * iType     - HB_FUNF_PROCEDURE if a procedure or 0
 */
void hb_compFunctionAdd( HB_COMP_DECL, const char * szFunName, HB_SYMBOLSCOPE cScope, int iType )
{
   PHB_HFUNC pFunc;

   hb_compFinalizeFunction( HB_COMP_PARAM );    /* fix all previous function returns offsets */

   if( cScope & ( HB_FS_INIT | HB_FS_EXIT ) )
   {
      char szNewName[ HB_SYMBOL_NAME_LEN + 1 ];
      int iLen;

      iLen = ( int ) strlen( szFunName );
      if( iLen >= HB_SYMBOL_NAME_LEN )
         iLen = HB_SYMBOL_NAME_LEN - 1;
      memcpy( szNewName, szFunName, iLen );
      szNewName[ iLen ] ='$';
      szNewName[ iLen + 1 ] = '\0';
      szFunName = hb_compIdentifierNew( HB_COMP_PARAM, szNewName, HB_IDENT_COPY );
   }

   pFunc = hb_compFunctionNew( HB_COMP_PARAM, szFunName, cScope );
   pFunc->funFlags |= iType;

   if( ( iType & HB_FUNF_FILE_DECL ) == 0 )
      hb_compRegisterFunc( HB_COMP_PARAM, pFunc, HB_TRUE );

   if( ( iType & ( HB_FUNF_FILE_DECL | HB_FUNF_FILE_FIRST ) ) != 0 )
      HB_COMP_PARAM->pDeclFunc = pFunc;

   hb_compAddFunc( HB_COMP_PARAM, pFunc );

   HB_COMP_PARAM->ilastLineErr = 0; /* position of last syntax error (line number) */

   hb_compGenPCode3( HB_P_FRAME, 0, 0, HB_COMP_PARAM );  /* frame for locals and parameters */
   hb_compGenPCode3( HB_P_SFRAME, 0, 0, HB_COMP_PARAM ); /* frame for statics variables */

   if( HB_COMP_PARAM->fDebugInfo )
      hb_compGenModuleName( HB_COMP_PARAM, szFunName );
   else
      HB_COMP_PARAM->lastLine = -1;
}

/* create an ANNOUNCEd procedure
 */
static void hb_compAnnounce( HB_COMP_DECL, const char * szFunName )
{
   PHB_HFUNC pFunc;

   /* Clipper call this function after compiling .prg module where ANNOUNCE
    * symbol was defined not after compiling all .prg modules and search for
    * public ANNOUNCEd function/procedure in all compiled so far modules
    * and then for static one in currently compiler module.
    */

   /* check for reserved name
    * NOTE: Clipper doesn't check for it
    */
   hb_compCheckReservedNames( HB_COMP_PARAM, szFunName, HB_TRUE );

   pFunc = hb_compFunctionFind( HB_COMP_PARAM, szFunName, HB_FALSE );
   if( pFunc )
   {
      /* there is a function/procedure defined already - ANNOUNCEd procedure
       * have to be a public symbol - check if existing symbol is public
       */
      if( pFunc->cScope & HB_FS_STATIC )
         hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'F', HB_COMP_ERR_FUNC_ANNOUNCE, szFunName, NULL );
   }
   else
   {
      PHB_HSYMBOL pSym;

      /* create a new procedure
       */
      pFunc = hb_compFunctionNew( HB_COMP_PARAM, szFunName, HB_FS_LOCAL );
      pFunc->funFlags |= HB_FUNF_PROCEDURE;

      pSym = hb_compSymbolFind( HB_COMP_PARAM, szFunName, NULL, HB_SYM_FUNCNAME );
      if( ! pSym )
         pSym = hb_compSymbolAdd( HB_COMP_PARAM, szFunName, NULL, HB_SYM_FUNCNAME );
      pSym->cScope |= pFunc->cScope;
      pSym->pFunc = pFunc;

      hb_compAddFunc( HB_COMP_PARAM, pFunc );

      /* this function have a very limited functionality
       */
      hb_compGenPCode1( HB_P_ENDPROC, HB_COMP_PARAM );
   }
}

void hb_compFunctionSetScope( HB_COMP_DECL, const char * szFunName, HB_SYMBOLSCOPE cScope )
{
   PHB_HSYMBOL pSym = hb_compSymbolFind( HB_COMP_PARAM, szFunName, NULL, HB_SYM_FUNCNAME );

   if( pSym )
   {
      if( ( pSym->cScope & ( HB_FS_DEFERRED | HB_FS_LOCAL ) ) == 0 )
         pSym->cScope |= cScope;
   }
}

PHB_HINLINE hb_compInlineAdd( HB_COMP_DECL, const char * szFunName, int iLine )
{
   PHB_HINLINE pInline;
   PHB_HSYMBOL pSym;

   if( szFunName )
   {
      pSym = hb_compSymbolFind( HB_COMP_PARAM, szFunName, NULL, HB_SYM_FUNCNAME );
      if( ! pSym )
         pSym = hb_compSymbolAdd( HB_COMP_PARAM, szFunName, NULL, HB_SYM_FUNCNAME );
      pSym->cScope |= HB_FS_STATIC | HB_FS_LOCAL;
   }
   pInline = hb_compInlineNew( pComp, szFunName, iLine );

   if( HB_COMP_PARAM->inlines.iCount == 0 )
   {
      HB_COMP_PARAM->inlines.pFirst = pInline;
      HB_COMP_PARAM->inlines.pLast  = pInline;
   }
   else
   {
      HB_COMP_PARAM->inlines.pLast->pNext = pInline;
      HB_COMP_PARAM->inlines.pLast = pInline;
   }

   HB_COMP_PARAM->inlines.iCount++;

   return pInline;
}

void hb_compGenBreak( HB_COMP_DECL )
{
   hb_compGenPushFunCall( "BREAK", HB_FN_RESERVED, HB_COMP_PARAM );
}

/* generates the symbols for the EXTERN names */
static void hb_compExternGen( HB_COMP_DECL )
{
   PHB_HEXTERN pDelete;

   while( HB_COMP_PARAM->externs )
   {
      HB_SYMBOLSCOPE cScope = HB_COMP_PARAM->externs->cScope;
      PHB_HSYMBOL pSym = hb_compSymbolFind( HB_COMP_PARAM, HB_COMP_PARAM->externs->szName, NULL, HB_SYM_FUNCNAME );

      if( pSym )
      {
         pSym->cScope |= cScope;
      }
      else if( ( cScope & HB_FS_DEFERRED ) == 0 )
      {
         pSym = hb_compSymbolAdd( HB_COMP_PARAM, HB_COMP_PARAM->externs->szName, NULL, HB_SYM_FUNCNAME );
         pSym->cScope |= cScope;
      }
      pDelete = HB_COMP_PARAM->externs;
      HB_COMP_PARAM->externs = HB_COMP_PARAM->externs->pNext;
      hb_xfree( pDelete );
   }
}

static void hb_compNOOPadd( PHB_HFUNC pFunc, HB_SIZE nPos )
{
   pFunc->pCode[ nPos ] = HB_P_NOOP;

   if( pFunc->nNOOPs )
      pFunc->pNOOPs = ( HB_SIZE * ) hb_xrealloc( pFunc->pNOOPs, sizeof( HB_SIZE ) * ( pFunc->nNOOPs + 1 ) );
   else
      pFunc->pNOOPs = ( HB_SIZE * ) hb_xgrab( sizeof( HB_SIZE ) );
   pFunc->pNOOPs[ pFunc->nNOOPs++ ] = nPos;
}

static void hb_compPrepareJumps( HB_COMP_DECL )
{
   PHB_HFUNC pFunc = HB_COMP_PARAM->functions.pLast;

   if( pFunc->nJumps )
      pFunc->pJumps = ( HB_SIZE * ) hb_xrealloc( pFunc->pJumps, sizeof( HB_SIZE ) * ( pFunc->nJumps + 1 ) );
   else
      pFunc->pJumps = ( HB_SIZE * ) hb_xgrab( sizeof( HB_SIZE ) );
   pFunc->pJumps[ pFunc->nJumps++ ] = ( HB_SIZE ) ( pFunc->nPCodePos - 4 );
}

HB_SIZE hb_compGenJump( HB_ISIZ nOffset, HB_COMP_DECL )
{
   if( ! HB_LIM_INT24( nOffset ) )
      hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'F', HB_COMP_ERR_JUMP_TOO_LONG, NULL, NULL );

   hb_compGenPCode4( HB_P_JUMPFAR, HB_LOBYTE( nOffset ), HB_HIBYTE( nOffset ), ( HB_BYTE ) ( ( nOffset >> 16 ) & 0xFF ), HB_COMP_PARAM );
   hb_compPrepareJumps( HB_COMP_PARAM );

   return HB_COMP_PARAM->functions.pLast->nPCodePos - 3;
}

HB_SIZE hb_compGenJumpFalse( HB_ISIZ nOffset, HB_COMP_DECL )
{
   if( ! HB_LIM_INT24( nOffset ) )
      hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'F', HB_COMP_ERR_JUMP_TOO_LONG, NULL, NULL );

   hb_compGenPCode4( HB_P_JUMPFALSEFAR, HB_LOBYTE( nOffset ), HB_HIBYTE( nOffset ), ( HB_BYTE ) ( ( nOffset >> 16 ) & 0xFF ), HB_COMP_PARAM );
   hb_compPrepareJumps( HB_COMP_PARAM );

   return HB_COMP_PARAM->functions.pLast->nPCodePos - 3;
}

HB_SIZE hb_compGenJumpTrue( HB_ISIZ nOffset, HB_COMP_DECL )
{
   if( ! HB_LIM_INT24( nOffset ) )
      hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'F', HB_COMP_ERR_JUMP_TOO_LONG, NULL, NULL );

   hb_compGenPCode4( HB_P_JUMPTRUEFAR, HB_LOBYTE( nOffset ), HB_HIBYTE( nOffset ), ( HB_BYTE ) ( ( nOffset >> 16 ) & 0xFF ), HB_COMP_PARAM );
   hb_compPrepareJumps( HB_COMP_PARAM );

   return HB_COMP_PARAM->functions.pLast->nPCodePos - 3;
}

void hb_compGenJumpThere( HB_SIZE nFrom, HB_SIZE nTo, HB_COMP_DECL )
{
   HB_BYTE * pCode = HB_COMP_PARAM->functions.pLast->pCode;
   HB_ISIZ nOffset = nTo - nFrom + 1;

   if( HB_LIM_INT24( nOffset ) )
   {
      HB_PUT_LE_UINT24( &pCode[ nFrom ], nOffset );
   }
   else
      hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'F', HB_COMP_ERR_JUMP_TOO_LONG, NULL, NULL );
}

void hb_compGenJumpHere( HB_SIZE nOffset, HB_COMP_DECL )
{
   hb_compGenJumpThere( nOffset, HB_COMP_PARAM->functions.pLast->nPCodePos, HB_COMP_PARAM );
}

void hb_compLinePush( HB_COMP_DECL ) /* generates the pcode with the currently compiled source code line */
{
   if( HB_COMP_PARAM->fLineNumbers )
   {
      if( HB_COMP_PARAM->fDebugInfo && HB_COMP_PARAM->lastModule != HB_COMP_PARAM->currModule )
         hb_compGenModuleName( HB_COMP_PARAM, NULL );

      if( HB_COMP_PARAM->currLine != HB_COMP_PARAM->lastLine )
      {
         hb_compGenPCode3( HB_P_LINE, HB_LOBYTE( HB_COMP_PARAM->currLine ),
                                      HB_HIBYTE( HB_COMP_PARAM->currLine ), HB_COMP_PARAM );
         HB_COMP_PARAM->lastLine = HB_COMP_PARAM->currLine;
      }
   }

   if( HB_COMP_PARAM->functions.pLast->funFlags & HB_FUNF_BREAK_CODE )
   {
      /* previous line contained RETURN/BREAK/LOOP/EXIT statement */
      hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_UNREACHABLE, NULL, NULL );
      /* clear RETURN/BREAK flag */
      HB_COMP_PARAM->functions.pLast->funFlags &= ~ ( /*HB_FUNF_WITH_RETURN |*/ HB_FUNF_BREAK_CODE );
   }
}

/*
 * Test if we can generate statement (without line pushing)
 */
void hb_compStatmentStart( HB_COMP_DECL )
{
   if( ( HB_COMP_PARAM->functions.pLast->funFlags & HB_FUNF_STATEMENTS ) == 0 )
   {
      PHB_HFUNC pFunc = HB_COMP_PARAM->functions.pLast;

      if( ( pFunc->funFlags & HB_FUNF_FILE_DECL ) != 0 )
      {
         if( HB_COMP_PARAM->iStartProc == 2 && pFunc->szName[ 0 ] &&
             hb_compRegisterFunc( HB_COMP_PARAM, pFunc, HB_FALSE ) )
            pFunc->funFlags &= ~HB_FUNF_FILE_DECL;
         else
            hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_OUTSIDE, NULL, NULL );
      }
      pFunc->funFlags |= HB_FUNF_STATEMENTS;
   }
}

void hb_compLinePushIfInside( HB_COMP_DECL ) /* generates the pcode with the currently compiled source code line */
{
   hb_compStatmentStart( HB_COMP_PARAM );
   hb_compLinePush( HB_COMP_PARAM );
}

/* Generates the pcode with the currently compiled source code line
 * if debug code was requested only
 */
void hb_compLinePushIfDebugger( HB_COMP_DECL )
{
   hb_compStatmentStart( HB_COMP_PARAM );

   if( HB_COMP_PARAM->fDebugInfo )
      hb_compLinePush( HB_COMP_PARAM );
   else
   {
      if( HB_COMP_PARAM->functions.pLast->funFlags & HB_FUNF_BREAK_CODE )
      {
         /* previous line contained RETURN/BREAK/LOOP/EXIT statement */
         hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_UNREACHABLE, NULL, NULL );
      }
      HB_COMP_PARAM->functions.pLast->funFlags &= ~( /*HB_FUNF_WITH_RETURN |*/ HB_FUNF_BREAK_CODE );   /* clear RETURN flag */
   }
}

/* generates the pcode with the currently compiled module and function name */
void hb_compGenModuleName( HB_COMP_DECL, const char * szFunName )
{
   hb_compGenPCode1( HB_P_MODULENAME, HB_COMP_PARAM );
   hb_compGenPCodeN( ( const HB_BYTE * ) HB_COMP_PARAM->currModule,
                     strlen( HB_COMP_PARAM->currModule ), HB_COMP_PARAM );
   hb_compGenPCode1( ':', HB_COMP_PARAM );
   if( szFunName && *szFunName )
      hb_compGenPCodeN( ( const HB_BYTE * ) szFunName, strlen( szFunName ) + 1, HB_COMP_PARAM );
   else /* special version "filename:" when the file changes within function */
      hb_compGenPCode1( '\0', HB_COMP_PARAM );
   HB_COMP_PARAM->lastModule = HB_COMP_PARAM->currModule;
   HB_COMP_PARAM->lastLine = -1;
}

#if 0
void hb_compGenStaticName( const char * szVarName, HB_COMP_DECL )
{
   if( HB_COMP_PARAM->fDebugInfo )
   {
      HB_BYTE bGlobal = 0;
      PHB_HFUNC pFunc;
      int iVar;

      if( ( HB_COMP_PARAM->functions.pLast->funFlags & HB_FUNF_FILE_DECL ) != 0 )
      {
         /* Variable declaration is outside of function/procedure body.
            File-wide static variable
          */
         hb_compStaticDefStart( HB_COMP_PARAM );
         bGlobal = 1;
      }
      pFunc = HB_COMP_PARAM->functions.pLast;
      iVar = hb_compStaticGetPos( szVarName, pFunc );

      hb_compGenPCode4( HB_P_STATICNAME, bGlobal, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ), HB_COMP_PARAM );
      hb_compGenPCodeN( ( HB_BYTE * ) szVarName, strlen( szVarName ) + 1, HB_COMP_PARAM );

      if( bGlobal )
         hb_compStaticDefEnd( HB_COMP_PARAM );
   }
}
#endif

/*
 * Function generates passed pcode for passed runtime variable
 * (field or memvar)
 */
static void hb_compGenVarPCode( HB_BYTE bPCode, const char * szVarName, HB_COMP_DECL )
{
   HB_USHORT wVar;
   PHB_HSYMBOL pSym;

   /* Check if this variable name is placed into the symbol table
    */
   pSym = hb_compSymbolFind( HB_COMP_PARAM, szVarName, &wVar, HB_SYM_MEMVAR );
   if( ! pSym )
      pSym = hb_compSymbolAdd( HB_COMP_PARAM, szVarName, &wVar, HB_SYM_MEMVAR );
   pSym->cScope |= HB_FS_MEMVAR;

   if( bPCode == HB_P_PUSHALIASEDFIELD && wVar <= 255 )
      hb_compGenPCode2( HB_P_PUSHALIASEDFIELDNEAR, ( HB_BYTE ) wVar, HB_COMP_PARAM );
   else if( bPCode == HB_P_POPALIASEDFIELD && wVar <= 255 )
      hb_compGenPCode2( HB_P_POPALIASEDFIELDNEAR, ( HB_BYTE ) wVar, HB_COMP_PARAM );
   else
      hb_compGenPCode3( bPCode, HB_LOBYTE( wVar ), HB_HIBYTE( wVar ), HB_COMP_PARAM );
}

/*
 * Function generates pcode for undeclared variable
 */
static void hb_compGenVariablePCode( HB_COMP_DECL, HB_BYTE bPCode, const char * szVarName )
{
   HB_BOOL bGenCode;

   /*
    * NOTE:
    * Clipper always assumes a memvar variable if undeclared variable
    * is popped (a value is assigned to a variable).
    */
   if( HB_SUPPORT_HARBOUR )
      bGenCode = HB_COMP_PARAM->fForceMemvars;    /* Harbour compatibility */
   else
      bGenCode = ( HB_COMP_PARAM->fForceMemvars || bPCode == HB_P_POPVARIABLE );

   if( bGenCode )
   {
      /* -v switch was used -> assume it is a memvar variable
       */
      if( HB_COMP_PARAM->functions.pLast->iEarlyEvalPass == 0 || HB_SUPPORT_MACRODECL )
         hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_MEMVAR_ASSUMED, szVarName, NULL );

      if( bPCode == HB_P_POPVARIABLE )
         bPCode = HB_P_POPMEMVAR;
      else if( bPCode == HB_P_PUSHVARIABLE )
         bPCode = HB_P_PUSHMEMVAR;
      else
         bPCode = HB_P_PUSHMEMVARREF;
   }
   else if( HB_COMP_PARAM->functions.pLast->iEarlyEvalPass == 0 || HB_SUPPORT_MACRODECL )
      hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_AMBIGUOUS_VAR, szVarName, NULL );

   hb_compGenVarPCode( bPCode, szVarName, HB_COMP_PARAM );
}

/* Generate a pcode for a field variable
 */
static void hb_compGenFieldPCode( HB_COMP_DECL, HB_BYTE bPCode, PHB_HVAR pField )
{
   if( pField->szAlias )
   {
      /* the alias was specified in FIELD declaration
       * Push alias symbol before the field symbol
       */
      if( bPCode == HB_P_POPFIELD )
         bPCode = HB_P_POPALIASEDFIELD;
      else if( bPCode == HB_P_PUSHFIELD )
         bPCode = HB_P_PUSHALIASEDFIELD;

      hb_compGenPushSymbol( pField->szAlias, HB_SYM_ALIAS, HB_COMP_PARAM );
   }
   hb_compGenVarPCode( bPCode, pField->szName, HB_COMP_PARAM );
}

/* sends a message to an object */
/* bIsObject = HB_TRUE if we are sending a message to real object
   bIsObject is HB_FALSE if we are sending a message to an object specified
   with WITH OBJECT statement.
 */
void hb_compGenMessage( const char * szMsgName, HB_BOOL bIsObject, HB_COMP_DECL )
{
   HB_USHORT wSym;
   PHB_HSYMBOL pSym;

   if( szMsgName )
   {
      pSym = hb_compSymbolFind( HB_COMP_PARAM, szMsgName, &wSym, HB_SYM_MSGNAME );
      if( ! pSym )  /* the symbol was not found on the symbol table */
         pSym = hb_compSymbolAdd( HB_COMP_PARAM, szMsgName, &wSym, HB_SYM_MSGNAME );
      pSym->cScope |= HB_FS_MESSAGE;
      if( bIsObject )
         hb_compGenPCode3( HB_P_MESSAGE, HB_LOBYTE( wSym ), HB_HIBYTE( wSym ), HB_COMP_PARAM );
      else
         hb_compGenPCode3( HB_P_WITHOBJECTMESSAGE, HB_LOBYTE( wSym ), HB_HIBYTE( wSym ), HB_COMP_PARAM );
   }
   else
   {
      wSym = 0xFFFF;
      hb_compGenPCode3( HB_P_WITHOBJECTMESSAGE, HB_LOBYTE( wSym ), HB_HIBYTE( wSym ), HB_COMP_PARAM );
   }

   if( ! bIsObject && HB_COMP_PARAM->functions.pLast->iEarlyEvalPass == 1 )
   {
      if( HB_SUPPORT_MACRODECL )
         HB_COMP_PARAM->functions.pLast->iEarlyEvalPass = 0;
      else
         hb_compErrorCodeblockWith( HB_COMP_PARAM, szMsgName ? szMsgName : "&..." );
   }
}

void hb_compGenMessageData( const char * szMsg, HB_BOOL bIsObject, HB_COMP_DECL ) /* generates an underscore-symbol name for a data assignment */
{
   char szResult[ HB_SYMBOL_NAME_LEN + 1 ];
   int iLen = ( int ) strlen( szMsg );

   if( iLen >= HB_SYMBOL_NAME_LEN )
      iLen = HB_SYMBOL_NAME_LEN - 1;
   szResult[ 0 ] = '_';
   memcpy( szResult + 1, szMsg, iLen );
   szResult[ iLen + 1 ] = '\0';

   hb_compGenMessage( hb_compIdentifierNew( HB_COMP_PARAM, szResult, HB_IDENT_COPY ), bIsObject, HB_COMP_PARAM );
}

static void hb_compCheckEarlyMacroEval( HB_COMP_DECL, const char * szVarName, int iScope )
{
   if( iScope == HB_VS_CBLOCAL_VAR ||
       /* iScope == HB_VS_LOCAL_VAR || */ /* codeblock parameters */
       iScope == HB_VS_STATIC_VAR ||
       iScope == HB_VS_GLOBAL_STATIC ||
       iScope == HB_VS_LOCAL_FIELD ||
       iScope == HB_VS_GLOBAL_FIELD )
   {
      /* Disable early evaluation if codeblock contains macros and
       * declared variables, i.e. {| x | cLocal + &cPriv }
       * and support for macros with declared symbols is enabled.
       */
      if( HB_COMP_PARAM->functions.pLast->iEarlyEvalPass == 1 &&
          HB_SUPPORT_MACRODECL )
         HB_COMP_PARAM->functions.pLast->iEarlyEvalPass = 0;
      else
         hb_compErrorCodeblockDecl( HB_COMP_PARAM, szVarName );
   }
}

/* Check variable in the following order:
 * LOCAL variable
 *    local STATIC variable
 *       local FIELD variable
 *  local MEMVAR variable
 * global STATIC variable
 *    global FIELD variable
 *       global MEMVAR variable
 * (if not found - it is an undeclared variable)
 */
void hb_compGenPopVar( const char * szVarName, HB_COMP_DECL ) /* generates the pcode to pop a value from the virtual machine stack onto a variable */
{
   int iVar, iScope;
   PHB_HVAR pVar;

   pVar = hb_compVariableFind( HB_COMP_PARAM, szVarName, &iVar, &iScope );
   if( pVar )
   {
      if( HB_COMP_PARAM->functions.pLast->iEarlyEvalPass == 1 )
         hb_compCheckEarlyMacroEval( HB_COMP_PARAM, szVarName, iScope );

      switch( iScope )
      {
         case HB_VS_LOCAL_VAR:
         case HB_VS_CBLOCAL_VAR:
            /* local variable */
            /* local variables used in a codeblock will not be adjusted
             * if PARAMETERS statement will be used then it is safe to
             * use 2 bytes for LOCALNEAR
             */
            if( HB_LIM_INT8( iVar ) && ! HB_COMP_PARAM->functions.pLast->szName &&
                !( HB_COMP_PARAM->functions.pLast->funFlags & HB_FUNF_EXTBLOCK ) )
               hb_compGenPCode2( HB_P_POPLOCALNEAR, ( HB_BYTE ) iVar, HB_COMP_PARAM );
            else
               hb_compGenPCode3( HB_P_POPLOCAL, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ), HB_COMP_PARAM );
            break;

         case HB_VS_STATIC_VAR:
         case HB_VS_GLOBAL_STATIC:
            /* Static variable */
            hb_compGenPCode3( HB_P_POPSTATIC, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ), HB_COMP_PARAM );
            {
               PHB_HFUNC pFunc;
               /* Check if we are generating a pop code for static variable
                * initialization function - if YES then we have to switch to a function
                * where the static variable was declared
                */
               pFunc = HB_COMP_PARAM->functions.pLast;
               if( ( HB_COMP_PARAM->functions.pLast->cScope & HB_FS_INITEXIT ) == HB_FS_INITEXIT )
                  pFunc = pFunc->pOwner;
               pFunc->funFlags |= HB_FUNF_USES_STATICS;
            }
            break;

         case HB_VS_LOCAL_FIELD:
         case HB_VS_GLOBAL_FIELD:
            /* declared field */
            hb_compGenFieldPCode( HB_COMP_PARAM, HB_P_POPFIELD, pVar );
            break;

         case HB_VS_LOCAL_MEMVAR:
         case HB_VS_GLOBAL_MEMVAR:
            /* declared memvar variable */
            hb_compGenVarPCode( HB_P_POPMEMVAR, szVarName, HB_COMP_PARAM );
            break;

         default:
            pVar = NULL;
            break;
      }
   }

   if( ! pVar ) /* undeclared variable */
   {
      hb_compGenVariablePCode( HB_COMP_PARAM, HB_P_POPVARIABLE, szVarName );
   }
}

/* generates the pcode to pop a value from the virtual machine stack onto a memvar variable */
void hb_compGenPopMemvar( const char * szVarName, HB_COMP_DECL )
{
   if( ( hb_compVariableScope( HB_COMP_PARAM, szVarName ) & HB_VS_LOCAL_MEMVAR ) == 0 )
      hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_MEMVAR_ASSUMED, szVarName, NULL );
   hb_compGenVarPCode( HB_P_POPMEMVAR, szVarName, HB_COMP_PARAM );
}

/* generates the pcode to push a non-aliased variable value to the virtual
 * machine stack
 * bMacroVar is HB_TRUE if macro &szVarName context
 */
void hb_compGenPushVar( const char * szVarName, HB_COMP_DECL )
{
   int iVar, iScope;
   PHB_HVAR pVar;

   pVar = hb_compVariableFind( HB_COMP_PARAM, szVarName, &iVar, &iScope );
   if( pVar )
   {
      if( HB_COMP_PARAM->functions.pLast->iEarlyEvalPass == 1 )
         hb_compCheckEarlyMacroEval( HB_COMP_PARAM, szVarName, iScope );

      switch( iScope )
      {
         case HB_VS_LOCAL_VAR:
         case HB_VS_CBLOCAL_VAR:
            /* local variable */
            /* local variables used in a codeblock will not be adjusted
             * if PARAMETERS statement will be used then it is safe to
             * use 2 bytes for LOCALNEAR
             */
            if( HB_LIM_INT8( iVar ) && ! HB_COMP_PARAM->functions.pLast->szName &&
                !( HB_COMP_PARAM->functions.pLast->funFlags & HB_FUNF_EXTBLOCK ) )
               hb_compGenPCode2( HB_P_PUSHLOCALNEAR, ( HB_BYTE ) iVar, HB_COMP_PARAM );
            else
               hb_compGenPCode3( HB_P_PUSHLOCAL, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ), HB_COMP_PARAM );
            break;

         case HB_VS_STATIC_VAR:
         case HB_VS_GLOBAL_STATIC:
            /* Static variable */
            hb_compGenPCode3( HB_P_PUSHSTATIC, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ), HB_COMP_PARAM );
            HB_COMP_PARAM->functions.pLast->funFlags |= HB_FUNF_USES_STATICS;
            break;

         case HB_VS_LOCAL_FIELD:
         case HB_VS_GLOBAL_FIELD:
            /* declared field */
            hb_compGenFieldPCode( HB_COMP_PARAM, HB_P_PUSHFIELD, pVar );
            break;

         case HB_VS_LOCAL_MEMVAR:
         case HB_VS_GLOBAL_MEMVAR:
            /* declared memvar variable */
            hb_compGenVarPCode( HB_P_PUSHMEMVAR, szVarName, HB_COMP_PARAM );
            break;

         default:
            pVar = NULL;
            break;
      }
   }

   if( ! pVar ) /* undeclared variable */
   {
      hb_compGenVariablePCode( HB_COMP_PARAM, HB_P_PUSHVARIABLE, szVarName );
   }
}

void hb_compGenPushVarRef( const char * szVarName, HB_COMP_DECL ) /* generates the pcode to push a variable by reference to the virtual machine stack */
{
   int iVar, iScope;
   PHB_HVAR pVar;

   pVar = hb_compVariableFind( HB_COMP_PARAM, szVarName, &iVar, &iScope );
   if( pVar )
   {
      if( HB_COMP_PARAM->functions.pLast->iEarlyEvalPass == 1 )
         hb_compCheckEarlyMacroEval( HB_COMP_PARAM, szVarName, iScope );

      switch( iScope )
      {
         case HB_VS_LOCAL_VAR:
         case HB_VS_CBLOCAL_VAR:
            /* local variable */
            hb_compGenPCode3( HB_P_PUSHLOCALREF, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ), HB_COMP_PARAM );
            break;

         case HB_VS_STATIC_VAR:
         case HB_VS_GLOBAL_STATIC:
            /* Static variable */
            hb_compGenPCode3( HB_P_PUSHSTATICREF, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ), HB_COMP_PARAM );
            HB_COMP_PARAM->functions.pLast->funFlags |= HB_FUNF_USES_STATICS;
            break;

         case HB_VS_LOCAL_FIELD:
         case HB_VS_GLOBAL_FIELD:
            /* pushing fields by reference is not allowed */
            hb_compErrorRefer( HB_COMP_PARAM, NULL, szVarName );
            break;

         case HB_VS_LOCAL_MEMVAR:
         case HB_VS_GLOBAL_MEMVAR:
            /* declared memvar variable */
            hb_compGenVarPCode( HB_P_PUSHMEMVARREF, szVarName, HB_COMP_PARAM );
            break;

         default:
            pVar = NULL;
      }
   }

   if( ! pVar )
   {
      /* undeclared variable */
      /* field cannot be passed by the reference - assume the memvar */
      hb_compGenVariablePCode( HB_COMP_PARAM, HB_P_PUSHMEMVARREF, szVarName );
   }
}

void hb_compGenPushMemvarRef( const char * szVarName, HB_COMP_DECL ) /* generates the pcode to push memvar variable by reference to the virtual machine stack */
{
   hb_compGenVarPCode( HB_P_PUSHMEMVARREF, szVarName, HB_COMP_PARAM );
}

/* generates the pcode to pop a value from the virtual machine stack onto
 * an aliased variable
 */
void hb_compGenPopAliasedVar( const char * szVarName,
                              HB_BOOL bPushAliasValue,
                              const char * szAlias,
                              HB_MAXINT nWorkarea,
                              HB_COMP_DECL )
{
   if( bPushAliasValue )
   {
      if( szAlias )
      {
         int iLen = ( int ) strlen( szAlias );
         if( szAlias[ 0 ] == 'M' && ( iLen == 1 ||
             ( iLen >= 4 && iLen <= 6 &&
               memcmp( szAlias, "MEMVAR", iLen ) == 0 ) ) )
         {
            /* M->variable or MEMV[A[R]]->variable */
            hb_compGenVarPCode( HB_P_POPMEMVAR, szVarName, HB_COMP_PARAM );
         }
         else if( iLen >= 4 && iLen <= 5 &&
                  memcmp( szAlias, "FIELD", iLen ) == 0 )
         {
            /* FIEL[D]->variable */
            hb_compGenVarPCode( HB_P_POPFIELD, szVarName, HB_COMP_PARAM );
         }
         else
         {
            /* database alias */
            hb_compGenPushSymbol( szAlias, HB_SYM_ALIAS, HB_COMP_PARAM );
            hb_compGenVarPCode( HB_P_POPALIASEDFIELD, szVarName, HB_COMP_PARAM );
         }
      }
      else
      {
         hb_compGenPushLong( nWorkarea, HB_COMP_PARAM );
         hb_compGenVarPCode( HB_P_POPALIASEDFIELD, szVarName, HB_COMP_PARAM );
      }
   }
   else
      /* Alias is already placed on stack
       * NOTE: An alias will be determined at runtime then we cannot decide
       * here if passed name is either a field or a memvar
       */
      hb_compGenVarPCode( HB_P_POPALIASEDVAR, szVarName, HB_COMP_PARAM );
}

/* generates the pcode to push an aliased variable value to the virtual
 * machine stack
 */
void hb_compGenPushAliasedVar( const char * szVarName,
                               HB_BOOL bPushAliasValue,
                               const char * szAlias,
                               HB_MAXINT nWorkarea,
                               HB_COMP_DECL )
{
   if( bPushAliasValue )
   {
      if( szAlias )
      {
         int iLen = ( int ) strlen( szAlias );
         /* myalias->var
          * FIELD->var
          * MEMVAR->var
          */
         if( szAlias[ 0 ] == 'M' && ( iLen == 1 ||
             ( iLen >= 4 && iLen <= 6 &&
               memcmp( szAlias, "MEMVAR", iLen ) == 0 ) ) )
         {
            /* M->variable or MEMV[A[R]]->variable */
            hb_compGenVarPCode( HB_P_PUSHMEMVAR, szVarName, HB_COMP_PARAM );
         }
         else if( iLen >= 4 && iLen <= 5 &&
                  memcmp( szAlias, "FIELD", iLen ) == 0 )
         {
            /* FIEL[D]->variable */
            hb_compGenVarPCode( HB_P_PUSHFIELD, szVarName, HB_COMP_PARAM );
         }
         else
         {
            /* database alias */
            hb_compGenPushSymbol( szAlias, HB_SYM_ALIAS, HB_COMP_PARAM );
            hb_compGenVarPCode( HB_P_PUSHALIASEDFIELD, szVarName, HB_COMP_PARAM );
         }
      }
      else
      {
         hb_compGenPushLong( nWorkarea, HB_COMP_PARAM );
         hb_compGenVarPCode( HB_P_PUSHALIASEDFIELD, szVarName, HB_COMP_PARAM );
      }
   }
   else
      /* Alias is already placed on stack
       * NOTE: An alias will be determined at runtime then we cannot decide
       * here if passed name is either a field or a memvar
       */
      hb_compGenVarPCode( HB_P_PUSHALIASEDVAR, szVarName, HB_COMP_PARAM );
}


void hb_compGenPushLogical( int iTrueFalse, HB_COMP_DECL ) /* pushes a logical value on the virtual machine stack */
{
   hb_compGenPCode1( ( HB_BYTE ) ( iTrueFalse ? HB_P_TRUE : HB_P_FALSE ), HB_COMP_PARAM );
}

void hb_compGenPushNil( HB_COMP_DECL )
{
   hb_compGenPCode1( HB_P_PUSHNIL, HB_COMP_PARAM );
}

/* generates the pcode to push a double number on the virtual machine stack */
void hb_compGenPushDouble( double dNumber, HB_BYTE bWidth, HB_BYTE bDec, HB_COMP_DECL )
{
   HB_BYTE pBuffer[ sizeof( double ) + sizeof( HB_BYTE ) + sizeof( HB_BYTE ) + 1 ];

   pBuffer[ 0 ] = HB_P_PUSHDOUBLE;
   HB_PUT_LE_DOUBLE( &( pBuffer[ 1 ] ), dNumber );

   pBuffer[ 1 + sizeof( double ) ] = bWidth;
   pBuffer[ 1 + sizeof( double ) + sizeof( HB_BYTE ) ] = bDec;

   hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), HB_COMP_PARAM );
}

void hb_compGenPushFunCall( const char * szFunName, int iFlags, HB_COMP_DECL )
{
   PHB_HSYMBOL pSym;
   HB_USHORT wSym;

   HB_SYMBOL_UNUSED( iFlags );

   pSym = hb_compSymbolFind( HB_COMP_PARAM, szFunName, &wSym, HB_SYM_FUNCNAME );
   if( ! pSym )
      pSym = hb_compSymbolAdd( HB_COMP_PARAM, szFunName, &wSym, HB_SYM_FUNCNAME );

   pSym->cScope |= HB_FS_USED;

   hb_compGenPCode3( HB_P_PUSHFUNCSYM, HB_LOBYTE( wSym ), HB_HIBYTE( wSym ), HB_COMP_PARAM );
}

void hb_compGenPushFunSym( const char * szFunName, int iFlags, HB_COMP_DECL )
{
   HB_SYMBOL_UNUSED( iFlags );
   hb_compGenPushSymbol( szFunName, HB_SYM_FUNCNAME, HB_COMP_PARAM );
}

void hb_compGenPushFunRef( const char * szFunName, HB_COMP_DECL )
{
   hb_compGenPushSymbol( szFunName, HB_SYM_FUNCNAME, HB_COMP_PARAM );
}

/* generates the pcode to push a symbol on the virtual machine stack */
void hb_compGenPushSymbol( const char * szSymbolName, HB_BOOL bFunction, HB_COMP_DECL )
{
   PHB_HSYMBOL pSym;
   HB_USHORT wSym;

   pSym = hb_compSymbolFind( HB_COMP_PARAM, szSymbolName, &wSym, bFunction );
   if( ! pSym )
      pSym = hb_compSymbolAdd( HB_COMP_PARAM, szSymbolName, &wSym, bFunction );

   if( bFunction )
      pSym->cScope |= HB_FS_USED;

   if( wSym > 255 )
      hb_compGenPCode3( HB_P_PUSHSYM, HB_LOBYTE( wSym ), HB_HIBYTE( wSym ), HB_COMP_PARAM );
   else
      hb_compGenPCode2( HB_P_PUSHSYMNEAR, ( HB_BYTE ) wSym, HB_COMP_PARAM );
}

/* generates the pcode to push a long number on the virtual machine stack */
void hb_compGenPushLong( HB_MAXINT nNumber, HB_COMP_DECL )
{
   if( ! HB_COMP_PARAM->fSwitchCase )
   {
      if( nNumber == 0 )
         hb_compGenPCode1( HB_P_ZERO, HB_COMP_PARAM );
      else if( nNumber == 1 )
         hb_compGenPCode1( HB_P_ONE, HB_COMP_PARAM );
      else if( HB_LIM_INT8( nNumber ) )
         hb_compGenPCode2( HB_P_PUSHBYTE, ( HB_BYTE ) nNumber, HB_COMP_PARAM );
      else if( HB_LIM_INT16( nNumber ) )
         hb_compGenPCode3( HB_P_PUSHINT, HB_LOBYTE( nNumber ), HB_HIBYTE( nNumber ), HB_COMP_PARAM );
      else if( HB_LIM_INT32( nNumber ) )
      {
         HB_BYTE pBuffer[ 5 ];
         pBuffer[ 0 ] = HB_P_PUSHLONG;
         HB_PUT_LE_UINT32( pBuffer + 1, nNumber );
         hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), HB_COMP_PARAM );
      }
      else
      {
         HB_BYTE pBuffer[ 9 ];
         pBuffer[ 0 ] = HB_P_PUSHLONGLONG;
         HB_PUT_LE_UINT64( pBuffer + 1, nNumber );
         hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), HB_COMP_PARAM );
      }
   }
   else
   {
      if( HB_LIM_INT32( nNumber ) )
      {
         HB_BYTE pBuffer[ 5 ];
         pBuffer[ 0 ] = HB_P_PUSHLONG;
         HB_PUT_LE_UINT32( pBuffer + 1, nNumber );
         hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), HB_COMP_PARAM );
      }
      else
      {
         HB_BYTE pBuffer[ 9 ];
         pBuffer[ 0 ] = HB_P_PUSHLONGLONG;
         HB_PUT_LE_UINT64( pBuffer + 1, nNumber );
         hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), HB_COMP_PARAM );
      }
   }
}

void hb_compGenPushDate( long lDate, HB_COMP_DECL )
{
   HB_BYTE pBuffer[ 5 ];

   pBuffer[ 0 ] = HB_P_PUSHDATE;
   HB_PUT_LE_UINT32( pBuffer + 1, lDate );
   hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), HB_COMP_PARAM );
}

void hb_compGenPushTimeStamp( long lDate, long lTime, HB_COMP_DECL )
{
   HB_BYTE pBuffer[ 9 ];

   pBuffer[ 0 ] = HB_P_PUSHTIMESTAMP;
   HB_PUT_LE_UINT32( pBuffer + 1, lDate );
   HB_PUT_LE_UINT32( pBuffer + 5, lTime );
   hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), HB_COMP_PARAM );
}

/* generates the pcode to push a string on the virtual machine stack */
void hb_compGenPushString( const char * szText, HB_SIZE nStrLen, HB_COMP_DECL )
{
   if( HB_COMP_PARAM->iHidden && ! HB_COMP_PARAM->fSwitchCase )
   {
      char * szTemp;
      --nStrLen;
      szTemp = hb_compEncodeString( HB_COMP_PARAM->iHidden, szText, &nStrLen );
      if( nStrLen > UINT16_MAX )
         hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_STRING_TOO_LONG, NULL, NULL );
      else
      {
         hb_compGenPCode4( HB_P_PUSHSTRHIDDEN, ( HB_BYTE ) HB_COMP_PARAM->iHidden,
                           HB_LOBYTE( nStrLen ), HB_HIBYTE( nStrLen ), HB_COMP_PARAM );
         hb_compGenPCodeN( ( HB_BYTE * ) szTemp, nStrLen, HB_COMP_PARAM );
      }
      hb_xfree( szTemp );
   }
   else
   {
      if( nStrLen > UINT24_MAX )
         hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_STRING_TOO_LONG, NULL, NULL );
      else
      {
         if( nStrLen > USHRT_MAX )
            hb_compGenPCode4( HB_P_PUSHSTRLARGE, HB_LOBYTE( nStrLen ), HB_HIBYTE( nStrLen ), HB_ULBYTE( nStrLen ), HB_COMP_PARAM );
         else if( nStrLen > UCHAR_MAX )
            hb_compGenPCode3( HB_P_PUSHSTR, HB_LOBYTE( nStrLen ), HB_HIBYTE( nStrLen ), HB_COMP_PARAM );
         else
            hb_compGenPCode2( HB_P_PUSHSTRSHORT, ( HB_BYTE ) nStrLen, HB_COMP_PARAM );
         hb_compGenPCodeN( ( const HB_BYTE * ) szText, nStrLen, HB_COMP_PARAM );
      }
   }
}

void hb_compNOOPfill( PHB_HFUNC pFunc, HB_SIZE nFrom, HB_ISIZ nCount, HB_BOOL fPop, HB_BOOL fCheck )
{
   while( nCount-- )
   {
      if( fPop )
      {
         pFunc->pCode[ nFrom ] = HB_P_POP;
         fPop = HB_FALSE;
      }
      else if( fCheck && pFunc->pCode[ nFrom ] == HB_P_NOOP && pFunc->nNOOPs )
      {
         HB_SIZE n;

         for( n = 0; n < pFunc->nNOOPs; ++n )
         {
            if( pFunc->pNOOPs[ n ] == nFrom )
               break;
         }
         if( n == pFunc->nNOOPs )
            hb_compNOOPadd( pFunc, nFrom );
      }
      else
         hb_compNOOPadd( pFunc, nFrom );
      ++nFrom;
   }
}

/*
 * Warning - when jump optimization is disabled this function can be used
 * _ONLY_ in very limited situations when there is no jumps over the
 * removed block
 */
static void hb_compRemovePCODE( HB_COMP_DECL, HB_SIZE nPos, HB_SIZE nCount,
                                HB_BOOL fCanMove )
{
   PHB_HFUNC pFunc = HB_COMP_PARAM->functions.pLast;

   if( HB_COMP_ISSUPPORTED( HB_COMPFLAG_OPTJUMP ) || ! fCanMove )
   {
      /*
       * We can safely remove the dead code when Jump Optimization
       * is enabled by replacing it with HB_P_NOOP opcodes - which
       * will be later eliminated and jump data updated.
       */
      hb_compNOOPfill( pFunc, nPos, nCount, HB_FALSE, HB_TRUE );
   }
   else
   {
      HB_SIZE n;

      memmove( pFunc->pCode + nPos, pFunc->pCode + nPos + nCount,
               pFunc->nPCodePos - nPos - nCount );
      pFunc->nPCodePos -= nCount;

      for( n = pFunc->nNOOPs; n; --n )
      {
         if( pFunc->pNOOPs[ n ] >= nPos )
         {
            if( pFunc->pNOOPs[ n ] < nPos + nCount )
            {
               memmove( &pFunc->pNOOPs[ n ], &pFunc->pNOOPs[ n + 1 ],
                        pFunc->nNOOPs - n );
               pFunc->nNOOPs--;
            }
            else
            {
               pFunc->pNOOPs[ n ] -= nCount;
            }
         }
      }
   }
}

HB_BOOL hb_compHasJump( PHB_HFUNC pFunc, HB_SIZE nPos )
{
   HB_SIZE nJump;

   for( nJump = 0; nJump < pFunc->nJumps; nJump++ )
   {
      HB_SIZE nJumpAddr = pFunc->pJumps[ nJump ];
      switch( pFunc->pCode[ nJumpAddr ] )
      {
         case HB_P_JUMPNEAR:
         case HB_P_JUMPFALSENEAR:
         case HB_P_JUMPTRUENEAR:
            nJumpAddr += ( signed char ) pFunc->pCode[ nJumpAddr + 1 ];
            break;

         case HB_P_JUMP:
         case HB_P_JUMPFALSE:
         case HB_P_JUMPTRUE:
            nJumpAddr += HB_PCODE_MKSHORT( &pFunc->pCode[ nJumpAddr + 1 ] );
            break;

         /* Jump can be replaced by series of NOOPs or POP and NOOPs
          * and not stripped yet
          */
         case HB_P_NOOP:
         case HB_P_POP:
            nJumpAddr = nPos + 1;
            break;

         default:
            nJumpAddr += HB_PCODE_MKINT24( &pFunc->pCode[ nJumpAddr + 1 ] );
            break;
      }
      if( nJumpAddr == nPos )
         return HB_TRUE;
   }

   return HB_FALSE;
}

/* Generate the opcode to open BEGIN/END sequence
 * This code is similar to JUMP opcode - the offset will be filled with
 * - either the address of HB_P_SEQEND opcode if there is no RECOVER clause
 * - or the address of RECOVER code
 */
HB_SIZE hb_compSequenceBegin( HB_COMP_DECL )
{
   hb_compGenPCode4( HB_P_SEQALWAYS, 0, 0, 0, HB_COMP_PARAM );
   hb_compPrepareJumps( HB_COMP_PARAM );

   hb_compGenPCode4( HB_P_SEQBEGIN, 0, 0, 0, HB_COMP_PARAM );
   hb_compPrepareJumps( HB_COMP_PARAM );

   return HB_COMP_PARAM->functions.pLast->nPCodePos - 3;
}

/* Generate the opcode to close BEGIN/END sequence
 * This code is similar to JUMP opcode - the offset will be filled with
 * the address of first line after END SEQUENCE
 * This opcode will be executed if recover code was not requested (as the
 * last statement in code between BEGIN ... RECOVER) or if BREAK was requested
 * and there was no matching RECOVER clause.
 */
HB_SIZE hb_compSequenceEnd( HB_COMP_DECL )
{
   hb_compGenPCode4( HB_P_SEQEND, 0, 0, 0, HB_COMP_PARAM );

   hb_compPrepareJumps( HB_COMP_PARAM );

   return HB_COMP_PARAM->functions.pLast->nPCodePos - 3;
}

HB_SIZE hb_compSequenceAlways( HB_COMP_DECL )
{
   hb_compGenPCode4( HB_P_ALWAYSBEGIN, 0, 0, 0, HB_COMP_PARAM );

   hb_compPrepareJumps( HB_COMP_PARAM );

   return HB_COMP_PARAM->functions.pLast->nPCodePos - 3;
}

/* Remove unnecessary opcodes in case there were no executable statements
 * between BEGIN and RECOVER sequence
 */
void hb_compSequenceFinish( HB_COMP_DECL, HB_SIZE nStartPos, HB_SIZE nEndPos,
                            HB_SIZE nAlways, HB_BOOL fUsualStmts, HB_BOOL fRecover,
                            HB_BOOL fCanMove )
{
   --nStartPos;  /* HB_P_SEQBEGIN address */

   if( ! fUsualStmts && fCanMove && ! HB_COMP_PARAM->fDebugInfo )
   {
      nStartPos -= 4;
      if( nAlways )
      {
         /* remove HB_P_ALWAYSEND opcode */
         HB_COMP_PARAM->functions.pLast->nPCodePos--;
         /* remove HB_P_SEQALWAYS ... HB_P_ALWAYSBEGIN opcodes */
         hb_compRemovePCODE( HB_COMP_PARAM, nStartPos,
                             nAlways - nStartPos + 4, fCanMove );
      }
      else
      {
         hb_compRemovePCODE( HB_COMP_PARAM, nStartPos,
                             HB_COMP_PARAM->functions.pLast->nPCodePos -
                             nStartPos, fCanMove );
      }
   }
   else if( ! nAlways )
   {
      /* remove HB_P_SEQALWAYS opcode */
      hb_compRemovePCODE( HB_COMP_PARAM, nStartPos - 4, 4, fCanMove );
   }
   else
   {
      if( ! fRecover )
      {
         /* remove HB_P_SEQBEGIN and HB_P_SEQEND */
         hb_compRemovePCODE( HB_COMP_PARAM, nEndPos - 1, 4, fCanMove );
         hb_compRemovePCODE( HB_COMP_PARAM, nStartPos, 4, fCanMove );
         if( ! HB_COMP_ISSUPPORTED( HB_COMPFLAG_OPTJUMP ) )
         {
            /* Fix ALWAYS address in HB_P_SEQALWAYS opcode */
            nAlways -= 8;
            hb_compGenJumpThere( nStartPos - 3, nAlways, HB_COMP_PARAM );
         }
      }
      /* empty always block? */
      if( HB_COMP_PARAM->functions.pLast->nPCodePos - nAlways == 5 &&
          ! HB_COMP_PARAM->fDebugInfo )
      {
         /* remove HB_P_ALWAYSBEGIN and HB_P_ALWAYSEND opcodes */
         hb_compRemovePCODE( HB_COMP_PARAM, nAlways, 5, HB_TRUE );
         /* remove HB_P_SEQALWAYS opcode */
         hb_compRemovePCODE( HB_COMP_PARAM, nStartPos - 4, 4, fCanMove );
      }
   }
}

/*
 * Start of definition of static variable
 * We are using here the special function HB_COMP_PARAM->pInitFunc which will store
 * pcode needed to initialize all static variables declared in PRG module.
 * pOwner member will point to a function where the static variable is
 * declared:
 */
void hb_compStaticDefStart( HB_COMP_DECL )
{
   HB_COMP_PARAM->functions.pLast->funFlags |= HB_FUNF_USES_STATICS;
   if( ! HB_COMP_PARAM->pInitFunc )
   {
      HB_BYTE pBuffer[ 5 ];

      HB_COMP_PARAM->pInitFunc = hb_compFunctionNew( HB_COMP_PARAM, "(_INITSTATICS)", HB_FS_INITEXIT | HB_FS_LOCAL );
      HB_COMP_PARAM->pInitFunc->pOwner = HB_COMP_PARAM->functions.pLast;
      HB_COMP_PARAM->pInitFunc->funFlags = HB_FUNF_USES_STATICS | HB_FUNF_PROCEDURE;
      HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pInitFunc;

      pBuffer[ 0 ] = HB_P_STATICS;
      pBuffer[ 1 ] = 0;
      pBuffer[ 2 ] = 0;
      pBuffer[ 3 ] = 1; /* the number of static variables is unknown now */
      pBuffer[ 4 ] = 0;

      hb_compGenPCodeN( pBuffer, 5, HB_COMP_PARAM );

      hb_compGenPCode3( HB_P_SFRAME, 0, 0, HB_COMP_PARAM );     /* frame for statics variables */

      if( HB_COMP_PARAM->fDebugInfo )
      {
         /* uncomment this if you want to always set main module name
            not the one where first static variable was declared */
         #if 0
         HB_COMP_PARAM->currModule = HB_COMP_PARAM->szFile;
         #endif
         hb_compGenModuleName( HB_COMP_PARAM, HB_COMP_PARAM->pInitFunc->szName );
      }
   }
   else
   {
      HB_COMP_PARAM->pInitFunc->pOwner = HB_COMP_PARAM->functions.pLast;
      HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pInitFunc;
   }
}

/*
 * End of definition of static variable
 * Return to previously pcoded function.
 */
void hb_compStaticDefEnd( HB_COMP_DECL, const char * szVarName )
{
   HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pInitFunc->pOwner;
   HB_COMP_PARAM->pInitFunc->pOwner = NULL;
   if( HB_COMP_PARAM->fDebugInfo )
   {
      HB_BYTE bGlobal = 0;
      int iVar;

      if( ( HB_COMP_PARAM->functions.pLast->funFlags & HB_FUNF_FILE_DECL ) != 0 )
      {
         /* Variable declaration is outside of function/procedure body.
          * File-wide static variable
          */
         HB_COMP_PARAM->pInitFunc->pOwner = HB_COMP_PARAM->functions.pLast;
         HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pInitFunc;
         bGlobal = 1;
      }

      iVar = HB_COMP_PARAM->iStaticCnt;
      hb_compGenPCode4( HB_P_STATICNAME, bGlobal, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ), HB_COMP_PARAM );
      hb_compGenPCodeN( ( const HB_BYTE * ) szVarName, strlen( szVarName ) + 1, HB_COMP_PARAM );
      if( bGlobal )
      {
         HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pInitFunc->pOwner;
         HB_COMP_PARAM->pInitFunc->pOwner = NULL;
      }
   }
}

/*
 * Mark thread static variables
 */
static void hb_compStaticDefThreadSet( HB_COMP_DECL )
{
   if( HB_COMP_PARAM->pInitFunc )
   {
      HB_USHORT uiCount = 0;
      PHB_HFUNC pFunc;
      PHB_HVAR pVar;

      pFunc = HB_COMP_PARAM->functions.pFirst;
      while( pFunc )
      {
         pVar = pFunc->pStatics;
         while( pVar )
         {
            if( pVar->uiFlags & HB_VSCOMP_THREAD )
               ++uiCount;
            pVar = pVar->pNext;
         }
         pFunc = pFunc->pNext;
      }

      if( uiCount )
      {
         HB_SIZE nSize = ( ( HB_SIZE ) uiCount << 1 ) + 3;
         HB_BYTE * pBuffer = ( HB_BYTE * ) hb_xgrab( nSize ), *ptr;
         HB_USHORT uiVar = 0;
         pBuffer[ 0 ] = HB_P_THREADSTATICS;
         pBuffer[ 1 ] = HB_LOBYTE( uiCount );
         pBuffer[ 2 ] = HB_HIBYTE( uiCount );
         ptr = pBuffer + 3;
         pFunc = HB_COMP_PARAM->functions.pFirst;
         while( pFunc && uiCount )
         {
            pVar = pFunc->pStatics;
            while( pVar && uiCount )
            {
               ++uiVar;
               if( pVar->uiFlags & HB_VSCOMP_THREAD )
               {
                  HB_PUT_LE_UINT16( ptr, uiVar );
                  ptr += 2;
                  --uiCount;
               }
               pVar = pVar->pNext;
            }
            pFunc = pFunc->pNext;
         }

         HB_COMP_PARAM->pInitFunc->pOwner = HB_COMP_PARAM->functions.pLast;
         HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pInitFunc;

         hb_compGenPCodeN( pBuffer, nSize, HB_COMP_PARAM );

         HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pInitFunc->pOwner;
         HB_COMP_PARAM->pInitFunc->pOwner = NULL;

         hb_xfree( pBuffer );
      }
   }
}

/*
 * Start of stop line number info generation
 */
static void hb_compLineNumberDefStart( HB_COMP_DECL )
{
   if( ! HB_COMP_PARAM->pLineFunc )
   {
      HB_COMP_PARAM->pLineFunc = hb_compFunctionNew( HB_COMP_PARAM, "(_INITLINES)", HB_FS_INITEXIT | HB_FS_LOCAL );
      HB_COMP_PARAM->pLineFunc->pOwner = HB_COMP_PARAM->functions.pLast;
      HB_COMP_PARAM->pLineFunc->funFlags = 0;
      HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pLineFunc;

      if( HB_COMP_PARAM->fDebugInfo )
      {
         /* set main module name */
         HB_COMP_PARAM->currModule = HB_COMP_PARAM->szFile;
         hb_compGenModuleName( HB_COMP_PARAM, HB_COMP_PARAM->pLineFunc->szName );
      }
   }
   else
   {
      HB_COMP_PARAM->pLineFunc->pOwner = HB_COMP_PARAM->functions.pLast;
      HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pLineFunc;
   }
}

/*
 * End of stop line number info generation
 * Return to previously pcoded function.
 */
static void hb_compLineNumberDefEnd( HB_COMP_DECL )
{
   HB_COMP_PARAM->functions.pLast = HB_COMP_PARAM->pLineFunc->pOwner;
   HB_COMP_PARAM->pLineFunc->pOwner = NULL;
}

/*
 * Start a new fake-function that will hold pcodes for a codeblock
 */
void hb_compCodeBlockStart( HB_COMP_DECL, int iEarlyEvalPass )
{
   PHB_HFUNC pBlock;

   pBlock                  = hb_compFunctionNew( HB_COMP_PARAM, NULL, HB_FS_STATIC | HB_FS_LOCAL );
   pBlock->pOwner          = HB_COMP_PARAM->functions.pLast;
   pBlock->iEarlyEvalPass  = iEarlyEvalPass;

   HB_COMP_PARAM->functions.pLast = pBlock;
}

void hb_compCodeBlockEnd( HB_COMP_DECL )
{
   PHB_HFUNC pCodeblock;   /* pointer to the current codeblock */
   PHB_HFUNC pFunc;        /* pointer to a function that owns a codeblock */
   const char * pFuncName;
   HB_SIZE nSize;
   HB_USHORT wLocals = 0;  /* number of referenced local variables */
   HB_USHORT wLocalsCnt, wLocalsLen;
   PHB_HVAR pVar;

   pCodeblock = HB_COMP_PARAM->functions.pLast;

   /* Check if the extended codeblock has return statement */
   if( ( pCodeblock->funFlags & HB_FUNF_EXTBLOCK ) )
   {
      if( !( pCodeblock->funFlags & HB_FUNF_WITH_RETURN ) )
      {
         if( HB_COMP_PARAM->iWarnings >= 1 )
            hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_FUN_WITH_NO_RETURN,
                               "{||...}", NULL );
         /* finish the codeblock without popping the return value from HVM stack */
         hb_compGenPCode1( HB_P_ENDPROC, HB_COMP_PARAM );
      }
   }

   hb_compGenPCode1( HB_P_ENDBLOCK, HB_COMP_PARAM ); /* finish the codeblock */

   if( ! pCodeblock->bError )
   {
      if( pCodeblock->wParamCount && !( pCodeblock->funFlags & HB_FUNF_USES_LOCAL_PARAMS ) )
         /* PARAMETERs were used after LOCALs in extended codeblock
          * fix generated local indexes
          */
         hb_compFixFuncPCode( HB_COMP_PARAM, pCodeblock );
      hb_compOptimizeJumps( HB_COMP_PARAM );
   }

   /* return to pcode buffer of function/codeblock in which the current
    * codeblock was defined
    */
   HB_COMP_PARAM->functions.pLast = pCodeblock->pOwner;

   /* find the function that owns the codeblock */
   pFunc = pCodeblock->pOwner;
   pFuncName = pFunc->szName;
   while( pFunc->pOwner )
   {
      pFunc = pFunc->pOwner;
      if( pFunc->szName && *pFunc->szName )
         pFuncName = pFunc->szName;
   }
   if( *pFuncName == 0 )
      pFuncName = "(_INITSTATICS)";
   pFunc->funFlags |= ( pCodeblock->funFlags & HB_FUNF_USES_STATICS );

   /* generate a proper codeblock frame with a codeblock size and with
    * a number of expected parameters
    */

   /* Count the number of referenced local variables */
   wLocalsLen = 0;
   pVar = pCodeblock->pDetached;
   while( pVar )
   {
      if( HB_COMP_PARAM->fDebugInfo )
         wLocalsLen += 4 + ( HB_USHORT ) strlen( pVar->szName );
      pVar = pVar->pNext;
      ++wLocals;
   }
   wLocalsCnt = wLocals;

   nSize = pCodeblock->nPCodePos + 2;
   if( HB_COMP_PARAM->fDebugInfo )
   {
      nSize += 3 + strlen( HB_COMP_PARAM->currModule ) + strlen( pFuncName );
      nSize += wLocalsLen;
   }

   if( nSize <= 255 && pCodeblock->wParamCount == 0 && wLocals == 0 )
   {
      /* NOTE: 2 = HB_P_PUSHBLOCK + HB_BYTE( size ) */
      hb_compGenPCode2( HB_P_PUSHBLOCKSHORT, ( HB_BYTE ) nSize, HB_COMP_PARAM );
   }
   else
   {
      /* NOTE: 8 = HB_P_PUSHBLOCK + HB_USHORT( size ) + HB_USHORT( wParams ) + HB_USHORT( wLocals ) + _ENDBLOCK */
      nSize += 5 + wLocals * 2;
      if( nSize <= USHRT_MAX )
         hb_compGenPCode3( HB_P_PUSHBLOCK, HB_LOBYTE( nSize ), HB_HIBYTE( nSize ), HB_COMP_PARAM );
      else if( nSize < UINT24_MAX )
      {
         ++nSize;
         hb_compGenPCode4( HB_P_PUSHBLOCKLARGE, HB_LOBYTE( nSize ), HB_HIBYTE( nSize ), HB_ULBYTE( nSize ), HB_COMP_PARAM );
      }
      else
         hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_BLOCK_TOO_BIG, NULL, NULL );

      /* generate the number of local parameters */
      hb_compGenPCode2( HB_LOBYTE( pCodeblock->wParamCount ), HB_HIBYTE( pCodeblock->wParamCount ), HB_COMP_PARAM );
      /* generate the number of referenced local variables */
      hb_compGenPCode2( HB_LOBYTE( wLocals ), HB_HIBYTE( wLocals ), HB_COMP_PARAM );

      /* generate the table of referenced local variables */
      pVar = pCodeblock->pDetached;
      while( wLocals-- )
      {
         HB_USHORT wPos = hb_compVariableGetPos( pFunc->pLocals, pVar->szName );
         hb_compGenPCode2( HB_LOBYTE( wPos ), HB_HIBYTE( wPos ), HB_COMP_PARAM );
         pVar = pVar->pNext;
      }
   }

   if( HB_COMP_PARAM->fDebugInfo )
   {
      int iLocalPos;

      hb_compGenModuleName( HB_COMP_PARAM, pFuncName );

      /* generate the name of referenced local variables */
      pVar = pCodeblock->pDetached;
      iLocalPos = -1;
      while( wLocalsCnt-- )
      {
         hb_compGenPCode3( HB_P_LOCALNAME, HB_LOBYTE( iLocalPos ), HB_HIBYTE( iLocalPos ), HB_COMP_PARAM );
         hb_compGenPCodeN( ( const HB_BYTE * ) pVar->szName, strlen( pVar->szName ) + 1, HB_COMP_PARAM );
         iLocalPos--;
         pVar = pVar->pNext;
      }

   }

   hb_compGenPCodeN( pCodeblock->pCode, pCodeblock->nPCodePos, HB_COMP_PARAM );

   if( HB_COMP_PARAM->iWarnings )
   {
      pVar = pCodeblock->pLocals;
      while( pVar )
      {
         if( HB_COMP_PARAM->iWarnings && pVar->szName && ! ( pVar->iUsed & HB_VU_USED ) )
            hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_BLOCKVAR_NOT_USED, pVar->szName, pFuncName );
         pVar = pVar->pNext;
      }
      pVar = pCodeblock->pStatics;
      while( pVar )
      {
         if( HB_COMP_PARAM->iWarnings && pVar->szName && ! ( pVar->iUsed & HB_VU_USED ) )
            hb_compWarnUnusedVar( HB_COMP_PARAM, "{||...}", pVar->szName, pVar->iDeclLine );
         pVar = pVar->pNext;
      }
   }

   /* move static variables to owner */
   pVar = pFunc->pStatics;
   if( pVar )
   {
      while( pVar->pNext )
         pVar = pVar->pNext;
      pVar->pNext = pCodeblock->pStatics;
   }
   else
      pFunc->pStatics = pCodeblock->pStatics;
   pVar = pCodeblock->pStatics;
   pCodeblock->pStatics = NULL;
   /* change static variables names to avoid conflicts */
   while( pVar )
   {
      char szName[ HB_SYMBOL_NAME_LEN + 4 ];
      hb_snprintf( szName, sizeof( szName ), "%s(b)", pVar->szName );
      pVar->szName = hb_compIdentifierNew( HB_COMP_PARAM, szName, HB_IDENT_COPY );
      pVar = pVar->pNext;
   }

   hb_compFunctionKill( HB_COMP_PARAM, pCodeblock );
}

void hb_compCodeBlockStop( HB_COMP_DECL )
{
   PHB_HFUNC pCodeblock;   /* pointer to the current codeblock */

   pCodeblock = HB_COMP_PARAM->functions.pLast;

   /* return to pcode buffer of function/codeblock in which the current
    * codeblock was defined
    */
   HB_COMP_PARAM->functions.pLast = pCodeblock->pOwner;
   hb_compGenPCodeN( pCodeblock->pCode, pCodeblock->nPCodePos, HB_COMP_PARAM );

   if( HB_COMP_PARAM->iWarnings )
   {
      PHB_HVAR pVar = pCodeblock->pLocals;
      /* find the function that owns the codeblock */
      PHB_HFUNC pFunc = pCodeblock->pOwner;
      while( pFunc->pOwner )
         pFunc = pFunc->pOwner;
      while( pVar )
      {
         if( pFunc->szName && pVar->szName && ! ( pVar->iUsed & HB_VU_USED ) )
            hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_BLOCKVAR_NOT_USED, pVar->szName, pFunc->szName );
         pVar = pVar->pNext;
      }
   }

   hb_compFunctionKill( HB_COMP_PARAM, pCodeblock );
}

void hb_compCodeBlockRewind( HB_COMP_DECL )
{
   PHB_HFUNC pCodeblock;   /* pointer to the current codeblock */

   pCodeblock = HB_COMP_PARAM->functions.pLast;
   pCodeblock->nPCodePos = 0;

   /* Release the NOOP array. */
   if( pCodeblock->pNOOPs )
   {
      hb_xfree( pCodeblock->pNOOPs );
      pCodeblock->pNOOPs = NULL;
      pCodeblock->nNOOPs = 0;
   }
   /* Release the Jumps array. */
   if( pCodeblock->pJumps )
   {
      hb_xfree( pCodeblock->pJumps );
      pCodeblock->pJumps = NULL;
      pCodeblock->nJumps = 0;
   }
   while( pCodeblock->pDetached )
   {
      PHB_HVAR pVar = pCodeblock->pDetached;
      pCodeblock->pDetached = pVar->pNext;
      hb_xfree( pVar );
   }
   while( pCodeblock->pLocals )
   {
      PHB_HVAR pVar = pCodeblock->pLocals;
      pCodeblock->pLocals = pVar->pNext;
      hb_xfree( pVar );
   }
}

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

/* initialize support variables */
static void hb_compInitVars( HB_COMP_DECL )
{
   HB_COMP_PARAM->functions.iCount = 0;
   HB_COMP_PARAM->functions.pFirst = NULL;
   HB_COMP_PARAM->functions.pLast  = NULL;
   HB_COMP_PARAM->szAnnounce       = NULL;
   HB_COMP_PARAM->fSwitchCase      = HB_FALSE;

   HB_COMP_PARAM->symbols.iCount   = 0;
   HB_COMP_PARAM->symbols.pFirst   = NULL;
   HB_COMP_PARAM->symbols.pLast    = NULL;
   HB_COMP_PARAM->pInitFunc        = NULL;
   HB_COMP_PARAM->pLineFunc        = NULL;
   HB_COMP_PARAM->pDeclFunc        = NULL;

   HB_COMP_PARAM->iStaticCnt       = 0;
   HB_COMP_PARAM->iVarScope        = HB_VSCOMP_LOCAL;

   HB_COMP_PARAM->inlines.iCount   = 0;
   HB_COMP_PARAM->inlines.pFirst   = NULL;
   HB_COMP_PARAM->inlines.pLast    = NULL;

   HB_COMP_PARAM->szFile           = NULL;

   HB_COMP_PARAM->iModulesCount    = 0;
}

static void hb_compGenOutput( HB_COMP_DECL, int iLanguage )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_compGenOutput()" ) );

   switch( iLanguage )
   {
      case HB_LANG_C:
         hb_compGenCCode( HB_COMP_PARAM, HB_COMP_PARAM->pFileName );
         break;

      case HB_LANG_PORT_OBJ:
         hb_compGenPortObj( HB_COMP_PARAM, HB_COMP_PARAM->pFileName );
         break;

      case HB_LANG_PORT_OBJ_BUF:
         if( HB_COMP_PARAM->pOutBuf )
            hb_xfree( HB_COMP_PARAM->pOutBuf );
         hb_compGenBufPortObj( HB_COMP_PARAM, &HB_COMP_PARAM->pOutBuf, &HB_COMP_PARAM->nOutBufSize );
         break;
   }
}

static void hb_compPpoFile( HB_COMP_DECL, const char * szPrg, const char * szExt,
                            char * szPpoName )
{
   PHB_FNAME pFilePpo = hb_fsFNameSplit( szPrg );

   pFilePpo->szExtension = szExt;
   if( HB_COMP_PARAM->pPpoPath )
   {
      pFilePpo->szPath = HB_COMP_PARAM->pPpoPath->szPath;
      if( HB_COMP_PARAM->pPpoPath->szName )
      {
         pFilePpo->szName = HB_COMP_PARAM->pPpoPath->szName;
         pFilePpo->szExtension = HB_COMP_PARAM->pPpoPath->szExtension;
      }
   }
   hb_fsFNameMerge( szPpoName, pFilePpo );
   hb_xfree( pFilePpo );
}

static void hb_compOutputFile( HB_COMP_DECL )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_compOutputFile()" ) );

   HB_COMP_PARAM->pFileName->szPath = NULL;
   HB_COMP_PARAM->pFileName->szExtension = NULL;

   /* we create the output file name */
   if( HB_COMP_PARAM->pOutPath )
   {
      if( HB_COMP_PARAM->pOutPath->szPath )
         HB_COMP_PARAM->pFileName->szPath = HB_COMP_PARAM->pOutPath->szPath;

      if( HB_COMP_PARAM->pOutPath->szName )
      {
         HB_COMP_PARAM->pFileName->szName = HB_COMP_PARAM->pOutPath->szName;
         if( HB_COMP_PARAM->pOutPath->szExtension )
            HB_COMP_PARAM->pFileName->szExtension = HB_COMP_PARAM->pOutPath->szExtension;
      }
   }
}

static void hb_compAddInitFunc( HB_COMP_DECL, PHB_HFUNC pFunc )
{
   PHB_HSYMBOL pSym = hb_compSymbolAdd( HB_COMP_PARAM, pFunc->szName, NULL, HB_SYM_FUNCNAME );

   pSym->cScope |= pFunc->cScope;
   pSym->pFunc = pFunc;
   pFunc->funFlags |= HB_FUNF_ATTACHED;
   hb_compAddFunc( HB_COMP_PARAM, pFunc );
   hb_compGenPCode1( HB_P_ENDPROC, HB_COMP_PARAM );
}

void hb_compModuleAdd( HB_COMP_DECL, const char * szModuleName, HB_BOOL fForce )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_compModuleAdd(%s,%d)", szModuleName, fForce ) );

   if( ! HB_COMP_PARAM->fSingleModule || fForce )
   {
      PHB_MODULE * pModule = &HB_COMP_PARAM->modules;

      while( *pModule )
      {
         if( hb_stricmp( ( *pModule )->szName, szModuleName ) == 0 )
            return;
         pModule = &( *pModule )->pNext;
      }

      *pModule = ( PHB_MODULE ) hb_xgrab( sizeof( HB_MODULE ) );
      ( *pModule )->szName = szModuleName;
      ( *pModule )->force = fForce;
      ( *pModule )->pNext = NULL;
   }
}

void hb_compCompileEnd( HB_COMP_DECL )
{
   if( HB_COMP_PARAM->pFileName )
   {
      hb_xfree( HB_COMP_PARAM->pFileName );
      HB_COMP_PARAM->pFileName = NULL;
   }

   while( HB_COMP_PARAM->functions.pLast &&
          ! HB_COMP_PARAM->functions.pLast->szName )
   {
      PHB_HFUNC pFunc = HB_COMP_PARAM->functions.pLast;
      HB_COMP_PARAM->functions.pLast = pFunc->pOwner;
      hb_compFunctionKill( HB_COMP_PARAM, pFunc );
   }
   HB_COMP_PARAM->functions.pLast = NULL;

   if( HB_COMP_PARAM->pInitFunc &&
       ( HB_COMP_PARAM->pInitFunc->funFlags & HB_FUNF_ATTACHED ) == 0 )
   {
      hb_compFunctionKill( HB_COMP_PARAM, HB_COMP_PARAM->pInitFunc );
   }
   HB_COMP_PARAM->pInitFunc = NULL;

   if( HB_COMP_PARAM->functions.pFirst )
   {
      PHB_HFUNC pFunc = HB_COMP_PARAM->functions.pFirst;

      while( pFunc )
         pFunc = hb_compFunctionKill( HB_COMP_PARAM, pFunc );
      HB_COMP_PARAM->functions.pFirst = NULL;
   }

   while( HB_COMP_PARAM->externs )
   {
      PHB_HEXTERN pExtern = HB_COMP_PARAM->externs;

      HB_COMP_PARAM->externs = pExtern->pNext;
      hb_xfree( pExtern );
   }

   while( HB_COMP_PARAM->modules )
   {
      PHB_MODULE pModule = HB_COMP_PARAM->modules;

      HB_COMP_PARAM->modules = pModule->pNext;
      hb_xfree( pModule );
   }

   while( HB_COMP_PARAM->incfiles )
   {
      PHB_INCLST pIncFile = HB_COMP_PARAM->incfiles;

      HB_COMP_PARAM->incfiles = pIncFile->pNext;
      hb_xfree( pIncFile );
   }

   while( HB_COMP_PARAM->ppdefines )
   {
      PHB_PPDEFINE pDefine = HB_COMP_PARAM->ppdefines;

      HB_COMP_PARAM->ppdefines = pDefine->pNext;
      hb_xfree( pDefine->szName );
      hb_xfree( pDefine );
   }

   while( HB_COMP_PARAM->inlines.pFirst )
   {
      PHB_HINLINE pInline = HB_COMP_PARAM->inlines.pFirst;

      HB_COMP_PARAM->inlines.pFirst = pInline->pNext;
      if( pInline->pCode )
         hb_xfree( pInline->pCode );
      hb_xfree( pInline );
   }

   while( HB_COMP_PARAM->symbols.pFirst )
   {
      PHB_HSYMBOL pSym = HB_COMP_PARAM->symbols.pFirst;
      HB_COMP_PARAM->symbols.pFirst = pSym->pNext;
      hb_xfree( pSym );
   }

   hb_compDeclaredReset( HB_COMP_PARAM );
}

static void hb_compGenIncluded( HB_COMP_DECL )
{
   if( HB_COMP_PARAM->iTraceInclude > 0 && HB_COMP_PARAM->incfiles )
   {
      PHB_INCLST pIncFile = HB_COMP_PARAM->incfiles;
      char szDestFile[ HB_PATH_MAX ];
      HB_FNAME FileName;

      memcpy( &FileName, HB_COMP_PARAM->pFileName, sizeof( HB_FNAME ) );
      szDestFile[ 0 ] = '\0';

      if( ( HB_COMP_PARAM->iTraceInclude & 0xff ) == 2 )
      {
         FileName.szExtension = HB_COMP_PARAM->szDepExt;
         if( ! FileName.szExtension )
         {
            switch( HB_COMP_PARAM->iLanguage )
            {
               case HB_LANG_C:
                  FileName.szExtension = ".c";
                  break;
               case HB_LANG_PORT_OBJ:
               case HB_LANG_PORT_OBJ_BUF:
                  FileName.szExtension = ".hrb";
                  break;

               default:
                  FileName.szExtension = ".c";
            }
         }
         hb_fsFNameMerge( szDestFile, &FileName );
      }

      if( ( HB_COMP_PARAM->iTraceInclude & 0x100 ) != 0 )
      {
         HB_SIZE nLen = 0, u;
         HB_BYTE * buffer;

         while( pIncFile )
         {
            nLen += strlen( pIncFile->szFileName ) + 1;
            pIncFile = pIncFile->pNext;
         }
         if( HB_COMP_PARAM->nOutBufSize != 0 )
            ++nLen;
         u = strlen( szDestFile );
         if( u )
            nLen += u + 2;
         HB_COMP_PARAM->pOutBuf = ( HB_BYTE * ) hb_xrealloc(
                                       HB_COMP_PARAM->pOutBuf,
                                       HB_COMP_PARAM->nOutBufSize + nLen );
         buffer = HB_COMP_PARAM->pOutBuf + HB_COMP_PARAM->nOutBufSize;
         if( HB_COMP_PARAM->nOutBufSize != 0 )
            *buffer++ = '\n';
         if( u )
         {
            memcpy( buffer, szDestFile, u );
            buffer += u;
            *buffer++ = ':';
            *buffer++ = ' ';
         }
         HB_COMP_PARAM->nOutBufSize += nLen - 1;
         pIncFile = HB_COMP_PARAM->incfiles;
         while( pIncFile )
         {
            u = strlen( pIncFile->szFileName );
            memcpy( buffer, pIncFile->szFileName, u );
            buffer +=u;
            pIncFile = pIncFile->pNext;
            *buffer++ = pIncFile ? ' ' : '\0';
         }
      }
      else if( ( HB_COMP_PARAM->iTraceInclude & 0xff ) == 2 )
      {
         char szFileName[ HB_PATH_MAX ];
         FILE * file;

         FileName.szExtension = ".d";
         hb_fsFNameMerge( szFileName, &FileName );
         file = hb_fopen( szFileName, "w" );
         if( file )
         {
            if( szDestFile[ 0 ] )
               fprintf( file, "%s:", szDestFile );
            while( pIncFile )
            {
               fprintf( file, " %s", pIncFile->szFileName );
               pIncFile = pIncFile->pNext;
            }
            fprintf( file, "\n" );
            fclose( file );
         }
         else
            hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_CREATE_OUTPUT, szFileName, NULL );
      }
      else
      {
         HB_BOOL fFullQuiet = HB_COMP_PARAM->fFullQuiet;
         HB_COMP_PARAM->fFullQuiet = HB_FALSE;
         if( szDestFile[ 0 ] )
         {
            hb_compOutStd( HB_COMP_PARAM, szDestFile );
            hb_compOutStd( HB_COMP_PARAM, ": " );
         }
         while( pIncFile )
         {
            if( pIncFile != HB_COMP_PARAM->incfiles )
               hb_compOutStd( HB_COMP_PARAM, " " );
            hb_compOutStd( HB_COMP_PARAM, pIncFile->szFileName );
            pIncFile = pIncFile->pNext;
         }
         hb_compOutStd( HB_COMP_PARAM, "\n" );
         HB_COMP_PARAM->fFullQuiet = fFullQuiet;
      }
   }
}

static void hb_compSaveSwitches( HB_COMP_DECL, PHB_COMP_SWITCHES pSwitches )
{
   pSwitches->fDebugInfo        = HB_COMP_PARAM->fDebugInfo;
   pSwitches->fHideSource       = HB_COMP_PARAM->fHideSource;
   pSwitches->fAutoMemvarAssume = HB_COMP_PARAM->fAutoMemvarAssume;
   pSwitches->fI18n             = HB_COMP_PARAM->fI18n;
   pSwitches->fLineNumbers      = HB_COMP_PARAM->fLineNumbers;
   pSwitches->fPPO              = HB_COMP_PARAM->fPPO;
   pSwitches->fPPT              = HB_COMP_PARAM->fPPT;
   pSwitches->fQuiet            = HB_COMP_PARAM->fQuiet;
   pSwitches->fForceMemvars     = HB_COMP_PARAM->fForceMemvars;
   pSwitches->iStartProc        = HB_COMP_PARAM->iStartProc;
   pSwitches->iWarnings         = HB_COMP_PARAM->iWarnings;
   pSwitches->iGenCOutput       = HB_COMP_PARAM->iGenCOutput;
   pSwitches->iExitLevel        = HB_COMP_PARAM->iExitLevel;
   pSwitches->iHidden           = HB_COMP_PARAM->iHidden;
   pSwitches->supported         = HB_COMP_PARAM->supported;
}

static void hb_compRestoreSwitches( HB_COMP_DECL, PHB_COMP_SWITCHES pSwitches )
{
   HB_COMP_PARAM->fDebugInfo        = pSwitches->fDebugInfo;
   HB_COMP_PARAM->fHideSource       = pSwitches->fHideSource;
   HB_COMP_PARAM->fAutoMemvarAssume = pSwitches->fAutoMemvarAssume;
   HB_COMP_PARAM->fI18n             = pSwitches->fI18n;
   HB_COMP_PARAM->fLineNumbers      = pSwitches->fLineNumbers;
   HB_COMP_PARAM->fPPO              = pSwitches->fPPO;
   HB_COMP_PARAM->fPPT              = pSwitches->fPPT;
   HB_COMP_PARAM->fQuiet            = pSwitches->fQuiet;
   HB_COMP_PARAM->fForceMemvars     = pSwitches->fForceMemvars;
   HB_COMP_PARAM->iStartProc        = pSwitches->iStartProc;
   HB_COMP_PARAM->iWarnings         = pSwitches->iWarnings;
   HB_COMP_PARAM->iGenCOutput       = pSwitches->iGenCOutput;
   HB_COMP_PARAM->iExitLevel        = pSwitches->iExitLevel;
   HB_COMP_PARAM->iHidden           = pSwitches->iHidden;
   HB_COMP_PARAM->supported         = pSwitches->supported;
}

static int hb_compCompile( HB_COMP_DECL, const char * szPrg, const char * szBuffer, int iStartLine )
{
   char buffer[ HB_PATH_MAX * 2 + 80 ];
   HB_COMP_SWITCHES switches;
   int iStatus = EXIT_SUCCESS;
   PHB_FNAME pFileName = NULL;
   PHB_MODULE pModule;
   HB_BOOL fGenCode = HB_TRUE;

   HB_TRACE( HB_TR_DEBUG, ( "hb_compCompile(%s,%p,%d)", szPrg, ( const void * ) szBuffer, iStartLine ) );

   hb_compSaveSwitches( HB_COMP_PARAM, &switches );
   /* Initialize support variables */
   hb_compInitVars( HB_COMP_PARAM );

   if( ! szBuffer )
   {
      if( szPrg[ 0 ] == '@' )
         iStatus = hb_compReadClpFile( HB_COMP_PARAM, szPrg + 1 );
      else
         hb_compModuleAdd( HB_COMP_PARAM,
                           hb_compIdentifierNew( HB_COMP_PARAM, szPrg, HB_IDENT_COPY ),
                           HB_TRUE );
   }

   pModule = HB_COMP_PARAM->modules;
   while( iStatus == EXIT_SUCCESS && ! HB_COMP_PARAM->fExit &&
          ( pModule || szBuffer ) )
   {
      char szFileName[ HB_PATH_MAX ];     /* filename to parse */
      HB_BOOL fSkip = HB_FALSE;

      /* Clear and reinitialize preprocessor state */
      hb_pp_reset( HB_COMP_PARAM->pLex->pPP );
      HB_COMP_PARAM->pLex->iState = HB_COMP_PARAM->pLex->iClose =
      HB_COMP_PARAM->pLex->iScope = 0;
      HB_COMP_PARAM->pLex->fEol = HB_FALSE;
      hb_compDeclaredReset( HB_COMP_PARAM );

      if( ! szBuffer )
         szPrg = pModule->szName;

      if( pFileName && HB_COMP_PARAM->pFileName != pFileName )
         hb_xfree( pFileName );
      pFileName = hb_fsFNameSplit( szPrg );
      if( ! HB_COMP_PARAM->pFileName )
         HB_COMP_PARAM->pFileName = pFileName;

      if( ! pFileName->szName )
      {
         hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'F', HB_COMP_ERR_BADFILENAME, szPrg, NULL );
         iStatus = EXIT_FAILURE;
         break;
      }

      if( ! pFileName->szExtension )
         pFileName->szExtension = ".prg";
      hb_fsFNameMerge( szFileName, pFileName );

      if( szBuffer )
      {
         if( ! hb_pp_inBuffer( HB_COMP_PARAM->pLex->pPP, szFileName, szBuffer, strlen( szBuffer ), iStartLine ) )
         {
            hb_compOutErr( HB_COMP_PARAM, "Cannot create preprocessor buffer." );
            iStatus = EXIT_FAILURE;
            break;
         }
      }
      else if( ! hb_pp_inFile( HB_COMP_PARAM->pLex->pPP, szFileName, HB_FALSE, NULL, HB_FALSE ) )
      {
         hb_snprintf( buffer, sizeof( buffer ),
                      "Cannot open %s, assumed external\n", szFileName );
         hb_compOutErr( HB_COMP_PARAM, buffer );
         if( pModule->force )
         {
            iStatus = EXIT_FAILURE;
            break;
         }
         fSkip = HB_TRUE;
      }

      if( ! fSkip )
      {
         char szPpoName[ HB_PATH_MAX ];

         if( HB_COMP_PARAM->fPPT )
         {
            hb_compPpoFile( HB_COMP_PARAM, szFileName, ".ppt", szPpoName );
            if( ! hb_pp_traceFile( HB_COMP_PARAM->pLex->pPP, szPpoName, NULL ) )
            {
               iStatus = EXIT_FAILURE;
               break;
            }
         }

         if( HB_COMP_PARAM->fPPO )
         {
            hb_compPpoFile( HB_COMP_PARAM, szFileName, ".ppo", szPpoName );
            if( ! hb_pp_outFile( HB_COMP_PARAM->pLex->pPP, szPpoName, NULL ) )
            {
               iStatus = EXIT_FAILURE;
               break;
            }
         }

#if ! defined( HB_MODULES_MERGE )
         /* TODO: HRB format does not support yet multiple static functions
          *       with the same name. Such functionality needs extended .HRB
          *       file format.
          */
         if( HB_COMP_PARAM->iLanguage != HB_LANG_PORT_OBJ &&
             HB_COMP_PARAM->iLanguage != HB_LANG_PORT_OBJ_BUF )
         {
            if( HB_COMP_PARAM->iModulesCount++ )
               hb_compExternGen( HB_COMP_PARAM );
         }
         else
#endif
            HB_COMP_PARAM->iModulesCount = 1;

         HB_COMP_PARAM->currLine = hb_pp_line( HB_COMP_PARAM->pLex->pPP ) + 1;
         HB_COMP_PARAM->currModule = hb_compIdentifierNew(
                                    HB_COMP_PARAM, szFileName, HB_IDENT_COPY );
         if( HB_COMP_PARAM->szFile == NULL )
            HB_COMP_PARAM->szFile = HB_COMP_PARAM->currModule;

         if( szBuffer )
            /* Generate the starting procedure frame, lower letters used
             * intentionally to not create name conflicts when -n2 switch
             * is used and we compile code not encapsulated in function.
             */
            hb_compFunctionAdd( HB_COMP_PARAM, "__hbInit", HB_FS_STATIC,
                                HB_FUNF_PROCEDURE | HB_FUNF_FILE_FIRST | HB_FUNF_FILE_DECL );
         else
         {
            if( ! HB_COMP_PARAM->fQuiet )
            {
               if( HB_COMP_PARAM->fPPO )
                  hb_snprintf( buffer, sizeof( buffer ),
                               "Compiling '%s' and generating preprocessed output to '%s'...\n",
                               szFileName, szPpoName );
               else
                  hb_snprintf( buffer, sizeof( buffer ),
                               "Compiling '%s'...\n", szFileName );
               hb_compOutStd( HB_COMP_PARAM, buffer );
            }

            /* Generate the starting procedure frame */
            hb_compFunctionAdd( HB_COMP_PARAM,
                                hb_compIdentifierNew( HB_COMP_PARAM, hb_strupr( hb_strdup( pFileName->szName ) ), HB_IDENT_FREE ),
                                HB_FS_PUBLIC, HB_FUNF_PROCEDURE | HB_FUNF_FILE_FIRST | ( HB_COMP_PARAM->iStartProc == 0 ? 0 : HB_FUNF_FILE_DECL ) );
         }

         if( ! HB_COMP_PARAM->fExit )
         {
            int iExitLevel = HB_COMP_PARAM->iExitLevel;
            if( HB_COMP_PARAM->iSyntaxCheckOnly >= 2 )
               hb_compParserRun( HB_COMP_PARAM );
            else
               hb_comp_yyparse( HB_COMP_PARAM );
            HB_COMP_PARAM->iExitLevel = HB_MAX( iExitLevel, HB_COMP_PARAM->iExitLevel );
         }
      }

      if( szBuffer )
      {
         szBuffer = NULL;
         pModule = HB_COMP_PARAM->modules;
      }
      else
         pModule = pModule->pNext;

      while( pModule && ! pModule->force &&
             hb_compIsModuleFunc( HB_COMP_PARAM, pModule->szName ) )
         pModule = pModule->pNext;
   }

   if( pFileName && HB_COMP_PARAM->pFileName != pFileName )
      hb_xfree( pFileName );

   if( ! HB_COMP_PARAM->fExit && iStatus == EXIT_SUCCESS )
   {
      /* Begin of finalization phase. */

      /* fix all previous function returns offsets */
      hb_compFinalizeFunction( HB_COMP_PARAM );

      if( HB_COMP_PARAM->fDebugInfo )
         hb_compExternAdd( HB_COMP_PARAM, "__DBGENTRY", 0 );

      hb_compExternGen( HB_COMP_PARAM );       /* generates EXTERN symbols names */

      if( HB_COMP_PARAM->pInitFunc )
      {
         char szNewName[ 25 ];

         /* Mark thread static variables */
         hb_compStaticDefThreadSet( HB_COMP_PARAM );
         /* Fix the number of static variables */
         HB_COMP_PARAM->pInitFunc->pCode[ 3 ] = HB_LOBYTE( HB_COMP_PARAM->iStaticCnt );
         HB_COMP_PARAM->pInitFunc->pCode[ 4 ] = HB_HIBYTE( HB_COMP_PARAM->iStaticCnt );
         HB_COMP_PARAM->pInitFunc->iStaticsBase = HB_COMP_PARAM->iStaticCnt;
         /* Update pseudo function name */
         hb_snprintf( szNewName, sizeof( szNewName ), "(_INITSTATICS%05d)", HB_COMP_PARAM->iStaticCnt );
         HB_COMP_PARAM->pInitFunc->szName = hb_compIdentifierNew( HB_COMP_PARAM, szNewName, HB_IDENT_COPY );

         hb_compAddInitFunc( HB_COMP_PARAM, HB_COMP_PARAM->pInitFunc );
      }

      if( HB_COMP_PARAM->fLineNumbers && HB_COMP_PARAM->fDebugInfo )
      {
         PHB_DEBUGINFO pInfo = hb_compGetDebugInfo( HB_COMP_PARAM ), pNext;
         if( pInfo )
         {
            int iModules = 0;
            hb_compLineNumberDefStart( HB_COMP_PARAM );
            do
            {
               HB_SIZE nSkip = pInfo->ulFirstLine >> 3;
               HB_SIZE nLen = ( ( pInfo->ulLastLine + 7 ) >> 3 ) - nSkip;

               hb_compGenPushString( pInfo->pszModuleName, strlen( pInfo->pszModuleName ) + 1, HB_COMP_PARAM );
               hb_compGenPushLong( nSkip << 3, HB_COMP_PARAM );
               hb_compGenPushString( ( char * ) pInfo->pLineMap + nSkip, nLen + 1, HB_COMP_PARAM );
               hb_compGenPCode3( HB_P_ARRAYGEN, 3, 0, HB_COMP_PARAM );
               iModules++;

               pNext = pInfo->pNext;
               hb_xfree( pInfo->pszModuleName );
               hb_xfree( pInfo->pLineMap );
               hb_xfree( pInfo );
               pInfo = pNext;
            }
            while( pInfo );

            hb_compGenPCode3( HB_P_ARRAYGEN, HB_LOBYTE( iModules ), HB_HIBYTE( iModules ), HB_COMP_PARAM );
            hb_compGenPCode1( HB_P_RETVALUE, HB_COMP_PARAM );
            hb_compLineNumberDefEnd( HB_COMP_PARAM );
            hb_compAddInitFunc( HB_COMP_PARAM, HB_COMP_PARAM->pLineFunc );
         }
      }

      if( HB_COMP_PARAM->szAnnounce )
         hb_compAnnounce( HB_COMP_PARAM, HB_COMP_PARAM->szAnnounce );

      hb_compUpdateFunctionNames( HB_COMP_PARAM );

      /* End of finalization phase. */

      if( HB_COMP_PARAM->iErrorCount || HB_COMP_PARAM->fAnyWarning )
      {
         if( HB_COMP_PARAM->iErrorCount )
         {
            iStatus = EXIT_FAILURE;
            fGenCode = HB_FALSE;
            hb_snprintf( buffer, sizeof( buffer ),
                         "\r%i error%s\n",
                         HB_COMP_PARAM->iErrorCount,
                         HB_COMP_PARAM->iErrorCount > 1 ? "s" : "" );
            hb_compOutStd( HB_COMP_PARAM, buffer );
         }
         else if( HB_COMP_PARAM->iExitLevel == HB_EXITLEVEL_SETEXIT )
         {
            iStatus = EXIT_FAILURE;
         }
         else if( HB_COMP_PARAM->iExitLevel == HB_EXITLEVEL_DELTARGET )
         {
            iStatus = EXIT_FAILURE;
            fGenCode = HB_FALSE;
         }
      }

      /* we create the output file name */
      hb_compOutputFile( HB_COMP_PARAM );

      if( fGenCode && HB_COMP_PARAM->iErrorCount == 0 &&
          HB_COMP_PARAM->iTraceInclude > 0 )
         hb_compGenIncluded( HB_COMP_PARAM );

      if( HB_COMP_PARAM->iSyntaxCheckOnly == 0 &&
          fGenCode && HB_COMP_PARAM->iErrorCount == 0 )
      {
         const char * szFirstFunction = NULL;
         int iFunctionCount = 0;
         PHB_HFUNC pFunc;


         pFunc = HB_COMP_PARAM->functions.pFirst;

         while( pFunc && ! HB_COMP_PARAM->fExit )
         {
            /* skip pseudo function frames used in automatically included
               files for file wide declarations */
            if( ( pFunc->funFlags & HB_FUNF_FILE_DECL ) == 0 )
            {
               hb_compOptimizeFrames( HB_COMP_PARAM, pFunc );

               if( szFirstFunction == NULL &&
                  ! ( pFunc->cScope & ( HB_FS_INIT | HB_FS_EXIT ) ) )
               {
                  szFirstFunction = pFunc->szName;
               }
               if( pFunc != HB_COMP_PARAM->pInitFunc &&
                   pFunc != HB_COMP_PARAM->pLineFunc )
                  ++iFunctionCount;
            }
            pFunc = pFunc->pNext;
         }

         if( szFirstFunction )
         {
            PHB_HSYMBOL pSym = hb_compSymbolFind( HB_COMP_PARAM, szFirstFunction,
                                                  NULL, HB_SYM_FUNCNAME );
            if( pSym )
               pSym->cScope |= HB_FS_FIRST;
         }

         if( ! HB_COMP_PARAM->fQuiet )
         {
            hb_snprintf( buffer, sizeof( buffer ),
                         "\rLines %i, Functions/Procedures %i\n",
                         hb_pp_lineTot( HB_COMP_PARAM->pLex->pPP ),
                         iFunctionCount );
            hb_compOutStd( HB_COMP_PARAM, buffer );
         }

         hb_compGenOutput( HB_COMP_PARAM, HB_COMP_PARAM->iLanguage );
      }
      else
         fGenCode = HB_FALSE;

      if( fGenCode && HB_COMP_PARAM->iErrorCount == 0 )
      {
         if( hb_compI18nSave( HB_COMP_PARAM, HB_FALSE ) )
            hb_compI18nFree( HB_COMP_PARAM );
      }
   }
   else
      fGenCode = HB_FALSE;

   if( ! fGenCode && ! HB_COMP_PARAM->fExit &&
       HB_COMP_PARAM->iSyntaxCheckOnly == 0 )
      hb_compOutStd( HB_COMP_PARAM, "\nNo code generated.\n" );

   hb_compCompileEnd( HB_COMP_PARAM );
   hb_compRestoreSwitches( HB_COMP_PARAM, &switches );

   return HB_COMP_PARAM->fExit ? EXIT_FAILURE : iStatus;
}
