see ChangeLog 1999.05.08-03:02
This commit is contained in:
@@ -1,3 +1,30 @@
|
||||
Sat May 8 03:02:04 1999 Ryszard Glab <rglab@imid.med.pl>
|
||||
|
||||
* source/compiler/harbour.y, source/compiler/harbour.l
|
||||
-static variables can be accessed in a codeblock even if this
|
||||
codeblock is a return value (detached static variables)
|
||||
-Harbour finds now illegal initializations of static variables
|
||||
(static variables can be initialized using literals only)
|
||||
-there is no 'redefinition of predefined function' error when the name
|
||||
of compiled source code is the same as reserved function
|
||||
-corrected support for /*******/ comments
|
||||
-Harbour distinguish now 'CASE' variable, 'CASE()' function and
|
||||
CASE statement (see tests/working/keywords.prg)
|
||||
|
||||
* tests/working/keywords.prg
|
||||
-added many more wild statements to test Harbour compiler
|
||||
|
||||
* test/working/statics.prg
|
||||
-added code to test access of static variables from a codeblock
|
||||
|
||||
* source/rtl/extend.c
|
||||
-added brackets to avoid ambiguous if/else
|
||||
|
||||
* source/include/extend.h
|
||||
* source/rtl/codebloc.c
|
||||
- added support for static variables in a codeblock
|
||||
|
||||
|
||||
19990507-20:15 EDT David G. Holm <dholm@jsd-llc.com>
|
||||
* source/compiler/harbour.l
|
||||
* source/compiler/harbour.y
|
||||
@@ -37,9 +64,10 @@ Thu May 07 17:00:00 1999 Victor Szel <info@szelvesz.hu>
|
||||
19990507-07:25 Ryszard Glab <rglab@imid.med.pl>
|
||||
|
||||
* source/compiler/harbour.y, source/compiler/harbour.l
|
||||
-improoved support for BEGIN SEGEUENCE
|
||||
-added distinction between BEGIN comannd and begin variable
|
||||
-added distinction between BREAK command and break variable
|
||||
-improoved support for BEGIN SEGEUENCE
|
||||
-added distinction between BEGIN command and begin variable
|
||||
-added distinction between BREAK command and break variable
|
||||
|
||||
* tests/working/keywords.prg
|
||||
-new file to test if we are 100% compatible with Clipper
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@ typedef struct /* items hold at the virtual machine stack */
|
||||
void * pBaseArray; /* array base */
|
||||
} value;
|
||||
WORD wBase; /* stack frame number of items position for a function call */
|
||||
PSYMBOL pSymbols; /* codeblocks symbols */
|
||||
WORD wLine; /* currently processed PRG line number */
|
||||
WORD wParams; /* number of received parameters for a function call */
|
||||
} ITEM, * PITEM;
|
||||
@@ -106,6 +105,7 @@ typedef struct
|
||||
WORD wDetached; /* holds if pItems table variables values */
|
||||
PSYMBOL pSymbols; /* codeblocks symbols */
|
||||
WORD wRefBase; /* stack frame position for referenced local variables */
|
||||
int iStatBase; /* static base for function where CB was created */
|
||||
long lCounter; /* numer of references to this codeblock */
|
||||
} CODEBLOCK, * PCODEBLOCK;
|
||||
|
||||
|
||||
@@ -55,7 +55,15 @@ long lNumber = 0;
|
||||
#define LOOKUP 0
|
||||
int _iState = LOOKUP;
|
||||
|
||||
//Comment1 "/*"((.*)|(\n))"*/"
|
||||
void yy_lex_count_lf( void )
|
||||
{
|
||||
char * pTmp = yytext;
|
||||
while( (pTmp = strchr(pTmp, '\n')) )
|
||||
{
|
||||
++iLine;
|
||||
++pTmp;
|
||||
}
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
@@ -67,7 +75,7 @@ Identifier (([a-zA-Z])|([_a-zA-Z][_a-zA-Z0-9]+))
|
||||
String (\"(([^\"]*)|([\!]*))\")|(\'(([^\']*)|([\!]*))\')
|
||||
PseudoFunc {Identifier}"("+.*")"+
|
||||
|
||||
Comment1 "/*"([^\*]|("*"[^\/]))*"*/"
|
||||
Comment1 "/*"(.*|[\n])"*/"
|
||||
Comment2 [\/][\/].*
|
||||
Comment ({Comment1}|{Comment2})
|
||||
LineCont (;.*\n)
|
||||
@@ -75,7 +83,7 @@ Separator {SpaceTab}|{Comment}|{LineCont}
|
||||
|
||||
%x COMMENT3 DEFINE DEFINE_PARAMS DEFINE_EXPR
|
||||
%x IFDEF IFNDEF STRING1 STRING2
|
||||
%x NEXT_ BREAK_
|
||||
%x NEXT_ BREAK_ CASE_
|
||||
|
||||
%%
|
||||
|
||||
@@ -96,8 +104,9 @@ Separator {SpaceTab}|{Comment}|{LineCont}
|
||||
yylval.string[ yyleng - 2 ] = 0; return LITERAL; }
|
||||
|
||||
"/*" BEGIN COMMENT3;
|
||||
<COMMENT3>"*/" BEGIN 0;
|
||||
<COMMENT3>"*"["*"]*"/" BEGIN 0;
|
||||
<COMMENT3>[^"*/"\n]* ;
|
||||
<COMMENT3>"*" ;
|
||||
<COMMENT3>[\/\"]+ ;
|
||||
<COMMENT3>\n ++iLine; if( ! _iQuiet ) printf( "\rline: %i", iLine );
|
||||
|
||||
@@ -154,28 +163,64 @@ Separator {SpaceTab}|{Comment}|{LineCont}
|
||||
}
|
||||
else
|
||||
{ /* there is another item in line already */
|
||||
yylval.string = "BrEaK";
|
||||
yylval.string = strdup("BrEaK");
|
||||
return IDENTIFIER;
|
||||
}
|
||||
}
|
||||
<BREAK_>{Separator}*[^_a-zA-Z] { /* there is no identifier after "break" */
|
||||
yy_lex_count_lf();
|
||||
BEGIN 0;
|
||||
yylval.string = ((yytext[ yyleng-1 ] =='(')?"BREAK":"BrEaK");
|
||||
yylval.string = strdup( ((yytext[ yyleng-1 ] =='(')?"BREAK":"BrEaK") );
|
||||
_iState =IDENTIFIER;
|
||||
unput( yytext[ yyleng-1 ] );
|
||||
return IDENTIFIER;
|
||||
}
|
||||
<BREAK_>{Separator}*. { /* an identifier follows BREAK statement */
|
||||
yy_lex_count_lf();
|
||||
BEGIN 0;
|
||||
unput( yytext[ yyleng-1 ] );
|
||||
_iState =BREAK;
|
||||
return BREAK;
|
||||
}
|
||||
<BREAK_>. { BEGIN 0; unput( yytext[ yyleng-1 ] ); }
|
||||
"case" return CASE;
|
||||
"case" { BEGIN CASE_; }
|
||||
<CASE_>{Separator}*[\:\=\|\$\%\*\,\/\[\]\)\}] { /* there is an operator after "case" */
|
||||
yy_lex_count_lf();
|
||||
BEGIN 0;
|
||||
yylval.string = strdup( "CASE" );
|
||||
_iState =IDENTIFIER;
|
||||
unput( yytext[ yyleng-1 ] );
|
||||
return IDENTIFIER;
|
||||
}
|
||||
<CASE_>{Separator}*("+="|"-=") { /* operators */
|
||||
yy_lex_count_lf();
|
||||
BEGIN 0;
|
||||
yylval.string = strdup( "CASE" );
|
||||
_iState =IDENTIFIER;
|
||||
unput( yytext[ yyleng-2 ] );
|
||||
unput( yytext[ yyleng-1 ] );
|
||||
return IDENTIFIER;
|
||||
}
|
||||
<CASE_>{Separator}*(\n|.) { /* not operator */
|
||||
yy_lex_count_lf();
|
||||
BEGIN 0;
|
||||
if( yytext[ yyleng-1 ] == '\n' )
|
||||
--iLine;
|
||||
unput( yytext[ yyleng-1 ] );
|
||||
if( _iState == LOOKUP )
|
||||
{ /* it is first item in the line */
|
||||
_iState =CASE;
|
||||
return CASE;
|
||||
}
|
||||
else
|
||||
{ /* there is another item in line already */
|
||||
yylval.string = strdup( "CASE" );
|
||||
return IDENTIFIER;
|
||||
}
|
||||
}
|
||||
"do" return DO;
|
||||
"do"{SpaceTab}+"case" return DOCASE;
|
||||
("do"{SpaceTab}+"while")|"while" return WHILE;
|
||||
"do"{Separator}+"case" { _iState =DOCASE; return DOCASE; }
|
||||
("do"{SpaceTab}+"while")|"while" { _iState =WHILE; return WHILE; }
|
||||
"else" return ELSE;
|
||||
"elseif" _iState =ELSEIF; return ELSEIF;
|
||||
"end"/[^(] return END;
|
||||
@@ -208,18 +253,20 @@ Separator {SpaceTab}|{Comment}|{LineCont}
|
||||
else
|
||||
{ /* there is another item in line already */
|
||||
unput( yytext[ yyleng-1 ] );
|
||||
yylval.string = "nExT";
|
||||
yylval.string = strdup( "nExT" );
|
||||
return IDENTIFIER;
|
||||
}
|
||||
}
|
||||
<NEXT_>{Separator}*[^_a-zA-Z\n\;] { /* there is no identifier after "next" */
|
||||
<NEXT_>{Separator}*[^_a-zA-Z] { /* there is no identifier after "next" */
|
||||
yy_lex_count_lf();
|
||||
BEGIN 0;
|
||||
yylval.string = ((yytext[ yyleng-1 ] =='(')?"NEXT":"nExT");
|
||||
yylval.string = strdup( ((yytext[ yyleng-1 ] =='(')?"NEXT":"nExT") );
|
||||
unput( yytext[ yyleng-1 ] );
|
||||
_iState =IDENTIFIER;
|
||||
return IDENTIFIER;
|
||||
}
|
||||
<NEXT_>{Separator}*. { /* an identifier follows NEXT statement */
|
||||
yy_lex_count_lf();
|
||||
BEGIN 0;
|
||||
unput( yytext[ yyleng-1 ] );
|
||||
_iState =NEXT;
|
||||
@@ -311,7 +358,7 @@ Separator {SpaceTab}|{Comment}|{LineCont}
|
||||
|
||||
{String} yylval.string = strdup( yytext + 1 ); yylval.string[ yyleng - 2 ] = 0; return LITERAL;
|
||||
|
||||
{LineCont} { ++iLine; }
|
||||
{LineCont} ++iLine;
|
||||
|
||||
{Identifier} {
|
||||
PDEFINE pDef = FindDef( yytext );
|
||||
|
||||
@@ -80,6 +80,8 @@ typedef struct __FUNC /* functions definition support */
|
||||
*/
|
||||
#define FUN_STATEMENTS 1 /* Function have at least one executable statement */
|
||||
#define FUN_USES_STATICS 2 /* Function uses static variables */
|
||||
#define FUN_PROCEDURE 4 /* This is a procedure that shouldn't return value */
|
||||
#define FUN_ILLEGAL_INIT 8 /* Attempt to initialize static variable with a function call */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -172,7 +174,7 @@ void FixElseIfs( void * pIfElseIfs ); /* implements the ElseIfs pcode fixups */
|
||||
void FixReturns( void ); /* fixes all last defined function returns jumps offsets */
|
||||
void Function( BYTE bParams ); /* generates the pcode to execute a Clipper function pushing its result */
|
||||
PFUNCTION FunctionNew( char *, char ); /* creates and initialises the _FUNC structure */
|
||||
void FunDef( char * szFunName, char cScope ); /* starts a new Clipper language function definition */
|
||||
void FunDef( char * szFunName, char 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 * GenElseIf( void * pFirstElseIf, WORD wOffset ); /* generates a support structure for elseifs pcode fixups */
|
||||
void GenError( int, char*, char * ); /* generic parsing error management function */
|
||||
@@ -222,6 +224,7 @@ void CodeBlockEnd( void ); /* end of codeblock creation */
|
||||
/* Static variables */
|
||||
void StaticDefStart( void );
|
||||
void StaticDefEnd( WORD );
|
||||
void StaticAssign( void ); /* checks if static variable is initialized with function call */
|
||||
|
||||
void * OurMalloc( LONG lSize ); /* our malloc with error control */
|
||||
void * OurRealloc( void * p, LONG lSize ); /* our malloc with error control */
|
||||
@@ -262,6 +265,7 @@ int iVarScope = 0; /* holds the scope for next variables to be defined
|
||||
#define ERR_NUMERIC_FORMAT 6
|
||||
#define ERR_STRING_TERMINATOR 7
|
||||
#define ERR_FUNC_RESERVED 8
|
||||
#define ERR_ILLEGAL_INIT 9
|
||||
|
||||
/* Table with parse errors */
|
||||
char * _szErrors[] = { "Statement not allowed outside of procedure or function",
|
||||
@@ -271,7 +275,8 @@ char * _szErrors[] = { "Statement not allowed outside of procedure or function",
|
||||
"Outer codeblock variable is out of reach: \'%s\'",
|
||||
"Invalid numeric format '.'",
|
||||
"Unterminated string: \'%s\'",
|
||||
"Redefinition of predefined function %s: \'%s\'"
|
||||
"Redefinition of predefined function %s: \'%s\'",
|
||||
"Illegal initializer: \'%s\'"
|
||||
};
|
||||
|
||||
/* Table with reserved functions names
|
||||
@@ -468,8 +473,8 @@ ExtList : IDENTIFIER { AddExtern( $1 ); }
|
||||
| ExtList ',' IDENTIFIER { AddExtern( $3 ); }
|
||||
;
|
||||
|
||||
Function : FunScope FUNCTION IDENTIFIER { FunDef( $3, $1 ); } Params Crlf { SetFrame(); }
|
||||
| FunScope PROCEDURE IDENTIFIER { FunDef( $3, $1 ); } Params Crlf { SetFrame(); }
|
||||
Function : FunScope FUNCTION IDENTIFIER { FunDef( $3, $1, 0 ); } Params Crlf { SetFrame(); }
|
||||
| FunScope PROCEDURE IDENTIFIER { FunDef( $3, $1, FUN_PROCEDURE ); } Params Crlf { SetFrame(); }
|
||||
;
|
||||
|
||||
FunScope : { $$ = FS_PUBLIC; }
|
||||
@@ -523,14 +528,14 @@ FunCall : FunStart ')' { $$ = 0; }
|
||||
| FunStart ArgList ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
FunStart : IDENTIFIER '(' { PushSymbol( $1, 1 ); PushNil(); $$ = $1; }
|
||||
FunStart : IDENTIFIER '(' { StaticAssign(); PushSymbol( $1, 1 ); PushNil(); $$ = $1; }
|
||||
;
|
||||
|
||||
MethCall : MethStart ')' { $$ = 0; }
|
||||
| MethStart ArgList ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
MethStart : IDENTIFIER '(' { Message( $1 ); $$ = $1; }
|
||||
MethStart : IDENTIFIER '(' { StaticAssign(); Message( $1 ); $$ = $1; }
|
||||
;
|
||||
|
||||
ArgList : ',' { PushNil(); PushNil(); $$ = 2; }
|
||||
@@ -1127,7 +1132,7 @@ int harbour_main( int argc, char * argv[] )
|
||||
|
||||
if( Include( szFileName ) )
|
||||
{
|
||||
FunDef( strupr( strdup( pFileName->name ) ), FS_PUBLIC );
|
||||
FunDef( strupr( strdup( pFileName->name ) ), FS_PUBLIC, FUN_PROCEDURE );
|
||||
yyparse();
|
||||
FixReturns(); /* fix all previous function returns offsets */
|
||||
fclose( yyin );
|
||||
@@ -1397,7 +1402,14 @@ void AddVar( char * szVarName )
|
||||
* defined is stored in pOwner member.
|
||||
*/
|
||||
if( iVarScope == VS_STATIC )
|
||||
{
|
||||
pFunc =pFunc->pOwner;
|
||||
/* Check if an illegal action was invoked during a static variable
|
||||
* value initialization
|
||||
*/
|
||||
if( _pInitFunc->bFlags & FUN_ILLEGAL_INIT )
|
||||
GenError( ERR_ILLEGAL_INIT, szVarName, pFunc->szName );
|
||||
}
|
||||
|
||||
/* Check if a declaration of duplicated variable name is requested */
|
||||
if( pFunc->szName )
|
||||
@@ -1583,7 +1595,13 @@ PFUNCTION FunctionNew( char *szName, char cScope )
|
||||
return pFunc;
|
||||
}
|
||||
|
||||
void FunDef( char * szFunName, char cScope ) /* stores a Clipper defined function */
|
||||
/*
|
||||
* Stores a Clipper defined function/procedure
|
||||
* szFunName - name of a function
|
||||
* cScope - scope of a function
|
||||
* iType - FUN_PROCEDURE if a procedure or 0
|
||||
*/
|
||||
void FunDef( char * szFunName, char cScope, int iType )
|
||||
{
|
||||
PCOMSYMBOL pSym;
|
||||
PFUNCTION pFunc;
|
||||
@@ -1620,6 +1638,7 @@ void FunDef( char * szFunName, char cScope ) /* stores a Clipper defined functi
|
||||
pSym->cScope |= cScope; /* we may have a non public function and a object message */
|
||||
|
||||
pFunc =FunctionNew( szFunName, cScope );
|
||||
pFunc->bFlags |= iType;
|
||||
|
||||
if( functions.iCount == 0 )
|
||||
{
|
||||
@@ -2677,6 +2696,14 @@ void PushId( char * szVarName ) /* generates the pcode to push a variable value
|
||||
{
|
||||
WORD wVar;
|
||||
|
||||
if( iVarScope == VS_STATIC )
|
||||
{
|
||||
/* Reffering to any variable is not allowed during initialization
|
||||
* of static variable
|
||||
*/
|
||||
_pInitFunc->bFlags |= FUN_ILLEGAL_INIT;
|
||||
}
|
||||
|
||||
if( ( wVar = GetLocalVarPos( szVarName ) ) )
|
||||
GenPCode3( _PUSHLOCAL, LOBYTE( wVar ), HIBYTE( wVar ) );
|
||||
|
||||
@@ -2698,6 +2725,14 @@ void PushIdByRef( char * szVarName ) /* generates the pcode to push a variable b
|
||||
{
|
||||
WORD wVar;
|
||||
|
||||
if( iVarScope == VS_STATIC )
|
||||
{
|
||||
/* Reffering to any variable is not allowed during initialization
|
||||
* of static variable
|
||||
*/
|
||||
_pInitFunc->bFlags |= FUN_ILLEGAL_INIT;
|
||||
}
|
||||
|
||||
if( ( wVar = GetLocalVarPos( szVarName ) ) )
|
||||
GenPCode3( _PUSHLOCALREF, LOBYTE( wVar ), HIBYTE( wVar ) );
|
||||
|
||||
@@ -3110,7 +3145,7 @@ void StaticDefStart( void )
|
||||
{
|
||||
_pInitFunc =FunctionNew( "_INITSTATICS", FS_INIT );
|
||||
_pInitFunc->pOwner =functions.pLast;
|
||||
_pInitFunc->bFlags =FUN_USES_STATICS;
|
||||
_pInitFunc->bFlags =FUN_USES_STATICS | FUN_PROCEDURE;
|
||||
functions.pLast =_pInitFunc;
|
||||
PushInteger( 1 ); /* the number of static variables is unknown now */
|
||||
GenPCode3( _STATICS, 0, 0 );
|
||||
@@ -3133,6 +3168,18 @@ void StaticDefEnd( WORD wCount )
|
||||
functions.pLast =_pInitFunc->pOwner;
|
||||
_pInitFunc->pOwner =NULL;
|
||||
_wStatics += wCount;
|
||||
iVarScope =0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks if we are initializing a static variable.
|
||||
* It should be called only in case when the parser have recognized any
|
||||
* function or method invocation.
|
||||
*/
|
||||
void StaticAssign( void )
|
||||
{
|
||||
if( iVarScope == VS_STATIC )
|
||||
_pInitFunc->bFlags |= FUN_ILLEGAL_INIT;
|
||||
}
|
||||
|
||||
void * OurMalloc( LONG lSize )
|
||||
|
||||
@@ -23,7 +23,8 @@ extern STACK stack;
|
||||
* +2 bytes -> table of referenced local variables
|
||||
* +2 + 2 *(number of referenced variables) -> codeblock pcode
|
||||
*/
|
||||
PCODEBLOCK CodeblockNew( BYTE * pBuffer, WORD wSize, PSYMBOL pSymbols )
|
||||
PCODEBLOCK CodeblockNew( BYTE * pBuffer, WORD wSize, PSYMBOL pSymbols,
|
||||
int iStaticsBase, WORD wStackBase )
|
||||
{
|
||||
PCODEBLOCK pCBlock;
|
||||
WORD wVars;
|
||||
@@ -61,18 +62,26 @@ PCODEBLOCK CodeblockNew( BYTE * pBuffer, WORD wSize, PSYMBOL pSymbols )
|
||||
/* the codeblock initally contains references to local variables
|
||||
*/
|
||||
pCBlock->wDetached =FALSE;
|
||||
/* since the only allowed operation on a codeblock is evaluating it then
|
||||
* there is no need to duplicate its pcode -just store the poiter to it
|
||||
/*
|
||||
* pcode is stored in static segment now.
|
||||
* The only allowed operation on a codeblock is evaluating it then
|
||||
* there is no need to duplicate its pcode -just store the pointer to it
|
||||
*/
|
||||
pCBlock->pCode = (BYTE *) _xgrab( wSize );
|
||||
memcpy( pCBlock->pCode, pBuffer, wSize );
|
||||
pCBlock->pCode = pBuffer;
|
||||
|
||||
pCBlock->pSymbols =pSymbols;
|
||||
pCBlock->wDetached =FALSE;
|
||||
pCBlock->lCounter =1;
|
||||
pCBlock->iStatBase =iStaticsBase;
|
||||
/*
|
||||
* wStackBase is stack base of function where the codeblock was defined
|
||||
* We need it because stack.pBase points to a stack base of EVAL function
|
||||
* at the time of codeblock evaluation.
|
||||
*/
|
||||
pCBlock->wRefBase =wStackBase;
|
||||
|
||||
#ifdef CODEBLOCKDEBUG
|
||||
printf( "codeblock created (%li)\n", pCBlock->lCounter );
|
||||
printf( "codeblock created (%li) %lx\n", pCBlock->lCounter, pCBlock );
|
||||
#endif
|
||||
return pCBlock;
|
||||
}
|
||||
@@ -82,7 +91,7 @@ PCODEBLOCK CodeblockNew( BYTE * pBuffer, WORD wSize, PSYMBOL pSymbols )
|
||||
void CodeblockDelete( PCODEBLOCK pCBlock )
|
||||
{
|
||||
#ifdef CODEBLOCKDEBUG
|
||||
printf( "delete a codeblock (%li)\n", pCBlock->lCounter );
|
||||
printf( "delete a codeblock (%li) %lx\n", pCBlock->lCounter, pCBlock );
|
||||
#endif
|
||||
if( --pCBlock->lCounter == 0 )
|
||||
{
|
||||
@@ -92,14 +101,11 @@ void CodeblockDelete( PCODEBLOCK pCBlock )
|
||||
*/
|
||||
while( w < pCBlock->wLocals )
|
||||
ItemRelease( &pCBlock->pItems[ w++ ] );
|
||||
/* free space allocated for a codeblock pcodes
|
||||
*/
|
||||
_xfree( pCBlock->pCode );
|
||||
/* free space allocated for a CODEBLOCK structure
|
||||
*/
|
||||
_xfree( pCBlock );
|
||||
#ifdef CODEBLOCKDEBUG
|
||||
printf( "codeblock deleted (%li)\n", pCBlock->lCounter );
|
||||
printf( "codeblock deleted (%li) %lx\n", pCBlock->lCounter, pCBlock );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -132,7 +138,7 @@ void CodeblockDetach( PCODEBLOCK pCBlock )
|
||||
pCBlock->wDetached =TRUE;
|
||||
}
|
||||
#ifdef CODEBLOCKDEBUG
|
||||
printf( "codeblock detached(%li)\n", pCBlock->lCounter );
|
||||
printf( "codeblock detached(%li) %lx\n", pCBlock->lCounter, pCBlock );
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -140,10 +146,13 @@ void CodeblockDetach( PCODEBLOCK pCBlock )
|
||||
* wStackBase is stack base of function where the codeblock was defined
|
||||
* We need it because stack.pBase points to a stack base of EVAL function
|
||||
*/
|
||||
void CodeblockEvaluate( PCODEBLOCK pCBlock, WORD wStackBase )
|
||||
void CodeblockEvaluate( PCODEBLOCK pCBlock )
|
||||
{
|
||||
pCBlock->wRefBase =wStackBase;
|
||||
int iStatics = stack.iStatics;
|
||||
|
||||
stack.iStatics = pCBlock->iStatBase;
|
||||
VirtualMachine( pCBlock->pCode, pCBlock->pSymbols );
|
||||
stack.iStatics = iStatics;
|
||||
}
|
||||
|
||||
/* Get local variable referenced in a codeblock
|
||||
@@ -175,6 +184,6 @@ void CodeblockCopy( PITEM pDest, PITEM pSource )
|
||||
pDest->value.pCodeblock =pSource->value.pCodeblock;
|
||||
((PCODEBLOCK) pDest->value.pCodeblock)->lCounter++;
|
||||
#ifdef CODEBLOCKDEBUG
|
||||
printf( "copy a codeblock (%li)\n", ((PCODEBLOCK) pDest->value.pCodeblock)->lCounter);
|
||||
printf( "copy a codeblock (%li) %lx\n", ((PCODEBLOCK) pDest->value.pCodeblock)->lCounter, pDest->value.pCodeblock);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -44,11 +44,12 @@ char * _parc( WORD wParam, ... )
|
||||
pItem = stack.pBase + 1 + wParam;
|
||||
|
||||
if( IS_ARRAY( pItem ) )
|
||||
{
|
||||
if( wArrayIndex )
|
||||
return ArrayGetString( pItem, wArrayIndex );
|
||||
else
|
||||
return "";
|
||||
|
||||
}
|
||||
else if( IS_STRING( pItem ) )
|
||||
return pItem->value.szText;
|
||||
|
||||
@@ -73,11 +74,12 @@ ULONG _parclen( WORD wParam, ... )
|
||||
pItem = stack.pBase + 1 + wParam;
|
||||
|
||||
if( IS_ARRAY( pItem ) )
|
||||
{
|
||||
if( wArrayIndex )
|
||||
return ArrayGetStringLen( pItem, wArrayIndex );
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
else if( IS_STRING( pItem ) )
|
||||
return pItem->wLength;
|
||||
|
||||
|
||||
@@ -112,10 +112,10 @@ void StackPush( void ); /* pushes an item on to the stack */
|
||||
void StackInit( void ); /* initializes the stack */
|
||||
void StackShow( void ); /* show the types of the items on the stack for HBDEBUGging purposes */
|
||||
|
||||
PCODEBLOCK CodeblockNew( BYTE *, WORD, PSYMBOL );
|
||||
PCODEBLOCK CodeblockNew( BYTE *, WORD, PSYMBOL, int, WORD );
|
||||
void CodeblockDelete( PCODEBLOCK );
|
||||
PITEM CodeblockGetVar( PITEM, SHORT );
|
||||
void CodeblockEvaluate( PCODEBLOCK, WORD );
|
||||
void CodeblockEvaluate( PCODEBLOCK );
|
||||
void CodeblockCopy( PITEM, PITEM );
|
||||
void CodeblockDetach( PCODEBLOCK );
|
||||
|
||||
@@ -608,7 +608,7 @@ void Do( WORD wParams )
|
||||
WORD wItemIndex = pItem - stack.pItems;
|
||||
PITEM pSelf = stack.pPos - wParams - 1;
|
||||
HARBOURFUNC pFunc;
|
||||
WORD iStatics = stack.iStatics; /* Return iStatics position */
|
||||
int iStatics = stack.iStatics; /* Return iStatics position */
|
||||
|
||||
if( ! IS_SYMBOL( pItem ) )
|
||||
{
|
||||
@@ -683,7 +683,7 @@ HARBOUR DoBlock( void )
|
||||
*/
|
||||
stack.pBase->wLine =pBlock->wLine;
|
||||
|
||||
CodeblockEvaluate( (PCODEBLOCK)pBlock->value.pCodeblock, pBlock->wBase );
|
||||
CodeblockEvaluate( (PCODEBLOCK)pBlock->value.pCodeblock );
|
||||
|
||||
/* restore stack pointers */
|
||||
stack.pBase = stack.pItems + wStackBase;
|
||||
@@ -1526,7 +1526,8 @@ void PushBlock( BYTE * pCode, WORD wSize, WORD wParam, PSYMBOL pSymbols )
|
||||
{
|
||||
ItemRelease( stack.pPos );
|
||||
stack.pPos->wType = IT_BLOCK;
|
||||
stack.pPos->value.pCodeblock = (BYTE *)CodeblockNew( pCode, wSize, pSymbols );
|
||||
stack.pPos->value.pCodeblock = (BYTE *)CodeblockNew( pCode, wSize, pSymbols,
|
||||
stack.iStatics, stack.pBase - stack.pItems );
|
||||
/* store the stack base of function where the codeblock was defined */
|
||||
stack.pPos->wBase = stack.pBase - stack.pItems;
|
||||
/* store the number of expected parameters */
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
//DO NOT RUN THIS PROGRAM - ITS PURPOSE IS THE SYNTAX CHECK ONLY!
|
||||
|
||||
STATIC nExt, bEgin, bReak
|
||||
STATIC nExt, bEgin, bReak, cAse
|
||||
|
||||
Function Main()
|
||||
|
||||
NEXT(nExt)
|
||||
BEGIN( bEgin +';' + ; //////
|
||||
";" ; /* ;;;;;just trying to be smart;;;;;;; */
|
||||
//just to prevent any disaster if someone will want to run it
|
||||
IF( .T. )
|
||||
RETURN nil
|
||||
ENDIF
|
||||
|
||||
NEXT(nExt) //in Clipper: NEXT does not match FOR
|
||||
BEGIN( bEgin +';' + ;; //////Clipper doesn't like more then one ';'
|
||||
";" ; /* ;;;;;Clipper doesn't like this comment after ';' ;;;;;;; */
|
||||
)
|
||||
BREAK_(bReak)
|
||||
// CASE(case) //it is not possible to call case() in this context
|
||||
case :=CASE( CASE ) //this is valid
|
||||
|
||||
RETURN nil
|
||||
|
||||
/*================================================================
|
||||
************************************************ Checking for NEXT
|
||||
* * * * * ** Checking for NEXT
|
||||
*/
|
||||
FUNCTION NeXT( next_next/*next next*/ )
|
||||
Local nExt, nExt7, nExtNEXT
|
||||
@@ -23,15 +33,24 @@ Local nExt, nExt7, nExtNEXT
|
||||
OutStd( nExT ) // Actually this needs to use str()
|
||||
|
||||
Next /*next*/ nExt //next
|
||||
//NEXT
|
||||
|
||||
FOR nExt = 1 TO nExt
|
||||
QOut( nExt )
|
||||
NEXT
|
||||
|
||||
FOR nExt :=1 TO 10
|
||||
QOut( nExt )
|
||||
NEXT ; ////////// ;
|
||||
NEXT
|
||||
|
||||
nExt := 10 //next
|
||||
|
||||
nExt++ /*n_ext*/ //---
|
||||
nExt++ /*in Clipper: NEXT does not match FOR*/
|
||||
--nExt /*next*/
|
||||
nExt7 :=7
|
||||
nExtNEXT := nExt //next
|
||||
|
||||
nExt[ 1 ] :=nExt //in Clipper: NEXT does not match FOR
|
||||
nExt[ nExt ] := NEXT( nExt[nExt+nExt] * nExt *(nExt+nExt*5) )
|
||||
|
||||
IF( nExt > nExt+4 )
|
||||
@@ -48,11 +67,10 @@ RETURN( nExt * /*next*/ nExt )
|
||||
* Checking for BEGIN
|
||||
*/
|
||||
FUNCTION BEGIN( BEGIN_BEGIN )
|
||||
//LOCAL bEgin, xbEgin , bEginBEGIN , bEgin0, xbEginBEGIN:=100
|
||||
LOCAL bEgin
|
||||
LOCAL xbEgin
|
||||
LOCAL bEginBEGIN
|
||||
LOCAL bEgin0, /* BEGIN OF BEGIN */ ; /* begin */
|
||||
LOCAL bEgin0, /* BEGIN OF BEGIN */ ; /* in Clipper: Incomplete statement */
|
||||
bEgin1
|
||||
LOCAL xbEginBEGIN := 100
|
||||
|
||||
@@ -91,12 +109,28 @@ LOCAL bReak:=0
|
||||
IF( bReak = 0 )
|
||||
Break /*break*/ ( nil )
|
||||
BREAK /* break to beggining */
|
||||
Break() //this line is not valid in Clipper: syntax error: ')'
|
||||
Break() //in Clipper: syntax error: ')'
|
||||
ENDIF
|
||||
|
||||
Break /* break in break */ ;;;
|
||||
; /////////////
|
||||
()
|
||||
Break /**** BREAK AGAIN ****/; ;;;;;
|
||||
; //////////////////////////////////////////////////
|
||||
; //What
|
||||
; //the
|
||||
; //comment
|
||||
; //like
|
||||
; //it
|
||||
; //is
|
||||
; //doing
|
||||
; //in
|
||||
; //this
|
||||
; //place?
|
||||
; //Do
|
||||
; //you
|
||||
; //use
|
||||
; //it
|
||||
; //often?
|
||||
;///////////////////////////////////////////////////
|
||||
() //in Clipper: incomplete statement or unbalanced delimiters
|
||||
|
||||
begin sequence
|
||||
FOR bReak:=1 To 10
|
||||
@@ -109,4 +143,51 @@ recover USING bReak
|
||||
end
|
||||
|
||||
BREAK
|
||||
RETURN bReak[ bReak ]
|
||||
RETURN bReak[ bReak ] //in Clipper: syntax error ' BREAK '
|
||||
|
||||
/*====================================================================
|
||||
* Test for CASE/DO CASE
|
||||
*/
|
||||
FUNCTION CASE( case_ )
|
||||
LOCAL case
|
||||
|
||||
FOR case:=1 TO 15
|
||||
QUOT( case )
|
||||
QOUT( case * ; ////
|
||||
case )
|
||||
NEXT case
|
||||
|
||||
case[ case ] :=case //in Clipper: Case is not immediatelly within DO CASE
|
||||
case[ 2 ] :=2 //in Clipper: the same as above - Harbour compiles both
|
||||
case =case + case - case
|
||||
case :={|case| case( case )}
|
||||
case :={|| case }
|
||||
|
||||
DO /* case */ CASE
|
||||
CASE 1
|
||||
case =case ** case
|
||||
CASE 2+case
|
||||
case =case +1
|
||||
CASE case++
|
||||
// case-- //sorry -Clipper also doesn't compile this line
|
||||
// case++ //sorry -Clipper also doesn't compile this line
|
||||
CASE ++case
|
||||
++case
|
||||
CASE ;
|
||||
case( case )
|
||||
CASE CASE
|
||||
CASE !CASE
|
||||
CASE -CASE
|
||||
CASE +CASE
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
CASE( CASE )
|
||||
case =case != case
|
||||
CASE( CASE ) //new CASE or function call? :)
|
||||
OTHERWISE
|
||||
case *=case
|
||||
ENDCASE
|
||||
|
||||
RETURN case
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
static z := "First"
|
||||
|
||||
function Main()
|
||||
LOCAL i
|
||||
LOCAL i, cb
|
||||
|
||||
static a := "Hello", b := { 1, 3 }
|
||||
static a := "Hello", b := { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
|
||||
|
||||
QOut( a )
|
||||
QOut( b[ 2 ] )
|
||||
@@ -17,6 +17,11 @@ LOCAL i
|
||||
FOR i:=1 TO 10
|
||||
NumStat()
|
||||
NEXT
|
||||
|
||||
cb :=DetachVar( 10 )
|
||||
FOR i:=1 To 10
|
||||
QOut( EVAL( cb, b[ i ] ) )
|
||||
NEXT
|
||||
|
||||
return nil
|
||||
|
||||
@@ -32,8 +37,20 @@ FUNCTION THREE( p )
|
||||
QOut( p )
|
||||
RETURN p
|
||||
|
||||
PROCEDURE NumStat()
|
||||
STATIC n:=0
|
||||
PROCEDURE NumStat(a)
|
||||
STATIC n:=1
|
||||
LOCAL cb
|
||||
//STATIC m:=n //uncomment it to see an error
|
||||
//STATIC m:=Time() //uncomment it to see an error
|
||||
|
||||
cb :={|x| z +STR(x)}
|
||||
QOut( ++n )
|
||||
QOut( z )
|
||||
RETURN
|
||||
QOut( EVAL( cb,n ) )
|
||||
|
||||
RETURN
|
||||
|
||||
|
||||
FUNCTION DetachVar( xLocal )
|
||||
STATIC xStatic:=100
|
||||
|
||||
RETURN( {|x| ++xStatic, x+xStatic+xLocal} )
|
||||
Reference in New Issue
Block a user