* *
* update copyright headers with new FSF postal address
* COPYING.txt -> LICENSE.txt (rest of repo to be synced)
781 lines
28 KiB
C
781 lines
28 KiB
C
/*
|
|
* Compiler Expression Optimizer
|
|
*
|
|
* Copyright 1999 Ryszard Glab
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file LICENSE.txt. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "hbcomp.h"
|
|
|
|
/* ************************************************************************ */
|
|
|
|
#ifndef HB_MACRO_SUPPORT
|
|
HB_SIZE hb_compExprListEval( HB_COMP_DECL, PHB_EXPR pExpr, PHB_COMP_CARGO_FUNC pEval )
|
|
{
|
|
HB_SIZE nLen = 0;
|
|
|
|
if( pEval && ( pExpr->ExprType == HB_ET_LIST ||
|
|
pExpr->ExprType == HB_ET_ARGLIST ) )
|
|
{
|
|
pExpr = pExpr->value.asList.pExprList;
|
|
while( pExpr )
|
|
{
|
|
( pEval )( HB_COMP_PARAM, ( void * ) pExpr );
|
|
pExpr = pExpr->pNext;
|
|
++nLen;
|
|
}
|
|
}
|
|
return nLen;
|
|
}
|
|
|
|
HB_SIZE hb_compExprListEval2( HB_COMP_DECL, PHB_EXPR pExpr1, PHB_EXPR pExpr2, PHB_COMP_CARGO2_FUNC pEval )
|
|
{
|
|
HB_SIZE nLen = 0;
|
|
|
|
if( ! pEval )
|
|
return nLen;
|
|
|
|
if( ( pExpr1->ExprType == HB_ET_LIST || pExpr1->ExprType == HB_ET_ARGLIST )
|
|
&&
|
|
( pExpr2->ExprType == HB_ET_LIST || pExpr2->ExprType == HB_ET_ARGLIST ) )
|
|
{
|
|
pExpr1 = pExpr1->value.asList.pExprList;
|
|
pExpr2 = pExpr2->value.asList.pExprList;
|
|
while( pExpr1 && pExpr2 )
|
|
{
|
|
( pEval )( HB_COMP_PARAM, ( void * ) pExpr1, ( void * ) pExpr2 );
|
|
pExpr1 = pExpr1->pNext;
|
|
pExpr2 = pExpr2->pNext;
|
|
++nLen;
|
|
}
|
|
}
|
|
else if( pExpr1->ExprType == HB_ET_LIST || pExpr1->ExprType == HB_ET_ARGLIST )
|
|
{
|
|
pExpr1 = pExpr1->value.asList.pExprList;
|
|
while( pExpr1 )
|
|
{
|
|
( pEval )( HB_COMP_PARAM, ( void * ) pExpr1, ( void * ) pExpr2 );
|
|
pExpr1 = pExpr1->pNext;
|
|
++nLen;
|
|
}
|
|
}
|
|
return nLen;
|
|
}
|
|
#endif
|
|
|
|
/* Create function call
|
|
*/
|
|
#ifdef HB_MACRO_SUPPORT
|
|
PHB_EXPR hb_macroExprNewFunCall( PHB_EXPR pName, PHB_EXPR pParms, HB_COMP_DECL )
|
|
#else
|
|
PHB_EXPR hb_compExprNewFunCall( PHB_EXPR pName, PHB_EXPR pParms, HB_COMP_DECL )
|
|
#endif
|
|
{
|
|
PHB_EXPR pExpr;
|
|
|
|
#ifdef HB_MACRO_SUPPORT
|
|
if( pName->ExprType == HB_ET_VARIABLE )
|
|
{
|
|
/* My&var.1() executed by macro compiler
|
|
*/
|
|
/* NOTE: direct type change */
|
|
pName->ExprType = HB_ET_FUNNAME;
|
|
pName->value.asSymbol.name =
|
|
hb_compGetFuncID( pName->value.asSymbol.name,
|
|
&pName->value.asSymbol.funcid,
|
|
&pName->value.asSymbol.flags );
|
|
}
|
|
#endif
|
|
|
|
if( pName->ExprType == HB_ET_FUNNAME )
|
|
{
|
|
/* The name of a function is specified at compile time
|
|
* e.g. MyFunc()
|
|
*
|
|
* NOTE: 'pName' can be a macro expression that will be resolved
|
|
* at runtime - in this case pName is an expression of HB_ET_MACRO type
|
|
* e.g. &MyVar()
|
|
*/
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_compExprNewFunCall(%s)", pName->value.asSymbol.name ) );
|
|
|
|
#if ! defined( HB_MACRO_SUPPORT ) && defined( HB_USE_ENUM_FUNCTIONS )
|
|
{
|
|
int iLen = strlen( pName->value.asSymbol.name );
|
|
if( iLen >= 10 && iLen <= 14 && memcmp( "HB_ENUM", pName->value.asSymbol.name, 7 ) == 0 )
|
|
{
|
|
const char * szMessage = pName->value.asSymbol.name + 7;
|
|
|
|
if( iLen == 12 && memcmp( "INDEX", szMessage, 5 ) == 0 )
|
|
szMessage = "__ENUMINDEX";
|
|
else if( iLen == 12 && memcmp( "VALUE", szMessage, 5 ) == 0 )
|
|
szMessage = "__ENUMVALUE";
|
|
else if( iLen == 11 && memcmp( "BASE", szMessage, 4 ) == 0 )
|
|
szMessage = "__ENUMBASE";
|
|
else if( iLen == 10 && memcmp( "KEY", szMessage, 3 ) == 0 )
|
|
szMessage = "__ENUMKEY";
|
|
else if( iLen == 14 && memcmp( "ISFIRST", szMessage, 7 ) == 0 )
|
|
szMessage = "__ENUMISFIRST";
|
|
else if( iLen == 13 && memcmp( "ISLAST", szMessage, 6 ) == 0 )
|
|
szMessage = "__ENUMISLAST";
|
|
else
|
|
szMessage = NULL;
|
|
|
|
if( szMessage )
|
|
{
|
|
int iCount = ( int ) hb_compExprParamListLen( pParms );
|
|
PHB_ENUMERATOR pForVar, pEnumVar = NULL;
|
|
|
|
pForVar = HB_COMP_PARAM->functions.pLast->pEnum;
|
|
|
|
if( iCount == 0 )
|
|
{
|
|
while( pForVar )
|
|
{
|
|
if( pForVar->iForEachDir != 0 )
|
|
pEnumVar = pForVar;
|
|
pForVar = pForVar->pNext;
|
|
}
|
|
}
|
|
else if( iCount == 1 )
|
|
{
|
|
if( pParms->value.asList.pExprList->ExprType == HB_ET_VARIABLE ||
|
|
pParms->value.asList.pExprList->ExprType == HB_ET_VARREF )
|
|
{
|
|
const char * szName = pParms->value.asList.pExprList->value.asSymbol.name;
|
|
|
|
while( pForVar )
|
|
{
|
|
if( pForVar->iForEachDir != 0 &&
|
|
strcmp( pEnumVar->szName, szName ) == 0 )
|
|
{
|
|
pEnumVar = pForVar;
|
|
break;
|
|
}
|
|
pForVar = pForVar->pNext;
|
|
}
|
|
}
|
|
}
|
|
if( pEnumVar )
|
|
{
|
|
#if 0
|
|
if( pEnumVar->iForEachDir < 0 )
|
|
{
|
|
if( strcmp( "__ENUMISFIRST", szMessage ) == 0 )
|
|
szMessage = "__ENUMISLAST";
|
|
else if( strcmp( "__ENUMISLAST", szMessage ) == 0 )
|
|
szMessage = "__ENUMISFIRST";
|
|
}
|
|
#endif
|
|
if( pParms )
|
|
HB_COMP_EXPR_FREE( pParms );
|
|
HB_COMP_EXPR_FREE( pName );
|
|
return hb_compExprNewMethodObject(
|
|
hb_compExprNewSend( szMessage, HB_COMP_PARAM ),
|
|
hb_compExprNewVar( pEnumVar->szName, HB_COMP_PARAM ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
if( pName->value.asSymbol.funcid == HB_F_EVAL &&
|
|
hb_compExprParamListLen( pParms ) != 0 )
|
|
{
|
|
/* Optimize Eval( bBlock, [ArgList] ) to: bBlock:Eval( [ArgList] ) */
|
|
PHB_EXPR pEval;
|
|
|
|
pEval = hb_compExprNewMethodCall(
|
|
hb_compExprNewMethodObject(
|
|
hb_compExprNewSend( "EVAL", HB_COMP_PARAM ),
|
|
pParms->value.asList.pExprList ),
|
|
hb_compExprNewArgList(
|
|
pParms->value.asList.pExprList->pNext,
|
|
HB_COMP_PARAM ) );
|
|
#if ! defined( HB_MACRO_SUPPORT )
|
|
/* force reduction */
|
|
pEval->nLength = 1;
|
|
#endif
|
|
pParms->value.asList.pExprList = NULL;
|
|
HB_COMP_EXPR_FREE( pParms );
|
|
HB_COMP_EXPR_FREE( pName );
|
|
return pEval;
|
|
}
|
|
else if( pName->value.asSymbol.funcid == HB_F__GET_ &&
|
|
hb_compExprParamListLen( pParms ) != 0 )
|
|
{
|
|
/* Reserved Clipper function used to handle GET variables
|
|
*/
|
|
PHB_EXPR pArg, pNext;
|
|
HB_USHORT uiCount;
|
|
|
|
/* pArg has to be reduced to eliminate possible problems with
|
|
* cloned expressions in SETGET block
|
|
*/
|
|
if( HB_SUPPORT_HARBOUR )
|
|
{
|
|
pParms = HB_EXPR_USE( pParms, HB_EA_REDUCE );
|
|
pArg = pParms->value.asList.pExprList;
|
|
}
|
|
else
|
|
{
|
|
pArg = pParms->value.asList.pExprList;
|
|
pNext = pArg->pNext;
|
|
pArg->pNext = NULL;
|
|
pArg = hb_compExprListStrip( HB_EXPR_USE( pArg, HB_EA_REDUCE ), HB_COMP_PARAM );
|
|
pArg->pNext = pNext;
|
|
pParms->value.asList.pExprList = pArg;
|
|
}
|
|
|
|
if( pArg->ExprType == HB_ET_ARRAYAT )
|
|
{
|
|
/* replace:
|
|
_GET_( a[1], "a[1]", , , )
|
|
into:
|
|
__GetA( {||a }, "a", , , , { 1 } )
|
|
*/
|
|
PHB_EXPR pIndex, pVar;
|
|
PHB_EXPR pBase;
|
|
|
|
pName->value.asSymbol.name = "__GETA";
|
|
/* NOTE: a[ i, j ] is stored as: (pExprList)->(pIndex)
|
|
* ( ( a->[ i ] )->[ j ] )
|
|
*/
|
|
pVar = HB_EXPR_USE( pArg->value.asList.pExprList, HB_EA_REDUCE );
|
|
pBase = pVar->ExprType == HB_ET_ARRAYAT ? pVar : NULL;
|
|
pIndex = HB_EXPR_USE( pArg->value.asList.pIndex, HB_EA_REDUCE );
|
|
pIndex->pNext = NULL;
|
|
while( pVar->ExprType == HB_ET_ARRAYAT )
|
|
{
|
|
/* traverse back to a leftmost expression and build a list
|
|
* of index expressions
|
|
*/
|
|
pVar->value.asList.pIndex->pNext = pIndex;
|
|
pIndex = pVar->value.asList.pIndex;
|
|
pVar = pVar->value.asList.pExprList;
|
|
}
|
|
|
|
/* create a set only codeblock */
|
|
if( pVar->ExprType == HB_ET_MACRO )
|
|
{
|
|
/* &var[1] */
|
|
HB_COMP_EXPR_FREE( pVar );
|
|
pVar = hb_compExprNewNil( HB_COMP_PARAM );
|
|
}
|
|
else
|
|
{
|
|
pVar = hb_compExprAddCodeblockExpr( hb_compExprNewCodeBlock( NULL, 0, 0, HB_COMP_PARAM ), pVar );
|
|
}
|
|
|
|
/* pVar will be the first argument now
|
|
*/
|
|
pParms->value.asList.pExprList = pVar;
|
|
/* link the rest of parameters
|
|
*/
|
|
pVar->pNext = pArg->pNext;
|
|
/* Delete an argument that was the first one
|
|
*/
|
|
pArg->value.asList.pIndex = NULL;
|
|
pArg->value.asList.pExprList = NULL;
|
|
HB_COMP_EXPR_CLEAR( pArg );
|
|
/* Create an array with index elements
|
|
*/
|
|
pIndex = hb_compExprNewArray( hb_compExprNewList( pIndex, HB_COMP_PARAM ), HB_COMP_PARAM );
|
|
/* The array with index elements have to be the sixth argument
|
|
* of __GetA() call
|
|
*/
|
|
uiCount = 1;
|
|
while( ++uiCount < 6 )
|
|
{
|
|
if( pVar->pNext == NULL )
|
|
pVar->pNext = hb_compExprNewNil( HB_COMP_PARAM );
|
|
pVar = pVar->pNext;
|
|
}
|
|
if( pVar->pNext ) /* Delete 6-th argument if present */
|
|
{
|
|
pIndex->pNext = pVar->pNext->pNext;
|
|
HB_COMP_EXPR_FREE( pVar->pNext );
|
|
}
|
|
pVar->pNext = pIndex; /* Set a new 6-th argument */
|
|
|
|
/* Remove the index expression from a string representation
|
|
*/
|
|
pVar = pParms->value.asList.pExprList->pNext;
|
|
if( pVar->ExprType == HB_ET_STRING )
|
|
{
|
|
HB_SIZE i = 0;
|
|
char * szVar = pVar->value.asString.string;
|
|
|
|
/* NOTE: Clipper strips a string at the first '[' character too
|
|
*/
|
|
while( ++i < pVar->nLength )
|
|
{
|
|
if( szVar[ i ] == '[' )
|
|
{
|
|
if( ! pVar->value.asString.dealloc )
|
|
{
|
|
szVar = pVar->value.asString.string = ( char * )
|
|
hb_xmemdup( pVar->value.asString.string, i + 1 );
|
|
pVar->value.asString.dealloc = HB_TRUE;
|
|
}
|
|
szVar[ i ] = 0;
|
|
pVar->nLength = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* clear expressions no longer used */
|
|
if( pBase )
|
|
{
|
|
while( pBase->ExprType == HB_ET_ARRAYAT )
|
|
{
|
|
pVar = pBase->value.asList.pExprList;
|
|
pBase->value.asList.pExprList = NULL;
|
|
HB_COMP_EXPR_CLEAR( pBase );
|
|
pBase = pVar;
|
|
}
|
|
}
|
|
}
|
|
else if( pArg->ExprType == HB_ET_MACRO ||
|
|
( pArg->ExprType == HB_ET_ALIASVAR &&
|
|
( pArg->value.asAlias.pAlias->ExprType == HB_ET_MACRO ||
|
|
pArg->value.asAlias.pVar->ExprType == HB_ET_MACRO ) ) )
|
|
{
|
|
const char * szText = NULL;
|
|
|
|
if( pArg->ExprType == HB_ET_ALIASVAR )
|
|
{
|
|
const char * szAlias = NULL, * szAliasPref = "",
|
|
* szVar = NULL, * szVarPref = "";
|
|
|
|
if( pArg->value.asAlias.pAlias->ExprType == HB_ET_ALIAS )
|
|
szAlias = pArg->value.asAlias.pAlias->value.asSymbol.name;
|
|
else if( pArg->value.asAlias.pAlias->ExprType == HB_ET_MACRO &&
|
|
pArg->value.asAlias.pAlias->value.asMacro.pExprList == NULL )
|
|
{
|
|
szAlias = pArg->value.asAlias.pAlias->value.asMacro.szMacro;
|
|
if( pArg->value.asAlias.pAlias->value.asMacro.cMacroOp == '&' )
|
|
szAliasPref = "&";
|
|
}
|
|
|
|
if( pArg->value.asAlias.pVar->ExprType == HB_ET_VARIABLE )
|
|
szVar = pArg->value.asAlias.pVar->value.asSymbol.name;
|
|
else if( pArg->value.asAlias.pVar->ExprType == HB_ET_MACRO &&
|
|
pArg->value.asAlias.pVar->value.asMacro.pExprList == NULL )
|
|
{
|
|
szVar = pArg->value.asAlias.pVar->value.asMacro.szMacro;
|
|
if( pArg->value.asAlias.pVar->value.asMacro.cMacroOp == '&' )
|
|
szVarPref = "&";
|
|
}
|
|
|
|
if( szAlias != NULL && szVar != NULL )
|
|
{
|
|
if( pArg->pNext && pArg->pNext->ExprType == HB_ET_STRING )
|
|
szText = "";
|
|
else
|
|
szText = hb_xstrcpy( NULL, szAliasPref, szAlias, "->", szVarPref, szVar, NULL );
|
|
}
|
|
}
|
|
else if( pArg->value.asMacro.pExprList == NULL )
|
|
/* Simple macro expansion (not a parenthesized expressions) */
|
|
szText = pArg->value.asMacro.szMacro;
|
|
|
|
pName->value.asSymbol.name = "__GET";
|
|
if( szText == NULL )
|
|
{
|
|
/* @ 0,0 GET &(var)
|
|
* @ 0,0 GET &(var)->var
|
|
* @ 0,0 GET var->&(var)
|
|
*/
|
|
#if defined( HB_MACRO_SUPPORT )
|
|
hb_macroError( EG_SYNTAX, HB_COMP_PARAM );
|
|
#else
|
|
hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_GET_COMPLEX_MACRO, NULL, NULL );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
/* @ 0,0 GET &var => __Get( NIL, var,... )
|
|
* @ 0,0 GET var&var => __Get( NIL, "var&var",... )
|
|
* @ 0,0 GET &var->var => __Get( NIL, "&var->var",... )
|
|
* @ 0,0 GET var->var&var => __Get( NIL, "var->var&var",... )
|
|
* @ 0,0 GET var&var->&var => __Get( NIL, "var&var->&var",... )
|
|
*/
|
|
PHB_EXPR pFirst = pArg; /* save first argument */
|
|
|
|
pArg = hb_compExprNewNil( HB_COMP_PARAM ); /* replace 1-st with NIL */
|
|
if( pFirst->pNext && pFirst->pNext->ExprType == HB_ET_STRING )
|
|
pArg->pNext = pFirst->pNext;
|
|
else
|
|
{
|
|
if( pArg->ExprType == HB_ET_ALIASVAR )
|
|
pArg->pNext = hb_compExprNewString( szText, strlen( szText ), HB_TRUE, HB_COMP_PARAM );
|
|
else if( pFirst->value.asMacro.cMacroOp == '&' )
|
|
/* simple &variable - replace the second argument with
|
|
* a variable name
|
|
*/
|
|
pArg->pNext = hb_compExprNewVar( szText, HB_COMP_PARAM );
|
|
else
|
|
/* text substitution text&variable - replace the second
|
|
* argument with a string
|
|
*/
|
|
pArg->pNext = hb_compExprNewString( szText, strlen( szText ), HB_FALSE, HB_COMP_PARAM );
|
|
|
|
if( pFirst->pNext )
|
|
{
|
|
pArg->pNext->pNext = pFirst->pNext->pNext;
|
|
HB_COMP_EXPR_FREE( pFirst->pNext ); /* delete a second argument */
|
|
}
|
|
}
|
|
HB_COMP_EXPR_FREE( pFirst ); /* delete first argument */
|
|
/* set an updated list of arguments */
|
|
pParms->value.asList.pExprList = pArg;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pName->value.asSymbol.name = "__GET";
|
|
|
|
/* store second and a rest of arguments */
|
|
pNext = pArg->pNext;
|
|
pArg->pNext = NULL;
|
|
/* replace first argument with a set/get codeblock */
|
|
#if ! defined( HB_MACRO_SUPPORT )
|
|
if( pArg->ExprType == HB_ET_VARIABLE &&
|
|
! hb_compVariableFind( HB_COMP_PARAM, pArg->value.asSymbol.name, NULL, NULL ) )
|
|
{
|
|
/* Undeclared variable name - create a set/get codeblock
|
|
* at runtime
|
|
*/
|
|
if( HB_COMP_PARAM->iWarnings >= 2 )
|
|
hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_AMBIGUOUS_VAR, pArg->value.asSymbol.name, NULL );
|
|
HB_COMP_EXPR_FREE( pArg );
|
|
pArg = hb_compExprNewNil( HB_COMP_PARAM );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
pArg = hb_compExprSetGetBlock( pArg, HB_COMP_PARAM );
|
|
}
|
|
/* restore next arguments */
|
|
pArg->pNext = pNext;
|
|
/* set an updated list of arguments */
|
|
pParms->value.asList.pExprList = pArg;
|
|
}
|
|
|
|
pName->value.asSymbol.name =
|
|
hb_compGetFuncID( pName->value.asSymbol.name,
|
|
&pName->value.asSymbol.funcid,
|
|
&pName->value.asSymbol.flags );
|
|
}
|
|
}
|
|
else if( pName->ExprType == HB_ET_MACRO )
|
|
{
|
|
/* Signal that macro compiler have to generate a pcode that will
|
|
* return function name as symbol instead of usual value
|
|
*/
|
|
pName->value.asMacro.SubType = HB_ET_MACRO_SYMBOL;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_compExprNewFunCall(&)" ) );
|
|
}
|
|
|
|
pExpr = HB_COMP_EXPR_NEW( HB_ET_FUNCALL );
|
|
pExpr->value.asFunCall.pParms = pParms;
|
|
pExpr->value.asFunCall.pFunName = pName;
|
|
|
|
return pExpr;
|
|
}
|
|
|
|
/* Creates new array access expression
|
|
* pArray[ pIndex ]
|
|
* NOTE: In case of multiple indexes it is called recursively
|
|
* array[ idx1, idx2 ] => ( array[ idx1 ] )[ idx2 ]
|
|
*/
|
|
#ifdef HB_MACRO_SUPPORT
|
|
PHB_EXPR hb_macroExprNewArrayAt( PHB_EXPR pArray, PHB_EXPR pIndex, HB_COMP_DECL )
|
|
#else
|
|
PHB_EXPR hb_compExprNewArrayAt( PHB_EXPR pArray, PHB_EXPR pIndex, HB_COMP_DECL )
|
|
#endif
|
|
{
|
|
PHB_EXPR pExpr;
|
|
|
|
#ifdef HB_MACRO_SUPPORT
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_macroExprNewArrayAt()" ) );
|
|
#else
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_compExprNewArrayAt()" ) );
|
|
#endif
|
|
|
|
pExpr = HB_COMP_EXPR_NEW( HB_ET_ARRAYAT );
|
|
|
|
/* Check if this expression can be indexed */
|
|
if( ! HB_SUPPORT_ARRSTR )
|
|
HB_EXPR_USE( pArray, HB_EA_ARRAY_AT );
|
|
/* Check if this expression can be an index */
|
|
HB_EXPR_USE( pIndex, HB_EA_ARRAY_INDEX );
|
|
pExpr->value.asList.pExprList = pArray;
|
|
pExpr->value.asList.pIndex = pIndex;
|
|
pExpr->value.asList.reference = HB_FALSE;
|
|
|
|
return pExpr;
|
|
}
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
#ifndef HB_MACRO_SUPPORT
|
|
|
|
/* List of functions which can be used as static initializers */
|
|
static const char * s_szStaticFun[] = {
|
|
"HB_MUTEXCREATE",
|
|
"__BREAKBLOCK"
|
|
};
|
|
|
|
static HB_BOOL hb_compStaticFunction( const char * szName )
|
|
{
|
|
unsigned int ui;
|
|
|
|
for( ui = 0; ui < HB_SIZEOFARRAY( s_szStaticFun ); ++ui )
|
|
{
|
|
if( strcmp( szName, s_szStaticFun[ ui ] ) == 0 )
|
|
return HB_TRUE;
|
|
}
|
|
return HB_FALSE;
|
|
}
|
|
|
|
|
|
static void hb_compExprCheckStaticInitializer( PHB_EXPR pLeftExpr, PHB_EXPR pRightExpr, HB_COMP_DECL )
|
|
{
|
|
if( ( pRightExpr->ExprType > HB_ET_FUNREF ||
|
|
pRightExpr->ExprType == HB_ET_SELF ) &&
|
|
! ( pRightExpr->ExprType == HB_ET_FUNCALL &&
|
|
pRightExpr->value.asFunCall.pFunName->ExprType == HB_ET_FUNNAME &&
|
|
hb_compStaticFunction( pRightExpr->value.asFunCall.pFunName->
|
|
value.asSymbol.name ) &&
|
|
hb_compExprParamListLen( pRightExpr->value.asFunCall.pParms ) == 0 ) )
|
|
{
|
|
/* Illegal initializer for static variable (not a constant value)
|
|
*/
|
|
hb_compErrorStatic( HB_COMP_PARAM, pLeftExpr->value.asSymbol.name, pRightExpr );
|
|
}
|
|
}
|
|
|
|
static void hb_compExprCheckStaticListInitializers( PHB_EXPR pLeftExpr, PHB_EXPR pRightExpr, HB_COMP_DECL )
|
|
{
|
|
PHB_EXPR * pExpr = &pRightExpr->value.asList.pExprList;
|
|
|
|
while( *pExpr )
|
|
{
|
|
if( ! HB_SUPPORT_HARBOUR )
|
|
{
|
|
/* When -kc switch is used expression list is not stripped
|
|
* in reduce operation
|
|
*/
|
|
/* NOTE: During reduction the expression can be replaced by the
|
|
* new one - this will break the linked list of expressions.
|
|
* (classical case of replacing an item in a linked list)
|
|
*/
|
|
PHB_EXPR pNext = ( *pExpr )->pNext; /* store next expression in case the current will be reduced */
|
|
*pExpr = hb_compExprListStrip( *pExpr, HB_COMP_PARAM );
|
|
( *pExpr )->pNext = pNext; /* restore the link to next expression */
|
|
}
|
|
|
|
if( ( *pExpr )->ExprType == HB_ET_ARRAY ||
|
|
( *pExpr )->ExprType == HB_ET_HASH )
|
|
{
|
|
hb_compExprCheckStaticListInitializers( pLeftExpr, *pExpr, HB_COMP_PARAM );
|
|
}
|
|
else
|
|
{
|
|
hb_compExprCheckStaticInitializer( pLeftExpr, *pExpr, HB_COMP_PARAM );
|
|
}
|
|
pExpr = &( *pExpr )->pNext;
|
|
}
|
|
}
|
|
|
|
/* It initializes static variable.
|
|
* It is called in the following context:
|
|
* STATIC sVar := expression
|
|
*
|
|
* pLeftExpr - is a variable name
|
|
* pRightExpr - can be an expression of any type
|
|
*/
|
|
PHB_EXPR hb_compExprAssignStatic( PHB_EXPR pLeftExpr, PHB_EXPR pRightExpr, HB_COMP_DECL )
|
|
{
|
|
PHB_EXPR pExpr;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_compExprAssignStatic()" ) );
|
|
|
|
pExpr = HB_COMP_EXPR_NEW( HB_EO_ASSIGN );
|
|
|
|
pExpr->value.asOperator.pLeft = pLeftExpr;
|
|
/* Try to reduce the assigned value */
|
|
pRightExpr = HB_EXPR_USE( pRightExpr, HB_EA_REDUCE );
|
|
/* When -kc switch is used expression list is not stripped
|
|
* in reduce operation
|
|
*/
|
|
if( ! HB_SUPPORT_HARBOUR )
|
|
pRightExpr = hb_compExprListStrip( pRightExpr, HB_COMP_PARAM );
|
|
|
|
pExpr->value.asOperator.pRight = pRightExpr;
|
|
|
|
if( pRightExpr->ExprType == HB_ET_ARGLIST )
|
|
{
|
|
/* HB_ET_ARGLIST is used in case of STATIC var[dim1, dim2, dimN]
|
|
* was used - we have to check if all array dimensions are
|
|
* constant values
|
|
*/
|
|
hb_compExprCheckStaticListInitializers( pLeftExpr, pRightExpr, HB_COMP_PARAM );
|
|
}
|
|
else if( pRightExpr->ExprType == HB_ET_ARRAY )
|
|
{
|
|
/* { elem1, elem2, elemN } was used as initializer
|
|
* Scan an array for illegal initializers.
|
|
* An array item have to be a const value too.
|
|
*/
|
|
hb_compExprCheckStaticListInitializers( pLeftExpr, pRightExpr, HB_COMP_PARAM );
|
|
}
|
|
else if( pRightExpr->ExprType == HB_ET_HASH )
|
|
{
|
|
/* { idx1=>var1, idx2=>var2, idxN=>varN } was used as initializer
|
|
* Scan a hash array for illegal initializers.
|
|
* A hash item have to be a const value too.
|
|
*/
|
|
hb_compExprCheckStaticListInitializers( pLeftExpr, pRightExpr, HB_COMP_PARAM );
|
|
}
|
|
else
|
|
{
|
|
hb_compExprCheckStaticInitializer( pLeftExpr, pRightExpr, HB_COMP_PARAM );
|
|
}
|
|
|
|
return pExpr;
|
|
}
|
|
|
|
PHB_EXPR hb_compExprSetCodeblockBody( PHB_EXPR pExpr, HB_BYTE * pCode, HB_SIZE nLen )
|
|
{
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_compExprSetCodeblockBody(%p,%p,%" HB_PFS "u)", pExpr, pCode, nLen ) );
|
|
|
|
pExpr->value.asCodeblock.string = ( char * ) hb_xgrab( nLen + 1 );
|
|
memcpy( pExpr->value.asCodeblock.string, pCode, nLen );
|
|
pExpr->value.asCodeblock.string[ nLen ] = '\0';
|
|
pExpr->nLength = nLen;
|
|
|
|
return pExpr;
|
|
}
|
|
#endif
|
|
|
|
/* ************************************************************************* */
|
|
|
|
#if defined( HB_MACRO_SUPPORT )
|
|
|
|
/* Generates pcode to push an expressions
|
|
* NOTE: It pushes a value on the stack and leaves this value on the stack
|
|
*/
|
|
PHB_EXPR hb_macroExprGenPush( PHB_EXPR pExpr, HB_COMP_DECL )
|
|
{
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_macroExprGenPush(%i)", pExpr->ExprType ) );
|
|
|
|
pExpr = HB_EXPR_USE( pExpr, HB_EA_REDUCE );
|
|
return HB_EXPR_USE( pExpr, HB_EA_PUSH_PCODE );
|
|
}
|
|
|
|
/* Generates pcode to pop an expressions
|
|
*/
|
|
PHB_EXPR hb_macroExprGenPop( PHB_EXPR pExpr, HB_COMP_DECL )
|
|
{
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_macroExprGenPop(%i)", pExpr->ExprType ) );
|
|
|
|
pExpr = HB_EXPR_USE( pExpr, HB_EA_REDUCE );
|
|
HB_EXPR_USE( pExpr, HB_EA_LVALUE );
|
|
return HB_EXPR_USE( pExpr, HB_EA_POP_PCODE );
|
|
}
|
|
|
|
#else
|
|
|
|
/* Generates pcode to push an expressions
|
|
* NOTE: It pushes a value on the stack and leaves this value on the stack
|
|
*/
|
|
PHB_EXPR hb_compExprGenPush( PHB_EXPR pExpr, HB_COMP_DECL )
|
|
{
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_compExprGenPush(%i)", pExpr->ExprType ) );
|
|
|
|
pExpr = HB_EXPR_USE( pExpr, HB_EA_REDUCE );
|
|
return HB_EXPR_USE( pExpr, HB_EA_PUSH_PCODE );
|
|
}
|
|
|
|
/* Generates pcode to pop an expressions
|
|
*/
|
|
PHB_EXPR hb_compExprGenPop( PHB_EXPR pExpr, HB_COMP_DECL )
|
|
{
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_compExprGenPop(%i)", pExpr->ExprType ) );
|
|
|
|
HB_EXPR_USE( pExpr, HB_EA_LVALUE );
|
|
return HB_EXPR_USE( pExpr, HB_EA_POP_PCODE );
|
|
}
|
|
|
|
/* Generates pcode for inline expression used as a statement
|
|
* NOTE: It doesn't not leave any value on the eval stack
|
|
*/
|
|
PHB_EXPR hb_compExprGenStatement( PHB_EXPR pExpr, HB_COMP_DECL )
|
|
{
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_compExprGenStatement(%p)", pExpr ) );
|
|
if( pExpr )
|
|
{
|
|
if( pExpr->ExprType == HB_EO_EQUAL )
|
|
{
|
|
/* NOTE: direct type change */
|
|
pExpr->ExprType = HB_EO_ASSIGN;
|
|
}
|
|
|
|
pExpr = HB_EXPR_USE( pExpr, HB_EA_REDUCE );
|
|
HB_EXPR_USE( pExpr, HB_EA_STATEMENT );
|
|
}
|
|
return pExpr;
|
|
}
|
|
|
|
PHB_EXPR hb_compExprReduce( PHB_EXPR pExpr, HB_COMP_DECL )
|
|
{
|
|
return HB_EXPR_USE( pExpr, HB_EA_REDUCE );
|
|
}
|
|
#endif
|
|
|
|
/* ************************************************************************* */
|