ChangeLog 19990823-12:40
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
#include "extend.h"
|
||||
#include "errorapi.h"
|
||||
#include "inkey.h"
|
||||
#include "init.h"
|
||||
|
||||
#if defined( OS_UNIX_COMPATIBLE )
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ PRG_SOURCES=\
|
||||
arreval.prg \
|
||||
arrindex.prg \
|
||||
atest.prg \
|
||||
begin.prg \
|
||||
box.prg \
|
||||
byref.prg \
|
||||
calling.prg \
|
||||
|
||||
131
harbour/tests/working/begin.prg
Normal file
131
harbour/tests/working/begin.prg
Normal 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
|
||||
Reference in New Issue
Block a user