Files
harbour-core/harbour/source/compiler/harbour.y
1999-09-06 23:09:57 +00:00

6019 lines
204 KiB
Plaintext

%{
/*
* $Id$
*/
/*
* Harbour compiler (yacc rules and actions)
* Build 29 summer 1999
* Usage: bison -d -v harbour.y
* You may find Bison at www.harbour.project.org
*
* Copyright(C) 1999 by Antonio Linares.
*
* The generated C output files structure by the function GenCCode()
* is also under this copyright.
*
* 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.
*
* 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.
*
* You can contact me at: alinares@fivetech.com
*
* Partial Copyright (C) 1999 Eddie Runia <eddie@runia.com>
* partial copyright regarding generation portable objects
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h> /* required for allocating and freeing memory */
#include <ctype.h>
#include "extend.h"
#include "pcode.h" /* pcode values */
#include "compiler.h"
#include "hberrors.h"
#include "hbpp.h"
#include "hbver.h"
#define debug_msg( x, z )
extern FILE *yyin; /* currently yacc parsed file */
extern int iLine; /* currently parsed file line number */
/* Following two lines added for preprocessor */
extern int lPpo; /* flag indicating, is ppo output needed */
extern FILE *yyppo; /* output .ppo file */
typedef struct /* #include support */
{
FILE * handle; /* handle of the opened file */
void * pBuffer; /* buffer used by yacc */
char * szFileName; /* name of the file */
void * pPrev; /* pointer to the previous opened file */
void * pNext; /* pointer to the next opened file */
int iLine; /* currently processed line number */
} _FILE, * PFILE; /* structure to hold an opened PRG or CH */
typedef struct
{
PFILE pLast; /* pointer to the last opened file */
int iFiles; /* number of files currently opened */
} FILES; /* structure to control several opened PRGs and CHs */
int Include( char * szFileName, PATHNAMES * pSearchPath ); /* end #include support */
/*
* flags for bFlags member
*/
#define FUN_STATEMENTS 1 /* Function have at least one executable statement */
#define FUN_USES_STATICS 2 /* Function uses static variables */
#define FUN_PROCEDURE 4 /* This is a procedure that shouldn't return value */
#define FUN_ILLEGAL_INIT 8 /* Attempt to initialize static variable with a function call */
#define FUN_USES_LOCAL_PARAMS 16 /* parameters are declared using () */
/* pcode chunks bytes size */
#define PCODE_CHUNK 100
typedef struct __ELSEIF
{
WORD wOffset;
struct __ELSEIF * pNext;
} _ELSEIF, * PELSEIF; /* support structure for else if pcode fixups */
typedef struct _LOOPEXIT
{
WORD wOffset;
WORD wLine;
struct _LOOPEXIT * pLoopList;
struct _LOOPEXIT * pExitList;
struct _LOOPEXIT * pNext;
} LOOPEXIT, * PTR_LOOPEXIT; /* support structure for EXIT and LOOP statements */
static void LoopStart( void );
static void LoopEnd( void );
static void LoopLoop( void );
static void LoopExit( void );
static void LoopHere( void );
typedef struct __EXTERN
{
char * szName;
struct __EXTERN * pNext;
} _EXTERN, * PEXTERN; /* support structure for extern symbols */
/* as they have to be placed on the symbol table later than the first public symbol */
/* Support for aliased expressions
*/
typedef struct _ALIASID
{
char type;
union {
int iAlias;
char * szAlias;
} alias;
struct _ALIASID * pPrev;
} ALIASID, *ALIASID_PTR;
#define ALIAS_NUMBER 1
#define ALIAS_NAME 2
#define ALIAS_EVAL 3
void AliasAddInt( int );
void AliasAddExp( void );
void AliasAddStr( char * );
void AliasPush( void );
void AliasPop( void );
void AliasSwap( void );
void AliasAdd( ALIASID_PTR );
void AliasRemove( void );
/* lex & yacc related prototypes */
void yyerror( char * ); /* parsing error management function */
int yylex( void ); /* main lex token function, called by yyparse() */
int yyparse( void ); /* main yacc parsing function */
#ifdef __cplusplus
extern "C" int yywrap( void );
#else
int yywrap( void ); /* manages the EOF of current processed file */
#endif
/* Following line added for preprocessor */
void Hbpp_init ( void );
#ifdef __cplusplus
typedef struct yy_buffer_state *YY_BUFFER_STATE;
YY_BUFFER_STATE yy_create_buffer( FILE *, int ); /* yacc functions to manage multiple files */
void yy_switch_to_buffer( YY_BUFFER_STATE ); /* yacc functions to manage multiple files */
void yy_delete_buffer( YY_BUFFER_STATE ); /* yacc functions to manage multiple files */
#else
void * yy_create_buffer( FILE *, int ); /* yacc functions to manage multiple files */
void yy_switch_to_buffer( void * ); /* yacc functions to manage multiple files */
void yy_delete_buffer( void * ); /* yacc functions to manage multiple files */
#endif
char * yy_strdup( char * p ); /* this will exit if there is not enough memory */
char *yy_strupr( char * p );
#if 0
static void __yy_memcpy( char * from, char * to, int count ); /* Bison prototype */
#endif
/* production related functions */
PFUNCTION AddFunCall( char * szFuntionName );
void AddExtern( char * szExternName ); /* defines a new extern name */
void AddSearchPath( char *, PATHNAMES * * ); /* add pathname to a search list */
void AddVar( char * szVarName ); /* add a new param, local, static variable to a function definition or a public or private */
PCOMSYMBOL AddSymbol( char *, WORD * );
void CheckDuplVars( PVAR pVars, char * szVarName, int iVarScope ); /*checks for duplicate variables definitions */
void Dec( void ); /* generates the pcode to decrement the latest value on the virtual machine stack */
void DimArray( WORD wDimensions ); /* instructs the virtual machine to build an array with wDimensions */
void Do( BYTE bParams ); /* generates the pcode to execute a Clipper function discarding its result */
void Duplicate( void ); /* duplicates the virtual machine latest stack latest value and places it on the stack */
void DupPCode( WORD wStart ); /* duplicates the current generated pcode from an offset */
void FieldPCode( BYTE , char * ); /* generates the pcode for database field */
void FixElseIfs( void * pIfElseIfs ); /* implements the ElseIfs pcode fixups */
void FixReturns( void ); /* fixes all last defined function returns jumps offsets */
WORD FixSymbolPos( WORD ); /* converts symbol's compile-time position into generation-time position */
void Function( BYTE bParams ); /* generates the pcode to execute a Clipper function pushing its result */
PFUNCTION FunctionNew( char *, char ); /* creates and initialises the _FUNC structure */
void FunDef( char * szFunName, SYMBOLSCOPE cScope, int iType ); /* starts a new Clipper language function definition */
void GenArray( WORD wElements ); /* instructs the virtual machine to build an array and load elemnst from the stack */
void GenBreak( void ); /* generate code for BREAK statement */
void * GenElseIf( void * pFirstElseIf, WORD wOffset ); /* generates a support structure for elseifs pcode fixups */
void GenExterns( void ); /* generates the symbols for the EXTERN names */
PFUNCTION GetFuncall( char * szFunName ); /* locates a previously defined called function */
int GetFieldVarPos( char *, PFUNCTION * ); /* return if passed name is a field variable */
PVAR GetVar( PVAR pVars, WORD wOrder ); /* returns a variable if defined or zero */
WORD GetVarPos( PVAR pVars, char * szVarName ); /* returns the order + 1 of a variable if defined or zero */
int GetLocalVarPos( char * szVarName ); /* returns the order + 1 of a local variable */
PCOMSYMBOL GetSymbol( char *, WORD * ); /* returns a symbol pointer from the symbol table */
PCOMSYMBOL GetSymbolOrd( WORD ); /* returns a symbol based on its index on the symbol table */
void Inc( void ); /* generates the pcode to increment the latest value on the virtual machine stack */
WORD Jump( int iOffset ); /* generates the pcode to jump to a specific offset */
WORD JumpFalse( int iOffset ); /* generates the pcode to jump if false */
void JumpHere( int iOffset ); /* returns the pcode pos where to set a jump offset */
void JumpThere( int iOffset, WORD wTo ); /* sets a jump offset */
WORD JumpTrue( int iOffset ); /* generates the pcode to jump if true */
PFUNCTION KillFunction( PFUNCTION ); /* releases all memory allocated by function and returns the next one */
PCOMSYMBOL KillSymbol( PCOMSYMBOL ); /* releases all memory allocated by symbol and returns the next one */
void Line( void ); /* generates the pcode with the currently compiled source code line */
void LineDebug( void ); /* generates the pcode with the currently compiled source code line */
void LineBody( void ); /* generates the pcode with the currently compiled source code line */
void VariablePCode( BYTE , char * ); /* generates the pcode for memvar variable */
void Message( char * szMsgName ); /* sends a message to an object */
void MessageFix( char * szMsgName ); /* fix a generated message to an object */
void MessageDupl( char * szMsgName ); /* fix a one generated message to an object and duplicate */
void PopId( char * szVarName ); /* generates the pcode to pop a value from the virtual machine stack onto a variable */
void PushDouble( double fNumber, BYTE bDec ); /* Pushes a number on the virtual machine stack */
void PushFunCall( char * ); /* generates the pcode to push function's call */
void PushId( char * szVarName ); /* generates the pcode to push a variable value to the virtual machine stack */
void PushIdByRef( char * szVarName ); /* generates the pcode to push a variable by reference to the virtual machine stack */
void PushInteger( int iNumber ); /* Pushes a integer number on the virtual machine stack */
void PushLogical( int iTrueFalse ); /* pushes a logical value on the virtual machine stack */
void PushLong( long lNumber ); /* Pushes a long number on the virtual machine stack */
void PushNil( void ); /* Pushes nil on the virtual machine stack */
void PushString( char * szText ); /* Pushes a string on the virtual machine stack */
void PushSymbol( char * szSymbolName, int iIsFunction ); /* Pushes a symbol on to the Virtual machine stack */
void GenPCode1( BYTE ); /* generates 1 byte of pcode */
void GenPCode3( BYTE, BYTE, BYTE ); /* generates 3 bytes of pcode */
void GenPCodeN( BYTE * pBuffer, WORD wSize ); /* copy bytes to a pcode buffer */
char * SetData( char * szMsg ); /* generates an underscore-symbol name for a data assignment */
int SequenceBegin( void );
int SequenceEnd( void );
void SequenceFinish( int, int );
/* support for FIELD declaration */
void FieldsSetAlias( char *, int );
int FieldsCount( void );
/* Codeblocks */
void CodeBlockStart( void ); /* starts a codeblock creation */
void CodeBlockEnd( void ); /* end of codeblock creation */
/* Static variables */
void StaticDefStart( void );
void StaticDefEnd( WORD );
void StaticAssign( void ); /* checks if static variable is initialized with function call */
/* output related functions */
void GenCCode( char *, char * ); /* generates the C language output */
void GenJava( char *, char * ); /* generates the Java language output */
void GenPascal( char *, char * ); /* generates the Pascal language output */
void GenRC( char *, char * ); /* generates the RC language output */
void GenPortObj( char *, char * ); /* generates the portable objects */
#ifdef HARBOUR_OBJ_GENERATION
void GenObj32( char *, char * ); /* generates OBJ 32 bits */
#endif
/* argument checking */
void CheckArgs( char *, int );
void PrintUsage( char * );
#define YYDEBUG 1 /* Parser debug information support */
typedef enum
{
LANG_C, /* C language (by default) <file.c> */
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 */
#define VS_LOCAL 1
#define VS_STATIC 2
#define VS_FIELD 4
#define VS_PARAMETER 8
#define VS_PRIVATE 64
#define VS_PUBLIC 128
#define VS_MEMVAR (VS_PUBLIC | VS_PRIVATE)
int iVarScope = VS_LOCAL; /* holds the scope for next variables to be defined */
/* different values for iVarScope */
/* Table with parse errors */
char * _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 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 at line: %i",
"%s statement with no loop in sight",
"Syntax error: \'%s\' in: \'%s\'",
"Incomplete statement: %s",
"Incorrect number of arguments: %s %s",
"Invalid lvalue",
"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",
"%s" /* YACC error messages */
};
/* Table with parse warnings */
char * _szCWarnings[] =
{
"Ambiguous reference: \'%s\'",
"Ambiguous reference, assuming memvar: \'%s\'",
"Variable: \'%s\' declared but not used in function: \'%s\'",
"CodeBlock Parameter: \'%s\' declared but not used in function: \'%s\'",
"Incompatible type in assignment to: \'%s\' expected: \'%s\'",
"Incompatible operand type: \'%s\' expected: \'Logical\'",
"Incompatible operand type: \'%s\' expected: \'Numeric\'",
"Incompatible operand types: \'%s\' and: \'%s\'",
"Suspicious type in assignment to: \'%s\' expected: \'%s\'",
"Suspicious operand type: \'UnKnown\' expected: \'%s\'",
"Suspicious operand type: \'UnKnown\' expected: \'Logical\'",
"Suspicious operand type: \'UnKnown\' expected: \'Numeric\'"
};
/* 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 * )
/* function compares strings upto maximum 4 characters (used in bsearch) */
/* Borland C 3.1 reports error when this forward declaration is used
* int sz_compare4( const void *, const void * );
*
*/
/* 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.
*/
int EXTERNAL_LINKAGE sz_compare4( const void * pLookup, const void * pReserved )
{
int iCmp;
iCmp = strncmp( ( const char * ) pLookup, * ( ( const char * * ) pReserved ), 4 );
if( iCmp == 0 )
iCmp = strncmp( ( const char * ) pLookup, * ( ( const char * * ) pReserved ),
strlen( ( const char * ) pLookup ) );
return iCmp;
}
#define RESERVED_FUNC(szName) \
bsearch( (szName), _szReservedFun, RESERVED_FUNCTIONS, sizeof( char * ), sz_compare4 )
FILES files;
FUNCTIONS functions, funcalls;
PFUNCTION _pInitFunc;
SYMBOLS symbols;
BOOL _bStartProc = TRUE; /* holds if we need to create the starting procedure */
BOOL _bLineNumbers = TRUE; /* holds if we need pcodes with line numbers */
BOOL _bQuiet = FALSE; /* quiet mode */
BOOL _bSyntaxCheckOnly = FALSE; /* syntax check only */
int _iLanguage = LANG_C; /* default Harbour generated output language */
BOOL _bRestrictSymbolLength = FALSE; /* generate 10 chars max symbols length */
BOOL _bShortCuts = TRUE; /* .and. & .or. expressions shortcuts */
BOOL _bWarnings = FALSE; /* enable parse warnings */
BOOL _bAutoMemvarAssume = FALSE; /* holds if undeclared variables are automatically assumed MEMVAR */
BOOL _bForceMemvars = FALSE; /* holds if memvars are assumed when accesing undeclared variable */
BOOL _bDebugInfo = FALSE; /* holds if generate debugger required info */
/* This variable is used to flag if variables have to be passed by reference
* - it is required in DO <proc> WITH <params> statement
* For example:
* DO proces WITH aVar, bVar:=cVar
* aVar - have to be passed by reference
* bVar and cBar - have to be passed by value
*/
BOOL _bForceByRefer = FALSE;
/* This variable is true if the right value of assignment will be build.
* It is used to temporarily cancel the above _bForceByRefer
*/
BOOL _bRValue = FALSE;
WORD _wSeqCounter = 0;
WORD _wForCounter = 0;
WORD _wIfCounter = 0;
WORD _wWhileCounter = 0;
WORD _wCaseCounter = 0;
LONG _lMessageFix = 0; /* Position of the message which needs to be changed */
#ifdef HARBOUR_OBJ_GENERATION
BOOL _bObj32 = FALSE; /* generate OBJ 32 bits */
#endif
WORD _wStatics = 0; /* number of defined statics variables on the PRG */
PEXTERN pExterns = NULL;
PTR_LOOPEXIT pLoops = NULL;
PATHNAMES *_pIncludePath = NULL;
PHB_FNAME _pFileName = NULL;
ALIASID_PTR pAliasId = NULL;
WORD _wLastLinePos = 0; /* position of last opcode with line number */
BOOL _bDontGenLineNum = FALSE; /* suppress line number generation */
PSTACK_VAL_TYPE pStackValType = NULL; /* compile time stack values linked list */
char cVarType = ' '; /* current declared variable type */
#define LOOKUP 0
extern int _iState; /* current parser state (defined in harbour.l */
%}
%union /* special structure used by lex and yacc to share info */
{
char * string; /* to hold a string returned by lex */
int iNumber; /* to hold a number returned by lex */
long lNumber; /* to hold a long number returned by lex */
struct
{
double dNumber; /* to hold a double number returned by lex */
/* NOTE: Intentionally using "unsigned char" instead of "BYTE" */
unsigned char bDec; /* to hold the number of decimal points in the value */
} dNum;
void * pVoid; /* to hold any memory structure we may need */
};
%token FUNCTION PROCEDURE IDENTIFIER RETURN NIL DOUBLE INASSIGN INTEGER INTLONG
%token LOCAL STATIC IIF IF ELSE ELSEIF END ENDIF LITERAL TRUEVALUE FALSEVALUE
%token EXTERN INIT EXIT AND OR NOT PUBLIC EQ NE1 NE2
%token INC DEC ALIAS DOCASE CASE OTHERWISE ENDCASE ENDDO MEMVAR
%token WHILE EXIT LOOP END FOR NEXT TO STEP LE GE FIELD IN PARAMETERS
%token PLUSEQ MINUSEQ MULTEQ DIVEQ POWER EXPEQ MODEQ EXITLOOP
%token PRIVATE BEGINSEQ BREAK RECOVER USING DO WITH SELF LINE
%token AS_NUMERIC AS_CHARACTER AS_LOGICAL AS_DATE AS_ARRAY AS_BLOCK AS_OBJECT DECLARE_FUN
/*the lowest precedence*/
/*postincrement and postdecrement*/
%left POST
/*assigment - from right to left*/
%right INASSIGN
%left PLUSEQ MINUSEQ
%left MULTEQ DIVEQ MODEQ
%left EXPEQ
/*logical operators*/
%left OR
%left AND
%left NOT
/*relational operators*/
%left '<' '>' EQ NE1 NE2 LE GE '$'
/*mathematical operators*/
%left '+' '-'
%left '*' '/' '%'
%left POWER
%left UNARY
/*preincrement and predecrement*/
%left PRE
/*special operators*/
%left ALIAS '&' '@' ')'
%right '\n' ';' ',' '='
/*the highest precedence*/
%type <string> IDENTIFIER LITERAL FunStart MethStart IdSend ObjectData AliasVar
%type <dNum> DOUBLE
%type <iNumber> ArgList ElemList PareExpList ExpList FunCall FunScope IncDec
%type <iNumber> Params ParamList Logical
%type <iNumber> INTEGER BlockExpList Argument IfBegin VarId VarList MethParams ObjFunCall
%type <iNumber> MethCall BlockList FieldList DoArgList VarAt
%type <lNumber> INTLONG WhileBegin BlockBegin
%type <pVoid> IfElseIf Cases
%%
Main : { Line(); } Source {
FixReturns(); /* fix all previous function returns offsets */
if( ! _bQuiet ) printf( "\nsyntax ok\n" );
}
Source : Crlf
| VarDefs
| FieldsDef
| MemvarDef
| Function
| Statement
| Line
| Source Crlf
| Source Function
| Source { LineBody(); } Statement
| Source VarDefs
| Source FieldsDef
| Source MemvarDef
| Source Line
;
Line : LINE INTEGER LITERAL Crlf
| LINE INTEGER LITERAL '@' LITERAL Crlf /* XBase++ style */
;
Function : FunScope FUNCTION IDENTIFIER { cVarType = ' '; FunDef( $3, $1, 0 ); } Params Crlf {}
| FunScope PROCEDURE IDENTIFIER { cVarType = ' '; FunDef( $3, $1, FUN_PROCEDURE ); } Params Crlf {}
| FunScope DECLARE_FUN IDENTIFIER Params Crlf { cVarType = ' '; AddSymbol( $3, NULL ); }
| FunScope DECLARE_FUN IDENTIFIER Params AS_NUMERIC Crlf { cVarType = 'N'; AddSymbol( $3, NULL ); }
| FunScope DECLARE_FUN IDENTIFIER Params AS_CHARACTER Crlf { cVarType = 'C'; AddSymbol( $3, NULL ); }
| FunScope DECLARE_FUN IDENTIFIER Params AS_DATE Crlf { cVarType = 'D'; AddSymbol( $3, NULL ); }
| FunScope DECLARE_FUN IDENTIFIER Params AS_LOGICAL Crlf { cVarType = 'L'; AddSymbol( $3, NULL ); }
| FunScope DECLARE_FUN IDENTIFIER Params AS_ARRAY Crlf { cVarType = 'A'; AddSymbol( $3, NULL ); }
| FunScope DECLARE_FUN IDENTIFIER Params AS_OBJECT Crlf { cVarType = 'O'; AddSymbol( $3, NULL ); }
| FunScope DECLARE_FUN IDENTIFIER Params AS_BLOCK Crlf { cVarType = 'B'; AddSymbol( $3, NULL ); }
;
FunScope : { $$ = FS_PUBLIC; }
| STATIC { $$ = FS_STATIC; }
| INIT { $$ = FS_INIT; }
| EXIT { $$ = FS_EXIT; }
;
Params : { $$ = 0; }
| '(' ')' { $$ = 0; }
| '(' { iVarScope = VS_PARAMETER; } ParamList ')' { $$ = $3; }
;
ParamList : IDENTIFIER { cVarType = ' '; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_NUMERIC { cVarType = 'N'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_CHARACTER { cVarType = 'C'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_DATE { cVarType = 'D'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_LOGICAL { cVarType = 'L'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_ARRAY { cVarType = 'A'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_BLOCK { cVarType = 'B'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_OBJECT { cVarType = 'O'; AddVar( $1 ); $$ = 1; }
| ParamList ',' IDENTIFIER { AddVar( $3 ); $$++; }
;
Statements : Statement
| Statements { Line(); } Statement
;
Statement : ExecFlow Crlf {}
| FunCall Crlf { Do( $1 ); }
| AliasFunc Crlf {}
| IfInline Crlf { GenPCode1( HB_P_POP ); }
| ObjectMethod Crlf { GenPCode1( HB_P_POP ); }
| VarUnary Crlf { GenPCode1( HB_P_POP ); }
| VarAssign Crlf { GenPCode1( HB_P_POP ); _bRValue =FALSE; }
| IDENTIFIER '=' Expression Crlf { PopId( $1 ); }
| AliasVar '=' { $<pVoid>$=(void*)pAliasId; pAliasId=NULL; } Expression Crlf { pAliasId=(ALIASID_PTR) $<pVoid>3; PopId( $1 ); AliasRemove(); }
| AliasFunc '=' Expression Crlf { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); }
| VarAt '=' Expression Crlf { GenPCode1( HB_P_ARRAYPUT ); GenPCode1( HB_P_POP ); }
| FunCallArray '=' Expression Crlf { GenPCode1( HB_P_ARRAYPUT ); GenPCode1( HB_P_POP ); }
| ObjectData '=' { MessageFix( SetData( $1 ) ); } Expression Crlf { Function( 1 ); GenPCode1( HB_P_POP ); }
| ObjectData ArrayIndex '=' Expression Crlf { GenPCode1( HB_P_ARRAYPUT ); GenPCode1( HB_P_POP ); }
| ObjectMethod ArrayIndex '=' Expression Crlf { GenPCode1( HB_P_ARRAYPUT ); GenPCode1( HB_P_POP ); }
| BREAK { GenBreak(); } Crlf { Do( 0 ); }
| BREAK { GenBreak(); } Expression Crlf { Do( 1 ); }
| RETURN Crlf { if( _wSeqCounter ) GenError( _szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "RETURN", NULL ); GenPCode1( HB_P_ENDPROC ); }
| RETURN Expression Crlf { if( _wSeqCounter ) GenError( _szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "RETURN", NULL ); GenPCode1( HB_P_RETVALUE ); GenPCode1( HB_P_ENDPROC ); }
| PUBLIC { iVarScope = VS_PUBLIC; } VarList Crlf
| PRIVATE { iVarScope = VS_PRIVATE; } VarList Crlf
| EXITLOOP Crlf { LoopExit(); }
| LOOP Crlf { LoopLoop(); }
| DoProc Crlf
| EXTERN ExtList Crlf
;
ExtList : IDENTIFIER { AddExtern( $1 ); }
| ExtList ',' IDENTIFIER { AddExtern( $3 ); }
;
FunCall : FunStart ')' { $$=0; CheckArgs( $1, $$ ); }
| FunStart ArgList ')' { $$=$2; CheckArgs( $1, $$ ); }
;
FunStart : IDENTIFIER '(' { StaticAssign(); PushFunCall( $1 ); $$ = $1; }
;
MethCall : MethStart ')' { $$ = 0; }
| MethStart ArgList ')' { $$ = $2; }
;
MethStart : IDENTIFIER '(' { StaticAssign(); Message( $1 ); $$ = $1; }
;
ArgList : ',' { PushNil(); PushNil(); $$ = 2; }
| Argument { $$ = 1; }
| ArgList ',' { PushNil(); $$++; }
| ArgList ',' Argument { $$++; }
| ',' { PushNil(); } Argument { $$ = 2; }
;
Argument : Expression {}
| '@' IDENTIFIER { PushIdByRef( $2 ); }
| '@' IDENTIFIER '(' ')' { PushSymbol( $2, 1 ); GenPCode1( HB_P_FUNCPTR ); }
;
MethParams : /* empty */ { $$ = 0; }
| ArgList { $$ = $1; }
;
ObjectData : IdSend IDENTIFIER { $$ = $2; _lMessageFix = functions.pLast->lPCodePos; Message( $2 ); Function( 0 ); }
| VarAt ':' IDENTIFIER { GenPCode1( HB_P_ARRAYAT ); $$ = $3; _lMessageFix = functions.pLast->lPCodePos; Message( $3 ); Function( 0 ); }
| ObjFunCall IDENTIFIER { $$ = $2; _lMessageFix = functions.pLast->lPCodePos; Message( $2 ); Function( 0 ); }
| ObjFunArray ':' IDENTIFIER { $$ = $3; _lMessageFix = functions.pLast->lPCodePos; Message( $3 ); Function( 0 ); }
| ObjectMethod ':' IDENTIFIER { $$ = $3; _lMessageFix = functions.pLast->lPCodePos; Message( $3 ); Function( 0 ); }
| ObjectData ':' IDENTIFIER { $$ = $3; _lMessageFix = functions.pLast->lPCodePos; Message( $3 ); Function( 0 ); }
| ObjectData ArrayIndex ':' IDENTIFIER { GenPCode1( HB_P_ARRAYAT ); $$ = $4; _lMessageFix = functions.pLast->lPCodePos; Message( $4 ); Function( 0 ); }
;
ObjectMethod : IdSend IDENTIFIER { Message( $2 ); } '(' MethParams ')' { Function( $5 ); }
| VarAt ':' MethCall { Function( $3 ); GenPCode1( HB_P_ARRAYAT ); }
| ObjFunCall MethCall { Function( $2 ); }
| ObjFunArray ':' MethCall { Function( $3 ); }
| ObjectData ':' MethCall { Function( $3 ); }
| ObjectData ArrayIndex ':' MethCall { Function( $4 ); { GenPCode1( HB_P_ARRAYAT ); } }
| ObjectMethod ':' MethCall { Function( $3 ); }
;
IdSend : IDENTIFIER ':' { PushId( $1 ); $$ = $1; }
;
ObjFunCall : FunCall ':' { Function( $1 ); $$ = $1; }
;
FunCallArray : FunCall { Function( $1 ); } ArrayIndex
;
ObjFunArray : FunCallArray ':' { GenPCode1( HB_P_ARRAYAT ); }
;
NumExpression : DOUBLE { PushDouble( $1.dNumber,$1.bDec ); }
| INTEGER { PushInteger( $1 ); }
| INTLONG { PushLong( $1 ); }
;
ConExpression : NIL { PushNil(); }
| LITERAL { PushString( $1 ); }
| CodeBlock {}
;
DynExpression : Variable
| VarUnary
| Logical { PushLogical( $1 ); }
| Operators {}
| FunCall { Function( $1 ); }
| IfInline {}
| Array {}
| ObjectMethod {}
| Macro {}
| AliasVar { PushId( $1 ); AliasRemove(); }
| AliasFunc {}
| PareExpList {}
| SELF { GenPCode1( HB_P_PUSHSELF ); }
;
Expression : NumExpression
| ConExpression
| DynExpression
;
IfInline : IIF '(' Expression ',' { $<iNumber>$ = JumpFalse( 0 ); }
IfInlExp ',' { $<iNumber>$ = Jump( 0 ); JumpHere( $<iNumber>5 ); }
IfInlExp ')' { JumpHere( $<iNumber>8 );
if( _bWarnings )
{
PSTACK_VAL_TYPE pFree;
if( pStackValType )
{
pFree = pStackValType;
debug_msg( "\n***---IIF()\n", NULL );
pStackValType = pStackValType->pPrev;
hb_xfree( ( void * )pFree );
}
else
debug_msg( "\n***IIF() Compile time stack overflow\n", NULL );
}
}
| IF '(' Expression ',' { $<iNumber>$ = JumpFalse( 0 ); }
IfInlExp ',' { $<iNumber>$ = Jump( 0 ); JumpHere( $<iNumber>5 ); }
IfInlExp ')' { JumpHere( $<iNumber>8 );
if( _bWarnings )
{
PSTACK_VAL_TYPE pFree;
if( pStackValType )
{
pFree = pStackValType;
debug_msg( "\n***---IIF()\n", NULL );
pStackValType = pStackValType->pPrev;
hb_xfree( ( void * )pFree );
}
else
debug_msg( "\n***IIF() Compile time stack overflow\n", NULL );
}
}
;
IfInlExp : /* nothing => nil */ { PushNil(); }
| Expression
;
Macro : '&' Variable
| '&' '(' Expression ')'
;
AliasVar : INTEGER ALIAS { AliasAddInt( $1 ); } IDENTIFIER { $$ = $4; }
| IDENTIFIER ALIAS { AliasAddStr( $1 ); } IDENTIFIER { $$ = $4; }
| PareExpList ALIAS { AliasAddExp(); } IDENTIFIER { $$ = $4; }
;
/* NOTE: In the case:
* alias->( Expression )
* alias always selects a workarea even if it is MEMVAR or M
*/
AliasFunc : INTEGER ALIAS { AliasPush(); PushInteger( $1 ); AliasPop(); } PareExpList { AliasSwap(); }
| IDENTIFIER ALIAS { AliasPush(); PushSymbol( $1, 0 ); AliasPop(); } PareExpList { AliasSwap(); }
| PareExpList ALIAS { AliasPush(); AliasSwap(); } PareExpList { AliasSwap(); }
;
VarUnary : IDENTIFIER IncDec %prec POST { PushId( $1 ); Duplicate(); $2 ? Inc(): Dec(); PopId( $1 ); }
| IncDec IDENTIFIER %prec PRE { PushId( $2 ); $1 ? Inc(): Dec(); Duplicate(); PopId( $2 ); }
| VarAt IncDec %prec POST { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); $2 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); $2 ? Dec(): Inc(); }
| IncDec VarAt %prec PRE { DupPCode( $2 ); GenPCode1( HB_P_ARRAYAT ); $1 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); }
| FunCallArray IncDec %prec POST { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $2 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); $2 ? Dec(): Inc(); }
| IncDec FunCallArray %prec PRE { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $1 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectData IncDec %prec POST { MessageDupl( SetData( $1 ) ); Function( 0 ); $2 ? Inc(): Dec(); Function( 1 ); $2 ? Dec(): Inc(); }
| IncDec ObjectData %prec PRE { MessageDupl( SetData( $2 ) ); Function( 0 ); $1 ? Inc(): Dec(); Function( 1 ); }
| ObjectData ArrayIndex IncDec %prec POST { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $3 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); $3 ? Dec(): Inc(); }
| IncDec ObjectData ArrayIndex %prec PRE { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $1 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectMethod ArrayIndex IncDec %prec POST { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $3 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); $3 ? Dec(): Inc(); }
| IncDec ObjectMethod ArrayIndex %prec PRE { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $1 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); }
| AliasVar IncDec %prec POST { PushId( $1 ); Duplicate(); $2 ? Inc(): Dec(); PopId( $1 ); AliasRemove(); }
| IncDec AliasVar %prec PRE { PushId( $2 ); $1 ? Inc(): Dec(); Duplicate(); PopId( $2 ); AliasRemove(); }
;
IncDec : INC { $$ = 1; }
| DEC { $$ = 0; }
;
Variable : VarId {}
| VarAt { GenPCode1( HB_P_ARRAYAT ); }
| FunCallArray { GenPCode1( HB_P_ARRAYAT ); }
| ObjectData {}
| ObjectData ArrayIndex { GenPCode1( HB_P_ARRAYAT ); }
| ObjectMethod ArrayIndex { GenPCode1( HB_P_ARRAYAT ); }
;
VarId : IDENTIFIER { $$ = functions.pLast->lPCodePos;
if( _bForceByRefer && functions.pLast->szName && ! _bRValue )
/* DO .. WITH uses reference to a variable
* if not inside a codeblock
*/
PushIdByRef( $1 );
else
PushId( $1 );
}
;
VarAt : IDENTIFIER { $<iNumber>$ = functions.pLast->lPCodePos; PushId( $1 ); } ArrayIndex { $$ =$<iNumber>2; }
;
ArrayIndex : '[' IndexList ']'
| ArrayIndex { GenPCode1( HB_P_ARRAYAT ); } '[' IndexList ']'
;
IndexList : Expression
| IndexList { GenPCode1( HB_P_ARRAYAT ); } ',' Expression
;
/*NOTE: If _bRValue is TRUE then the expression is on the right side of assignment
* operator (or +=, -= ...) - in this case a variable is not pushed by
* a reference it is a part of DO <proc> WITH ... statement
*/
VarAssign : IDENTIFIER INASSIGN { _bRValue = TRUE; } Expression { PopId( $1 ); PushId( $1 ); }
| IDENTIFIER PLUSEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); PopId( $1 ); PushId( $1 ); }
| IDENTIFIER MINUSEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); PopId( $1 ); PushId( $1 ); }
| IDENTIFIER MULTEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); PopId( $1 ); PushId( $1 ); }
| IDENTIFIER DIVEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); PopId( $1 ); PushId( $1 ); }
| IDENTIFIER EXPEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); PopId( $1 ); PushId( $1 ); }
| IDENTIFIER MODEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); PopId( $1 ); PushId( $1 ); }
| VarAt INASSIGN { _bRValue = TRUE; } Expression { GenPCode1( HB_P_ARRAYPUT ); }
| VarAt PLUSEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); }
| VarAt MINUSEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); }
| VarAt MULTEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); }
| VarAt DIVEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); }
| VarAt EXPEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); }
| VarAt MODEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); }
| FunCallArray INASSIGN { _bRValue = TRUE; } Expression { GenPCode1( HB_P_ARRAYPUT ); }
| FunCallArray PLUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); }
| FunCallArray MINUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); }
| FunCallArray MULTEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); }
| FunCallArray DIVEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); }
| FunCallArray EXPEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); }
| FunCallArray MODEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectData INASSIGN { MessageFix ( SetData( $1 ) ); _bRValue = TRUE; } Expression { Function( 1 ); }
| ObjectData PLUSEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); Function( 1 ); }
| ObjectData MINUSEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); Function( 1 ); }
| ObjectData MULTEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); Function( 1 ); }
| ObjectData DIVEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); Function( 1 ); }
| ObjectData EXPEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); Function( 1 ); }
| ObjectData MODEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); Function( 1 ); }
| ObjectData ArrayIndex INASSIGN { _bRValue = TRUE; } Expression { GenPCode1( HB_P_ARRAYPUT ); }
| ObjectData ArrayIndex PLUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectData ArrayIndex MINUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectData ArrayIndex MULTEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectData ArrayIndex DIVEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectData ArrayIndex EXPEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectData ArrayIndex MODEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectMethod ArrayIndex INASSIGN { _bRValue = TRUE; } Expression { GenPCode1( HB_P_ARRAYPUT ); }
| ObjectMethod ArrayIndex PLUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectMethod ArrayIndex MINUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectMethod ArrayIndex MULTEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectMethod ArrayIndex DIVEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectMethod ArrayIndex EXPEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); }
| ObjectMethod ArrayIndex MODEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); }
| AliasVar INASSIGN { _bRValue = TRUE; $<pVoid>$=(void*)pAliasId; pAliasId=NULL; } Expression { pAliasId=(ALIASID_PTR) $<pVoid>3; PopId( $1 ); PushId( $1 ); AliasRemove(); }
| AliasVar PLUSEQ { PushId( $1 ); _bRValue = TRUE; $<pVoid>$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_PLUS ); pAliasId=(ALIASID_PTR) $<pVoid>3; PopId( $1 ); PushId( $1 ); AliasRemove(); }
| AliasVar MINUSEQ { PushId( $1 ); _bRValue = TRUE; $<pVoid>$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_MINUS ); pAliasId=(ALIASID_PTR) $<pVoid>3; PopId( $1 ); PushId( $1 ); AliasRemove(); }
| AliasVar MULTEQ { PushId( $1 ); _bRValue = TRUE; $<pVoid>$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_MULT ); pAliasId=(ALIASID_PTR) $<pVoid>3; PopId( $1 ); PushId( $1 ); AliasRemove(); }
| AliasVar DIVEQ { PushId( $1 ); _bRValue = TRUE; $<pVoid>$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_DIVIDE ); pAliasId=(ALIASID_PTR) $<pVoid>3; PopId( $1 ); PushId( $1 ); AliasRemove(); }
| AliasVar EXPEQ { PushId( $1 ); _bRValue = TRUE; $<pVoid>$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_POWER ); pAliasId=(ALIASID_PTR) $<pVoid>3; PopId( $1 ); PushId( $1 ); AliasRemove(); }
| AliasVar MODEQ { PushId( $1 ); _bRValue = TRUE; $<pVoid>$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_MODULUS ); pAliasId=(ALIASID_PTR) $<pVoid>3; PopId( $1 ); PushId( $1 ); AliasRemove(); }
| AliasFunc INASSIGN Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); }
| AliasFunc PLUSEQ Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); }
| AliasFunc MINUSEQ Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); }
| AliasFunc MULTEQ Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); }
| AliasFunc DIVEQ Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); }
| AliasFunc EXPEQ Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); }
| AliasFunc MODEQ Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); }
;
Operators : Expression '=' Expression { GenPCode1( HB_P_EQUAL ); } /* compare */
| Expression '+' Expression { GenPCode1( HB_P_PLUS ); }
| Expression '-' Expression { GenPCode1( HB_P_MINUS ); }
| Expression '*' Expression { GenPCode1( HB_P_MULT ); }
| Expression '/' Expression { GenPCode1( HB_P_DIVIDE ); }
| Expression '<' Expression { GenPCode1( HB_P_LESS ); }
| Expression '>' Expression { GenPCode1( HB_P_GREATER ); }
| Expression '$' Expression { GenPCode1( HB_P_INSTRING ); }
| Expression '%' Expression { GenPCode1( HB_P_MODULUS ); }
| Expression LE Expression { GenPCode1( HB_P_LESSEQUAL ); }
| Expression GE Expression { GenPCode1( HB_P_GREATEREQUAL ); }
| Expression AND { if( _bShortCuts ){ Duplicate(); $<iNumber>$ = JumpFalse( 0 ); } }
Expression { GenPCode1( HB_P_AND ); if( _bShortCuts ) JumpHere( $<iNumber>3 ); }
| Expression OR { if( _bShortCuts ){ Duplicate(); $<iNumber>$ = JumpTrue( 0 ); } }
Expression { GenPCode1( HB_P_OR ); if( _bShortCuts ) JumpHere( $<iNumber>3 ); }
| Expression EQ Expression { GenPCode1( HB_P_EXACTLYEQUAL ); }
| Expression NE1 Expression { GenPCode1( HB_P_NOTEQUAL ); }
| Expression NE2 Expression { GenPCode1( HB_P_NOTEQUAL ); }
| Expression POWER Expression { GenPCode1( HB_P_POWER ); }
| NOT Expression { GenPCode1( HB_P_NOT ); }
| '-' Expression %prec UNARY { GenPCode1( HB_P_NEGATE ); }
| '+' Expression %prec UNARY
| VarAssign { _bRValue = FALSE; }
;
Logical : TRUEVALUE { $$ = 1; }
| FALSEVALUE { $$ = 0; }
;
Array : '{' ElemList '}' { GenArray( $2 ); }
;
ElemList : /*empty array*/ { $$ = 0; }
| Expression { $$ = 1; }
| ElemList ',' { if( $$ == 0 ) {
PushNil();
PushNil();
$$ = 2;
} else {
PushNil();
$$++;
} }
| ElemList ',' Expression { if( $$ == 0 )
{
PushNil();
$$ = 2;
}
else
$$++; }
;
CodeBlock : BlockBegin '|' BlockExpList '}' { CodeBlockEnd(); }
| BlockBegin BlockList '|' BlockExpList '}' { CodeBlockEnd(); }
;
BlockBegin : '{' '|' { CodeBlockStart(); }
;
BlockExpList : Expression { $$ = 1; }
| ',' { PushNil(); GenPCode1( HB_P_POP ); PushNil(); $$ = 2; }
| BlockExpList ',' { GenPCode1( HB_P_POP ); PushNil(); $$++; }
| BlockExpList ',' { GenPCode1( HB_P_POP ); } Expression { $$++; }
;
BlockList : IDENTIFIER { cVarType = ' '; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_NUMERIC { cVarType = 'N'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_CHARACTER { cVarType = 'C'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_DATE { cVarType = 'D'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_LOGICAL { cVarType = 'L'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_ARRAY { cVarType = 'A'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_BLOCK { cVarType = 'B'; AddVar( $1 ); $$ = 1; }
| IDENTIFIER AS_OBJECT { cVarType = 'O'; AddVar( $1 ); $$ = 1; }
| BlockList ',' IDENTIFIER { AddVar( $3 ); $$++; }
;
PareExpList: '(' ExpList ')' { $$ = $2; }
;
ExpList : Expression %prec POST { $$ = 1; }
| ExpList { GenPCode1( HB_P_POP ); } ',' Expression %prec POST { $$++; }
;
VarDefs : LOCAL { iVarScope = VS_LOCAL; Line(); } VarList Crlf { cVarType = ' '; }
| STATIC { StaticDefStart() } VarList Crlf { StaticDefEnd( $<iNumber>3 ); }
| PARAMETERS { if( functions.pLast->bFlags & FUN_USES_LOCAL_PARAMS )
GenError( _szCErrors, 'E', ERR_PARAMETERS_NOT_ALLOWED, NULL, NULL );
else
functions.pLast->wParamNum=0; iVarScope = (VS_PRIVATE | VS_PARAMETER); }
MemvarList Crlf
;
VarList : VarDef { $$ = 1; }
| VarList ',' VarDef { $$++; }
;
VarDef : IDENTIFIER { cVarType = ' '; AddVar( $1 ); }
| IDENTIFIER AS_NUMERIC { cVarType = 'N'; AddVar( $1 ); }
| IDENTIFIER AS_CHARACTER { cVarType = 'C'; AddVar( $1 ); }
| IDENTIFIER AS_LOGICAL { cVarType = 'L'; AddVar( $1 ); }
| IDENTIFIER AS_DATE { cVarType = 'D'; AddVar( $1 ); }
| IDENTIFIER AS_ARRAY { cVarType = 'A'; AddVar( $1 ); }
| IDENTIFIER AS_BLOCK { cVarType = 'B'; AddVar( $1 ); }
| IDENTIFIER AS_OBJECT { cVarType = 'O'; AddVar( $1 ); }
| IDENTIFIER INASSIGN Expression { cVarType = ' '; AddVar( $1 ); PopId( $1 ); }
| IDENTIFIER AS_NUMERIC INASSIGN Expression { cVarType = 'N'; AddVar( $1 ); PopId( $1 ); }
| IDENTIFIER AS_CHARACTER INASSIGN Expression { cVarType = 'C'; AddVar( $1 ); PopId( $1 ); }
| IDENTIFIER AS_LOGICAL INASSIGN Expression { cVarType = 'L'; AddVar( $1 ); PopId( $1 ); }
| IDENTIFIER AS_DATE INASSIGN Expression { cVarType = 'D'; AddVar( $1 ); PopId( $1 ); }
| IDENTIFIER AS_ARRAY INASSIGN Expression { cVarType = 'A'; AddVar( $1 ); PopId( $1 ); }
| IDENTIFIER AS_BLOCK INASSIGN Expression { cVarType = 'B'; AddVar( $1 ); PopId( $1 ); }
| IDENTIFIER AS_OBJECT INASSIGN Expression { cVarType = 'O'; AddVar( $1 ); PopId( $1 ); }
| IDENTIFIER '[' ExpList ']' { cVarType = ' '; AddVar( $1 ); DimArray( $3 ); PopId( $1 ); }
| IDENTIFIER '[' ExpList ']' AS_ARRAY { cVarType = 'A'; AddVar( $1 ); DimArray( $3 ); PopId( $1 ); }
;
FieldsDef : FIELD { iVarScope =VS_FIELD; } FieldList Crlf
;
FieldList : IDENTIFIER { cVarType = ' '; $$=FieldsCount(); AddVar( $1 ); }
| IDENTIFIER AS_NUMERIC { cVarType = 'N'; $$=FieldsCount(); AddVar( $1 ); }
| IDENTIFIER AS_CHARACTER { cVarType = 'C'; $$=FieldsCount(); AddVar( $1 ); }
| IDENTIFIER AS_DATE { cVarType = 'D'; $$=FieldsCount(); AddVar( $1 ); }
| IDENTIFIER AS_LOGICAL { cVarType = 'L'; $$=FieldsCount(); AddVar( $1 ); }
| IDENTIFIER AS_ARRAY { cVarType = 'A'; $$=FieldsCount(); AddVar( $1 ); }
| IDENTIFIER AS_BLOCK { cVarType = 'B'; $$=FieldsCount(); AddVar( $1 ); }
| IDENTIFIER AS_OBJECT { cVarType = 'O'; $$=FieldsCount(); AddVar( $1 ); }
| FieldList ',' IDENTIFIER { AddVar( $3 ); }
| FieldList IN IDENTIFIER { FieldsSetAlias( $3, $<iNumber>1 ); }
;
MemvarDef : MEMVAR { iVarScope = VS_MEMVAR; } MemvarList Crlf
;
MemvarList : IDENTIFIER { AddVar( $1 ); }
| MemvarList ',' IDENTIFIER { AddVar( $3 ); }
;
ExecFlow : IfEndif
| DoCase
| DoWhile
| ForNext
| BeginSeq
;
IfEndif : IfBegin EndIf { JumpHere( $1 ); }
| IfBegin IfElse EndIf { JumpHere( $1 ); }
| IfBegin IfElseIf EndIf { JumpHere( $1 ); FixElseIfs( $2 ); }
| IfBegin IfElseIf IfElse EndIf { JumpHere( $1 ); FixElseIfs( $2 ); }
;
IfBegin : IF Expression { ++_wIfCounter; } Crlf { $$ = JumpFalse( 0 ); Line(); }
IfStats
{ $$ = Jump( 0 ); JumpHere( $<iNumber>5 ); }
;
IfElse : ELSE Crlf { Line(); } IfStats
;
IfElseIf : ELSEIF Expression Crlf { $<iNumber>$ = JumpFalse( 0 ); Line(); }
IfStats { $$ = GenElseIf( 0, Jump( 0 ) ); JumpHere( $<iNumber>4 ); }
| IfElseIf ELSEIF Expression Crlf { $<iNumber>$ = JumpFalse( 0 ); Line(); }
IfStats { $$ = GenElseIf( $1, Jump( 0 ) ); JumpHere( $<iNumber>5 ); }
;
EndIf : ENDIF { --_wIfCounter; }
| END { --_wIfCounter; }
;
IfStats : /* no statements */
| Statements
;
DoCase : DoCaseBegin
Cases
EndCase { FixElseIfs( $2 ); }
| DoCaseBegin
Otherwise
EndCase
| DoCaseBegin
EndCase
| DoCaseBegin
Cases
Otherwise
EndCase { FixElseIfs( $2 ); }
;
EndCase : ENDCASE { --_wCaseCounter; }
| END { --_wCaseCounter; }
;
DoCaseBegin : DOCASE { ++_wCaseCounter; } Crlf { Line(); }
;
Cases : CASE Expression Crlf { $<iNumber>$ = JumpFalse( 0 ); Line(); } CaseStmts { $$ = GenElseIf( 0, Jump( 0 ) ); JumpHere( $<iNumber>4 ); Line(); }
| Cases CASE Expression Crlf { $<iNumber>$ = JumpFalse( 0 ); Line(); } CaseStmts { $$ = GenElseIf( $1, Jump( 0 ) ); JumpHere( $<iNumber>5 ); Line(); }
;
Otherwise : OTHERWISE Crlf { Line(); } CaseStmts
;
CaseStmts : /* no statements */
| Statements
;
DoWhile : WhileBegin Expression Crlf { $<lNumber>$ = JumpFalse( 0 ); Line(); }
{ Jump( $1 - functions.pLast->lPCodePos ); }
EndWhile { JumpHere( $<lNumber>4 ); --_wWhileCounter; }
| WhileBegin Expression Crlf { $<lNumber>$ = JumpFalse( 0 ); Line(); }
WhileStatements { LoopHere(); Jump( $1 - functions.pLast->lPCodePos ); }
EndWhile { JumpHere( $<lNumber>4 ); --_wWhileCounter; LoopEnd(); }
;
WhileBegin : WHILE { $$ = functions.pLast->lPCodePos; ++_wWhileCounter; LoopStart(); }
;
WhileStatements : Statement
| WhileStatements { Line(); } Statement
;
EndWhile : END
| ENDDO
;
ForNext : FOR IDENTIFIER ForAssign Expression { PopId( $2 ); $<iNumber>$ = functions.pLast->lPCodePos; ++_wForCounter; LoopStart(); }
TO Expression { PushId( $2 ); }
StepExpr Crlf { if( $<lNumber>9 )
GenPCode1( HB_P_FORTEST );
else
GenPCode1( HB_P_LESS );
$<iNumber>$ = JumpTrue( 0 );
Line();
}
ForStatements { LoopHere();
PushId( $2 );
if( $<lNumber>9 )
GenPCode1( HB_P_PLUS );
else
Inc();
PopId( $2 );
Jump( $<iNumber>5 - functions.pLast->lPCodePos );
JumpHere( $<iNumber>11 );
LoopEnd();
if( $<lNumber>9 )
GenPCode1( HB_P_POP );
}
;
ForAssign : '='
| INASSIGN
;
StepExpr : /* default step expression */ { $<lNumber>$ =0; }
| STEP Expression { $<lNumber>$ =1; }
;
ForStatements : ForStat NEXT { --_wForCounter; }
| ForStat NEXT IDENTIFIER { --_wForCounter; }
| NEXT { --_wForCounter; }
| NEXT IDENTIFIER { --_wForCounter; }
;
ForStat : Statements { Line(); }
;
BeginSeq : BEGINSEQ { ++_wSeqCounter; $<lNumber>$=SequenceBegin(); } Crlf { Line(); }
SeqStatms
{
/* Set jump address for HB_P_SEQBEGIN opcode - this address
* will be used in BREAK code if there is no RECOVER clause
*/
JumpHere( $<lNumber>2 );
$<lNumber>$ = SequenceEnd();
Line();
}
RecoverSeq
{
/* Replace END address with RECOVER address in
* HB_P_SEQBEGIN opcode if there is RECOVER clause
*/
if( $<lNumber>7 )
JumpThere( $<lNumber>2, $<lNumber>7-(_bLineNumbers?3:0) );
}
END
{
/* Fix END address
* There is no line number after HB_P_SEQEND in case no
* RECOVER clause is used
*/
JumpThere( $<lNumber>6, functions.pLast->lPCodePos-((_bLineNumbers && !$<lNumber>7)?3:0) );
if( $<lNumber>7 ) /* only if there is RECOVER clause */
LineDebug();
else
--_wSeqCounter; /* RECOVER is also considered as end of sequence */
SequenceFinish( $<lNumber>2, $<lNumber>5 );
}
;
SeqStatms : /* empty */ { $<lNumber>$ = 0; }
| Statements { $<lNumber>$ = 1; }
;
RecoverSeq : /* no recover */ { $<lNumber>$ = 0; }
| RecoverEmpty Crlf { $<lNumber>$ = $<lNumber>1; }
| RecoverEmpty Crlf { $<lNumber>$ = $<lNumber>1; Line(); } Statements
| RecoverUsing Crlf { $<lNumber>$ = $<lNumber>1; }
| RecoverUsing Crlf { $<lNumber>$ = $<lNumber>1; Line(); } Statements
;
RecoverEmpty : RECOVER
{
$<lNumber>$ = functions.pLast->lPCodePos;
--_wSeqCounter;
GenPCode1( HB_P_SEQRECOVER );
GenPCode1( HB_P_POP );
}
;
RecoverUsing : RECOVER USING IDENTIFIER
{
$<lNumber>$ = functions.pLast->lPCodePos;
--_wSeqCounter;
GenPCode1( HB_P_SEQRECOVER );
PopId( $3 );
}
;
/* NOTE: In Clipper all variables used in DO .. WITH are passed by reference
* however if they are part of an expression then they are passed by value
* for example:
* DO .. WITH ++variable
* will pass the value of variable not a reference
*/
DoProc : DO IDENTIFIER { PushSymbol( $2, 1 ); PushNil(); Do( 0 ); }
| DO IDENTIFIER { PushSymbol( $2, 1 ); PushNil(); _bForceByRefer=TRUE; } WITH DoArgList { Do( $5 ); _bForceByRefer=FALSE; }
| WHILE { PushSymbol( yy_strdup("WHILE"), 1 ); PushNil(); _bForceByRefer=TRUE; } WITH DoArgList { Do( $4 ); _bForceByRefer=FALSE; }
;
DoArgList : ',' { PushNil(); PushNil(); $$ = 2; }
| DoExpression { $$ = 1; }
| DoArgList ',' { PushNil(); $$++; }
| DoArgList ',' DoExpression { $$++; }
| ',' { PushNil(); } DoExpression { $$ = 2; }
;
DoExpression: Expression { _bForceByRefer=TRUE; }
;
Crlf : '\n'
| ';' { _bDontGenLineNum =TRUE; }
| '\n' Crlf
| ';' Crlf { _bDontGenLineNum =TRUE; }
;
%%
void yyerror( char * s )
{
GenError( _szCErrors, 'E', ERR_YACC, s, NULL );
}
void * GenElseIf( void * pFirst, WORD wOffset )
{
PELSEIF pElseIf = ( PELSEIF ) hb_xgrab( sizeof( _ELSEIF ) ), pLast;
pElseIf->wOffset = wOffset;
pElseIf->pNext = 0;
if( ! pFirst )
pFirst = pElseIf;
else
{
pLast = ( PELSEIF ) pFirst;
while( pLast->pNext )
pLast = pLast->pNext;
pLast->pNext = pElseIf;
}
return pFirst;
}
void GenError( char* _szErrors[], char cPrefix, int iError, char * szError1, char * szError2 )
{
if( files.pLast->szFileName != NULL )
printf( "\r%s(%i) ", files.pLast->szFileName, iLine );
else
printf( "\rLine %i ", iLine );
printf( "Error %c%i ", cPrefix, iError );
printf( _szErrors[ iError - 1 ], szError1, szError2 );
printf( "\n\n" );
exit( EXIT_FAILURE );
}
void GenWarning( char* _szWarnings[], char cPrefix, int iWarning, char * szWarning1, char * szWarning2)
{
if( _bWarnings && iWarning < WARN_ASSIGN_SUSPECT ) /* TODO: add switch to set level */
{
printf( "\r%s(%i) ", files.pLast->szFileName, iLine );
printf( "Warning %c%i ", cPrefix, iWarning );
printf( _szWarnings[ iWarning - 1 ], szWarning1, szWarning2 );
printf( "\n" );
}
}
void EXTERNAL_LINKAGE close_on_exit( void )
{
PFILE pFile = files.pLast;
while( pFile )
{
printf( "\nClosing file: %s\n", pFile->szFileName );
fclose( pFile->handle );
pFile = (PFILE) pFile->pPrev;
}
}
int harbour_main( int argc, char * argv[] )
{
int iStatus = 0, iArg = 1;
if( argc > 1 )
{
char szFileName[ _POSIX_PATH_MAX ]; /* filename to parse */
char szPpoName[ _POSIX_PATH_MAX ];
PHB_FNAME pOutPath = NULL;
Hbpp_init(); /* Initialization of preprocessor arrays */
/* Command line options */
while( iArg < argc )
{
if( IS_OPT_SEP(argv[ iArg ][ 0 ]))
{
switch( argv[ iArg ][ 1 ] )
{
case '1':
if( argv[ iArg ][ 2 ] == '0' )
_bRestrictSymbolLength = TRUE;
break;
case 'a':
case 'A':
_bAutoMemvarAssume = TRUE;
break;
case 'b':
case 'B':
_bDebugInfo = TRUE;
_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;
#ifdef HARBOUR_OBJ_GENERATION
case 'f':
case 'F':
{
char * szUpper = yy_strupr( yy_strdup( &argv[ iArg ][ 2 ] ) );
if( ! strcmp( szUpper, "OBJ32" ) )
_bObj32 = TRUE;
free( szUpper );
}
break;
#endif
case 'g':
case 'G':
switch( argv[ iArg ][ 2 ] )
{
case 'c':
case 'C':
_iLanguage = LANG_C;
break;
case 'j':
case 'J':
_iLanguage = LANG_JAVA;
break;
case 'p':
case 'P':
_iLanguage = LANG_PASCAL;
break;
case 'r':
case 'R':
_iLanguage = LANG_RESOURCES;
break;
case 'h':
case 'H':
_iLanguage = LANG_PORT_OBJ;
break;
default:
printf( "\nUnsupported output language option\n" );
exit( EXIT_FAILURE );
}
break;
case 'i':
case 'I':
AddSearchPath( argv[ iArg ]+2, &_pIncludePath );
break;
case 'l':
case 'L':
_bLineNumbers = FALSE;
break;
case 'n':
case 'N':
_bStartProc = FALSE;
break;
case 'o':
case 'O':
pOutPath = hb_fsFNameSplit( argv[ iArg ] + 2 );
break;
/* Added for preprocessor needs */
case 'p':
case 'P':
lPpo = 1;
break;
case 'q':
case 'Q':
_bQuiet = TRUE;
break;
case 's':
case 'S':
_bSyntaxCheckOnly = TRUE;
break;
case 'v':
case 'V':
_bForceMemvars = TRUE;
break;
case 'w':
case 'W':
_bWarnings = TRUE;
break;
case 'y':
case 'Y':
yydebug = TRUE;
break;
case 'z':
case 'Z':
_bShortCuts = FALSE;
break;
default:
printf( "Invalid command line option: %s\n",
&argv[ iArg ][ 0 ] );
break;
}
}
else
_pFileName = hb_fsFNameSplit( argv[ iArg ] );
iArg++;
}
if( !_bQuiet )
printf( "Harbour compiler build %i%s (%04d.%02d.%02d)\n",
hb_build, hb_revision, hb_year, hb_month, hb_day );
if( _pFileName )
{
if( !_pFileName->szExtension )
_pFileName->szExtension = ".prg";
hb_fsFNameMerge( szFileName, _pFileName );
if( lPpo )
{
_pFileName->szExtension = ".ppo";
hb_fsFNameMerge( szPpoName, _pFileName );
yyppo = fopen ( szPpoName, "w" );
}
}
else
{
PrintUsage( argv[ 0 ] );
return iStatus;
}
files.iFiles = 0; /* initialize support variables */
files.pLast = NULL;
functions.iCount = 0;
functions.pFirst = NULL;
functions.pLast = NULL;
funcalls.iCount = 0;
funcalls.pFirst = NULL;
funcalls.pLast = NULL;
symbols.iCount = 0;
symbols.pFirst = NULL;
symbols.pLast = NULL;
_pInitFunc = NULL;
atexit( close_on_exit );
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, &_pIncludePath );
pPath = pDelim + 1;
}
AddSearchPath( pPath, &_pIncludePath );
}
/* Generate the starting procedure frame
*/
if( _bStartProc )
FunDef( yy_strupr( yy_strdup( _pFileName->szName ) ), FS_PUBLIC, FUN_PROCEDURE );
else
/* Don't pass the name of module if the code for starting procedure
* will be not generated. The name cannot be placed as first symbol
* because this symbol can be used as function call or memvar's name.
*/
FunDef( yy_strupr( yy_strdup( "" ) ), FS_PUBLIC, FUN_PROCEDURE );
yyparse();
GenExterns(); /* generates EXTERN symbols names */
fclose( yyin );
files.pLast = NULL;
#ifdef HARBOUR_OBJ_GENERATION
if( ! _bSyntaxCheckOnly && ! _bObj32 )
#else
if( ! _bSyntaxCheckOnly )
#endif
{
if( _pInitFunc )
{
PCOMSYMBOL pSym;
/* Fix the number of static variables */
_pInitFunc->pCode[ 1 ] =LOBYTE( _wStatics );
_pInitFunc->pCode[ 2 ] =HIBYTE( _wStatics );
_pInitFunc->wStaticsBase =_wStatics;
pSym = AddSymbol( _pInitFunc->szName, NULL );
pSym->cScope |= _pInitFunc->cScope;
functions.pLast->pNext = _pInitFunc;
++functions.iCount;
}
_pFileName->szPath = NULL;
_pFileName->szExtension = NULL;
/* we create a the output file */
if( pOutPath )
{
if( pOutPath->szPath )
_pFileName->szPath = pOutPath->szPath;
if( pOutPath->szName )
{
_pFileName->szName = pOutPath->szName;
if( pOutPath->szExtension )
_pFileName->szExtension = pOutPath->szExtension;
}
}
switch( _iLanguage )
{
case LANG_C:
if( ! _pFileName->szExtension )
_pFileName->szExtension =".c";
hb_fsFNameMerge( szFileName, _pFileName );
GenCCode( szFileName, _pFileName->szName );
break;
case LANG_JAVA:
if( ! _pFileName->szExtension )
_pFileName->szExtension =".java";
hb_fsFNameMerge( szFileName, _pFileName );
GenJava( szFileName, _pFileName->szName );
break;
case LANG_PASCAL:
if( ! _pFileName->szExtension )
_pFileName->szExtension =".pas";
hb_fsFNameMerge( szFileName, _pFileName );
GenPascal( szFileName, _pFileName->szName );
break;
case LANG_RESOURCES:
if( ! _pFileName->szExtension )
_pFileName->szExtension =".rc";
hb_fsFNameMerge( szFileName, _pFileName );
GenRC( szFileName, _pFileName->szName );
break;
case LANG_PORT_OBJ:
if( ! _pFileName->szExtension )
_pFileName->szExtension =".hrb";
hb_fsFNameMerge( szFileName, _pFileName );
GenPortObj( szFileName, _pFileName->szName );
break;
}
}
#ifdef HARBOUR_OBJ_GENERATION
if( _bObj32 )
{
if( ! _pFileName->szExtension )
_pFileName->szExtension = ".obj";
hb_fsFNameMerge( szFileName, _pFileName );
GenObj32( szFileName, _pFileName->szName );
}
#endif
if( lPpo ) fclose ( yyppo );
}
else
{
printf( "Can't open input file: %s\n", szFileName );
iStatus = 1;
}
hb_xfree( ( void * ) _pFileName );
if( pOutPath ) hb_xfree( pOutPath );
}
else
PrintUsage( argv[ 0 ] );
return iStatus;
}
/*
* Prints available options
*/
void PrintUsage( char * szSelf )
{
printf( "Syntax: %s <file.prg> [options]\n"
"\nOptions: \n"
"\t/a\t\tautomatic memvar declaration\n"
"\t/b\t\tdebug info\n"
"\t/d<id>[=<val>]\t#define <id>\n"
#ifdef HARBOUR_OBJ_GENERATION
"\t/f\t\tgenerated object file\n"
"\t\t\t /fobj32 --> Windows/Dos 32 bits OBJ\n"
#endif
"\t/g\t\tgenerated output language\n"
"\t\t\t /gc (C default) --> <file.c>\n"
"\t\t\t /gh (HRB file) --> <file.hrb>\n"
"\t\t\t /gj (Java) --> <file.java>\n"
"\t\t\t /gp (Pascal) --> <file.pas>\n"
"\t\t\t /gr (Resources) --> <file.rc>\n"
"\t/i<path>\tadd #include file search path\n"
"\t/l\t\tsuppress line number information\n"
"\t/n\t\tno implicit starting procedure\n"
"\t/o<path>\tobject file drive and/or path\n"
"\t/p\t\tgenerate pre-processed output (.ppo) file\n"
"\t/q\t\tquiet\n"
"\t/s\t\tsyntax check only\n"
"\t/v\t\tvariables are assumed M->\n"
"\t/w\t\tenable warnings\n"
"\t/y\t\ttrace lex & yacc activity\n"
"\t/z\t\tsuppress shortcutting (.and. & .or.)\n"
"\t/10\t\trestrict symbol length to 10 characters\n"
, szSelf );
}
/*
* 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;
}
/*
* 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 AddFunCall( char * szFunctionName )
{
PFUNCTION pFunc = FunctionNew( szFunctionName, 0 );
if( ! funcalls.iCount )
{
funcalls.pFirst = pFunc;
funcalls.pLast = pFunc;
}
else
{
( ( PFUNCTION ) funcalls.pLast )->pNext = pFunc;
funcalls.pLast = pFunc;
}
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 AddExtern( char * szExternName ) /* defines a new extern name */
{
PEXTERN pExtern = ( PEXTERN ) hb_xgrab( sizeof( _EXTERN ) ), pLast;
pExtern->szName = szExternName;
pExtern->pNext = NULL;
if( pExterns == NULL )
pExterns = pExtern;
else
{
pLast = pExterns;
while( pLast->pNext )
pLast = pLast->pNext;
pLast->pNext = pExtern;
}
}
void AddVar( char * szVarName )
{
PVAR pVar, pLastVar;
PFUNCTION pFunc =functions.pLast;
if( ! _bStartProc && functions.iCount <= 1 && iVarScope == VS_LOCAL )
{
/* Variable declaration is outside of function/procedure body.
In this case only STATIC and PARAMETERS variables are allowed. */
--iLine;
GenError( _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( (functions.pLast->bFlags & FUN_STATEMENTS) && !(iVarScope == VS_FIELD || (iVarScope & VS_MEMVAR)) )
{
--iLine;
GenError( _szCErrors, 'E', ERR_FOLLOWS_EXEC, (iVarScope==VS_LOCAL?"LOCAL":"STATIC"), NULL );
}
/* When static variable is added then functions.pLast points to function
* that will initialise variables. The function where variable is being
* defined is stored in pOwner member.
*/
if( iVarScope == VS_STATIC )
{
pFunc =pFunc->pOwner;
/* Check if an illegal action was invoked during a static variable
* value initialization
*/
if( _pInitFunc->bFlags & FUN_ILLEGAL_INIT )
GenError( _szCErrors, 'E', ERR_ILLEGAL_INIT, szVarName, pFunc->szName );
}
/* Check if a declaration of duplicated variable name is requested */
if( pFunc->szName )
{
/* variable defined in a function/procedure */
CheckDuplVars( pFunc->pFields, szVarName, iVarScope );
CheckDuplVars( pFunc->pStatics, szVarName, iVarScope );
if( !( iVarScope == VS_PRIVATE || iVarScope == VS_PUBLIC ) )
CheckDuplVars( pFunc->pMemvars, szVarName, iVarScope );
}
else
/* variable defined in a codeblock */
iVarScope =VS_PARAMETER;
CheckDuplVars( pFunc->pLocals, szVarName, iVarScope );
pVar = ( PVAR ) hb_xgrab( sizeof( VAR ) );
pVar->szName = szVarName;
pVar->szAlias = NULL;
pVar->cType = cVarType;
pVar->iUsed = 0;
pVar->pNext = NULL;
if( iVarScope & VS_MEMVAR )
{
PCOMSYMBOL pSym;
WORD wPos;
if( _bAutoMemvarAssume || 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( iVarScope )
{
case VS_MEMVAR:
/* variable declared in MEMVAR statement */
break;
case (VS_PARAMETER | VS_PRIVATE):
{
BOOL bNewParameter = FALSE;
if( ++functions.pLast->wParamNum > functions.pLast->wParamCount )
{
functions.pLast->wParamCount =functions.pLast->wParamNum;
bNewParameter = TRUE;
}
pSym =GetSymbol( szVarName, &wPos ); /* check if symbol exists already */
if( ! pSym )
pSym =AddSymbol( yy_strdup(szVarName), &wPos );
pSym->cScope |=VS_MEMVAR;
GenPCode3( HB_P_PARAMETER, LOBYTE(wPos), HIBYTE(wPos) );
GenPCode1( LOBYTE(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 = cVarType;
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:
{
PushSymbol( yy_strdup( "__MVPRIVATE" ), 1);
PushNil();
PushSymbol( yy_strdup(szVarName), 0 );
Do( 1 );
pSym = GetSymbol( szVarName, NULL );
pSym->cScope |= VS_MEMVAR;
}
break;
case VS_PUBLIC:
{
PushSymbol( yy_strdup( "__MVPUBLIC" ), 1);
PushNil();
PushSymbol( yy_strdup(szVarName), 0 );
Do( 1 );
pSym = GetSymbol( szVarName, NULL );
pSym->cScope |= VS_MEMVAR;
}
break;
}
}
else
{
switch( iVarScope )
{
case VS_LOCAL:
case VS_PARAMETER:
{
WORD wLocal = 1;
if( ! pFunc->pLocals )
pFunc->pLocals = pVar;
else
{
pLastVar = pFunc->pLocals;
while( pLastVar->pNext )
{
pLastVar = pLastVar->pNext;
wLocal++;
}
pLastVar->pNext = pVar;
}
if( iVarScope == VS_PARAMETER )
{
++functions.pLast->wParamCount;
functions.pLast->bFlags |= FUN_USES_LOCAL_PARAMS;
}
if( _bDebugInfo )
{
GenPCode3( HB_P_LOCALNAME, LOBYTE( wLocal ), HIBYTE( wLocal ) );
GenPCodeN( ( BYTE * )szVarName, strlen( szVarName ) );
GenPCode1( 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 AddSymbol( char * szSymbolName, WORD * pwPos )
{
PCOMSYMBOL pSym = ( PCOMSYMBOL ) hb_xgrab( sizeof( COMSYMBOL ) );
pSym->szName = szSymbolName;
pSym->cScope = 0;
pSym->cType = cVarType;
pSym->pNext = NULL;
if( ! symbols.iCount )
{
symbols.pFirst = pSym;
symbols.pLast = pSym;
}
else
{
( ( PCOMSYMBOL ) symbols.pLast )->pNext = pSym;
symbols.pLast = pSym;
}
symbols.iCount++;
if( pwPos )
*pwPos = symbols.iCount;
/*if( cVarType != ' ') printf("\nDeclared %s as type %c at symbol %i\n", szSymbolName, cVarType, symbols.iCount );*/
return pSym;
}
/* Adds new alias to the alias stack
*/
void AliasAdd( ALIASID_PTR pAlias )
{
pAlias->pPrev = pAliasId;
pAliasId = pAlias;
}
/* Restores previously selected alias
*/
void AliasRemove( void )
{
ALIASID_PTR pAlias = pAliasId;
pAliasId = 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 )
{
GenPCode1( HB_P_PUSHALIAS );
}
/* Generates pcodes to select the workarea number using current value
* from the eval stack
*/
void AliasPop( void )
{
GenPCode1( 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 )
{
GenPCode1( HB_P_SWAPALIAS );
}
int Include( char * szFileName, PATHNAMES * pSearch )
{
PFILE pFile;
yyin = fopen( szFileName, "r" );
if( ! yyin )
{
if( pSearch )
{
PHB_FNAME pFileName =hb_fsFNameSplit( szFileName );
char szFName[ _POSIX_PATH_MAX ]; /* filename to parse */
pFileName->szName =szFileName;
pFileName->szExtension =NULL;
while( pSearch && !yyin )
{
pFileName->szPath =pSearch->szPath;
hb_fsFNameMerge( szFName, pFileName );
yyin = fopen( szFName, "r" );
if( ! yyin )
{
pSearch = pSearch->pNext;
if( ! pSearch )
return 0;
}
}
hb_xfree( ( void * ) pFileName );
}
else
return 0;
}
if( ! _bQuiet )
printf( "\nparsing file %s\n", szFileName );
pFile = ( PFILE ) hb_xgrab( sizeof( _FILE ) );
pFile->handle = yyin;
pFile->szFileName = szFileName;
pFile->pPrev = NULL;
if( ! files.iFiles )
files.pLast = pFile;
else
{
files.pLast->iLine = iLine;
iLine = 1;
pFile->pPrev = files.pLast;
files.pLast = pFile;
}
#ifdef __cplusplus
yy_switch_to_buffer( (YY_BUFFER_STATE) (pFile->pBuffer = yy_create_buffer( yyin, 8192 * 2 ) ) );
#else
yy_switch_to_buffer( pFile->pBuffer = yy_create_buffer( yyin, 8192 * 2 ) );
#endif
files.iFiles++;
return 1;
}
int yywrap( void ) /* handles the EOF of the currently processed file */
{
void * pLast;
if( files.iFiles == 1 )
return 1; /* we have reached the main EOF */
else
{
pLast = files.pLast;
fclose( files.pLast->handle );
files.pLast = ( PFILE ) ( ( PFILE ) files.pLast )->pPrev;
iLine = files.pLast->iLine;
if( ! _bQuiet )
printf( "\nparsing file %s\n", files.pLast->szFileName );
#ifdef __cplusplus
yy_delete_buffer( (YY_BUFFER_STATE) ( ( PFILE ) pLast )->pBuffer );
#else
yy_delete_buffer( ( ( PFILE ) pLast )->pBuffer );
#endif
free( pLast );
files.iFiles--;
yyin = files.pLast->handle;
#ifdef __cplusplus
yy_switch_to_buffer( (YY_BUFFER_STATE) files.pLast->pBuffer );
#else
yy_switch_to_buffer( files.pLast->pBuffer );
#endif
return 0; /* we close the currently include file and continue */
}
}
void Duplicate( void )
{
GenPCode1( HB_P_DUPLICATE );
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = pStackValType->cType;
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
/*debug_msg( "\n* *Duplicate()\n ", NULL );*/
}
}
void DupPCode( WORD wStart ) /* duplicates the current generated pcode from an offset */
{
WORD w, wEnd = functions.pLast->lPCodePos - wStart;
for( w = 0; w < wEnd; w++ )
GenPCode1( functions.pLast->pCode[ wStart + w ] );
}
/*
* Function generates passed pcode for passed database field
*/
void FieldPCode( BYTE bPCode, char * szVarName )
{
WORD wVar;
PCOMSYMBOL pVar;
pVar = GetSymbol( szVarName, &wVar );
if( ! pVar )
pVar =AddSymbol( szVarName, &wVar );
pVar->cScope |=VS_MEMVAR;
GenPCode3( bPCode, LOBYTE( wVar ), HIBYTE( wVar ) );
}
/*
* This function creates and initialises the _FUNC structure
*/
PFUNCTION FunctionNew( char * szName, 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->wStaticsBase = _wStatics;
pFunc->pOwner = NULL;
pFunc->bFlags = 0;
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 FunDef( char * szFunName, SYMBOLSCOPE cScope, int iType )
{
PCOMSYMBOL pSym;
PFUNCTION pFunc;
char * * pFunction;
pFunc = GetFunction( szFunName );
if( pFunc )
{
/* The name of a function/procedure is already defined */
if( ( pFunc != functions.pFirst ) || _bStartProc )
/* it is not a starting procedure that was automatically created */
GenError( _szCErrors, 'E', ERR_FUNC_DUPL, szFunName, NULL );
}
pFunction = ( char * * ) RESERVED_FUNC( szFunName );
if( pFunction && !( functions.iCount==0 && !_bStartProc ) )
{
/* We are ignoring it when it is the name of PRG file and we are
* not creating implicit starting procedure
*/
GenError( _szCErrors, 'E', ERR_FUNC_RESERVED, *pFunction, szFunName );
}
FixReturns(); /* fix all previous function returns offsets */
pSym = GetSymbol( szFunName, NULL );
if( ! pSym )
/* there is not a symbol on the symbol table for this function name */
pSym = AddSymbol( 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( functions.iCount == 0 )
{
functions.pFirst = pFunc;
functions.pLast = pFunc;
}
else
{
functions.pLast->pNext = pFunc;
functions.pLast = pFunc;
}
functions.iCount++;
_wLastLinePos = 0; /* optimization of line numbers opcode generation */
GenPCode3( HB_P_FRAME, 0, 0 ); /* frame for locals and parameters */
GenPCode3( HB_P_SFRAME, 0, 0 ); /* frame for statics variables */
if( _bDebugInfo )
{
GenPCode1( HB_P_MODULENAME );
GenPCodeN( ( BYTE * )files.pLast->szFileName, strlen( files.pLast->szFileName ) );
GenPCode1( ':' );
GenPCodeN( ( BYTE * )szFunName, strlen( szFunName ) );
GenPCode1( 0 );
}
}
void GenJava( char * szFileName, char * szName )
{
printf( "\nGenerating Java language output...\n" );
printf( "%s -> not implemented yet! %s\n", szFileName, szName );
}
void GenPascal( char * szFileName, char * szName )
{
printf( "\nGenerating Pascal language output...\n" );
printf( "%s -> not implemented yet! %s\n", szFileName, szName );
}
void GenRC( char * szFileName, char * szName )
{
printf( "\nGenerating resources output...\n" );
printf( "%s -> not implemented yet! %s\n", szFileName, szName );
}
void GenCCode( char * szFileName, char * szName ) /* generates the C language output */
{
PFUNCTION pFunc = functions.pFirst, pFTemp;
PCOMSYMBOL pSym = symbols.pFirst;
WORD w, wLen, wSym, wVar;
WORD iNestedCodeblock = 0;
LONG lPCodePos;
char chr;
BOOL bEndProcRequired;
FILE * yyc; /* file handle for C output */
HB_SYMBOL_UNUSED( szName );
yyc = fopen( szFileName, "wb" );
if( ! yyc )
{
printf( "Error opening file %s\n", szFileName );
return;
}
if( ! _bQuiet )
printf( "\nGenerating C language output...\n" );
fprintf( yyc, "/* Harbour compiler generated code */\n\n" );
fprintf( yyc, "#include \"hb_vmpub.h\"\n" );
fprintf( yyc, "#include \"init.h\"\n\n\n" );
if( ! _bStartProc )
pFunc = pFunc->pNext; /* No implicit starting procedure */
/* write functions prototypes for PRG defined functions */
while( pFunc )
{
if( pFunc->cScope & FS_STATIC || pFunc->cScope & FS_INIT || pFunc->cScope & FS_EXIT )
fprintf( yyc, "static " );
if( pFunc == _pInitFunc )
fprintf( yyc, "HARBOUR hb_INITSTATICS( void );\n" ); /* NOTE: hb_ intentionally in lower case */
else
fprintf( yyc, "HARBOUR HB_%s( void );\n", pFunc->szName );
pFunc = pFunc->pNext;
}
/* write functions prototypes for called functions outside this PRG */
pFunc = funcalls.pFirst;
while( pFunc )
{
pFTemp = GetFunction( pFunc->szName );
if( ! pFTemp || pFTemp == functions.pFirst )
fprintf( yyc, "HARBOUR HB_%s( void );\n", pFunc->szName );
pFunc = pFunc->pNext;
}
/* writes the symbol table */
/* Generate the wrapper that will initialize local symbol table
*/
yy_strupr( _pFileName->szName );
fprintf( yyc, "\n\nHB_INIT_SYMBOLS_BEGIN( hb_vm_SymbolInit_%s )\n", _pFileName->szName );
if( ! _bStartProc )
pSym = pSym->pNext; /* starting procedure is always the first symbol */
wSym = 0; /* symbols counter */
while( pSym )
{
if( pSym->szName[ 0 ] == '(' )
{
/* Since the normal function cannot be INIT and EXIT at the same time
* we are using these two bits to mark the special function used to
* initialize static variables
*/
fprintf( yyc, "{ \"(_INITSTATICS)\", FS_INIT | FS_EXIT, hb_INITSTATICS, 0}" ); /* NOTE: hb_ intentionally in lower case */
}
else
{
fprintf( yyc, "{ \"%s\", ", pSym->szName );
if( pSym->cScope & FS_STATIC )
fprintf( yyc, "FS_STATIC" );
else if( pSym->cScope & FS_INIT )
fprintf( yyc, "FS_INIT" );
else if( pSym->cScope & FS_EXIT )
fprintf( yyc, "FS_EXIT" );
else
fprintf( yyc, "FS_PUBLIC" );
if( pSym->cScope & VS_MEMVAR )
fprintf( yyc, " | FS_MEMVAR" );
if( ( pSym->cScope != FS_MESSAGE ) && ( pSym->cScope & FS_MESSAGE ) ) /* only for non public symbols */
fprintf( yyc, " | FS_MESSAGE" );
/* specify the function address if it is a defined function or an
external called function */
if( GetFunction( pSym->szName ) ) /* is it a function defined in this module */
fprintf( yyc, ", HB_%s, 0 }", pSym->szName );
else if( GetFuncall( pSym->szName ) ) /* is it a function called from this module */
fprintf( yyc, ", HB_%s, 0 }", pSym->szName );
else
fprintf( yyc, ", 0, 0 }" ); /* memvar */
}
++wSym;
if( pSym != symbols.pLast )
fprintf( yyc, ",\n" );
pSym = pSym->pNext;
}
fprintf( yyc, "\nHB_INIT_SYMBOLS_END( hb_vm_SymbolInit_%s )\n", _pFileName->szName );
fprintf( yyc, "#if ! defined(__GNUC__)\n#pragma startup hb_vm_SymbolInit_%s\n#endif\n\n\n", _pFileName->szName );
/* Generate functions data
*/
pFunc = functions.pFirst;
if( ! _bStartProc )
pFunc = pFunc->pNext; /* No implicit starting procedure */
while( pFunc )
{
if( pFunc->cScope != FS_PUBLIC )
fprintf( yyc, "static " );
if( pFunc == _pInitFunc ) /* Is it (_INITSTATICS) */
fprintf( yyc, "HARBOUR hb_INITSTATICS( void )\n{\n static BYTE pcode[] = { \n" ); /* NOTE: hb_ intentionally in lower case */
else
fprintf( yyc, "HARBOUR HB_%s( void )\n{\n static BYTE pcode[] = { \n", pFunc->szName );
bEndProcRequired =TRUE;
lPCodePos = 0;
while( lPCodePos < pFunc->lPCodePos )
{
switch( pFunc->pCode[ lPCodePos ] )
{
case HB_P_AND:
fprintf( yyc, "\t\tHB_P_AND,\n" );
lPCodePos++;
break;
case HB_P_ARRAYAT:
fprintf( yyc, "\t\tHB_P_ARRAYAT,\n" );
lPCodePos++;
break;
case HB_P_ARRAYPUT:
fprintf( yyc, "\t\tHB_P_ARRAYPUT,\n" );
lPCodePos++;
break;
case HB_P_DEC:
fprintf( yyc, "\t\tHB_P_DEC,\n" );
lPCodePos++;
break;
case HB_P_DIMARRAY:
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, "\t\tHB_P_DIMARRAY, %i, %i,\t/* %i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w );
lPCodePos += 3;
break;
case HB_P_DIVIDE:
fprintf( yyc, "\t\tHB_P_DIVIDE,\n" );
lPCodePos++;
break;
case HB_P_DO:
fprintf( yyc, "\t\tHB_P_DO, %i, %i,\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ] );
lPCodePos += 3;
break;
case HB_P_DUPLICATE:
fprintf( yyc, "\t\tHB_P_DUPLICATE,\n" );
lPCodePos++;
break;
case HB_P_DUPLTWO:
fprintf( yyc, "\t\tHB_P_DUPLTWO,\n" );
lPCodePos++;
break;
case HB_P_EQUAL:
fprintf( yyc, "\t\tHB_P_EQUAL,\n" );
lPCodePos++;
break;
case HB_P_EXACTLYEQUAL:
fprintf( yyc, "\t\tHB_P_EXACTLYEQUAL,\n" );
lPCodePos++;
break;
case HB_P_ENDBLOCK:
--iNestedCodeblock;
fprintf( yyc, "\t\tHB_P_ENDBLOCK,\n" );
lPCodePos++;
break;
case HB_P_ENDPROC:
lPCodePos++;
if( lPCodePos == pFunc->lPCodePos )
{
bEndProcRequired =FALSE;
fprintf( yyc, "\t\tHB_P_ENDPROC\n" );
}
else
fprintf( yyc, "\t\tHB_P_ENDPROC,\n" );
break;
case HB_P_FALSE:
fprintf( yyc, "\t\tHB_P_FALSE,\n" );
lPCodePos++;
break;
case HB_P_FORTEST: /* ER For tests. Step > 0 LESS */
/* Step < 0 GREATER */
fprintf( yyc, "\t\tHB_P_FORTEST,\n" );
lPCodePos++;
break;
case HB_P_FRAME:
{
PVAR pLocal = pFunc->pLocals;
BYTE bLocals = 0;
while( pLocal )
{
pLocal = pLocal->pNext;
bLocals++;
}
if( bLocals || pFunc->wParamCount )
fprintf( yyc, "\t\tHB_P_FRAME, %i, %i,\t/* locals, params */\n",
bLocals - pFunc->wParamCount,
pFunc->wParamCount );
lPCodePos += 3;
}
break;
case HB_P_FUNCPTR:
fprintf( yyc, "\t\tHB_P_FUNCPTR,\n" );
lPCodePos++;
break;
case HB_P_FUNCTION:
fprintf( yyc, "\t\tHB_P_FUNCTION, %i, %i,\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ] );
lPCodePos += 3;
break;
case HB_P_GENARRAY:
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, "\t\tHB_P_GENARRAY, %i, %i,\t/* %i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w );
lPCodePos += 3;
break;
case HB_P_GREATER:
fprintf( yyc, "\t\tHB_P_GREATER,\n" );
lPCodePos++;
break;
case HB_P_GREATEREQUAL:
fprintf( yyc, "\t\tHB_P_GREATEREQUAL,\n" );
lPCodePos++;
break;
case HB_P_INC:
fprintf( yyc, "\t\tHB_P_INC,\n" );
lPCodePos++;
break;
case HB_P_INSTRING:
fprintf( yyc, "\t\tHB_P_INSTRING,\n" );
lPCodePos++;
break;
case HB_P_JUMP:
/*if( 1 ) (lPCodePos + 3) < pFunc->lPCodePos ) */
{
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, "\t\tHB_P_JUMP, %i, %i,\t/* %i (abs: %05li) */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w, lPCodePos + ( w ? w: 3 ) );
}
lPCodePos += 3;
break;
case HB_P_JUMPFALSE:
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, "\t\tHB_P_JUMPFALSE, %i, %i,\t/* %i (abs: %05li) */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w, lPCodePos + ( w ? w: 3 ) );
lPCodePos += 3;
break;
case HB_P_JUMPTRUE:
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, "\t\tHB_P_JUMPTRUE, %i, %i,\t/* %i (abs: %05li) */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w, lPCodePos + ( w ? w: 3 ) );
lPCodePos += 3;
break;
case HB_P_LESS:
fprintf( yyc, "\t\tHB_P_LESS,\n" );
lPCodePos++;
break;
case HB_P_LESSEQUAL:
fprintf( yyc, "\t\tHB_P_LESSEQUAL,\n" );
lPCodePos++;
break;
case HB_P_LINE:
fprintf( yyc, "/* %05li */", lPCodePos );
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, " HB_P_LINE, %i, %i,\t\t/* %i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w );
lPCodePos += 3;
break;
case HB_P_LOCALNAME:
fprintf( yyc, "\t\tHB_P_LOCALNAME, %i, %i,\t/* %s */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
( char * ) pFunc->pCode + lPCodePos + 3 );
lPCodePos += 3;
while( pFunc->pCode[ lPCodePos ] )
{
chr = pFunc->pCode[ lPCodePos++ ];
if( chr == '\'' || chr == '\\')
fprintf( yyc, " \'\\%c\',", chr );
else
fprintf( yyc, " \'%c\',", chr );
}
fprintf( yyc, " 0,\n" );
lPCodePos++;
break;
case HB_P_MESSAGE:
{
WORD wFixPos;
wSym = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wSym );
fprintf( yyc, "\t\tHB_P_MESSAGE, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
GetSymbolOrd( wSym )->szName );
lPCodePos += 3;
}
break;
case HB_P_MINUS:
fprintf( yyc, "\t\tHB_P_MINUS,\n" );
lPCodePos++;
break;
case HB_P_MODULENAME:
fprintf( yyc, "\t\tHB_P_MODULENAME,\t/* %s */\n",
( char * ) pFunc->pCode + lPCodePos++ + 1 );
while( pFunc->pCode[ lPCodePos ] )
{
chr = pFunc->pCode[ lPCodePos++ ];
if( chr == '\'' || chr == '\\')
fprintf( yyc, " \'\\%c\',", chr );
else
fprintf( yyc, " \'%c\',", chr );
}
fprintf( yyc, " 0,\n" );
lPCodePos++;
break;
case HB_P_MODULUS:
fprintf( yyc, "\t\tHB_P_MODULUS,\n" );
lPCodePos++;
break;
case HB_P_MULT:
fprintf( yyc, "\t\tHB_P_MULT,\n" );
lPCodePos++;
break;
case HB_P_NEGATE:
fprintf( yyc, "\t\tHB_P_NEGATE,\n" );
lPCodePos++;
break;
case HB_P_NOT:
fprintf( yyc, "\t\tHB_P_NOT,\n" );
lPCodePos++;
break;
case HB_P_NOTEQUAL:
fprintf( yyc, "\t\tHB_P_NOTEQUAL,\n" );
lPCodePos++;
break;
case HB_P_OR:
fprintf( yyc, "\t\tHB_P_OR,\n" );
lPCodePos++;
break;
case HB_P_PARAMETER:
{
WORD wFixPos;
wVar = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wVar );
fprintf( yyc, "\t\tHB_P_PARAMETER, %i, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
pFunc->pCode[ lPCodePos + 3 ],
GetSymbolOrd( wVar )->szName );
lPCodePos += 4;
}
break;
case HB_P_PLUS:
fprintf( yyc, "\t\tHB_P_PLUS,\n" );
lPCodePos++;
break;
case HB_P_POP:
fprintf( yyc, "\t\tHB_P_POP,\n" );
lPCodePos++;
break;
case HB_P_POPALIAS:
fprintf( yyc, "\t\tHB_P_POPALIAS,\n" );
lPCodePos++;
break;
case HB_P_POPALIASEDFIELD:
{
WORD wFixPos;
wVar = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wVar );
fprintf( yyc, "\t\tHB_P_POPALIASEDFIELD, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
GetSymbolOrd( wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_POPFIELD:
{
WORD wFixPos;
wVar = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wVar );
fprintf( yyc, "\t\tHB_P_POPFIELD, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
GetSymbolOrd( wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_POPLOCAL:
{
SHORT wVar = * ( ( SHORT * ) &(pFunc->pCode )[ lPCodePos + 1 ] );
/* Variable with negative order are local variables
* referenced in a codeblock -handle it with care
*/
if( iNestedCodeblock )
{
/* we are accesing variables within a codeblock */
/* the names of codeblock variable are lost */
if( wVar < 0 )
fprintf( yyc, "\t\tHB_P_POPLOCAL, %i, %i,\t/* localvar%i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
-wVar );
else
fprintf( yyc, "\t\tHB_P_POPLOCAL, %i, %i,\t/* codeblockvar%i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
wVar );
}
else
fprintf( yyc, "\t\tHB_P_POPLOCAL, %i, %i,\t/* %s */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
GetVar( pFunc->pLocals, wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_POPMEMVAR:
{
WORD wFixPos;
wVar = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wVar );
fprintf( yyc, "\t\tHB_P_POPMEMVAR, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
GetSymbolOrd( wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_POPSTATIC:
{
PVAR pVar;
PFUNCTION pTmp = functions.pFirst;
wVar = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
while( pTmp->pNext && pTmp->pNext->wStaticsBase < wVar )
pTmp =pTmp->pNext;
pVar = GetVar( pTmp->pStatics, wVar - pTmp->wStaticsBase );
fprintf( yyc, "\t\tHB_P_POPSTATIC, %i, %i,\t/* %s */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
pVar->szName );
lPCodePos += 3;
}
break;
case HB_P_POWER:
fprintf( yyc, "\t\tHB_P_POWER,\n" );
lPCodePos++;
break;
case HB_P_PUSHALIAS:
fprintf( yyc, "\t\tHB_P_PUSHALIAS,\n" );
lPCodePos++;
break;
case HB_P_PUSHALIASEDFIELD:
{
WORD wFixPos;
wVar = pFunc->pCode[ lPCodePos + 1 ] +
pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wVar );
fprintf( yyc, "\t\tHB_P_PUSHALIASEDFIELD, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
GetSymbolOrd( wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_PUSHBLOCK:
++iNestedCodeblock;
fprintf( yyc, "\t\tHB_P_PUSHBLOCK, %i, %i,\t/* %i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
pFunc->pCode[ lPCodePos + 1 ] +
pFunc->pCode[ lPCodePos + 2 ] * 256 );
w = * ( ( WORD * ) &( pFunc->pCode [ lPCodePos + 3 ] ) );
fprintf( yyc, "\t\t%i, %i,\t/* number of local parameters (%i) */\n",
pFunc->pCode[ lPCodePos + 3 ],
pFunc->pCode[ lPCodePos + 4 ], w );
wVar = * ( ( WORD * ) &( pFunc->pCode [ lPCodePos + 5 ] ) );
fprintf( yyc, "\t\t%i, %i,\t/* number of local variables (%i) */\n",
pFunc->pCode[ lPCodePos + 5 ],
pFunc->pCode[ lPCodePos + 6 ], wVar );
lPCodePos += 7; /* codeblock size + number of parameters + number of local variables */
/* create the table of referenced local variables */
while( wVar-- )
{
w = * ( ( WORD * ) &( pFunc->pCode [ lPCodePos ] ) );
fprintf( yyc, "\t\t%i, %i,\t/* %s */\n",
pFunc->pCode[ lPCodePos ],
pFunc->pCode[ lPCodePos + 1 ],
GetVar( pFunc->pLocals, w )->szName );
lPCodePos +=2;
}
break;
case HB_P_PUSHDOUBLE:
{
int i;
++lPCodePos;
fprintf( yyc, "\t\tHB_P_PUSHDOUBLE, " );
for( i = 0; i < sizeof( double ) + sizeof( BYTE ); ++i )
fprintf( yyc, "%i,", ( ( BYTE * ) pFunc->pCode )[ lPCodePos + i ] );
fprintf( yyc, "\t/* %.*f, %d */\n",
*( ( BYTE * ) &( pFunc->pCode[ lPCodePos + sizeof( double ) ] ) ),
*( ( double * ) &( pFunc->pCode[ lPCodePos ] ) ),
*( ( BYTE * ) &( pFunc->pCode[ lPCodePos + sizeof( double ) ] ) ) );
lPCodePos += sizeof( double ) + sizeof( BYTE );
}
break;
case HB_P_PUSHFIELD:
{
WORD wFixPos;
wVar = pFunc->pCode[ lPCodePos + 1 ] +
pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wVar );
fprintf( yyc, "\t\tHB_P_PUSHFIELD, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
GetSymbolOrd( wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_PUSHINT:
fprintf( yyc, "\t\tHB_P_PUSHINT, %i, %i,\t/* %i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
pFunc->pCode[ lPCodePos + 1 ] +
pFunc->pCode[ lPCodePos + 2 ] * 256 );
lPCodePos += 3;
break;
case HB_P_PUSHLOCAL:
{
SHORT wVar = * ( ( SHORT * ) &(pFunc->pCode )[ lPCodePos + 1 ] );
/* Variable with negative order are local variables
* referenced in a codeblock -handle it with care
*/
if( iNestedCodeblock )
{
/* we are accesing variables within a codeblock */
/* the names of codeblock variable are lost */
if( wVar < 0 )
fprintf( yyc, "\t\tHB_P_PUSHLOCAL, %i, %i,\t/* localvar%i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
-wVar );
else
fprintf( yyc, "\t\tHB_P_PUSHLOCAL, %i, %i,\t/* codeblockvar%i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
wVar );
}
else
fprintf( yyc, "\t\tHB_P_PUSHLOCAL, %i, %i,\t/* %s */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
GetVar( pFunc->pLocals, wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_PUSHLOCALREF:
{
SHORT wVar = * ( ( SHORT * ) &(pFunc->pCode )[ lPCodePos + 1 ] );
/* Variable with negative order are local variables
* referenced in a codeblock -handle it with care
*/
if( iNestedCodeblock )
{
/* we are accesing variables within a codeblock */
/* the names of codeblock variable are lost */
if( wVar < 0 )
fprintf( yyc, "\t\tHB_P_PUSHLOCALREF, %i, %i,\t/* localvar%i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
-wVar );
else
fprintf( yyc, "\t\tHB_P_PUSHLOCALREF, %i, %i,\t/* codeblockvar%i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
wVar );
}
else
fprintf( yyc, "\t\tHB_P_PUSHLOCALREF, %i, %i,\t/* %s */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
GetVar( pFunc->pLocals, wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_PUSHLONG:
fprintf( yyc, "\t\tHB_P_PUSHLONG, %i, %i, %i, %i,\t/* %li */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
pFunc->pCode[ lPCodePos + 3 ],
pFunc->pCode[ lPCodePos + 4 ],
*( ( long * ) &( pFunc->pCode[ lPCodePos + 1 ] ) ) );
lPCodePos +=( 1 + sizeof(long) );
break;
case HB_P_PUSHMEMVAR:
{
WORD wFixPos;
wVar = pFunc->pCode[ lPCodePos + 1 ] +
pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wVar );
fprintf( yyc, "\t\tHB_P_PUSHMEMVAR, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
GetSymbolOrd( wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_PUSHMEMVARREF:
{
WORD wFixPos;
wVar = pFunc->pCode[ lPCodePos + 1 ] +
pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wVar );
fprintf( yyc, "\t\tHB_P_PUSHMEMVARREF, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
GetSymbolOrd( wVar )->szName );
lPCodePos += 3;
}
break;
case HB_P_PUSHNIL:
fprintf( yyc, "\t\tHB_P_PUSHNIL,\n" );
lPCodePos++;
break;
case HB_P_PUSHSELF:
fprintf( yyc, "\t\tHB_P_PUSHSELF,\n" );
lPCodePos++;
break;
case HB_P_PUSHSTATIC:
{
PVAR pVar;
PFUNCTION pTmp = functions.pFirst;
wVar = pFunc->pCode[ lPCodePos + 1 ] +pFunc->pCode[ lPCodePos + 2 ] * 256;
while( pTmp->pNext && pTmp->pNext->wStaticsBase < wVar )
pTmp =pTmp->pNext;
pVar = GetVar( pTmp->pStatics, wVar - pTmp->wStaticsBase );
fprintf( yyc, "\t\tHB_P_PUSHSTATIC, %i, %i,\t/* %s */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
pVar->szName );
lPCodePos += 3;
}
break;
case HB_P_PUSHSTATICREF:
{
PVAR pVar;
PFUNCTION pTmp = functions.pFirst;
wVar = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
while( pTmp->pNext && pTmp->pNext->wStaticsBase < wVar )
pTmp =pTmp->pNext;
pVar = GetVar( pTmp->pStatics, wVar - pTmp->wStaticsBase );
fprintf( yyc, "\t\tHB_P_PUSHSTATICREF, %i, %i,\t/* %s */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ],
pVar->szName );
lPCodePos += 3;
}
break;
case HB_P_PUSHSTR:
wLen = pFunc->pCode[ lPCodePos + 1 ] +
pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, "\t\tHB_P_PUSHSTR, %i, %i,\t/* %i */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], wLen );
lPCodePos +=3;
while( wLen-- )
{
chr = pFunc->pCode[ lPCodePos++ ];
if( chr == '\'' || chr == '\\')
fprintf( yyc, " \'\\%c\',", chr );
else
fprintf( yyc, " \'%c\',", chr );
}
fprintf( yyc, "\n" );
break;
case HB_P_PUSHSYM:
{
WORD wFixPos;
wSym = pFunc->pCode[ lPCodePos + 1 ] +
pFunc->pCode[ lPCodePos + 2 ] * 256;
wFixPos =FixSymbolPos( wSym );
fprintf( yyc, "\t\tHB_P_PUSHSYM, %i, %i,\t/* %s */\n",
LOBYTE( wFixPos ),
HIBYTE( wFixPos ),
GetSymbolOrd( wSym )->szName );
lPCodePos += 3;
}
break;
case HB_P_RETVALUE:
fprintf( yyc, "\t\tHB_P_RETVALUE,\n" );
lPCodePos++;
break;
case HB_P_SEQBEGIN:
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, "\t\tHB_P_SEQBEGIN, %i, %i,\t/* %i (abs: %05li) */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w, lPCodePos + ( w ? w: 3 ) );
lPCodePos += 3;
break;
case HB_P_SEQEND:
fprintf( yyc, "/* %05li */", lPCodePos );
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, " HB_P_SEQEND, %i, %i,\t/* %i (abs: %05li) */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w, lPCodePos + ( w ? w: 3 ) );
lPCodePos += 3;
break;
case HB_P_SEQRECOVER:
fprintf( yyc, "\t\tHB_P_SEQRECOVER,\n" );
lPCodePos++;
break;
case HB_P_SFRAME:
/* we only generate it if there are statics used in this function */
if( pFunc->bFlags & FUN_USES_STATICS )
{
GetSymbol( _pInitFunc->szName, &w );
w = FixSymbolPos( w );
fprintf( yyc, "\t\tHB_P_SFRAME, %i, %i,\t/* symbol (_INITSTATICS) */\n",
LOBYTE( w ), HIBYTE( w ) );
}
lPCodePos += 3;
break;
case HB_P_STATICS:
{
GetSymbol( _pInitFunc->szName, &w );
w = FixSymbolPos( w );
fprintf( yyc, "\t\tHB_P_STATICS, %i, %i,\t/* symbol (_INITSTATICS) */\n",
LOBYTE( w ), HIBYTE( w ) );
lPCodePos += 3;
}
break;
case HB_P_SWAPALIAS:
fprintf( yyc, "\t\tHB_P_SWAPALIAS,\n" );
lPCodePos++;
break;
case HB_P_TRUE:
fprintf( yyc, "\t\tHB_P_TRUE,\n" );
lPCodePos++;
break;
case HB_P_ZERO:
fprintf( yyc, "\t\tHB_P_ZERO,\n" );
lPCodePos++;
break;
default:
printf( "Incorrect pcode value: %u\n", pFunc->pCode[ lPCodePos ] );
lPCodePos = pFunc->lPCodePos;
break;
}
}
fprintf( yyc, "/* %05li */", lPCodePos );
if( bEndProcRequired )
fprintf( yyc, " HB_P_ENDPROC };\n\n" );
else
fprintf( yyc, " };\n\n" );
fprintf( yyc, " hb_vmExecute( pcode, symbols );\n}\n\n" );
pFunc = pFunc->pNext;
}
fclose( yyc );
pFunc =functions.pFirst;
while( pFunc )
pFunc = KillFunction( pFunc );
pFunc =funcalls.pFirst;
while( pFunc )
{
funcalls.pFirst =pFunc->pNext;
hb_xfree( ( void * ) pFunc ); /*NOTE: szName will be released by KillSymbol() */
pFunc =funcalls.pFirst;
}
pSym =symbols.pFirst;
while( pSym )
pSym = KillSymbol( pSym );
if( ! _bQuiet )
printf( "%s -> done!\n", szFileName );
}
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 GenBreak( void )
{
PushSymbol( yy_strdup("BREAK"), 1 );
PushNil();
}
void GenExterns( void ) /* generates the symbols for the EXTERN names */
{
PEXTERN pDelete;
if( _bDebugInfo )
AddExtern( yy_strdup( "__DBGENTRY" ) );
while( pExterns )
{
if( GetSymbol( pExterns->szName, NULL ) )
{
if( ! GetFuncall( pExterns->szName ) )
AddFunCall( pExterns->szName );
}
else
{
AddSymbol( pExterns->szName, NULL );
AddFunCall( pExterns->szName );
}
pDelete = pExterns;
pExterns = pExterns->pNext;
hb_xfree( ( void * ) pDelete );
}
}
PFUNCTION GetFuncall( char * szFunctionName ) /* returns a previously called defined function */
{
PFUNCTION pFunc = 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 = 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, WORD wOrder ) /* returns variable if defined or zero */
{
WORD w = 1;
while( pVars->pNext && w++ < wOrder )
pVars = pVars->pNext;
return pVars;
}
WORD GetVarPos( PVAR pVars, char * szVarName ) /* returns the order + 1 of a variable if defined or zero */
{
WORD wVar = 1;
while( pVars )
{
if( pVars->szName && ! strcmp( pVars->szName, szVarName ) )
{
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
pVars->iUsed = 1;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = pVars->cType;
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n* *GetVarPos()\n", NULL );
}
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 =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
*/
GenError( _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 = 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->wStaticsBase;
/* 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( !_bStartProc )
{
iPos =GetVarPos( 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
* It also returns a pointer to the function where this field was declared
*/
int GetFieldVarPos( char * szVarName, PFUNCTION * pOwner )
{
int iVar;
PFUNCTION pFunc = functions.pLast;
*pOwner = NULL;
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 );
}
/* If not found on the list declared in current function then check
* the global list (only if there will be no starting procedure)
*/
if( ! iVar && ! _bStartProc )
{
pFunc = functions.pFirst;
iVar = GetVarPos( pFunc->pFields, szVarName );
}
if( iVar )
*pOwner = pFunc;
return iVar;
}
/** 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 GetMemvarPos( char * szVarName )
{
int iVar;
PFUNCTION pFunc = functions.pLast;
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 );
}
/* if not found on the list declared in current function then check
* the global list (only if there will be no starting procedure)
*/
if( ! iVar && ! _bStartProc )
iVar =GetVarPos( functions.pFirst->pMemvars, szVarName );
return iVar;
}
WORD FixSymbolPos( WORD wCompilePos )
{
return ( _bStartProc ? wCompilePos - 1 : wCompilePos - 2 );
}
/* returns a symbol pointer from the symbol table
* and sets its position in the symbol table
*/
PCOMSYMBOL GetSymbol( char * szSymbolName, WORD * pwPos )
{
PCOMSYMBOL pSym = symbols.pFirst;
WORD 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 GetSymbolOrd( WORD wSymbol ) /* returns a symbol based on its index on the symbol table */
{
PCOMSYMBOL pSym = symbols.pFirst;
WORD w = 1;
while( w++ < wSymbol && pSym->pNext )
pSym = pSym->pNext;
return pSym;
}
WORD GetFunctionPos( char * szFunctionName ) /* return 0 if not found or order + 1 */
{
PFUNCTION pFunc = functions.pFirst;
WORD wFunction = _bStartProc;
while( pFunc )
{
if( ! strcmp( pFunc->szName, szFunctionName ) && pFunc != functions.pFirst )
return wFunction;
else
{
if( pFunc->pNext )
{
pFunc = pFunc->pNext;
wFunction++;
}
else
return 0;
}
}
return 0;
}
void Inc( void )
{
GenPCode1( HB_P_INC );
if( _bWarnings )
{
if( pStackValType )
{
if( pStackValType->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_NUMERIC_SUSPECT, NULL, NULL );
else if( pStackValType->cType != 'N' )
{
char sType[ 2 ];
sType[ 0 ] = pStackValType->cType;
sType[ 1 ] = '\0';
GenWarning( _szCWarnings, 'W', WARN_NUMERIC_TYPE, sType, NULL );
}
}
else
debug_msg( "\n* *Inc() Compile time stack overflow\n", NULL );
}
}
WORD Jump( int iOffset )
{
GenPCode3( HB_P_JUMP, LOBYTE( iOffset ), HIBYTE( iOffset ) );
return functions.pLast->lPCodePos - 2;
}
WORD JumpFalse( int iOffset )
{
GenPCode3( HB_P_JUMPFALSE, LOBYTE( iOffset ), HIBYTE( iOffset ) );
if( _bWarnings )
{
PSTACK_VAL_TYPE pFree;
char sType[2];
if( pStackValType )
{
sType[0] = pStackValType->cType;
sType[1] = '\0';
}
else
debug_msg( "\n* *HB_P_JUMPFALSE Compile time stack overflow\n", NULL );
/* compile time Operand value */
if( pStackValType && pStackValType->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_LOGICAL_SUSPECT, NULL, NULL );
else if( pStackValType && pStackValType->cType != 'L')
GenWarning( _szCWarnings, 'W', WARN_LOGICAL_TYPE, sType, NULL );
/* compile time assignment value has to be released */
pFree = pStackValType;
debug_msg( "\n* *---JampFalse()\n", NULL );
if( pStackValType )
{
pStackValType = pStackValType->pPrev;
}
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
return functions.pLast->lPCodePos - 2;
}
void JumpThere( int iOffset, WORD wTo )
{
BYTE * pCode = functions.pLast->pCode;
pCode[ ( WORD ) iOffset ] = LOBYTE( wTo - iOffset + 1 );
pCode[ ( WORD ) iOffset + 1 ] = HIBYTE( wTo - iOffset + 1 );
}
void JumpHere( int iOffset )
{
JumpThere( iOffset, functions.pLast->lPCodePos );
}
WORD JumpTrue( int iOffset )
{
GenPCode3( HB_P_JUMPTRUE, LOBYTE( iOffset ), HIBYTE( iOffset ) );
if( _bWarnings )
{
PSTACK_VAL_TYPE pFree;
char sType[2];
if( pStackValType )
{
sType[0] = pStackValType->cType;
sType[1] = '\0';
}
else
debug_msg( "\n* *HB_P_JUMPTRUE Compile time stack overflow\n", NULL );
/* compile time Operand value */
if( pStackValType && pStackValType->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_LOGICAL_SUSPECT, NULL, NULL );
else if( pStackValType && pStackValType->cType != 'L')
GenWarning( _szCWarnings, 'W', WARN_LOGICAL_TYPE, sType, NULL );
/* compile time assignment value has to be released */
pFree = pStackValType;
debug_msg( "\n* *---JampTrue() \n", NULL );
if( pStackValType )
{
pStackValType = pStackValType->pPrev;
}
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
return functions.pLast->lPCodePos - 2;
}
void Line( void ) /* generates the pcode with the currently compiled source code line */
{
if( _bLineNumbers && ! _bDontGenLineNum )
{
if( ((functions.pLast->lPCodePos - _wLastLinePos) > 3) || _bDebugInfo )
{
_wLastLinePos =functions.pLast->lPCodePos;
GenPCode3( HB_P_LINE, LOBYTE( iLine ), HIBYTE( iLine ) );
}
else
{
functions.pLast->pCode[ _wLastLinePos +1 ] =LOBYTE( iLine );
functions.pLast->pCode[ _wLastLinePos +2 ] =HIBYTE( iLine );
}
}
_bDontGenLineNum =FALSE;
}
/* Generates the pcode with the currently compiled source code line
* if debug code was requested only
*/
void LineDebug( void )
{
if( _bDebugInfo )
Line();
}
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( _iState != EXTERN )
{
if( ! _bStartProc && functions.iCount <= 1 )
{
GenError( _szCErrors, 'E', ERR_OUTSIDE, NULL, NULL );
}
}
functions.pLast->bFlags |= FUN_STATEMENTS;
Line();
}
/**
* Function generates passed pcode for passed variable name
*/
void VariablePCode( BYTE bPCode, char * szVarName )
{
WORD wVar;
PCOMSYMBOL pSym;
PFUNCTION pOwnerFunc = NULL;
if( _bForceMemvars )
{ /* -v swith was used -> first check the MEMVARs */
wVar =GetMemvarPos( szVarName );
if( ! wVar )
{
wVar =GetFieldVarPos( szVarName, &pOwnerFunc );
if( ! wVar )
GenWarning( _szCWarnings, 'W', ((bPCode==HB_P_POPMEMVAR) ? WARN_MEMVAR_ASSUMED : WARN_AMBIGUOUS_VAR),
szVarName, NULL );
}
}
else
{ /* -v was not used -> default action is checking FIELDs list */
wVar =GetFieldVarPos( szVarName, &pOwnerFunc );
if( wVar == 0 )
{
wVar =GetMemvarPos( szVarName );
if( wVar == 0 )
GenWarning( _szCWarnings, 'W', ((bPCode==HB_P_POPMEMVAR) ? WARN_MEMVAR_ASSUMED : WARN_AMBIGUOUS_VAR),
szVarName, NULL );
}
}
if( wVar && pOwnerFunc )
{ /* variable is declared using FIELD statement */
PVAR pField = GetVar( pOwnerFunc->pFields, wVar );
if( pField->szAlias )
{ /* the alias was specified too */
if( bPCode == HB_P_POPMEMVAR )
bPCode =HB_P_POPALIASEDFIELD;
else if( bPCode == HB_P_PUSHMEMVAR )
bPCode =HB_P_PUSHALIASEDFIELD;
else
/* pushing fields by reference is not allowed */
GenError( _szCErrors, 'E', ERR_INVALID_REFER, szVarName, NULL );
PushSymbol( yy_strdup( pField->szAlias ), 0 );
}
else
{ /* this is unaliased field */
if( bPCode == HB_P_POPMEMVAR )
bPCode =HB_P_POPFIELD;
else if( bPCode == HB_P_PUSHMEMVAR )
bPCode =HB_P_PUSHFIELD;
else
/* pushing fields by reference is not allowed */
GenError( _szCErrors, 'E', ERR_INVALID_REFER, szVarName, NULL );
}
}
pSym = GetSymbol( szVarName, &wVar );
if( ! pSym )
pSym =AddSymbol( szVarName, &wVar );
pSym->cScope |=VS_MEMVAR;
GenPCode3( bPCode, LOBYTE( wVar ), HIBYTE( wVar ) );
}
void Message( char * szMsgName ) /* sends a message to an object */
{
WORD wSym;
PCOMSYMBOL pSym =GetSymbol( szMsgName, &wSym );
if( ! pSym ) /* the symbol was not found on the symbol table */
pSym =AddSymbol( szMsgName, &wSym );
pSym->cScope |= FS_MESSAGE;
GenPCode3( HB_P_MESSAGE, LOBYTE( wSym ), HIBYTE( wSym ) );
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
char cType;
cType = pSym->cType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = cType;
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
pStackValType->cType = cType;
debug_msg( "\n***Message()\n", NULL );
}
}
void MessageDupl( char * szMsgName ) /* fix a generated message and duplicate to an object */
{
WORD wSetSym;
PCOMSYMBOL pSym;
BYTE bLoGetSym, bHiGetSym; /* get symbol */
PFUNCTION pFunc = functions.pLast; /* get the currently defined Clipper function */
pSym =GetSymbol( szMsgName, &wSetSym );
if( ! pSym ) /* the symbol was not found on the symbol table */
pSym =AddSymbol( szMsgName, &wSetSym );
pSym->cScope |= FS_MESSAGE;
/* Get previously generated message */
bLoGetSym = pFunc->pCode[ _lMessageFix + 1];
bHiGetSym = pFunc->pCode[ _lMessageFix + 2];
pFunc->pCode[ _lMessageFix + 1 ] = LOBYTE( wSetSym );
pFunc->pCode[ _lMessageFix + 2 ] = HIBYTE( wSetSym );
pFunc->lPCodePos -= 3; /* Remove unnecessary function call */
Duplicate(); /* Duplicate object */
GenPCode3( HB_P_MESSAGE, bLoGetSym, bHiGetSym );
/* Generate new message */
}
void MessageFix( char * szMsgName ) /* fix a generated message to an object */
{
WORD wSym;
PCOMSYMBOL pSym;
PFUNCTION pFunc = functions.pLast; /* get the currently defined Clipper function */
pSym =GetSymbol( szMsgName, &wSym );
if( ! pSym ) /* the symbol was not found on the symbol table */
pSym =AddSymbol( szMsgName, &wSym );
pSym->cScope |= FS_MESSAGE;
pFunc->pCode[ _lMessageFix + 1 ] = LOBYTE( wSym );
pFunc->pCode[ _lMessageFix + 2 ] = HIBYTE( wSym );
pFunc->lPCodePos -= 3; /* Remove unnecessary function call */
}
void PopId( char * szVarName ) /* generates the pcode to pop a value from the virtual machine stack onto a variable */
{
int iVar;
if( pAliasId == NULL )
{
iVar = GetLocalVarPos( szVarName );
if( iVar )
GenPCode3( HB_P_POPLOCAL, LOBYTE( iVar ), HIBYTE( iVar ) );
else
{
iVar = GetStaticVarPos( szVarName );
if( iVar )
{
GenPCode3( HB_P_POPSTATIC, LOBYTE( iVar ), HIBYTE( iVar ) );
functions.pLast->bFlags |= FUN_USES_STATICS;
}
else
{
VariablePCode( HB_P_POPMEMVAR, szVarName );
}
}
}
else
{
if( pAliasId->type == ALIAS_NAME )
{
if( pAliasId->alias.szAlias[0] == 'M' && pAliasId->alias.szAlias[1] == '\x0' )
{ /* M->variable */
VariablePCode( HB_P_POPMEMVAR, szVarName );
}
else
{
int iCmp = strncmp( pAliasId->alias.szAlias, "MEMVAR", 4 );
if( iCmp == 0 )
iCmp = strncmp( pAliasId->alias.szAlias, "MEMVAR", strlen(pAliasId->alias.szAlias) );
if( iCmp == 0 )
{ /* MEMVAR-> or MEMVA-> or MEMV-> */
VariablePCode( HB_P_POPMEMVAR, szVarName );
}
else
{ /* field variable */
iCmp = strncmp( pAliasId->alias.szAlias, "FIELD", 4 );
if( iCmp == 0 )
iCmp = strncmp( pAliasId->alias.szAlias, "FIELD", strlen(pAliasId->alias.szAlias) );
if( iCmp == 0 )
{ /* FIELD-> */
FieldPCode( HB_P_POPFIELD, szVarName );
}
else
{ /* database alias */
PushSymbol( yy_strdup( pAliasId->alias.szAlias ), 0 );
FieldPCode( HB_P_POPALIASEDFIELD, szVarName );
}
}
}
}
else if( pAliasId->type == ALIAS_NUMBER )
{
PushInteger( pAliasId->alias.iAlias );
FieldPCode( HB_P_POPALIASEDFIELD, szVarName );
}
else
/* Alias is already placed on stack */
FieldPCode( HB_P_POPALIASEDFIELD, szVarName );
}
if( _bWarnings )
{
PSTACK_VAL_TYPE pVarType, pFree;
char sType[2];
/* Just pushed by Get...Pos() */
pVarType = pStackValType;
if( pVarType )
{
sType[0] = pVarType->cType;
sType[1] = '\0';
/* skip back to the assigned value */
pStackValType = pStackValType->pPrev;
}
else
debug_msg( "\n***PopId() Compile time stack overflow\n", NULL );
if( pVarType && pStackValType && pVarType->cType != ' ' && pStackValType->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_ASSIGN_SUSPECT, szVarName, sType );
else if( pVarType && pStackValType && pVarType->cType != ' ' && pVarType->cType != pStackValType->cType )
GenWarning( _szCWarnings, 'W', WARN_ASSIGN_TYPE, szVarName, sType );
/* compile time variable has to be released */
if( pVarType )
{
hb_xfree( ( void * ) pVarType );
}
debug_msg( "\n***--- Var at PopId()\n", NULL );
/* compile time assignment value has to be released */
pFree = pStackValType;
debug_msg( "\n***--- Value at PopId()\n", NULL );
if( pStackValType )
{
pStackValType = pStackValType->pPrev;
}
else
{
debug_msg( "\n***PopId() Compile time stack overflow\n", NULL );
}
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
}
void PushId( char * szVarName ) /* generates the pcode to push a variable value to the virtual machine stack */
{
int iVar;
if( pAliasId == NULL )
{
if( iVarScope == VS_STATIC && functions.pLast->szName )
{
/* Reffering to any variable is not allowed during initialization
* of static variable
*/
_pInitFunc->bFlags |= FUN_ILLEGAL_INIT;
}
iVar = GetLocalVarPos( szVarName );
if( iVar )
GenPCode3( HB_P_PUSHLOCAL, LOBYTE( iVar ), HIBYTE( iVar ) );
else
{
iVar = GetStaticVarPos( szVarName );
if( iVar )
{
GenPCode3( HB_P_PUSHSTATIC, LOBYTE( iVar ), HIBYTE( iVar ) );
functions.pLast->bFlags |= FUN_USES_STATICS;
}
else
{
VariablePCode( HB_P_PUSHMEMVAR, szVarName );
}
}
}
else
{
if( pAliasId->type == ALIAS_NAME )
{
if( pAliasId->alias.szAlias[0] == 'M' && pAliasId->alias.szAlias[1] == '\x0' )
{ /* M->variable */
VariablePCode( HB_P_PUSHMEMVAR, szVarName );
}
else
{
int iCmp = strncmp( pAliasId->alias.szAlias, "MEMVAR", 4 );
if( iCmp == 0 )
iCmp = strncmp( pAliasId->alias.szAlias, "MEMVAR", strlen(pAliasId->alias.szAlias) );
if( iCmp == 0 )
{ /* MEMVAR-> or MEMVA-> or MEMV-> */
VariablePCode( HB_P_PUSHMEMVAR, szVarName );
}
else
{ /* field variable */
iCmp = strncmp( pAliasId->alias.szAlias, "FIELD", 4 );
if( iCmp == 0 )
iCmp = strncmp( pAliasId->alias.szAlias, "FIELD", strlen(pAliasId->alias.szAlias) );
if( iCmp == 0 )
{ /* FIELD-> */
FieldPCode( HB_P_PUSHFIELD, szVarName );
}
else
{ /* database alias */
PushSymbol( yy_strdup( pAliasId->alias.szAlias ), 0 );
FieldPCode( HB_P_PUSHALIASEDFIELD, szVarName );
}
}
}
}
else if( pAliasId->type == ALIAS_NUMBER )
{
PushInteger( pAliasId->alias.iAlias );
FieldPCode( HB_P_PUSHALIASEDFIELD, szVarName );
}
else
/* Alias is already placed on stack */
FieldPCode( HB_P_PUSHALIASEDFIELD, szVarName );
}
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = cVarType;
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***HB_P_PUSHMEMVAR\n ", NULL );
}
}
void PushIdByRef( char * szVarName ) /* generates the pcode to push a variable by reference to the virtual machine stack */
{
WORD iVar;
if( iVarScope == VS_STATIC && functions.pLast->szName )
{
/* Reffering to any variable is not allowed during initialization
* of static variable
*/
_pInitFunc->bFlags |= FUN_ILLEGAL_INIT;
}
iVar = GetLocalVarPos( szVarName );
if( iVar )
GenPCode3( HB_P_PUSHLOCALREF, LOBYTE( iVar ), HIBYTE( iVar ) );
else
{
iVar = GetStaticVarPos( szVarName );
if( iVar )
{
GenPCode3( HB_P_PUSHSTATICREF, LOBYTE( iVar ), HIBYTE( iVar ) );
functions.pLast->bFlags |= FUN_USES_STATICS;
}
else
{
VariablePCode( HB_P_PUSHMEMVARREF, szVarName );
}
}
}
void PushLogical( int iTrueFalse ) /* pushes a logical value on the virtual machine stack */
{
if( iTrueFalse )
GenPCode1( HB_P_TRUE );
else
GenPCode1( HB_P_FALSE );
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = 'L';
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***PushLogical()\n", NULL );
}
}
void PushNil( void )
{
GenPCode1( HB_P_PUSHNIL );
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = ' ' /*TODO maybe 'U'*/ ;
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***PushNil()\n", NULL );
}
}
/* generates the pcode to push a double number on the virtual machine stack */
void PushDouble( double dNumber, BYTE bDec )
{
GenPCode1( HB_P_PUSHDOUBLE );
GenPCodeN( ( BYTE * ) &dNumber, sizeof( double ) );
GenPCode1( bDec );
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = 'N';
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***PushDouble()\n", NULL );
}
}
void PushFunCall( char * szFunName )
{
char * * pFunction;
pFunction = ( char * * ) RESERVED_FUNC( szFunName );
if( pFunction )
{
/* Abbreviated function name was used - change it for whole name
*/
PushSymbol( yy_strdup( *pFunction ), 1 );
}
else
PushSymbol( szFunName, 1 );
PushNil();
}
/* generates the pcode to push a integer number on the virtual machine stack */
void PushInteger( int iNumber )
{
if( iNumber )
GenPCode3( HB_P_PUSHINT, LOBYTE( ( WORD ) iNumber ), HIBYTE( ( WORD ) iNumber ) );
else
GenPCode1( HB_P_ZERO );
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = 'N';
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***PushInteger() %i\n ", iNumber );
}
}
/* generates the pcode to push a long number on the virtual machine stack */
void PushLong( long lNumber )
{
if( lNumber )
{
GenPCode1( HB_P_PUSHLONG );
GenPCode1( ( ( char * ) &lNumber )[ 0 ] );
GenPCode1( ( ( char * ) &lNumber )[ 1 ] );
GenPCode1( ( ( char * ) &lNumber )[ 2 ] );
GenPCode1( ( ( char * ) &lNumber )[ 3 ] );
}
else
GenPCode1( HB_P_ZERO );
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = 'N';
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***PushLong()\n", NULL );
}
}
/* generates the pcode to push a string on the virtual machine stack */
void PushString( char * szText )
{
WORD wStrLen = strlen( szText );
GenPCode3( HB_P_PUSHSTR, LOBYTE(wStrLen), HIBYTE(wStrLen) );
GenPCodeN( ( BYTE * ) szText, wStrLen );
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = 'C';
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***PushString()\n", NULL );
}
}
/* generates the pcode to push a symbol on the virtual machine stack */
void PushSymbol( char * szSymbolName, int iIsFunction )
{
WORD wSym;
PCOMSYMBOL pSym;
if( iIsFunction )
{
char * * pName = ( char * * ) 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 = GetSymbol( szSymbolName, &wSym );
if( ! pSym ) /* the symbol was not found on the symbol table */
{
pSym =AddSymbol( szSymbolName, &wSym );
if( iIsFunction )
AddFunCall( szSymbolName );
}
else
{
if( iIsFunction && ! GetFuncall( szSymbolName ) )
AddFunCall( szSymbolName );
}
GenPCode3( HB_P_PUSHSYM, LOBYTE( wSym ), HIBYTE( wSym ) );
if( _bWarnings )
{
PSTACK_VAL_TYPE pNewStackType;
char cType;
if( iIsFunction )
cType = pSym->cType;
else
cType = cVarType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = cType;
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***PushSymbol()\n", NULL );
}
}
void CheckDuplVars( PVAR pVar, char * szVarName, int iVarScope )
{
while( pVar )
{
if( ! strcmp( pVar->szName, szVarName ) )
{
if( ! (iVarScope & VS_PARAMETER) )
--iLine;
GenError( _szCErrors, 'E', ERR_VAR_DUPL, szVarName, NULL );
}
else
pVar = pVar->pNext;
}
}
void Dec( void )
{
GenPCode1( HB_P_DEC );
if( _bWarnings )
{
if( pStackValType )
{
if( pStackValType->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_NUMERIC_SUSPECT, NULL, NULL );
else if( pStackValType->cType != 'N' )
{
char sType[ 2 ];
sType[ 0 ] = pStackValType->cType;
sType[ 1 ] = '\0';
GenWarning( _szCWarnings, 'W', WARN_NUMERIC_TYPE, sType, NULL );
}
}
else
debug_msg( "\n***Dec() Compile time stack overflow\n", NULL );
}
}
void DimArray( WORD wDimensions )
{
GenPCode3( HB_P_DIMARRAY, LOBYTE( wDimensions ), HIBYTE( wDimensions ) );
}
void Do( BYTE bParams )
{
GenPCode3( HB_P_DO, bParams, 0 );
if( _bWarnings )
{
PSTACK_VAL_TYPE pFree;
int i;
/* Releasing the compile time stack items used as parameters to the function. */
for( i = abs( bParams ); i > 0; i-- )
{
pFree = pStackValType;
debug_msg( "\n***---Do() \n", NULL );
if( pStackValType )
pStackValType = pStackValType->pPrev;
else
debug_msg( "\n***Do() Compile time stack overflow\n", NULL );
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
/* releasing the compile time Nil symbol terminator */
pFree = pStackValType;
debug_msg( "\n***---Do()\n", NULL );
if( pStackValType )
pStackValType = pStackValType->pPrev;
else
debug_msg( "\n***Do(2) Compile time stack overflow\n", NULL );
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
/* releasing the compile time procedure value */
pFree = pStackValType;
debug_msg( "\n***---Do() \n", NULL );
if( pStackValType )
{
pStackValType = pStackValType->pPrev;
}
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
}
void FixElseIfs( void * pFixElseIfs )
{
PELSEIF pFix = ( PELSEIF ) pFixElseIfs;
while( pFix )
{
JumpHere( pFix->wOffset );
pFix = pFix->pNext;
}
}
void FixReturns( void ) /* fixes all last defined function returns jumps offsets */
{
if( _bWarnings && functions.pLast )
{
PVAR pVar;
pVar = functions.pLast->pLocals;
while( pVar )
{
if( pVar->szName && functions.pLast->szName && functions.pLast->szName[0] && ! pVar->iUsed )
GenWarning( _szCWarnings, 'W', WARN_VAR_NOT_USED, pVar->szName, functions.pLast->szName );
pVar = pVar->pNext;
}
pVar = functions.pLast->pStatics;
while( pVar )
{
if( pVar->szName && functions.pLast->szName && functions.pLast->szName[0] && ! pVar->iUsed )
GenWarning( _szCWarnings, 'W', WARN_VAR_NOT_USED, pVar->szName, functions.pLast->szName );
pVar = pVar->pNext;
}
/* Clear the compile time stack values (should be empty at this point) */
while( pStackValType )
{
PSTACK_VAL_TYPE pFree;
debug_msg( "\n***Compile time stack underflow - type: %c\n", pStackValType->cType );
pFree = pStackValType;
pStackValType = pStackValType->pPrev;
hb_xfree( ( void * ) pFree );
}
pStackValType = NULL;
}
/* TODO: check why it triggers this error in keywords.prg
if( pLoops )
{
PTR_LOOPEXIT pLoop = pLoops;
char cLine[ 64 ];
while( pLoop->pNext )
pLoop =pLoop->pNext;
itoa( pLoop->wLine, cLine, 10 );
GenError( _szCErrors, 'E', ERR_UNCLOSED_STRU, cLine, NULL );
}
*/
}
void Function( BYTE bParams )
{
GenPCode3( HB_P_FUNCTION, bParams, 0 );
if( _bWarnings )
{
PSTACK_VAL_TYPE pFree;
int i;
/* Releasing the compile time stack items used as parameters to the function. */
for( i = abs( bParams ); i > 0; i-- )
{
pFree = pStackValType;
debug_msg( "\n***---Function() parameter %i \n", i );
if( pStackValType )
pStackValType = pStackValType->pPrev;
else
debug_msg( "\n***Function() parameter %i Compile time stack overflow\n", i );
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
/* releasing the compile time Nil symbol terminator */
pFree = pStackValType;
debug_msg( "\n***---NIL at Function()\n", NULL );
if( pStackValType )
{
pStackValType = pStackValType->pPrev;
}
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
}
void GenArray( WORD wElements )
{
GenPCode3( HB_P_GENARRAY, LOBYTE( wElements ), HIBYTE( wElements ) );
if( _bWarnings )
{
PSTACK_VAL_TYPE pFree;
WORD wIndex;
/* Releasing the stack items used by the _GENARRAY (other than the 1st element). */
for( wIndex = wElements; wIndex > 1; wIndex-- )
{
pFree = pStackValType;
debug_msg( "\n***---element %i at GenArray()\n", wIndex );
if( pStackValType )
pStackValType = pStackValType->pPrev;
else
debug_msg( "\n***GenArray() Compile time stack overflow\n", NULL );
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
if( wElements == 0 )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = 'A';
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***empty array in GenArray()\n ", NULL );
}
/* Using the either remaining 1st element place holder or a new item if empty array. */
if( pStackValType )
pStackValType->cType = 'A';
else
debug_msg( "\n***ArrrayGen() Compile time stack overflow\n", NULL );
}
}
void GenPCode1( BYTE byte )
{
PFUNCTION pFunc = functions.pLast; /* get the currently defined Clipper function */
/* Releasing value consumed by HB_P_ARRAYPUT */
if( _bWarnings )
{
if( byte == HB_P_PUSHSELF )
{
PSTACK_VAL_TYPE pNewStackType;
pNewStackType = ( STACK_VAL_TYPE * )hb_xgrab( sizeof( STACK_VAL_TYPE ) );
pNewStackType->cType = 'O';
pNewStackType->pPrev = pStackValType;
pStackValType = pNewStackType;
debug_msg( "\n***HB_P_PUSHSELF\n", NULL );
}
else if( byte == HB_P_ARRAYPUT )
{
PSTACK_VAL_TYPE pFree;
/* Releasing compile time assignment value */
pFree = pStackValType;
debug_msg( "\n***---ArrayPut()\n", NULL );
if( pStackValType )
pStackValType = pStackValType->pPrev;
else
debug_msg( "\n***HB_P_ARRAYPUT Compile time stack overflow\n", NULL );
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
/* Releasing compile time array element index value */
pFree = pStackValType;
debug_msg( "\n***---HB_P_ARRAYPUT\n", NULL );
if( pStackValType )
pStackValType = pStackValType->pPrev;
else
debug_msg( "\n***HB_P_ARRAYPUT2 Compile time stack overflow\n", NULL );
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
else if( byte == HB_P_POP || byte == HB_P_RETVALUE || byte == HB_P_FORTEST || byte == HB_P_ARRAYAT )
{
PSTACK_VAL_TYPE pFree;
pFree = pStackValType;
debug_msg( "\n***---HB_P_POP / HB_P_RETVALUE / HB_P_FORTEST / HB_P_ARRAYAT pCode: %i\n", byte );
if( pStackValType )
pStackValType = pStackValType->pPrev;
else
debug_msg( "\n***pCode: %i Compile time stack overflow\n", byte );
if( pFree )
{
hb_xfree( ( void * ) pFree );
}
}
else if( byte == HB_P_MULT || byte == HB_P_DIVIDE || byte == HB_P_MODULUS || byte == HB_P_POWER || byte == HB_P_NEGATE )
{
PSTACK_VAL_TYPE pOperand1 = NULL, pOperand2;
char sType1[2], sType2[2];
/* 2nd. Operand (stack top)*/
pOperand2 = pStackValType;
/* skip back to the 1st. operand */
if( pOperand2 )
{
pOperand1 = pOperand2->pPrev;
sType2[0] = pOperand1->cType;
sType2[1] = '\0';
}
else
debug_msg( "\n***HB_P_MULT pCode: %i Compile time stack overflow\n", byte );
/* skip back to the 1st. operand */
if( pOperand1 )
{
sType1[0] = pOperand1->cType;
sType1[1] = '\0';
}
else
debug_msg( "\n***HB_P_MULT2 pCode: %i Compile time stack overflow\n", byte );
if( pOperand1 && pOperand1->cType != 'N' && pOperand1->cType != ' ' )
GenWarning( _szCWarnings, 'W', WARN_NUMERIC_TYPE, sType1, NULL );
else if( pOperand1 && pOperand1->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_NUMERIC_SUSPECT, NULL, NULL );
if( pOperand2 && pOperand2->cType != 'N' && pOperand2->cType != ' ' )
GenWarning( _szCWarnings, 'W', WARN_NUMERIC_TYPE, sType2, NULL );
else if( pOperand2 && pOperand2->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_NUMERIC_SUSPECT, NULL, NULL );
/* compile time 2nd. operand has to be released */
if( pOperand2 )
{
hb_xfree( ( void * ) pOperand2 );
}
/* compile time 1st. operand has to be released *but* result will be pushed and assumed numeric type */
pStackValType = pOperand1;
pStackValType->cType = 'N';
}
else if( byte == HB_P_PLUS || byte == HB_P_MINUS )
{
PSTACK_VAL_TYPE pOperand1 = NULL, pOperand2;
char sType1[2], sType2[2], cType = ' ';
/* 2nd. Operand (stack top)*/
pOperand2 = pStackValType;
/* skip back to the 1st. operand */
if( pOperand2 )
{
pOperand1 = pOperand2->pPrev;
sType2[0] = pOperand2->cType;
sType2[1] = '\0';
}
else
debug_msg( "\n***HB_P_PLUS / HB_P_MINUS Compile time stack overflow\n", NULL );
if( pOperand1 )
{
sType1[0] = pOperand1->cType;
sType1[1] = '\0';
}
else
debug_msg( "\n***HB_P_PLUS / HB_P_MINUS2 Compile time stack overflow\n", NULL );
if( pOperand1 && pOperand2 && pOperand1->cType != ' ' && pOperand2->cType != ' ' && pOperand1->cType != pOperand2->cType )
GenWarning( _szCWarnings, 'W', WARN_OPERANDS_INCOMPATBLE, sType1, sType2 );
else if( pOperand1 && pOperand2 && pOperand2->cType != ' ' && pOperand1->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_OPERAND_SUSPECT, sType2, NULL );
else if( pOperand1 && pOperand2 && pOperand1->cType != ' ' && pOperand2->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_OPERAND_SUSPECT, sType1, NULL );
else
cType = pOperand1->cType;
/* compile time 2nd. operand has to be released */
if( pOperand2 )
{
hb_xfree( ( void * ) pOperand2 );
}
/* compile time 1st. operand has to be released *but* result will be pushed and type as calculated */
/* Resetting */
pStackValType = pOperand1;
pStackValType->cType = cType;
}
else if( byte == HB_P_EQUAL || byte == HB_P_LESS || byte == HB_P_GREATER || byte == HB_P_INSTRING || byte == HB_P_LESSEQUAL || byte == HB_P_GREATEREQUAL || byte == HB_P_EXACTLYEQUAL || byte == HB_P_NOTEQUAL )
{
PSTACK_VAL_TYPE pOperand1 = NULL, pOperand2;
char sType1[2], sType2[2];
/* 2nd. Operand (stack top)*/
pOperand2 = pStackValType;
/* skip back to the 1st. operand */
if( pOperand2 )
{
pOperand1 = pOperand2->pPrev;
sType2[0] = pOperand2->cType;
sType2[1] = '\0';
}
else
debug_msg( "\n***HB_P_EQUAL pCode: %i Compile time stack overflow\n", byte );
if( pOperand1 )
{
sType1[0] = pOperand1->cType;
sType1[1] = '\0';
}
else
debug_msg( "\n***HB_P_EQUAL2 pCode: %i Compile time stack overflow\n", byte );
if( pOperand1 && pOperand2 && pOperand1->cType != ' ' && pOperand2->cType != ' ' && pOperand1->cType != pOperand2->cType )
GenWarning( _szCWarnings, 'W', WARN_OPERANDS_INCOMPATBLE, sType1, sType2 );
else if( pOperand1 && pOperand2 && pOperand2->cType != ' ' && pOperand1->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_OPERAND_SUSPECT, sType2, NULL );
else if( pOperand1 && pOperand2 && pOperand1->cType != ' ' && pOperand2->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_OPERAND_SUSPECT, sType1, NULL );
/* compile time 2nd. operand has to be released */
if( pOperand2 )
{
hb_xfree( ( void * ) pOperand2 );
}
/* compile time 1st. operand has to be released *but* result will be pushed and of type logical */
if( pOperand1 )
pOperand1->cType = 'L';
/* Resetting */
pStackValType = pOperand1;
}
else if( byte == HB_P_NOT )
{
char sType[2];
if( pStackValType )
{
sType[0] = pStackValType->cType;
sType[1] = '\0';
}
else
debug_msg( "\n***HB_P_NOT Compile time stack overflow\n", NULL );
if( pStackValType && pStackValType->cType == ' ' )
GenWarning( _szCWarnings, 'W', WARN_LOGICAL_SUSPECT, NULL, NULL );
else if( pStackValType && pStackValType->cType != 'L' )
GenWarning( _szCWarnings, 'W', WARN_LOGICAL_TYPE, sType, NULL );
/* compile time 1st. operand has to be released *but* result will be pushed and assumed logical */
if( pStackValType )
pStackValType->cType = 'L';
}
}
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 GenPCode3( BYTE byte1, BYTE byte2, BYTE byte3 )
{
PFUNCTION pFunc = 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 GenPCodeN( BYTE * pBuffer, WORD wSize )
{
PFUNCTION pFunc = functions.pLast; /* get the currently defined Clipper function */
if( ! pFunc->pCode ) /* has been created the memory block to hold the pcode ? */
{
pFunc->lPCodeSize = ( ( wSize / PCODE_CHUNK ) + 1 ) * PCODE_CHUNK;
pFunc->pCode = ( BYTE * ) hb_xgrab( pFunc->lPCodeSize );
pFunc->lPCodePos = 0;
}
else if( pFunc->lPCodePos + wSize > pFunc->lPCodeSize )
{
/* not enough free space in pcode buffer - increase it */
pFunc->lPCodeSize += ( ( ( wSize / PCODE_CHUNK ) + 1 ) * PCODE_CHUNK );
pFunc->pCode = ( BYTE * ) hb_xrealloc( pFunc->pCode, pFunc->lPCodeSize );
}
memcpy( pFunc->pCode+pFunc->lPCodePos, pBuffer, wSize );
pFunc->lPCodePos +=wSize;
}
char * SetData( char * szMsg ) /* generates an underscore-symbol name for a data assignment */
{
char * szResult = ( char * ) hb_xgrab( strlen( szMsg ) + 2 );
strcpy( szResult, "_" );
strcat( szResult, szMsg );
return szResult;
}
/* 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
*/
int SequenceBegin( void )
{
GenPCode3( HB_P_SEQBEGIN, 0, 0 );
return 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.
*/
int SequenceEnd( void )
{
GenPCode3( HB_P_SEQEND, 0, 0 );
return functions.pLast->lPCodePos - 2;
}
/* Remove unnecessary opcodes in case there were no executable statements
* beetwen BEGIN and RECOVER sequence
*/
void SequenceFinish( int iStartPos, int bUsualStmts )
{
if( ! _bDebugInfo ) /* only if no debugger info is required */
{
if( ! bUsualStmts )
{
functions.pLast->lPCodePos = iStartPos - 1; /* remove also HB_P_SEQBEGIN */
_wLastLinePos = iStartPos - 4;
}
}
}
/*
* Start a new fake-function that will hold pcodes for a codeblock
*/
void CodeBlockStart()
{
PFUNCTION pFunc = FunctionNew( NULL, FS_STATIC );
pFunc->pOwner = functions.pLast;
pFunc->wStaticsBase = functions.pLast->wStaticsBase;
functions.pLast = pFunc;
LineDebug();
}
void CodeBlockEnd()
{
PFUNCTION pCodeblock; /* pointer to the current codeblock */
PFUNCTION pFunc; /* poiter to a function that owns a codeblock */
WORD wSize;
WORD wLocals = 0; /* number of referenced local variables */
WORD wPos;
PVAR pVar, pFree;
pCodeblock = functions.pLast;
/* return to pcode buffer of function/codeblock in which the current
* codeblock was defined
*/
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 WORD 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 + WORD(size) + WORD(wParams) + WORD(wLocals) +_ENDBLOCK */
wSize =( WORD ) pCodeblock->lPCodePos +8 +wLocals*2;
GenPCode3( HB_P_PUSHBLOCK, LOBYTE(wSize), HIBYTE(wSize) );
GenPCode1( LOBYTE(pCodeblock->wParamCount) );
GenPCode1( HIBYTE(pCodeblock->wParamCount) );
GenPCode1( LOBYTE(wLocals) );
GenPCode1( HIBYTE(wLocals) );
/* generate the table of referenced local variables */
pVar = pCodeblock->pStatics;
while( wLocals-- )
{
wPos = GetVarPos( pFunc->pLocals, pVar->szName );
GenPCode1( LOBYTE(wPos) );
GenPCode1( HIBYTE(wPos) );
pFree = pVar;
hb_xfree( ( void * ) pFree->szName );
pVar = pVar->pNext;
hb_xfree( ( void * ) pFree );
}
GenPCodeN( pCodeblock->pCode, pCodeblock->lPCodePos );
GenPCode1( HB_P_ENDBLOCK ); /* finish the codeblock */
/* this fake-function is no longer needed */
hb_xfree( ( void * ) pCodeblock->pCode );
pVar = pCodeblock->pLocals;
while( pVar )
{
if( _bWarnings && pFunc->szName && pVar->szName && ! pVar->iUsed )
GenWarning( _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 );
if( _bWarnings )
{
if( pStackValType )
/* reusing the place holder of the result value */
pStackValType->cType = 'B';
else
debug_msg( "\n***CodeBlockEnd() Compile time stack overflow\n", NULL );
}
}
/* 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 = 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 = functions.pLast->pFields;
while( pVar )
{
++iFields;
pVar = pVar->pNext;
}
return iFields;
}
/*
* Start of definition of static variable
* We are using here the special function _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 StaticDefStart( void )
{
iVarScope =VS_STATIC;
Line();
functions.pLast->bFlags |= FUN_USES_STATICS;
if( ! _pInitFunc )
{
_pInitFunc =FunctionNew( yy_strdup("(_INITSTATICS)"), FS_INIT );
_pInitFunc->pOwner =functions.pLast;
_pInitFunc->bFlags =FUN_USES_STATICS | FUN_PROCEDURE;
_pInitFunc->cScope =FS_INIT | FS_EXIT;
functions.pLast =_pInitFunc;
PushInteger( 1 ); /* the number of static variables is unknown now */
GenPCode3( HB_P_STATICS, 0, 0 );
GenPCode3( HB_P_SFRAME, 0, 0 ); /* frame for statics variables */
}
else
{
_pInitFunc->pOwner =functions.pLast;
functions.pLast =_pInitFunc;
}
}
/*
* End of definition of static variable
* Return to previously pcoded function.
*/
void StaticDefEnd( WORD wCount )
{
functions.pLast =_pInitFunc->pOwner;
_pInitFunc->pOwner =NULL;
_wStatics += wCount;
iVarScope =VS_LOCAL;
if( _bWarnings )
{
PSTACK_VAL_TYPE pFree;
if( pStackValType )
{
pFree = pStackValType;
debug_msg( "\n***---%i in StaticeDefEnd()\n", _wStatics );
pStackValType = pStackValType->pPrev;
hb_xfree( ( void * ) pFree );
}
else
debug_msg( "\n***StaticDefEnd() Compile time stack overflow\n", NULL );
}
}
/*
* This function checks if we are initializing a static variable.
* It should be called only in case when the parser have recognized any
* function or method invocation.
*/
void StaticAssign( void )
{
if( iVarScope == VS_STATIC && functions.pLast->szName )
/* function call is allowed if it is inside a codeblock
*/
_pInitFunc->bFlags |= FUN_ILLEGAL_INIT;
}
/*
* This function stores the position in pcode buffer where the FOR/WHILE
* loop starts. It will be used to fix any LOOP/EXIT statements
*/
static void LoopStart( void )
{
PTR_LOOPEXIT pLoop = ( PTR_LOOPEXIT ) hb_xgrab( sizeof(LOOPEXIT) );
if( pLoops )
{
PTR_LOOPEXIT pLast =pLoops;
while( pLast->pNext )
pLast =pLast->pNext;
pLast->pNext =pLoop;
}
else
pLoops = pLoop;
pLoop->pNext = NULL;
pLoop->pExitList = NULL;
pLoop->pLoopList = NULL;
pLoop->wOffset = functions.pLast->lPCodePos; /* store the start position */
pLoop->wLine = iLine;
}
/*
* Stores the position of LOOP statement to fix it later at the end of loop
*/
static void LoopLoop( void )
{
PTR_LOOPEXIT pLast, pLoop;
if( _wSeqCounter && _wSeqCounter >= _wWhileCounter )
{
/* Attempt to LOOP from BEGIN/END sequence
* Notice that LOOP is allowed in RECOVER code.
*/
GenError( _szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "LOOP", NULL );
}
pLoop = (PTR_LOOPEXIT) hb_xgrab( sizeof( LOOPEXIT ) );
pLoop->pLoopList =NULL;
pLoop->wOffset =functions.pLast->lPCodePos; /* store the position to fix */
pLast =pLoops;
while( pLast->pNext )
pLast =pLast->pNext;
while( pLast->pLoopList )
pLast =pLast->pLoopList;
pLast->pLoopList =pLoop;
Jump( 0 );
}
/*
* Stores the position of EXIT statement to fix it later at the end of loop
*/
static void LoopExit( void )
{
PTR_LOOPEXIT pLast, pLoop;
if( _wSeqCounter && _wSeqCounter >= _wWhileCounter )
{
/* Attempt to EXIT from BEGIN/END sequence
* Notice that EXIT is allowed in RECOVER code.
*/
GenError( _szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "EXIT", NULL );
}
pLoop = (PTR_LOOPEXIT) hb_xgrab( sizeof( LOOPEXIT ) );
pLoop->pExitList =NULL;
pLoop->wOffset =functions.pLast->lPCodePos; /* store the position to fix */
pLast =pLoops;
while( pLast->pNext )
pLast =pLast->pNext;
while( pLast->pExitList )
pLast =pLast->pExitList;
pLast->pExitList =pLoop;
Jump( 0 );
}
/*
* Fixes the LOOP statement
*/
static void LoopHere( void )
{
PTR_LOOPEXIT pLoop = pLoops, pFree;
while( pLoop->pNext )
pLoop = pLoop->pNext;
pLoop = pLoop->pLoopList;
while( pLoop )
{
JumpHere( pLoop->wOffset +1 );
pFree = pLoop;
pLoop = pLoop->pLoopList;
hb_xfree( ( void * ) pFree );
}
}
/*
* Fixes the EXIT statements and releases memory allocated for current loop
*/
static void LoopEnd( void )
{
PTR_LOOPEXIT pExit, pLoop = pLoops, pLast = pLoops, pFree;
while( pLoop->pNext )
{
pLast = pLoop;
pLoop = pLoop->pNext;
}
pExit =pLoop->pExitList;
while( pExit )
{
JumpHere( pExit->wOffset +1 );
pFree = pExit;
pExit = pExit->pExitList;
hb_xfree( ( void * ) pFree );
}
pLast->pNext = NULL;
if( pLoop == pLoops )
pLoops = NULL;
hb_xfree( ( void * ) pLoop );
}
#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 )
GenError( _szCErrors, 'E', ERR_MEMALLOC, NULL, NULL );
return pMem;
}
void * hb_xrealloc( void * pMem, ULONG ulSize ) /* reallocates memory */
{
void * pResult = realloc( pMem, ulSize );
if( ! pResult )
GenError( _szCErrors, 'E', ERR_MEMREALLOC, NULL, NULL );
return pResult;
}
void hb_xfree( void * pMem ) /* frees fixed memory */
{
if( pMem )
free( pMem );
else
GenError( _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;
}
#define SYM_NOLINK 0 /* Symbol does not have to be linked */
#define SYM_FUNC 1 /* Defined function */
#define SYM_EXTERN 2 /* Previously defined function */
void GenPortObj( char * szFileName, char * szName )
{
PFUNCTION pFunc /*= functions.pFirst */;
PCOMSYMBOL pSym = symbols.pFirst;
WORD w, wLen, wVar;
LONG lPCodePos;
LONG lPad;
LONG lSymbols;
BOOL bEndProcReq;
ULONG ulCodeLength;
FILE * yyc; /* file handle for C output */
HB_SYMBOL_UNUSED( szName );
yyc = fopen( szFileName, "wb" );
if( ! yyc )
{
printf( "Error opening file %s\n", szFileName );
return;
}
if( ! _bQuiet )
printf( "\nGenerating portable object...\n" );
/* writes the symbol table */
if( ! _bStartProc )
pSym = pSym->pNext; /* starting procedure is always the first symbol */
lSymbols = 0; /* Count number of symbols */
while( pSym )
{
lSymbols++;
pSym = pSym->pNext;
}
fputc( ( BYTE ) ( ( lSymbols ) & 255 ), yyc ); /* Write number symbols */
fputc( ( BYTE ) ( ( lSymbols >> 8 ) & 255 ), yyc );
fputc( ( BYTE ) ( ( lSymbols >> 16 ) & 255 ), yyc );
fputc( ( BYTE ) ( ( lSymbols >> 24 ) & 255 ), yyc );
pSym = symbols.pFirst;
if( ! _bStartProc )
pSym = pSym->pNext; /* starting procedure is always the first symbol */
while( pSym )
{
fputs( pSym->szName, yyc );
fputc( 0, yyc );
if( pSym->cScope != FS_MESSAGE )
fputc( pSym->cScope, yyc );
else
fputc( 0, yyc );
/* specify the function address if it is a defined function or a
external called function */
if( GetFunction( pSym->szName ) ) /* is it a defined function ? */
{
fputc( SYM_FUNC, yyc );
}
else
{
if( GetFuncall( pSym->szName ) )
{
fputc( SYM_EXTERN, yyc );
}
else
{
fputc( SYM_NOLINK, yyc );
}
}
pSym = pSym->pNext;
}
pFunc = functions.pFirst;
if( ! _bStartProc )
pFunc = pFunc->pNext;
lSymbols = 0; /* Count number of symbols */
while( pFunc )
{
lSymbols++;
pFunc = pFunc->pNext;
}
fputc( ( BYTE ) ( ( lSymbols ) & 255 ), yyc ); /* Write number symbols */
fputc( ( BYTE ) ( ( lSymbols >> 8 ) & 255 ), yyc );
fputc( ( BYTE ) ( ( lSymbols >> 16 ) & 255 ), yyc );
fputc( ( BYTE ) ( ( lSymbols >> 24 ) & 255 ), yyc );
/* Generate functions data
*/
pFunc = functions.pFirst;
if( ! _bStartProc )
pFunc = pFunc->pNext; /* No implicit starting procedure */
while( pFunc )
{
fputs( pFunc->szName, yyc );
fputc( 0, yyc );
/* We will have to add HB_P_ENDPROC in cases when RETURN statement
* was not used in a function/procedure - this is why we have to reserve
* one additional byte
*/
ulCodeLength =pFunc->lPCodePos +1;
fputc( ( BYTE ) ( ( ulCodeLength ) & 255 ), yyc ); /* Write size */
fputc( ( BYTE ) ( ( ulCodeLength >> 8 ) & 255 ), yyc );
fputc( ( BYTE ) ( ( ulCodeLength >> 16 ) & 255 ), yyc );
fputc( ( BYTE ) ( ( ulCodeLength >> 24 ) & 255 ), yyc );
/* printf( "Creating output for %s\n", pFunc->szName ); */
lPCodePos = 0;
lPad = 0; /* Number of bytes optimized */
bEndProcReq = TRUE;
while( lPCodePos < pFunc->lPCodePos )
{
switch( pFunc->pCode[ lPCodePos ] )
{
case HB_P_AND:
case HB_P_ARRAYAT:
case HB_P_ARRAYPUT:
case HB_P_DEC:
case HB_P_DIVIDE:
case HB_P_DUPLICATE:
case HB_P_DUPLTWO:
case HB_P_ENDBLOCK:
case HB_P_EQUAL:
case HB_P_EXACTLYEQUAL:
case HB_P_FALSE:
case HB_P_FORTEST:
case HB_P_FUNCPTR:
case HB_P_GREATER:
case HB_P_GREATEREQUAL:
case HB_P_INC:
case HB_P_INSTRING:
case HB_P_LESS:
case HB_P_LESSEQUAL:
case HB_P_MINUS:
case HB_P_MODULUS:
case HB_P_MULT:
case HB_P_NEGATE:
case HB_P_NOT:
case HB_P_NOTEQUAL:
case HB_P_OR:
case HB_P_PLUS:
case HB_P_POP:
case HB_P_POPALIAS:
case HB_P_POWER:
case HB_P_PUSHALIAS:
case HB_P_PUSHNIL:
case HB_P_PUSHSELF:
case HB_P_RETVALUE:
case HB_P_SWAPALIAS:
case HB_P_SEQRECOVER:
case HB_P_TRUE:
case HB_P_ZERO:
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
break;
case HB_P_DIMARRAY:
case HB_P_DO:
case HB_P_FUNCTION:
case HB_P_GENARRAY:
case HB_P_JUMP:
case HB_P_JUMPFALSE:
case HB_P_JUMPTRUE:
case HB_P_LINE:
case HB_P_POPLOCAL:
case HB_P_POPSTATIC:
case HB_P_PUSHINT:
case HB_P_PUSHLOCAL:
case HB_P_PUSHLOCALREF:
case HB_P_PUSHSTATIC:
case HB_P_PUSHSTATICREF:
case HB_P_SEQBEGIN:
case HB_P_SEQEND:
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
break;
case HB_P_ENDPROC:
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
if( lPCodePos == pFunc->lPCodePos )
bEndProcReq = FALSE;
break;
case HB_P_FRAME:
/* update the number of local variables */
{
PVAR pLocal = pFunc->pLocals;
BYTE bLocals = 0;
while( pLocal )
{
pLocal = pLocal->pNext;
bLocals++;
}
if( bLocals || pFunc->wParamCount )
{
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( ( BYTE )(bLocals - pFunc->wParamCount), yyc );
fputc( ( BYTE )(pFunc->wParamCount), yyc );
lPCodePos += 2;
}
else
{
lPad += 3;
lPCodePos += 3;
}
}
break;
case HB_P_PUSHSYM:
case HB_P_MESSAGE:
case HB_P_POPMEMVAR:
case HB_P_PUSHMEMVAR:
case HB_P_PUSHMEMVARREF:
case HB_P_POPFIELD:
case HB_P_PUSHFIELD:
case HB_P_POPALIASEDFIELD:
case HB_P_PUSHALIASEDFIELD:
fputc( pFunc->pCode[ lPCodePos ], yyc );
wVar =FixSymbolPos( pFunc->pCode[ lPCodePos+1 ] + 256 * pFunc->pCode[ lPCodePos+2 ] );
fputc( LOBYTE( wVar ), yyc );
fputc( HIBYTE( wVar ), yyc );
lPCodePos +=3;
break;
case HB_P_PARAMETER:
fputc( pFunc->pCode[ lPCodePos ], yyc );
wVar = FixSymbolPos( pFunc->pCode[ lPCodePos+1 ] + 256 * pFunc->pCode[ lPCodePos+2 ] );
fputc( LOBYTE( wVar ), yyc );
fputc( HIBYTE( wVar ), yyc );
fputc( pFunc->pCode[ lPCodePos+3 ], yyc );
lPCodePos +=4;
break;
case HB_P_PUSHBLOCK:
wVar = * ( ( WORD * ) &( pFunc->pCode [ lPCodePos + 5 ] ) );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
/* create the table of referenced local variables */
while( wVar-- )
{
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
}
break;
case HB_P_PUSHDOUBLE:
{
int i;
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
for( i = 0; i < sizeof( double ); ++i )
fputc( ( ( BYTE * ) pFunc->pCode )[ lPCodePos + i ], yyc );
fputc( pFunc->pCode[ lPCodePos + sizeof( double ) ], yyc );
lPCodePos += sizeof( double ) + 1;
}
break;
case HB_P_PUSHLONG:
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
break;
case HB_P_PUSHSTR:
wLen = pFunc->pCode[ lPCodePos + 1 ] +
pFunc->pCode[ lPCodePos + 2 ] * 256;
fputc( pFunc->pCode[ lPCodePos ], yyc );
fputc( pFunc->pCode[ lPCodePos + 1 ], yyc );
fputc( pFunc->pCode[ lPCodePos + 2 ], yyc );
lPCodePos +=3;
while( wLen-- )
{
fputc( pFunc->pCode[ lPCodePos ++ ], yyc );
}
break;
case HB_P_SFRAME:
/* we only generate it if there are statics used in this function */
if( pFunc->bFlags & FUN_USES_STATICS )
{
GetSymbol( _pInitFunc->szName, &w );
w = FixSymbolPos( w );
fputc( pFunc->pCode[ lPCodePos ], yyc );
fputc( LOBYTE( w ), yyc );
fputc( HIBYTE( w ), yyc );
}
else
lPad += 3;
lPCodePos += 3;
break;
case HB_P_STATICS:
GetSymbol( _pInitFunc->szName, &w );
w = FixSymbolPos( w );
fputc( pFunc->pCode[ lPCodePos ], yyc );
fputc( LOBYTE( w ), yyc );
fputc( HIBYTE( w ), yyc );
lPCodePos += 3;
break;
default:
printf( "Incorrect pcode value: %u\n", pFunc->pCode[ lPCodePos ] );
lPCodePos = pFunc->lPCodePos;
break;
}
}
if( bEndProcReq )
fputc( HB_P_ENDPROC, yyc );
else
{
/* HB_P_ENDPROC was the last opcode: we have to fill the byte
* reserved earlier
*/
lPad++;
}
for( ; lPad; lPad-- )
{
/* write additional bytes to agree with stored earlier
* function/procedure size
*/
fputc( 0, yyc );
}
pFunc = pFunc->pNext;
}
fclose( yyc );
if( ! _bQuiet )
printf( "%s -> done!\n", szFileName );
}
typedef struct
{
char * cFuncName; /* function name */
int iMinParam; /* min no of parms it needs */
/* iMinParam = -1, means no checking */
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 CheckArgs( 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 );
GenError( _szCErrors, 'E', ERR_CHECKING_ARGS, szFuncCall, szMsg );
/* Clipper way */
/* GenError( _szCErrors, 'E', ERR_CHECKING_ARGS, szFuncCall, NULL ); */
}
}
}