diff --git a/harbour/ChangeLog b/harbour/ChangeLog index ead566524f..af6e230880 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,3 +1,41 @@ +20000103-19:48 GMT+1 Ryszard Glab + + *include/expropt.h + *include/hbexpr.c + * renamed: hb_compExprNewSymbol() -> hb_compExprNewFunName() + * added new expression type: HB_ET_RTVAR and hb_compExprNewRTVar() + for PUBLIC and PRIVATE variable declarations + + *source/compiler/expropt.c + *source/compiler/harbour.c + *source/compiler/harbour.y + *source/compiler/harbour.l + * added support for macro variables in PUBLIC and PRIVATE declarations + PRIVATE &var, &var.end + * optimization of PUBLIC/PRIVATE variables creation (there was a + single call __MVPUBLIC/__MVPRIVATE function for every variable, + there is a single call for a single statement now), for example: + PRIVATE var1, var2, var3 + // 3 calls previously - only one call now + + *source/macro/macro.y + * renamed: hb_compExprNewSymbol() -> hb_compExprNewFunName() + * fixed handling of &var.text syntax + + *source/macro/macro.c + * fixed handling of &var.text syntax + * handling of text substitution is now Clipper compatible - + previously only substituted value was scanned for nested macro + operator - the whole text is rescanned now, for example: + PRIVATE a:='&', b:='b' + ? &a.b + will print a value of variable 'b' now instead of a generation + of a syntax error. + + *include/extend.h + * added declaration for hb_macroTextSubst() + * added declaration for hb_macroIsIdent() + 20000102-14:27 EST Paul Tucker * source/rtl/environ.c * remove Borland check on define of VER_PLATFORM_WIN32_CE diff --git a/harbour/include/expropt.h b/harbour/include/expropt.h index 0845129374..65359c0976 100644 --- a/harbour/include/expropt.h +++ b/harbour/include/expropt.h @@ -46,6 +46,11 @@ typedef struct HB_EXPR_ char *asSymbol; /* variable name */ BOOL asLogical; /* logical value */ struct + { + struct HB_EXPR_ *pMacro; /* macro variable */ + char *szName; /* variable name */ + } asRTVar; /* PUBLIC or PRIVATE variable declaration */ + struct { long lVal; /* long value */ double dVal; /* double value */ @@ -134,7 +139,8 @@ HB_EXPR_PTR hb_compExprNewVar( char * ); HB_EXPR_PTR hb_compExprNewAliasVar( HB_EXPR_PTR, HB_EXPR_PTR ); HB_EXPR_PTR hb_compExprNewAliasExpr( HB_EXPR_PTR, HB_EXPR_PTR ); HB_EXPR_PTR hb_compExprNewMacro( HB_EXPR_PTR, unsigned char, char * ); -HB_EXPR_PTR hb_compExprNewSymbol( char * ); +HB_EXPR_PTR hb_compExprNewFunName( char * ); +HB_EXPR_PTR hb_compExprNewRTVar( char *, HB_EXPR_PTR ); HB_EXPR_PTR hb_compExprNewAlias( char * ); HB_EXPR_PTR hb_compExprNewEQ( HB_EXPR_PTR ); HB_EXPR_PTR hb_compExprNewNE( HB_EXPR_PTR ); diff --git a/harbour/include/extend.h b/harbour/include/extend.h index 2fdf6b6219..b4d05ac56f 100644 --- a/harbour/include/extend.h +++ b/harbour/include/extend.h @@ -461,6 +461,8 @@ extern void hb_macroPushSymbol( HB_ITEM_PTR ); extern void hb_macroRun( HB_MACRO_PTR ); extern HB_MACRO_PTR hb_macroCompile( char * ); extern void hb_macroDelete( HB_MACRO_PTR ); +extern char * hb_macroTextSubst( char *, ULONG * ); +extern BOOL hb_macroIsIdent( char * ); /* misc */ extern char * hb_version( USHORT uiMode ); diff --git a/harbour/include/hbexpr.c b/harbour/include/hbexpr.c index fd1dda2ce9..78822df49f 100644 --- a/harbour/include/hbexpr.c +++ b/harbour/include/hbexpr.c @@ -123,7 +123,7 @@ typedef enum /* additional definitions used to distinguish macro expressions */ #define HB_ET_MACRO_VAR 0 /* &variable */ -#define HB_ET_MACRO_FUNCALL 1 /* &fimcall() */ +#define HB_ET_MACRO_SYMBOL 1 /* &fimcall() */ #define HB_ET_MACRO_ALIASED 2 /* &alias->&variable */ /* types of expressions @@ -153,8 +153,9 @@ typedef enum HB_ET_ALIASVAR, HB_ET_ALIASEXPR, HB_ET_SEND, - HB_ET_SYMBOL, + HB_ET_FUNNAME, HB_ET_ALIAS, + HB_ET_RTVAR, /* PRIVATE or PUBLIC declaration of variable */ HB_ET_VARIABLE, HB_EO_POSTINC, /* post-operators -> lowest precedence */ HB_EO_POSTDEC, @@ -208,8 +209,9 @@ static HB_EXPR_FUNC( hb_compExprUseFunCall ); static HB_EXPR_FUNC( hb_compExprUseAliasVar ); static HB_EXPR_FUNC( hb_compExprUseAliasExpr ); static HB_EXPR_FUNC( hb_compExprUseSend ); -static HB_EXPR_FUNC( hb_compExprUseSymbol ); +static HB_EXPR_FUNC( hb_compExprUseFunName ); static HB_EXPR_FUNC( hb_compExprUseAlias ); +static HB_EXPR_FUNC( hb_compExprUseRTVariable ); static HB_EXPR_FUNC( hb_compExprUseVariable ); static HB_EXPR_FUNC( hb_compExprUseAssign ); static HB_EXPR_FUNC( hb_compExprUseEqual ); @@ -261,8 +263,9 @@ static HB_EXPR_FUNC_PTR s_ExprTable[] = { hb_compExprUseAliasVar, hb_compExprUseAliasExpr, hb_compExprUseSend, - hb_compExprUseSymbol, + hb_compExprUseFunName, hb_compExprUseAlias, + hb_compExprUseRTVariable, hb_compExprUseVariable, hb_compExprUsePostInc, /* post-operators -> lowest precedence */ hb_compExprUsePostDec, @@ -320,8 +323,9 @@ static BYTE s_PrecedTable[] = { HB_ET_NIL, /* HB_ET_ALIASVAR, */ HB_ET_NIL, /* HB_ET_ALIASEXPR, */ HB_ET_NIL, /* HB_ET_SEND, */ - HB_ET_NIL, /* HB_ET_SYMBOL, */ - HB_ET_NIL, /* HB_ET_ALIAS, */ + HB_ET_NIL, /* HB_ET_FUNNAME, */ + HB_ET_NIL, /* HB_ET_ALIAS, */ + HB_ET_NIL, /* HB_ET_RTVARIABLE, */ HB_ET_NIL, /* HB_ET_VARIABLE, */ HB_ET_NIL, /* HB_EO_POSTINC, post-operators */ HB_ET_NIL, /* HB_EO_POSTDEC, */ @@ -376,6 +380,7 @@ static char * s_OperTable[] = { ":", "", /* symbol */ "", /* alias */ + "", /* RunTime variable */ "", /* variable */ "++", /* post-operators -> lowest precedence */ "--", @@ -718,7 +723,7 @@ HB_EXPR_PTR hb_compExprNewFunCall( HB_EXPR_PTR pName, HB_EXPR_PTR pParms ) { HB_EXPR_PTR pExpr = NULL; - if( pName->ExprType == HB_ET_SYMBOL ) + if( pName->ExprType == HB_ET_FUNNAME ) { /* The name of a function is specified at compile time * e.g. MyFunc() @@ -800,7 +805,7 @@ HB_EXPR_PTR hb_compExprNewFunCall( HB_EXPR_PTR pName, HB_EXPR_PTR pParms ) /* 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_FUNCALL; + pName->value.asMacro.SubType = HB_ET_MACRO_SYMBOL; HB_TRACE(HB_TR_DEBUG, ("hb_compExprNewFunCall(&)")); } @@ -1044,11 +1049,27 @@ HB_EXPR_PTR hb_compExprNewVar( char * szName ) return pExpr; } +/* Create a new declaration of PUBLIC or PRIVATE variable. + * + * szName is a string with variable name if 'PUBLIC varname' context + * pMacroVar is a macro expression if 'PUBLIC &varname' context + */ +HB_EXPR_PTR hb_compExprNewRTVar( char * szName, HB_EXPR_PTR pMacroVar ) +{ + HB_EXPR_PTR pExpr = hb_compExprNew( HB_ET_RTVAR ); + + pExpr->value.asRTVar.szName = szName; + pExpr->value.asRTVar.pMacro = pMacroVar; + if( pMacroVar ) + pMacroVar->value.asMacro.SubType = HB_ET_MACRO_SYMBOL; + return pExpr; +} + /* Create a new symbol used in function calls */ -HB_EXPR_PTR hb_compExprNewSymbol( char * szName ) +HB_EXPR_PTR hb_compExprNewFunName( char * szName ) { - HB_EXPR_PTR pExpr = hb_compExprNew( HB_ET_SYMBOL ); + HB_EXPR_PTR pExpr = hb_compExprNew( HB_ET_FUNNAME ); pExpr->value.asSymbol = szName; return pExpr; } @@ -1331,7 +1352,7 @@ HB_EXPR_PTR hb_compExprAssign( HB_EXPR_PTR pLeftExpr, HB_EXPR_PTR pRightExpr ) /* 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 */ @@ -2346,7 +2367,7 @@ static HB_EXPR_FUNC( hb_compExprUseMacro ) } /* compile & run - leave a result on the eval stack */ - if( pSelf->value.asMacro.SubType == HB_ET_MACRO_FUNCALL ) + if( pSelf->value.asMacro.SubType == HB_ET_MACRO_SYMBOL ) hb_compGenPCode1( HB_P_MACROSYMBOL ); else if( pSelf->value.asMacro.SubType != HB_ET_MACRO_ALIASED ) hb_compGenPCode1( HB_P_MACROPUSH ); @@ -2723,7 +2744,7 @@ static HB_EXPR_FUNC( hb_compExprUseAlias ) return pSelf; } -static HB_EXPR_FUNC( hb_compExprUseSymbol ) +static HB_EXPR_FUNC( hb_compExprUseFunName ) { switch( iMessage ) { @@ -2747,6 +2768,41 @@ static HB_EXPR_FUNC( hb_compExprUseSymbol ) return pSelf; } +static HB_EXPR_FUNC( hb_compExprUseRTVariable ) +{ + switch( iMessage ) + { + case HB_EA_REDUCE: + case HB_EA_ARRAY_AT: + case HB_EA_ARRAY_INDEX: + case HB_EA_LVALUE: + break; + case HB_EA_PUSH_PCODE: + if( pSelf->value.asRTVar.szName ) +#ifndef HB_MACRO_SUPPORT + hb_compGenPushSymbol( pSelf->value.asRTVar.szName, 0 ); /* this is not a function name */ +#else + hb_compGenPushSymbol( pSelf->value.asRTVar.szName ); +#endif + else + HB_EXPR_USE( pSelf->value.asRTVar.pMacro, HB_EA_PUSH_PCODE ); + break; + case HB_EA_POP_PCODE: + if( pSelf->value.asRTVar.szName ) + hb_compGenPopVar( pSelf->value.asRTVar.szName ); + else + HB_EXPR_USE( pSelf->value.asRTVar.pMacro, HB_EA_POP_PCODE ); + break; + + case HB_EA_PUSH_POP: + case HB_EA_STATEMENT: + case HB_EA_DELETE: + break; + } + return pSelf; +} + + static HB_EXPR_FUNC( hb_compExprUseVariable ) { switch( iMessage ) diff --git a/harbour/source/compiler/expropt.c b/harbour/source/compiler/expropt.c index 9bb12828a6..1ca580e917 100644 --- a/harbour/source/compiler/expropt.c +++ b/harbour/source/compiler/expropt.c @@ -3,7 +3,7 @@ */ /* hbexpr.c is also included from ../macro/macro.c - * However it produces a slighty different code if used in macro - * compiler + * However it produces a slighty different code if used in + * macro compiler */ #include "hbexpr.c" diff --git a/harbour/source/compiler/harbour.c b/harbour/source/compiler/harbour.c index 3c9c37787e..5518a3bfab 100644 --- a/harbour/source/compiler/harbour.c +++ b/harbour/source/compiler/harbour.c @@ -479,21 +479,17 @@ void hb_compVariableAdd( char * szVarName, char cValueType ) break; case VS_PRIVATE: { - hb_compGenPushSymbol( hb_strdup( "__MVPRIVATE" ), 1); - hb_compGenPushNil(); - hb_compGenPushSymbol( hb_strdup( szVarName ), 0 ); - hb_compGenPCode3( HB_P_DO, 1, 0 ); - pSym = hb_compSymbolFind( szVarName, NULL ); + pSym = hb_compSymbolFind( szVarName, &wPos ); /* check if symbol exists already */ + if( ! pSym ) + pSym = hb_compSymbolAdd( hb_strdup( szVarName ), &wPos ); pSym->cScope |= VS_MEMVAR; } break; case VS_PUBLIC: { - hb_compGenPushSymbol( hb_strdup( "__MVPUBLIC" ), 1); - hb_compGenPushNil(); - hb_compGenPushSymbol( hb_strdup( szVarName ), 0 ); - hb_compGenPCode3( HB_P_DO, 1, 0 ); - pSym = hb_compSymbolFind( szVarName, NULL ); + pSym = hb_compSymbolFind( szVarName, &wPos ); /* check if symbol exists already */ + if( ! pSym ) + pSym = hb_compSymbolAdd( hb_strdup( szVarName ), &wPos ); pSym->cScope |= VS_MEMVAR; } break; diff --git a/harbour/source/compiler/harbour.l b/harbour/source/compiler/harbour.l index 3d5e697fc1..f01e8bec01 100644 --- a/harbour/source/compiler/harbour.l +++ b/harbour/source/compiler/harbour.l @@ -947,7 +947,7 @@ Separator {SpaceTab} "priv"("ate"|"at"|"a")? { BEGIN PRIVATE_; yylval.string = hb_strupr( hb_strdup( yytext ) ); } -{Separator}+[_a-zA-Z] { /* an Identifier after PRIVATE */ +{Separator}+[_a-zA-Z\&] { /* an Identifier after PRIVATE */ unput( yytext[ yyleng-1 ] ); if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; if( hb_comp_iState == LOOKUP ) @@ -963,7 +963,6 @@ Separator {SpaceTab} } } {Separator}*[^a-zA-Z] { /* any character (not identifier) after PRIVATE */ - /* TODO: add support for macro operator */ unput( yytext[ yyleng-1 ] ); if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; hb_comp_iState =IDENTIFIER; @@ -979,7 +978,7 @@ Separator {SpaceTab} "publ"("ic"|"i")? { BEGIN PUBLIC_; yylval.string = hb_strupr( hb_strdup( yytext ) ); } -{Separator}+[_a-zA-Z] { /* an identifier after PUBLIC */ +{Separator}+[_a-zA-Z\&] { /* an identifier after PUBLIC */ unput( yytext[ yyleng-1 ] ); if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; if( hb_comp_iState == LOOKUP ) @@ -995,7 +994,6 @@ Separator {SpaceTab} } } {Separator}*[^a-zA-Z] { /* any character (not identifier) after PUBLIC */ - /* TODO: add support for macro operator */ unput( yytext[ yyleng-1 ] ); if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; hb_comp_iState =IDENTIFIER; @@ -1097,10 +1095,10 @@ Separator {SpaceTab} {Separator}*. { if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; unput( yytext[ yyleng-1 ] ); - if( hb_comp_iState == WHILE || - hb_comp_iState == DO || - hb_comp_iState == MACROVAR || - hb_comp_iState == MACROTEXT || + if( hb_comp_iState == WHILE || + hb_comp_iState == DO || + hb_comp_iState == MACROVAR || + hb_comp_iState == MACROTEXT || hb_comp_iState == IDENTIFIER ) { /* DO WITH */ hb_comp_iState =WITH; diff --git a/harbour/source/compiler/harbour.y b/harbour/source/compiler/harbour.y index f2fd372dde..51c860788b 100644 --- a/harbour/source/compiler/harbour.y +++ b/harbour/source/compiler/harbour.y @@ -81,6 +81,9 @@ static void hb_compLoopHere( void ); static void * hb_compElseIfGen( void * pFirstElseIf, ULONG ulOffset ); /* generates a support structure for elseifs pcode fixups */ static void hb_compElseIfFix( void * pIfElseIfs ); /* implements the ElseIfs pcode fixups */ +static void hb_compRTVariableAdd( HB_EXPR_PTR, BOOL ); +static void hb_compRTVariableGen( char * ); + /* Misc functions defined in harbour.c */ extern void hb_compGenError( char* _szErrors[], char cPrefix, int iError, char * szError1, char * szError2 ); extern void hb_compGenWarning( char* _szWarnings[], char cPrefix, int iWarning, char * szWarning1, char * szWarning2); @@ -106,13 +109,22 @@ typedef struct _LOOPEXIT struct _LOOPEXIT * pNext; } LOOPEXIT, * PTR_LOOPEXIT; /* support structure for EXIT and LOOP statements */ +typedef struct HB_RTVAR_ +{ + HB_EXPR_PTR pVar; + BOOL bPopValue; + struct HB_RTVAR_ *pNext; + struct HB_RTVAR_ *pPrev; +} HB_RTVAR, *HB_RTVAR_PTR; /* support structure for PUBLIC and PRIVATE statements */ + USHORT hb_comp_wSeqCounter = 0; USHORT hb_comp_wForCounter = 0; USHORT hb_comp_wIfCounter = 0; USHORT hb_comp_wWhileCounter = 0; USHORT hb_comp_wCaseCounter = 0; -PTR_LOOPEXIT hb_comp_pLoops = NULL; +static PTR_LOOPEXIT hb_comp_pLoops = NULL; +static HB_RTVAR_PTR hb_comp_rtvars = NULL; %} @@ -183,7 +195,7 @@ PTR_LOOPEXIT hb_comp_pLoops = NULL; %type NUM_LONG %type FunScope AsType %type Params ParamList -%type IfBegin VarList +%type IfBegin VarList ExtVarList %type FieldList %type WhileBegin %type IfElseIf Cases @@ -326,8 +338,10 @@ Statement : ExecFlow CrlfStmnt { } hb_comp_bDontGenLineNum = TRUE; hb_comp_functions.pLast->bFlags |= FUN_BREAK_CODE; } - | PUBLIC { hb_comp_iVarScope = VS_PUBLIC; } VarList CrlfStmnt - | PRIVATE { hb_comp_iVarScope = VS_PRIVATE; } VarList CrlfStmnt + | PUBLIC { hb_comp_iVarScope = VS_PUBLIC; } ExtVarList + { hb_compRTVariableGen( "__MVPUBLIC" ); } CrlfStmnt + | PRIVATE { hb_comp_iVarScope = VS_PRIVATE; } ExtVarList + { hb_compRTVariableGen( "__MVPRIVATE" ); } CrlfStmnt | EXITLOOP CrlfStmnt { hb_compLoopExit(); hb_comp_functions.pLast->bFlags |= FUN_BREAK_CODE; } | LOOP CrlfStmnt { hb_compLoopLoop(); hb_comp_functions.pLast->bFlags |= FUN_BREAK_CODE; } @@ -529,7 +543,7 @@ VariableAtAlias : VariableAt ALIASOP { $$ = $1; } /* Function call */ -FunCall : IDENTIFIER '(' ArgList ')' { $$ = hb_compExprNewFunCall( hb_compExprNewSymbol( $1 ), $3 ); } +FunCall : IDENTIFIER '(' ArgList ')' { $$ = hb_compExprNewFunCall( hb_compExprNewFunName( $1 ), $3 ); } | MacroVar '(' ArgList ')' { $$ = hb_compExprNewFunCall( $1, $3 ); } ; @@ -977,6 +991,38 @@ VarList : VarDef { $$ = 1; } | VarList ',' VarDef { $$++; } ; +ExtVarList : ExtVarDef { $$ = 1; } + | ExtVarList ',' ExtVarDef { $$++; } + ; + +/* NOTE: if STATIC or LOCAL variables are declared and initialized then we can + * assign a value immediately - however for PRIVATE and PUBLIC variables + * initialization have to be delayed because we have to create these variables + * first. + */ +ExtVarDef : VarDef + | MacroVar AsType + { hb_compRTVariableAdd( hb_compExprNewRTVar( NULL, $1 ), FALSE ); } + | MacroVar AsType INASSIGN Expression + { hb_compExprDelete( hb_compExprGenPush( $4 ) ); + hb_compRTVariableAdd( hb_compExprNewRTVar( NULL, $1 ), TRUE ); + } + | MacroVar DimList + { + USHORT uCount = hb_compExprListLen( $2 ); + hb_compExprDelete( hb_compExprGenPush( $2 ) ); + hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) ); + hb_compRTVariableAdd( hb_compExprNewRTVar( NULL, $1 ), TRUE ); + } + | MacroVar DimList AS_ARRAY + { + USHORT uCount = hb_compExprListLen( $2 ); + hb_compExprDelete( hb_compExprGenPush( $2 ) ); + hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) ); + hb_compRTVariableAdd( hb_compExprNewRTVar( NULL, $1 ), TRUE ); + } + ; + VarDef : IDENTIFIER AsType { if( hb_comp_iVarScope == VS_STATIC ) @@ -985,6 +1031,11 @@ VarDef : IDENTIFIER AsType hb_compVariableAdd( $1, $2 ); hb_compStaticDefEnd(); } + else if( hb_comp_iVarScope == VS_PUBLIC || hb_comp_iVarScope == VS_PRIVATE ) + { + hb_compVariableAdd( $1, $2 ); + hb_compRTVariableAdd( hb_compExprNewRTVar( $1, NULL ), FALSE ); + } else hb_compVariableAdd( $1, $2 ); } @@ -998,6 +1049,12 @@ VarDef : IDENTIFIER AsType hb_compExprDelete( hb_compExprGenStatement( hb_compExprAssignStatic( hb_compExprNewVar( $1 ), $4 ) ) ); hb_compStaticDefEnd(); } + else if( hb_comp_iVarScope == VS_PUBLIC || hb_comp_iVarScope == VS_PRIVATE ) + { + hb_compExprDelete( hb_compExprGenPush( $4 ) ); + hb_compVariableAdd( $1, $2 ); + hb_compRTVariableAdd( hb_compExprNewRTVar( $1, NULL ), TRUE ); + } else { hb_compVariableAdd( $1, $2 ); @@ -1007,19 +1064,41 @@ VarDef : IDENTIFIER AsType | IDENTIFIER DimList { - USHORT uCount = hb_compExprListLen( $2 ); - hb_compVariableAdd( $1, 'A' ); - hb_compExprDelete( hb_compExprGenPush( $2 ) ); - hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) ); - hb_compExprDelete( hb_compExprGenPop( hb_compExprNewVar( $1 ) ) ); + if( hb_comp_iVarScope == VS_PUBLIC || hb_comp_iVarScope == VS_PRIVATE ) + { + USHORT uCount = hb_compExprListLen( $2 ); + hb_compVariableAdd( $1, 'A' ); + hb_compExprDelete( hb_compExprGenPush( $2 ) ); + hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) ); + hb_compRTVariableAdd( hb_compExprNewRTVar( $1, NULL ), TRUE ); + } + else + { + USHORT uCount = hb_compExprListLen( $2 ); + hb_compVariableAdd( $1, 'A' ); + hb_compExprDelete( hb_compExprGenPush( $2 ) ); + hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) ); + hb_compExprDelete( hb_compExprGenPop( hb_compExprNewVar( $1 ) ) ); + } } | IDENTIFIER DimList AS_ARRAY { - USHORT uCount = hb_compExprListLen( $2 ); - hb_compVariableAdd( $1, 'A' ); - hb_compExprDelete( hb_compExprGenPush( $2 ) ); - hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) ); - hb_compExprDelete( hb_compExprGenPop( hb_compExprNewVar( $1 ) ) ); + if( hb_comp_iVarScope == VS_PUBLIC || hb_comp_iVarScope == VS_PRIVATE ) + { + USHORT uCount = hb_compExprListLen( $2 ); + hb_compVariableAdd( $1, 'A' ); + hb_compExprDelete( hb_compExprGenPush( $2 ) ); + hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) ); + hb_compRTVariableAdd( hb_compExprNewRTVar( $1, NULL ), TRUE ); + } + else + { + USHORT uCount = hb_compExprListLen( $2 ); + hb_compVariableAdd( $1, 'A' ); + hb_compExprDelete( hb_compExprGenPush( $2 ) ); + hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) ); + hb_compExprDelete( hb_compExprGenPop( hb_compExprNewVar( $1 ) ) ); + } } ; @@ -1321,7 +1400,7 @@ RecoverUsing : RECOVER USING IDENTIFIER * DO .. WITH ++variable * will pass the value of variable not a reference */ -DoName : IDENTIFIER { $$ = hb_compExprNewSymbol( $1 ); } +DoName : IDENTIFIER { $$ = hb_compExprNewFunName( $1 ); } | MacroVar { $$ = $1; } ; @@ -1330,7 +1409,7 @@ DoProc : DO DoName | DO DoName WITH DoArgList { $$ = hb_compExprNewFunCall( $2, $4 ); } | WHILE WITH DoArgList - { $$ = hb_compExprNewFunCall( hb_compExprNewSymbol( hb_strdup("WHILE") ), $3 ); } + { $$ = hb_compExprNewFunCall( hb_compExprNewFunName( hb_strdup("WHILE") ), $3 ); } ; DoArgList : ',' { $$ = hb_compExprAddListExpr( hb_compExprNewArgList( hb_compExprNewNil() ), hb_compExprNewNil() ); } @@ -1692,3 +1771,60 @@ static void hb_compElseIfFix( void * pFixElseIfs ) } } +static void hb_compRTVariableAdd( HB_EXPR_PTR pVar, BOOL bPopInitValue ) +{ + HB_RTVAR_PTR pRTvar = ( HB_RTVAR_PTR ) hb_xgrab( sizeof( HB_RTVAR ) ); + + pRTvar->pVar = pVar; + pRTvar->bPopValue = bPopInitValue; + pRTvar->pNext = NULL; + pRTvar->pPrev = NULL; + + if( hb_comp_rtvars ) + { + HB_RTVAR_PTR pLast = hb_comp_rtvars; + while( pLast->pNext ) + pLast = pLast->pNext; + pLast->pNext = pRTvar; + pRTvar->pPrev = pLast; + } + else + hb_comp_rtvars = pRTvar; +} + +static void hb_compRTVariableGen( char * szCreateFun ) +{ + USHORT usCount = 0; + HB_RTVAR_PTR pVar = hb_comp_rtvars; + HB_RTVAR_PTR pDel; + + /* generate the function call frame */ + hb_compGenPushSymbol( hb_strdup( szCreateFun ), 1); + hb_compGenPushNil(); + + /* push variable names to create */ + while( pVar->pNext ) + { + hb_compExprGenPush( pVar->pVar ); + pVar = pVar->pNext; + ++usCount; + } + hb_compExprGenPush( pVar->pVar ); + ++usCount; + + /* call function that will create either PUBLIC or PRIVATE variables */ + hb_compGenPCode3( HB_P_DO, HB_LOBYTE( usCount ), HB_HIBYTE( usCount ) ); + + /* pop initial values */ + while( pVar ) + { + if( pVar->bPopValue ) + hb_compExprDelete( hb_compExprGenPop( pVar->pVar ) ); + else + hb_compExprDelete( pVar->pVar ); + pDel = pVar; + pVar = pVar->pPrev; + hb_xfree( pDel ); + } + hb_comp_rtvars = NULL; +} diff --git a/harbour/source/macro/macro.c b/harbour/source/macro/macro.c index 1c297a372c..7152f3368b 100644 --- a/harbour/source/macro/macro.c +++ b/harbour/source/macro/macro.c @@ -137,7 +137,8 @@ static void hb_macroSyntaxError( HB_MACRO_PTR pMacro ) HB_TRACE(HB_TR_DEBUG, ("hb_macroSyntaxError(%p)", pMacro)); - hb_macroDelete( pMacro ); /* TODO: use pMacro->status for more detailed error messagess */ + if( pMacro ) + hb_macroDelete( pMacro ); /* TODO: use pMacro->status for more detailed error messagess */ pResult = hb_errRT_BASE_Subst( EG_SYNTAX, 1449, NULL, "&" ); @@ -148,9 +149,9 @@ static void hb_macroSyntaxError( HB_MACRO_PTR pMacro ) } } -/* Check if passed string is a valid function name +/* Check if passed string is a valid function or variable name */ -static BOOL hb_macroIsIdent( char * szString ) +BOOL hb_macroIsIdent( char * szString ) { char * pTmp = szString; BOOL bIsIdent = FALSE; @@ -191,13 +192,21 @@ static BOOL hb_macroIsIdent( char * szString ) * string if there was no macro operator in it or a pointer to a new * allocated memory with expanded string if there was a macro operator * in passed string. + * NOTE: + * Clipper restarts scanning of the text from the beginning of + * inserted text after macro expansion, for example: + * PRIVATE a:='&', b:='c' + * PRIVATE &a.b // this will create 'c' variable + * + * PRIVATE a:=0, b:='b', ab:='c' + * PRIVATE &a&b //this will cause syntax error '&' + * */ -static char * hb_macroTextSubst( char * szString, ULONG *pulStringLen ) +char * hb_macroTextSubst( char * szString, ULONG *pulStringLen ) { char * szResult; - ULONG ulCopy; - ULONG ulResLen; - ULONG ulResPos; + ULONG ulResStrLen; + ULONG ulResBufLen; ULONG ulCharsLeft; char * pHead; char * pTail; @@ -208,29 +217,28 @@ static char * hb_macroTextSubst( char * szString, ULONG *pulStringLen ) if( pHead == NULL ) return szString; /* no more processing is required */ + /* initial length of the string and the result buffer (it can contain null bytes) */ + ulResBufLen = ulResStrLen = *pulStringLen; /* initial buffer for return value */ - szResult = (char *) hb_xgrab( *pulStringLen + 1 ); - /* copy initial length of the string (it can contain null bytes) */ - ulResLen = ulCharsLeft = *pulStringLen; - /* current position within the buffer where byte will be copied */ - ulResPos = 0; + szResult = (char *) hb_xgrab( ulResBufLen + 1 ); + + /* copy the input string with trailing zero byte + */ + memcpy( szResult, szString, ulResStrLen + 1 ); + /* switch the pointer so it will point into the result buffer + */ + pHead = szResult + ( pHead - szString ); - pTail = szString; do { - ulCopy = pHead - pTail; - if( ulCopy ) - { - /* copy bytes located before '&' character */ - memcpy( szResult + ulResPos, pTail, ulCopy ); - ulResPos += ulCopy; - pTail = pHead; - } - + /* store the position where '&' was found so we can restart scanning + * from this point after macro expansion + */ + pTail = pHead; /* check if the next character can start a valid identifier * (only _a-zA-Z are allowed) */ - ++pHead; + ++pHead; /* skip '&' character */ if( *pHead == '_' || (*pHead >= 'A' && *pHead <= 'Z') || (*pHead >= 'a' && *pHead <= 'z') ) { /* extract a variable name */ @@ -266,74 +274,64 @@ static char * hb_macroTextSubst( char * szString, ULONG *pulStringLen ) szValPtr = hb_memvarGetStrValuePtr( pName, &ulValLen ); if( szValPtr ) { - char * szValSubst; - if( *pHead == '.' ) { /* we have stopped at the macro terminator '.' - skip it */ ++pHead; ++ulNameLen; } + ++ulNameLen; /* count also the '&' character */ - /* Check if returned string contains nested macro operators - * and expand them if they exist - */ - szValSubst = hb_macroTextSubst( szValPtr, &ulValLen ); + /* number of characters left on the right side of a variable name */ + ulCharsLeft = ulResStrLen - ( pHead - szResult ); - /* expand the result buffer if the substituted value is too - * long to be stored in the current buffer + /* NOTE: + * if a replacement string is shorter then the variable + * name then we don't have to reallocate the result buffer: + * 'ulResStrLen' stores the current length of a string in the buffer + * 'ulResBufLen' stores the length of the buffer */ - if( (ulResPos + ulValLen) >= ulResLen ) + if( ulValLen > ulNameLen ) { - ulResLen = ulResPos + ulValLen; - szResult = ( char * ) hb_xrealloc( szResult, ulResLen + 1 ); + ulResStrLen += ( ulValLen - ulNameLen ); + if( ulResStrLen > ulResBufLen ) + { + ulResBufLen = ulResStrLen; + szResult = ( char * ) hb_xrealloc( szResult, ulResBufLen + 1 ); + } } - memcpy( szResult + ulResPos, szValSubst, ulValLen ); - ulResPos += ulValLen; - if( szValSubst != szValPtr ) - { - /* a new pointer was created in hb_macroTextSubst - * (if a macro operator was expanded) - we should release it - */ - hb_xfree( szValSubst ); - } - /* move a pointer to the characters processed so far - - * replaced characters shouldn't be copied + else + ulResStrLen -= ( ulNameLen - ulValLen ); + + /* move bytes located on the right side of a variable name */ + memmove( pTail + ulValLen, pHead, ulCharsLeft + 1 ); + /* copy substituted value */ + memcpy( pTail, szValPtr, ulValLen ); + /* restart scanning from the beginning of replaced string */ + /* NOTE: This causes that the following code: + * a := '&a' + * var := '&a.b' + * is the same as: + * var := '&ab' */ - pTail = pHead; + pHead = pTail; } - } } - /* copy characters that were not a valid identifier */ - ulCopy = pHead - pTail; - if( ulCopy ) - { - memcpy( szResult + ulResPos, pTail, ulCopy ); - ulResPos += ulCopy; - pTail = pHead; - } - ulCharsLeft = *pulStringLen - ( pTail - szString ); + ulCharsLeft = ulResStrLen - ( pHead - szResult ); } - while( ulCharsLeft && ( pHead = (char *) memchr( (void *)pTail, '&', ulCharsLeft ) ) ); + while( ulCharsLeft && ( pHead = (char *) memchr( (void *)pHead, '&', ulCharsLeft ) ) ); - if( ulCharsLeft ) - { - /* copy trailing characters */ - memcpy( szResult + ulResPos, pTail, ulCharsLeft ); - ulResPos += ulCharsLeft; - } - - if( ulResPos < ulResLen ) + if( ulResStrLen < ulResBufLen ) { /* result string is shorter then allocated buffer - * cut it to a required length */ - szResult = ( char * ) hb_xrealloc( szResult, ulResPos + 1 ); + szResult = ( char * ) hb_xrealloc( szResult, ulResStrLen + 1 ); } - szResult[ ulResPos ] = 0; /* place terminating null character */ + szResult[ ulResStrLen ] = 0; /* place terminating null character */ /* return a length of result string */ - *pulStringLen = ulResPos; + *pulStringLen = ulResStrLen; return szResult; /* a new memory buffer was allocated */ } @@ -379,9 +377,9 @@ void hb_macroSetValue( HB_ITEM_PTR pItem ) if( hb_macroCheckParam( pItem ) ) { + char * szString = pItem->item.asString.value; HB_MACRO struMacro; int iStatus; - char * szString = pItem->item.asString.value; struMacro.bShortCuts = hb_comp_bShortCuts; struMacro.bName10 = hb_comp_bUseName10; @@ -434,7 +432,6 @@ void hb_macroPushSymbol( HB_ITEM_PTR pItem ) if( hb_macroCheckParam( pItem ) ) { - HB_MACRO struMacro; char * szString; BOOL bNewBuffer; ULONG ulLength = pItem->item.asString.length; @@ -460,7 +457,7 @@ void hb_macroPushSymbol( HB_ITEM_PTR pItem ) { if( bNewBuffer ) hb_xfree( szString ); /* free space allocated in hb_macroTextSubst */ - hb_macroSyntaxError( &struMacro ); + hb_macroSyntaxError( NULL ); } } } diff --git a/harbour/source/macro/macro.y b/harbour/source/macro/macro.y index b77500f0c3..493829c283 100644 --- a/harbour/source/macro/macro.y +++ b/harbour/source/macro/macro.y @@ -57,7 +57,7 @@ #define malloc hb_xgrab #undef free #define free hb_xfree -/* This is workaround of yyparse() declaration bug in bison.simple +/* This is workaround of yyparse() declaration bug in bison.simple */ #ifdef __GNUC__ #undef __GNUC__ @@ -253,8 +253,21 @@ VarAlias : IDENTIFIER ALIASOP { $$ = hb_compExprNewAlias( $1 ); } MacroVar : MACROVAR { $$ = hb_compExprNewMacro( NULL, '&', $1 ); HB_MACRO_CHECK( $$ ); } - | MACROTEXT { $$ = hb_compExprNewMacro( NULL, 0, $1 ); - HB_MACRO_CHECK( $$ ); + | MACROTEXT { ULONG ulLen = strlen( $1 ); + char * szVarName = hb_macroTextSubst( $1, &ulLen ); + if( hb_macroIsIdent( szVarName ) ) + { + $$ = hb_compExprNewVar( szVarName ); + hb_xfree( $1 ); + HB_MACRO_CHECK( $$ ); + } + else + { + /* invalid variable name + */ + hb_xfree( $1 ); + YYABORT; + } } ; @@ -333,7 +346,7 @@ VariableAt : NilValue ArrayIndex { $$ = $2; } /* Function call */ -FunCall : IDENTIFIER '(' ArgList ')' { $$ = hb_compExprNewFunCall( hb_compExprNewSymbol( $1 ), $3, HB_MACRO_PARAM ); +FunCall : IDENTIFIER '(' ArgList ')' { $$ = hb_compExprNewFunCall( hb_compExprNewFunName( $1 ), $3, HB_MACRO_PARAM ); HB_MACRO_CHECK( $$ ); } | MacroVar '(' ArgList ')' { $$ = hb_compExprNewFunCall( $1, $3, HB_MACRO_PARAM );