diff --git a/harbour/ChangeLog b/harbour/ChangeLog index ceff87c6b0..0272ead1b5 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,3 +1,31 @@ +19990604-02:22 Ryszard Glab + +* source/compiler/harbour.y + * corrected "unmatched END" error if BEGIN/END SEQUENCE was used + + LOOP now loops to the begginig of FOR/NEXT or WHILE statement + + EXIT now exits from FOR/NEXT or WHILE statement + +* source/compiler/harbour.l + * corrected support for the following keywords: + IF, IIF (90 % compatible with Clipper), IN, INCLUDE, INIT, LOCAL, LOOP + +* source/vm/hvm.c + local variables passed by reference in a codeblock are handled + correctly now + +* include/hberrors.h + + added new error message + +* tests/working/keywords.prg + + added some new keywords for compatibility testing + ++ tests/working/keywords.ch + + new file for INCLUDE testing + ++ doc/codebloc.txt + + new file with a short description of a codeblock implementation + + 19990603-19:00 EDT David G. Holm Thanks go to Ryszard Glab * makefile.dos diff --git a/harbour/doc/codebloc.txt b/harbour/doc/codebloc.txt new file mode 100644 index 0000000000..5e253d1deb --- /dev/null +++ b/harbour/doc/codebloc.txt @@ -0,0 +1,75 @@ +The Harbour implementation of codeblocks. +Ryszard Glab + + +The compilation of a codeblock. + During compile the codeblock is stored in the following form: +- the header +- the stream of pcode bytes + + The header stores information about referenced local variables. ++0: the pcode byte for _PUSHBLOCK ++1: the number of bytes that defines a codeblock ++3: number of codeblock parameters (declared between || in a codeblock) ++5: number of used local variables declared in procedure/function where + the codeblock is created ++7: the list of procedure/function local variables positions on the the eval + stack of procedure/function. Every local variable used in a codeblock + occupies 2 bytes in this list. ++x: The stream of pcode bytes follows the header. ++y: the pcode byte for _ENDBLOCK + + +The evaluation of a codeblock. + Before a codeblock evaluation the virtual machine creates the eval stack +where all codeblock parameters are stored (just like function parameters). +When a codeblock parameter is referenced then its position on the eval stack +is used. When a procedure local variable is referenced then the index into +the table of local variables positions (copied from the header) is used. +The negative value is used as an index to distinguish it from the reference +to a codeblock parameter. The table of local variables positions is created +during creation of a codeblock (in PushBlock() function). + + +Detached locals. + If the codeblock is returned from a function and this codeblock refers to +local variables defined in that function then the position of local variable +stored in a codeblock is replaced with the current value of the variable. +In this way the value of local variable can be accessed even outside of the +function where the variable was declared. This proccess is also called +'detaching local variables' + + +Incompatbility with the Clipper. + There is a little difference between the handling of variables passed by +the reference in a codeblock. +The following code explains it (thanks to David G. Holm) + +Function Main() +Local nTest +Local bBlock1 := MakeBlock() +Local bBlock2 := {|| DoThing( @nTest ), qout("From Main: ", nTest ) } + + eval( bBlock1 ) + eval( bBlock2 ) + +Return( NIL ) + +Function MakeBlock() +Local nTest +Return( {|| DoThing( @nTest ), qout("From MakeBlock: ", nTest ) } ) + +Function DoThing( n ) + + n := 42 + +Return( NIL ) + + + In Clipper it produces: +From MakeBlock: NIL +From Main: 42 + + In Harbour it produces (it is the correct output, IMHO) +From MakeBlock: 42 +From Main: 42 diff --git a/harbour/include/hberrors.h b/harbour/include/hberrors.h index 030e2c49bb..4cc4d3792b 100644 --- a/harbour/include/hberrors.h +++ b/harbour/include/hberrors.h @@ -22,5 +22,6 @@ #define ERR_SYNTAX 17 #define ERR_UNCLOSED_STRU 18 #define ERR_UNMATCHED_EXIT 19 +#define ERR_SYNTAX2 20 void GenError( int, char*, char * ); /* generic parsing error management function */ diff --git a/harbour/source/compiler/harbour.l b/harbour/source/compiler/harbour.l index 7120bff74e..64bdcb4ee5 100644 --- a/harbour/source/compiler/harbour.l +++ b/harbour/source/compiler/harbour.l @@ -101,7 +101,7 @@ Separator {SpaceTab}|{Comment}|{LineCont} %x COMMENT3 DEFINE DEFINE_PARAMS DEFINE_EXPR %x IFDEF IFNDEF STRING1 STRING2 STRING3 %x NEXT_ BREAK_ CASE_ DO_ WHILE_ WITH_ END_ EXIT_ EXTERNAL_ FIELD_ -%x FOR_ FUNCTION_ +%x FOR_ FUNCTION_ IIF_ IF_ IN_ INCLUDE_ INIT_ LOCAL_ LOOP_ %s INDEX %% @@ -294,8 +294,17 @@ Separator {SpaceTab}|{Comment}|{LineCont} yy_lex_count_lf(); if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; unput( yytext[ yyleng-1 ] ); - _iState =BREAK; - return BREAK; + if( _iState == LOOKUP ) + { + _iState =BREAK; + return BREAK; + } + else + { + yylval.string = strdup( "BREAK" ); + _iState =IDENTIFIER; + return IDENTIFIER; + } } . { if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; unput( yytext[ yyleng-1 ] ); } %{ @@ -339,6 +348,7 @@ Separator {SpaceTab}|{Comment}|{LineCont} else { /* there is another item in line already */ yylval.string = strdup( "CASE" ); + _iState =IDENTIFIER; return IDENTIFIER; } } @@ -458,6 +468,7 @@ Separator {SpaceTab}|{Comment}|{LineCont} else { /* there is another item in line already */ yylval.string = strdup( "END" ); + _iState =IDENTIFIER; return IDENTIFIER; } } @@ -491,7 +502,7 @@ Separator {SpaceTab}|{Comment}|{LineCont} if( _iState == LOOKUP ) { /* it is first item in the line */ if( _wForCounter == 0 && _wWhileCounter == 0 ) - GenError( ERR_UNMATCHED_EXIT, NULL, NULL ); + GenError( ERR_UNMATCHED_EXIT, "EXIT", NULL ); _iState =EXITLOOP; return EXITLOOP; } @@ -502,7 +513,7 @@ Separator {SpaceTab}|{Comment}|{LineCont} return IDENTIFIER; } } -{Separator}+[_a-zA-Z] { /* an identifier after the EXIT */ +{Separator}+[fFpP] { /* FUNCTION or PROCEDURE after EXIT */ yy_lex_count_lf(); unput( yytext[ yyleng-1 ] ); if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; @@ -638,7 +649,7 @@ Separator {SpaceTab}|{Comment}|{LineCont} "func"|"funct"|"functi"|"functio"|"function" { BEGIN FUNCTION_; } {Separator}+[_a-zA-Z] { yy_lex_count_lf(); - BEGIN 0; + BEGIN 0; /* we can don't care about INDEX_STATE here */ unput( yytext[ yyleng-1 ] ); _iState=FUNCTION; return FUNCTION; @@ -649,13 +660,218 @@ Separator {SpaceTab}|{Comment}|{LineCont} %{ /* ************************************************************************ */ %} -("if"|"iif"){SpaceTab}*/[(] _iState =IF; return IF; -"if" _iState =IF; return IF; -"in" return IN; -"include" return INCLUDE; -"init" return INIT; -"local" _iState =LOCAL; return LOCAL; -"loop" return LOOP; +"iif" { + if( _iState == FUNCTION || _iState == PROCEDURE ) + GenError( ERR_SYNTAX, "IIF", NULL ); + else + BEGIN IIF_; + /* Note: In Clipper: + IIF( expression ) + ENDIF + is not a valid statement -this is why we have to separate + IF and IIF + */ + } +{Separator}*"(" { + yy_lex_count_lf(); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); + _iState=IIF; + return IIF; + } +{Separator}*[^\(] { + GenError( ERR_SYNTAX, ((yytext[ yyleng-1 ]=='\n')?"IIF":yytext), NULL ); + } +%{ +/* ************************************************************************ */ +%} +"if" { + if( _iState == FUNCTION || _iState == PROCEDURE ) + GenError( ERR_SYNTAX, "IF", NULL ); + else + BEGIN IF_; + } +{Separator}*"(" { + yy_lex_count_lf(); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); + if( _iState == LOOKUP ) + _iState =IF; + else + _iState =IIF; + return _iState; + } +{Separator}*[\)\[\]\/\^\*\%\=\$\@] { + GenError( ERR_SYNTAX2, yytext, "IF" ); + } +{Separator}*"->" { + GenError( ERR_SYNTAX2, yytext, "IF" ); + } +{Separator}*[\n] { + GenError( ERR_SYNTAX, "IF", NULL ); + } +{Separator}*("++"|"--")/[\n] { + GenError( ERR_SYNTAX2, yytext, "IF" ); + } +{Separator}*. { + yy_lex_count_lf(); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); + _iState =IF; + return IF; + } +%{ +/* ************************************************************************ */ +%} +"in" BEGIN IN_; +{Separator}+[_a-zA-Z] { + yy_lex_count_lf(); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); + if( _iState == IDENTIFIER ) + return IN; + else + { + yylval.string =strdup( "IN" ); + _iState =IDENTIFIER; + return IDENTIFIER; + } + } +{Separator}*\n { + yy_lex_count_lf(); + --iLine; + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); + yylval.string =strdup( "IN" ); + _iState =IDENTIFIER; + return IDENTIFIER; + } +{Separator}*[0-9] { + GenError( ERR_SYNTAX, yytext, NULL ); + } +{Separator}*. { + yy_lex_count_lf(); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); + yylval.string =strdup( "IN" ); + _iState =IDENTIFIER; + return IDENTIFIER; + } +%{ +/* ************************************************************************ */ +%} +"include" BEGIN INCLUDE_; +{Separator}+\" { /* only "" are allowed for filename */ + yy_lex_count_lf(); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); + _iState =INCLUDE; + return INCLUDE; + } +{Separator}*[^\"] { + yy_lex_count_lf(); + if( yytext[ yyleng-1 ] == '\n' ) + --iLine; + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); + yylval.string =strdup( "INCLUDE" ); + _iState =IDENTIFIER; + return IDENTIFIER; + } +%{ +/* ************************************************************************ */ +%} +"init" BEGIN INIT_; +{Separator}+[fFpP] { /* FUNCTION or PROCEDURE after INIT */ + yy_lex_count_lf(); + unput( yytext[ yyleng-1 ] ); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + if( _iState == LOOKUP ) + { /* it is first item in the line */ + _iState =INIT; + return INIT; + } + else + { /* there is another item in line already */ + yylval.string = strdup( "INIT" ); + _iState =IDENTIFIER; + return IDENTIFIER; + } + } +{Separator}*[^fFpP] { /* any character (not identifier) after EXIT */ + yy_lex_count_lf(); + if( yytext[ yyleng-1 ] == '\n' ) + --iLine; + unput( yytext[ yyleng-1 ] ); + yylval.string = strdup( "INIT" ); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + _iState =IDENTIFIER; + return IDENTIFIER; + } +%{ +/* ************************************************************************ */ +%} +"local" BEGIN LOCAL_; +{Separator}+[_a-zA-Z] { /* an identifier after LOCAL */ + yy_lex_count_lf(); + unput( yytext[ yyleng-1 ] ); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + if( _iState == LOOKUP ) + { /* it is first item in the line */ + _iState =LOCAL; + return LOCAL; + } + else + { /* there is another item in line already */ + yylval.string = strdup( "LOCAL" ); + _iState =IDENTIFIER; + return IDENTIFIER; + } + } +{Separator}*[^a-zA-Z] { /* any character (not identifier) after LOCAL */ + yy_lex_count_lf(); + if( yytext[ yyleng-1 ] == '\n' ) + --iLine; + unput( yytext[ yyleng-1 ] ); + yylval.string = strdup( "LOCAL" ); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + _iState =IDENTIFIER; + return IDENTIFIER; + } +%{ +/* ************************************************************************ */ +%} +"loop" BEGIN LOOP_; +{Separator}*\n { /* at the end of the line */ + yy_lex_count_lf(); + --iLine; + unput( yytext[ yyleng-1 ] ); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + if( _iState == LOOKUP ) + { /* it is first item in the line */ + if( _wWhileCounter == 0 && _wForCounter == 0 ) + GenError( ERR_UNMATCHED_EXIT, "LOOP", NULL ); + _iState =LOOP; + return LOOP; + } + else + { /* there is another item in line already */ + yylval.string = strdup( "LOOP" ); + _iState =IDENTIFIER; + return IDENTIFIER; + } + } +{Separator}*. { /* any character (not LF) after LOOP */ + yy_lex_count_lf(); + unput( yytext[ yyleng-1 ] ); + yylval.string = strdup( "LOOP" ); + if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + _iState =IDENTIFIER; + return IDENTIFIER; + } +%{ +/* ************************************************************************ */ +%} "memvar" _iState =MEMVAR; return MEMVAR; %{ /* ************************************************************************ */ @@ -663,9 +879,10 @@ Separator {SpaceTab}|{Comment}|{LineCont} "next" BEGIN NEXT_; {Separator}*[\n\;] { /* at the end of line */ if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); + --iLine; if( _iState == LOOKUP ) { /* it is first item in the line */ - ++iLine; if( _wForCounter == 0 ) GenError( ERR_NEXTFOR, NULL, NULL ); _iState =NEXT; @@ -713,11 +930,20 @@ Separator {SpaceTab}|{Comment}|{LineCont} {Separator}*. { /* an identifier follows NEXT statement */ yy_lex_count_lf(); if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; - if( _wForCounter == 0 ) - GenError( ERR_NEXTFOR, NULL, NULL ); unput( yytext[ yyleng-1 ] ); - _iState =NEXT; - return NEXT; + if( _iState == LOOKUP ) + { + if( _wForCounter == 0 ) + GenError( ERR_NEXTFOR, NULL, NULL ); + _iState =NEXT; + return NEXT; + } + else + { + yylval.string = strdup( "NEXT" ); + _iState =IDENTIFIER; + return IDENTIFIER; + } } %{ /* ************************************************************************ */ @@ -775,16 +1001,16 @@ Separator {SpaceTab}|{Comment}|{LineCont} {Separator}*. { /* identifiers and literals */ yy_lex_count_lf(); if( i_INDEX_STATE ) BEGIN INDEX; else BEGIN 0; + unput( yytext[ yyleng-1 ] ); if( _iState == LOOKUP || _iState == DO ) - { /* it is first item in the line or after DO */ - unput( yytext[ yyleng-1 ] ); + { /* it is first item in the line or after DO or FIELD */ _iState =WHILE; return WHILE; } else { /* there is another item in line already */ - unput( yytext[ yyleng-1 ] ); yylval.string = strdup( "WHILE" ); + _iState =IDENTIFIER; return IDENTIFIER; } } @@ -833,6 +1059,7 @@ Separator {SpaceTab}|{Comment}|{LineCont} else { yylval.string = strdup( "WITH" ); + _iState =IDENTIFIER; return IDENTIFIER; } } @@ -1025,7 +1252,6 @@ Separator {SpaceTab}|{Comment}|{LineCont} yyleng = 10; } yylval.string = strupr( strdup( yytext ) ); - /*printf( "\nIdentifier = '%s'\n", strupr( strdup( yytext ) ) );*/ return IDENTIFIER; } } diff --git a/harbour/source/compiler/harbour.y b/harbour/source/compiler/harbour.y index 3bdc783af8..bac95ca952 100644 --- a/harbour/source/compiler/harbour.y +++ b/harbour/source/compiler/harbour.y @@ -85,6 +85,20 @@ typedef struct __RETURN struct __RETURN * pNext; } _RETURN, * PRETURN; /* support structure for multiple returns from a function */ +typedef struct _LOOPEXIT +{ + WORD wOffset; + WORD wLine; + struct _LOOPEXIT *pLoopList; + struct _LOOPEXIT *pExitList; + struct _LOOPEXIT *pNext; +} LOOPEXIT, * PLOOPEXIT; /* support structure for EXIT and LOOP statements */ +static void LoopStart( void ); +static void LoopEnd( void ); +static void LoopLoop( void ); +static void LoopExit( void ); +static void LoopHere( void ); + typedef struct /* support for filenames */ { char _buffer[ _POSIX_PATH_MAX+3 ]; @@ -244,8 +258,9 @@ char * _szErrors[] = { "Statement not allowed outside of procedure or function", "ELSE does not match IF", "ELSEIF does not match IF", "Syntax error: \'%s\'", - "Unclosed control structures", - "EXIT statement with no loop in sight" + "Unclosed control structures at line: %i", + "%s statement with no loop in sight", + "Syntax error: \'%s\' in: \'%s\'" }; /* Table with reserved functions names @@ -366,6 +381,7 @@ int _iObj32 = 0; /* generate OBJ 32 bits */ WORD _wStatics = 0; /* number of defined statics variables on the PRG */ PRETURN pReturns = 0; /* list of multiple returns from a function */ PEXTERN pExterns = 0; +PLOOPEXIT pLoops = 0; PATHNAMES *_pIncludePath = NULL; %} @@ -384,7 +400,7 @@ PATHNAMES *_pIncludePath = NULL; }; %token FUNCTION PROCEDURE IDENTIFIER RETURN NIL DOUBLE INASSIGN INTEGER INTLONG -%token LOCAL STATIC IF ELSE ELSEIF END ENDIF LITERAL TRUEVALUE FALSEVALUE +%token LOCAL STATIC IIF IF ELSE ELSEIF END ENDIF LITERAL TRUEVALUE FALSEVALUE %token INCLUDE EXTERN INIT EXIT AND OR NOT PUBLIC EQ NE1 NE2 %token INC DEC ALIAS DOCASE CASE OTHERWISE ENDCASE ENDDO MEMVAR %token WHILE EXIT LOOP END FOR NEXT TO STEP LE GE FIELD IN PARAMETERS @@ -506,8 +522,8 @@ Statement : ExecFlow Crlf {} | PUBLIC VarList Crlf | PRIVATE VarList Crlf | PARAMETERS IdentList Crlf - | EXITLOOP Crlf - | LOOP Crlf + | EXITLOOP Crlf { LoopExit(); } + | LOOP Crlf { LoopLoop(); } | DoProc Crlf ; @@ -591,7 +607,11 @@ Expression : NIL { PushNil(); } | SELF { GenPCode1( _PUSHSELF ); } ; -IfInline : IF '(' Expression ',' { $$ = JumpFalse( 0 ); } +IfInline : IIF '(' Expression ',' { $$ = JumpFalse( 0 ); } + IfInlExp ',' { $$ = Jump( 0 ); JumpHere( $5 ); } + IfInlExp ')' { JumpHere( $8 ); } + + | IF '(' Expression ',' { $$ = JumpFalse( 0 ); } IfInlExp ',' { $$ = Jump( 0 ); JumpHere( $5 ); } IfInlExp ')' { JumpHere( $8 ); } ; @@ -867,11 +887,11 @@ DoWhile : WhileBegin Expression Crlf { $$ = JumpFalse( 0 ); } EndWhile { JumpHere( $4 ); --_wWhileCounter; } | WhileBegin Expression Crlf { $$ = JumpFalse( 0 ); Line(); } - WhileStatements { Jump( $1 - functions.pLast->lPCodePos ); } - EndWhile { JumpHere( $4 ); --_wWhileCounter; } + WhileStatements { LoopHere(); Jump( $1 - functions.pLast->lPCodePos ); } + EndWhile { JumpHere( $4 ); --_wWhileCounter; LoopEnd(); } ; -WhileBegin : WHILE { $$ = functions.pLast->lPCodePos; ++_wWhileCounter; } +WhileBegin : WHILE { $$ = functions.pLast->lPCodePos; ++_wWhileCounter; LoopStart(); } ; WhileStatements : Statement @@ -882,10 +902,10 @@ EndWhile : END | ENDDO ; -ForNext : FOR IDENTIFIER ForAssign Expression { PopId( $2 ); $$ = functions.pLast->lPCodePos; ++_wForCounter; } +ForNext : FOR IDENTIFIER ForAssign Expression { PopId( $2 ); $$ = functions.pLast->lPCodePos; ++_wForCounter; LoopStart(); } TO Expression { PushId( $2 ); } StepExpr Crlf { GenPCode1( _FORTEST ); $$ = JumpTrue( 0 ); /*PushId( $2 )*/; } - ForStatements { PushId( $2 ); GenPCode1( _PLUS ); PopId( $2 ); Jump( $5 - functions.pLast->lPCodePos ); JumpHere( $11 ); } + ForStatements { LoopHere(); PushId( $2 ); GenPCode1( _PLUS ); PopId( $2 ); Jump( $5 - functions.pLast->lPCodePos ); JumpHere( $11 ); LoopEnd(); } ; ForAssign : '=' @@ -905,14 +925,14 @@ ForStatements : ForStat NEXT { --_wForCounter; } ForStat : Statements { Line(); } ; -BeginSeq : BEGINSEQ Crlf { ++_wSeqCounter; } +BeginSeq : BEGINSEQ { ++_wSeqCounter; } Crlf + SeqStatms RecoverSeq END { --_wSeqCounter; } + ; - | BEGINSEQ Crlf { ++_wSeqCounter; } - Statements - RecoverSeq - END { --_wSeqCounter; } +SeqStatms : /* empty */ + | Statements ; RecoverSeq : /* no recover */ @@ -3060,9 +3080,19 @@ void FixReturns( void ) /* fixes all last defined function returns jumps offsets } pReturns = 0; } +/* TODO: check why it triggers this error in keywords.prg + if( pLoops ) + { + PLOOPEXIT pLoop = pLoops; + char cLine[ 64 ]; - if( (_wSeqCounter + _wWhileCounter + _wIfCounter + _wCaseCounter + _wForCounter) > 0 ) - GenError( ERR_UNCLOSED_STRU, NULL, NULL ); + while( pLoop->pNext ) + pLoop =pLoop->pNext; + + itoa( pLoop->wLine, cLine, 10 ); + GenError( ERR_UNCLOSED_STRU, cLine, NULL ); + } +*/ } void Function( BYTE bParams ) @@ -3337,6 +3367,125 @@ void StaticAssign( void ) _pInitFunc->bFlags |= FUN_ILLEGAL_INIT; } +/* + * 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 ) +{ + PLOOPEXIT pLoop = OurMalloc( sizeof(LOOPEXIT) ); + + if( pLoops ) + { + PLOOPEXIT pLast =pLoops; + + while( pLast->pNext ) + pLast =pLast->pNext; + pLast->pNext =pLoop; + } + else + pLoops = pLoop; + + pLoop->pNext =NULL; + pLoop->pExitList =NULL; + pLoop->pLoopList =NULL; + pLoop->wOffset =functions.pLast->lPCodePos; /* store the start position */ + pLoop->wLine =iLine; +} + +/* + * Stores the position of LOOP statement to fix it later at the end of loop + */ +static void LoopLoop( void ) +{ + PLOOPEXIT pLast, pLoop = (PLOOPEXIT) OurMalloc( sizeof( LOOPEXIT ) ); + + pLoop->pLoopList =NULL; + pLoop->wOffset =functions.pLast->lPCodePos; /* store the position to fix */ + + pLast =pLoops; + while( pLast->pNext ) + pLast =pLast->pNext; + + while( pLast->pLoopList ) + pLast =pLast->pLoopList; + + pLast->pLoopList =pLoop; + + Jump( 0 ); +} + +/* + * Stores the position of EXIT statement to fix it later at the end of loop + */ +static void LoopExit( void ) +{ + PLOOPEXIT pLast, pLoop = (PLOOPEXIT) OurMalloc( sizeof( LOOPEXIT ) ); + + pLoop->pExitList =NULL; + pLoop->wOffset =functions.pLast->lPCodePos; /* store the position to fix */ + + pLast =pLoops; + while( pLast->pNext ) + pLast =pLast->pNext; + + while( pLast->pExitList ) + pLast =pLast->pExitList; + + pLast->pExitList =pLoop; + + Jump( 0 ); +} + +/* + * Fixes the LOOP statement + */ +static void LoopHere( void ) +{ + PLOOPEXIT pLoop = pLoops, pFree; + + while( pLoop->pNext ) + pLoop = pLoop->pNext; + + pLoop =pLoop->pLoopList; + while( pLoop ) + { + JumpHere( pLoop->wOffset +1 ); + pFree = pLoop; + pLoop = pLoop->pLoopList; + OurFree( pFree ); + } +} + +/* + * Fixes the EXIT statements and releases memory allocated for current loop + */ +static void LoopEnd( void ) +{ + PLOOPEXIT pExit, pLoop = pLoops, pLast = pLoops, pFree; + + while( pLoop->pNext ) + { + pLast = pLoop; + pLoop = pLoop->pNext; + } + + pExit =pLoop->pExitList; + while( pExit ) + { + JumpHere( pExit->wOffset +1 ); + pFree = pExit; + pExit = pExit->pExitList; + OurFree( pFree ); + } + + pLast->pNext = NULL; + if( pLoop == pLoops ) + pLoops = NULL; + OurFree( pLoop ); +} + + void * OurMalloc( LONG lSize ) { void * pMem = malloc( lSize ); diff --git a/harbour/source/makefile.dos b/harbour/source/makefile.dos index c3eaddd0a4..80041efcb4 100644 --- a/harbour/source/makefile.dos +++ b/harbour/source/makefile.dos @@ -1,9 +1,9 @@ # $Id$ # Makefile for DOS DJGPP # -.PHONY: compiler vm rtl +.PHONY: compiler vm rtl tools -all: compiler vm rtl +all: compiler vm rtl tools compiler: make --directory=./compiler -r -f makefile.dos @@ -14,6 +14,9 @@ vm: rtl: make --directory=./rtl -f makefile.dos +tools: + make --directory=./tools -f makefile.dos + clean: make --directory=./compiler -f makefile.dos clean make --directory=./vm -f makefile.dos clean diff --git a/harbour/source/tools/makefile.dos b/harbour/source/tools/makefile.dos index e465f81e67..bdb3708de0 100644 --- a/harbour/source/tools/makefile.dos +++ b/harbour/source/tools/makefile.dos @@ -3,18 +3,17 @@ # include ../../makedos.env +SRCPRG:= $(wildcard *.prg) +CPRG=$(SRCPRG:.prg=.c) +OBJPRG=$(CPRG:.c=.o) + SRCC:= $(wildcard *.c) OBJC=$(SRCC:.c=.o) all: $(HARBOURLIB) -$(HARBOURLIB): ${OBJC} ${OBJPRG} - ar r $(HARBOURLIB) ${OBJC} - -prg: - ../../bin/harbour -n error.prg - ../../bin/harbour -n errorsys.prg - ../../bin/harbour -n tclass.prg +$(HARBOURLIB): ${OBJPRG} $(OBJC) + ar r $(HARBOURLIB) ${OBJC} ${OBJPRG} clean: -del *.o diff --git a/harbour/source/vm/hvm.c b/harbour/source/vm/hvm.c index d599761e38..7ac9633b33 100644 --- a/harbour/source/vm/hvm.c +++ b/harbour/source/vm/hvm.c @@ -1324,7 +1324,13 @@ void PopLocal( SHORT iLocal ) /* local variable or local parameter */ pLocal = stack.pBase + 1 + iLocal; if( IS_BYREF( pLocal ) ) + { + if( pLocal->value.iNumber >= 0) ItemCopy( stack.pItems + pLocal->value.wItem, stack.pPos ); + else + /* local variable referenced in a codeblock */ + ItemCopy( CodeblockGetVar( stack.pItems +pLocal->wBase +1, pLocal->value.wItem ), stack.pPos ); + } else ItemCopy( pLocal, stack.pPos ); } @@ -1426,7 +1432,13 @@ void PushLocal( SHORT iLocal ) /* local variable or local parameter */ pLocal = stack.pBase + 1 + iLocal; if( IS_BYREF( pLocal ) ) + { + if( pLocal->value.iNumber >= 0 ) ItemCopy( stack.pPos, stack.pItems + pLocal->value.wItem ); + else + /* local variable referenced in a codeblock */ + ItemCopy( stack.pPos, CodeblockGetVar( stack.pItems + pLocal->wBase +1, pLocal->value.wItem ) ); + } else ItemCopy( stack.pPos, pLocal ); } @@ -1446,8 +1458,11 @@ void PushLocalByRef( SHORT iLocal ) /* local variable or local parameter */ stack.pPos->value.wItem = stack.pBase + 1 + iLocal - stack.pItems; else + { /* local variable referenced in a codeblock */ - stack.pPos->value.wItem = iLocal; + stack.pPos->value.iNumber = iLocal; + stack.pPos->wBase = stack.pBase - stack.pItems; + } StackPush(); HBDEBUG2( "PushLocalByRef %i\n", iLocal ); diff --git a/harbour/tests/working/keywords.ch b/harbour/tests/working/keywords.ch new file mode 100644 index 0000000000..abc1318e5f --- /dev/null +++ b/harbour/tests/working/keywords.ch @@ -0,0 +1,3 @@ +//This is test file for KEYWORDS.PRG +// +//This file is needed to test #include keyword \ No newline at end of file diff --git a/harbour/tests/working/keywords.prg b/harbour/tests/working/keywords.prg index 4b7a27af5f..30ff094c26 100644 --- a/harbour/tests/working/keywords.prg +++ b/harbour/tests/working/keywords.prg @@ -4,9 +4,11 @@ */ //DO NOT RUN THIS PROGRAM - ITS PURPOSE IS THE SYNTAX CHECK ONLY! +#include "keywords.ch" //INCLUDE test + EXTERNAL __case, __begin STATIC nExt, bEgin, bReak, cAse, do, wHile, wIth, eXit, eXternal, fIeld -STATIC for +STATIC for, in, include, init, loop, local Function Main() @@ -49,6 +51,16 @@ Function Main() for :=FOR( for ) + in( in ) + + include( include ) + + Init( init ) + + LOCAL( local ) + + LOOP( loop ) + RETURN nil /*================================================================ @@ -103,28 +115,26 @@ RETURN( nExt * /*next*/ nExt ) **/ FUNCTION BEGIN( BEGIN_BEGIN ) LOCAL bEgin -LOCAL xbEgin -LOCAL bEginBEGIN //LOCAL bEgin0, /* BEGIN OF BEGIN */ ; /* in Clipper: Incomplete statement */ // bEgin1 -LOCAL xbEginBEGIN := 100 BEGIN SEQUENCE - bEgin0 :=0 + bEgin :=0 FOR bEgin:=1 TO 10 QOUT( bEgin ) - xbEgin :=bEgin - bEginBEGIN :=xbEgin * 10 - bEgin0 +=bEginBEGIN - --xbEginBEGIN + bEgin :=bEgin[ 1 ] + bEgin[ 1 ] :=bEgin + bEgin :=bEgin * 10 bEgin++ --bEgin ( begin )->( begin () ) NEXT bEgin + bEgin :=begin->begin + // begin->begin :=begin->begin +; /************************/ // begin->begin - bEgin :=BEGIN( xbegin +bEgin +bEginBEGIN -bEgin0 * xbEginBEGIN ) +; + bEgin :=BEGIN( begin +bEgin ) +; bEgin[ bEgin ] END SEQUENCE @@ -308,6 +318,8 @@ LOCAL with while->while :=while() +while->while enddo + do->do :=while->while + // while[ 1 ] :=while // while[ 2 ] +=2 // while( while ) @@ -548,6 +560,9 @@ FUNCTION FOR( for ) for :=for() for :=for( for( for ) ) + for :={|for| for} + EVAL( {|for| for}, for ) + for->for :=for for :=for->for for->for :=for->for @@ -560,3 +575,175 @@ FUNCTION FOR( for ) ENDDO RETURN for + +/*==================================================================== +* Test for IN +*/ +FUNCTION IN( _in ) +FIELD begin IN begin +FIELD break IN break +FIELD case IN case +FIELD do IN do +FIELD for IN for +FIELD in IN in +FIELD next IN next +FIELD while IN while +FIELD end IN end +FIELD with IN with +FIELD exit IN exit +FIELD external IN external +FIELD field IN field + + IN( in ) + in++ + --in + in->in :=in + in[ 1 ] :=1 + in[ in ] :=in[ in ] + ( in )->in :=in + + in :={|in| in} + EVAL( {|in| in}, in ) + + DO in + DO in WITH in + +RETURN in + +/*==================================================================== +* Test for INCLUDE +*/ +FUNCTION include( include ) + + FOR include:=1 TO 10 + include++ + --include + NEXT include + + WHILE include + ENDDO + + include[ 1 ] :=1 + include := include[ include ] + + include :={|include| include} + EVAL( {|include| include}, include ) + + DO include + DO include WITH include + + include->include :=1 + include->include :=include->include +1 + ( include )->include :=INCLUDE( include->include ) + +RETURN include + +/*==================================================================== +* Test for INIT +*/ +INIT fUNCTION Init( init ) + + FOR init:=1 TO 10 + init++ + --init + NEXT init + + WHILE init + init :=!init + END + + init[ 1 ] :=1 + init :=init[ init ] + + init->init :=init->init +1 + ( init )->init :=INIT( init[ init->init ] ) + + init :={|init| init} + EVAL( {|init| init}, init ) + + DO INIT WITH init + DO INIT + +RETURN init + + +/*==================================================================== +* Test for LOCAL +*/ +FUNCTION local( _local ) +LOCAL local + + FOR local:=1 TO 10 + local++ + --local + NEXT local + + local :={|local| local} + EVAL( {|local| local}, local ) + + WHILE local + ENDDO + + local[ 1 ] :=1 + local :=local[ local ] + + local->local :=local->local + ( local )->local :=LOCAL( local[ local->local ] ) + + DO local + DO local WITH local + +RETURN local + +/*==================================================================== +* Test for LOOP +*/ +FUNCTION loop( loop ) + + FOR loop:=1 TO 10 + loop++ + --loop + QOut( loop ) + IF( loop == 5 ) + Qout( "LOOP to begginig" ) + loop + ENDIF + IF( loop == 9 ) + Qout( "EXIT from FOR statement" ) + EXIT + ENDIF + NEXT loop + Qout( "After ", loop, "loops" ) + + +// LOOP + + loop :={|loop| loop} + EVAL( {|loop| loop}, loop ) + + loop =1 + WHILE loop <= 10 + Qout( loop ) + IF( loop == 5 ) + Qout( "LOOP to 7" ) + loop :=7 + LOOP + ENDIF + IF( loop == 9 ) + Qout( "EXIT form while" ) + EXIT + ENDIF + ++loop + ENDDO + Qout( "After ", loop, " loops" ) + + loop[ 1 ] :=1 + loop :=loop[ loop ] + + loop->loop :=loop->loop + ( loop )->loop :=loop( loop[ loop->loop ] ) + + DO loop + DO loop WITH loop + +RETURN loop