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

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 );
}