Files
harbour-core/harbour/source/compiler/harbour.c
1999-11-16 21:06:31 +00:00

3384 lines
101 KiB
C

/*
* $Id$
*/
/*
* Harbour Project source code:
* Compiler main file
*
* Copyright 1999 {list of individual authors and e-mail addresses}
* 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 of the License, or
* (at your option) any later version, with one exception:
*
* The exception is that if you link the Harbour Runtime Library (HRL)
* and/or the Harbour Virtual Machine (HVM) 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 HRL
* and/or HVM code into it.
*
* 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 program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
* their web site at http://www.gnu.org/).
*
*/
#include "compiler.h"
#if defined(DOS) && defined(__BORLANDC__)
#include <limits.h>
extern unsigned _stklen = UINT_MAX;
#endif
/* /ES command line setting types */
#define HB_EXITLEVEL_DEFAULT 0
#define HB_EXITLEVEL_SETEXIT 1
#define HB_EXITLEVEL_DELTARGET 2
typedef enum
{
LANG_C, /* C language (by default) <file.c> */
LANG_OBJ32, /* DOS/Windows 32 bits <file.obj> */
LANG_JAVA, /* Java <file.java> */
LANG_PASCAL, /* Pascal <file.pas> */
LANG_RESOURCES, /* Resources <file.rc> */
LANG_PORT_OBJ /* Portable objects <file.hrb> */
} LANGUAGES; /* supported Harbour output languages */
extern int harbour_main( char *szName );
extern int Include( char * szFileName, PATHNAMES * pSearchPath ); /* end #include support */
/* Following line added for preprocessor */
extern void Hbpp_init ( void );
/* output related functions */
extern void GenCCode( PHB_FNAME ); /* generates the C language output */
extern void GenJava( PHB_FNAME ); /* generates the Java language output */
extern void GenPascal( PHB_FNAME ); /* generates the Pascal language output */
extern void GenRC( PHB_FNAME ); /* generates the RC language output */
extern void GenPortObj( PHB_FNAME ); /* generates the portable objects */
#ifdef HARBOUR_OBJ_GENERATION
extern void GenObj32( PHB_FNAME ); /* generates OBJ 32 bits */
#endif
/* Following two lines added for preprocessor */
extern BOOL _bPPO; /* flag indicating, is ppo output needed */
extern FILE *yyppo; /* output .ppo file */
static void PrintUsage( char * );
static void PrintCredits( void );
static BOOL SwitchCmp( char * szString, char * szSwitch );
static ULONG PackDateTime( void );
static void AddSearchPath( char *, PATHNAMES * * ); /* add pathname to a search list */
static char * RESERVED_FUNC( char * );
void EXTERNAL_LINKAGE close_on_exit( void );
extern int iLine; /* currently parsed file line number */
/* global variables */
FILES hb_comp_files;
FUNCTIONS hb_comp_functions, hb_comp_funcalls;
SYMBOLS hb_comp_symbols;
PFUNCTION hb_comp_pInitFunc;
PHB_FNAME hb_comp_pFileName = NULL;
BOOL hb_comp_bStartProc = TRUE; /* holds if we need to create the starting procedure */
BOOL hb_comp_bLineNumbers = TRUE; /* holds if we need pcodes with line numbers */
BOOL hb_comp_bQuiet = FALSE; /* quiet mode */
BOOL hb_comp_bRestrictSymbolLength = FALSE; /* generate 10 chars max symbols length */
BOOL hb_comp_bShortCuts = TRUE; /* .and. & .or. expressions shortcuts */
int hb_comp_iWarnings = 0; /* enable parse warnings */
BOOL hb_comp_bAnyWarning = FALSE; /* holds if there was any warning during the compilation process */
BOOL hb_comp_bAutoMemvarAssume = FALSE; /* holds if undeclared variables are automatically assumed MEMVAR (-a)*/
BOOL hb_comp_bForceMemvars = FALSE; /* holds if memvars are assumed when accesing undeclared variable (-v)*/
BOOL hb_comp_bDebugInfo = FALSE; /* holds if generate debugger required info */
char hb_comp_szPrefix[ 20 ] = { '\0' }; /* holds the prefix added to the generated symbol init function name (in C output currently) */
BOOL hb_comp_bGenCVerbose = TRUE; /* C code generation should be verbose (use comments) or not */
int hb_comp_iExitLevel = HB_EXITLEVEL_DEFAULT; /* holds if there was any warning during the compilation process */
PATHNAMES *hb_comp_pIncludePath = NULL;
int hb_comp_iFunctionCnt = 0;
int hb_comp_iErrorCount = 0;
char hb_comp_cVarType = ' '; /* current declared variable type */
BOOL hb_comp_bDontGenLineNum = FALSE; /* suppress line number generation */
LONG hb_comp_lLastPushPos = -1; /* position of last push pcode */
ULONG hb_comp_ulLastLinePos = 0; /* position of last opcode with line number */
ULONG hb_comp_ulMessageFix = 0; /* Position of the message which needs to be changed */
ALIASID_PTR hb_comp_pAliasId = NULL;
int hb_comp_iStaticCnt = 0; /* number of defined statics variables on the PRG */
BOOL hb_comp_bExternal = FALSE;
PTR_LOOPEXIT hb_comp_pLoops = NULL;
PEXTERN hb_comp_pExterns = NULL;
EXPLIST_PTR hb_comp_pExprList = NULL; /* stack used for parenthesized expressions */
int hb_comp_iVarScope = VS_LOCAL; /* holds the scope for next variables to be defined */
/* different values for hb_comp_iVarScope */
/* local variables */
static PHB_FNAME s_pOutPath = NULL;
static BOOL s_bCredits = FALSE; /* print credits */
static BOOL s_bLogo = TRUE; /* print logo */
static BOOL s_bSyntaxCheckOnly = FALSE; /* syntax check only */
static int s_iLanguage = LANG_C; /* default Harbour generated output language */
/* Table with parse errors */
char * hb_comp_szCErrors[] =
{
"Statement not allowed outside of procedure or function",
"Redefinition of procedure or function: \'%s\'",
"Duplicate variable declaration: \'%s\'",
"%s declaration follows executable statement",
"Outer codeblock variable is out of reach: \'%s\'",
"Invalid numeric format '.'",
"Unterminated string: \'%s\'",
"Redefinition of predefined function %s: \'%s\'",
"Illegal variable \'%s\' initializer: \'%s\'",
"ENDIF does not match IF",
"ENDDO does not match WHILE",
"ENDCASE does not match DO CASE",
"NEXT does not match FOR",
"ELSE does not match IF",
"ELSEIF does not match IF",
"Syntax error: \'%s\'",
"Unclosed control structures",
"%s statement with no loop in sight",
"Syntax error: \'%s\' in: \'%s\'",
"Incomplete statement: %s",
"Incorrect number of arguments: %s %s",
"Invalid lvalue: \'%s\'",
"Invalid use of \'@\' (pass by reference): \'%s\'",
"Formal parameters already declared",
"Invalid %s from within of SEQUENCE code",
"Unterminated array index",
"Memory allocation error",
"Memory reallocation error",
"Freeing a NULL memory pointer",
"Syntax error: \"%s at \'%s\'\"",
"Jump offset too long",
"Can't create output file: \'%s\'",
"Can't create preprocessed output file: \'%s\'",
"Bad command line option: \'%s\'",
"Bad command line parameter: \'%s\'",
"Invalid filename: \'%s\'",
"Mayhem in CASE handler",
"Operation not supported for this data type: \'%s\'",
"Invalid alias expression: \'%s\'",
"Invalid array index expression: \'%s\'",
"Bound error: \'%s\'"
};
/* Table with parse warnings */
/* NOTE: The first character stores the warning's level that triggers this
* warning. The warning's level is set by -w<n> command line option.
*/
char * hb_comp_szCWarnings[] =
{
"1Ambiguous reference: \'%s\'",
"1Ambiguous reference, assuming memvar: \'%s\'",
"2Variable: \'%s\' declared but not used in function: \'%s\'",
"2CodeBlock Parameter: \'%s\' declared but not used in function: \'%s\'",
"1RETURN statement with no return value in function",
"1Procedure returns value",
"1Function \'%s\' does not end with RETURN statement",
"3Incompatible type in assignment to: \'%s\' expected: \'%s\'",
"3Incompatible operand type: \'%s\' expected: \'Logical\'",
"3Incompatible operand type: \'%s\' expected: \'Numeric\'",
"3Incompatible operand types: \'%s\' and: \'%s\'",
"3Suspicious type in assignment to: \'%s\' expected: \'%s\'",
"3Suspicious operand type: \'UnKnown\' expected: \'%s\'",
"3Suspicious operand type: \'UnKnown\' expected: \'Logical\'",
"3Suspicious operand type: \'UnKnown\' expected: \'Numeric\'",
"0Meaningless use of expression: \'%s\'"
};
/* Table with reserved functions names
* NOTE: THIS TABLE MUST BE SORTED ALPHABETICALLY
*/
static const char * _szReservedFun[] = {
"AADD" ,
"ABS" ,
"ASC" ,
"AT" ,
"BOF" ,
"BREAK" ,
"CDOW" ,
"CHR" ,
"CMONTH" ,
"COL" ,
"CTOD" ,
"DATE" ,
"DAY" ,
"DELETED" ,
"DEVPOS" ,
"DOW" ,
"DTOC" ,
"DTOS" ,
"EMPTY" ,
"EOF" ,
"EXP" ,
"FCOUNT" ,
"FIELDNAME" ,
"FLOCK" ,
"FOUND" ,
"INKEY" ,
"INT" ,
"LASTREC" ,
"LEFT" ,
"LEN" ,
"LOCK" ,
"LOG" ,
"LOWER" ,
"LTRIM" ,
"MAX" ,
"MIN" ,
"MONTH" ,
"PCOL" ,
"PCOUNT" ,
"PROW" ,
"QSELF" ,
"RECCOUNT" ,
"RECNO" ,
"REPLICATE" ,
"RLOCK" ,
"ROUND" ,
"ROW" ,
"RTRIM" ,
"SECONDS" ,
"SELECT" ,
"SETPOS" ,
"SETPOSBS" ,
"SPACE" ,
"SQRT" ,
"STR" ,
"SUBSTR" ,
"TIME" ,
"TRANSFORM" ,
"TRIM" ,
"TYPE" ,
"UPPER" ,
"VAL" ,
"WORD" ,
"YEAR"
};
#define RESERVED_FUNCTIONS sizeof( _szReservedFun ) / sizeof( char * )
int main( int argc, char * argv[] )
{
int iStatus = 0;
int iArg;
BOOL bSkipGen;
/* Check for the nologo switch /q0 before everything else. */
for( iArg = 1; iArg < argc; iArg++ )
{
if( SwitchCmp( argv[ iArg ], "Q0" ) )
s_bLogo = FALSE;
else if( SwitchCmp( argv[ iArg ], "CREDITS" ) ||
SwitchCmp( argv[ iArg ], "CREDIT" ) ||
SwitchCmp( argv[ iArg ], "CREDI" ) ||
SwitchCmp( argv[ iArg ], "CRED" ) )
s_bCredits = TRUE;
}
if( s_bLogo )
{
printf( "Harbour Compiler, Build %i%s (%04d.%02d.%02d)\n",
hb_build, hb_revision, hb_year, hb_month, hb_day );
printf( "Copyright 1999, http://www.harbour-project.org\n" );
}
if( s_bCredits )
{
PrintCredits();
return iStatus;
}
if( argc > 1 )
{
char szFileName[ _POSIX_PATH_MAX ]; /* filename to parse */
char szPpoName[ _POSIX_PATH_MAX ];
hb_comp_pFileName = NULL;
s_pOutPath = NULL;
Hbpp_init(); /* Initialization of preprocessor arrays */
/* Command line options */
for( iArg = 1; iArg < argc; iArg++ )
{
if( IS_OPT_SEP( argv[ iArg ][ 0 ] ) )
{
switch( argv[ iArg ][ 1 ] )
{
case '1':
if( argv[ iArg ][ 2 ] == '0' )
hb_comp_bRestrictSymbolLength = TRUE;
break;
case 'a':
case 'A':
/* variables declared by PRIVATE and PUBLIC statement are
* automatically assumed as MEMVAR
*/
hb_comp_bAutoMemvarAssume = TRUE;
break;
case 'b':
case 'B':
hb_comp_bDebugInfo = TRUE;
hb_comp_bLineNumbers = TRUE;
break;
case 'd':
case 'D': /* defines a Lex #define from the command line */
{
unsigned int i = 0;
char * szDefText = yy_strdup( argv[ iArg ] + 2 );
while( i < strlen( szDefText ) && szDefText[ i ] != '=' )
i++;
if( szDefText[ i ] != '=' )
AddDefine( szDefText, 0 );
else
{
szDefText[ i ] = '\0';
AddDefine( szDefText, szDefText + i + 1 );
}
free( szDefText );
}
break;
case 'e':
case 'E':
if( argv[ iArg ][ 2 ] == 's' ||
argv[ iArg ][ 2 ] == 'S' )
{
switch( argv[ iArg ][ 3 ] )
{
case '\0':
case '0':
hb_comp_iExitLevel = HB_EXITLEVEL_DEFAULT;
break;
case '1':
hb_comp_iExitLevel = HB_EXITLEVEL_SETEXIT;
break;
case '2':
hb_comp_iExitLevel = HB_EXITLEVEL_DELTARGET;
break;
default:
hb_compGenError( hb_comp_szCErrors, 'E', ERR_BADOPTION, argv[ iArg ], NULL );
}
}
else
hb_compGenError( hb_comp_szCErrors, 'E', ERR_BADOPTION, argv[ iArg ], NULL );
break;
case 'g':
case 'G':
switch( argv[ iArg ][ 2 ] )
{
case 'c':
case 'C':
s_iLanguage = LANG_C;
switch( argv[ iArg ][ 3 ] )
{
case '\0':
case '1':
hb_comp_bGenCVerbose = TRUE;
break;
case '0':
hb_comp_bGenCVerbose = FALSE;
break;
default:
hb_compGenError( hb_comp_szCErrors, 'E', ERR_BADOPTION, argv[ iArg ], NULL );
}
break;
case 'f':
case 'F':
s_iLanguage = LANG_OBJ32;
break;
case 'j':
case 'J':
s_iLanguage = LANG_JAVA;
break;
case 'p':
case 'P':
s_iLanguage = LANG_PASCAL;
break;
case 'r':
case 'R':
s_iLanguage = LANG_RESOURCES;
break;
case 'h':
case 'H':
s_iLanguage = LANG_PORT_OBJ;
break;
default:
printf( "\nUnsupported output language option\n" );
exit( EXIT_FAILURE );
}
break;
case 'i':
case 'I':
{
char * pPath;
char * pDelim;
char * szInclude;
pPath = szInclude = yy_strdup( argv[ iArg ] + 2 );
while( ( pDelim = strchr( pPath, OS_PATH_LIST_SEPARATOR ) ) != NULL )
{
* pDelim = '\0';
AddSearchPath( pPath, &hb_comp_pIncludePath );
pPath = pDelim + 1;
}
AddSearchPath( pPath, &hb_comp_pIncludePath );
}
break;
case 'l':
case 'L':
hb_comp_bLineNumbers = FALSE;
break;
case 'm':
case 'M':
/* TODO: Implement this switch */
printf( "Not yet supported command line option: %s\n", argv[ iArg ] );
break;
case 'n':
case 'N':
hb_comp_bStartProc = FALSE;
break;
case 'o':
case 'O':
s_pOutPath = hb_fsFNameSplit( argv[ iArg ] + 2 );
break;
/* Added for preprocessor needs */
case 'p':
case 'P':
_bPPO = TRUE;
break;
case 'q':
case 'Q':
hb_comp_bQuiet = TRUE;
break;
case 'r':
case 'R':
/* TODO: Implement this switch */
printf( "Not yet supported command line option: %s\n", argv[ iArg ] );
break;
case 's':
case 'S':
s_bSyntaxCheckOnly = TRUE;
break;
case 't':
case 'T':
/* TODO: Implement this switch */
printf( "Not yet supported command line option: %s\n", argv[ iArg ] );
break;
case 'u':
case 'U':
/* TODO: Implement this switch */
printf( "Not yet supported command line option: %s\n", argv[ iArg ] );
break;
case 'v':
case 'V':
/* All undeclared variables are assumed MEMVAR variables
*/
hb_comp_bForceMemvars = TRUE;
break;
case 'w':
case 'W':
hb_comp_iWarnings = 1;
if( argv[ iArg ][ 2 ] )
{ /*there is -w<0,1,2,3> probably */
hb_comp_iWarnings = argv[ iArg ][ 2 ] - '0';
if( hb_comp_iWarnings < 0 || hb_comp_iWarnings > 3 )
hb_compGenError( hb_comp_szCErrors, 'E', ERR_BADOPTION, argv[ iArg ], NULL );
}
break;
case 'x':
case 'X':
{
if( strlen( argv[ iArg ] + 2 ) == 0 )
sprintf( hb_comp_szPrefix, "%08lX_", PackDateTime() );
else
{
strncpy( hb_comp_szPrefix, argv[ iArg ] + 2, 16 );
hb_comp_szPrefix[ 16 ] = '\0';
strcat( hb_comp_szPrefix, "_" );
}
}
break;
#ifdef YYDEBUG
case 'y':
case 'Y':
yydebug = TRUE;
break;
#endif
case 'z':
case 'Z':
hb_comp_bShortCuts = FALSE;
break;
default:
hb_compGenError( hb_comp_szCErrors, 'E', ERR_BADOPTION, argv[ iArg ], NULL );
break;
}
}
else if( argv[ iArg ][ 0 ] == '@' )
/* TODO: Implement this switch */
printf( "Not yet supported command line option: %s\n", argv[ iArg ] );
else
{
if( hb_comp_pFileName )
hb_compGenError( hb_comp_szCErrors, 'E', ERR_BADPARAM, argv[ iArg ], NULL );
else
{
hb_comp_pFileName = hb_fsFNameSplit( argv[ iArg ] );
if( ! hb_comp_pFileName->szName )
hb_compGenError( hb_comp_szCErrors, 'E', ERR_BADFILENAME, argv[ iArg ], NULL );
}
}
}
if( hb_comp_pFileName )
{
if( !hb_comp_pFileName->szExtension )
hb_comp_pFileName->szExtension = ".prg";
hb_fsFNameMerge( szFileName, hb_comp_pFileName );
if( _bPPO )
{
hb_comp_pFileName->szExtension = ".ppo";
hb_fsFNameMerge( szPpoName, hb_comp_pFileName );
yyppo = fopen( szPpoName, "w" );
if( ! yyppo )
{
hb_compGenError( hb_comp_szCErrors, 'E', ERR_CREATE_PPO, szPpoName, NULL );
return iStatus;
}
}
}
else
{
PrintUsage( argv[ 0 ] );
return iStatus;
}
atexit( close_on_exit );
hb_comp_files.iFiles = 0; /* initialize support variables */
hb_comp_files.pLast = NULL;
hb_comp_functions.iCount = 0;
hb_comp_functions.pFirst = NULL;
hb_comp_functions.pLast = NULL;
hb_comp_funcalls.iCount = 0;
hb_comp_funcalls.pFirst = NULL;
hb_comp_funcalls.pLast = NULL;
hb_comp_symbols.iCount = 0;
hb_comp_symbols.pFirst = NULL;
hb_comp_symbols.pLast = NULL;
hb_comp_pInitFunc = NULL;
hb_comp_bAnyWarning = FALSE;
if( Include( szFileName, NULL ) )
{
char * szInclude = getenv( "INCLUDE" );
if( szInclude )
{
char * pPath;
char * pDelim;
pPath = szInclude = yy_strdup( szInclude );
while( ( pDelim = strchr( pPath, OS_PATH_LIST_SEPARATOR ) ) != NULL )
{
*pDelim = '\0';
AddSearchPath( pPath, &hb_comp_pIncludePath );
pPath = pDelim + 1;
}
AddSearchPath( pPath, &hb_comp_pIncludePath );
}
/*
* Start processing
*/
harbour_main( hb_comp_pFileName->szName );
bSkipGen = FALSE;
if( hb_comp_bAnyWarning )
{
if( hb_comp_iExitLevel == HB_EXITLEVEL_SETEXIT )
iStatus = 1;
if( hb_comp_iExitLevel == HB_EXITLEVEL_DELTARGET )
{
iStatus = 1;
bSkipGen = TRUE;
printf( "\nNo code generated\n" );
}
}
if( ! s_bSyntaxCheckOnly && ! bSkipGen && ( hb_comp_iErrorCount == 0 ) )
{
hb_comp_pFileName->szPath = NULL;
hb_comp_pFileName->szExtension = NULL;
/* we create a the output file */
if( s_pOutPath )
{
if( s_pOutPath->szPath )
hb_comp_pFileName->szPath = s_pOutPath->szPath;
if( s_pOutPath->szName )
{
hb_comp_pFileName->szName = s_pOutPath->szName;
if( s_pOutPath->szExtension )
hb_comp_pFileName->szExtension = s_pOutPath->szExtension;
}
}
switch( s_iLanguage )
{
case LANG_C:
GenCCode( hb_comp_pFileName );
break;
case LANG_OBJ32:
#ifdef HARBOUR_OBJ_GENERATION
GenObj32( hb_comp_pFileName );
#endif
break;
case LANG_JAVA:
GenJava( hb_comp_pFileName );
break;
case LANG_PASCAL:
GenPascal( hb_comp_pFileName );
break;
case LANG_RESOURCES:
GenRC( hb_comp_pFileName );
break;
case LANG_PORT_OBJ:
GenPortObj( hb_comp_pFileName );
break;
}
}
if( _bPPO )
fclose( yyppo );
}
else
{
printf( "Cannot open input file: %s\n", szFileName );
iStatus = 1;
}
hb_xfree( ( void * ) hb_comp_pFileName );
if( s_pOutPath )
hb_xfree( s_pOutPath );
if( hb_comp_iErrorCount > 0 )
iStatus = EXIT_FAILURE;
}
else
PrintUsage( argv[ 0 ] );
return iStatus;
}
/*
* Prints available options
*/
static void PrintUsage( char * szSelf )
{
printf( "\nSyntax: %s <file[.prg]> [options]"
"\n"
"\nOptions: /a automatic memvar declaration"
"\n /b debug info"
"\n /d<id>[=<val>] #define <id>"
"\n /es[<level>] set exit severity"
"\n /g<type> output type generated is <type> (see below)"
"\n /gc[<type>] output type: C source (.c) (default)"
"\n <type>: 0=without comments, 1=normal (default)"
#ifdef HARBOUR_OBJ_GENERATION
"\n /gf output type: Windows/DOS OBJ32 (.obj)"
#endif
"\n /gh output type: Harbour Portable Object (.hrb)"
"\n /gj output type: Java source (.java)"
"\n /gp output type: Pascal source (.pas)"
"\n /gr output type: Windows resource (.rc)"
"\n /i<path> add #include file search path"
"\n /l suppress line number information"
/* TODO: "\n /m compile module only" */
"\n /n no implicit starting procedure"
"\n /o<path> object file drive and/or path"
"\n /p generate pre-processed output (.ppo) file"
"\n /q quiet"
"\n /q0 quiet and don't display program header"
/* TODO: "\n /r[<lib>] request linker to search <lib> (or none)" */
"\n /s syntax check only"
/* TODO: "\n /t<path> path for temp file creation" */
/* TODO: "\n /u[<file>] use command def set in <file> (or none)" */
"\n /v variables are assumed M->"
"\n /w[<level>] set warning level number (0..3, default 1)"
"\n /x[<prefix>] set symbol init function name prefix (for .c only)"
#ifdef YYDEBUG
"\n /y trace lex & yacc activity"
#endif
"\n /z suppress shortcutting (.and. & .or.)"
"\n /10 restrict symbol length to 10 characters"
/* TODO: "\n @<file> compile list of modules in <file>" */
"\n"
, szSelf );
}
/*
* Prints credits
*/
static void PrintCredits( void )
{
printf( "\nCredits: The Harbour Team at www.harbour-project.com"
);
}
#if defined(__IBMCPP__) || defined(_MSC_VER)
int isatty( int handle )
{
return ( handle < 4 ) ? 1 : 0;
}
#endif
static BOOL SwitchCmp( char * szString, char * szSwitch )
{
if( IS_OPT_SEP( *szString ) )
{
szString++;
if( strlen( szString ) == strlen( szSwitch ) )
{
while( *szString != '\0' )
{
if( toupper( *szString ) != *szSwitch )
return FALSE;
szString++;
szSwitch++;
}
return TRUE;
}
}
return FALSE;
}
/* NOTE: Making the date and time info to fit into 32 bits can only be done
in a "lossy" way, in practice that means it's not possible to unpack
the exact date/time info from the resulting ULONG. Since the year
is only stored in 6 bits, 1980 will result in the same bit pattern
as 2044. The purpose of this value is only used to *differenciate*
between the dates ( the exact dates are not significant ), so this can
be used here without problems. */
/* 76543210765432107654321076543210
|.......|.......|.......|.......
|____| Year 6 bits
|__| Month 4 bits
|___| Day 5 bits
|___| Hour 5 bits
|____| Minute 6 bits
|____| Second 6 bits */
static ULONG PackDateTime( void )
{
BYTE szString[ 4 ];
BYTE nValue;
time_t t;
struct tm * oTime;
time( &t );
oTime = localtime( &t );
nValue = ( BYTE ) ( ( ( oTime->tm_year + 1900 ) - 1980 ) & ( 2 ^ 6 ) ) ; /* 6 bits */
szString[ 0 ] = nValue << 2;
nValue = ( BYTE ) ( oTime->tm_mon + 1 ); /* 4 bits */
szString[ 0 ] |= nValue >> 2;
szString[ 1 ] = nValue << 6;
nValue = ( BYTE ) ( oTime->tm_mday ); /* 5 bits */
szString[ 1 ] |= nValue << 1;
nValue = ( BYTE ) oTime->tm_hour; /* 5 bits */
szString[ 1 ] = nValue >> 4;
szString[ 2 ] = nValue << 4;
nValue = ( BYTE ) oTime->tm_min; /* 6 bits */
szString[ 2 ] |= nValue >> 2;
szString[ 3 ] = nValue << 6;
nValue = ( BYTE ) oTime->tm_sec; /* 6 bits */
szString[ 3 ] |= nValue;
return HB_MKLONG( szString[ 3 ], szString[ 2 ], szString[ 1 ], szString[ 0 ] );
}
/*
* Function that adds specified path to the list of pathnames to search
*/
void AddSearchPath( char * szPath, PATHNAMES * * pSearchList )
{
PATHNAMES * pPath = *pSearchList;
if( pPath )
{
while( pPath->pNext )
pPath = pPath->pNext;
pPath->pNext = ( PATHNAMES * ) hb_xgrab( sizeof( PATHNAMES ) );
pPath = pPath->pNext;
}
else
{
*pSearchList = pPath = ( PATHNAMES * ) hb_xgrab( sizeof( PATHNAMES ) );
}
pPath->pNext = NULL;
pPath->szPath = szPath;
}
void EXTERNAL_LINKAGE close_on_exit( void )
{
PFILE pFile = hb_comp_files.pLast;
while( pFile )
{
fclose( pFile->handle );
pFile = ( PFILE ) pFile->pPrev;
}
}
/* ------------------------------------------------------------------------- */
#define IS_PATH_SEP( c ) ( strchr( OS_PATH_DELIMITER_LIST, ( c ) ) != NULL )
/* Split given filename into path, name and extension */
PHB_FNAME hb_fsFNameSplit( char * szFileName )
{
PHB_FNAME pFileName = ( PHB_FNAME ) hb_xgrab( sizeof( HB_FNAME ) );
int iLen = strlen( szFileName );
int iSlashPos;
int iDotPos;
int iPos;
pFileName->szPath =
pFileName->szName =
pFileName->szExtension = NULL;
iSlashPos = iLen - 1;
iPos = 0;
while( iSlashPos >= 0 && !IS_PATH_SEP( szFileName[ iSlashPos ] ) )
--iSlashPos;
if( iSlashPos == 0 )
{
/* root path -> \filename */
pFileName->szBuffer[ 0 ] = OS_PATH_DELIMITER;
pFileName->szBuffer[ 1 ] = '\0';
pFileName->szPath = pFileName->szBuffer;
iPos = 2; /* first free position after the slash */
}
else if( iSlashPos > 0 )
{
/* If we are after a drive letter let's keep the following backslash */
if( IS_PATH_SEP( ':' ) &&
( szFileName[ iSlashPos ] == ':' || szFileName[ iSlashPos - 1 ] == ':' ) )
{
/* path with separator -> d:\path\filename or d:path\filename */
memcpy( pFileName->szBuffer, szFileName, iSlashPos + 1 );
pFileName->szBuffer[ iSlashPos + 1 ] = '\0';
iPos = iSlashPos + 2; /* first free position after the slash */
}
else
{
/* path with separator -> path\filename */
memcpy( pFileName->szBuffer, szFileName, iSlashPos );
pFileName->szBuffer[ iSlashPos ] = '\0';
iPos = iSlashPos + 1; /* first free position after the slash */
}
pFileName->szPath = pFileName->szBuffer;
}
iDotPos = iLen - 1;
while( iDotPos > iSlashPos && szFileName[ iDotPos ] != '.' )
--iDotPos;
if( ( iDotPos - iSlashPos ) > 1 )
{
/* the dot was found
* and there is at least one character between a slash and a dot
*/
if( iDotPos == iLen - 1 )
{
/* the dot is the last character - use it as extension name */
pFileName->szExtension = pFileName->szBuffer + iPos;
pFileName->szBuffer[ iPos++ ] = '.';
pFileName->szBuffer[ iPos++ ] = '\0';
}
else
{
pFileName->szExtension = pFileName->szBuffer + iPos;
/* copy rest of the string with terminating ZERO character */
memcpy( pFileName->szExtension, szFileName + iDotPos + 1, iLen - iDotPos );
iPos += iLen - iDotPos;
}
}
else
/* there is no dot in the filename or it is '.filename' */
iDotPos = iLen;
if( ( iDotPos - iSlashPos - 1 ) > 0 )
{
pFileName->szName = pFileName->szBuffer + iPos;
memcpy( pFileName->szName, szFileName + iSlashPos + 1, iDotPos - iSlashPos - 1 );
pFileName->szName[ iDotPos - iSlashPos - 1 ] = '\0';
}
/* DEBUG
printf( "\nFilename: %s\n", szFileName );
printf( "\n szPath: %s\n", pFileName->szPath );
printf( "\n szName: %s\n", pFileName->szName );
printf( "\n szExt: %s\n", pFileName->szExtension );
*/
return pFileName;
}
/* This function joins path, name and extension into a string with a filename */
char * hb_fsFNameMerge( char * szFileName, PHB_FNAME pFileName )
{
if( pFileName->szPath && pFileName->szPath[ 0 ] )
{
/* we have not empty path specified */
int iLen = strlen( pFileName->szPath );
strcpy( szFileName, pFileName->szPath );
/* if the path is a root directory then we don't need to add path separator */
if( !( IS_PATH_SEP( pFileName->szPath[ 0 ] ) && pFileName->szPath[ 0 ] == '\0' ) )
{
/* add the path separator only in cases:
* when a name doesn't start with it
* when the path doesn't end with it
*/
if( !( IS_PATH_SEP( pFileName->szName[ 0 ] ) || IS_PATH_SEP( pFileName->szPath[ iLen-1 ] ) ) )
{
szFileName[ iLen++ ] = OS_PATH_DELIMITER;
szFileName[ iLen ] = '\0';
}
}
if( pFileName->szName )
strcpy( szFileName + iLen, pFileName->szName );
}
else
{
if( pFileName->szName )
strcpy( szFileName, pFileName->szName );
}
if( pFileName->szExtension )
{
int iLen = strlen( szFileName );
if( !( pFileName->szExtension[ 0 ] == '.' || szFileName[ iLen - 1 ] == '.') )
{
/* add extension separator only when extansion doesn't contain it */
szFileName[ iLen++ ] = '.';
szFileName[ iLen ] = '\0';
}
strcpy( szFileName + iLen, pFileName->szExtension );
}
/* DEBUG
printf( "\nMERGE:\n" );
printf( "\n szPath: %s\n", pFileName->szPath );
printf( "\n szName: %s\n", pFileName->szName );
printf( "\n szExt: %s\n", pFileName->szExtension );
printf( "\nFilename result: %s\n", szFileName );
*/
return szFileName;
}
/* ------------------------------------------------------------------------- */
void * hb_xgrab( ULONG ulSize ) /* allocates fixed memory, exits on failure */
{
void * pMem = malloc( ulSize );
if( ! pMem )
hb_compGenError( hb_comp_szCErrors, 'E', ERR_MEMALLOC, NULL, NULL );
return pMem;
}
void * hb_xrealloc( void * pMem, ULONG ulSize ) /* reallocates memory */
{
void * pResult = realloc( pMem, ulSize );
if( ! pResult )
hb_compGenError( hb_comp_szCErrors, 'E', ERR_MEMREALLOC, NULL, NULL );
return pResult;
}
void hb_xfree( void * pMem ) /* frees fixed memory */
{
if( pMem )
free( pMem );
else
hb_compGenError( hb_comp_szCErrors, 'E', ERR_MEMFREE, NULL, NULL );
}
char * yy_strupr( char * p )
{
char * p1;
for( p1 = p; * p1; p1++ )
* p1 = toupper( * p1 );
return p;
}
char * yy_strdup( char * p )
{
char * pDup;
int iLen;
iLen = strlen( p ) + 1;
pDup = ( char * ) hb_xgrab( iLen );
memcpy( pDup, p, iLen );
return pDup;
}
/* ------------------------------------------------------------------------- */
void hb_compGenError( char* _szErrors[], char cPrefix, int iError, char * szError1, char * szError2 )
{
if( hb_comp_files.pLast != NULL && hb_comp_files.pLast->szFileName != NULL )
printf( "\r%s(%i) ", hb_comp_files.pLast->szFileName, iLine );
printf( "Error %c%04i ", cPrefix, iError );
printf( _szErrors[ iError - 1 ], szError1, szError2 );
printf( "\n" );
hb_comp_iErrorCount++;
/* exit( EXIT_FAILURE ); */
}
void hb_compGenWarning( char* _szWarnings[], char cPrefix, int iWarning, char * szWarning1, char * szWarning2)
{
char *szText = _szWarnings[ iWarning - 1 ];
if( (szText[ 0 ] - '0') <= hb_comp_iWarnings )
{
printf( "\r%s(%i) ", hb_comp_files.pLast->szFileName, iLine );
printf( "Warning %c%04i ", cPrefix, iWarning );
printf( szText + 1, szWarning1, szWarning2 );
printf( "\n" );
hb_comp_bAnyWarning = TRUE; /* report warnings at exit */
}
}
/* ------------------------------------------------------------------------- */
/* checks if passed string is a reserved function name
*/
static char * RESERVED_FUNC( char * szName )
{
USHORT wNum = 0;
int iFound = 1;
while( wNum < RESERVED_FUNCTIONS && iFound )
{
/* Compare first 4 characters
* If they are the same then compare the whole name
* SECO() is not allowed because of Clipper function SECONDS()
* however SECO32() is a valid name.
*/
iFound = strncmp( szName, _szReservedFun[ wNum ], 4 );
if( iFound == 0 )
iFound = strncmp( szName, _szReservedFun[ wNum ], strlen( szName ) );
++wNum;
}
if( iFound )
return NULL;
else
return (char *) _szReservedFun[ wNum - 1 ];
}
/* NOTE: iMinParam = -1, means no checking */
/* iMaxParam = -1, means no upper limit */
typedef struct
{
char * cFuncName; /* function name */
int iMinParam; /* min no of parms it needs */
int iMaxParam; /* max no of parms need */
} FUNCINFO, * PFUNCINFO;
static FUNCINFO _StdFun[] =
{
{ "AADD" , 2, 2 },
{ "ABS" , 1, 1 },
{ "ASC" , 1, 1 },
{ "AT" , 2, 2 },
{ "BOF" , 0, 0 },
{ "BREAK" , 0, 1 },
{ "CDOW" , 1, 1 },
{ "CHR" , 1, 1 },
{ "CMONTH" , 1, 1 },
{ "COL" , 0, 0 },
{ "CTOD" , 1, 1 },
{ "DATE" , 0, 0 },
{ "DAY" , 1, 1 },
{ "DELETED" , 0, 0 },
{ "DEVPOS" , 2, 2 },
{ "DOW" , 1, 1 },
{ "DTOC" , 1, 1 },
{ "DTOS" , 1, 1 },
{ "EMPTY" , 1, 1 },
{ "EOF" , 0, 0 },
{ "EVAL" , 1, -1 },
{ "EXP" , 1, 1 },
{ "FCOUNT" , 0, 0 },
{ "FIELDNAME" , 1, 1 },
{ "FILE" , 1, 1 },
{ "FLOCK" , 0, 0 },
{ "FOUND" , 0, 0 },
{ "INKEY" , 0, 2 },
{ "INT" , 1, 1 },
{ "LASTREC" , 0, 0 },
{ "LEFT" , 2, 2 },
{ "LEN" , 1, 1 },
{ "LOCK" , 0, 0 },
{ "LOG" , 1, 1 },
{ "LOWER" , 1, 1 },
{ "LTRIM" , 1, 1 },
{ "MAX" , 2, 2 },
{ "MIN" , 2, 2 },
{ "MONTH" , 1, 1 },
{ "PCOL" , 0, 0 },
{ "PCOUNT" , 0, 0 },
{ "PROW" , 0, 0 },
{ "RECCOUNT" , 0, 0 },
{ "RECNO" , 0, 0 },
{ "REPLICATE" , 2, 2 },
{ "RLOCK" , 0, 0 },
{ "ROUND" , 2, 2 },
{ "ROW" , 0, 0 },
{ "RTRIM" , 1, 2 }, /* Second parameter is a Harbour extension */
{ "SECONDS" , 0, 0 },
{ "SELECT" , 0, 1 },
{ "SETPOS" , 2, 2 },
{ "SETPOSBS" , 0, 0 },
{ "SPACE" , 1, 1 },
{ "SQRT" , 1, 1 },
{ "STR" , 1, 3 },
{ "SUBSTR" , 2, 3 },
{ "TIME" , 0, 0 },
{ "TRANSFORM" , 2, 2 },
{ "TRIM" , 1, 2 }, /* Second parameter is a Harbour extension */
{ "TYPE" , 1, 1 },
{ "UPPER" , 1, 1 },
{ "VAL" , 1, 1 },
{ "VALTYPE" , 1, 1 },
{ "WORD" , 1, 1 },
{ "YEAR" , 1, 1 },
{ 0 , 0, 0 }
};
void hb_compCheckArgs( char * szFuncCall, int iArgs )
{
FUNCINFO * f = _StdFun;
int i = 0;
int iPos = -1;
int iCmp;
while( f[ i ].cFuncName )
{
iCmp = strncmp( szFuncCall, f[ i ].cFuncName, 4 );
if( iCmp == 0 )
iCmp = strncmp( szFuncCall, f[ i ].cFuncName, strlen( szFuncCall ) );
if( iCmp == 0 )
{
iPos = i;
break;
}
else
++i;
}
if( iPos >= 0 && ( f[ iPos ].iMinParam != -1 ) )
{
if( iArgs < f[ iPos ].iMinParam || ( f[ iPos ].iMaxParam != -1 && iArgs > f[ iPos ].iMaxParam ) )
{
char szMsg[ 40 ];
if( f[ iPos ].iMaxParam == -1 )
sprintf( szMsg, "\nPassed: %i, expected: at least %i", iArgs, f[ iPos ].iMinParam );
else if( f[ iPos ].iMinParam == f[ iPos ].iMaxParam )
sprintf( szMsg, "\nPassed: %i, expected: %i", iArgs, f[ iPos ].iMinParam );
else
sprintf( szMsg, "\nPassed: %i, expected: %i - %i", iArgs, f[ iPos ].iMinParam, f[ iPos ].iMaxParam );
hb_compGenError( hb_comp_szCErrors, 'E', ERR_CHECKING_ARGS, szFuncCall, szMsg );
/* Clipper way */
/* hb_compGenError( hb_comp_szCErrors, 'E', ERR_CHECKING_ARGS, szFuncCall, NULL ); */
}
}
}
/* ------------------------------------------------------------------------- */
/** ACTIONS **/
/* ------------------------------------------------------------------------- */
/*
* This function adds the name of called function into the list
* as they have to be placed on the symbol table later than the first
* public symbol
*/
PFUNCTION hb_compAddFunCall( char * szFunctionName )
{
PFUNCTION pFunc = FunctionNew( szFunctionName, 0 );
if( ! hb_comp_funcalls.iCount )
{
hb_comp_funcalls.pFirst = pFunc;
hb_comp_funcalls.pLast = pFunc;
}
else
{
( ( PFUNCTION ) hb_comp_funcalls.pLast )->pNext = pFunc;
hb_comp_funcalls.pLast = pFunc;
}
hb_comp_funcalls.iCount++;
return pFunc;
}
/*
* This function adds the name of external symbol into the list of externals
* as they have to be placed on the symbol table later than the first
* public symbol
*/
void hb_compAddExtern( char * szExternName ) /* defines a new extern name */
{
PEXTERN pExtern = ( PEXTERN ) hb_xgrab( sizeof( _EXTERN ) ), pLast;
pExtern->szName = szExternName;
pExtern->pNext = NULL;
if( hb_comp_pExterns == NULL )
hb_comp_pExterns = pExtern;
else
{
pLast = hb_comp_pExterns;
while( pLast->pNext )
pLast = pLast->pNext;
pLast->pNext = pExtern;
}
}
void hb_compAddVar( char * szVarName, char cValueType )
{
PVAR pVar, pLastVar;
PFUNCTION pFunc = hb_comp_functions.pLast;
if( ! hb_comp_bStartProc && hb_comp_functions.iCount <= 1 && hb_comp_iVarScope == VS_LOCAL )
{
/* Variable declaration is outside of function/procedure body.
In this case only STATIC and PARAMETERS variables are allowed. */
--iLine;
hb_compGenError( hb_comp_szCErrors, 'E', ERR_OUTSIDE, NULL, NULL );
}
/* check if we are declaring local/static variable after some
* executable statements
* Note: FIELD and MEMVAR are executable statements
*/
if( ( hb_comp_functions.pLast->bFlags & FUN_STATEMENTS ) && !( hb_comp_iVarScope == VS_FIELD || ( hb_comp_iVarScope & VS_MEMVAR ) ) )
{
--iLine;
hb_compGenError( hb_comp_szCErrors, 'E', ERR_FOLLOWS_EXEC, ( hb_comp_iVarScope == VS_LOCAL ? "LOCAL" : "STATIC" ), NULL );
}
/* When static variable is added then hb_comp_functions.pLast points to function
* that will initialise variables. The function where variable is being
* defined is stored in pOwner member.
*/
if( hb_comp_iVarScope == VS_STATIC )
pFunc = pFunc->pOwner;
/* Check if a declaration of duplicated variable name is requested */
if( pFunc->szName )
{
/* variable defined in a function/procedure */
CheckDuplVars( pFunc->pFields, szVarName, hb_comp_iVarScope );
CheckDuplVars( pFunc->pStatics, szVarName, hb_comp_iVarScope );
if( !( hb_comp_iVarScope == VS_PRIVATE || hb_comp_iVarScope == VS_PUBLIC ) )
CheckDuplVars( pFunc->pMemvars, szVarName, hb_comp_iVarScope );
}
else
/* variable defined in a codeblock */
hb_comp_iVarScope = VS_PARAMETER;
CheckDuplVars( pFunc->pLocals, szVarName, hb_comp_iVarScope );
pVar = ( PVAR ) hb_xgrab( sizeof( VAR ) );
pVar->szName = szVarName;
pVar->szAlias = NULL;
pVar->cType = hb_comp_cVarType;
pVar->iUsed = 0;
pVar->pNext = NULL;
if( hb_comp_iVarScope & VS_MEMVAR )
{
PCOMSYMBOL pSym;
USHORT wPos;
if( hb_comp_bAutoMemvarAssume || hb_comp_iVarScope == VS_MEMVAR )
{
/* add this variable to the list of MEMVAR variables
*/
if( ! pFunc->pMemvars )
pFunc->pMemvars = pVar;
else
{
pLastVar = pFunc->pMemvars;
while( pLastVar->pNext )
pLastVar = pLastVar->pNext;
pLastVar->pNext = pVar;
}
}
switch( hb_comp_iVarScope )
{
case VS_MEMVAR:
/* variable declared in MEMVAR statement */
break;
case ( VS_PARAMETER | VS_PRIVATE ):
{
BOOL bNewParameter = FALSE;
if( ++hb_comp_functions.pLast->wParamNum > hb_comp_functions.pLast->wParamCount )
{
hb_comp_functions.pLast->wParamCount = hb_comp_functions.pLast->wParamNum;
bNewParameter = TRUE;
}
pSym = hb_compGetSymbol( szVarName, &wPos ); /* check if symbol exists already */
if( ! pSym )
pSym = hb_compAddSymbol( yy_strdup( szVarName ), &wPos );
pSym->cScope |= VS_MEMVAR;
hb_compGenPCode3( HB_P_PARAMETER, HB_LOBYTE( wPos ), HB_HIBYTE( wPos ) );
hb_compGenPCode1( HB_LOBYTE( hb_comp_functions.pLast->wParamNum ) );
/* Add this variable to the local variables list - this will
* allow to use the correct positions for real local variables.
* The name of variable have to be hidden because we should
* not find this name on the local variables list.
* We have to use the new structure because it is used in
* memvars list already.
*/
if( bNewParameter )
{
pVar = ( PVAR ) hb_xgrab( sizeof( VAR ) );
pVar->szName = yy_strdup( szVarName );
pVar->szAlias = NULL;
pVar->cType = cValueType;
pVar->iUsed = 0;
pVar->pNext = NULL;
pVar->szName[ 0 ] ='!';
if( ! pFunc->pLocals )
pFunc->pLocals = pVar;
else
{
pLastVar = pFunc->pLocals;
while( pLastVar->pNext )
pLastVar = pLastVar->pNext;
pLastVar->pNext = pVar;
}
}
}
break;
case VS_PRIVATE:
{
hb_compPushSymbol( yy_strdup( "__MVPRIVATE" ), 1);
hb_compGenPushNil();
hb_compPushSymbol( yy_strdup( szVarName ), 0 );
hb_compGenDoProc( 1 );
pSym = hb_compGetSymbol( szVarName, NULL );
pSym->cScope |= VS_MEMVAR;
}
break;
case VS_PUBLIC:
{
hb_compPushSymbol( yy_strdup( "__MVPUBLIC" ), 1);
hb_compGenPushNil();
hb_compPushSymbol( yy_strdup( szVarName ), 0 );
hb_compGenDoProc( 1 );
pSym = hb_compGetSymbol( szVarName, NULL );
pSym->cScope |= VS_MEMVAR;
}
break;
}
}
else
{
switch( hb_comp_iVarScope )
{
case VS_LOCAL:
case VS_PARAMETER:
{
USHORT wLocal = 1;
if( ! pFunc->pLocals )
pFunc->pLocals = pVar;
else
{
pLastVar = pFunc->pLocals;
while( pLastVar->pNext )
{
pLastVar = pLastVar->pNext;
wLocal++;
}
pLastVar->pNext = pVar;
}
if( hb_comp_iVarScope == VS_PARAMETER )
{
++hb_comp_functions.pLast->wParamCount;
hb_comp_functions.pLast->bFlags |= FUN_USES_LOCAL_PARAMS;
}
if( hb_comp_bDebugInfo )
{
hb_compGenPCode3( HB_P_LOCALNAME, HB_LOBYTE( wLocal ), HB_HIBYTE( wLocal ) );
hb_compGenPCodeN( ( BYTE * )szVarName, strlen( szVarName ) );
hb_compGenPCode1( 0 );
}
}
break;
case VS_STATIC:
if( ! pFunc->pStatics )
pFunc->pStatics = pVar;
else
{
pLastVar = pFunc->pStatics;
while( pLastVar->pNext )
pLastVar = pLastVar->pNext;
pLastVar->pNext = pVar;
}
break;
case VS_FIELD:
if( ! pFunc->pFields )
pFunc->pFields = pVar;
else
{
pLastVar = pFunc->pFields;
while( pLastVar->pNext )
pLastVar = pLastVar->pNext;
pLastVar->pNext = pVar;
}
break;
}
}
}
PCOMSYMBOL hb_compAddSymbol( char * szSymbolName, USHORT * pwPos )
{
PCOMSYMBOL pSym = ( PCOMSYMBOL ) hb_xgrab( sizeof( COMSYMBOL ) );
pSym->szName = szSymbolName;
pSym->cScope = 0;
pSym->cType = hb_comp_cVarType;
pSym->pNext = NULL;
if( ! hb_comp_symbols.iCount )
{
hb_comp_symbols.pFirst = pSym;
hb_comp_symbols.pLast = pSym;
}
else
{
( ( PCOMSYMBOL ) hb_comp_symbols.pLast )->pNext = pSym;
hb_comp_symbols.pLast = pSym;
}
hb_comp_symbols.iCount++;
if( pwPos )
*pwPos = hb_comp_symbols.iCount;
/*if( hb_comp_cVarType != ' ') printf("\nDeclared %s as type %c at symbol %i\n", szSymbolName, hb_comp_cVarType, hb_comp_symbols.iCount );*/
return pSym;
}
/* Adds new alias to the alias stack
*/
void AliasAdd( ALIASID_PTR pAlias )
{
pAlias->pPrev = hb_comp_pAliasId;
hb_comp_pAliasId = pAlias;
}
/* Restores previously selected alias
*/
void AliasRemove( void )
{
ALIASID_PTR pAlias = hb_comp_pAliasId;
hb_comp_pAliasId = hb_comp_pAliasId->pPrev;
hb_xfree( pAlias );
}
/* Adds an integer workarea number into alias stack
*/
void AliasAddInt( int iWorkarea )
{
ALIASID_PTR pAlias = ( ALIASID_PTR ) hb_xgrab( sizeof( ALIASID ) );
pAlias->type = ALIAS_NUMBER;
pAlias->alias.iAlias = iWorkarea;
AliasAdd( pAlias );
}
/* Adds an expression into alias stack
*/
void AliasAddExp( void )
{
ALIASID_PTR pAlias = ( ALIASID_PTR ) hb_xgrab( sizeof( ALIASID ) );
pAlias->type = ALIAS_EVAL;
AliasAdd( pAlias );
}
/* Adds an alias name into alias stack
*/
void AliasAddStr( char * szAlias )
{
ALIASID_PTR pAlias = ( ALIASID_PTR ) hb_xgrab( sizeof( ALIASID ) );
pAlias->type = ALIAS_NAME;
pAlias->alias.szAlias = szAlias;
AliasAdd( pAlias );
}
/* Generates pcodes to store the current workarea number
*/
void AliasPush( void )
{
hb_compGenPCode1( HB_P_PUSHALIAS );
}
/* Generates pcodes to select the workarea number using current value
* from the eval stack
*/
void AliasPop( void )
{
hb_compGenPCode1( HB_P_POPALIAS );
}
/* Generates pcodes to swap two last items from the eval stack.
* Last item (after swaping) is next popped as current workarea
*/
void AliasSwap( void )
{
hb_compGenPCode1( HB_P_SWAPALIAS );
}
void Duplicate( void )
{
hb_compGenPCode1( HB_P_DUPLICATE );
}
void DupPCode( ULONG ulStart ) /* duplicates the current generated pcode from an offset */
{
ULONG w, wEnd = hb_comp_functions.pLast->lPCodePos - ulStart;
for( w = 0; w < wEnd; w++ )
hb_compGenPCode1( hb_comp_functions.pLast->pCode[ ulStart + w ] );
}
/*
* Starts a new expression in the parenthesized epressions list
*/
void ExpListPush( void )
{
EXPLIST_PTR pExp = ( EXPLIST_PTR ) hb_xgrab( sizeof( EXPLIST ) );
pExp->pNext = pExp->pPrev = NULL;
/* Store the previous state on the stack */
if( hb_comp_pExprList )
{
hb_comp_pExprList->pNext = pExp;
pExp->pPrev = hb_comp_pExprList;
/* save currently used pcode buffer */
hb_comp_pExprList->exprSize = hb_comp_functions.pLast->lPCodePos;
hb_comp_pExprList->exprPCode = hb_comp_functions.pLast->pCode;
}
hb_comp_pExprList = pExp;
/* store current pcode buffer */
pExp->prevPCode = hb_comp_functions.pLast->pCode;
pExp->prevSize = hb_comp_functions.pLast->lPCodeSize;
pExp->prevPos = hb_comp_functions.pLast->lPCodePos;
/* and create the new one */
hb_comp_functions.pLast->pCode = ( BYTE * ) hb_xgrab( PCODE_CHUNK );
hb_comp_functions.pLast->lPCodeSize = PCODE_CHUNK;
hb_comp_functions.pLast->lPCodePos = 0;
pExp->exprPCode = hb_comp_functions.pLast->pCode;
}
/*
* Pops specified number of expressions from the stack
*/
void ExpListPop( int iExpCount )
{
EXPLIST_PTR pExp, pDel;
/* save currently used pcode buffer */
hb_comp_pExprList->exprSize = hb_comp_functions.pLast->lPCodePos;
hb_comp_pExprList->exprPCode = hb_comp_functions.pLast->pCode;
/* find the first expression in the list */
while( --iExpCount )
hb_comp_pExprList = hb_comp_pExprList->pPrev;
/* return to the original pcode buffer */
hb_comp_functions.pLast->pCode = hb_comp_pExprList->prevPCode;
hb_comp_functions.pLast->lPCodeSize = hb_comp_pExprList->prevSize;
hb_comp_functions.pLast->lPCodePos = hb_comp_pExprList->prevPos;
pExp = hb_comp_pExprList;
if( hb_comp_pExprList->pPrev )
{
hb_comp_pExprList = hb_comp_pExprList->pPrev;
hb_comp_pExprList->pNext = NULL;
}
else
hb_comp_pExprList = NULL;
while( pExp )
{
if( pExp->exprSize )
{
hb_compGenPCodeN( pExp->exprPCode, pExp->exprSize );
if( pExp->pNext )
hb_compGenPCode1( HB_P_POP );
}
else
{
/* exprN, , exprN1
* in this context empty expression is not allowed
*
* NOTE:
* We don't have to generate this error - it is safe to continue
* pcode generation - in this case an empty expression will not
* generate any opcode
*/
hb_compGenError( hb_comp_szCErrors, 'E', ERR_SYNTAX, ")", NULL );
}
hb_xfree( pExp->exprPCode );
pDel = pExp;
pExp = pExp->pNext;
hb_xfree( pDel );
}
}
/*
* Function generates passed pcode for passed database field
*/
void FieldPCode( BYTE bPCode, char * szVarName )
{
USHORT wVar;
PCOMSYMBOL pVar;
pVar = hb_compGetSymbol( szVarName, &wVar );
if( ! pVar )
pVar = hb_compAddSymbol( szVarName, &wVar );
pVar->cScope |= VS_MEMVAR;
hb_compGenPCode3( bPCode, HB_LOBYTE( wVar ), HB_HIBYTE( wVar ) );
}
/*
* This function creates and initialises the _FUNC structure
*/
PFUNCTION FunctionNew( char * szName, HB_SYMBOLSCOPE cScope )
{
PFUNCTION pFunc;
pFunc = ( PFUNCTION ) hb_xgrab( sizeof( _FUNC ) );
pFunc->szName = szName;
pFunc->cScope = cScope;
pFunc->pLocals = NULL;
pFunc->pStatics = NULL;
pFunc->pFields = NULL;
pFunc->pMemvars = NULL;
pFunc->pCode = NULL;
pFunc->lPCodeSize = 0;
pFunc->lPCodePos = 0;
pFunc->pNext = NULL;
pFunc->wParamCount = 0;
pFunc->wParamNum = 0;
pFunc->iStaticsBase = hb_comp_iStaticCnt;
pFunc->pOwner = NULL;
pFunc->bFlags = 0;
hb_comp_lLastPushPos = -1;
return pFunc;
}
/*
* Stores a Clipper defined function/procedure
* szFunName - name of a function
* cScope - scope of a function
* iType - FUN_PROCEDURE if a procedure or 0
*/
void hb_compFunDef( char * szFunName, HB_SYMBOLSCOPE cScope, int iType )
{
PCOMSYMBOL pSym;
PFUNCTION pFunc;
char * szFunction;
FixReturns(); /* fix all previous function returns offsets */
pFunc = GetFunction( szFunName );
if( pFunc )
{
/* The name of a function/procedure is already defined */
if( ( pFunc != hb_comp_functions.pFirst ) || hb_comp_bStartProc )
/* it is not a starting procedure that was automatically created */
hb_compGenError( hb_comp_szCErrors, 'E', ERR_FUNC_DUPL, szFunName, NULL );
}
szFunction = RESERVED_FUNC( szFunName );
if( szFunction && !( hb_comp_functions.iCount==0 && !hb_comp_bStartProc ) )
{
/* We are ignoring it when it is the name of PRG file and we are
* not creating implicit starting procedure
*/
hb_compGenError( hb_comp_szCErrors, 'E', ERR_FUNC_RESERVED, szFunction, szFunName );
}
hb_comp_iFunctionCnt++;
pSym = hb_compGetSymbol( szFunName, NULL );
if( ! pSym )
/* there is not a symbol on the symbol table for this function name */
pSym = hb_compAddSymbol( szFunName, NULL );
if( cScope != FS_PUBLIC )
/* pSym->cScope = FS_PUBLIC; */
/* else */
pSym->cScope |= cScope; /* we may have a non public function and a object message */
pFunc = FunctionNew( szFunName, cScope );
pFunc->bFlags |= iType;
if( hb_comp_functions.iCount == 0 )
{
hb_comp_functions.pFirst = pFunc;
hb_comp_functions.pLast = pFunc;
}
else
{
hb_comp_functions.pLast->pNext = pFunc;
hb_comp_functions.pLast = pFunc;
}
hb_comp_functions.iCount++;
hb_comp_ulLastLinePos = 0; /* optimization of line numbers opcode generation */
hb_compGenPCode3( HB_P_FRAME, 0, 0 ); /* frame for locals and parameters */
hb_compGenPCode3( HB_P_SFRAME, 0, 0 ); /* frame for statics variables */
if( hb_comp_bDebugInfo )
{
hb_compGenPCode1( HB_P_MODULENAME );
hb_compGenPCodeN( ( BYTE * )hb_comp_files.pLast->szFileName, strlen( hb_comp_files.pLast->szFileName ) );
hb_compGenPCode1( ':' );
hb_compGenPCodeN( ( BYTE * )szFunName, strlen( szFunName ) );
hb_compGenPCode1( 0 );
}
}
void hb_compGenPushFunRef( char * szName )
{
HB_SYMBOL_UNUSED( szName ); /* TODO: */
}
void * GenElseIf( void * pFirst, ULONG ulOffset )
{
PELSEIF pElseIf = ( PELSEIF ) hb_xgrab( sizeof( _ELSEIF ) ), pLast;
pElseIf->ulOffset = ulOffset;
pElseIf->pNext = 0;
if( ! pFirst )
pFirst = pElseIf;
else
{
pLast = ( PELSEIF ) pFirst;
while( pLast->pNext )
pLast = pLast->pNext;
pLast->pNext = pElseIf;
}
return pFirst;
}
PFUNCTION KillFunction( PFUNCTION pFunc )
{
PFUNCTION pNext = pFunc->pNext;
PVAR pVar;
while( pFunc->pLocals )
{
pVar = pFunc->pLocals;
pFunc->pLocals = pVar->pNext;
hb_xfree( ( void * ) pVar->szName );
hb_xfree( ( void * ) pVar );
}
while( pFunc->pStatics )
{
pVar = pFunc->pStatics;
pFunc->pStatics = pVar->pNext;
hb_xfree( ( void * ) pVar->szName );
hb_xfree( ( void * ) pVar );
}
while( pFunc->pFields )
{
pVar = pFunc->pFields;
pFunc->pFields = pVar->pNext;
hb_xfree( ( void * ) pVar->szName );
if( pVar->szAlias )
{
hb_xfree( ( void * ) pVar->szAlias );
}
hb_xfree( ( void * ) pVar );
}
while( pFunc->pMemvars )
{
pVar = pFunc->pMemvars;
pFunc->pMemvars = pVar->pNext;
hb_xfree( ( void * ) pVar->szName );
if( pVar->szAlias )
{
hb_xfree( ( void * ) pVar->szAlias );
}
hb_xfree( ( void * ) pVar );
}
hb_xfree( ( void * ) pFunc->pCode );
/* hb_xfree( ( void * ) pFunc->szName ); The name will be released in KillSymbol() */
hb_xfree( ( void * ) pFunc );
return pNext;
}
PCOMSYMBOL KillSymbol( PCOMSYMBOL pSym )
{
PCOMSYMBOL pNext = pSym->pNext;
hb_xfree( ( void * ) pSym->szName );
hb_xfree( ( void * ) pSym );
return pNext;
}
void hb_compGenBreak( void )
{
hb_compPushSymbol( yy_strdup("BREAK"), 1 );
hb_compGenPushNil();
}
void hb_compGenExterns( void ) /* generates the symbols for the EXTERN names */
{
PEXTERN pDelete;
if( hb_comp_bDebugInfo )
hb_compAddExtern( yy_strdup( "__DBGENTRY" ) );
while( hb_comp_pExterns )
{
if( hb_compGetSymbol( hb_comp_pExterns->szName, NULL ) )
{
if( ! GetFuncall( hb_comp_pExterns->szName ) )
hb_compAddFunCall( hb_comp_pExterns->szName );
}
else
{
hb_compAddSymbol( hb_comp_pExterns->szName, NULL );
hb_compAddFunCall( hb_comp_pExterns->szName );
}
pDelete = hb_comp_pExterns;
hb_comp_pExterns = hb_comp_pExterns->pNext;
hb_xfree( ( void * ) pDelete );
}
}
/* This function generates pcodes for IIF( expr1, expr2, expr3 )
* or IF( expr1, expr2, expr3 )
*
* NOTE:
* 'IF' followed by parenthesized expression containing 3 expressions
* is always interpreted as IF inlined - it is not possible to distinguish
* it from IF( expr1, expr2, expr3 ); ENDIF syntax
* (This behaviour is Clipper compatible)
*/
void GenIfInline( void )
{
EXPLIST_PTR pExp, pDel;
int iExpCount = 3; /* We are expecting 3 expressions here */
BOOL bhb_compGenPCode;
/* save currently used pcode buffer */
hb_comp_pExprList->exprSize = hb_comp_functions.pLast->lPCodePos;
hb_comp_pExprList->exprPCode = hb_comp_functions.pLast->pCode;
/* find the first expression in the list */
while( --iExpCount )
hb_comp_pExprList = hb_comp_pExprList->pPrev;
/* return to the original pcode buffer */
hb_comp_functions.pLast->pCode = hb_comp_pExprList->prevPCode;
hb_comp_functions.pLast->lPCodeSize = hb_comp_pExprList->prevSize;
hb_comp_functions.pLast->lPCodePos = hb_comp_pExprList->prevPos;
/* Update the pointer for nested or next expressions */
pExp = hb_comp_pExprList;
if( hb_comp_pExprList->pPrev )
{
hb_comp_pExprList = hb_comp_pExprList->pPrev;
hb_comp_pExprList->pNext = NULL;
}
else
hb_comp_pExprList = NULL;
bhb_compGenPCode = TRUE;
pDel = pExp; /* save it for later use */
/* pExp points now to pcode buffer for logical condition
*/
if( pExp->exprSize == 0 )
{
/* The logical condition have to be specified.
* If it is empty then generate the syntax error
*/
hb_compGenError( hb_comp_szCErrors, 'E', ERR_SYNTAX, ",", NULL );
}
else if( pExp->exprSize == 1 )
{
/* one byte opcode for logical condition - check if it is TRUE or FALSE
*/
if( pExp->exprPCode[ 0 ] == HB_P_TRUE )
{
/* move to the second expression */
pExp = pExp->pNext;
if( pExp->exprSize )
hb_compGenPCodeN( pExp->exprPCode, pExp->exprSize );
else
hb_compGenPushNil(); /* IIF have to return some value */
bhb_compGenPCode = FALSE;
}
else if( pExp->exprPCode[ 0 ] == HB_P_FALSE )
{
/* move to the third expression */
pExp = pExp->pNext;
pExp = pExp->pNext;
if( pExp->exprSize )
hb_compGenPCodeN( pExp->exprPCode, pExp->exprSize );
else
hb_compGenPushNil(); /* IIF have to return some value */
bhb_compGenPCode = FALSE;
}
}
if( bhb_compGenPCode )
{
/* generate pcodes for all expressions
*/
LONG lPosFalse, lPosEnd;
hb_compGenPCodeN( pExp->exprPCode, pExp->exprSize );
lPosFalse = hb_compGenJumpFalse( 0 );
pExp = pExp->pNext;
if( pExp->exprSize )
hb_compGenPCodeN( pExp->exprPCode, pExp->exprSize );
else
hb_compGenPushNil(); /* IIF have to return some value */
lPosEnd = hb_compGenJump( 0 );
hb_compGenJumpHere( lPosFalse );
pExp = pExp->pNext;
if( pExp->exprSize )
hb_compGenPCodeN( pExp->exprPCode, pExp->exprSize );
else
hb_compGenPushNil(); /* IIF have to return some value */
hb_compGenJumpHere( lPosEnd );
}
while( pDel )
{
pExp = pDel;
pDel = pDel->pNext;
hb_xfree( pExp->exprPCode );
hb_xfree( pExp );
}
}
PFUNCTION GetFuncall( char * szFunctionName ) /* returns a previously called defined function */
{
PFUNCTION pFunc = hb_comp_funcalls.pFirst;
while( pFunc )
{
if( ! strcmp( pFunc->szName, szFunctionName ) )
return pFunc;
else
{
if( pFunc->pNext )
pFunc = pFunc->pNext;
else
return NULL;
}
}
return NULL;
}
PFUNCTION GetFunction( char * szFunctionName ) /* returns a previously defined function */
{
PFUNCTION pFunc = hb_comp_functions.pFirst;
while( pFunc )
{
if( ! strcmp( pFunc->szName, szFunctionName ) )
return pFunc;
else
{
if( pFunc->pNext )
pFunc = pFunc->pNext;
else
return NULL;
}
}
return NULL;
}
PVAR GetVar( PVAR pVars, USHORT wOrder ) /* returns variable if defined or zero */
{
USHORT w = 1;
while( pVars->pNext && w++ < wOrder )
pVars = pVars->pNext;
return pVars;
}
USHORT GetVarPos( PVAR pVars, char * szVarName ) /* returns the order + 1 of a variable if defined or zero */
{
USHORT wVar = 1;
while( pVars )
{
if( pVars->szName && ! strcmp( pVars->szName, szVarName ) )
{
/* TODO: This is not the best place to push the variable type
* in some cases it will be called two times for the same variable
*/
pVars->iUsed = 1;
return wVar;
}
else
{
if( pVars->pNext )
{
pVars = pVars->pNext;
wVar++;
}
else
return 0;
}
}
return 0;
}
int GetLocalVarPos( char * szVarName ) /* returns the order + 1 of a variable if defined or zero */
{
int iVar = 0;
PFUNCTION pFunc = hb_comp_functions.pLast;
if( pFunc->szName )
/* we are in a function/procedure -we don't need any tricks */
return GetVarPos( pFunc->pLocals, szVarName );
else
{
/* we are in a codeblock */
iVar = GetVarPos( pFunc->pLocals, szVarName );
if( iVar == 0 )
{
/* this is not a current codeblock parameter
* we have to check the list of nested codeblocks up to a function
* where the codeblock is defined
*/
PFUNCTION pOutBlock = pFunc; /* the outermost codeblock */
pFunc = pFunc->pOwner;
while( pFunc )
{
iVar = GetVarPos( pFunc->pLocals, szVarName );
if( iVar )
{
if( pFunc->pOwner )
{
/* this variable is defined in a parent codeblock
* It is not possible to access a parameter of a codeblock in which
* the current codeblock is defined
*/
hb_compGenError( hb_comp_szCErrors, 'E', ERR_OUTER_VAR, szVarName, NULL );
}
else
{
/* We want to access a local variable defined in a function
* that owns this codeblock. We cannot access this variable in
* a normal way because at runtime the stack base will point
* to local variables of EVAL function.
* The codeblock cannot have static variables then we can
* use this structure to store temporarily all referenced
* local variables
*/
/* NOTE: The list of local variables defined in a function
* and referenced in a codeblock will be stored in a outer
* codeblock only. This makes sure that all variables will be
* detached properly - the inner codeblock can be created
* outside of a function where it was defined when the local
* variables are not accessible.
*/
iVar = -GetVarPos( pOutBlock->pStatics, szVarName );
if( iVar == 0 )
{
/* this variable was not referenced yet - add it to the list */
PVAR pVar;
pVar = ( PVAR ) hb_xgrab( sizeof( VAR ) );
pVar->szName = szVarName;
pVar->cType = ' ';
pVar->iUsed = 0;
pVar->pNext = NULL;
/* Use negative order to signal that we are accessing a local
* variable from a codeblock
*/
iVar = -1; /* first variable */
if( ! pOutBlock->pStatics )
pOutBlock->pStatics = pVar;
else
{
PVAR pLastVar = pOutBlock->pStatics;
--iVar; /* this will be at least second variable */
while( pLastVar->pNext )
{
pLastVar = pLastVar->pNext;
--iVar;
}
pLastVar->pNext = pVar;
}
}
return iVar;
}
}
pOutBlock = pFunc;
pFunc = pFunc->pOwner;
}
}
}
return iVar;
}
/*
* Gets position of passed static variables.
* All static variables are hold in a single array at runtime then positions
* are numbered for whole PRG module.
*/
int GetStaticVarPos( char * szVarName )
{
int iPos;
PFUNCTION pFunc = hb_comp_functions.pLast;
/* First we have to check if this name belongs to a static variable
* defined in current function
*/
if( pFunc->pOwner )
pFunc = pFunc->pOwner; /* we are in the static variable definition state */
iPos = GetVarPos( pFunc->pStatics, szVarName );
if( iPos )
return iPos + pFunc->iStaticsBase;
/* Next we have to check the list of global static variables
* Note: It is not possible to have global static variables when
* implicit starting procedure is defined
*/
if( !hb_comp_bStartProc )
{
iPos = GetVarPos( hb_comp_functions.pFirst->pStatics, szVarName );
if( iPos )
return iPos;
}
return 0;
}
/* Checks if passed variable name is declared as FIELD
* Returns 0 if not found in FIELD list or its position in this list if found
*/
int GetFieldVarPos( char * szVarName, PFUNCTION pFunc )
{
int iVar;
if( pFunc->szName )
/* we are in a function/procedure -we don't need any tricks */
iVar = GetVarPos( pFunc->pFields, szVarName );
else
{
/* we have to check the list of nested codeblock up to a function
* where the codeblock is defined
*/
while( pFunc->pOwner )
pFunc = pFunc->pOwner;
iVar = GetVarPos( pFunc->pFields, szVarName );
}
return iVar;
}
/* Checks if passed variable name is declared as MEMVAR
* Returns 0 if not found in MEMVAR list or its position in this list if found
*/
int GetMemvarPos( char * szVarName, PFUNCTION pFunc )
{
int iVar;
if( pFunc->szName )
/* we are in a function/procedure -we don't need any tricks */
iVar = GetVarPos( pFunc->pMemvars, szVarName );
else
{
/* we have to check the list of nested codeblock up to a function
* where the codeblock is defined
*/
while( pFunc->pOwner )
pFunc = pFunc->pOwner;
iVar = GetVarPos( pFunc->pMemvars, szVarName );
}
return iVar;
}
USHORT FixSymbolPos( USHORT wCompilePos )
{
return ( hb_comp_bStartProc ? wCompilePos - 1 : wCompilePos - 2 );
}
/* returns a symbol pointer from the symbol table
* and sets its position in the symbol table
*/
PCOMSYMBOL hb_compGetSymbol( char * szSymbolName, USHORT * pwPos )
{
PCOMSYMBOL pSym = hb_comp_symbols.pFirst;
USHORT wCnt = 1;
if( pwPos )
*pwPos = 0;
while( pSym )
{
if( ! strcmp( pSym->szName, szSymbolName ) )
{
if( pwPos )
*pwPos = wCnt;
return pSym;
}
else
{
if( pSym->pNext )
{
pSym = pSym->pNext;
++wCnt;
}
else
return NULL;
}
}
return NULL;
}
PCOMSYMBOL hb_compGetSymbolOrd( USHORT wSymbol ) /* returns a symbol based on its index on the symbol table */
{
PCOMSYMBOL pSym = hb_comp_symbols.pFirst;
USHORT w = 1;
while( w++ < wSymbol && pSym->pNext )
pSym = pSym->pNext;
return pSym;
}
USHORT GetFunctionPos( char * szFunctionName ) /* return 0 if not found or order + 1 */
{
PFUNCTION pFunc = hb_comp_functions.pFirst;
USHORT wFunction = hb_comp_bStartProc;
while( pFunc )
{
if( ! strcmp( pFunc->szName, szFunctionName ) && pFunc != hb_comp_functions.pFirst )
return wFunction;
else
{
if( pFunc->pNext )
{
pFunc = pFunc->pNext;
wFunction++;
}
else
return 0;
}
}
return 0;
}
void Inc( void )
{
hb_compGenPCode1( HB_P_INC );
}
ULONG hb_compGenJump( LONG lOffset )
{
/* TODO: We need a longer offset (longer then two bytes)
*/
if( lOffset < ( LONG ) SHRT_MIN || lOffset > ( LONG ) SHRT_MAX )
hb_compGenError( hb_comp_szCErrors, 'E', ERR_JUMP_TOO_LONG, NULL, NULL );
hb_compGenPCode3( HB_P_JUMP, HB_LOBYTE( lOffset ), HB_HIBYTE( lOffset ) );
return hb_comp_functions.pLast->lPCodePos - 2;
}
ULONG hb_compGenJumpFalse( LONG lOffset )
{
/* TODO: We need a longer offset (longer then two bytes)
*/
if( lOffset < ( LONG ) SHRT_MIN || lOffset > ( LONG ) SHRT_MAX )
hb_compGenError( hb_comp_szCErrors, 'E', ERR_JUMP_TOO_LONG, NULL, NULL );
hb_compGenPCode3( HB_P_JUMPFALSE, HB_LOBYTE( lOffset ), HB_HIBYTE( lOffset ) );
return hb_comp_functions.pLast->lPCodePos - 2;
}
void hb_compGenJumpThere( ULONG ulFrom, ULONG ulTo )
{
BYTE * pCode = hb_comp_functions.pLast->pCode;
LONG lOffset = ulTo - ulFrom + 1;
/* TODO: We need a longer offset (longer then two bytes)
*/
if( lOffset < ( LONG ) SHRT_MIN || lOffset > ( LONG ) SHRT_MAX )
hb_compGenError( hb_comp_szCErrors, 'E', ERR_JUMP_TOO_LONG, NULL, NULL );
pCode[ ( ULONG ) ulFrom ] = HB_LOBYTE( lOffset );
pCode[ ( ULONG ) ulFrom + 1 ] = HB_HIBYTE( lOffset );
}
void hb_compGenJumpHere( ULONG ulOffset )
{
hb_compGenJumpThere( ulOffset, hb_comp_functions.pLast->lPCodePos );
}
ULONG hb_compGenJumpTrue( LONG lOffset )
{
/* TODO: We need a longer offset (longer then two bytes)
*/
if( lOffset < ( LONG ) SHRT_MIN || lOffset > ( LONG ) SHRT_MAX )
hb_compGenError( hb_comp_szCErrors, 'E', ERR_JUMP_TOO_LONG, NULL, NULL );
hb_compGenPCode3( HB_P_JUMPTRUE, HB_LOBYTE( lOffset ), HB_HIBYTE( lOffset ) );
return hb_comp_functions.pLast->lPCodePos - 2;
}
void Line( void ) /* generates the pcode with the currently compiled source code line */
{
if( hb_comp_bLineNumbers && ! hb_comp_bDontGenLineNum )
{
if( ( ( hb_comp_functions.pLast->lPCodePos - hb_comp_ulLastLinePos ) > 3 ) || hb_comp_bDebugInfo )
{
hb_comp_ulLastLinePos = hb_comp_functions.pLast->lPCodePos;
hb_compGenPCode3( HB_P_LINE, HB_LOBYTE( iLine ), HB_HIBYTE( iLine ) );
}
else
{
hb_comp_functions.pLast->pCode[ hb_comp_ulLastLinePos +1 ] = HB_LOBYTE( iLine );
hb_comp_functions.pLast->pCode[ hb_comp_ulLastLinePos +2 ] = HB_HIBYTE( iLine );
}
}
hb_comp_bDontGenLineNum = FALSE;
hb_comp_functions.pLast->bFlags &= ~ FUN_WITH_RETURN; /* clear RETURN flag */
hb_comp_lLastPushPos = -1;
}
/* Generates the pcode with the currently compiled source code line
* if debug code was requested only
*/
void LineDebug( void )
{
if( hb_comp_bDebugInfo )
Line();
else
hb_comp_functions.pLast->bFlags &= ~ FUN_WITH_RETURN; /* clear RETURN flag */
}
void LineBody( void ) /* generates the pcode with the currently compiled source code line */
{
/* This line can be placed inside a procedure or function only */
/* except EXTERNAL */
if( ! hb_comp_bExternal )
{
hb_comp_bExternal = FALSE;
if( ! hb_comp_bStartProc && hb_comp_functions.iCount <= 1 )
{
hb_compGenError( hb_comp_szCErrors, 'E', ERR_OUTSIDE, NULL, NULL );
}
}
hb_comp_functions.pLast->bFlags |= FUN_STATEMENTS;
Line();
}
/*
* Function generates passed pcode for passed variable name
*/
void VariablePCode( BYTE bPCode, char * szVarName )
{
USHORT wVar;
PCOMSYMBOL pSym;
PFUNCTION pOwnerFunc = NULL;
int iType = VS_LOCAL; /* not really */
/* Check if it is a FIELD declared in current function
*/
wVar = GetFieldVarPos( szVarName, hb_comp_functions.pLast );
if( wVar == 0 )
{
/* Check if it is a MEMVAR declared in current function
*/
wVar = GetMemvarPos( szVarName, hb_comp_functions.pLast );
if( wVar )
iType = VS_MEMVAR;
}
else
{
iType = VS_FIELD;
pOwnerFunc = hb_comp_functions.pLast;
}
/* if it is not declared in current function then check if it is
* a symbol with file wide scope
*/
if( wVar == 0 && ! hb_comp_bStartProc )
{
wVar = GetFieldVarPos( szVarName, hb_comp_functions.pFirst );
if( wVar == 0 )
{
wVar = GetMemvarPos( szVarName, hb_comp_functions.pFirst );
if( wVar )
iType = VS_MEMVAR;
}
else
{
iType = VS_FIELD;
pOwnerFunc = hb_comp_functions.pFirst;
}
}
if( wVar == 0 )
{
/* This is undeclared variable */
/*
* NOTE:
* Clipper always assumes a memvar variable if undeclared variable
* is popped (a value is asssigned to a variable).
*
*/
#if defined( HARBOUR_STRICT_CLIPPER_COMPATIBILITY )
if( hb_comp_bForceMemvars || bPCode == HB_P_POPVARIABLE )
#else
if( hb_comp_bForceMemvars )
#endif
{
/* -v switch was used -> assume it is a memvar variable
*/
iType = VS_MEMVAR;
hb_compGenWarning( hb_comp_szCWarnings, 'W', WARN_MEMVAR_ASSUMED, szVarName, NULL );
}
else
hb_compGenWarning( hb_comp_szCWarnings, 'W', WARN_AMBIGUOUS_VAR, szVarName, NULL );
}
if( iType == VS_FIELD )
{ /* variable is declared using FIELD statement */
PVAR pField = GetVar( pOwnerFunc->pFields, wVar );
if( pField->szAlias )
{ /* the alias was specified in FIELD declaration */
if( bPCode == HB_P_POPVARIABLE )
bPCode = HB_P_POPALIASEDFIELD;
else if( bPCode == HB_P_PUSHVARIABLE )
bPCode = HB_P_PUSHALIASEDFIELD;
else
/* pushing fields by reference is not allowed */
hb_compGenError( hb_comp_szCErrors, 'E', ERR_INVALID_REFER, szVarName, NULL );
/*
* Push alias symbol before the field symbol
*/
hb_compPushSymbol( yy_strdup( pField->szAlias ), 0 );
}
else
{ /* this is unaliased field */
if( bPCode == HB_P_POPVARIABLE )
bPCode = HB_P_POPFIELD;
else if( bPCode == HB_P_PUSHVARIABLE )
bPCode = HB_P_PUSHFIELD;
else if( bPCode == HB_P_PUSHMEMVARREF )
/* pushing fields by reference is not allowed */
hb_compGenError( hb_comp_szCErrors, 'E', ERR_INVALID_REFER, szVarName, NULL );
}
}
else if( iType == VS_MEMVAR )
{
/* variable is declared or assumed MEMVAR */
if( bPCode == HB_P_POPVARIABLE )
bPCode = HB_P_POPMEMVAR;
else if( bPCode == HB_P_PUSHVARIABLE )
bPCode = HB_P_PUSHMEMVAR;
}
/* Check if this variable name is placed into the symbol table
*/
pSym = hb_compGetSymbol( szVarName, &wVar );
if( ! pSym )
pSym = hb_compAddSymbol( szVarName, &wVar );
pSym->cScope |= VS_MEMVAR;
hb_compGenPCode3( bPCode, HB_LOBYTE( wVar ), HB_HIBYTE( wVar ) );
}
/*
* Function generates passed pcode for passed memvar name
*/
void MemvarPCode( BYTE bPCode, char * szVarName )
{
USHORT wVar;
PCOMSYMBOL pSym;
/* Check if this variable name is placed into the symbol table
*/
pSym = hb_compGetSymbol( szVarName, &wVar );
if( ! pSym )
pSym = hb_compAddSymbol( szVarName, &wVar );
pSym->cScope |= VS_MEMVAR;
hb_compGenPCode3( bPCode, HB_LOBYTE( wVar ), HB_HIBYTE( wVar ) );
}
void hb_compGenMessage( char * szMsgName ) /* sends a message to an object */
{
USHORT wSym;
PCOMSYMBOL pSym = hb_compGetSymbol( szMsgName, &wSym );
if( ! pSym ) /* the symbol was not found on the symbol table */
pSym = hb_compAddSymbol( szMsgName, &wSym );
pSym->cScope |= FS_MESSAGE;
hb_compGenPCode3( HB_P_MESSAGE, HB_LOBYTE( wSym ), HB_HIBYTE( wSym ) );
}
void hb_compGenMessageData( char * szMsg ) /* generates an underscore-symbol name for a data assignment */
{
char * szResult = ( char * ) hb_xgrab( strlen( szMsg ) + 2 );
strcpy( szResult, "_" );
strcat( szResult, szMsg );
hb_compGenMessage( szResult );
}
void hb_compGenPopVar( char * szVarName ) /* generates the pcode to pop a value from the virtual machine stack onto a variable */
{
int iVar;
if( hb_comp_pAliasId == NULL )
{
iVar = GetLocalVarPos( szVarName );
if( iVar )
hb_compGenPCode3( HB_P_POPLOCAL, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ) );
else
{
iVar = GetStaticVarPos( szVarName );
if( iVar )
{
hb_compGenPCode3( HB_P_POPSTATIC, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ) );
hb_comp_functions.pLast->bFlags |= FUN_USES_STATICS;
}
else
{
VariablePCode( HB_P_POPVARIABLE, szVarName );
}
}
}
else
{
if( hb_comp_pAliasId->type == ALIAS_NAME )
{
if( hb_comp_pAliasId->alias.szAlias[ 0 ] == 'M' && hb_comp_pAliasId->alias.szAlias[ 1 ] == '\0' )
{ /* M->variable */
MemvarPCode( HB_P_POPMEMVAR, szVarName );
}
else
{
int iCmp = strncmp( hb_comp_pAliasId->alias.szAlias, "MEMVAR", 4 );
if( iCmp == 0 )
iCmp = strncmp( hb_comp_pAliasId->alias.szAlias, "MEMVAR", strlen( hb_comp_pAliasId->alias.szAlias ) );
if( iCmp == 0 )
{ /* MEMVAR-> or MEMVA-> or MEMV-> */
MemvarPCode( HB_P_POPMEMVAR, szVarName );
}
else
{ /* field variable */
iCmp = strncmp( hb_comp_pAliasId->alias.szAlias, "FIELD", 4 );
if( iCmp == 0 )
iCmp = strncmp( hb_comp_pAliasId->alias.szAlias, "FIELD", strlen( hb_comp_pAliasId->alias.szAlias ) );
if( iCmp == 0 )
{ /* FIELD-> */
FieldPCode( HB_P_POPFIELD, szVarName );
}
else
{ /* database alias */
hb_compPushSymbol( yy_strdup( hb_comp_pAliasId->alias.szAlias ), 0 );
FieldPCode( HB_P_POPALIASEDFIELD, szVarName );
}
}
}
}
else if( hb_comp_pAliasId->type == ALIAS_NUMBER )
{
hb_compGenPushInteger( hb_comp_pAliasId->alias.iAlias );
FieldPCode( HB_P_POPALIASEDFIELD, szVarName );
}
else
/* Alias is already placed on stack */
FieldPCode( HB_P_POPALIASEDFIELD, szVarName );
}
}
void hb_compGenPushVar( char * szVarName ) /* generates the pcode to push a variable value to the virtual machine stack */
{
int iVar;
if( hb_comp_pAliasId == NULL )
{
iVar = GetLocalVarPos( szVarName );
if( iVar )
hb_compGenPCode3( HB_P_PUSHLOCAL, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ) );
else
{
iVar = GetStaticVarPos( szVarName );
if( iVar )
{
hb_compGenPCode3( HB_P_PUSHSTATIC, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ) );
hb_comp_functions.pLast->bFlags |= FUN_USES_STATICS;
}
else
{
VariablePCode( HB_P_PUSHVARIABLE, szVarName );
}
}
}
else
{
if( hb_comp_pAliasId->type == ALIAS_NAME )
{
if( hb_comp_pAliasId->alias.szAlias[ 0 ] == 'M' && hb_comp_pAliasId->alias.szAlias[ 1 ] == '\0' )
{ /* M->variable */
MemvarPCode( HB_P_PUSHMEMVAR, szVarName );
}
else
{
int iCmp = strncmp( hb_comp_pAliasId->alias.szAlias, "MEMVAR", 4 );
if( iCmp == 0 )
iCmp = strncmp( hb_comp_pAliasId->alias.szAlias, "MEMVAR", strlen( hb_comp_pAliasId->alias.szAlias ) );
if( iCmp == 0 )
{ /* MEMVAR-> or MEMVA-> or MEMV-> */
MemvarPCode( HB_P_PUSHMEMVAR, szVarName );
}
else
{ /* field variable */
iCmp = strncmp( hb_comp_pAliasId->alias.szAlias, "FIELD", 4 );
if( iCmp == 0 )
iCmp = strncmp( hb_comp_pAliasId->alias.szAlias, "FIELD", strlen( hb_comp_pAliasId->alias.szAlias ) );
if( iCmp == 0 )
{ /* FIELD-> */
FieldPCode( HB_P_PUSHFIELD, szVarName );
}
else
{ /* database alias */
hb_compPushSymbol( yy_strdup( hb_comp_pAliasId->alias.szAlias ), 0 );
FieldPCode( HB_P_PUSHALIASEDFIELD, szVarName );
}
}
}
}
else if( hb_comp_pAliasId->type == ALIAS_NUMBER )
{
hb_compGenPushInteger( hb_comp_pAliasId->alias.iAlias );
FieldPCode( HB_P_PUSHALIASEDFIELD, szVarName );
}
else
/* Alias is already placed on stack */
FieldPCode( HB_P_PUSHALIASEDFIELD, szVarName );
}
}
void hb_compGenPushVarRef( char * szVarName ) /* generates the pcode to push a variable by reference to the virtual machine stack */
{
USHORT iVar;
iVar = GetLocalVarPos( szVarName );
if( iVar )
hb_compGenPCode3( HB_P_PUSHLOCALREF, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ) );
else
{
iVar = GetStaticVarPos( szVarName );
if( iVar )
{
hb_compGenPCode3( HB_P_PUSHSTATICREF, HB_LOBYTE( iVar ), HB_HIBYTE( iVar ) );
hb_comp_functions.pLast->bFlags |= FUN_USES_STATICS;
}
else
{
/* if undeclared variable is passed by reference then a memvar
* variable is assumed because fields cannot be passed by
* a reference
*/
VariablePCode( HB_P_PUSHMEMVARREF, szVarName );
}
}
}
void hb_compGenPushLogical( int iTrueFalse ) /* pushes a logical value on the virtual machine stack */
{
if( iTrueFalse )
hb_compGenPCode1( HB_P_TRUE );
else
hb_compGenPCode1( HB_P_FALSE );
}
void hb_compGenPushNil( void )
{
hb_compGenPCode1( HB_P_PUSHNIL );
}
/* generates the pcode to push a double number on the virtual machine stack */
void hb_compGenPushDouble( double dNumber, BYTE bDec )
{
hb_compGenPCode1( HB_P_PUSHDOUBLE );
hb_compGenPCodeN( ( BYTE * ) &dNumber, sizeof( double ) );
hb_compGenPCode1( bDec );
}
void hb_compGenPushFunCall( char * szFunName )
{
char * szFunction;
szFunction = RESERVED_FUNC( szFunName );
if( szFunction )
{
/* Abbreviated function name was used - change it for whole name
*/
hb_compPushSymbol( yy_strdup( szFunction ), 1 );
}
else
hb_compPushSymbol( szFunName, 1 );
}
/* generates the pcode to push a integer number on the virtual machine stack */
void hb_compGenPushInteger( int iNumber )
{
if( iNumber )
hb_compGenPCode3( HB_P_PUSHINT, HB_LOBYTE( ( USHORT ) iNumber ), HB_HIBYTE( ( USHORT ) iNumber ) );
else
hb_compGenPCode1( HB_P_ZERO );
}
/* generates the pcode to push a long number on the virtual machine stack */
void hb_compGenPushLong( long lNumber )
{
if( lNumber )
{
hb_compGenPCode1( HB_P_PUSHLONG );
hb_compGenPCode1( ( ( char * ) &lNumber )[ 0 ] );
hb_compGenPCode1( ( ( char * ) &lNumber )[ 1 ] );
hb_compGenPCode1( ( ( char * ) &lNumber )[ 2 ] );
hb_compGenPCode1( ( ( char * ) &lNumber )[ 3 ] );
}
else
hb_compGenPCode1( HB_P_ZERO );
}
/* generates the pcode to push a string on the virtual machine stack */
void hb_compGenPushString( char * szText, ULONG ulStrLen )
{
hb_compGenPCode3( HB_P_PUSHSTR, HB_LOBYTE( ulStrLen ), HB_HIBYTE( ulStrLen ) );
hb_compGenPCodeN( ( BYTE * ) szText, ulStrLen );
}
/* generates the pcode to push a symbol on the virtual machine stack */
void hb_compPushSymbol( char * szSymbolName, int iIsFunction )
{
USHORT wSym;
PCOMSYMBOL pSym;
if( iIsFunction )
{
char * pName = RESERVED_FUNC( szSymbolName );
/* If it is reserved function name then we should truncate
* the requested name.
* We have to use passed szSymbolName so we can latter deallocate it
* (pName points to static data)
*/
if( pName )
szSymbolName[ strlen( pName ) ] ='\0';
}
pSym = hb_compGetSymbol( szSymbolName, &wSym );
if( ! pSym ) /* the symbol was not found on the symbol table */
{
pSym = hb_compAddSymbol( szSymbolName, &wSym );
if( iIsFunction )
hb_compAddFunCall( szSymbolName );
}
else
{
if( iIsFunction && ! GetFuncall( szSymbolName ) )
hb_compAddFunCall( szSymbolName );
}
hb_compGenPCode3( HB_P_PUSHSYM, HB_LOBYTE( wSym ), HB_HIBYTE( wSym ) );
}
void CheckDuplVars( PVAR pVar, char * szVarName, int iVarScope )
{
while( pVar )
{
if( ! strcmp( pVar->szName, szVarName ) )
{
if( ! ( iVarScope & VS_PARAMETER ) )
--iLine;
hb_compErrorDuplVar( szVarName );
}
else
pVar = pVar->pNext;
}
}
void Dec( void )
{
hb_compGenPCode1( HB_P_DEC );
}
void hb_compGenDoProc( BYTE bParams )
{
hb_compGenPCode3( HB_P_DO, bParams, 0 );
}
void FixElseIfs( void * pFixElseIfs )
{
PELSEIF pFix = ( PELSEIF ) pFixElseIfs;
while( pFix )
{
hb_compGenJumpHere( pFix->ulOffset );
pFix = pFix->pNext;
}
}
void FixReturns( void ) /* fixes all last defined function returns jumps offsets */
{
if( hb_comp_iWarnings && hb_comp_functions.pLast )
{
PVAR pVar;
pVar = hb_comp_functions.pLast->pLocals;
while( pVar )
{
if( pVar->szName && hb_comp_functions.pLast->szName && hb_comp_functions.pLast->szName[0] && ! pVar->iUsed )
hb_compGenWarning( hb_comp_szCWarnings, 'W', WARN_VAR_NOT_USED, pVar->szName, hb_comp_functions.pLast->szName );
pVar = pVar->pNext;
}
pVar = hb_comp_functions.pLast->pStatics;
while( pVar )
{
if( pVar->szName && hb_comp_functions.pLast->szName && hb_comp_functions.pLast->szName[0] && ! pVar->iUsed )
hb_compGenWarning( hb_comp_szCWarnings, 'W', WARN_VAR_NOT_USED, pVar->szName, hb_comp_functions.pLast->szName );
pVar = pVar->pNext;
}
/* Check if the function returned some value
*/
if( (hb_comp_functions.pLast->bFlags & FUN_WITH_RETURN) == 0 &&
(hb_comp_functions.pLast->bFlags & FUN_PROCEDURE) == 0 )
hb_compGenWarning( hb_comp_szCWarnings, 'W', WARN_FUN_WITH_NO_RETURN,
hb_comp_functions.pLast->szName, NULL );
}
/* TODO: check why it triggers this error in keywords.prg
if( hb_comp_pLoops )
{
PTR_LOOPEXIT pLoop = hb_comp_pLoops;
char cLine[ 64 ];
while( pLoop->pNext )
pLoop = pLoop->pNext;
itoa( pLoop->iLine, cLine, 10 );
hb_compGenError( hb_comp_szCErrors, 'E', ERR_UNCLOSED_STRU, cLine, NULL );
}
*/
}
void Function( BYTE bParams )
{
hb_compGenPCode3( HB_P_FUNCTION, bParams, 0 );
}
void hb_compGenArray( int iElements )
{
hb_compGenPCode3( HB_P_ARRAYGEN, HB_LOBYTE( iElements ), HB_HIBYTE( iElements ) );
}
void hb_compGenPCode1( BYTE byte )
{
PFUNCTION pFunc = hb_comp_functions.pLast; /* get the currently defined Clipper function */
if( ! pFunc->pCode ) /* has been created the memory block to hold the pcode ? */
{
pFunc->pCode = ( BYTE * ) hb_xgrab( PCODE_CHUNK );
pFunc->lPCodeSize = PCODE_CHUNK;
pFunc->lPCodePos = 0;
}
else
if( ( pFunc->lPCodeSize - pFunc->lPCodePos ) < 1 )
pFunc->pCode = ( BYTE * ) hb_xrealloc( pFunc->pCode, pFunc->lPCodeSize += PCODE_CHUNK );
pFunc->pCode[ pFunc->lPCodePos++ ] = byte;
}
void hb_compGenPCode3( BYTE byte1, BYTE byte2, BYTE byte3 )
{
PFUNCTION pFunc = hb_comp_functions.pLast; /* get the currently defined Clipper function */
if( ! pFunc->pCode ) /* has been created the memory block to hold the pcode ? */
{
pFunc->pCode = ( BYTE * ) hb_xgrab( PCODE_CHUNK );
pFunc->lPCodeSize = PCODE_CHUNK;
pFunc->lPCodePos = 0;
}
else
if( ( pFunc->lPCodeSize - pFunc->lPCodePos ) < 3 )
pFunc->pCode = ( BYTE * ) hb_xrealloc( pFunc->pCode, pFunc->lPCodeSize += PCODE_CHUNK );
pFunc->pCode[ pFunc->lPCodePos++ ] = byte1;
pFunc->pCode[ pFunc->lPCodePos++ ] = byte2;
pFunc->pCode[ pFunc->lPCodePos++ ] = byte3;
}
void hb_compGenPCodeN( BYTE * pBuffer, ULONG ulSize )
{
PFUNCTION pFunc = hb_comp_functions.pLast; /* get the currently defined Clipper function */
if( ! pFunc->pCode ) /* has been created the memory block to hold the pcode ? */
{
pFunc->lPCodeSize = ( ( ulSize / PCODE_CHUNK ) + 1 ) * PCODE_CHUNK;
pFunc->pCode = ( BYTE * ) hb_xgrab( pFunc->lPCodeSize );
pFunc->lPCodePos = 0;
}
else if( pFunc->lPCodePos + ulSize > pFunc->lPCodeSize )
{
/* not enough free space in pcode buffer - increase it */
pFunc->lPCodeSize += ( ( ( ulSize / PCODE_CHUNK ) + 1 ) * PCODE_CHUNK );
pFunc->pCode = ( BYTE * ) hb_xrealloc( pFunc->pCode, pFunc->lPCodeSize );
}
memcpy( pFunc->pCode + pFunc->lPCodePos, pBuffer, ulSize );
pFunc->lPCodePos += ulSize;
}
/* Generate the opcode to open BEGIN/END sequence
* This code is simmilar to JUMP opcode - the offset will be filled with
* - either the address of HB_P_SEQEND opcode if there is no RECOVER clause
* - or the address of RECOVER code
*/
ULONG SequenceBegin( void )
{
hb_compGenPCode3( HB_P_SEQBEGIN, 0, 0 );
return hb_comp_functions.pLast->lPCodePos - 2;
}
/* Generate the opcode to close BEGIN/END sequence
* This code is simmilar to JUMP opcode - the offset will be filled with
* the address of first line after END SEQUENCE
* This opcode will be executed if recover code was not requested (as the
* last statement in code beetwen BEGIN ... RECOVER) or if BREAK was requested
* and there was no matching RECOVER clause.
*/
ULONG SequenceEnd( void )
{
hb_compGenPCode3( HB_P_SEQEND, 0, 0 );
return hb_comp_functions.pLast->lPCodePos - 2;
}
/* Remove unnecessary opcodes in case there were no executable statements
* beetwen BEGIN and RECOVER sequence
*/
void SequenceFinish( ULONG ulStartPos, int bUsualStmts )
{
if( ! hb_comp_bDebugInfo ) /* only if no debugger info is required */
{
if( ! bUsualStmts )
{
hb_comp_functions.pLast->lPCodePos = ulStartPos - 1; /* remove also HB_P_SEQBEGIN */
hb_comp_ulLastLinePos = ulStartPos - 4;
}
}
}
/* Set the name of an alias for the list of previously declared FIELDs
*
* szAlias -> name of the alias
* iField -> position of the first FIELD name to change
*/
void FieldsSetAlias( char * szAlias, int iField )
{
PVAR pVar;
pVar = hb_comp_functions.pLast->pFields;
while( iField-- && pVar )
pVar = pVar->pNext;
while( pVar )
{
pVar->szAlias = szAlias;
pVar = pVar->pNext;
}
}
/* This functions counts the number of FIELD declaration in a function
* We will required this information in FieldsSetAlias function
*/
int FieldsCount()
{
int iFields = 0;
PVAR pVar = hb_comp_functions.pLast->pFields;
while( pVar )
{
++iFields;
pVar = pVar->pNext;
}
return iFields;
}
/*
* Start of definition of static variable
* We are using here the special function hb_comp_pInitFunc which will store
* pcode needed to initialize all static variables declared in PRG module.
* pOwner member will point to a function where the static variable is
* declared:
* TODO: support for static variables in codeblock
*/
void hb_compStaticDefStart( void )
{
hb_comp_functions.pLast->bFlags |= FUN_USES_STATICS;
if( ! hb_comp_pInitFunc )
{
BYTE pBuffer[ 5 ];
hb_comp_pInitFunc = FunctionNew( yy_strdup("(_INITSTATICS)"), FS_INIT );
hb_comp_pInitFunc->pOwner = hb_comp_functions.pLast;
hb_comp_pInitFunc->bFlags = FUN_USES_STATICS | FUN_PROCEDURE;
hb_comp_pInitFunc->cScope = FS_INIT | FS_EXIT;
hb_comp_functions.pLast = hb_comp_pInitFunc;
pBuffer[ 0 ] = HB_P_STATICS;
pBuffer[ 1 ] = 0;
pBuffer[ 2 ] = 0;
pBuffer[ 3 ] = 1; /* the number of static variables is unknown now */
pBuffer[ 4 ] = 0;
hb_compGenPCodeN( pBuffer, 5 );
hb_compGenPCode3( HB_P_SFRAME, 0, 0 ); /* frame for statics variables */
}
else
{
hb_comp_pInitFunc->pOwner = hb_comp_functions.pLast;
hb_comp_functions.pLast = hb_comp_pInitFunc;
}
}
/*
* End of definition of static variable
* Return to previously pcoded function.
*/
void hb_compStaticDefEnd( void )
{
hb_comp_functions.pLast = hb_comp_pInitFunc->pOwner;
hb_comp_pInitFunc->pOwner = NULL;
++hb_comp_iStaticCnt;
}
/*
* Start a new fake-function that will hold pcodes for a codeblock
*/
void hb_compCodeBlockStart()
{
PFUNCTION pFunc = FunctionNew( NULL, FS_STATIC );
pFunc->pOwner = hb_comp_functions.pLast;
pFunc->iStaticsBase = hb_comp_functions.pLast->iStaticsBase;
hb_comp_functions.pLast = pFunc;
LineDebug();
}
void hb_compCodeBlockEnd( void )
{
PFUNCTION pCodeblock; /* pointer to the current codeblock */
PFUNCTION pFunc; /* pointer to a function that owns a codeblock */
USHORT wSize;
USHORT wLocals = 0; /* number of referenced local variables */
USHORT wPos;
PVAR pVar, pFree;
pCodeblock = hb_comp_functions.pLast;
/* return to pcode buffer of function/codeblock in which the current
* codeblock was defined
*/
hb_comp_functions.pLast = pCodeblock->pOwner;
/* find the function that owns the codeblock */
pFunc = pCodeblock->pOwner;
while( pFunc->pOwner )
pFunc = pFunc->pOwner;
pFunc->bFlags |= ( pCodeblock->bFlags & FUN_USES_STATICS );
/* generate a proper codeblock frame with a codeblock size and with
* a number of expected parameters
*/
/*QUESTION: would be 64kB enough for a codeblock size?
* we are assuming now a USHORT for a size of codeblock
*/
/* Count the number of referenced local variables */
pVar = pCodeblock->pStatics;
while( pVar )
{
pVar = pVar->pNext;
++wLocals;
}
/*NOTE: 8 = HB_P_PUSHBLOCK + USHORT( size ) + USHORT( wParams ) + USHORT( wLocals ) + _ENDBLOCK */
wSize = ( USHORT ) pCodeblock->lPCodePos + 8 + wLocals * 2;
hb_compGenPCode3( HB_P_PUSHBLOCK, HB_LOBYTE( wSize ), HB_HIBYTE( wSize ) );
hb_compGenPCode1( HB_LOBYTE( pCodeblock->wParamCount ) );
hb_compGenPCode1( HB_HIBYTE( pCodeblock->wParamCount ) );
hb_compGenPCode1( HB_LOBYTE( wLocals ) );
hb_compGenPCode1( HB_HIBYTE( wLocals ) );
/* generate the table of referenced local variables */
pVar = pCodeblock->pStatics;
while( wLocals-- )
{
wPos = GetVarPos( pFunc->pLocals, pVar->szName );
hb_compGenPCode1( HB_LOBYTE( wPos ) );
hb_compGenPCode1( HB_HIBYTE( wPos ) );
pFree = pVar;
hb_xfree( ( void * ) pFree->szName );
pVar = pVar->pNext;
hb_xfree( ( void * ) pFree );
}
hb_compGenPCodeN( pCodeblock->pCode, pCodeblock->lPCodePos );
hb_compGenPCode1( HB_P_ENDBLOCK ); /* finish the codeblock */
/* this fake-function is no longer needed */
hb_xfree( ( void * ) pCodeblock->pCode );
pVar = pCodeblock->pLocals;
while( pVar )
{
if( hb_comp_iWarnings && pFunc->szName && pVar->szName && ! pVar->iUsed )
hb_compGenWarning( hb_comp_szCWarnings, 'W', WARN_BLOCKVAR_NOT_USED, pVar->szName, pFunc->szName );
/* free used variables */
pFree = pVar;
hb_xfree( ( void * ) pFree->szName );
pVar = pVar->pNext;
hb_xfree( ( void * ) pFree );
}
hb_xfree( ( void * ) pCodeblock );
}
/* ************************************************************************* */
HB_EXPR_PTR hb_compErrorLValue( HB_EXPR_PTR pExpr )
{
char * szDesc = hb_compExprDescription( pExpr );
hb_compGenError( hb_comp_szCErrors, 'E', ERR_INVALID_LVALUE, szDesc, NULL );
return pExpr;
}
HB_EXPR_PTR hb_compErrorType( HB_EXPR_PTR pExpr )
{
char * szDesc = hb_compExprDescription( pExpr );
hb_compGenError( hb_comp_szCErrors, 'E', ERR_INVALID_TYPE, szDesc, NULL );
return pExpr;
}
HB_EXPR_PTR hb_compErrorIndex( HB_EXPR_PTR pExpr )
{
char * szDesc = hb_compExprDescription( pExpr );
hb_compGenError( hb_comp_szCErrors, 'E', ERR_INVALID_INDEX, szDesc, NULL );
return pExpr;
}
HB_EXPR_PTR hb_compErrorBound( HB_EXPR_PTR pExpr )
{
char * szDesc = hb_compExprDescription( pExpr );
hb_compGenError( hb_comp_szCErrors, 'E', ERR_INVALID_BOUND, szDesc, NULL );
return pExpr;
}
HB_EXPR_PTR hb_compErrorSyntax( HB_EXPR_PTR pExpr )
{
char * szDesc = hb_compExprDescription( pExpr );
hb_compGenError( hb_comp_szCErrors, 'E', ERR_SYNTAX, szDesc, NULL );
return pExpr;
}
HB_EXPR_PTR hb_compErrorAlias( HB_EXPR_PTR pExpr )
{
char * szDesc = hb_compExprDescription( pExpr );
hb_compGenError( hb_comp_szCErrors, 'E', ERR_INVALID_ALIAS, szDesc, NULL );
return pExpr;
}
HB_EXPR_PTR hb_compErrorStatic( char * szVarName, HB_EXPR_PTR pExpr )
{
char * szDesc = hb_compExprDescription( pExpr );
hb_compGenError( hb_comp_szCErrors, 'E', ERR_ILLEGAL_INIT, szVarName, szDesc );
return pExpr;
}
void hb_compErrorDuplVar( char * szVarName )
{
hb_compGenError( hb_comp_szCErrors, 'E', ERR_VAR_DUPL, szVarName, NULL );
}
HB_EXPR_PTR hb_compWarnMeaningless( HB_EXPR_PTR pExpr )
{
char * szDesc = hb_compExprDescription( pExpr );
hb_compGenWarning( hb_comp_szCWarnings, 'W', WARN_MEANINGLESS, szDesc, NULL );
return pExpr;
}