/* 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 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 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; }
/* Delete all components and delete self */ static void hb_compExprFree( HB_COMP_DECL, PHB_EXPR pExpr ) { HB_TRACE( HB_TR_DEBUG, ( "hb_compExprFree()" ) ); HB_EXPR_USE( pExpr, HB_EA_DELETE ); hb_compExprDealloc( HB_COMP_PARAM, pExpr ); }
/* 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_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; }
PHB_EXPR hb_compExprReduce( PHB_EXPR pExpr, HB_COMP_DECL ) { return HB_EXPR_USE( pExpr, HB_EA_REDUCE ); }
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; /* 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 ) { HB_USHORT uiCount; /* 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 ) { /* @ 0,0 GET &var => __Get( NIL, var,... ) * @ 0,0 GET var&var => __Get( NIL, "var&var",... ) */ pName->value.asSymbol.name = "__GET"; if( pArg->value.asMacro.pExprList == NULL ) { /* Simple macro expansion (not a parenthesized expressions) */ PHB_EXPR pFirst; pFirst = pArg; /* first argument */ pNext = pFirst->pNext; /* second argument */ if( pNext ) pNext = pNext->pNext; /* third argument */ pArg = hb_compExprNewNil( HB_COMP_PARAM ); /* replace 1st with NIL */ pParms->value.asList.pExprList = pArg; pArg->pNext = pFirst->pNext; if( pFirst->value.asMacro.cMacroOp == '&' ) { /* simple &variable - replace the second argument with * a variable name */ const char * szName = pFirst->value.asMacro.szMacro; if( pFirst->pNext ) HB_COMP_EXPR_FREE( pFirst->pNext ); /* delete a second argument */ pArg->pNext = hb_compExprNewVar( szName, HB_COMP_PARAM ); pArg->pNext->pNext = pNext; /* restore third argument */ } else { /* text substitution text&variable - replace the second * argument with a string */ if( pArg->pNext == NULL ) { /* no second argument */ const char *szText = pFirst->value.asMacro.szMacro; pArg->pNext = hb_compExprNewString( szText, strlen( szText ), HB_FALSE, HB_COMP_PARAM ); pArg->pNext->pNext = pNext; } } HB_COMP_EXPR_FREE( pFirst ); /* delete first argument */ } else { /* @ 0,0 GET &(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 { 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 ) { if( hb_compVariableFind( HB_COMP_PARAM, pArg->value.asSymbol.name, NULL, NULL ) ) pArg = hb_compExprSetGetBlock( pArg, HB_COMP_PARAM ); else { /* 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; }