Files
harbour-core/src/compiler/hbmain.c
vszakats 9687850865 2013-03-16 02:10 UTC+0100 Viktor Szakats (harbour syenar.net)
* (all files)
    * stripped svn header
    * minor cleanups
    ; use following command to find out the history of files:
       git log
       git log --follow
       git blame
       git annotate
2013-03-16 02:11:42 +01:00

4474 lines
144 KiB
C

/*
* Harbour Project source code:
* Compiler main file
*
* Copyright 1999 Antonio Linares <alinares@fivetechsoft.com>
* www - http://harbour-project.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
* their web site at http://www.gnu.org/).
*
* The following parts are Copyright of the individual authors.
* www - http://harbour-project.org
*
* Copyright 2000 RonPinkas <Ron@Profit-Master.com>
* hb_compPrepareJumps()
* hb_compOptimizeJumps()
* hb_compOptimizeFrames()
* hb_compDeclaredParameterAdd()
* hb_compClassAdd()
* hb_compClassFind()
* hb_compMethodAdd()
* hb_compMethodFind()
* hb_compDeclaredAdd()
*
* See COPYING.txt for licensing terms.
*
*/
/*
* 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 "hbhash.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;
HB_BOOL bAnyFiles = HB_FALSE;
int i;
HB_TRACE( HB_TR_DEBUG, ( "hb_compMain()" ) );
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_compChkCompilerSwitch( HB_COMP_PARAM, 0, NULL );
/* Then check command line arguments
This will override duplicated environment settings */
hb_compChkCompilerSwitch( 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 );
if( HB_COMP_PARAM->fBuildInfo || HB_COMP_PARAM->fCredits )
{
hb_comp_free( HB_COMP_PARAM );
return iStatus;
}
/* Set Search Path */
if( HB_COMP_PARAM->fINCLUDE )
hb_compChkPaths( HB_COMP_PARAM );
/* Set standard rules */
hb_compInitPP( HB_COMP_PARAM, argc, argv, pOpenFunc );
/* Prepare the table of identifiers */
hb_compIdentifierOpen( HB_COMP_PARAM );
}
if( szSource )
{
bAnyFiles = HB_TRUE;
iStatus = hb_compCompile( HB_COMP_PARAM, "{SOURCE}", szSource, iStartLine );
}
else
{
/* 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 ] ) )
{
bAnyFiles = HB_TRUE;
iStatus = hb_compCompile( HB_COMP_PARAM, argv[ i ], NULL, 0 );
if( iStatus != EXIT_SUCCESS )
break;
}
}
}
if( ! bAnyFiles && ! HB_COMP_PARAM->fQuiet && ! HB_COMP_PARAM->fExit )
{
hb_compPrintUsage( HB_COMP_PARAM, argv[ 0 ] );
iStatus = EXIT_FAILURE;
}
if( HB_COMP_PARAM->iErrorCount > 0 )
iStatus = EXIT_FAILURE;
if( 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 );
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' )
{
/* printf( "\nVariable %s is of Class: %s\n", szVarName, pVarType->szFromClass ); */
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;
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 acccess'
* 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;
}
int hb_compVariableScope( HB_COMP_DECL, const char * szVarName )
{
int iScope;
hb_compVariableFind( HB_COMP_PARAM, szVarName, NULL, &iScope );
return iScope;
}
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, iScope;
/* 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 )
{
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;
/*printf( "Declaring Class: %s\n", szClassName );*/
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;
/*printf( "\nDeclaring Method: %s of Class: %s Pointer: %li\n", szMethodName, pClass->szName, pClass );*/
if( HB_COMP_PARAM->iWarnings < 3 )
return NULL;
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;
/*printf( "\nDeclaring Function: %s\n", szDeclaredName, NULL );*/
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 /* Declared Method Parameter */
{
/* 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 ); */
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 );
/* printf( "\nParameter: %s FROM CLASS: %s\n", szVarName, HB_COMP_PARAM->pLastMethod->pParamClasses[ HB_COMP_PARAM->pLastMethod->iParamCount - 1 ]->szName ); */
}
}
}
PHB_VARTYPE hb_compVarTypeNew( HB_COMP_DECL, char 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 begining 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 sth 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 pooint 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 ) - backword (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 adjustements 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( !( pFunc->funFlags & HB_FUNF_USES_STATICS ) ) */
if( pFunc->pCode[ 8 ] == HB_P_ENDPROC )
{
pFunc->nPCodePos -= 3;
memmove( pFunc->pCode + 5, pFunc->pCode + 8, pFunc->nPCodePos - 5 );
}
else /* Check Global Statics. */
{
/* PHB_HVAR pVar = pFunc->pStatics; */
PHB_HVAR pVar = HB_COMP_PARAM->functions.pFirst->pStatics;
while( pVar )
{
/*printf( "\nChecking: %s Used: %i\n", pVar->szName, pVar->iUsed );*/
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 initialises the HB_HFUNC structure
*/
static PHB_HFUNC hb_compFunctionNew( HB_COMP_DECL, const char * szName, HB_SYMBOLSCOPE cScope )
{
PHB_HFUNC pFunc;
pFunc = ( PHB_HFUNC ) hb_xgrab( sizeof( HB_HFUNC ) );
memset( pFunc, 0, 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;
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 )
{
HB_BOOL fGlobal = HB_FALSE;
PHB_HFUNC pSeek = HB_COMP_PARAM->functions.pFirst;
while( pSeek )
{
if( pFunc == pSeek )
fGlobal = HB_TRUE;
else if( ( ! fGlobal || ( pSeek->cScope & ( HB_FS_STATIC | HB_FS_INITEXIT ) ) == 0 ) &&
strcmp( pFunc->szName, pSeek->szName ) == 0 )
pFunc->iFuncSuffix++;
pSeek = pSeek->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 deined 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_compFunctionMarkStatic( HB_COMP_DECL, const char * szFunName )
{
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 |= HB_FS_STATIC | HB_FS_LOCAL;
}
}
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 asssigned 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 );
}
}
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_compErrorCodeblock( 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 coddeblock 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 nonaliased 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 coddeblock 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 )
{
HB_SIZE n;
while( nCount-- )
{
if( fPop )
{
pFunc->pCode[ nFrom ] = HB_P_POP;
fPop = HB_FALSE;
}
else if( fCheck && pFunc->pCode[ nFrom ] == HB_P_NOOP && pFunc->nNOOPs )
{
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;
HB_SIZE n;
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
{
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 simmilar 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 simmilar 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 beetwen 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
* beetwen 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 */
/* HB_COMP_PARAM->currModule = HB_COMP_PARAM->szFile; */
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, uiVar = 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;
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;
HB_USHORT wPos;
int iLocalPos;
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-- )
{
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 )
{
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 stati 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 )
{
if( HB_COMP_PARAM->iErrorCount != 0 )
hb_compExprLstDealloc( HB_COMP_PARAM );
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->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->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->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->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->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, 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 */
char szPpoName[ HB_PATH_MAX ];
HB_BOOL fSkip = HB_FALSE;
/* Clear and reinitialize preprocessor state */
hb_pp_reset( HB_COMP_PARAM->pLex->pPP );
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, 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 )
{
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;
}