diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 0b66976058..30e9dcbc26 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -16,6 +16,38 @@ The license applies to all entries newer than 2009-04-28. */ +2012-09-19 04:06 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * harbour/include/hbexprb.c + * harbour/include/hbcomp.h + * harbour/include/hbcompdf.h + * harbour/src/compiler/hbusage.c + * harbour/src/compiler/harbour.yyc + * harbour/src/compiler/harbour.y + * harbour/src/compiler/ppcomp.c + * harbour/src/compiler/hbmain.c + * harbour/src/compiler/cmdcheck.c + * harbour/doc/cmpopt.txt + * harbour/doc/xhb-diff.txt + + added new harbour compiler switch: + -kd => accept macros with declared symbols + This switch allows to use declared symbols like LOCALs, STATICs + and FIELDs in macros and macrocodeblocks (every evaluated). + ; Please do not confuse different things. Above modification + does not mean to that such variables are visible for macro + compiler. It only allows to write code like: + cbVar := {|| &cLocal + cPrivate } + or: + cbVar := {|| &cLocalPref.func&cPriv1( cPriv2 ) } + or: + ? &cLocalPref.func&cPriv1( cPriv2 ) + etc. + If possible then for macrocodeblocks Harbour compiler tries to + generate early eval code in which macros are expanded when codeblock + is created. Otherwise macros are expanded each time codeblocks are + evaluated. + For more information look at harbour/doc/xhb-diff.txt section: + MACROS WITH DECLARED SYMBOLS + 2012-09-18 18:26 UTC+0200 Viktor Szakats (harbour syenar.net) * contrib/hbide/main.prg ! include rddads.hbx on win/linux platforms only diff --git a/harbour/doc/cmpopt.txt b/harbour/doc/cmpopt.txt index a1e65e25c7..7678175e83 100644 --- a/harbour/doc/cmpopt.txt +++ b/harbour/doc/cmpopt.txt @@ -199,6 +199,25 @@ declarations. This code illustrates it: This behavior is not replicated in Harbour even if -kc switch is used and Harbour optimize expressions in all declarations. +Harbour supports macro expansion for expressions with declared symbols. +This functionality can be enabled by -kd compiler switch: + -kd => accept macros with declared symbols +It only allows to write code like: + cbVar := {|| &cLocal + cPrivate } +or: + cbVar := {|| &cLocalPref.func&cPriv1( cPriv2 ) } +or: + ? &cLocalPref.func&cPriv1( cPriv2, &cStatic ) +etc. +If possible then for macrocodeblocks Harbour compiler tries to +generate early eval code in which macros are expanded when codeblock +is created. Otherwise macros are expanded each time codeblock is +evaluated. +This feature can be useful also in porting some other xbase compatible +code to Harbour because some compilers just like xHarbour accepted +in some limited way officially unsupported syntax with macros using +declared symbols. + Harbour has additional optimization phase which operates on generated PCODE. It can also reduce expressions, joins jumps, removes death or meaningless code which can appear after all other optimizations and were not optimized diff --git a/harbour/doc/xhb-diff.txt b/harbour/doc/xhb-diff.txt index d9bea0f2ac..5043fa1857 100644 --- a/harbour/doc/xhb-diff.txt +++ b/harbour/doc/xhb-diff.txt @@ -627,6 +627,69 @@ hb_arrayToParams() or similar function. +### MACROS WITH DECLARED SYMBOLS ### +========================================== +Harbour supports macro expansion for expressions with declared symbols. +This functionality can be enabled by -kd compiler switch: + -kd => accept macros with declared symbols +It allows to write code like: + cbVar := {|| &cLocal + cPrivate } +or: + cbVar := {|| &cLocalPref.func&cPriv1( cPriv2 ) } +or: + ? &cLocalPref.func&cPriv1( cPriv2, &cStatic ) +etc. +If it's possible then for macrocodeblocks Harbour compiler tries to +generate early eval code in which macros are expanded when codeblock +is created. Otherwise macros are expanded each time codeblock is +evaluated. +xHarbour has also similar extension but limited to only to macro +variables and it works only if other macros are not used in the +same expression. When more complicated examples are create xHarbour +compiler generates broken code which generate RTE or GPF during +execution. It also does not support codeblocks which contain mixed +macros and refuse to compile such code. + +This example illustrates macros with declared symbols. + + #ifndef __XHARBOUR__ + #pragma -kd+ + #endif + proc main() + memvar nPrivate + memvar cPriv1, cPriv2 + local cbVar1, cbVar2 + local cLocal := "10", cLocalPref := "hb_" + static cStatic := "'123xyz'" + private nPrivate := 10000 + private cPriv1 := "test1", cPriv2 := "abc" + #ifndef __XHARBOUR__ + cbVar1 := {|| &cLocal + nPrivate + val( &cStatic ) } + cbVar2 := {|| &cLocalPref.func&cPriv1( cPriv2, &cStatic ) } + ? eval( cbVar1 ) + ? eval( cbVar2 ) + #endif + ? &cLocal + nPrivate + val( &cStatic ) + cLocal := "upp" + ? &cLocal.er( &cStatic ) + ? hb_funcTest1( cPriv2, &cStatic ) + ? &cLocalPref.func&cPriv1( cPriv2, &cStatic ) + ? &cLocalPref.func&cPriv1( cPriv2, &cStatic ) + return + + func hb_funcTest1( s1, s2 ) + return s1 + ":" + s2 + +Above code can be compiled by xHarbour but it will not work exploiting +some problems in this compiler and generated code. + +This feature can be useful also in porting some other xbase compatible +code to Harbour because some compilers just like xHarbour accepted +in some limited way officially unsupported syntax with macros using +declared symbols. + + + ### MACRO MESSAGES ### ============================ Both compilers Harbour and xHarbour supports macros as messages. diff --git a/harbour/include/hbcomp.h b/harbour/include/hbcomp.h index d365478e38..b5f8b8a339 100644 --- a/harbour/include/hbcomp.h +++ b/harbour/include/hbcomp.h @@ -289,13 +289,13 @@ extern void hb_compErrorVParams( HB_COMP_DECL, const char * szFuncOrBlock extern HB_EXPR_PTR hb_compErrorStatic( HB_COMP_DECL, const char *, HB_EXPR_PTR ); extern void hb_compErrorCodeblock( HB_COMP_DECL, const char * szBlock ); -extern HB_BOOL hb_compIsValidMacroText( HB_COMP_DECL, const char * szText, HB_SIZE nLen ); +extern void hb_compPushMacroText( HB_COMP_DECL, const char * szText, HB_SIZE nLen, HB_BOOL fMacro ); /* Codeblocks */ -extern void hb_compCodeBlockStart( HB_COMP_DECL, HB_BOOL bLateEval ); /* starts a codeblock creation */ -extern void hb_compCodeBlockEnd( HB_COMP_DECL ); /* end of codeblock creation */ -extern void hb_compCodeBlockStop( HB_COMP_DECL ); /* end of fake codeblock */ -extern void hb_compCodeBlockRewind( HB_COMP_DECL ); /* restart of fake codeblock */ +extern void hb_compCodeBlockStart( HB_COMP_DECL, int iEarlyEvalPass ); /* starts a codeblock creation */ +extern void hb_compCodeBlockEnd( HB_COMP_DECL ); /* end of codeblock creation */ +extern void hb_compCodeBlockStop( HB_COMP_DECL ); /* end of fake codeblock */ +extern void hb_compCodeBlockRewind( HB_COMP_DECL ); /* restart of fake codeblock */ #endif /* HB_MACRO_SUPPORT */ @@ -383,7 +383,8 @@ extern const HB_BYTE hb_comp_pcode_len[]; #define HB_COMPFLAG_OPTJUMP 0x0100 /* -kj turn off jump optimalization */ #define HB_COMPFLAG_HB_INLINE 0x0200 /* -ki hb_inLine(...) { ... } support */ #define HB_COMPFLAG_MACROTEXT 0x0400 /* -kM turn off macrotext substitution */ -#define HB_COMPFLAG_USERCP 0x0800 /* -kU strings in user encoding */ +#define HB_COMPFLAG_USERCP 0x0800 /* -ku strings in user encoding */ +#define HB_COMPFLAG_MACRODECL 0x1000 /* -kd accept macros with declared symbols */ #define HB_COMP_ISSUPPORTED(flag) ( HB_COMP_PARAM->supported & (flag) ) @@ -393,6 +394,7 @@ extern const HB_BYTE hb_comp_pcode_len[]; #define HB_SUPPORT_EXTOPT ( HB_COMP_ISSUPPORTED(HB_COMPFLAG_EXTOPT) ) #define HB_SUPPORT_MACROTEXT ( HB_COMP_ISSUPPORTED(HB_COMPFLAG_MACROTEXT) ) #define HB_SUPPORT_USERCP ( HB_COMP_ISSUPPORTED(HB_COMPFLAG_USERCP) ) +#define HB_SUPPORT_MACRODECL ( HB_COMP_ISSUPPORTED(HB_COMPFLAG_MACRODECL) ) #if defined( HB_MACRO_SUPPORT ) # define HB_MACRO_GENFLAGS HB_COMPFLAG_RT_MACRO diff --git a/harbour/include/hbcompdf.h b/harbour/include/hbcompdf.h index 457a589a46..1ac20c6fc6 100644 --- a/harbour/include/hbcompdf.h +++ b/harbour/include/hbcompdf.h @@ -511,13 +511,13 @@ typedef struct __FUNC HB_BYTE * pCode; /* pointer to a memory block where pcode is stored */ HB_SIZE nPCodeSize; /* total memory size for pcode */ HB_SIZE nPCodePos; /* actual pcode offset */ - int iStaticsBase; /* base for this function statics */ - int iFuncSuffix; /* function suffix for multiple static functions with the same name */ HB_SIZE * pNOOPs; /* pointer to the NOOP array */ HB_SIZE * pJumps; /* pointer to the Jumps array */ HB_SIZE nNOOPs; /* NOOPs Counter */ HB_SIZE nJumps; /* Jumps Counter */ - HB_BOOL bLateEval; /* HB_TRUE if accessing of declared (compile time) variables is allowed */ + int iStaticsBase; /* base for this function statics */ + int iFuncSuffix; /* function suffix for multiple static functions with the same name */ + int iEarlyEvalPass; /* !=0 if early evaluaded block is compiled - accessing of declared (compile time) variables is limited */ HB_BOOL fVParams; /* HB_TRUE if variable number of parameters is used */ HB_BOOL bError; /* error during function compilation */ HB_BOOL bBlock; /* HB_TRUE if simple codeblock body is compiled */ diff --git a/harbour/include/hbexprb.c b/harbour/include/hbexprb.c index 3268b5c6c0..69fb9753e6 100644 --- a/harbour/include/hbexprb.c +++ b/harbour/include/hbexprb.c @@ -130,7 +130,7 @@ static HB_EXPR_FUNC( hb_compExprUseNegate ); #if defined( HB_MACRO_SUPPORT ) static void hb_compExprCodeblockPush( HB_EXPR_PTR, HB_COMP_DECL ); #else - static void hb_compExprCodeblockPush( HB_EXPR_PTR, HB_BOOL, HB_COMP_DECL ); + static HB_BOOL hb_compExprCodeblockPush( HB_EXPR_PTR, int, HB_COMP_DECL ); static void hb_compExprCodeblockEarly( HB_EXPR_PTR, HB_COMP_DECL ); static void hb_compExprCodeblockExtPush( HB_EXPR_PTR pSelf, HB_COMP_DECL ); #endif @@ -394,20 +394,23 @@ static HB_EXPR_FUNC( hb_compExprUseString ) break; case HB_EA_PUSH_PCODE: { +#if ! defined( HB_MACRO_SUPPORT ) + if( !HB_SUPPORT_MACROTEXT ) + HB_GEN_FUNC2( PushString, pSelf->value.asString.string, + pSelf->nLength + 1 ); + else + hb_compPushMacroText( HB_COMP_PARAM, + pSelf->value.asString.string, + pSelf->nLength, HB_FALSE ); +#else HB_GEN_FUNC2( PushString, pSelf->value.asString.string, pSelf->nLength + 1 ); -#if ! defined( HB_MACRO_SUPPORT ) - if( HB_SUPPORT_MACROTEXT && - hb_compIsValidMacroText( HB_COMP_PARAM, - pSelf->value.asString.string, - pSelf->nLength ) ) -#else if( hb_macroIsValidMacroText( pSelf->value.asString.string, pSelf->nLength ) ) -#endif { HB_GEN_FUNC1( PCode1, HB_P_MACROTEXT ); } +#endif break; } case HB_EA_POP_PCODE: @@ -456,7 +459,7 @@ static HB_EXPR_FUNC( hb_compExprUseCodeblock ) /* early evaluation of a macro */ hb_compExprCodeblockEarly( pSelf, HB_COMP_PARAM ); else - hb_compExprCodeblockPush( pSelf, HB_TRUE, HB_COMP_PARAM ); + hb_compExprCodeblockPush( pSelf, 0, HB_COMP_PARAM ); #endif break; } @@ -1591,7 +1594,13 @@ static HB_EXPR_FUNC( hb_compExprUseMacro ) /* simple macro variable expansion: &variable * 'szMacro' is a variable name */ +#if ! defined( HB_MACRO_SUPPORT ) + int iEarlyEvalPass = HB_COMP_PARAM->functions.pLast->iEarlyEvalPass; HB_GEN_FUNC1( PushVar, pSelf->value.asMacro.szMacro ); + HB_COMP_PARAM->functions.pLast->iEarlyEvalPass = iEarlyEvalPass; +#else + HB_GEN_FUNC1( PushVar, pSelf->value.asMacro.szMacro ); +#endif } else { @@ -1604,11 +1613,12 @@ static HB_EXPR_FUNC( hb_compExprUseMacro ) * local, static or field. */ #if ! defined( HB_MACRO_SUPPORT ) - hb_compIsValidMacroText( HB_COMP_PARAM, - pSelf->value.asMacro.szMacro, - strlen( pSelf->value.asMacro.szMacro ) ); -#endif + hb_compPushMacroText( HB_COMP_PARAM, + pSelf->value.asMacro.szMacro, + strlen( pSelf->value.asMacro.szMacro ), HB_TRUE ); +#else HB_GEN_FUNC2( PushString, pSelf->value.asMacro.szMacro, strlen( pSelf->value.asMacro.szMacro ) + 1 ); +#endif } } @@ -1676,7 +1686,13 @@ static HB_EXPR_FUNC( hb_compExprUseMacro ) /* simple macro variable expansion: &variable * 'szMacro' is a variable name */ +#if ! defined( HB_MACRO_SUPPORT ) + int iEarlyEvalPass = HB_COMP_PARAM->functions.pLast->iEarlyEvalPass; HB_GEN_FUNC1( PushVar, pSelf->value.asMacro.szMacro ); + HB_COMP_PARAM->functions.pLast->iEarlyEvalPass = iEarlyEvalPass; +#else + HB_GEN_FUNC1( PushVar, pSelf->value.asMacro.szMacro ); +#endif } else { @@ -1689,11 +1705,12 @@ static HB_EXPR_FUNC( hb_compExprUseMacro ) * local, static or field. */ #if ! defined( HB_MACRO_SUPPORT ) - hb_compIsValidMacroText( HB_COMP_PARAM, - pSelf->value.asMacro.szMacro, - strlen( pSelf->value.asMacro.szMacro ) ); -#endif + hb_compPushMacroText( HB_COMP_PARAM, + pSelf->value.asMacro.szMacro, + strlen( pSelf->value.asMacro.szMacro ), HB_TRUE ); +#else HB_GEN_FUNC2( PushString, pSelf->value.asMacro.szMacro, strlen( pSelf->value.asMacro.szMacro ) + 1 ); +#endif } } /* compile & run - macro compiler will generate pcode to pop a value @@ -4472,7 +4489,7 @@ static HB_EXPR_FUNC( hb_compExprUsePreDec ) #if defined( HB_MACRO_SUPPORT ) static void hb_compExprCodeblockPush( HB_EXPR_PTR pSelf, HB_COMP_DECL ) #else -static void hb_compExprCodeblockPush( HB_EXPR_PTR pSelf, HB_BOOL bLateEval, HB_COMP_DECL ) +static HB_BOOL hb_compExprCodeblockPush( HB_EXPR_PTR pSelf, int iEarlyEvalPass, HB_COMP_DECL ) #endif { HB_EXPR_PTR pExpr, pNext; @@ -4486,7 +4503,7 @@ static void hb_compExprCodeblockPush( HB_EXPR_PTR pSelf, HB_BOOL bLateEval, HB_C HB_PCODE_DATA->fVParams = ( pSelf->value.asCodeblock.flags & HB_BLOCK_VPARAMS ) != 0; #else - hb_compCodeBlockStart( HB_COMP_PARAM, bLateEval ); + hb_compCodeBlockStart( HB_COMP_PARAM, iEarlyEvalPass ); HB_COMP_PARAM->functions.pLast->fVParams = ( pSelf->value.asCodeblock.flags & HB_BLOCK_VPARAMS ) != 0; @@ -4548,7 +4565,7 @@ static void hb_compExprCodeblockPush( HB_EXPR_PTR pSelf, HB_BOOL bLateEval, HB_C else HB_EXPR_USE( pExpr, HB_EA_PUSH_PCODE ); #else - if( pNext && bLateEval ) + if( pNext && ( iEarlyEvalPass == 0 || HB_SUPPORT_MACRODECL ) ) HB_EXPR_USE( pExpr, HB_EA_PUSH_POP ); else HB_EXPR_USE( pExpr, HB_EA_PUSH_PCODE ); @@ -4559,10 +4576,16 @@ static void hb_compExprCodeblockPush( HB_EXPR_PTR pSelf, HB_BOOL bLateEval, HB_C #if defined( HB_MACRO_SUPPORT ) hb_macroCodeBlockEnd( HB_COMP_PARAM ); #else - if( bLateEval ) + if( HB_COMP_PARAM->functions.pLast->iEarlyEvalPass == 0 ) + { hb_compCodeBlockEnd( HB_COMP_PARAM ); + return HB_TRUE; + } else + { hb_compCodeBlockRewind( HB_COMP_PARAM ); + return HB_FALSE; + } #endif } @@ -4603,11 +4626,18 @@ static void hb_compExprCodeblockEarly( HB_EXPR_PTR pSelf, HB_COMP_DECL ) /* everything else is macro compiled at runtime * {|| &variable+1} => &( '{|| &variable+1}' ) */ - hb_compExprCodeblockPush( pSelf, HB_FALSE, HB_COMP_PARAM ); - pExpr = hb_compExprNewMacro( hb_compExprNewString( pSelf->value.asCodeblock.string, pSelf->nLength, HB_FALSE, HB_COMP_PARAM ), 0, NULL, HB_COMP_PARAM ); - HB_EXPR_USE( pExpr, HB_EA_PUSH_PCODE ); - HB_COMP_EXPR_FREE( pExpr ); - hb_compCodeBlockStop( HB_COMP_PARAM ); + if( !hb_compExprCodeblockPush( pSelf, 1, HB_COMP_PARAM ) ) + { + HB_BOOL fMacroText = ( HB_COMP_PARAM->supported & HB_COMPFLAG_MACROTEXT ) != 0; + HB_COMP_PARAM->supported |= HB_COMPFLAG_MACROTEXT; + HB_COMP_PARAM->functions.pLast->iEarlyEvalPass = 2; + pExpr = hb_compExprNewMacro( hb_compExprNewString( pSelf->value.asCodeblock.string, pSelf->nLength, HB_FALSE, HB_COMP_PARAM ), 0, NULL, HB_COMP_PARAM ); + HB_EXPR_USE( pExpr, HB_EA_PUSH_PCODE ); + HB_COMP_EXPR_FREE( pExpr ); + hb_compCodeBlockStop( HB_COMP_PARAM ); + if( !fMacroText ) + HB_COMP_PARAM->supported &= ~HB_COMPFLAG_MACROTEXT; + } } } #endif /*HB_MACRO_SUPPORT*/ diff --git a/harbour/src/compiler/cmdcheck.c b/harbour/src/compiler/cmdcheck.c index c3e6a53155..bf27f95b8c 100644 --- a/harbour/src/compiler/cmdcheck.c +++ b/harbour/src/compiler/cmdcheck.c @@ -411,6 +411,17 @@ static void hb_compChkEnvironVar( HB_COMP_DECL, const char *szSwitch ) HB_COMP_PARAM->supported &= ~HB_COMPFLAG_MACROTEXT; break; + case 'd': + case 'D': + if( s[i] == '-' ) + { + i++; + HB_COMP_PARAM->supported &= ~HB_COMPFLAG_MACRODECL; + } + else + HB_COMP_PARAM->supported |= HB_COMPFLAG_MACRODECL; + break; + case 'r': case 'R': if( s[i] == '-' ) diff --git a/harbour/src/compiler/harbour.y b/harbour/src/compiler/harbour.y index 8f3700cb3f..c224f55c5c 100644 --- a/harbour/src/compiler/harbour.y +++ b/harbour/src/compiler/harbour.y @@ -1038,7 +1038,7 @@ CodeBlock : BlockHead HB_CBVAR_PTR pVar; $$ = HB_COMP_PARAM->functions.pLast->nPCodePos; $2 = HB_COMP_PARAM->lastLine; - hb_compCodeBlockStart( HB_COMP_PARAM, HB_TRUE ); + hb_compCodeBlockStart( HB_COMP_PARAM, 0 ); HB_COMP_PARAM->functions.pLast->funFlags |= FUN_EXTBLOCK; HB_COMP_PARAM->functions.pLast->fVParams = ( $1->value.asCodeblock.flags & HB_BLOCK_VPARAMS ) != 0; diff --git a/harbour/src/compiler/harbour.yyc b/harbour/src/compiler/harbour.yyc index 9b68ef86be..438a1ca72f 100644 --- a/harbour/src/compiler/harbour.yyc +++ b/harbour/src/compiler/harbour.yyc @@ -6110,7 +6110,7 @@ yyreduce: HB_CBVAR_PTR pVar; (yyval.sNumber) = HB_COMP_PARAM->functions.pLast->nPCodePos; (yyvsp[(2) - (2)].sNumber) = HB_COMP_PARAM->lastLine; - hb_compCodeBlockStart( HB_COMP_PARAM, HB_TRUE ); + hb_compCodeBlockStart( HB_COMP_PARAM, 0 ); HB_COMP_PARAM->functions.pLast->funFlags |= FUN_EXTBLOCK; HB_COMP_PARAM->functions.pLast->fVParams = ( (yyvsp[(1) - (2)].asExpr)->value.asCodeblock.flags & HB_BLOCK_VPARAMS ) != 0; diff --git a/harbour/src/compiler/hbmain.c b/harbour/src/compiler/hbmain.c index 95d73780df..d339264736 100644 --- a/harbour/src/compiler/hbmain.c +++ b/harbour/src/compiler/hbmain.c @@ -733,7 +733,7 @@ PVAR hb_compVariableFind( HB_COMP_DECL, const char * szVarName, int * piPos, int */ hb_compGenError( HB_COMP_PARAM, hb_comp_szErrors, 'E', HB_COMP_ERR_ILLEGAL_INIT, "(b)", szVarName ); } - else if( fBlock ) + 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 @@ -892,10 +892,12 @@ int hb_compVariableScope( HB_COMP_DECL, const char * szVarName ) return iScope; } -HB_BOOL hb_compIsValidMacroText( HB_COMP_DECL, const char * szText, HB_SIZE nLen ) +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 ) { @@ -919,7 +921,7 @@ HB_BOOL hb_compIsValidMacroText( HB_COMP_DECL, const char * szText, HB_SIZE nLen if( ch >= 'a' && ch <= 'z' ) szSymName[ iSize++ ] = ch - ( 'a' - 'A' ); else if( ch == '_' || ( ch >= 'A' && ch <= 'Z' ) || - ( ch >= '0' && ch <= '9' ) ) + ( iSize > 0 && ch >= '0' && ch <= '9' ) ) szSymName[ iSize++ ] = ch; else break; @@ -928,7 +930,10 @@ HB_BOOL hb_compIsValidMacroText( HB_COMP_DECL, const char * szText, HB_SIZE nLen if( iSize ) { + const char * pszVarName; + szSymName[ iSize ] = '\0'; + pszVarName = hb_compIdentifierNew( HB_COMP_PARAM, szSymName, HB_IDENT_COPY ); /* NOTE: All variables are assumed memvars in macro compiler - * there is no need to check for a valid name but to be Clipper @@ -937,20 +942,59 @@ HB_BOOL hb_compIsValidMacroText( HB_COMP_DECL, const char * szText, HB_SIZE nLen * Only MEMVAR or undeclared (memvar will be assumed) * variables can be used in macro text. */ - fFound = HB_TRUE; - iScope = hb_compVariableScope( HB_COMP_PARAM, szSymName ); - if( iScope != HB_VS_UNDECLARED && !( iScope & HB_VS_LOCAL_MEMVAR ) ) + iScope = hb_compVariableScope( HB_COMP_PARAM, pszVarName ); + if( iScope == HB_VS_UNDECLARED || ( iScope & HB_VS_LOCAL_MEMVAR ) ) { - hb_compErrorMacro( HB_COMP_PARAM, szText ); - break; + fFound = HB_TRUE; + if( fMacro && iScope == HB_VS_UNDECLARED ) + hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_AMBIGUOUS_VAR, pszVarName, 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( pszVarName, 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 ) + { + hb_compGenPushString( szText, nLen + 1, HB_COMP_PARAM ); + if( iParts > 0 ) + hb_compGenPCode1( HB_P_PLUS, HB_COMP_PARAM ); + } - return fFound; + if( fFound ) + hb_compGenPCode1( HB_P_MACROTEXT, HB_COMP_PARAM ); + + HB_COMP_PARAM->functions.pLast->iEarlyEvalPass = iEarlyEvalPass; } @@ -1844,7 +1888,7 @@ static PFUNCTION hb_compFunctionNew( HB_COMP_DECL, const char * szName, HB_SYMBO pFunc->szName = szName; pFunc->cScope = cScope; pFunc->iStaticsBase = HB_COMP_PARAM->iStaticCnt; - pFunc->bLateEval = HB_TRUE; + pFunc->iEarlyEvalPass = 0; pFunc->fVParams = HB_FALSE; pFunc->bError = HB_FALSE; @@ -2498,7 +2542,7 @@ static void hb_compGenVariablePCode( HB_COMP_DECL, HB_BYTE bPCode, const char * * Clipper always assumes a memvar variable if undeclared variable * is popped (a value is asssigned to a variable). */ - if( HB_COMP_ISSUPPORTED( HB_COMPFLAG_HARBOUR ) ) + if( HB_SUPPORT_HARBOUR ) bGenCode = HB_COMP_PARAM->fForceMemvars; /* harbour compatibility */ else bGenCode = ( HB_COMP_PARAM->fForceMemvars || bPCode == HB_P_POPVARIABLE ); @@ -2507,7 +2551,8 @@ static void hb_compGenVariablePCode( HB_COMP_DECL, HB_BYTE bPCode, const char * { /* -v switch was used -> assume it is a memvar variable */ - hb_compGenWarning( HB_COMP_PARAM, hb_comp_szWarnings, 'W', HB_COMP_WARN_MEMVAR_ASSUMED, szVarName, NULL ); + 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; @@ -2516,7 +2561,7 @@ static void hb_compGenVariablePCode( HB_COMP_DECL, HB_BYTE bPCode, const char * else bPCode = HB_P_PUSHMEMVARREF; } - else + 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 ); @@ -2582,18 +2627,24 @@ void hb_compGenMessageData( const char * szMsg, HB_BOOL bIsObject, HB_COMP_DECL 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 ) +static void hb_compCheckEarlyMacroEval( HB_COMP_DECL, const char *szVarName, int iScope ) { - int iScope = hb_compVariableScope( HB_COMP_PARAM, szVarName ); - if( iScope == HB_VS_CBLOCAL_VAR || - /* iScope == HB_VS_LOCAL_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 ) { - hb_compErrorCodeblock( HB_COMP_PARAM, szVarName ); + /* 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 ); } } @@ -2612,16 +2663,12 @@ void hb_compGenPopVar( const char * szVarName, HB_COMP_DECL ) /* generates the p int iVar, iScope; PVAR pVar; - if( ! HB_COMP_PARAM->functions.pLast->bLateEval ) - { - /* pseudo-generation of pcode for a codeblock with macro symbol */ - hb_compCheckEarlyMacroEval( HB_COMP_PARAM, szVarName ); - return; - } - 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: @@ -2668,12 +2715,12 @@ void hb_compGenPopVar( const char * szVarName, HB_COMP_DECL ) /* generates the p break; default: - /* undeclared variable */ - hb_compGenVariablePCode( HB_COMP_PARAM, HB_P_POPVARIABLE, szVarName ); + pVar = NULL; break; } } - else + + if( !pVar ) { /* undeclared variable */ hb_compGenVariablePCode( HB_COMP_PARAM, HB_P_POPVARIABLE, szVarName ); } @@ -2696,16 +2743,12 @@ void hb_compGenPushVar( const char * szVarName, HB_COMP_DECL ) int iVar, iScope; PVAR pVar; - if( ! HB_COMP_PARAM->functions.pLast->bLateEval ) - { - /* pseudo-generation of pcode for a codeblock with macro symbol */ - hb_compCheckEarlyMacroEval( HB_COMP_PARAM, szVarName ); - return; - } - 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: @@ -2742,12 +2785,12 @@ void hb_compGenPushVar( const char * szVarName, HB_COMP_DECL ) break; default: - /* undeclared variable */ - hb_compGenVariablePCode( HB_COMP_PARAM, HB_P_PUSHVARIABLE, szVarName ); + pVar = NULL; break; } } - else + + if( !pVar ) { /* undeclared variable */ hb_compGenVariablePCode( HB_COMP_PARAM, HB_P_PUSHVARIABLE, szVarName ); } @@ -2758,16 +2801,12 @@ void hb_compGenPushVarRef( const char * szVarName, HB_COMP_DECL ) /* generates t int iVar, iScope; PVAR pVar; - if( ! HB_COMP_PARAM->functions.pLast->bLateEval ) - { - /* pseudo-generation of pcode for a codeblock with macro symbol */ - hb_compCheckEarlyMacroEval( HB_COMP_PARAM, szVarName ); - return; - } - 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: @@ -2796,13 +2835,11 @@ void hb_compGenPushVarRef( const char * szVarName, HB_COMP_DECL ) /* generates t break; default: - /* undeclared variable */ - /* field cannot be passed by the reference - assume the memvar */ - hb_compGenVariablePCode( HB_COMP_PARAM, HB_P_PUSHMEMVARREF, szVarName ); - break; + pVar = NULL; } } - else + + if( !pVar ) { /* undeclared variable */ /* field cannot be passed by the reference - assume the memvar */ hb_compGenVariablePCode( HB_COMP_PARAM, HB_P_PUSHMEMVARREF, szVarName ); @@ -3470,13 +3507,13 @@ static void hb_compLineNumberDefEnd( HB_COMP_DECL ) /* * Start a new fake-function that will hold pcodes for a codeblock */ -void hb_compCodeBlockStart( HB_COMP_DECL, HB_BOOL bLateEval ) +void hb_compCodeBlockStart( HB_COMP_DECL, int iEarlyEvalPass ) { PFUNCTION pBlock; - pBlock = hb_compFunctionNew( HB_COMP_PARAM, NULL, HB_FS_STATIC | HB_FS_LOCAL ); - pBlock->pOwner = HB_COMP_PARAM->functions.pLast; - pBlock->bLateEval = bLateEval; + 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; } @@ -3707,6 +3744,18 @@ void hb_compCodeBlockRewind( HB_COMP_DECL ) pCodeblock->pJumps = NULL; pCodeblock->nJumps = 0; } + while( pCodeblock->pDetached ) + { + PVAR pVar = pCodeblock->pDetached; + pCodeblock->pDetached = pVar->pNext; + hb_xfree( pVar ); + } + while( pCodeblock->pLocals ) + { + PVAR pVar = pCodeblock->pLocals; + pCodeblock->pLocals = pVar->pNext; + hb_xfree( pVar ); + } } /* ************************************************************************* */ diff --git a/harbour/src/compiler/hbusage.c b/harbour/src/compiler/hbusage.c index ea92ee88e1..15602c731b 100644 --- a/harbour/src/compiler/hbusage.c +++ b/harbour/src/compiler/hbusage.c @@ -140,8 +140,9 @@ void hb_compPrintModes( HB_COMP_DECL ) "\n s[-] allow indexed assignment on all types", "\n x[-] extended Xbase++ mode", "\n u[-] strings in user encoding", - "\n j[+] turn off jump optimization in pcode", + "\n d[-] accept macros with declared symbols", "\n m[+] turn off macrotext substitution", + "\n j[+] turn off jump optimization in pcode", "\n ? this info", "\n" }; @@ -154,8 +155,10 @@ void hb_compPrintModes( HB_COMP_DECL ) HB_COMPFLAG_RT_MACRO, HB_COMPFLAG_ARRSTR, HB_COMPFLAG_XBASE, - ~HB_COMPFLAG_OPTJUMP, + HB_COMPFLAG_USERCP, + HB_COMPFLAG_MACRODECL, ~HB_COMPFLAG_MACROTEXT, + ~HB_COMPFLAG_OPTJUMP, }; int iLine; diff --git a/harbour/src/compiler/ppcomp.c b/harbour/src/compiler/ppcomp.c index 09a0978d8f..848c94fa7a 100644 --- a/harbour/src/compiler/ppcomp.c +++ b/harbour/src/compiler/ppcomp.c @@ -291,6 +291,10 @@ static HB_BOOL hb_pp_CompilerSwitch( void * cargo, const char * szSwitch, iFlag = HB_COMPFLAG_MACROTEXT; iValue = !iValue; break; + case 'd': + case 'D': + iFlag = HB_COMPFLAG_MACRODECL; + break; case 's': case 'S': iFlag = HB_COMPFLAG_ARRSTR;