1431 lines
56 KiB
Plaintext
1431 lines
56 KiB
Plaintext
%{
|
|
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* Compiler YACC rules and actions
|
|
*
|
|
* Copyright 1999 Antonio Linares <alinares@fivetech.com>
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version, with one exception:
|
|
*
|
|
* The exception is that if you link the Harbour Runtime Library (HRL)
|
|
* and/or the Harbour Virtual Machine (HVM) with other files to produce
|
|
* an executable, this does not by itself cause the resulting executable
|
|
* to be covered by the GNU General Public License. Your use of that
|
|
* executable is in no way restricted on account of linking the HRL
|
|
* and/or HVM code into it.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
|
|
* their web site at http://www.gnu.org/).
|
|
*
|
|
*/
|
|
|
|
/* TODO list
|
|
* 1) jumps longer then 2^15 bytes
|
|
* 2) macro support
|
|
* 3) correct support for undeclared variables (all variables are assumed
|
|
* memvars now - we should add runtime recognition of variable type)
|
|
* - work in progress (rglab@imid.med.pl)
|
|
* 4) in some cases incorrect warnings are generated when -w option is used
|
|
* 5) in some cases GPF occurs when -w option is used, example:
|
|
* LOCAL nDouble := NumAnd32(RandGetLong() / 65536, 32767) / 997
|
|
* 6) support for expr:expr (QSELF():cVar) syntax.
|
|
* see tests/broken/clasname.prg
|
|
* 7) Change the pcode generated by ::cVar from Self:cVar to QSELF():cVar
|
|
* 8) Support this syntax: _FIELD->c->mmezo := mt
|
|
* 9) Support this syntax: nPtr := @Hello()
|
|
*10) Support for syntax: FOR [ array | object | alias_expr | other ] := value
|
|
*/
|
|
|
|
#include "compiler.h"
|
|
|
|
/* Compile using: bison -d -v harbour.y */
|
|
|
|
extern FILE *yyin; /* currently yacc parsed file */
|
|
extern int iLine; /* currently parsed file line number */
|
|
extern char *yytext;
|
|
|
|
#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
|
|
|
|
/* 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
|
|
|
|
static void LoopStart( void );
|
|
static void LoopEnd( void );
|
|
static void LoopLoop( void );
|
|
static void LoopExit( void );
|
|
static void LoopHere( void );
|
|
|
|
|
|
/* Misc functions defined in harbour.c */
|
|
extern PHB_FNAME hb_fsFNameSplit( char * szFileName );
|
|
extern char * hb_fsFNameMerge( char * szFileName, PHB_FNAME pFileName );
|
|
extern void * hb_xgrab( ULONG ulSize ); /* allocates fixed memory, exits on failure */
|
|
extern void * hb_xrealloc( void * pMem, ULONG ulSize ); /* reallocates memory */
|
|
extern void hb_xfree( void * pMem ); /* frees fixed memory */
|
|
extern char * yy_strupr( char * p );
|
|
extern char * yy_strdup( char * p );
|
|
extern void hb_compGenError( char* _szErrors[], char cPrefix, int iError, char * szError1, char * szError2 );
|
|
extern void hb_compGenWarning( char* _szWarnings[], char cPrefix, int iWarning, char * szWarning1, char * szWarning2);
|
|
|
|
|
|
#ifdef HARBOUR_YYDEBUG
|
|
#define YYDEBUG 1 /* Parser debug information support */
|
|
#endif
|
|
|
|
|
|
USHORT hb_comp_wSeqCounter = 0;
|
|
USHORT hb_comp_wForCounter = 0;
|
|
USHORT hb_comp_wIfCounter = 0;
|
|
USHORT hb_comp_wWhileCounter = 0;
|
|
USHORT hb_comp_wCaseCounter = 0;
|
|
|
|
%}
|
|
|
|
%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 temporary integer number */
|
|
long lNumber; /* to hold a temporary long number */
|
|
struct
|
|
{
|
|
int iNumber; /* to hold a number returned by lex */
|
|
char * szValue;
|
|
} valInteger;
|
|
struct
|
|
{
|
|
long lNumber; /* to hold a long number returned by lex */
|
|
char * szValue;
|
|
} valLong;
|
|
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 */
|
|
char * szValue;
|
|
} valDouble;
|
|
HB_EXPR_PTR asExpr;
|
|
void * pVoid; /* to hold any memory structure we may need */
|
|
};
|
|
|
|
%token FUNCTION PROCEDURE IDENTIFIER RETURN NIL NUM_DOUBLE INASSIGN NUM_INTEGER NUM_LONG
|
|
%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 ALIASOP 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
|
|
%right UNARY
|
|
/*preincrement and predecrement*/
|
|
%left PRE
|
|
/*special operators*/
|
|
%left ALIASOP '&' '@'
|
|
%right '\n' ';' ','
|
|
/*the highest precedence*/
|
|
|
|
%type <string> IDENTIFIER LITERAL
|
|
%type <valDouble> NUM_DOUBLE
|
|
%type <valInteger> NUM_INTEGER
|
|
%type <valLong> NUM_LONG
|
|
%type <iNumber> FunScope AsType
|
|
%type <iNumber> Params ParamList
|
|
%type <iNumber> IfBegin VarList
|
|
%type <iNumber> FieldList DoArgList
|
|
%type <lNumber> WhileBegin
|
|
%type <pVoid> IfElseIf Cases
|
|
%type <asExpr> Argument ArgList ElemList BlockExpList BlockVarList BlockNoVar
|
|
%type <asExpr> PareExpList1 PareExpList2 PareExpList3 PareExpListN
|
|
%type <asExpr> ExpList ExpList1 ExpList2 ExpList3
|
|
%type <asExpr> NumValue NumAlias
|
|
%type <asExpr> NilValue NilAlias
|
|
%type <asExpr> LiteralValue LiteralAlias
|
|
%type <asExpr> CodeBlock CodeBlockAlias
|
|
%type <asExpr> Logical LogicalAlias
|
|
%type <asExpr> SelfValue SelfAlias
|
|
%type <asExpr> Array ArrayAlias
|
|
%type <asExpr> ArrayAt ArrayAtAlias
|
|
%type <asExpr> Variable VarAlias
|
|
%type <asExpr> MacroVar MacroVarAlias
|
|
%type <asExpr> MacroExpr MacroExprAlias
|
|
%type <asExpr> AliasVar AliasExpr
|
|
%type <asExpr> VariableAt VariableAtAlias
|
|
%type <asExpr> FunCall FunCallAlias
|
|
%type <asExpr> ObjectData ObjectDataAlias
|
|
%type <asExpr> ObjectMethod ObjectMethodAlias
|
|
%type <asExpr> IfInline IfInlineAlias
|
|
%type <asExpr> PareExpList PareExpListAlias
|
|
%type <asExpr> Expression SimpleExpression LValue
|
|
%type <asExpr> EmptyExpression
|
|
%type <asExpr> ExprAssign ExprOperEq ExprEqual ExprPreOp ExprPostOp
|
|
%type <asExpr> ExprEqual ExprMath ExprBool ExprRelation
|
|
%type <asExpr> ArrayIndex IndexList
|
|
%type <asExpr> DimIndex DimList
|
|
%type <asExpr> FieldAlias FieldVarAlias
|
|
%type <asExpr> PostOp
|
|
|
|
%%
|
|
|
|
Main : { Line(); } Source {
|
|
FixReturns(); /* fix all previous function returns offsets */
|
|
if( ! hb_comp_bQuiet )
|
|
{
|
|
if( ! hb_comp_bStartProc )
|
|
--hb_comp_iFunctionCnt;
|
|
printf( "\rLines %i, Functions/Procedures %i\n", iLine, hb_comp_iFunctionCnt );
|
|
}
|
|
}
|
|
|
|
Source : Crlf
|
|
| VarDefs
|
|
| FieldsDef
|
|
| MemvarDef
|
|
| Function
|
|
| Statement
|
|
| Line
|
|
| Source Crlf
|
|
| Source Function
|
|
| Source Statement
|
|
| Source VarDefs
|
|
| Source FieldsDef
|
|
| Source MemvarDef
|
|
| Source Line
|
|
;
|
|
|
|
Line : LINE NUM_INTEGER LITERAL Crlf
|
|
| LINE NUM_INTEGER LITERAL '@' LITERAL Crlf /* XBase++ style */
|
|
;
|
|
|
|
Function : FunScope FUNCTION IDENTIFIER { hb_comp_cVarType = ' '; hb_compFunDef( $3, ( HB_SYMBOLSCOPE ) $1, 0 ); } Params Crlf {}
|
|
| FunScope PROCEDURE IDENTIFIER { hb_comp_cVarType = ' '; hb_compFunDef( $3, ( HB_SYMBOLSCOPE ) $1, FUN_PROCEDURE ); } Params Crlf {}
|
|
| FunScope DECLARE_FUN IDENTIFIER Params AsType Crlf { hb_compAddSymbol( $3, NULL ); }
|
|
;
|
|
|
|
FunScope : { $$ = FS_PUBLIC; }
|
|
| STATIC { $$ = FS_STATIC; }
|
|
| INIT { $$ = FS_INIT; }
|
|
| EXIT { $$ = FS_EXIT; }
|
|
;
|
|
|
|
Params : { $$ = 0; }
|
|
| '(' ')' { $$ = 0; }
|
|
| '(' { hb_comp_iVarScope = VS_PARAMETER; } ParamList ')' { $$ = $3; }
|
|
;
|
|
|
|
AsType : /* not specified */ { hb_comp_cVarType = ' '; }
|
|
| AS_NUMERIC { hb_comp_cVarType = 'N'; }
|
|
| AS_CHARACTER { hb_comp_cVarType = 'C'; }
|
|
| AS_DATE { hb_comp_cVarType = 'D'; }
|
|
| AS_LOGICAL { hb_comp_cVarType = 'L'; }
|
|
| AS_ARRAY { hb_comp_cVarType = 'A'; }
|
|
| AS_BLOCK { hb_comp_cVarType = 'B'; }
|
|
| AS_OBJECT { hb_comp_cVarType = 'O'; }
|
|
;
|
|
|
|
ParamList : IDENTIFIER AsType { hb_compAddVar( $1, ' ' ); $$ = 1; }
|
|
| ParamList ',' IDENTIFIER AsType { hb_compAddVar( $3, $4 ); $$++; }
|
|
;
|
|
|
|
/* NOTE: This alllows the use of Expression as a statement.
|
|
* The Expression is validated later in reduction phase of
|
|
* hb_compExprGenStatement(). With this solution we don't have to
|
|
* stop compilation if invalid syntax will be used.
|
|
*/
|
|
Statement : ExecFlow CrlfStmnt { }
|
|
| Expression { hb_compExprDelete( hb_compExprGenStatement( $1 ) ); } CrlfStmnt
|
|
| BREAK { hb_compGenBreak(); } CrlfStmnt { hb_compGenDoProc( 0 ); }
|
|
| BREAK { hb_compGenBreak(); } Expression CrlfStmnt { hb_compExprDelete( hb_compExprGenPush( $3 ) ); hb_compGenDoProc( 1 ); }
|
|
| RETURN CrlfStmnt {
|
|
if( hb_comp_wSeqCounter )
|
|
{
|
|
hb_compGenError( hb_comp_szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "RETURN", NULL );
|
|
}
|
|
hb_compGenPCode1( HB_P_ENDPROC );
|
|
if( (hb_comp_functions.pLast->bFlags & FUN_PROCEDURE) == 0 )
|
|
{ /* return from a function without a return value */
|
|
hb_compGenWarning( hb_comp_szCWarnings, 'W', WARN_NO_RETURN_VALUE, NULL, NULL );
|
|
}
|
|
hb_comp_functions.pLast->bFlags |= FUN_WITH_RETURN;
|
|
hb_comp_bDontGenLineNum = TRUE;
|
|
}
|
|
| RETURN Expression CrlfStmnt {
|
|
if( hb_comp_wSeqCounter )
|
|
{
|
|
hb_compGenError( hb_comp_szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "RETURN", NULL );
|
|
}
|
|
hb_compExprGenPush( $2 ); /* TODO: check if return value agree with declared value */
|
|
hb_compGenPCode1( HB_P_RETVALUE );
|
|
hb_compGenPCode1( HB_P_ENDPROC );
|
|
if( hb_comp_functions.pLast->bFlags & FUN_PROCEDURE )
|
|
{ /* procedure returns a value */
|
|
hb_compGenWarning( hb_comp_szCWarnings, 'W', WARN_PROC_RETURN_VALUE, NULL, NULL );
|
|
}
|
|
hb_comp_functions.pLast->bFlags |= FUN_WITH_RETURN;
|
|
hb_comp_bDontGenLineNum = TRUE;
|
|
}
|
|
| PUBLIC { hb_comp_iVarScope = VS_PUBLIC; } VarList CrlfStmnt
|
|
| PRIVATE { hb_comp_iVarScope = VS_PRIVATE; } VarList CrlfStmnt
|
|
|
|
| EXITLOOP CrlfStmnt { LoopExit(); }
|
|
| LOOP CrlfStmnt { LoopLoop(); }
|
|
| DoProc CrlfStmnt
|
|
| EXTERN { hb_comp_bExternal = TRUE; } ExtList CrlfStmnt
|
|
;
|
|
|
|
CrlfStmnt : { LineBody(); } Crlf
|
|
;
|
|
|
|
LineStat : Crlf { $<lNumber>$ = 0; }
|
|
| Statement { $<lNumber>$ = 1; }
|
|
;
|
|
|
|
Statements : LineStat { $<lNumber>$ = $<lNumber>1; }
|
|
| Statements { Line(); } LineStat { $<lNumber>$ += $<lNumber>3; }
|
|
;
|
|
|
|
ExtList : IDENTIFIER { hb_compAddExtern( $1 ); }
|
|
| ExtList ',' IDENTIFIER { hb_compAddExtern( $3 ); }
|
|
;
|
|
|
|
/* Numeric values
|
|
*/
|
|
NumValue : NUM_DOUBLE { $$ = hb_compExprNewDouble( $1.dNumber, $1.bDec ); }
|
|
| NUM_INTEGER { $$ = hb_compExprNewLong( $1.iNumber ); }
|
|
| NUM_LONG { $$ = hb_compExprNewLong( $1.lNumber ); }
|
|
;
|
|
|
|
NumAlias : NUM_INTEGER ALIASOP { $$ = hb_compExprNewLong( $1.iNumber ); }
|
|
| NUM_LONG ALIASOP { $$ = hb_compExprNewLong( $1.lNumber ); }
|
|
| NUM_DOUBLE ALIASOP { $$ = hb_compErrorAlias( hb_compExprNewDouble( $1.dNumber, $1.bDec ) ); }
|
|
;
|
|
|
|
/* NIL value
|
|
*/
|
|
NilValue : NIL { $$ = hb_compExprNewNil(); }
|
|
;
|
|
|
|
NilAlias : NilValue ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Literal string value
|
|
*/
|
|
LiteralValue : LITERAL { $$ = hb_compExprNewString( $1 ); }
|
|
;
|
|
|
|
LiteralAlias : LiteralValue ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Codeblock value
|
|
*/
|
|
CodeBlockAlias : CodeBlock ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Logical value
|
|
*/
|
|
Logical : TRUEVALUE { $$ = hb_compExprNewLogical( TRUE ); }
|
|
| FALSEVALUE { $$ = hb_compExprNewLogical( FALSE ); }
|
|
;
|
|
|
|
LogicalAlias : Logical ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* SELF value and expressions
|
|
*/
|
|
SelfValue : SELF { $$ = hb_compExprNewSelf(); }
|
|
;
|
|
|
|
SelfAlias : SelfValue ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Literal array
|
|
*/
|
|
Array : '{' ElemList '}' { $$ = hb_compExprNewArray( $2 ); }
|
|
;
|
|
|
|
ArrayAlias : Array ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Literal array access
|
|
*/
|
|
ArrayAt : Array ArrayIndex { $$ = $2; }
|
|
;
|
|
|
|
ArrayAtAlias : ArrayAt ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Variables
|
|
*/
|
|
Variable : IDENTIFIER { $$ = hb_compExprNewVar( $1 ); }
|
|
;
|
|
|
|
VarAlias : IDENTIFIER ALIASOP { $$ = hb_compExprNewSymbol( $1 ); }
|
|
;
|
|
|
|
/* Macro variables
|
|
*/
|
|
MacroVar : '&' IDENTIFIER { hb_compExprNewMacro( hb_compExprNewVar( $2 ), NULL ); }
|
|
| '&' IDENTIFIER '.' { hb_compExprNewMacro( hb_compExprNewVar( $2 ), NULL ); }
|
|
| '&' IDENTIFIER '.' IDENTIFIER { hb_compExprNewMacro( hb_compExprNewVar( $2 ), $4 ); }
|
|
| '&' IDENTIFIER '.' NUM_INTEGER { hb_compExprNewMacro( hb_compExprNewVar( $2 ), $4.szValue ); }
|
|
| '&' IDENTIFIER '.' NUM_LONG { hb_compExprNewMacro( hb_compExprNewVar( $2 ), $4.szValue ); }
|
|
;
|
|
|
|
MacroVarAlias : MacroVar ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Macro expressions
|
|
*/
|
|
MacroExpr : '&' PareExpList { $$ = hb_compExprNewMacro( $2, NULL ); }
|
|
;
|
|
|
|
MacroExprAlias : MacroExpr ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Aliased variables
|
|
*/
|
|
/* special case: _FIELD-> and FIELD-> can be nested
|
|
*/
|
|
FieldAlias : FIELD ALIASOP { $$ = hb_compExprNewSymbol( "FIELD" ); }
|
|
| FIELD ALIASOP FieldAlias { $$ = $3; }
|
|
;
|
|
|
|
/* ignore _FIELD-> or FIELD-> if a real alias is specified
|
|
*/
|
|
FieldVarAlias : FieldAlias VarAlias { hb_compExprDelete( $1 ); $$ = $2; }
|
|
| FieldAlias NumAlias { hb_compExprDelete( $1 ); $$ = $2; }
|
|
| FieldAlias PareExpListAlias { hb_compExprDelete( $1 ); $$ = $2; }
|
|
| FieldAlias MacroVarAlias { hb_compExprDelete( $1 ); $$ = $2; }
|
|
| FieldAlias MacroExprAlias { hb_compExprDelete( $1 ); $$ = $2; }
|
|
| FieldAlias NilAlias { hb_compExprDelete( $1 ); $$ = hb_compErrorAlias( $2 ); }
|
|
| FieldAlias LiteralAlias { hb_compExprDelete( $1 ); $$ = hb_compErrorAlias( $2 ); }
|
|
| FieldAlias LogicalAlias { hb_compExprDelete( $1 ); $$ = hb_compErrorAlias( $2 ); }
|
|
| FieldAlias CodeBlockAlias { hb_compExprDelete( $1 ); $$ = hb_compErrorAlias( $2 ); }
|
|
| FieldAlias SelfAlias { hb_compExprDelete( $1 ); $$ = hb_compErrorAlias( $2 ); }
|
|
| FieldAlias ArrayAlias { hb_compExprDelete( $1 ); $$ = hb_compErrorAlias( $2 ); }
|
|
| FieldAlias ArrayAtAlias { hb_compExprDelete( $1 ); $$ = hb_compErrorAlias( $2 ); }
|
|
| FieldAlias IfInlineAlias { hb_compExprDelete( $1 ); $$ = hb_compErrorAlias( $2 ); }
|
|
;
|
|
|
|
AliasVar : NumAlias IDENTIFIER { $$ = hb_compExprNewAliasVar( $1, $2 ); }
|
|
| MacroVarAlias IDENTIFIER { $$ = hb_compExprNewAliasVar( $1, $2 ); }
|
|
| MacroExprAlias IDENTIFIER { $$ = hb_compExprNewAliasVar( $1, $2 ); }
|
|
| PareExpListAlias IDENTIFIER { $$ = hb_compExprNewAliasVar( $1, $2 ); }
|
|
| NilAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); }
|
|
| LiteralAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); }
|
|
| LogicalAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); }
|
|
| CodeBlockAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); }
|
|
| SelfAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); }
|
|
| ArrayAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); }
|
|
| ArrayAtAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); } /* QUESTION: Clipper reports error here - we can handle this */
|
|
| VariableAtAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); } /* QUESTION: Clipper reports error here - we can handle this */
|
|
| IfInlineAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); } /* QUESTION: Clipper reports error here - we can handle this */
|
|
| FunCallAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); } /* QUESTION: Clipper reports error here - we can handle this */
|
|
| ObjectDataAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); } /* QUESTION: Clipper reports error here - we can handle this */
|
|
| ObjectMethodAlias IDENTIFIER { $$ = hb_compErrorAlias( $1 ); } /* QUESTION: Clipper reports error here - we can handle this */
|
|
| VarAlias IDENTIFIER { $$ = hb_compExprNewAliasVar( $1, $2 ); }
|
|
| FieldAlias IDENTIFIER { $$ = hb_compExprNewAliasVar( $1, $2 ); }
|
|
| FieldVarAlias IDENTIFIER { $$ = hb_compExprNewAliasVar( $1, $2 ); }
|
|
;
|
|
|
|
/* Aliased expressions
|
|
*/
|
|
/* NOTE: In the case:
|
|
* alias->( Expression )
|
|
* alias always selects a workarea at runtime
|
|
*/
|
|
AliasExpr : NumAlias PareExpList { $$ = hb_compExprNewAliasExpr( $1, hb_compExprReduce( $2 ) ); }
|
|
| VarAlias PareExpList { $$ = hb_compExprNewAliasExpr( $1, hb_compExprReduce( $2 ) ); }
|
|
| MacroVarAlias PareExpList { $$ = hb_compExprNewAliasExpr( $1, hb_compExprReduce( $2 ) ); }
|
|
| MacroExprAlias PareExpList { $$ = hb_compExprNewAliasExpr( $1, hb_compExprReduce( $2 ) ); }
|
|
| PareExpListAlias PareExpList { $$ = hb_compExprNewAliasExpr( $1, hb_compExprReduce( $2 ) ); }
|
|
| FieldAlias PareExpList { $$ = hb_compErrorAlias( $2 ); } /* QUESTION: Clipper reports error here - we can handle it */
|
|
;
|
|
|
|
/* Array expressions access
|
|
*/
|
|
VariableAt : NilValue ArrayIndex { $$ = $2; }
|
|
| LiteralValue ArrayIndex { $$ = $2; }
|
|
| CodeBlock ArrayIndex { $$ = $2; }
|
|
| Logical ArrayIndex { $$ = $2; }
|
|
| SelfValue ArrayIndex { $$ = $2; }
|
|
| Variable ArrayIndex { $$ = $2; }
|
|
| AliasVar ArrayIndex { $$ = $2; }
|
|
| AliasExpr ArrayIndex { $$ = $2; }
|
|
| MacroVar ArrayIndex { $$ = $2; }
|
|
| MacroExpr ArrayIndex { $$ = $2; }
|
|
| ObjectData ArrayIndex { $$ = $2; }
|
|
| ObjectMethod ArrayIndex { $$ = $2; }
|
|
| FunCall ArrayIndex { $$ = $2; }
|
|
| IfInline ArrayIndex { $$ = $2; }
|
|
| PareExpList ArrayIndex { $$ = $2; }
|
|
;
|
|
|
|
VariableAtAlias : VariableAt ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Function call
|
|
*/
|
|
FunCall : IDENTIFIER '(' ArgList ')' { $$ = hb_compExprNewFunCall( $1, $3 ); }
|
|
;
|
|
|
|
ArgList : Argument { $$ = hb_compExprNewArgList( $1 ); }
|
|
| ArgList ',' Argument { $$ = hb_compExprAddListExpr( $1, $3 ); }
|
|
;
|
|
|
|
Argument : EmptyExpression { $$ = $1; }
|
|
| '@' IDENTIFIER { $$ = hb_compExprNewVarRef( $2 ); }
|
|
| '@' IDENTIFIER '(' ')' { $$ = hb_compExprNewFunRef( $2 ); }
|
|
;
|
|
|
|
FunCallAlias : FunCall ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Object's instance variable
|
|
*/
|
|
ObjectData : NumValue ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| NilValue ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| LiteralValue ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| CodeBlock ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| Logical ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| SelfValue ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| Array ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| ArrayAt ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| Variable ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| AliasVar ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| AliasExpr ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| MacroVar ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| MacroExpr ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| FunCall ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| IfInline ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| PareExpList ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| VariableAt ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| ObjectMethod ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
| ObjectData ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); }
|
|
;
|
|
|
|
ObjectDataAlias : ObjectData ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* Object's method
|
|
*/
|
|
ObjectMethod : ObjectData '(' ArgList ')' { $$ = hb_compExprNewMethodCall( $1, $3 ); }
|
|
;
|
|
|
|
ObjectMethodAlias : ObjectMethod ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
/* NOTE: We have to distinguish IDENTIFIER here because it is repeated
|
|
* in DoExpression (a part of DO <proc> WITH .. statement)
|
|
* where it generates different action.
|
|
*/
|
|
SimpleExpression :
|
|
NumValue
|
|
| NilValue { $$ = $1; }
|
|
| LiteralValue { $$ = $1; }
|
|
| CodeBlock { $$ = $1; }
|
|
| Logical { $$ = $1; }
|
|
| SelfValue { $$ = $1; }
|
|
| Array { $$ = $1; }
|
|
| ArrayAt { $$ = $1; }
|
|
| AliasVar { $$ = $1; }
|
|
| MacroVar { $$ = $1; }
|
|
| MacroExpr { $$ = $1; }
|
|
| VariableAt { $$ = $1; }
|
|
| FunCall { $$ = $1; }
|
|
| IfInline { $$ = $1; }
|
|
| ObjectData { $$ = $1; }
|
|
| ObjectMethod { $$ = $1; }
|
|
| AliasExpr { $$ = $1; }
|
|
| ExprAssign { $$ = $1; }
|
|
| ExprOperEq { $$ = $1; }
|
|
| ExprEqual { $$ = $1; }
|
|
| ExprPostOp { $$ = $1; }
|
|
| ExprPreOp { $$ = $1; }
|
|
| ExprMath { $$ = $1; }
|
|
| ExprBool { $$ = $1; }
|
|
| ExprRelation { $$ = $1; }
|
|
;
|
|
|
|
Expression : Variable { $$ = $1; }
|
|
| SimpleExpression { $$ = $1; }
|
|
| PareExpList { $$ = $1; }
|
|
;
|
|
|
|
EmptyExpression: /* nothing => nil */ { $$ = hb_compExprNewEmpty(); }
|
|
| Expression
|
|
;
|
|
|
|
LValue : IDENTIFIER { $$ = hb_compExprNewVar( $1 ); }
|
|
| AliasVar
|
|
| MacroVar
|
|
| MacroExpr
|
|
| ObjectData
|
|
| VariableAt
|
|
;
|
|
|
|
/* NOTE: PostOp can be used in one context only - it uses $0 rule
|
|
* (the rule that stands before PostOp)
|
|
*/
|
|
PostOp : INC { $$ = hb_compExprNewPostInc( $<asExpr>0 ); }
|
|
| DEC { $$ = hb_compExprNewPostDec( $<asExpr>0 ); }
|
|
;
|
|
|
|
/* NOTE: We cannot use 'Expression PostOp' because it caused
|
|
* shift/reduce conflicts
|
|
*/
|
|
ExprPostOp : NumValue PostOp %prec POST { $$ = $2; }
|
|
| NilValue PostOp %prec POST { $$ = $2; }
|
|
| LiteralValue PostOp %prec POST { $$ = $2; }
|
|
| CodeBlock PostOp %prec POST { $$ = $2; }
|
|
| Logical PostOp %prec POST { $$ = $2; }
|
|
| SelfValue PostOp %prec POST { $$ = $2; }
|
|
| Array PostOp %prec POST { $$ = $2; }
|
|
| ArrayAt PostOp %prec POST { $$ = $2; }
|
|
| Variable PostOp %prec POST { $$ = $2; }
|
|
| MacroVar PostOp %prec POST { $$ = $2; }
|
|
| MacroExpr PostOp %prec POST { $$ = $2; }
|
|
| AliasVar PostOp %prec POST { $$ = $2; }
|
|
| AliasExpr PostOp %prec POST { $$ = $2; }
|
|
| VariableAt PostOp %prec POST { $$ = $2; }
|
|
| PareExpList PostOp %prec POST { $$ = $2; }
|
|
| IfInline PostOp %prec POST { $$ = $2; }
|
|
| FunCall PostOp %prec POST { $$ = $2; }
|
|
| ObjectData PostOp %prec POST { $$ = $2; }
|
|
| ObjectMethod PostOp %prec POST { $$ = $2; }
|
|
;
|
|
|
|
ExprPreOp : INC Expression %prec PRE { $$ = hb_compExprNewPreInc( $2 ); }
|
|
| DEC Expression %prec PRE { $$ = hb_compExprNewPreDec( $2 ); }
|
|
| NOT Expression %prec UNARY { $$ = hb_compExprNewNot( $2 ); }
|
|
| '-' Expression %prec UNARY { $$ = hb_compExprNewNegate( $2 ); }
|
|
| '+' Expression %prec UNARY { $$ = $2; }
|
|
;
|
|
|
|
ExprAssign : Expression INASSIGN Expression { $$ = hb_compExprAssign( $1, $3 ); }
|
|
;
|
|
|
|
ExprOperEq : Expression PLUSEQ Expression { $$ = hb_compExprSetOperand( hb_compExprNewPlusEq( $1 ), $3 ); }
|
|
| Expression MINUSEQ Expression { $$ = hb_compExprSetOperand( hb_compExprNewMinusEq( $1 ), $3 ); }
|
|
| Expression MULTEQ Expression { $$ = hb_compExprSetOperand( hb_compExprNewMultEq( $1 ), $3 ); }
|
|
| Expression DIVEQ Expression { $$ = hb_compExprSetOperand( hb_compExprNewDivEq( $1 ), $3 ); }
|
|
| Expression MODEQ Expression { $$ = hb_compExprSetOperand( hb_compExprNewModEq( $1 ), $3 ); }
|
|
| Expression EXPEQ Expression { $$ = hb_compExprSetOperand( hb_compExprNewExpEq( $1 ), $3 ); }
|
|
;
|
|
|
|
ExprEqual : Expression '=' Expression { $$ = hb_compExprSetOperand( hb_compExprNewEqual( $1 ), $3 ); }
|
|
;
|
|
|
|
ExprMath : Expression '+' Expression { $$ = hb_compExprSetOperand( hb_compExprNewPlus( $1 ), $3 ); }
|
|
| Expression '-' Expression { $$ = hb_compExprSetOperand( hb_compExprNewMinus( $1 ), $3 ); }
|
|
| Expression '*' Expression { $$ = hb_compExprSetOperand( hb_compExprNewMult( $1 ), $3 ); }
|
|
| Expression '/' Expression { $$ = hb_compExprSetOperand( hb_compExprNewDiv( $1 ), $3 ); }
|
|
| Expression '%' Expression { $$ = hb_compExprSetOperand( hb_compExprNewMod( $1 ), $3 ); }
|
|
| Expression POWER Expression { $$ = hb_compExprSetOperand( hb_compExprNewPower( $1 ), $3 ); }
|
|
;
|
|
|
|
ExprBool : Expression AND Expression { $$ = hb_compExprSetOperand( hb_compExprNewAnd( $1 ), $3 ); }
|
|
| Expression OR Expression { $$ = hb_compExprSetOperand( hb_compExprNewOr( $1 ), $3 ); }
|
|
;
|
|
|
|
ExprRelation: Expression EQ Expression { $$ = hb_compExprSetOperand( hb_compExprNewEQ( $1 ), $3 ); }
|
|
| Expression '<' Expression { $$ = hb_compExprSetOperand( hb_compExprNewLT( $1 ), $3 ); }
|
|
| Expression '>' Expression { $$ = hb_compExprSetOperand( hb_compExprNewGT( $1 ), $3 ); }
|
|
| Expression LE Expression { $$ = hb_compExprSetOperand( hb_compExprNewLE( $1 ), $3 ); }
|
|
| Expression GE Expression { $$ = hb_compExprSetOperand( hb_compExprNewGE( $1 ), $3 ); }
|
|
| Expression NE1 Expression { $$ = hb_compExprSetOperand( hb_compExprNewNE( $1 ), $3 ); }
|
|
| Expression NE2 Expression { $$ = hb_compExprSetOperand( hb_compExprNewNE( $1 ), $3 ); }
|
|
| Expression '$' Expression { $$ = hb_compExprSetOperand( hb_compExprNewIN( $1 ), $3 ); }
|
|
;
|
|
|
|
ArrayIndex : IndexList ']' { $$ = $1; }
|
|
;
|
|
|
|
/* NOTE: $0 represents the expression before ArrayIndex
|
|
* Don't use ArrayIndex in other context than as an array index!
|
|
*/
|
|
IndexList : '[' Expression { $$ = hb_compExprNewArrayAt( $<asExpr>0, $2 ); }
|
|
| IndexList ',' Expression { $$ = hb_compExprNewArrayAt( $1, $3 ); }
|
|
| IndexList ']' '[' Expression { $$ = hb_compExprNewArrayAt( $1, $4 ); }
|
|
;
|
|
|
|
ElemList : EmptyExpression { $$ = hb_compExprNewList( $1 ); }
|
|
| ElemList ',' EmptyExpression { $$ = hb_compExprAddListExpr( $1, $3 ); }
|
|
;
|
|
|
|
CodeBlock : '{' '|' { $<asExpr>$ = hb_compExprNewCodeBlock(); } BlockNoVar
|
|
'|' BlockExpList '}' { $$ = $<asExpr>3; }
|
|
| '{' '|' { $<asExpr>$ = hb_compExprNewCodeBlock(); } BlockVarList
|
|
'|' BlockExpList '}' { $$ = $<asExpr>3; }
|
|
;
|
|
|
|
/* NOTE: This uses $-2 then don't use BlockExpList in other context
|
|
*/
|
|
BlockExpList : Expression { $$ = hb_compExprAddListExpr( $<asExpr>-2, $1 ); }
|
|
| BlockExpList ',' Expression { $$ = hb_compExprAddListExpr( $<asExpr>-2, $3 ); }
|
|
;
|
|
|
|
/* NOTE: This is really not needed however it allows the use of $-2 item
|
|
* in BlockExpList to refer the same rule defined in Codeblock
|
|
*/
|
|
BlockNoVar : /* empty list */ { $$ = NULL; }
|
|
;
|
|
|
|
BlockVarList : IDENTIFIER AsType { hb_comp_iVarScope = VS_LOCAL; $$ = hb_compExprCBVarAdd( $<asExpr>0, $1, $2 ); }
|
|
| BlockVarList ',' IDENTIFIER AsType { hb_comp_iVarScope = VS_LOCAL; $$ = hb_compExprCBVarAdd( $<asExpr>0, $3, $4 ); }
|
|
;
|
|
|
|
/* There is a conflict between the use of IF( Expr1, Expr2, Expr3 )
|
|
* and parenthesized expression ( Expr1, Expr2, Expr3 )
|
|
* To solve this conflict we have to split the definitions into more
|
|
* atomic ones.
|
|
* Also the generation of pcodes have to be delayed and moved to the
|
|
* end of whole parenthesized expression.
|
|
*/
|
|
PareExpList1: ExpList1 ')' { $$ = $1; }
|
|
;
|
|
|
|
PareExpList2: ExpList2 ')' { $$ = $1; }
|
|
;
|
|
|
|
PareExpList3: ExpList3 ')' { $$ = $1; }
|
|
;
|
|
|
|
PareExpListN: ExpList ')' { $$ = $1; }
|
|
;
|
|
|
|
PareExpList : PareExpList1 { $$ = $1; }
|
|
| PareExpList2 { $$ = $1; }
|
|
| PareExpList3 { $$ = $1; }
|
|
| PareExpListN { $$ = $1; }
|
|
;
|
|
|
|
PareExpListAlias : PareExpList ALIASOP { $$ = hb_compExprReduce( $1 ); }
|
|
;
|
|
|
|
ExpList1 : '(' EmptyExpression { $$ = hb_compExprNewList( $2 ); }
|
|
;
|
|
|
|
ExpList2 : ExpList1 ',' EmptyExpression { $$ = hb_compExprAddListExpr( $1, $3 ); }
|
|
;
|
|
|
|
ExpList3 : ExpList2 ',' EmptyExpression { $$ = hb_compExprAddListExpr( $1, $3 ); }
|
|
;
|
|
|
|
ExpList : ExpList3 ',' EmptyExpression { $$ = hb_compExprAddListExpr( $1, $3 ); }
|
|
| ExpList ',' EmptyExpression { $$ = hb_compExprAddListExpr( $1, $3 ); }
|
|
;
|
|
|
|
IfInline : IIF PareExpList3 { $$ = hb_compExprNewIIF( $2 ); }
|
|
| IF ExpList1 ',' EmptyExpression ','
|
|
{ $<asExpr>$ = hb_compExprAddListExpr( $2, $4 ); }
|
|
EmptyExpression ')'
|
|
{ $$ = hb_compExprNewIIF( hb_compExprAddListExpr( $<asExpr>6, $7 ) ); }
|
|
;
|
|
|
|
IfInlineAlias : IfInline ALIASOP { $$ = $1; }
|
|
;
|
|
|
|
VarDefs : LOCAL { hb_comp_iVarScope = VS_LOCAL; Line(); } VarList Crlf { hb_comp_cVarType = ' '; }
|
|
| STATIC { hb_comp_iVarScope = VS_STATIC; Line(); } VarList Crlf { hb_comp_cVarType = ' '; }
|
|
| PARAMETERS { if( hb_comp_functions.pLast->bFlags & FUN_USES_LOCAL_PARAMS )
|
|
hb_compGenError( hb_comp_szCErrors, 'E', ERR_PARAMETERS_NOT_ALLOWED, NULL, NULL );
|
|
else
|
|
hb_comp_functions.pLast->wParamNum=0; hb_comp_iVarScope = ( VS_PRIVATE | VS_PARAMETER ); }
|
|
MemvarList Crlf
|
|
;
|
|
|
|
VarList : VarDef { $$ = 1; }
|
|
| VarList ',' VarDef { $$++; }
|
|
;
|
|
|
|
VarDef : IDENTIFIER AsType
|
|
{
|
|
if( hb_comp_iVarScope == VS_STATIC )
|
|
{
|
|
hb_compStaticDefStart(); /* switch to statics pcode buffer */
|
|
hb_compAddVar( $1, $2 );
|
|
hb_compStaticDefEnd();
|
|
}
|
|
else
|
|
hb_compAddVar( $1, $2 );
|
|
}
|
|
|
|
| IDENTIFIER AsType INASSIGN Expression
|
|
{
|
|
if( hb_comp_iVarScope == VS_STATIC )
|
|
{
|
|
hb_compStaticDefStart(); /* switch to statics pcode buffer */
|
|
hb_compAddVar( $1, $2 );
|
|
hb_compExprDelete( hb_compExprGenStatement( hb_compExprAssignStatic( hb_compExprNewVar( $1 ), $4 ) ) );
|
|
hb_compStaticDefEnd();
|
|
}
|
|
else
|
|
{
|
|
hb_compAddVar( $1, $2 );
|
|
hb_compExprDelete( hb_compExprGenStatement( hb_compExprAssign( hb_compExprNewVar( $1 ), $4 ) ) );
|
|
}
|
|
}
|
|
|
|
| IDENTIFIER DimList
|
|
{
|
|
USHORT uCount = hb_compExprListLen( $2 );
|
|
hb_compAddVar( $1, 'A' );
|
|
hb_compExprDelete( hb_compExprGenPush( $2 ) );
|
|
hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) );
|
|
hb_compExprDelete( hb_compExprGenPop( hb_compExprNewVar( $1 ) ) );
|
|
}
|
|
| IDENTIFIER DimList AS_ARRAY
|
|
{
|
|
USHORT uCount = hb_compExprListLen( $2 );
|
|
hb_compAddVar( $1, 'A' );
|
|
hb_compExprDelete( hb_compExprGenPush( $2 ) );
|
|
hb_compGenPCode3( HB_P_ARRAYDIM, HB_LOBYTE( uCount ), HB_HIBYTE( uCount ) );
|
|
hb_compExprDelete( hb_compExprGenPop( hb_compExprNewVar( $1 ) ) );
|
|
}
|
|
;
|
|
|
|
/* NOTE: DimList and DimIndex is the same as ArrayIndex and IndexList
|
|
* however we are using quite different actions here
|
|
*/
|
|
DimList : DimIndex ']' { $$ = $1; }
|
|
;
|
|
|
|
DimIndex : '[' Expression { $$ = hb_compExprNewArgList( $2 ); }
|
|
| DimIndex ',' Expression { $$ = hb_compExprAddListExpr( $1, $3 ); }
|
|
| DimIndex ']' '[' Expression { $$ = hb_compExprAddListExpr( $1, $4 ); }
|
|
;
|
|
|
|
|
|
FieldsDef : FIELD { hb_comp_iVarScope = VS_FIELD; } FieldList Crlf
|
|
;
|
|
|
|
FieldList : IDENTIFIER AsType { $$=FieldsCount(); hb_compAddVar( $1, $2 ); }
|
|
| FieldList ',' IDENTIFIER AsType { hb_compAddVar( $3, $4 ); }
|
|
| FieldList IN IDENTIFIER { FieldsSetAlias( $3, $<iNumber>1 ); }
|
|
;
|
|
|
|
MemvarDef : MEMVAR { hb_comp_iVarScope = VS_MEMVAR; } MemvarList Crlf
|
|
;
|
|
|
|
MemvarList : IDENTIFIER { hb_compAddVar( $1, ' ' ); }
|
|
| MemvarList ',' IDENTIFIER { hb_compAddVar( $3, ' ' ); }
|
|
;
|
|
|
|
ExecFlow : IfEndif
|
|
| DoCase
|
|
| DoWhile
|
|
| ForNext
|
|
| BeginSeq
|
|
;
|
|
|
|
IfEndif : IfBegin EndIf { hb_compGenJumpHere( $1 ); }
|
|
| IfBegin IfElse EndIf { hb_compGenJumpHere( $1 ); }
|
|
| IfBegin IfElseIf EndIf { hb_compGenJumpHere( $1 ); FixElseIfs( $2 ); }
|
|
| IfBegin IfElseIf IfElse EndIf { hb_compGenJumpHere( $1 ); FixElseIfs( $2 ); }
|
|
;
|
|
|
|
EmptyStats : /* empty */
|
|
| Statements
|
|
;
|
|
|
|
IfBegin : IF SimpleExpression { ++hb_comp_wIfCounter; Line(); } Crlf { hb_compExprDelete( hb_compExprGenPush( $2 ) ); $$ = hb_compGenJumpFalse( 0 ); Line(); }
|
|
EmptyStats
|
|
{ $$ = hb_compGenJump( 0 ); hb_compGenJumpHere( $<iNumber>5 ); }
|
|
|
|
| IF Variable { ++hb_comp_wIfCounter; Line(); } Crlf { hb_compExprDelete( hb_compExprGenPush( $2 ) ); $$ = hb_compGenJumpFalse( 0 ); Line(); }
|
|
EmptyStats
|
|
{ $$ = hb_compGenJump( 0 ); hb_compGenJumpHere( $<iNumber>5 ); }
|
|
|
|
| IF PareExpList1 { ++hb_comp_wIfCounter; Line(); } Crlf { hb_compExprDelete( hb_compExprGenPush( $2 ) ); $$ = hb_compGenJumpFalse( 0 ); Line(); }
|
|
EmptyStats
|
|
{ $$ = hb_compGenJump( 0 ); hb_compGenJumpHere( $<iNumber>5 ); }
|
|
|
|
| IF PareExpList2 { ++hb_comp_wIfCounter; Line(); } Crlf { hb_compExprDelete( hb_compExprGenPush( $2 ) ); $$ = hb_compGenJumpFalse( 0 ); Line(); }
|
|
EmptyStats
|
|
{ $$ = hb_compGenJump( 0 ); hb_compGenJumpHere( $<iNumber>5 ); }
|
|
|
|
| IF PareExpListN { ++hb_comp_wIfCounter; Line(); } Crlf { hb_compExprDelete( hb_compExprGenPush( $2 ) ); $$ = hb_compGenJumpFalse( 0 ); Line(); }
|
|
EmptyStats
|
|
{ $$ = hb_compGenJump( 0 ); hb_compGenJumpHere( $<iNumber>5 ); }
|
|
;
|
|
|
|
IfElse : ELSE Crlf { Line(); } EmptyStats
|
|
;
|
|
|
|
IfElseIf : ELSEIF Expression Crlf { hb_compExprDelete( hb_compExprGenPush( $2 ) ); $<iNumber>$ = hb_compGenJumpFalse( 0 ); Line(); }
|
|
EmptyStats { $$ = GenElseIf( 0, hb_compGenJump( 0 ) ); hb_compGenJumpHere( $<iNumber>4 ); }
|
|
|
|
| IfElseIf ELSEIF Expression Crlf { hb_compExprDelete( hb_compExprGenPush( $3 ) ); $<iNumber>$ = hb_compGenJumpFalse( 0 ); Line(); }
|
|
EmptyStats { $$ = GenElseIf( $1, hb_compGenJump( 0 ) ); hb_compGenJumpHere( $<iNumber>5 ); }
|
|
;
|
|
|
|
EndIf : ENDIF { --hb_comp_wIfCounter; hb_comp_functions.pLast->bFlags &= ~ FUN_WITH_RETURN; }
|
|
| END { --hb_comp_wIfCounter; hb_comp_functions.pLast->bFlags &= ~ FUN_WITH_RETURN; }
|
|
;
|
|
|
|
DoCase : DoCaseBegin
|
|
Cases
|
|
EndCase { FixElseIfs( $2 ); }
|
|
|
|
| DoCaseBegin
|
|
Otherwise
|
|
EndCase
|
|
|
|
| DoCaseBegin
|
|
EndCase
|
|
|
|
| DoCaseBegin
|
|
Cases
|
|
Otherwise
|
|
EndCase { FixElseIfs( $2 ); }
|
|
;
|
|
|
|
EndCase : ENDCASE { --hb_comp_wCaseCounter; hb_comp_functions.pLast->bFlags &= ~ FUN_WITH_RETURN; }
|
|
| END { --hb_comp_wCaseCounter; hb_comp_functions.pLast->bFlags &= ~ FUN_WITH_RETURN; }
|
|
;
|
|
|
|
DoCaseStart : DOCASE { ++hb_comp_wCaseCounter; } Crlf { Line(); }
|
|
;
|
|
|
|
DoCaseBegin : DoCaseStart { }
|
|
| DoCaseStart Statements {
|
|
if( $<lNumber>2 > 0 )
|
|
{
|
|
--iLine;
|
|
hb_compGenError( hb_comp_szCErrors, 'E', ERR_MAYHEM_IN_CASE, NULL, NULL );
|
|
}
|
|
}
|
|
;
|
|
|
|
Cases : CASE Expression Crlf
|
|
{
|
|
hb_compExprDelete( hb_compExprGenPush( $2 ) );
|
|
$<iNumber>$ = hb_compGenJumpFalse( 0 );
|
|
Line();
|
|
}
|
|
EmptyStats
|
|
{
|
|
$$ = GenElseIf( 0, hb_compGenJump( 0 ) );
|
|
hb_compGenJumpHere( $<iNumber>4 );
|
|
Line();
|
|
}
|
|
|
|
| Cases CASE Expression Crlf
|
|
{
|
|
hb_compExprDelete( hb_compExprGenPush( $3 ) );
|
|
$<iNumber>$ = hb_compGenJumpFalse( 0 );
|
|
Line();
|
|
}
|
|
EmptyStats
|
|
{
|
|
$$ = GenElseIf( $1, hb_compGenJump( 0 ) );
|
|
hb_compGenJumpHere( $<iNumber>5 );
|
|
Line();
|
|
}
|
|
;
|
|
|
|
Otherwise : OTHERWISE Crlf { Line(); } EmptyStats
|
|
;
|
|
|
|
DoWhile : WhileBegin Expression Crlf
|
|
{
|
|
hb_compExprDelete( hb_compExprGenPush( $2 ) );
|
|
$<lNumber>$ = hb_compGenJumpFalse( 0 );
|
|
Line();
|
|
}
|
|
EmptyStats
|
|
{
|
|
LoopHere();
|
|
hb_compGenJump( $1 - hb_comp_functions.pLast->lPCodePos );
|
|
}
|
|
EndWhile
|
|
{
|
|
hb_compGenJumpHere( $<lNumber>4 ); --hb_comp_wWhileCounter;
|
|
LoopEnd();
|
|
hb_comp_functions.pLast->bFlags &= ~ FUN_WITH_RETURN;
|
|
}
|
|
;
|
|
|
|
WhileBegin : WHILE { $$ = hb_comp_functions.pLast->lPCodePos; ++hb_comp_wWhileCounter; LoopStart(); }
|
|
;
|
|
|
|
EndWhile : END
|
|
| ENDDO
|
|
;
|
|
|
|
ForNext : FOR LValue ForAssign Expression /* 1 2 3 4 */
|
|
{
|
|
++hb_comp_wForCounter; /* 5 */
|
|
$<asExpr>$ = hb_compExprGenStatement( hb_compExprAssign( $2, $4 ) );
|
|
}
|
|
TO Expression StepExpr /* 6 7 8 */
|
|
{
|
|
LoopStart();
|
|
$<lNumber>$ = hb_comp_functions.pLast->lPCodePos; /* 9 */
|
|
if( $<asExpr>8 )
|
|
hb_compExprGenPush( $<asExpr>8 ); /* step */
|
|
hb_compExprGenPush( $2 ); /* counter */
|
|
hb_compExprGenPush( $7 ); /* end */
|
|
}
|
|
Crlf /* 10 */
|
|
{
|
|
if( $<asExpr>8 )
|
|
hb_compGenPCode1( HB_P_FORTEST );
|
|
else
|
|
hb_compGenPCode1( HB_P_LESSEQUAL );
|
|
$<lNumber>$ = hb_compGenJumpFalse( 0 ); /* 11 */
|
|
Line();
|
|
}
|
|
ForStatements /* 12 */
|
|
{
|
|
LoopHere();
|
|
if( $<asExpr>8 )
|
|
hb_compExprGenStatement( hb_compExprSetOperand( hb_compExprNewPlusEq( $2 ), $<asExpr>8 ) );
|
|
else
|
|
hb_compExprGenStatement( hb_compExprNewPreInc( $2 ) );
|
|
hb_compGenJump( $<lNumber>9 - hb_comp_functions.pLast->lPCodePos );
|
|
hb_compGenJumpHere( $<lNumber>11 );
|
|
LoopEnd();
|
|
hb_compExprDelete( $7 );
|
|
hb_compExprDelete( $<asExpr>5 );
|
|
hb_comp_functions.pLast->bFlags &= ~ FUN_WITH_RETURN;
|
|
}
|
|
;
|
|
|
|
ForAssign : '='
|
|
| INASSIGN
|
|
;
|
|
|
|
StepExpr : /* default step expression */ { $<asExpr>$ = NULL; }
|
|
| STEP Expression { $<asExpr>$ = $2; }
|
|
;
|
|
|
|
ForStatements : EmptyStats NEXT { --hb_comp_wForCounter; }
|
|
| EmptyStats NEXT IDENTIFIER { --hb_comp_wForCounter; }
|
|
;
|
|
|
|
BeginSeq : BEGINSEQ { ++hb_comp_wSeqCounter; $<lNumber>$ = SequenceBegin(); } Crlf { Line(); }
|
|
EmptyStats
|
|
{
|
|
/* Set jump address for HB_P_SEQBEGIN opcode - this address
|
|
* will be used in BREAK code if there is no RECOVER clause
|
|
*/
|
|
hb_compGenJumpHere( $<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 )
|
|
hb_compGenJumpThere( $<lNumber>2, $<lNumber>7-( hb_comp_bLineNumbers ? 3 : 0 ) );
|
|
}
|
|
END
|
|
{
|
|
/* Fix END address
|
|
* There is no line number after HB_P_SEQEND in case no
|
|
* RECOVER clause is used
|
|
*/
|
|
hb_compGenJumpThere( $<lNumber>6, hb_comp_functions.pLast->lPCodePos-((hb_comp_bLineNumbers && !$<lNumber>7)?3:0) );
|
|
if( $<lNumber>7 ) /* only if there is RECOVER clause */
|
|
LineDebug();
|
|
else
|
|
--hb_comp_wSeqCounter; /* RECOVER is also considered as end of sequence */
|
|
SequenceFinish( $<lNumber>2, $<iNumber>5 );
|
|
hb_comp_functions.pLast->bFlags &= ~ FUN_WITH_RETURN;
|
|
}
|
|
;
|
|
|
|
RecoverSeq : /* no recover */ { $<lNumber>$ = 0; }
|
|
| RecoverEmpty Crlf { $<lNumber>$ = $<lNumber>1; Line(); } EmptyStats
|
|
| RecoverUsing Crlf { $<lNumber>$ = $<lNumber>1; Line(); } EmptyStats
|
|
;
|
|
|
|
RecoverEmpty : RECOVER
|
|
{
|
|
$<lNumber>$ = hb_comp_functions.pLast->lPCodePos;
|
|
--hb_comp_wSeqCounter;
|
|
hb_compGenPCode1( HB_P_SEQRECOVER );
|
|
hb_compGenPCode1( HB_P_POP );
|
|
}
|
|
;
|
|
|
|
RecoverUsing : RECOVER USING IDENTIFIER
|
|
{
|
|
$<lNumber>$ = hb_comp_functions.pLast->lPCodePos;
|
|
--hb_comp_wSeqCounter;
|
|
hb_compGenPCode1( HB_P_SEQRECOVER );
|
|
hb_compGenPopVar( $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 { hb_compPushSymbol( $2, 1 ); hb_compGenPushNil(); hb_compGenDoProc( 0 ); }
|
|
| DO IDENTIFIER { hb_compPushSymbol( $2, 1 ); hb_compGenPushNil(); } WITH DoArgList { hb_compGenDoProc( $5 ); }
|
|
| WHILE { hb_compPushSymbol( yy_strdup("WHILE"), 1 ); hb_compGenPushNil(); } WITH DoArgList { hb_compGenDoProc( $4 ); }
|
|
;
|
|
|
|
DoArgList : ',' { hb_compGenPushNil(); hb_compGenPushNil(); $$ = 2; }
|
|
| DoExpression { $$ = 1; }
|
|
| DoArgList ',' { hb_compGenPushNil(); $$++; }
|
|
| DoArgList ',' DoExpression { $$++; }
|
|
| ',' { hb_compGenPushNil(); } DoExpression { $$ = 2; }
|
|
;
|
|
|
|
DoExpression: IDENTIFIER { hb_compGenPushVarRef( $1 ); }
|
|
| SimpleExpression { }
|
|
| PareExpList { }
|
|
;
|
|
|
|
Crlf : '\n' { ++iLine; }
|
|
| ';' { hb_comp_bDontGenLineNum = TRUE; }
|
|
;
|
|
|
|
%%
|
|
|
|
/*
|
|
** ------------------------------------------------------------------------ **
|
|
*/
|
|
|
|
int harbour_main( char * szName )
|
|
{
|
|
/* Generate the starting procedure frame
|
|
*/
|
|
if( hb_comp_bStartProc )
|
|
hb_compFunDef( yy_strupr( yy_strdup( 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.
|
|
*/
|
|
hb_compFunDef( yy_strupr( yy_strdup( "" ) ), FS_PUBLIC, FUN_PROCEDURE );
|
|
|
|
yyparse();
|
|
|
|
hb_compGenExterns(); /* generates EXTERN symbols names */
|
|
|
|
if( hb_comp_pInitFunc )
|
|
{
|
|
PCOMSYMBOL pSym;
|
|
|
|
/* Fix the number of static variables */
|
|
hb_comp_pInitFunc->pCode[ 3 ] = HB_LOBYTE( hb_comp_iStaticCnt );
|
|
hb_comp_pInitFunc->pCode[ 4 ] = HB_HIBYTE( hb_comp_iStaticCnt );
|
|
hb_comp_pInitFunc->iStaticsBase = hb_comp_iStaticCnt;
|
|
|
|
pSym = hb_compAddSymbol( hb_comp_pInitFunc->szName, NULL );
|
|
pSym->cScope |= hb_comp_pInitFunc->cScope;
|
|
hb_comp_functions.pLast->pNext = hb_comp_pInitFunc;
|
|
++hb_comp_functions.iCount;
|
|
}
|
|
|
|
/* Close processed file (it is opened in Include() function )
|
|
*/
|
|
fclose( yyin );
|
|
|
|
hb_comp_files.pLast = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
void yyerror( char * s )
|
|
{
|
|
if( yytext[ 0 ] == '\n' )
|
|
hb_compGenError( hb_comp_szCErrors, 'E', ERR_YACC, s, "<eol>" );
|
|
else
|
|
hb_compGenError( hb_comp_szCErrors, 'E', ERR_YACC, s, yytext );
|
|
}
|
|
|
|
|
|
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( ! hb_comp_bQuiet )
|
|
printf( "\nCompiling \'%s\'\n", szFileName );
|
|
|
|
pFile = ( PFILE ) hb_xgrab( sizeof( _FILE ) );
|
|
pFile->handle = yyin;
|
|
pFile->szFileName = szFileName;
|
|
pFile->pPrev = NULL;
|
|
|
|
if( ! hb_comp_files.iFiles )
|
|
hb_comp_files.pLast = pFile;
|
|
else
|
|
{
|
|
hb_comp_files.pLast->iLine = iLine;
|
|
iLine = 1;
|
|
pFile->pPrev = hb_comp_files.pLast;
|
|
hb_comp_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
|
|
hb_comp_files.iFiles++;
|
|
return 1;
|
|
}
|
|
|
|
int yywrap( void ) /* handles the EOF of the currently processed file */
|
|
{
|
|
void * pLast;
|
|
|
|
if( hb_comp_files.iFiles == 1 )
|
|
return 1; /* we have reached the main EOF */
|
|
else
|
|
{
|
|
pLast = hb_comp_files.pLast;
|
|
fclose( hb_comp_files.pLast->handle );
|
|
hb_comp_files.pLast = ( PFILE ) ( ( PFILE ) hb_comp_files.pLast )->pPrev;
|
|
iLine = hb_comp_files.pLast->iLine;
|
|
if( ! hb_comp_bQuiet )
|
|
printf( "\nCompiling %s\n", hb_comp_files.pLast->szFileName );
|
|
#ifdef __cplusplus
|
|
yy_delete_buffer( ( YY_BUFFER_STATE ) ( ( PFILE ) pLast )->pBuffer );
|
|
#else
|
|
yy_delete_buffer( ( ( PFILE ) pLast )->pBuffer );
|
|
#endif
|
|
free( pLast );
|
|
hb_comp_files.iFiles--;
|
|
yyin = hb_comp_files.pLast->handle;
|
|
#ifdef __cplusplus
|
|
yy_switch_to_buffer( ( YY_BUFFER_STATE ) hb_comp_files.pLast->pBuffer );
|
|
#else
|
|
yy_switch_to_buffer( hb_comp_files.pLast->pBuffer );
|
|
#endif
|
|
return 0; /* we close the currently include file and continue */
|
|
}
|
|
}
|
|
|
|
/* ************************************************************************* */
|
|
|
|
/*
|
|
* 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( hb_comp_pLoops )
|
|
{
|
|
PTR_LOOPEXIT pLast = hb_comp_pLoops;
|
|
|
|
while( pLast->pNext )
|
|
pLast = pLast->pNext;
|
|
pLast->pNext = pLoop;
|
|
}
|
|
else
|
|
hb_comp_pLoops = pLoop;
|
|
|
|
pLoop->pNext = NULL;
|
|
pLoop->pExitList = NULL;
|
|
pLoop->pLoopList = NULL;
|
|
pLoop->ulOffset = hb_comp_functions.pLast->lPCodePos; /* store the start position */
|
|
pLoop->iLine = iLine;
|
|
pLoop->wSeqCounter = hb_comp_wSeqCounter; /* store current SEQUENCE counter */
|
|
}
|
|
|
|
/*
|
|
* Stores the position of LOOP statement to fix it later at the end of loop
|
|
*/
|
|
static void LoopLoop( void )
|
|
{
|
|
PTR_LOOPEXIT pLast, pLoop;
|
|
|
|
pLoop = ( PTR_LOOPEXIT ) hb_xgrab( sizeof( LOOPEXIT ) );
|
|
|
|
pLoop->pLoopList = NULL;
|
|
pLoop->ulOffset = hb_comp_functions.pLast->lPCodePos; /* store the position to fix */
|
|
|
|
pLast = hb_comp_pLoops;
|
|
while( pLast->pNext )
|
|
pLast = pLast->pNext;
|
|
|
|
if( pLast->wSeqCounter != hb_comp_wSeqCounter )
|
|
{
|
|
/* Attempt to LOOP from BEGIN/END sequence
|
|
* Current SEQUENCE counter is different then at the beginning of loop
|
|
* Notice that LOOP is allowed in RECOVER code.
|
|
*/
|
|
hb_compGenError( hb_comp_szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "LOOP", NULL );
|
|
}
|
|
|
|
while( pLast->pLoopList )
|
|
pLast = pLast->pLoopList;
|
|
|
|
pLast->pLoopList = pLoop;
|
|
|
|
hb_compGenJump( 0 );
|
|
}
|
|
|
|
/*
|
|
* Stores the position of EXIT statement to fix it later at the end of loop
|
|
*/
|
|
static void LoopExit( void )
|
|
{
|
|
PTR_LOOPEXIT pLast, pLoop;
|
|
|
|
pLoop = ( PTR_LOOPEXIT ) hb_xgrab( sizeof( LOOPEXIT ) );
|
|
|
|
pLoop->pExitList = NULL;
|
|
pLoop->ulOffset = hb_comp_functions.pLast->lPCodePos; /* store the position to fix */
|
|
|
|
pLast = hb_comp_pLoops;
|
|
while( pLast->pNext )
|
|
pLast = pLast->pNext;
|
|
|
|
if( pLast->wSeqCounter != hb_comp_wSeqCounter )
|
|
{
|
|
/* Attempt to LOOP from BEGIN/END sequence
|
|
* Current SEQUENCE counter is different then at the beginning of loop
|
|
* Notice that LOOP is allowed in RECOVER code.
|
|
*/
|
|
hb_compGenError( hb_comp_szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "EXIT", NULL );
|
|
}
|
|
|
|
while( pLast->pExitList )
|
|
pLast = pLast->pExitList;
|
|
|
|
pLast->pExitList = pLoop;
|
|
|
|
hb_compGenJump( 0 );
|
|
}
|
|
|
|
/*
|
|
* Fixes the LOOP statement
|
|
*/
|
|
static void LoopHere( void )
|
|
{
|
|
PTR_LOOPEXIT pLoop = hb_comp_pLoops, pFree;
|
|
|
|
while( pLoop->pNext )
|
|
pLoop = pLoop->pNext;
|
|
|
|
pLoop = pLoop->pLoopList;
|
|
while( pLoop )
|
|
{
|
|
hb_compGenJumpHere( pLoop->ulOffset + 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 = hb_comp_pLoops, pLast = hb_comp_pLoops, pFree;
|
|
|
|
while( pLoop->pNext )
|
|
{
|
|
pLast = pLoop;
|
|
pLoop = pLoop->pNext;
|
|
}
|
|
|
|
pExit = pLoop->pExitList;
|
|
while( pExit )
|
|
{
|
|
hb_compGenJumpHere( pExit->ulOffset + 1 );
|
|
pFree = pExit;
|
|
pExit = pExit->pExitList;
|
|
hb_xfree( ( void * ) pFree );
|
|
}
|
|
|
|
pLast->pNext = NULL;
|
|
if( pLoop == hb_comp_pLoops )
|
|
hb_comp_pLoops = NULL;
|
|
hb_xfree( ( void * ) pLoop );
|
|
}
|
|
|