diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 3719570f55..d15148ee94 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,30 @@ 2002-12-01 23:12 UTC+0100 Foo Bar */ +2003-10-25 14:45 UTC+0100 Ryszard Glab + * include/hbexprb.c + * source/compiler/exproptb.c + * fixed to stop 'function defined but not used' warning with SIMPLEX + + * source/compiler/harbour.l + * enhanced to support nested '[]' strings created with dumb stingify + match marker (full Clipper compatibility with Flex) + + * source/pp/ppcomp.c + * source/pp/ppcore.c + * fixed support for stingify match markers - full Clipper + compatibility + + * tests/Makefile + * testpp.prg was added into BAD_PRG_SOURCES + + * tests/codebl.prg + * test for references of codeblock parameters was added + + + tests/testpp.prg + * new file to test stringify match markers (this file will + not run - compile it only) + 2003-10-24 11:50 UTC+0300 Alexander Kresin * source/rdd/dbfntx/dbfntx1.c ! Minor fix for calculating the maximum keys number in index page. diff --git a/harbour/include/hbexprb.c b/harbour/include/hbexprb.c index a510ce7a50..051bb2a5f4 100644 --- a/harbour/include/hbexprb.c +++ b/harbour/include/hbexprb.c @@ -510,7 +510,8 @@ static void hb_compExprCodeblockPush( HB_EXPR_PTR pSelf ) /* This generates a push pcode for early evaluation of a macro */ -#if !defined(HB_MACRO_SUPPORT) +#if !defined(SIMPLEX) +#if !defined(HB_MACRO_SUPPORT) static void hb_compExprCodeblockEarly( HB_EXPR_PTR pSelf ) { HB_EXPR_PTR pExpr; @@ -559,6 +560,7 @@ static void hb_compExprCodeblockEarly( HB_EXPR_PTR pSelf ) HB_EXPR_PCODE0( hb_compCodeBlockStop ); } #endif /*HB_MACRO_SUPPORT*/ +#endif /*SIMPLEX*/ /* actions for HB_ET_LOGICAL expression */ diff --git a/harbour/source/compiler/exproptb.c b/harbour/source/compiler/exproptb.c index 0ba2d44ece..a86698e1d2 100644 --- a/harbour/source/compiler/exproptb.c +++ b/harbour/source/compiler/exproptb.c @@ -5,6 +5,6 @@ /* hbexprb.c is also included from ../macro/macro.c * However it produces a slighty different code if used in * macro compiler (there is an additional parameter passed to some functions) - * 11 - ignore this magic number - this is used to force compilation + * 1.6 - ignore this magic number - this is used to force compilation */ #include "hbexprb.c" diff --git a/harbour/source/compiler/harbour.l b/harbour/source/compiler/harbour.l index a5eed108e5..6c032e70b2 100644 --- a/harbour/source/compiler/harbour.l +++ b/harbour/source/compiler/harbour.l @@ -45,6 +45,7 @@ /* helper functions */ static int yy_ConvertNumber( char * szBuffer ); extern int hb_ppInsideTextBlock; +extern BOOL hb_ppNestedLiteralString; /* YACC functions */ void yyerror( char * ); @@ -118,7 +119,7 @@ FalseValue "."[f|n]"." Separator {SpaceTab} -%x STRING1 STRING2 STRING3 STRING4START STRING4 +%x STRING1 STRING2 STRING3 STRING4START STRING4 STRING5 %x NEXT_ BREAK_ CASE_ DO_ WHILE_ WITH_ END_ FIELD_ %x FOR_ FUNCTION_ IIF_ IF_ IN_ INIT_ %x RETURN_ RECOVER_ @@ -144,7 +145,12 @@ Separator {SpaceTab} (hb_comp_iState == WITH) || (hb_comp_iState == WHILE) ) - BEGIN STRING3; + { + if( hb_ppNestedLiteralString ) + BEGIN STRING5; + else + BEGIN STRING3; + } else { hb_comp_iState = LINDEX; @@ -292,6 +298,28 @@ Separator {SpaceTab} return LITERAL; } +.*\n { + /* Preprocessed strings can contain embeded ] chars - look for the last + closing ']' + */ + int i; + + BEGIN 0; + for( i = yyleng-1; i; --i ) + { + if( yytext[ i ] == ']' ) + { + /* ] terminator was found */ + yyless( i+1 ); + yytext[ i ] = '\0'; + yylval.string = hb_compIdentifierNew( yytext, TRUE ); + hb_comp_iState = LITERAL; + + return LITERAL; + } + } +} + \( { BEGIN STRING4; return( '(' ); } . { BEGIN 0; unput( yytext[ yyleng-1 ] ); } diff --git a/harbour/source/pp/ppcomp.c b/harbour/source/pp/ppcomp.c index 9e6f6b1669..1314e01f6a 100644 --- a/harbour/source/pp/ppcomp.c +++ b/harbour/source/pp/ppcomp.c @@ -69,6 +69,7 @@ static int strncmp_nocase( char* s1, char* s2, int n ); extern BOOL hb_ppInsideTextBlock; +extern BOOL hb_ppNestedLiteralString; BOOL hb_pp_bInline = FALSE; @@ -92,6 +93,7 @@ int hb_pp_Internal( FILE * handl_o, char * sOut ) HB_TRACE(HB_TR_DEBUG, ("hb_pp_Internal(%p, %s)", handl_o, sOut)); + hb_ppNestedLiteralString = FALSE; while( TRUE ) { pFile = hb_comp_files.pLast; diff --git a/harbour/source/pp/ppcore.c b/harbour/source/pp/ppcore.c index d6d0a13bdd..7276097e30 100644 --- a/harbour/source/pp/ppcore.c +++ b/harbour/source/pp/ppcore.c @@ -185,6 +185,7 @@ static char s_prevchar; int * hb_pp_aCondCompile = NULL; int hb_pp_nCondCompile = 0; BOOL hb_ppInsideTextBlock = FALSE; +BOOL hb_ppNestedLiteralString = FALSE; char * hb_pp_STD_CH = NULL; @@ -2722,6 +2723,72 @@ static void SearnRep( char * exppatt, char * expreal, int lenreal, char * ptro, if( !bFound && s_Repeate ) s_aIsRepeate[ s_Repeate - 1 ]++; } +static BOOL ScanMacro( char * expreal, int lenitem, int * pNewLen ) +{ + BOOL bSmartMacro; + int i, lennew; + + HB_TRACE(HB_TR_DEBUG, ("ScanMacro(%s, %d, %p)", expreal, lenreal, pNewLen)); + + lennew = lenitem - 1; + bSmartMacro = TRUE; + i = 1; + do { + if( expreal[ i ] == '.' ) + { + /* '&var' => 'var' + '&var.' => 'var' + '&var.x' => '"&var.x"' + '&var. x' => '&var. x' ->invalid syntax + '&var. [1] => '"&var. [1]"' -> OK syntax + */ + int iDotPos = i; + + i++; + if( expreal[i] == '\0' || expreal[i] == ',' ) + { + lennew = iDotPos - 1; + break; + } + else if( expreal[i] == ' ' || expreal[i] == '\t' ) + { + while( (i < lenitem) && (expreal[i] == ' ' || expreal[i] == '\t') ) + i++; + if( expreal[i] == '\0' || expreal[i] == ',' ) + lennew = iDotPos - 1; + else if( expreal[i] == '[' ) + bSmartMacro = FALSE; + } + else + bSmartMacro = FALSE; + break; + } + else if( expreal[ i ] == '[' ) + { + /* &var[x] => "&var[x]" + &var.[x] => "&var.[x]" + */ + bSmartMacro = FALSE; + lennew = lenitem-1; + break; + } + else if( expreal[ i ] == '&' ) + { + /* &var&var => "&var&var" */ + bSmartMacro = FALSE; + lennew = lenitem-1; + break; + } + } while( i++ < lenitem ); + + if( bSmartMacro ) + *pNewLen = lennew; + else + *pNewLen = lenitem; + + return bSmartMacro; +} + static int ReplacePattern( char patttype, char * expreal, int lenreal, char * ptro, int lenres ) { int rmlen = lenreal, ifou, lenitem, i; @@ -2733,13 +2800,17 @@ static int ReplacePattern( char patttype, char * expreal, int lenreal, char * pt case '0': /* Regular result marker */ hb_pp_Stuff( expreal, ptro, lenreal, 4, lenres ); break; + case '1': /* Dumb stringify result marker */ pp_rQuotes( expreal, sQuotes ); hb_pp_Stuff( sQuotes, ptro, 2, 4, lenres ); if( lenreal ) hb_pp_Stuff( expreal, ptro+1, lenreal, 0, lenres ); rmlen = lenreal + 2; + if( *sQuotes == '[' ) + hb_ppNestedLiteralString = TRUE; break; + case '2': /* Normal stringify result marker */ if( !lenreal ) hb_pp_Stuff( "", ptro, 0, 4, lenres ); @@ -2749,73 +2820,64 @@ static int ReplacePattern( char patttype, char * expreal, int lenreal, char * pt lenres -= 4; rmlen = 0; do - { + { ifou = md_strAt( ",", 1, expreal, FALSE, TRUE, FALSE ); lenitem = (ifou)? ifou-1:lenreal; if( *expreal != '\0' ) - { -#if defined(SIMPLEX) - /* Ron Pinkas added 2000-01-21 */ + { + BOOL bSmartMacro = FALSE; + int lennew; + + lennew = lenitem; if( *expreal == '&' ) - { - i = 0; - if( ! ifou ) - { - lenitem--; - if( expreal[lenitem - 1] == '.' ) - { - lenitem--; - } - } - hb_pp_Stuff( expreal + 1, ptro, lenitem, 0, lenres ); - } - else /* END Ron Pinkas 2000-01-21 */ -#endif + bSmartMacro = ScanMacro( expreal, lenitem, &lennew ); + if( bSmartMacro ) + { + if( ifou ) + { + hb_pp_Stuff( ",", ptro, 1, 0, lenres ); + i = 1; + } + hb_pp_Stuff( expreal + 1, ptro, lennew, 0, lenres ); + } + else { i = (ifou)? 3:2; pp_rQuotes( expreal, sQuotes ); hb_pp_Stuff( sQuotes, ptro, i, 0, lenres ); hb_pp_Stuff( expreal, ptro+1, lenitem, 0, lenres+i ); } - ptro += i + lenitem; - rmlen += i + lenitem; - } + ptro += i + lennew; + rmlen += i + lennew; + } expreal += ifou; lenreal -= ifou; - } + } while( ifou > 0 ); } else { -#if defined(SIMPLEX) - /* rglab 2003-10-19 - * SIMPLEX specific solution guarded with #ifdef - * because this creates incorrect syntax: - * @ 0,0 GET &var.1 => _GET_( &var.1, var.1, ) - * in FLEX we need a correct Clipper syntax: - * @ 0,0 GET &var.1 => _GET_( &var.1, "&var.1", ) - */ - /* Ron Pinkas added 2000-01-21 */ - if( *expreal == '&' ) - { - rmlen--; - if( expreal[lenreal - 1] == '.' ) - { - rmlen--; - lenreal--; - } - hb_pp_Stuff( expreal + 1, ptro, lenreal - 1, 4, lenres ); - } - else /* END Ron Pinkas 2000-01-21 */ -#endif - { - pp_rQuotes( expreal, sQuotes ); - hb_pp_Stuff( sQuotes, ptro, 2, 4, lenres ); - hb_pp_Stuff( expreal, ptro+1, lenreal, 0, lenres ); - rmlen = lenreal + 2; - } + BOOL bSmartMacro = FALSE; + int lennew; + + lennew = lenreal; + if( *expreal == '&' ) + bSmartMacro = ScanMacro( expreal, lenreal, &lennew ); + if( bSmartMacro ) + { + hb_pp_Stuff( expreal + 1, ptro, lennew, 4, lenres ); + rmlen = lennew; + } + else + { + pp_rQuotes( expreal, sQuotes ); + hb_pp_Stuff( sQuotes, ptro, 2, 4, lenres ); + hb_pp_Stuff( expreal, ptro+1, lenreal, 0, lenres ); + rmlen = lenreal + 2; + } } break; + case '3': /* Smart stringify result marker */ if( patttype == '1' ) /* list match marker */ { @@ -2823,86 +2885,105 @@ static int ReplacePattern( char patttype, char * expreal, int lenreal, char * pt lenres -= 4; rmlen = 0; do + { + ifou = md_strAt( ",", 1, expreal, FALSE, TRUE, FALSE ); + lenitem = (ifou)? ifou-1:lenreal; + if( *expreal != '\0' ) { - ifou = md_strAt( ",", 1, expreal, FALSE, TRUE, FALSE ); - lenitem = (ifou)? ifou-1:lenreal; - if( *expreal != '\0' ) - { -#if defined(SIMPLEX) - if( !lenitem || *expreal == '(' || (*expreal=='&' && lenreal>1) || - ( *expreal=='\"' && *(expreal+lenitem-1)=='\"' ) || - ( *expreal == '\'' && *(expreal+lenitem-1)=='\'' ) ) - { - if( ifou ) lenitem++; - if( *expreal == '&' ) - { - lenitem--; - if( expreal[lenitem - 1] == '.' ) - { - lenitem--; - } - } - hb_pp_Stuff( ( *expreal=='&' ) ? expreal + 1 : expreal, ptro, - lenitem, 0, lenres ); -#else - if( !lenitem || *expreal == '(' || - ( *expreal=='\"' && *(expreal+lenitem-1)=='\"' ) || - ( *expreal == '\'' && *(expreal+lenitem-1)=='\'' ) ) - { - if( ifou ) lenitem++; - hb_pp_Stuff( expreal, ptro, lenitem, 0, lenres ); -#endif - } - else - { - i = (ifou)? 3:2; - pp_rQuotes( expreal, sQuotes ); - hb_pp_Stuff( sQuotes, ptro, i, 0, lenres ); - hb_pp_Stuff( expreal, ptro+1, lenitem, 0, lenres+i ); - ptro += i; - rmlen += i; - } - ptro += lenitem; - rmlen += lenitem; - } - expreal += ifou; - lenreal -= ifou; + if( !lenitem || *expreal == '(' || (*expreal=='&' && lenreal>1) || + ( *expreal=='\"' && *(expreal+lenitem-1)=='\"' ) || + ( *expreal=='[' && *(expreal+lenitem-1)==']' ) || + ( *expreal == '\'' && *(expreal+lenitem-1)=='\'' ) ) + { + + if( *expreal == '&' ) + { + BOOL bSmartMacro; + int lennew; + + i = 0; + lennew = lenitem; + bSmartMacro = ScanMacro( expreal, lenitem, &lennew ); + if( bSmartMacro ) + { + if( ifou ) + { + hb_pp_Stuff( ",", ptro, 1, 0, lenres ); + i = 1; + } + hb_pp_Stuff( expreal+1, ptro, lennew, 0, lenres ); + lenitem = lennew; + } + else + { + i = (ifou)? 3:2; + pp_rQuotes( expreal, sQuotes ); + hb_pp_Stuff( sQuotes, ptro, i, 0, lenres ); + hb_pp_Stuff( expreal, ptro+1, lenitem, 0, lenres+i ); + } + ptro += i; + rmlen += i; + } + else + { + if( ifou ) lenitem++; + hb_pp_Stuff( expreal, ptro, lenitem, 0, lenres ); + } + } + else + { + i = (ifou)? 3:2; + pp_rQuotes( expreal, sQuotes ); + hb_pp_Stuff( sQuotes, ptro, i, 0, lenres ); + hb_pp_Stuff( expreal, ptro+1, lenitem, 0, lenres+i ); + ptro += i; + rmlen += i; + } + ptro += lenitem; + rmlen += lenitem; } + expreal += ifou; + lenreal -= ifou; + } while( ifou > 0 ); } -#if defined(SIMPLEX) else if( !lenreal || *expreal == '(' || (*expreal=='&' && lenreal>1) || ( *expreal == '\"' && *( expreal + lenreal - 1 ) == '\"' ) || + ( *expreal == '[' && *( expreal + lenreal - 1 ) == ']' ) || ( *expreal == '\'' && *( expreal + lenreal - 1 ) == '\'' ) ) - { - if( *expreal == '&' ) - { - rmlen--; - if( expreal[lenreal - 1] == '.' ) - { - rmlen--; - lenreal--; - } - } - hb_pp_Stuff( ( *expreal == '&' ) ? expreal + 1 : expreal, ptro, - ( *expreal == '&' ) ? lenreal - 1 : lenreal, 4, lenres ); - } -#else - else if( !lenreal || *expreal == '(' || - ( *expreal == '\"' && *( expreal + lenreal - 1 ) == '\"' ) || - ( *expreal == '\'' && *( expreal + lenreal - 1 ) == '\'' ) ) - { - hb_pp_Stuff( expreal, ptro, lenreal, 4, lenres ); - } -#endif + { + if( *expreal == '&' ) + { + BOOL bSmartMacro; + int lennew; + + lennew = lenreal; + bSmartMacro = ScanMacro( expreal, lenreal, &lennew ); + if( bSmartMacro ) + { + hb_pp_Stuff( expreal+1, ptro, lennew, 4, lenres ); + rmlen += lennew; + } + else + { + pp_rQuotes( expreal, sQuotes ); + hb_pp_Stuff( sQuotes, ptro, 2, 4, lenres ); + hb_pp_Stuff( expreal, ptro + 1, lenreal, 0, lenres ); + rmlen = lenreal + 2; + } + } + else + hb_pp_Stuff( expreal, ptro, lenreal, 4, lenres ); + } else - { + { pp_rQuotes( expreal, sQuotes ); hb_pp_Stuff( sQuotes, ptro, 2, 4, lenres ); hb_pp_Stuff( expreal, ptro + 1, lenreal, 0, lenres ); rmlen = lenreal + 2; - } + } break; + case '4': /* Blockify result marker */ if( !lenreal ) hb_pp_Stuff( expreal, ptro, lenreal, 4, lenres ); @@ -3450,6 +3531,12 @@ static int IsInStr( char symb, char * s ) return 0; } +/* ptri = string for inserting + ptro = output string + len1 = length of ptri string + len2 = length of ptro string that will be replaced + lenres = length of ptro string +*/ void hb_pp_Stuff(char *ptri, char * ptro, int len1, int len2, int lenres ) { char *ptr1, *ptr2; @@ -3461,6 +3548,10 @@ void hb_pp_Stuff(char *ptri, char * ptro, int len1, int len2, int lenres ) { ptr1 = ptro + lenres; ptr2 = ptro + lenres + len1 - len2; + /* This is a static buffer - current inserting can erase the null char + than we need set it again. + */ + ptr2[1] = '\0'; for( i=0; i<=lenres; ptr1--,ptr2--,i++ ) *ptr2 = *ptr1; } else diff --git a/harbour/tests/Makefile b/harbour/tests/Makefile index b4838ea8a4..0012fa95e7 100644 --- a/harbour/tests/Makefile +++ b/harbour/tests/Makefile @@ -180,6 +180,7 @@ BAD_PRG_SOURCES=\ test10.prg \ testgt.prg \ testhbf.prg \ + testpp.prg \ testtok.prg \ tstprag.prg \ twirl.prg \ diff --git a/harbour/tests/codebl.prg b/harbour/tests/codebl.prg index eb2a37b324..3cc342db2b 100644 --- a/harbour/tests/codebl.prg +++ b/harbour/tests/codebl.prg @@ -36,6 +36,8 @@ LOCAL cb mqout( 300, EVAL( cbStatic, 200 ) ) mqout( 4, EVAL( cb, 3 ) ) + ReferParam() + Return( NIL ) Static Function TestBlocks() @@ -102,3 +104,65 @@ FUNCTION DetachToStatic( n ) cbStatic ={|x| n+x} RETURN NIL + +// ------------------------------------------------------------ + +Function ReferParam() + +Local bResult + + +? "Test for +codeblock parameter passed by reference" + +Whatever( {|lEnd| ; + + bResult := SomeStuff( @lEnd ), ; // SomeStuff( @lEnd ) isn't allowed +in Harbour! + + SomethingElse( @lEnd ) } ) + + + +? +? "Printed value should be .F.:", Eval( bResult ) // Clipper & xHarbour it's .F.; in Harbour +it is NIL + +? "Printed value should be 'L':", ValType( Eval( bResult ) ) +? +/* Clipper & xHarbour it is "L"; in Harbour + +it's "U" or worst: Unrecoverable error 9020: An item was going to be + +copied to itself from hb_itemCopy() + + +*/ +Return Nil + + + +Static Function Whatever( bBlock ) + +Local lSomeVar := .T. + +Eval( bBlock, lSomeVar ) + +Return .T. + + + +Static Function SomethingElse( lVar ) + +lVar := .F. + +Return Nil + + + +Static Function SomeStuff( lVar ) + +Return {|| lVar } + +// ------------------------------------------------------------ + diff --git a/harbour/tests/testpp.prg b/harbour/tests/testpp.prg new file mode 100644 index 0000000000..41328debbd --- /dev/null +++ b/harbour/tests/testpp.prg @@ -0,0 +1,93 @@ +/* + * $Id$ + */ + +// Tests for stringify match markers +// Preproces and compile only +PROC MAIN +LOCAL b +MEMVAR a +PRIVATE a + +#command _REGULAR_() => ? //REGULAR +#command _NORMAL_() => ? <"z"> //NORMAL +#command _SMART_() => ? <(z)> //SMART +#command _DUMB_() => ? # //DUMB + +#command _REGULAR_L() => s( ) +#command _NORMAL_L() => s( <"z"> ) //NORMAL +#command _SMART_L() => s( <(z)> ) //SMART +#command _DUMB_L() => s( # ) //DUMB + +USE &b ALIAS &a.1 INDEX &a.aa, &b, &c, &b. + +? "< > REGULAR" +_REGULAR_(a) +_REGULAR_("a") +_REGULAR_('a') +_REGULAR_(["'a'"]) +_REGULAR_(&a.1) +_REGULAR_(&a) +_REGULAR_(&a.) +_REGULAR_(&(a)) +_REGULAR_(&a[1]) +_REGULAR_(a[1]) +_REGULAR_("['']") + + +? '< " " > NORMAL' +_NORMAL_(a) +_NORMAL_("a") +_NORMAL_('a') +_NORMAL_(["'a'"]) +_NORMAL_(&a.1) +_NORMAL_(&a) +_NORMAL_(&a.) +_NORMAL_(&(a)) +_NORMAL_(&a[1]) +_NORMAL_(a[1]) +_NORMAL_("['']") + + +? '< ( ) > SMART' +_SMART_(a) +_SMART_("a") +_SMART_('a') +_SMART_(["'a'"]) +_SMART_(&a.1) +_SMART_(&a) +_SMART_(&a.) +_SMART_(&(a)) +_SMART_(&a[1]) +_SMART_(a[1]) +_SMART_("['']") + + +? '# < > DUMB' +_DUMB_(a) +_DUMB_("a") +_DUMB_('a') +_DUMB_(["'a'"]) +_DUMB_(&a.1) +_DUMB_(&a) +_DUMB_(&a.) +_DUMB_(&(a)) +_DUMB_(&a[1]) +_DUMB_(a[1]) +_DUMB_("['']") + + +? "< > REGULAR list" +_REGULAR_L(a,"a",'a',["'a'"],"['a']",'["a"]',&a.1,&a,&a.,&a. ,&(a),&a[1],&a.[1],&a. [2],&a&a, &a.a) +? "< > NORMAL list" +_NORMAL_L(a,"a",'a',["'a'"],"['a']",'["a"]',&a.1,&a,&a.,&a. ,&(a),&a[1],&a.[1],&a. [2],&a&a, &.a, &a.a) +? "< > SMART list" +_SMART_L(a,"a",'a',["'a'"],"['a']",'["a"]',&a.1,&a,&a.,&a. ,&(a),&a[1],&a.[1],&a. [2],&a&a, &.a, &a.a) +? "< > DUMB list" +_DUMB_L(a,"a",'a',["'a'"],"['a']",'["a"]',&a.1,&a,&a.,&a. ,&(a),&a[1],&a.[1],&a. [2],&a&a, &.a, &a.a) + +//a := [[,,]] +//? [[,,]] + +RETURN +