diff --git a/harbour/ChangeLog b/harbour/ChangeLog index d4617e6d5b..f96f9ecb9e 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,3 +1,21 @@ +2000-01-01 22:40 UTC+0800 Ron Pinkas + + * include/hberrors.h + * source/compiler/hbgenerr.c + + Added: "Unterminated inline block in function: \'%s\'" and "Too many inline blocks" + + * include/hbcomp.h + * source/compiler/harbour.c + + Added hb_compInlineNew(), hb_compInlineAdd(), and hb_compInlineFind() + + * source/pp/ppcomp.c + * source/compiler/harbour.slx + * source/compiler/genc.c + + Added support for inline C code blocks. + + + tests/inline_c.prg + + Added new test to demonstrate new inline C support. + 2001-01-01 22:15 GMT -3 Luiz Rafael Culik *utils/hbdoc/genpdf.prg *contrib/pdflib/pdfhbdoc.c diff --git a/harbour/include/hbcomp.h b/harbour/include/hbcomp.h index e76b54ad63..95dd3ff7aa 100644 --- a/harbour/include/hbcomp.h +++ b/harbour/include/hbcomp.h @@ -156,6 +156,15 @@ typedef struct __FUNC struct __FUNC * pNext; /* pointer to the next defined function */ } _FUNC, * PFUNCTION; +/* structure to hold a Clipper defined function */ +typedef struct __INLINE +{ + char * szName; /* name of a inline function */ + BYTE * pCode; /* pointer to a memory block where pcode is stored */ + ULONG lPCodeSize; /* total memory size for pcode */ + struct __INLINE * pNext; /* pointer to the next defined inline */ +} _INLINE, * PINLINE; + /* structure to control all Clipper defined functions */ typedef struct { @@ -164,6 +173,14 @@ typedef struct int iCount; /* number of defined functions */ } FUNCTIONS; +/* structure to control all Clipper defined functions */ +typedef struct +{ + PINLINE pFirst; /* pointer to the first defined inline */ + PINLINE pLast; /* pointer to the last defined inline */ + int iCount; /* number of defined inlines */ +} INLINES; + /* compiler symbol support structure */ typedef struct _COMSYMBOL { @@ -232,9 +249,11 @@ void hb_compPCodeEval( PFUNCTION, HB_PCODE_FUNC_PTR *, void * ); extern void hb_compFunctionAdd( char * szFunName, HB_SYMBOLSCOPE cScope, int iType ); /* starts a new Clipper language function definition */ extern PFUNCTION hb_compFunctionFind( char * szFunName ); /* locates a previously defined function */ +extern PINLINE hb_compInlineFind( char * szFunName ); extern USHORT hb_compFunctionGetPos( char * szSymbolName ); /* returns the index + 1 of a function on the functions defined list */ extern PFUNCTION hb_compFunctionKill( PFUNCTION ); /* releases all memory allocated by function and returns the next one */ extern void hb_compAnnounce( char * ); +extern PINLINE hb_compInlineAdd( char * szFunName ); extern PFUNCTION hb_compFunCallAdd( char * szFuntionName ); extern PFUNCTION hb_compFunCallFind( char * szFunName ); /* locates a previously defined called function */ @@ -443,6 +462,9 @@ extern char * hb_comp_szWarnings[]; extern char * hb_pp_STD_CH; extern BOOL hb_comp_bAutoOpen; extern BOOL hb_comp_bError; +extern char hb_comp_cInlineID; + +extern INLINES hb_comp_inlines; /* /GC command line setting types */ #define HB_COMPGENC_COMPACT 0 diff --git a/harbour/include/hberrors.h b/harbour/include/hberrors.h index 61f016c68b..45a967ceb3 100644 --- a/harbour/include/hberrors.h +++ b/harbour/include/hberrors.h @@ -93,6 +93,8 @@ extern "C" { #define HB_COMP_ERR_CASE 46 #define HB_COMP_ERR_BLOCK 47 #define HB_COMP_ERR_GET_COMPLEX_MACRO 48 +#define HB_COMP_ERR_INVALID_INLINE 49 +#define HB_COMP_ERR_TOOMANY_INLINE 50 #define HB_COMP_WARN_AMBIGUOUS_VAR 1 #define HB_COMP_WARN_MEMVAR_ASSUMED 2 diff --git a/harbour/source/compiler/genc.c b/harbour/source/compiler/genc.c index 021d1d65bf..8e8f4ce3a8 100644 --- a/harbour/source/compiler/genc.c +++ b/harbour/source/compiler/genc.c @@ -52,6 +52,7 @@ void hb_compGenCCode( PHB_FNAME pFileName ) /* generates the C language ou PCOMSYMBOL pSym = hb_comp_symbols.pFirst; PCOMDECLARED pDeclared; FILE * yyc; /* file handle for C output */ + PINLINE pInline = hb_comp_inlines.pFirst; if( ! pFileName->szExtension ) pFileName->szExtension = ".c"; @@ -98,13 +99,27 @@ void hb_compGenCCode( PHB_FNAME pFileName ) /* generates the C language ou fprintf( yyc, "HB_FUNC( %s );\n", pFunc->szName ); pFunc = pFunc->pNext; } + + /* write functions prototypes for inline blocks */ + while( pInline ) + { + fprintf( yyc, "static HB_FUNC( %s );\n", pInline->szName ); + pInline = pInline->pNext; + } + /* write functions prototypes for called functions outside this PRG */ pFunc = hb_comp_funcalls.pFirst; while( pFunc ) { pFTemp = hb_compFunctionFind( pFunc->szName ); if( ! pFTemp || pFTemp == hb_comp_functions.pFirst ) - fprintf( yyc, "extern HB_FUNC( %s );\n", pFunc->szName ); + { + if( pFTemp == NULL && hb_compInlineFind( pFunc->szName ) == NULL ) + { + fprintf( yyc, "extern HB_FUNC( %s );\n", pFunc->szName ); + } + } + pFunc = pFunc->pNext; } @@ -213,6 +228,20 @@ void hb_compGenCCode( PHB_FNAME pFileName ) /* generates the C language ou fprintf( yyc, " hb_vmExecute( pcode, symbols );\n}\n\n" ); pFunc = pFunc->pNext; } + + /* Generate codeblocks data + */ + if( hb_comp_inlines.iCount ) + { + fprintf( yyc, "#include \"hbapi.h\"\n" ); + pInline = hb_comp_inlines.pFirst; + while( pInline ) + { + fprintf( yyc, "static HB_FUNC( %s )\n", pInline->szName ); + fprintf( yyc, "%s", pInline->pCode ); + pInline = pInline->pNext; + } + } } else fprintf( yyc, "/* Empty source file */\n\n" ); @@ -231,6 +260,14 @@ void hb_compGenCCode( PHB_FNAME pFileName ) /* generates the C language ou pFunc = hb_comp_funcalls.pFirst; } + pInline = hb_comp_inlines.pFirst; + while( pInline ) + { + hb_comp_inlines.pFirst = pInline->pNext; + hb_xfree( ( void * ) pInline ); /* NOTE: szName will be released by hb_compSymbolKill() */ + pInline = hb_comp_inlines.pFirst; + } + pDeclared = hb_comp_pFirstDeclared; while( pDeclared ) { diff --git a/harbour/source/compiler/harbour.c b/harbour/source/compiler/harbour.c index 16263368a9..5a1b7f102d 100644 --- a/harbour/source/compiler/harbour.c +++ b/harbour/source/compiler/harbour.c @@ -69,6 +69,7 @@ static void hb_compGenVariablePCode( BYTE , char * ); /* generates the pcode static void hb_compGenVarPCode( BYTE , char * ); /* generates the pcode for undeclared variable */ static PFUNCTION hb_compFunctionNew( char *, HB_SYMBOLSCOPE ); /* creates and initialises the _FUNC structure */ +static PINLINE hb_compInlineNew( char * ); /* creates and initialises the _INLINE structure */ static void hb_compCheckDuplVars( PVAR pVars, char * szVarName ); /*checks for duplicate variables definitions */ /* int hb_compSort_ULONG( ULONG * ulLeft, ULONG * ulRight ); */ @@ -129,6 +130,9 @@ char * hb_comp_szDeclaredFun = NULL; BOOL hb_comp_bAutoOpen = TRUE; BOOL hb_comp_bError = FALSE; +char hb_comp_cInlineID = '0'; + +INLINES hb_comp_inlines; /* EXTERNAL statement can be placed into any place in a function - this flag is * used to suppress error report generation @@ -976,6 +980,20 @@ static PFUNCTION hb_compFunctionNew( char * szName, HB_SYMBOLSCOPE cScope ) return pFunc; } +static PINLINE hb_compInlineNew( char * szName ) +{ + PINLINE pInline; + + pInline = ( PINLINE ) hb_xgrab( sizeof( _INLINE ) ); + + pInline->szName = szName; + pInline->pCode = NULL; + pInline->lPCodeSize = 0; + pInline->pNext = NULL; + + return pInline; +} + /* * Stores a Clipper defined function/procedure * szFunName - name of a function @@ -1059,6 +1077,28 @@ void hb_compFunctionAdd( char * szFunName, HB_SYMBOLSCOPE cScope, int iType ) hb_comp_bDontGenLineNum = FALSE; /* reset the flag */ } +PINLINE hb_compInlineAdd( char * szFunName ) +{ + PINLINE pInline; + + pInline = hb_compInlineNew( szFunName ); + + if( hb_comp_inlines.iCount == 0 ) + { + hb_comp_inlines.pFirst = pInline; + hb_comp_inlines.pLast = pInline; + } + else + { + hb_comp_inlines.pLast->pNext = pInline; + hb_comp_inlines.pLast = pInline; + } + + hb_comp_inlines.iCount++; + + return pInline; +} + /* create an ANNOUNCEd procedure */ void hb_compAnnounce( char * szFunName ) @@ -1245,6 +1285,25 @@ PFUNCTION hb_compFunctionFind( char * szFunctionName ) /* returns a previously d return NULL; } +PINLINE hb_compInlineFind( char * szFunctionName ) +{ + PINLINE pInline = hb_comp_inlines.pFirst; + + while( pInline ) + { + if( ! strcmp( pInline->szName, szFunctionName ) ) + return pInline; + else + { + if( pInline->pNext ) + pInline = pInline->pNext; + else + return NULL; + } + } + return NULL; +} + /* return variable using its order after final fixing */ PVAR hb_compLocalVariableFind( PFUNCTION pFunc, USHORT wVar ) { @@ -3273,6 +3332,10 @@ static void hb_compInitVars( void ) hb_comp_ulLastLinePos = 0; hb_comp_iStaticCnt = 0; hb_comp_iVarScope = VS_LOCAL; + + hb_comp_inlines.iCount = 0; + hb_comp_inlines.pFirst = NULL; + hb_comp_inlines.pLast = NULL; } static void hb_compGenOutput( int iLanguage ) diff --git a/harbour/source/compiler/harbour.slx b/harbour/source/compiler/harbour.slx index 65c01c39b9..2b241261bb 100644 --- a/harbour/source/compiler/harbour.slx +++ b/harbour/source/compiler/harbour.slx @@ -172,6 +172,8 @@ SELF_CONTAINED_WORDS_ARE { /* When reservered words are used as Identifier. */ #define HB_IDENTIFIER LEX_CUSTOM_ACTION - 24 +#define HB_INLINE LEX_CUSTOM_ACTION - 25 + #define USE_KEYWORDS /* Key Words. */ @@ -257,6 +259,7 @@ LANGUAGE_WORDS_ARE { LEX_WORD( "AS{WS}USUAL" ) AS_TOKEN( AS_CHARACTER + DONT_REDUCE ), LEX_WORD( "FIELD" ) AS_TOKEN( FIELD ), + LEX_WORD( "HB_INLINE" ) AS_TOKEN( HB_INLINE ), LEX_WORD( "IF" ) AS_TOKEN( IIF ), LEX_WORD( "IIF" ) AS_TOKEN( IIF ), LEX_WORD( "IN" ) AS_TOKEN( HB_IN ), @@ -762,9 +765,9 @@ int hb_comp_SLX_CustomAction( int x, int aiHold[], int *ptr_iHold, BOOL *ptr_bIg if( x < HB_WANTS_EXP ) { - *ptr_bIgnoreWords = FALSE; + *ptr_bIgnoreWords = FALSE; iWantsEXP = (-x) + (HB_WANTS_EXP) ; - return REJECT_OP; + return REJECT_OP; } else if( x < HB_WANTS_EOL ) { @@ -942,14 +945,14 @@ int hb_comp_SLX_CustomAction( int x, int aiHold[], int *ptr_iHold, BOOL *ptr_bIg return IDENTIFIER + DONT_REDUCE; case HB_NESTED_LIT : - { - int iPairLen = strlen( sPair ); + { + int iPairLen = strlen( sPair ); - sPair[ iPairLen ] = sTerm[0]; - sPair[ iPairLen + 1 ] = '\0'; - yylval.string = hb_compIdentifierNew( sPair, TRUE ); - return LITERAL + DONT_REDUCE ; - } + sPair[ iPairLen ] = sTerm[0]; + sPair[ iPairLen + 1 ] = '\0'; + yylval.string = hb_compIdentifierNew( sPair, TRUE ); + return LITERAL + DONT_REDUCE ; + } case HB_QOUT_ACT : iIdentifier++; @@ -997,6 +1000,96 @@ int hb_comp_SLX_CustomAction( int x, int aiHold[], int *ptr_iHold, BOOL *ptr_bIg DEBUG_INFO( printf( "RELEASED ID_ON_HOLD: %s - Increased to: %i\n", sIdOnHold, iIdentifier ) ); return IDENTIFIER; + case HB_INLINE : + { + char sBuffer[ YY_BUF_SIZE ], *pBuffer, sInlineSym[] = "HB_INLINE_0"; + int iSize, iBraces = 0; + extern BOOL hb_pp_bInline; + PINLINE pInline; + + hb_pp_bInline = TRUE; + + sInlineSym[10] = hb_comp_cInlineID++; + + switch( sInlineSym[10] ) + { + case '9' + 1 : + sInlineSym[10] = 'A'; + break; + + case 'Z' + 1 : + hb_compGenError( hb_comp_szErrors, 'F', HB_COMP_ERR_TOOMANY_INLINE, NULL, NULL ); + break; + } + + pInline = hb_compInlineAdd( hb_compIdentifierNew( sInlineSym, TRUE ) ); + + DigestInline : + + YY_INPUT( (char*) sBuffer, iSize, YY_BUF_SIZE ); + if( iSize == 0 ) + { + hb_compGenError( hb_comp_szErrors, 'F', HB_COMP_ERR_INVALID_INLINE, hb_comp_functions.pLast->szName, NULL ); + hb_pp_bInline = FALSE; + return '\n' + DONT_REDUCE; + } + pBuffer = (char*) sBuffer; + + while( *pBuffer && ( *pBuffer == ' ' || *pBuffer == '\t' ) ) + { + pBuffer++; + } + + if( *pBuffer == '\0' ) + { + goto DigestInline; + } + else if( *pBuffer == '{' ) + { + iBraces++; + } + else if( *pBuffer == '}' && iBraces > 1 ) + { + iBraces--; + } + else if( *pBuffer == '}' ) + { + if( pInline->pCode == NULL ) + { + pInline->pCode = hb_xgrab( ( iSize = strlen( (char*) sBuffer ) ) + 1 ); + strcpy( pInline->pCode, (char*) sBuffer ); + } + else + { + pInline->pCode = hb_xrealloc( pInline->pCode, pInline->lPCodeSize + ( iSize = strlen( (char*) sBuffer ) ) + 1 ); + strcpy( pInline->pCode + pInline->lPCodeSize, (char*) sBuffer ); + } + + pInline->lPCodeSize += iSize; + + hb_pp_bInline = FALSE; + yylval.string = hb_compIdentifierNew( sInlineSym, TRUE ); + iIdentifier++; + DEBUG_INFO( printf( "INLINE, Primary Identifier %s Increased to: %i\n", "INLINE", iIdentifier ) ); + return IDENTIFIER + DONT_REDUCE; + } + + if( pInline->pCode == NULL ) + { + pInline->pCode = hb_xgrab( ( iSize = strlen( (char*) sBuffer ) ) + 1 ); + strcpy( pInline->pCode, (char*) sBuffer ); + } + else + { + pInline->pCode = hb_xrealloc( pInline->pCode, pInline->lPCodeSize + ( iSize = strlen( (char*) sBuffer ) ) + 1 ); + strcpy( pInline->pCode + pInline->lPCodeSize, (char*) sBuffer ); + } + + pInline->lPCodeSize += iSize; + + goto DigestInline; + } + default: printf( "WARNING! No Handler for Custom Action %i\n", x ); } diff --git a/harbour/source/compiler/hbgenerr.c b/harbour/source/compiler/hbgenerr.c index 8fa76ad48e..97672fdb7e 100644 --- a/harbour/source/compiler/hbgenerr.c +++ b/harbour/source/compiler/hbgenerr.c @@ -87,7 +87,9 @@ char * hb_comp_szErrors[] = "Jump PCode not found", "CASE or OTHERWISE does not match DO CASE", "Code block contains both macro and declared symbol references", - "GET contains complex macro" + "GET contains complex macro", + "Unterminated inline block in function: \'%s\'", + "Too many inline blocks" }; /* Table with parse warnings */ diff --git a/harbour/source/pp/ppcomp.c b/harbour/source/pp/ppcomp.c index 22b566a864..bec5fac230 100644 --- a/harbour/source/pp/ppcomp.c +++ b/harbour/source/pp/ppcomp.c @@ -49,6 +49,8 @@ #include "hbpp.h" #include "hbcomp.h" +BOOL hb_pp_bInline = FALSE; + static char s_szLine[ HB_PP_STR_SIZE ]; static char s_szOutLine[ HB_PP_STR_SIZE ]; static int hb_pp_LastOutLine = 1; @@ -86,7 +88,7 @@ int hb_pp_Internal( FILE * handl_o, char * sOut ) hb_compGenError( hb_pp_szErrors, 'F', HB_PP_ERR_BUFFER_OVERFLOW, NULL, NULL ); } - if( s_szLine[ lens - 1 ] == ';' ) + if( s_szLine[ lens - 1 ] == ';' && ! hb_pp_bInline ) { lContinue = 1; lens--; diff --git a/harbour/tests/inline_c.prg b/harbour/tests/inline_c.prg new file mode 100644 index 0000000000..12fa195aeb --- /dev/null +++ b/harbour/tests/inline_c.prg @@ -0,0 +1,28 @@ +Function Main() + + LOCAL cVar := "Hello" + + cVar := HB_INLINE( cVar ) + { + if( ISCHAR(1) ) + { + char *szPar1 = hb_parc(1); + + if( strcmp( szPar1, "Hello") == 0 ) + { + hb_retc( "It was Hello" ); + } + else + { + hb_retc( "No, it was not Hello" ); + } + } + else + { + hb_retc( "No Param passed" ); + } + } + + ? cVar + +RETURN NIL