ChangeLog 19990823-12:40

This commit is contained in:
Ryszard Glab
1999-08-23 11:33:50 +00:00
parent 71927c2a68
commit 16a8d20598
8 changed files with 559 additions and 37 deletions

View File

@@ -1,3 +1,46 @@
19990823-12:40 GMT+2 Ryszard Glab <rglab@imid.med.pl>
*source/compiler/harbour.y
+ added full support for BEGIN/RECOVER/END sequence
+ added full support for BREAK statement and BREAK function
(BREAK statement is implemented using BREAK function)
+ fixed incorrect warning about unused static variables
* added some optimalization of generated opcodes - repeated
HB_P_LINE opcodes are replaced with only one HB_P_LINE opcode
if compiled with no debugger support
*source/vm/hvm.c
+ added full support for BEGIN/RECOVER/END sequence and BREAK
+ new functions hb_vmRequestBreak() and hb_vmRequestQuit()
that can be used from C code to request BREAK or QUIT action
+ changed HB_DEBUG to empty macro instead of function when
debug code is not requested
* some internal variables declared 'static'
* EXIT functions are called on exit when QUIT is requested
QUESTION: How to handle the call to QUIT function inside of
EXIT procedure? Should we continue execution of the rest of
procedures or immediatelly quit to OS?
*include/pcode.h
+ added new opcodes
HB_P_SEQBEGIN
HB_P_SEQEND
HB_P_SEQRECOVER
NOTE: You have to recompile all PRG code!
*include/hberrors.h
+ added new error code ERR_EXIT_IN_SEQUENCE called when
EXIT, LOOP or RETURN is used inside BEGIN/END sequence
(however these statement are valid in RECOVER code)
*tests/working/begin.prg
+ new file to test BEGIN/RECOVER/END sequence and BREAK statement
*tests/working/Makefile
* added begin.prg
19990823-10:45 GMT+1 Bruno Cantero <bruno@issnet.net>
* include/rddapi.h
source/rdd/dbcmd.c

View File

@@ -63,6 +63,7 @@
#define ERR_INVALID_LVALUE 22
#define ERR_INVALID_REFER 23
#define ERR_PARAMETERS_NOT_ALLOWED 24
#define ERR_EXIT_IN_SEQUENCE 25
#define WARN_AMBIGUOUS_VAR 1
#define WARN_MEMVAR_ASSUMED 2

View File

@@ -97,6 +97,9 @@ typedef enum
HB_P_PUSHSTR, /* places a string on the virtual machine stack */
HB_P_PUSHSYM, /* places a symbol on the virtual machine stack */
HB_P_RETVALUE, /* instructs the virtual machine to return the latest stack value */
HB_P_SEQBEGIN, /* BEGIN SEQUENCE */
HB_P_SEQEND, /* END SEQUENCE */
HB_P_SEQRECOVER, /* RECOVER statement */
HB_P_SFRAME, /* sets the statics frame for a function */
HB_P_STATICS, /* defines the number of statics variables for a PRG */
HB_P_SWAPALIAS, /* restores the current workarea number from the eval stack */

View File

