/* * $Id$ */ /* * Harbour Project source code: * Compiler Expression Optimizer - utilities * * Copyright 1999 Ryszard Glab * www - http://www.harbour-project.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ #include #include "hbcomp.h" #include "hbmacro.ch" #define HB_USE_ARRAYAT_REF /* Temporary disabled optimization with references to object variables until we will not have extended reference items in our HVM [druzus] */ /* #define HB_USE_OBJMSG_REF */ /* ************************************************************************* */ void hb_compExprPushSendPop( HB_EXPR_PTR pSelf, HB_COMP_DECL ) { if( pSelf->value.asMessage.pObject ) { /* Push _message */ if( pSelf->value.asMessage.szMessage ) { HB_EXPR_PCODE2( hb_compGenMessageData, pSelf->value.asMessage.szMessage, TRUE ); } else { if( pSelf->value.asMessage.pMessage->ExprType == HB_ET_MACRO ) /* o:¯o := value * set ASSIGN flag in macro expression * it's cleared just after use */ pSelf->value.asMessage.pMessage->value.asMacro.SubType |= HB_ET_MACRO_ASSIGN; HB_EXPR_USE( pSelf->value.asMessage.pMessage, HB_EA_PUSH_PCODE ); } /* Push object */ HB_EXPR_USE( pSelf->value.asMessage.pObject, HB_EA_PUSH_PCODE ); } else /* WITH OBJECT */ { /* Push _message and object */ if( pSelf->value.asMessage.szMessage ) { HB_EXPR_PCODE2( hb_compGenMessageData, pSelf->value.asMessage.szMessage, FALSE ); } else { if( pSelf->value.asMessage.pMessage->ExprType == HB_ET_MACRO ) /* o:¯o := value * set ASSIGN flag in macro expression * it's cleared just after use */ pSelf->value.asMessage.pMessage->value.asMacro.SubType |= HB_ET_MACRO_ASSIGN; HB_EXPR_USE( pSelf->value.asMessage.pMessage, HB_EA_PUSH_PCODE ); /* Push object using WITHOBJECTMESSAGE pcode */ HB_EXPR_PCODE2( hb_compGenMessage, NULL, FALSE ); } } } void hb_compExprPushSendPush( HB_EXPR_PTR pSelf, HB_COMP_DECL ) { if( pSelf->value.asMessage.pObject ) { /* Push message */ if( pSelf->value.asMessage.szMessage ) { HB_EXPR_PCODE2( hb_compGenMessage, pSelf->value.asMessage.szMessage, TRUE ); } else { HB_EXPR_USE( pSelf->value.asMessage.pMessage, HB_EA_PUSH_PCODE ); } /* Push object */ HB_EXPR_USE( pSelf->value.asMessage.pObject, HB_EA_PUSH_PCODE ); } else /* WITH OBJECT */ { if( pSelf->value.asMessage.szMessage ) { /* Push message and object */ HB_EXPR_PCODE2( hb_compGenMessage, pSelf->value.asMessage.szMessage, FALSE ); } else { /* Push message */ HB_EXPR_USE( pSelf->value.asMessage.pMessage, HB_EA_PUSH_PCODE ); /* Push object using WITHOBJECTMESSAGE pcode */ HB_EXPR_PCODE2( hb_compGenMessage, NULL, FALSE ); } } } static void hb_compExprPushSendPopPush( HB_EXPR_PTR pObj, HB_EXPR_PTR pValue, BOOL fPreOp, BYTE bOper, HB_COMP_DECL ) { if( HB_SUPPORT_HARBOUR ) { hb_compExprPushSendPop( pObj, HB_COMP_PARAM ); /* duplicate object variable */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_DUPLICATE ); /* Push message */ if( pObj->value.asMessage.szMessage ) { /* TRUE used intnetionally to not push object variable in WITH OBJECT */ HB_EXPR_PCODE2( hb_compGenMessage, pObj->value.asMessage.szMessage, TRUE ); } else { HB_EXPR_USE( pObj->value.asMessage.pMessage, HB_EA_PUSH_PCODE ); } HB_EXPR_PCODE2( hb_compGenPCode2, HB_P_SWAP, 0 ); HB_EXPR_PCODE2( hb_compGenPCode2, HB_P_SENDSHORT, 0 ); if( fPreOp ) { /* push the result on the stack */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_DUPLICATE ); HB_EXPR_PCODE2( hb_compGenPCode2, HB_P_SWAP, 2 ); } } else { if( fPreOp ) { /* push current value - it will be a result of whole expression */ HB_EXPR_USE( pObj, HB_EA_PUSH_PCODE ); } hb_compExprPushSendPop( pObj, HB_COMP_PARAM ); hb_compExprPushSendPush( pObj, HB_COMP_PARAM ); HB_EXPR_PCODE2( hb_compGenPCode2, HB_P_SENDSHORT, 0 ); } /* push increment value */ if( pValue ) { HB_EXPR_USE( pValue, HB_EA_PUSH_PCODE ); } /* do operation */ HB_EXPR_PCODE1( hb_compGenPCode1, bOper ); /* Now do the assignment - call pop message with one argument */ HB_EXPR_PCODE2( hb_compGenPCode2, HB_P_SENDSHORT, 1 ); if( fPreOp ) { /* pop the unneeded value left by assignment message from the stack */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_POP ); } } void hb_compExprDelOperator( HB_EXPR_PTR pExpr, HB_COMP_DECL ) { if( pExpr->value.asOperator.pLeft ) HB_EXPR_PCODE1( hb_compExprDelete, pExpr->value.asOperator.pLeft ); if( pExpr->value.asOperator.pRight ) HB_EXPR_PCODE1( hb_compExprDelete, pExpr->value.asOperator.pRight ); } /* Generates pcodes for compound operators += -= *= /= %= ^= * * pExpr is an expression created by hb_compExprNewEq functions */ /* NOTE: COMPATIBILITY ISSUE: * The HB_SUPPORT_HARBOUR in code below determines * the way the chained send messages are handled. * For example, the following code: * * a:b( COUNT() ):c += 1 * * will be handled as: * * a:b( COUNT() ):c := a:b( COUNT() ):c + 1 * * in strict Clipper compatibility mode * (HB_SUPPORT_HARBOUR is not set: -kc compiler switch ) and * * temp := a:b( COUNT() ), temp:c += 1 * * in non-strict mode (-kh). * In practice in Clipper it will call COUNT() function two times: the * first time before addition and the second one after addition - in Harbour, * COUNT() function will be called only once, before addition. * The Harbour (non-strict) method is: * 1) faster * 2) it guarantees that the same instance variable of the same object will * be changed */ void hb_compExprPushOperEq( HB_EXPR_PTR pSelf, BYTE bOpEq, HB_COMP_DECL ) { BYTE bNewOp; if( HB_SUPPORT_HARBOUR ) { switch( bOpEq ) { case HB_P_PLUS: bNewOp = HB_P_PLUSEQ; break; case HB_P_MINUS: bNewOp = HB_P_MINUSEQ; break; case HB_P_MULT: bNewOp = HB_P_MULTEQ; break; case HB_P_DIVIDE: bNewOp = HB_P_DIVEQ; break; case HB_P_MODULUS: bNewOp = HB_P_MODEQ; break; case HB_P_POWER: bNewOp = HB_P_EXPEQ; break; default: bNewOp = bOpEq; break; } } else bNewOp = bOpEq; /* NOTE: an object instance variable needs special handling */ if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_SEND ) { if( pSelf->value.asOperator.pLeft->value.asMessage.pParms ) { hb_compErrorLValue( HB_COMP_PARAM, pSelf->value.asOperator.pLeft ); } #ifdef HB_USE_OBJMSG_REF else if( bOpEq != bNewOp ) { hb_compExprPushSendPop( pSelf->value.asOperator.pLeft, HB_COMP_PARAM ); HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_PUSHOVARREF ); /* push increment value */ HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE1( hb_compGenPCode1, bNewOp ); } #endif else { hb_compExprPushSendPopPush( pSelf->value.asOperator.pLeft, pSelf->value.asOperator.pRight, FALSE, bOpEq, HB_COMP_PARAM ); } return; } else if( bOpEq != bNewOp ) { if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_MACRO ) { USHORT usType = pSelf->value.asOperator.pLeft->value.asMacro.SubType; if( usType == HB_ET_MACRO_VAR ) { /* NOTE: direct type change */ pSelf->value.asOperator.pLeft->value.asMacro.SubType = HB_ET_MACRO_REFER; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE1( hb_compGenPCode1, bNewOp ); pSelf->value.asOperator.pLeft->value.asMacro.SubType = usType; return; } } #ifdef HB_USE_ARRAYAT_REF /* NOTE: code for arrays is differ to correctly handle a[ i++ ]++ */ else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_ARRAYAT ) { /* Note: change type to array reference */ pSelf->value.asOperator.pLeft->value.asList.reference = TRUE; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); pSelf->value.asOperator.pLeft->value.asList.reference = FALSE; HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE1( hb_compGenPCode1, bNewOp ); return; } #endif else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_VARIABLE ) { #if defined( HB_MACRO_SUPPORT ) { #else int iScope = hb_compVariableScope( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); if( iScope != HB_VS_LOCAL_FIELD && iScope != HB_VS_GLOBAL_FIELD && iScope != HB_VS_UNDECLARED ) { if( iScope == HB_VS_LOCAL_VAR && pSelf->value.asOperator.pRight->ExprType == HB_ET_NUMERIC && ( bOpEq == HB_P_PLUS || bOpEq == HB_P_MINUS ) ) { if( hb_compExprIsInteger( pSelf->value.asOperator.pRight ) ) { short iIncrement = ( short ) pSelf->value.asOperator.pRight->value.asNum.val.l; if( bOpEq != HB_P_MINUS || iIncrement >= -INT16_MAX ) { int iLocal = hb_compLocalGetPos( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); BYTE buffer[ 5 ]; if( bOpEq == HB_P_MINUS ) iIncrement = -iIncrement; buffer[ 0 ] = HB_P_LOCALADDINT; buffer[ 1 ] = HB_LOBYTE( iLocal ); buffer[ 2 ] = HB_HIBYTE( iLocal ); buffer[ 3 ] = HB_LOBYTE( iIncrement ); buffer[ 4 ] = HB_HIBYTE( iIncrement ); hb_compGenPCodeN( buffer, 5, HB_COMP_PARAM ); HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); return; } } } #endif /* NOTE: direct type change */ pSelf->value.asOperator.pLeft->ExprType = HB_ET_VARREF; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE1( hb_compGenPCode1, bNewOp ); return; } } } /* push old value */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); /* push increment value */ HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); /* perform operation and duplicate the new value */ HB_EXPR_PCODE1( hb_compGenPCode1, bOpEq ); HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_DUPLICATE ); /* pop the new value into variable and leave the copy on the stack */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_POP_PCODE ); } /* Generates pcodes for = syntax * used standalone as a statement (it cannot leave the value on the stack) */ void hb_compExprUseOperEq( HB_EXPR_PTR pSelf, BYTE bOpEq, HB_COMP_DECL ) { BYTE bNewOp; if( HB_SUPPORT_HARBOUR ) { switch( bOpEq ) { case HB_P_PLUS: bNewOp = HB_P_PLUSEQPOP; break; case HB_P_MINUS: bNewOp = HB_P_MINUSEQPOP; break; case HB_P_MULT: bNewOp = HB_P_MULTEQPOP; break; case HB_P_DIVIDE: bNewOp = HB_P_DIVEQPOP; break; case HB_P_MODULUS: bNewOp = HB_P_MODEQPOP; break; case HB_P_POWER: bNewOp = HB_P_EXPEQPOP; break; default: bNewOp = bOpEq; break; } } else bNewOp = bOpEq; /* NOTE: an object instance variable needs special handling */ if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_SEND ) { if( pSelf->value.asOperator.pLeft->value.asMessage.pParms ) { hb_compErrorLValue( HB_COMP_PARAM, pSelf->value.asOperator.pLeft ); } #ifdef HB_USE_OBJMSG_REF else if( bOpEq != bNewOp ) { hb_compExprPushSendPop( pSelf->value.asOperator.pLeft, HB_COMP_PARAM ); HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_PUSHOVARREF ); /* push increment value */ HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE1( hb_compGenPCode1, bNewOp ); } #endif else { hb_compExprPushSendPopPush( pSelf->value.asOperator.pLeft, pSelf->value.asOperator.pRight, FALSE, bOpEq, HB_COMP_PARAM ); /* pop the unneeded value from the stack */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_POP ); } return; } else if( bOpEq != bNewOp ) { if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_MACRO ) { USHORT usType = pSelf->value.asOperator.pLeft->value.asMacro.SubType; if( usType == HB_ET_MACRO_VAR ) { /* NOTE: direct type change */ pSelf->value.asOperator.pLeft->value.asMacro.SubType = HB_ET_MACRO_REFER; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE1( hb_compGenPCode1, bNewOp ); pSelf->value.asOperator.pLeft->value.asMacro.SubType = usType; return; } } #ifdef HB_USE_ARRAYAT_REF /* NOTE: code for arrays is differ to correctly handle a[ i++ ]++ */ else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_ARRAYAT ) { /* Note: change type to array reference */ pSelf->value.asOperator.pLeft->value.asList.reference = TRUE; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); pSelf->value.asOperator.pLeft->value.asList.reference = FALSE; HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE1( hb_compGenPCode1, bNewOp ); return; } #endif else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_VARIABLE ) { HB_EXPRTYPE iOldType; #if defined( HB_MACRO_SUPPORT ) { #else int iScope = hb_compVariableScope( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); if( iScope != HB_VS_LOCAL_FIELD && iScope != HB_VS_GLOBAL_FIELD && iScope != HB_VS_UNDECLARED ) { if( iScope == HB_VS_LOCAL_VAR && pSelf->value.asOperator.pRight->ExprType == HB_ET_NUMERIC && ( bOpEq == HB_P_PLUS || bOpEq == HB_P_MINUS ) ) { if( hb_compExprIsInteger( pSelf->value.asOperator.pRight ) ) { short iIncrement = ( short ) pSelf->value.asOperator.pRight->value.asNum.val.l; if( bOpEq != HB_P_MINUS || iIncrement >= -INT16_MAX ) { int iLocal = hb_compLocalGetPos( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); BYTE buffer[ 5 ]; if( bOpEq == HB_P_MINUS ) iIncrement = -iIncrement; buffer[ 0 ] = HB_P_LOCALADDINT; buffer[ 1 ] = HB_LOBYTE( iLocal ); buffer[ 2 ] = HB_HIBYTE( iLocal ); buffer[ 3 ] = HB_LOBYTE( iIncrement ); buffer[ 4 ] = HB_HIBYTE( iIncrement ); hb_compGenPCodeN( buffer, 5, HB_COMP_PARAM ); return; } } } #endif /* NOTE: direct type change */ iOldType = pSelf->value.asOperator.pLeft->ExprType; pSelf->value.asOperator.pLeft->ExprType = HB_ET_VARREF; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE1( hb_compGenPCode1, bNewOp ); pSelf->value.asOperator.pLeft->ExprType = iOldType; return; } } } /* push old value */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); /* push increment value */ HB_EXPR_USE( pSelf->value.asOperator.pRight, HB_EA_PUSH_PCODE ); /* add */ HB_EXPR_PCODE1( hb_compGenPCode1, bOpEq ); /* pop the new value into variable and remove it from the stack */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_POP_PCODE ); } /* Generates the pcodes for pre- increment/decrement expressions */ void hb_compExprPushPreOp( HB_EXPR_PTR pSelf, BYTE bOper, HB_COMP_DECL ) { /* NOTE: an object instance variable needs special handling */ if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_SEND ) { if( pSelf->value.asOperator.pLeft->value.asMessage.pParms ) { hb_compErrorLValue( HB_COMP_PARAM, pSelf->value.asOperator.pLeft ); } #ifdef HB_USE_OBJMSG_REF else if( HB_SUPPORT_HARBOUR ) { hb_compExprPushSendPop( pSelf->value.asOperator.pLeft, HB_COMP_PARAM ); HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_PUSHOVARREF ); /* increase/decrease operation, leave unreferenced value on stack */ hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQ : HB_P_DECEQ, HB_COMP_PARAM ); } #endif else { hb_compExprPushSendPopPush( pSelf->value.asOperator.pLeft, NULL, FALSE, bOper, HB_COMP_PARAM ); } return; } else if( HB_SUPPORT_HARBOUR ) { if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_MACRO && pSelf->value.asOperator.pLeft->value.asMacro.SubType == HB_ET_MACRO_VAR ) { USHORT usType = pSelf->value.asOperator.pLeft->value.asMacro.SubType; /* NOTE: direct type change */ pSelf->value.asOperator.pLeft->value.asMacro.SubType = HB_ET_MACRO_REFER; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); pSelf->value.asOperator.pLeft->value.asMacro.SubType = usType; /* increase/decrease operation, leave unreferenced value on stack */ hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQ : HB_P_DECEQ, HB_COMP_PARAM ); return; } #ifdef HB_USE_ARRAYAT_REF /* NOTE: code for arrays is differ to correctly handle a[ i++ ]++ */ else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_ARRAYAT ) { /* push reference to current value */ /* Note: change type to array reference */ pSelf->value.asOperator.pLeft->value.asList.reference = TRUE; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); pSelf->value.asOperator.pLeft->value.asList.reference = FALSE; /* increase/decrease operation, leave unreferenced value on stack */ hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQ : HB_P_DECEQ, HB_COMP_PARAM ); return; } #endif #if !defined( HB_MACRO_SUPPORT ) else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_VARIABLE ) { int iScope = hb_compVariableScope( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); if( iScope != HB_VS_LOCAL_FIELD && iScope != HB_VS_GLOBAL_FIELD && iScope != HB_VS_UNDECLARED ) { if( iScope == HB_VS_LOCAL_VAR ) { int iLocal = hb_compLocalGetPos( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); if( bOper == HB_P_INC ) { hb_compGenPCode3( HB_P_LOCALINCPUSH, HB_LOBYTE( iLocal ), HB_HIBYTE( iLocal ), HB_COMP_PARAM ); } else { hb_compGenPCode3( HB_P_LOCALDEC, HB_LOBYTE( iLocal ), HB_HIBYTE( iLocal ), HB_COMP_PARAM ); /* Push current value */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); } } else { /* NOTE: direct type change */ HB_EXPRTYPE iOldType = pSelf->value.asOperator.pLeft->ExprType; pSelf->value.asOperator.pLeft->ExprType = HB_ET_VARREF; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQ : HB_P_DECEQ, HB_COMP_PARAM ); pSelf->value.asOperator.pLeft->ExprType = iOldType; } return; } } #endif } /* Push current value */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); /* Increment */ HB_EXPR_PCODE1( hb_compGenPCode1, bOper ); /* duplicate a value */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_DUPLICATE ); /* pop new value and leave the duplicated copy of it on the stack */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_POP_PCODE ); } /* Generates the pcodes for post- increment/decrement expressions */ void hb_compExprPushPostOp( HB_EXPR_PTR pSelf, BYTE bOper, HB_COMP_DECL ) { /* NOTE: an object instance variable needs special handling */ if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_SEND ) { if( pSelf->value.asOperator.pLeft->value.asMessage.pParms ) { hb_compErrorLValue( HB_COMP_PARAM, pSelf->value.asOperator.pLeft ); } #ifdef HB_USE_OBJMSG_REF else if( HB_SUPPORT_HARBOUR ) { /* push reference to current value */ hb_compExprPushSendPop( pSelf->value.asOperator.pLeft, HB_COMP_PARAM ); HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_PUSHOVARREF ); /* Duplicate the reference and unref the original one - * it will be the result of whole expression */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_DUPLUNREF ); /* increment/decrement the value */ hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQPOP : HB_P_DECEQPOP, HB_COMP_PARAM ); } #endif else { hb_compExprPushSendPopPush( pSelf->value.asOperator.pLeft, NULL, TRUE, bOper, HB_COMP_PARAM ); } return; } else if( HB_SUPPORT_HARBOUR ) { if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_MACRO && pSelf->value.asOperator.pLeft->value.asMacro.SubType == HB_ET_MACRO_VAR ) { USHORT usType = pSelf->value.asOperator.pLeft->value.asMacro.SubType; /* NOTE: direct type change */ pSelf->value.asOperator.pLeft->value.asMacro.SubType = HB_ET_MACRO_REFER; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); pSelf->value.asOperator.pLeft->value.asMacro.SubType = usType; /* Duplicate the reference and unref the original one - * it will be the result of whole expression */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_DUPLUNREF ); /* increase/decrease operation */ hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQPOP : HB_P_DECEQPOP, HB_COMP_PARAM ); return; } #ifdef HB_USE_ARRAYAT_REF /* NOTE: code for arrays is differ to correctly handle a[ i++ ]++ */ else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_ARRAYAT ) { /* push reference to current value */ /* Note: change type to array reference */ pSelf->value.asOperator.pLeft->value.asList.reference = TRUE; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); pSelf->value.asOperator.pLeft->value.asList.reference = FALSE; /* Duplicate the reference and unref the original one - * it will be the result of whole expression */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_DUPLUNREF ); /* increase/decrease operation */ hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQPOP : HB_P_DECEQPOP, HB_COMP_PARAM ); return; } #endif #if !defined( HB_MACRO_SUPPORT ) else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_VARIABLE ) { int iScope = hb_compVariableScope( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); if( iScope != HB_VS_LOCAL_FIELD && iScope != HB_VS_GLOBAL_FIELD && iScope != HB_VS_UNDECLARED ) { if( iScope == HB_VS_LOCAL_VAR ) { int iLocal = hb_compLocalGetPos( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); /* Push current value */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); hb_compGenPCode3( ( bOper == HB_P_INC ) ? HB_P_LOCALINC : HB_P_LOCALDEC, HB_LOBYTE( iLocal ), HB_HIBYTE( iLocal ), HB_COMP_PARAM ); } else { /* NOTE: direct type change */ HB_EXPRTYPE iOldType = pSelf->value.asOperator.pLeft->ExprType; pSelf->value.asOperator.pLeft->ExprType = HB_ET_VARREF; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_DUPLUNREF ); hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQPOP : HB_P_DECEQPOP, HB_COMP_PARAM ); pSelf->value.asOperator.pLeft->ExprType = iOldType; } return; } } #endif } /* Push current value */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); /* Duplicate value */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_DUPLICATE ); /* Increment */ HB_EXPR_PCODE1( hb_compGenPCode1, bOper ); /* pop new value from the stack */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_POP_PCODE ); } /* Generates the pcodes for increment/decrement operations * used standalone as a statement */ void hb_compExprUsePreOp( HB_EXPR_PTR pSelf, BYTE bOper, HB_COMP_DECL ) { /* NOTE: an object instance variable needs special handling */ if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_SEND ) { if( pSelf->value.asOperator.pLeft->value.asMessage.pParms ) { hb_compErrorLValue( HB_COMP_PARAM, pSelf->value.asOperator.pLeft ); } #ifdef HB_USE_OBJMSG_REF else if( HB_SUPPORT_HARBOUR ) { /* push reference to current value */ hb_compExprPushSendPop( pSelf->value.asOperator.pLeft, HB_COMP_PARAM ); HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_PUSHOVARREF ); /* increment/decrement the value */ hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQPOP : HB_P_DECEQPOP, HB_COMP_PARAM ); } #endif else { hb_compExprPushSendPopPush( pSelf->value.asOperator.pLeft, NULL, FALSE, bOper, HB_COMP_PARAM ); /* pop the value from the stack */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_POP ); } return; } else if( HB_SUPPORT_HARBOUR ) { if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_MACRO && pSelf->value.asOperator.pLeft->value.asMacro.SubType == HB_ET_MACRO_VAR ) { USHORT usType = pSelf->value.asOperator.pLeft->value.asMacro.SubType; /* NOTE: direct type change */ pSelf->value.asOperator.pLeft->value.asMacro.SubType = HB_ET_MACRO_REFER; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); pSelf->value.asOperator.pLeft->value.asMacro.SubType = usType; /* increase/decrease operation */ hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQPOP : HB_P_DECEQPOP, HB_COMP_PARAM ); return; } #ifdef HB_USE_ARRAYAT_REF /* NOTE: code for arrays is differ to correctly handle a[ i++ ]++ */ else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_ARRAYAT ) { /* push reference to current value */ /* Note: change type to array reference */ pSelf->value.asOperator.pLeft->value.asList.reference = TRUE; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); pSelf->value.asOperator.pLeft->value.asList.reference = FALSE; /* increase/decrease operation */ hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQPOP : HB_P_DECEQPOP, HB_COMP_PARAM ); return; } #endif #if !defined( HB_MACRO_SUPPORT ) else if( pSelf->value.asOperator.pLeft->ExprType == HB_ET_VARIABLE ) { int iScope = hb_compVariableScope( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); if( iScope != HB_VS_LOCAL_FIELD && iScope != HB_VS_GLOBAL_FIELD && iScope != HB_VS_UNDECLARED ) { if( iScope == HB_VS_LOCAL_VAR ) { int iLocal = hb_compLocalGetPos( HB_COMP_PARAM, pSelf->value.asOperator.pLeft->value.asSymbol ); hb_compGenPCode3( ( bOper == HB_P_INC ) ? HB_P_LOCALINC : HB_P_LOCALDEC, HB_LOBYTE( iLocal ), HB_HIBYTE( iLocal ), HB_COMP_PARAM ); } else { /* NOTE: direct type change */ HB_EXPRTYPE iOldType = pSelf->value.asOperator.pLeft->ExprType; pSelf->value.asOperator.pLeft->ExprType = HB_ET_VARREF; HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); hb_compGenPCode1( ( bOper == HB_P_INC ) ? HB_P_INCEQPOP : HB_P_DECEQPOP, HB_COMP_PARAM ); pSelf->value.asOperator.pLeft->ExprType = iOldType; } return; } } #endif } /* Push current value */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_PUSH_PCODE ); /* Increment */ HB_EXPR_PCODE1( hb_compGenPCode1, bOper ); /* pop new value from the stack */ HB_EXPR_USE( pSelf->value.asOperator.pLeft, HB_EA_POP_PCODE ); } /* Generate pcode for aliased expression which contains macro operator on * the left or right side of the alias operator * expression->¯o or ¯o->expression or ¯o->¯o */ void hb_compExprUseAliasMacro( HB_EXPR_PTR pAliasedVar, BYTE bAction, HB_COMP_DECL ) { HB_EXPR_PTR pAlias, pVar; /* Alias->Var */ pAlias = pAliasedVar->value.asAlias.pAlias; pVar = pAliasedVar->value.asAlias.pVar; if( pAlias->ExprType == HB_ET_ALIAS ) { /* database alias */ /* Push alias identifier as string so it can be joined with * variable at runtime * NOTE: * ALIAS->&var is the same as &( "ALIAS->" + var ) * */ HB_EXPR_PCODE2( hb_compGenPushString, pAlias->value.asSymbol, strlen( pAlias->value.asSymbol ) + 1 ); HB_EXPR_USE( pVar, HB_EA_PUSH_PCODE ); if( bAction == HB_EA_PUSH_PCODE ) HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_MACROPUSHALIASED ); else HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_MACROPOPALIASED ); } else if( pVar->ExprType == HB_ET_VARIABLE ) { /* NOTE: * ¯o->var is the same as: &( macro + "->var" ) */ HB_EXPR_USE( pAlias, HB_EA_PUSH_PCODE ); HB_EXPR_PCODE2( hb_compGenPushString, pVar->value.asSymbol, strlen( pVar->value.asSymbol ) + 1 ); if( bAction == HB_EA_PUSH_PCODE ) HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_MACROPUSHALIASED ); else HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_MACROPOPALIASED ); } else { HB_EXPR_USE( pAlias, HB_EA_PUSH_PCODE ); HB_EXPR_USE( pVar, HB_EA_PUSH_PCODE ); if( bAction == HB_EA_PUSH_PCODE ) HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_MACROPUSHALIASED ); else HB_EXPR_PCODE1( hb_compGenPCode1, HB_P_MACROPOPALIASED ); } /* Always add byte to pcode indicating requested macro compiler flag. */ HB_EXPR_PCODE1( hb_compGenPCode1, HB_MACRO_GENFLAGS ); } /* Reduces the list of expressions * * pExpr is the first expression on the list */ ULONG hb_compExprReduceList( HB_EXPR_PTR pExpr, HB_COMP_DECL ) { HB_EXPR_PTR pNext; HB_EXPR_PTR * pPrev; ULONG ulCnt = 0; /* NOTE: During optimalization an expression on the list can be * replaced by the new one */ pPrev = &pExpr->value.asList.pExprList; pExpr = pExpr->value.asList.pExprList; while( pExpr ) { pNext = pExpr->pNext; /* store next expression in case the current will be reduced */ pExpr = HB_EXPR_USE( pExpr, HB_EA_REDUCE ); *pPrev = pExpr; /* store a new expression into the previous one */ pExpr->pNext = pNext; /* restore the link to next expression */ pPrev = &pExpr->pNext; pExpr = pNext; ++ulCnt; } return ulCnt; }