@@ -189,6 +189,7 @@ void Function( BYTE bParams ); /* generates the pcode to execute a Clipper funct
PFUNCTION FunctionNew( char *, char ); /* creates and initialises the _FUNC structure */
void FunDef( char * szFunName, SYMBOLSCOPE cScope, int iType ); /* starts a new Clipper language function definition */
void GenArray( WORD wElements ); /* instructs the virtual machine to build an array and load elemnst from the stack */
void GenBreak( void ); /* generate code for BREAK statement */
void * GenElseIf( void * pFirstElseIf, WORD wOffset ); /* generates a support structure for elseifs pcode fixups */
void GenExterns( void ); /* generates the symbols for the EXTERN names */
PFUNCTION GetFuncall( char * szFunName ); /* locates a previously defined called function */
@@ -207,6 +208,7 @@ WORD JumpTrue( int iOffset ); /* generates the pcode to jump if true *
PFUNCTION KillFunction( PFUNCTION ); /* releases all memory allocated by function and returns the next one */
PCOMSYMBOL KillSymbol( PCOMSYMBOL ); /* releases all memory allocated by symbol and returns the next one */
void Line( void ); /* generates the pcode with the currently compiled source code line */
void LineDebug( void ); /* generates the pcode with the currently compiled source code line */
void LineBody( void ); /* generates the pcode with the currently compiled source code line */
void VariablePCode( BYTE , char * ); /* generates the pcode for memvar variable */
void Message( char * szMsgName ); /* sends a message to an object */
@@ -227,6 +229,9 @@ void GenPCode1( BYTE ); /* generates 1 byte of pcode */
void GenPCode3( BYTE, BYTE, BYTE ); /* generates 3 bytes of pcode */
void GenPCodeN( BYTE * pBuffer, WORD wSize ); /* copy bytes to a pcode buffer */
char * SetData( char * szMsg ); /* generates an underscore-symbol name for a data assignment */
int SequenceBegin( void );
int SequenceEnd( void );
void SequenceFinish( int, int );
/* support for FIELD declaration */
void FieldsSetAlias( char *, int );
@@ -303,7 +308,8 @@ char * _szCErrors[] =
"Incorrect number of arguments: %s %s",
"Invalid lvalue",
"Invalid use of \'@\' (pass by reference): \'%s\'",
"Formal parameters already declared"
"Formal parameters already declared",
"Invalid %s from within of SEQUENCE code"
};
/* Table with parse warnings */
@@ -462,6 +468,7 @@ PTR_LOOPEXIT pLoops = 0;
PATHNAMES *_pIncludePath = NULL;
PHB_FNAME _pFileName = NULL;
ALIASID_PTR pAliasId = NULL;
WORD _wLastLinePos = 0; /* position of last opcode with line number */
PSTACK_VAL_TYPE pStackValType = 0; /* compile time stack values linked list */
char cVarType = ' '; /* current declared variable type */
@@ -610,10 +617,10 @@ Statement : ExecFlow Crlf {}
| ObjectData ArrayIndex '=' Expression Crlf { GenPCode1( HB_P_ARRAYPUT ); GenPCode1( HB_P_POP ); }
| ObjectMethod ArrayIndex '=' Expression Crlf { GenPCode1( HB_P_ARRAYPUT ); GenPCode1( HB_P_POP ); }
| BREAK Crlf
| BREAK Expression Crlf
| RETURN Crlf { GenPCode1( HB_P_ENDPROC ); }
| RETURN Expression Crlf { GenPCode1( HB_P_RETVALUE ); GenPCode1( HB_P_ENDPROC ); }
| BREAK { GenBreak(); } Crlf { Do( 0 ); }
| BREAK { GenBreak(); } Expression Crlf { Do( 1 ); }
| RETURN Crlf { if( _wSeqCounter ) GenError( _szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "RETURN", NULL ); GenPCode1( HB_P_ENDPROC ); }
| RETURN Expression Crlf { if( _wSeqCounter ) GenError( _szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "RETURN", NULL ); GenPCode1( HB_P_RETVALUE ); GenPCode1( HB_P_ENDPROC ); }
| PUBLIC { iVarScope = VS_PUBLIC; } VarList Crlf
| PRIVATE { iVarScope = VS_PRIVATE; } VarList Crlf
@@ -1106,7 +1113,7 @@ WhileBegin : WHILE { $$ = functions.pLast->lPCodePos; ++_wWhileCounter; LoopS
;
WhileStatements : Statement
| WhileStatements Statement { Line(); }
| WhileStatements { Line(); } Statement
;
EndWhile : END
@@ -1136,27 +1143,66 @@ ForStatements : ForStat NEXT { --_wForCounter; }
ForStat : Statements { Line(); }
;
BeginSeq : BEGINSEQ { ++_wSeqCounter; } Crlf
BeginSeq : BEGINSEQ { ++_wSeqCounter; $<lNumber>$=SequenceBegin(); } Crlf { Line(); }
SeqStatms
{
/* Set jump address for HB_P_SEQBEGIN opcode - this address
* will be used in BREAK code if there is no RECOVER clause
*/
JumpHere( $<lNumber>2 );
$<lNumber>$ = SequenceEnd();
Line();
}
RecoverSeq
END { --_wSeqCounter; }
{
/* Replace END address with RECOVER address in
* HB_P_SEQBEGIN opcode if there is RECOVER clause
*/
if( $<lNumber>7 )
JumpThere( $<lNumber>2, $<lNumber>7-(_bLineNumbers?3:0) );
}
END
{
/* Fix END address
* There is no line number after HB_P_SEQEND in case no
* RECOVER clause is used
*/
JumpThere( $<lNumber>6, functions.pLast->lPCodePos-((_bLineNumbers && !$<lNumber>7)?3:0) );
if( $<lNumber>7 ) /* only if there is RECOVER clause */
LineDebug();
else
--_wSeqCounter; /* RECOVER is also considered as end of sequence */
SequenceFinish( $<lNumber>2, $<lNumber>5 );
}
;
SeqStatms : /* empty */
| Statements
SeqStatms : /* empty */ { $<lNumber>$ = 0; }
| Statements { $<lNumber>$ = 1; }
;
RecoverSeq : /* no recover */
| RecoverEmpty Crlf
| RecoverEmpty Crlf Statements
| RecoverUsing Crlf
| RecoverUsing Crlf Statements
RecoverSeq : /* no recover */ { $<lNumber>$ = 0; }
| RecoverEmpty Crlf { $<lNumber>$ = $<lNumber>1; }
| RecoverEmpty Crlf { $<lNumber>$ = $<lNumber>1; Line(); } Statements
| RecoverUsing Crlf { $<lNumber>$ = $<lNumber>1; }
| RecoverUsing Crlf { $<lNumber>$ = $<lNumber>1; Line(); } Statements
;
RecoverEmpty : RECOVER
{
$<lNumber>$ = functions.pLast->lPCodePos;
--_wSeqCounter;
GenPCode1( HB_P_SEQRECOVER );
GenPCode1( HB_P_POP );
}
;
RecoverUsing : RECOVER USING IDENTIFIER
{
$<lNumber>$ = functions.pLast->lPCodePos;
--_wSeqCounter;
GenPCode1( HB_P_SEQRECOVER );
PopId( $3 );
}
;
/* NOTE: In Clipper all variables used in DO .. WITH are passed by reference
@@ -1981,7 +2027,6 @@ void AliasSwap( void )
GenPCode1( HB_P_SWAPALIAS );
}
int Include( char * szFileName, PATHNAMES *pSearch )
{
PFILE pFile;
@@ -2195,6 +2240,8 @@ void FunDef( char * szFunName, SYMBOLSCOPE cScope, int iType )
}
functions.iCount++;
_wLastLinePos =0; /* optimization of line numbers opcode generation */
GenPCode3( HB_P_FRAME, 0, 0 ); /* frame for locals and parameters */
GenPCode3( HB_P_SFRAME, 0, 0 ); /* frame for statics variables */
@@ -3028,6 +3075,28 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag
lPCodePos++;
break;
case HB_P_SEQBEGIN:
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, " HB_P_SEQBEGIN, %i, %i,\t/* %i (abs: %05li) */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w, lPCodePos + ( w ? w: 3 ) );
lPCodePos += 3;
break;
case HB_P_SEQEND:
fprintf( yyc, "/* %05li */", lPCodePos );
w = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256;
fprintf( yyc, " HB_P_SEQEND, %i, %i,\t/* %i (abs: %05li) */\n",
pFunc->pCode[ lPCodePos + 1 ],
pFunc->pCode[ lPCodePos + 2 ], w, lPCodePos + ( w ? w: 3 ) );
lPCodePos += 3;
break;
case HB_P_SEQRECOVER:
fprintf( yyc, " HB_P_SEQRECOVER,\n" );
lPCodePos++;
break;
case HB_P_SFRAME:
/* we only generate it if there are statics used in this function */
if( pFunc->bFlags & FUN_USES_STATICS )
@@ -3170,6 +3239,11 @@ PCOMSYMBOL KillSymbol( PCOMSYMBOL pSym )
return pNext;
}
void GenBreak( void )
{
PushSymbol( yy_strdup("BREAK"), 1 );
PushNil();
}
void GenExterns( void ) /* generates the symbols for the EXTERN names */
{
@@ -3662,8 +3736,28 @@ WORD JumpTrue( int iOffset )
void Line( void ) /* generates the pcode with the currently compiled source code line */
{
if( _bLineNumbers )
GenPCode3( HB_P_LINE, LOBYTE( iLine ), HIBYTE( iLine ) );
if( _bLineNumbers )
{
if( ((functions.pLast->lPCodePos - _wLastLinePos) > 3) || _bDebugInfo )
{
_wLastLinePos =functions.pLast->lPCodePos;
GenPCode3( HB_P_LINE, LOBYTE( iLine ), HIBYTE( iLine ) );
}
else
{
functions.pLast->pCode[ _wLastLinePos +1 ] =LOBYTE( iLine );
functions.pLast->pCode[ _wLastLinePos +2 ] =HIBYTE( iLine );
}
}
}
/* Generates the pcode with the currently compiled source code line
* if debug code was requested only
*/
void LineDebug( void )
{
if( _bDebugInfo )
Line();
}
void LineBody( void ) /* generates the pcode with the currently compiled source code line */
@@ -3679,8 +3773,7 @@ void LineBody( void ) /* generates the pcode with the currently compiled source
}
functions.pLast->bFlags |= FUN_STATEMENTS;
if( _bLineNumbers )
GenPCode3( HB_P_LINE, LOBYTE( iLine ), HIBYTE( iLine ) );
Line();
}
/**
@@ -4365,7 +4458,7 @@ void FixReturns( void ) /* fixes all last defined function returns jumps offsets
pVar = functions.pLast->pLocals;
while ( pVar )
{
if( pVar->szName && functions.pLast->szName && ! pVar->iUsed )
if( pVar->szName && functions.pLast->szName && functions.pLast->szName[0] && ! pVar->iUsed )
GenWarning( _szCWarnings, 'W', WARN_VAR_NOT_USED, pVar->szName, functions.pLast->szName );
pVar = pVar->pNext;
@@ -4374,7 +4467,7 @@ void FixReturns( void ) /* fixes all last defined function returns jumps offsets
pVar = functions.pLast->pStatics;
while ( pVar )
{
if( pVar->szName && functions.pLast->szName && ! pVar->iUsed )
if( pVar->szName && functions.pLast->szName && functions.pLast->szName[0] && ! pVar->iUsed )
GenWarning( _szCWarnings, 'W', WARN_VAR_NOT_USED, pVar->szName, functions.pLast->szName );
pVar = pVar->pNext;
@@ -4788,6 +4881,46 @@ char * SetData( char * szMsg ) /* generates an underscore-symbol name for a data
return szResult;
}
/* Generate the opcode to open BEGIN/END sequence
* This code is simmilar to JUMP opcode - the offset will be filled with
* - either the address of HB_P_SEQEND opcode if there is no RECOVER clause
* - or the address of RECOVER code
*/
int SequenceBegin( void )
{
GenPCode3( HB_P_SEQBEGIN, 0, 0 );
return functions.pLast->lPCodePos -2;
}
/* Generate the opcode to close BEGIN/END sequence
* This code is simmilar to JUMP opcode - the offset will be filled with
* the address of first line after END SEQUENCE
* This opcode will be executed if recover code was not requested (as the
* last statement in code beetwen BEGIN ... RECOVER) or if BREAK was requested
* and there was no matching RECOVER clause.
*/
int SequenceEnd( void )
{
GenPCode3( HB_P_SEQEND, 0, 0 );
return functions.pLast->lPCodePos -2;
}
/* Remove unnecessary opcodes in case there were no executable statements
* beetwen BEGIN and RECOVER sequence
*/
void SequenceFinish( int iStartPos, int bUsualStmts )
{
if( ! _bDebugInfo ) /* only if no debugger info is required */
if( ! bUsualStmts )
{
functions.pLast->lPCodePos =iStartPos -1; /* remove also HB_P_SEQBEGIN */
_wLastLinePos =iStartPos -4;
}
}
/*
* Start a new fake-function that will hold pcodes for a codeblock
*/
@@ -5032,7 +5165,17 @@ static void LoopStart( void )
*/
static void LoopLoop( void )
{
PTR_LOOPEXIT pLast, pLoop = (PTR_LOOPEXIT) hb_xalloc( sizeof( LOOPEXIT ) );
PTR_LOOPEXIT pLast, pLoop;
if( _wSeqCounter && _wSeqCounter >= _wWhileCounter )
{
/* Attempt to LOOP from BEGIN/END sequence
* Notice that LOOP is allowed in RECOVER code.
*/
GenError( _szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "LOOP", NULL );
}
pLoop = (PTR_LOOPEXIT) hb_xalloc( sizeof( LOOPEXIT ) );
pLoop->pLoopList =NULL;
pLoop->wOffset =functions.pLast->lPCodePos; /* store the position to fix */
@@ -5054,7 +5197,17 @@ static void LoopLoop( void )
*/
static void LoopExit( void )
{
PTR_LOOPEXIT pLast, pLoop = (PTR_LOOPEXIT) hb_xalloc( sizeof( LOOPEXIT ) );
PTR_LOOPEXIT pLast, pLoop;
if( _wSeqCounter && _wSeqCounter >= _wWhileCounter )
{
/* Attempt to EXIT from BEGIN/END sequence
* Notice that EXIT is allowed in RECOVER code.
*/
GenError( _szCErrors, 'E', ERR_EXIT_IN_SEQUENCE, "EXIT", NULL );
}
pLoop = (PTR_LOOPEXIT) hb_xalloc( sizeof( LOOPEXIT ) );
pLoop->pExitList =NULL;
pLoop->wOffset =functions.pLast->lPCodePos; /* store the position to fix */
@@ -5455,6 +5608,7 @@ void GenPortObj( char *szFileName, char *szName )
case HB_P_PUSHSELF:
case HB_P_RETVALUE:
case HB_P_SWAPALIAS:
case HB_P_SEQRECOVER:
case HB_P_TRUE:
case HB_P_ZERO:
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
@@ -5475,6 +5629,8 @@ void GenPortObj( char *szFileName, char *szName )
case HB_P_PUSHLOCALREF:
case HB_P_PUSHSTATIC:
case HB_P_PUSHSTATICREF:
case HB_P_SEQBEGIN:
case HB_P_SEQEND:
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );
fputc( pFunc->pCode[ lPCodePos++ ], yyc );

View File

@@ -77,6 +77,7 @@
#include "extend.h"
#include "errorapi.h"
#include "inkey.h"
#include "init.h"
#if defined( OS_UNIX_COMPATIBLE )
#include <unistd.h>

View File

@@ -90,20 +90,42 @@ extern POBJSYMBOLS HB_FIRSTSYMBOL, HB_LASTSYMBOL;
/* virtual machine state */
BOOL bHB_DEBUG = FALSE; /* if TRUE traces the virtual machine activity */
BOOL bDebugging = FALSE;
BOOL bDebugShowLines = FALSE; /* update source code line on the debugger display */
STACK stack;
HB_SYMB symEval = { "__EVAL", FS_PUBLIC, hb_vmDoBlock, 0 }; /* symbol to evaluate codeblocks */
PHB_SYMB pSymStart; /* start symbol of the application. MAIN() is not required */
HB_ITEM aStatics; /* Harbour array to hold all application statics variables */
HB_ITEM errorBlock; /* errorblock */
PSYMBOLS pSymbols = 0; /* to hold a linked list of all different modules symbol tables */
BOOL bQuit = FALSE; /* inmediately exit the application */
BYTE byErrorLevel = 0; /* application exit errorlevel */
HB_ITEM aStatics; /* Harbour array to hold all application statics variables */
#define HB_DEBUG( x ) if( bHB_DEBUG ) printf( x )
#define HB_DEBUG2( x, y ) if( bHB_DEBUG ) printf( x, y )
static BOOL bDebugging = FALSE;
static BOOL bDebugShowLines = FALSE; /* update source code line on the debugger display */
static PHB_SYMB pSymStart; /* start symbol of the application. MAIN() is not required */
static PSYMBOLS pSymbols = 0; /* to hold a linked list of all different modules symbol tables */
static BYTE byErrorLevel = 0; /* application exit errorlevel */
/* Stores the position on the stack of current SEQUENCE envelope or 0 if no
* SEQUENCE is active
*/
static LONG RecoverBase = 0;
#define HB_RECOVER_STATE -1
#define HB_RECOVER_BASE -2
#define HB_RECOVER_ADDRESS -3
#define HB_RECOVER_VALUE -4
/* Request for some action - stop processing of opcodes
*/
static WORD wActionRequest = 0;
#define HB_QUIT_REQUESTED 1 /* immediately quit the application */
#define HB_BREAK_REQUESTED 2 /* break to nearest RECOVER/END sequence */
/* uncomment it to trace the virtual machine activity */
/* #define bHB_DEBUG */
#if defined( bHB_DEBUG )
#define HB_DEBUG( x ) printf( x )
#define HB_DEBUG2( x, y ) printf( x, y )
#else
#define HB_DEBUG( x )
#define HB_DEBUG2( x, y )
#endif
/* application entry point */
@@ -158,6 +180,9 @@ int main( int argc, char * argv[] )
hb_vmDo( argc - 1 ); /* invoke it with number of supplied parameters */
/* QUESTION: How to handle QUIT or BREAK in EXIT procedures?
*/
wActionRequest = 0; /* EXIT procedures should be processed */
hb_vmDoExitFunctions(); /* process defined EXIT functions */
hb_itemClear( &stack.Return );
@@ -188,11 +213,12 @@ void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols )
{
BYTE bCode;
WORD w = 0, wParams, wSize;
BOOL bCanRecover = FALSE;
ULONG ulPrivateBase = hb_memvarGetPrivatesBase();
HB_DEBUG( "hb_vmExecute\n" );
while( ( bCode = pCode[ w ] ) != HB_P_ENDPROC && ! bQuit )
while( ( bCode = pCode[ w ] ) != HB_P_ENDPROC )
{
hb_inkeyPoll(); /* Poll the console keyboard */
switch( bCode )
@@ -560,6 +586,111 @@ void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols )
w++;
break;
case HB_P_SEQBEGIN:
/*
* Create the SEQUENCE envelope
* [ break return value ] -4
* [ address of recover code ] -3
* [ previous recover base ] -2
* [ current recovery state ] -1
* [ ] <- new recover base
*/
/*
* 1) clear the storage for value returned by BREAK statement
*/
stack.pPos->type =IT_NIL;
hb_stackPush();
/*
* 2) store the address of RECOVER or END opcode
*/
stack.pPos->type =IT_LONG;
stack.pPos->item.asLong.value =w + pCode[ w + 1 ] + ( pCode[ w + 2 ] * 256 );
hb_stackPush();
/*
* 3) store current RECOVER base
*/
stack.pPos->type =IT_LONG;
stack.pPos->item.asLong.value =RecoverBase;
hb_stackPush();
/*
* 4) store current bCanRecover flag - in a case of nested sequences
* in the same procedure/function
*/
stack.pPos->type =IT_LOGICAL;
stack.pPos->item.asLogical.value =bCanRecover;
hb_stackPush();
/*
* set new recover base
*/
RecoverBase =stack.pPos - stack.pItems;;
/*
* we are now inside a valid SEQUENCE envelope
*/
bCanRecover = TRUE;
w += 3;
break;
case HB_P_SEQEND:
/*
* Remove the SEQUENCE envelope
* This is executed either at the end of sequence or as the
* response to the break statement if there is no RECOVER clause
*/
/*
* 4) Restore previous recovery state
*/
hb_stackDec();
bCanRecover =stack.pPos->item.asLogical.value;
stack.pPos->type =IT_NIL;
/*
* 3) Restore previous RECOVER base
*/
hb_stackDec();
RecoverBase =stack.pPos->item.asLong.value;
stack.pPos->type =IT_NIL;
/*
* 2) Remove RECOVER address
*/
hb_stackDec();
stack.pPos->type =IT_NIL;
/* 1) Discard the value returned by BREAK statement - there
* was no RECOVER clause or there was no BREAK statement
*/
hb_stackPop();
/*
* skip outside of SEQUENCE structure
*/
w += pCode[ w + 1 ] + ( pCode[ w + 2 ] * 256 );
break;
case HB_P_SEQRECOVER:
/*
* Execute the RECOVER code
*/
/*
* 4) Restore previous recovery state
*/
hb_stackDec();
bCanRecover =stack.pPos->item.asLogical.value;
stack.pPos->type =IT_NIL;
/*
* 3) Restore previous RECOVER base
*/
hb_stackDec();
RecoverBase =stack.pPos->item.asLong.value;
stack.pPos->type =IT_NIL;
/*
* 2) Remove RECOVER address
*/
hb_stackDec();
stack.pPos->type =IT_NIL;
/*
* 1) Leave the value returned from BREAK - it will be popped
* in next executed opcode
*/
w++;
break;
case HB_P_SFRAME:
wParams = pCode[ w + 1 ] + ( pCode[ w + 2 ] * 256 );
hb_vmSFrame( pSymbols + wParams );
@@ -591,9 +722,40 @@ void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols )
hb_errInternal( 9999, "Unsupported VM opcode", NULL, NULL );
break;
}
if( wActionRequest )
{
if( wActionRequest & HB_BREAK_REQUESTED )
{
if( bCanRecover )
{
/*
* There is the BEGIN/END sequence deifined in current
* procedure/function - use it to continue opcodes execution
*/
/*
* remove all items placed on the stack after BEGIN code
*/
while( stack.pPos > stack.pItems + RecoverBase )
hb_stackPop();
/*
* reload the address of recovery code
*/
w = stack.pItems[ RecoverBase + HB_RECOVER_ADDRESS ].item.asLong.value;
/*
* leave the SEQUENCE envelope on the stack - it will
* be popped either in RECOVER or END opcode
*/
wActionRequest = 0;
}
else
break;
}
else if( wActionRequest & HB_QUIT_REQUESTED )
break;
}
}
hb_memvarSetPrivatesBase( ulPrivateBase );
HB_DEBUG( "EndProc\n" );
}
/* Pops the item from the eval stack and uses it to select the current
@@ -1289,6 +1451,8 @@ void hb_vmLessEqual( void )
void hb_vmLocalName( WORD wLocal, char * szLocalName ) /* locals and parameters index and name information for the debugger */
{
HB_SYMBOL_UNUSED( wLocal );
HB_SYMBOL_UNUSED( szLocalName );
}
void hb_vmMessage( PHB_SYMB pSymMsg ) /* sends a message to an object */
@@ -2479,9 +2643,14 @@ HARBOUR HB_PROCLINE(void)
hb_retni( 0 );
}
void hb_vmRequestQuit( void )
{
wActionRequest = HB_QUIT_REQUESTED;
}
HARBOUR HB___QUIT(void)
{
bQuit = TRUE;
hb_vmRequestQuit();
}
HARBOUR HB_ERRORLEVEL(void)
@@ -2516,3 +2685,20 @@ HARBOUR HB_PVALUE(void) /* PValue( <nArg> )
hb_errRT_BASE(EG_ARG, 3011, NULL, "PVALUE");
}
}
void hb_vmRequestBreak( PHB_ITEM pItem )
{
if( RecoverBase )
{
if( pItem )
hb_itemCopy( stack.pItems + RecoverBase + HB_RECOVER_VALUE, pItem );
wActionRequest = HB_BREAK_REQUESTED;
}
else
wActionRequest = HB_QUIT_REQUESTED;
}
HARBOUR HB_BREAK( void )
{
hb_vmRequestBreak( hb_param( 1, IT_ANY ) );
}

View File

@@ -30,6 +30,7 @@ PRG_SOURCES=\
arreval.prg \
arrindex.prg \
atest.prg \
begin.prg \
box.prg \
byref.prg \
calling.prg \

View File

@@ -0,0 +1,131 @@
//
// $Id$
//
// This files demonstrates the use of BEGIN/RECOVER/END SEQUENCE
// and BREAK statement
//
MEMVAR oMemvar
PROCEDURE MAIN
LOCAL oLocal
PRIVATE mPrivate:='private value in MAIN'
BEGIN SEQUENCE
? " Inside SEQUENCE 1"
? " No break issued...."
RECOVER
? " Recovering in 1 ..."
END SEQUENCE
? "After SEQUENCE 1"
BEGIN SEQUENCE
? " Inside SEQUENCE 2"
Break( "VALUE 2" )
RECOVER USING oLocal
? " Recovering in 2 using....", oLocal
END SEQUENCE
? "After SEQUENCE 2"
BEGIN SEQUENCE
? " Inside SEQUENCE 3"
Break
RECOVER USING oLocal
? " Recovering in 3 using....", oLocal
END SEQUENCE
? "After SEQUENCE 3"
BEGIN SEQUENCE
? " Inside SEQUENCE 4"
Break
? " Recovering in 4 using....", oLocal
END SEQUENCE
? "After SEQUENCE 4"
BEGIN SEQUENCE
? " Inside SEQUENCE 5"
Break1( )
? " Recovering in 5 using....", oLocal
END SEQUENCE
? "After SEQUENCE 5"
BEGIN SEQUENCE
? " Inside SEQUENCE 6"
Break1( )
RECOVER USING oMemvar
? " Recovering in 6 using... ", oMemvar
END SEQUENCE
? "After SEQUENCE 6"
BEGIN SEQUENCE
? " Inside SEQUENCE 7"
Break2( )
RECOVER USING oMemvar
? " Recovering in 7 using... ", oMemvar
END SEQUENCE
? "After SEQUENCE 7"
? M->mPrivate
BREAK( "exit from MAIN" )
? "This text will be not printed"
RETURN
PROCEDURE Break1()
PRIVATE mPrivate:='VALUE from Break1'
BREAK M->mPrivate
RETURN
PROCEDURE Break2()
BEGIN SEQUENCE
? " Inside SEQUENCE 8"
Break3( )
RECOVER USING oMemvar
? " Recovering in 8 using...", EVAL( oMemvar, ' eval in 8' )
BREAK( "BREAK from recovery code" )
END SEQUENCE
? "After SEQUENCE 8"
RETURN
PROCEDURE Break3()
STATIC oStatic
BEGIN SEQUENCE
? " Inside SEQUENCE 9"
BEGIN SEQUENCE
? " Inside SEQUENCE 10"
Break( "value from nested SEQUENCE 10" )
RECOVER USING oStatic
? " Recovering in 10 using...", oStatic
END SEQUENCE
? "After SEQUENCE 10"
Break4( " and parameter" )
RECOVER USING oMemvar
? " Recovering in 9 using...", EVAL( oMemvar, ' eval in 9' )
BREAK( oMemvar )
END SEQUENCE
? "After SEQUENCE 9"
RETURN
PROCEDURE Break4( cValue )
LOCAL oLocal:=' detached Break4 '
BREAK( {|x| oLocal + x + cValue} )
RETURN