From e4fc92764594e302d219912108c67433cf05bc51 Mon Sep 17 00:00:00 2001 From: Ryszard Glab Date: Sun, 8 Aug 1999 19:05:34 +0000 Subject: [PATCH] ChangeLog 19990808-20:55 --- harbour/ChangeLog | 81 +++ harbour/include/extend.h | 31 +- harbour/include/hb_vmpub.h | 44 +- harbour/include/hberrors.h | 1 + harbour/include/langapi.h | 7 +- harbour/include/memvars.ch | 14 + harbour/include/pcode.h | 12 +- harbour/source/compiler/harbour.y | 819 +++++++++++++++++++----------- harbour/source/rtl/console.c | 5 +- harbour/source/rtl/do.c | 45 ++ harbour/source/rtl/memvars.c | 163 +++++- harbour/source/vm/dynsym.c | 6 +- harbour/source/vm/hvm.c | 173 ++++++- harbour/source/vm/initsymb.c | 1 + harbour/tests/working/Makefile | 1 + harbour/tests/working/alias.prg | 133 +++++ 16 files changed, 1158 insertions(+), 378 deletions(-) create mode 100644 harbour/include/memvars.ch create mode 100644 harbour/tests/working/alias.prg diff --git a/harbour/ChangeLog b/harbour/ChangeLog index bd865f80fd..c36d346a10 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,3 +1,84 @@ +19990808-20:55 GMT+2 Ryszard Glab + + *source/compiler/harbour.y + * corrected checking for duplicated variable names when + MEMVAR and PRIVATE variable was declared + * Arguments used in DO ... WITH ... are pushed correctly now + using either a value or a reference + * RETURN statement is no longer generating JMP opcodes - it generates + HB_P_ENDPROC opcode now + * generated C code again includes "init.h" + + added support for aliased expressions (it seems that generated + C code is correct) + + *source/rtl/do.c + + added documentation + + *source/rtl/memvars.c + + added __MVSCOPE function to check if variable is created already + + *include/memvars.ch + ! new file that defines the values returned from __MVSCOPE + function + + *include/hb_vmpub.h + *include/extend.h + * changed to not duplicate definition of structures and type. + Duplicated definitions have caused undefined symbols during + linking of C++ compiler (Watcom) output. The C++ compilers + can mangle function's name into different names when + duplicated definitions of data types are used. + + *source/rtl/initsymb.c + + added again '#include "init.h"' - because some definitions + were moved into hb_vmpub.h to avoid problems with duplicated + definitions of data types. + + *include/langapi.h + - removed declaration of extern langDef (Watcom reported error) + see TODO comment in this file + + *include/pcode.h + - removed unused HB_P_PUSHWORD + + added opcodes: + HB_P_POPALIAS + HB_P_PUSHALIAS + HB_P_SWAPALIAS + HB_P_POPFIELD + HB_P_PUSHFIELD + HB_P_POPALIASEDFIELD + HB_P_PUSHALIASEDFIELD + NOTE: + You have to rebuild all harbour libraries and object files ! + + *source/vm/hvm.c + + added initial support for aliased expressions (fields are not + handled yet - we need to synchronize it with RDD development) + + *include/hberrors.h + + added ERR_INVALID_REFER reported when field or aliased variable + is passed by the reference + + *tests/working/alias.prg + + new file to check if aliased expressions are handled correctly + (only manual check at this moment - by looking at generated + C code) + + *test/working/Makefile + + added alias.prg into BAD_PRG_SOURCES because it cannot be run yet + - removed debugger.prg + + *source/rtl/console.c + - io.h cannot be included on Linux/GCC (placed inside #ifdef) + + *source/vm/dynsym.c + + restored definition of SYM_ALLOCATED because it is local symbol + NOTE: + When compared then this symbol _have to_ be type casted + to SYMBOLSCOPE. If it will be not type casted then some + compilers will compare (int)-1 with (char)-1 which is never + true! (I am changing it for the second time :) + 19990808-11:50 GMT+1 Victor Szel * source/runner/runner.c source/runner/Makefile diff --git a/harbour/include/extend.h b/harbour/include/extend.h index 1430172ef1..a098e349ad 100644 --- a/harbour/include/extend.h +++ b/harbour/include/extend.h @@ -33,6 +33,7 @@ #include #include "hbdefs.h" #include "hbsetup.h" +#include "hb_vmpub.h" #ifdef HARBOUR_STRICT_CLIPPER_COMPATIBILITY /* Clipper includes these from extend.h */ @@ -40,27 +41,6 @@ #include "fm.api" #endif -struct _HB_DYNS; /* forward declaration */ - -/* symbol support structure */ -typedef struct -{ - char* szName; /* the name of the symbol */ - SYMBOLSCOPE cScope; /* the scope of the symbol */ - PHB_FUNC pFunPtr; /* function address for function symbol table entries */ - struct _HB_DYNS * pDynSym; /* pointer to its dynamic symbol if defined */ -} HB_SYMB, * PHB_SYMB, * HB_SYMB_PTR; - -/* Harbour Functions scope (SYMBOLSCOPE) */ -#define FS_PUBLIC 0x00 -#define FS_STATIC 0x02 -#define FS_INIT 0x08 -#define FS_EXIT 0x10 -#define FS_INITEXIT ( FS_INIT | FS_EXIT ) -#define FS_MESSAGE 0x20 -#define FS_MEMVAR 0x80 -#define FS_ALLOCATED (-1) - /* items types */ #define IT_NIL 0x0000 #define IT_INTEGER 0x0002 @@ -211,15 +191,6 @@ typedef struct char szDate[ 9 ]; /* last returned date from _pards() yyyymmdd format */ } STACK; -/* dynamic symbol structure */ -typedef struct _HB_DYNS -{ - HB_HANDLE hArea; /* Workarea number */ - HB_HANDLE hMemvar; /* Index number into memvars ( publics & privates ) array */ - PHB_SYMB pSymbol; /* pointer to its relative local symbol */ - PHB_FUNC pFunPtr; /* Pointer to the function address */ -} HB_DYNS, * PHB_DYNS, * HB_DYNS_PTR; - /* internal structure for codeblocks */ typedef struct _HB_CODEBLOCK { diff --git a/harbour/include/hb_vmpub.h b/harbour/include/hb_vmpub.h index ae5c2930f0..d21703edf9 100644 --- a/harbour/include/hb_vmpub.h +++ b/harbour/include/hb_vmpub.h @@ -37,35 +37,10 @@ #ifndef HB_VMPUB_H_ #define HB_VMPUB_H_ +#include "hbdefs.h" #include "pcode.h" -/* Dummy definitions */ - -typedef void * PHB_DYNS; - -/* Parts copied from hbdefs.h */ - -typedef unsigned char BYTE; /* 1 byte unsigned */ -typedef unsigned short int WORD; - -#ifdef __GNUC__ - #define pascal __attribute__ ((stdcall)) -#endif - -#ifdef _MSC_VER - #define HARBOUR void -#else - #ifdef __IBMCPP__ - #define HARBOUR void - #else - #define HARBOUR void pascal - #endif -#endif -typedef void * PHB_FUNC; - -typedef char SYMBOLSCOPE; /* stores symbol's scope */ - -/* Parts copied from extend.h */ +struct _HB_DYNS; /* symbol support structure */ typedef struct @@ -73,10 +48,17 @@ typedef struct char * szName; /* the name of the symbol */ SYMBOLSCOPE cScope; /* the scope of the symbol */ PHB_FUNC pFunPtr; /* function address for function symbol table entries */ - PHB_DYNS pDynSym; /* pointer to its dynamic symbol if defined */ + struct _HB_DYNS *pDynSym; /* pointer to its dynamic symbol if defined */ } HB_SYMB, * PHB_SYMB; -extern void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols ); /* invokes the virtual machine */ +/* dynamic symbol structure */ +typedef struct _HB_DYNS +{ + HB_HANDLE hArea; /* Workarea number */ + HB_HANDLE hMemvar; /* Index number into memvars ( publics & privates ) array */ + PHB_SYMB pSymbol; /* pointer to its relative local symbol */ + PHB_FUNC pFunPtr; /* Pointer to the function address */ +} HB_DYNS, * PHB_DYNS, * HB_DYNS_PTR; /* Harbour Functions scope (SYMBOLSCOPE) */ #define FS_PUBLIC 0x00 @@ -87,8 +69,6 @@ extern void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols ); /* invokes the vir #define FS_MESSAGE 0x20 #define FS_MEMVAR 0x80 -/* This should always follow the type declarations */ - -#include "init.h" +extern void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols ); /* invokes the virtual machine */ #endif /* HB_VMPUB_H_ */ diff --git a/harbour/include/hberrors.h b/harbour/include/hberrors.h index ccb4a76092..8bc2eccb3d 100644 --- a/harbour/include/hberrors.h +++ b/harbour/include/hberrors.h @@ -61,6 +61,7 @@ #define ERR_INCOMPLETE_STMT 20 #define ERR_CHECKING_ARGS 21 #define ERR_INVALID_LVALUE 22 +#define ERR_INVALID_REFER 23 #define WARN_AMBIGUOUS_VAR 1 #define WARN_MEMVAR_ASSUMED 2 diff --git a/harbour/include/langapi.h b/harbour/include/langapi.h index b4da1ef0c2..88e6254e42 100644 --- a/harbour/include/langapi.h +++ b/harbour/include/langapi.h @@ -71,8 +71,13 @@ typedef struct _HB_LANGNODE struct _HB_LANGNODE * pNext; } HB_LANGNODE, * PHB_LANGNODE; +/* TODO: check if it have to be visible outside of langapi.c + * It it is required then there is a conflict: + * it is declared here as 'extern' and in langapi.c it is declared as + * 'static' - Watcom compiler reports error for this conflict + */ +/* extern PHB_LANG langDef; */ extern PHB_LANGNODE langList; -extern PHB_LANG langDef; /* Supported language list management */ diff --git a/harbour/include/memvars.ch b/harbour/include/memvars.ch new file mode 100644 index 0000000000..e1c4c0d10a --- /dev/null +++ b/harbour/include/memvars.ch @@ -0,0 +1,14 @@ +/* + * $Id$ +*/ + +/* NOTE: This file is also used by C code. */ + +// Values returned from __MVSCOPE function +// +#define MV_NOT_FOUND -2 //not found in the symbols table +#define MV_UNKNOWN -1 //not created yet +#define MV_ERROR 0 //information cannot be obtained +#define MV_PUBLIC 1 //PUBLIC variable +#define MV_PRIVATE_GLOBAL 2 //PRIVATE created outside of current function/procedure +#define MV_PRIVATE_LOCAL 3 //PRIVATE created in current function/procedure diff --git a/harbour/include/pcode.h b/harbour/include/pcode.h index 927428eb41..50914bf724 100644 --- a/harbour/include/pcode.h +++ b/harbour/include/pcode.h @@ -58,11 +58,11 @@ typedef enum HB_P_LESSEQUAL, /* checks if the second latest value on the stack is less equal that the latest one, leaves the result only */ HB_P_LESS, /* checks if the second latest value on the stack is less that the lastest one */ HB_P_LINE, /* currently compiled source code line number */ - HB_P_LOCALNAME, /* name of locals and parmaters when using debugger info */ + HB_P_LOCALNAME, /* sets the name of local variable */ HB_P_MESSAGE, /* sends a message to an object */ HB_P_MINUS, /* subs the latest two values on the stack, removing them and leaving there the result */ - HB_P_MODULENAME, /* name of the PRG file and function when using debugger info */ HB_P_MODULUS, /* calculates the modulus of the two values on the stack, removing them and leaving there the result */ + HB_P_MODULENAME, /* sets the name of debugged module */ HB_P_MULT, /* multiplies the latest two values on the stack, removing them and leaving there the result */ HB_P_NEGATE, /* numerically negates the latest value on the stack */ HB_P_NOOP, /* no operation */ @@ -72,11 +72,17 @@ typedef enum HB_P_PARAMETER, /* creates PRIVATE variables and assigns values to functions paramaters */ HB_P_PLUS, /* adds the latest two values on the stack, removing them and leaving there the result */ HB_P_POP, /* removes the latest value from the stack */ + HB_P_POPALIAS, /* pops the item from the eval stack and selects the current workarea */ + HB_P_POPALIASEDFIELD,/* pops aliased field */ + HB_P_POPFIELD, /* pops unaliased field */ HB_P_POPLOCAL, /* pops the contains of the virtual machine stack onto a local variable */ HB_P_POPMEMVAR, /* pops the contains of a memvar variable to the virtual machine stack */ HB_P_POPSTATIC, /* pops the contains of the virtual machine stack onto a static variable */ HB_P_POWER, /* calculates the power of the two values on the stack, removing them and leaving there the result */ + HB_P_PUSHALIAS, /* saves the current workarea number on the eval stack */ + HB_P_PUSHALIASEDFIELD, /* pushes aliased field */ HB_P_PUSHBLOCK, /* start of a codeblock definition */ + HB_P_PUSHFIELD, /* pushes unaliased field */ HB_P_PUSHINT, /* places an integer number on the virtual machine stack */ HB_P_PUSHLOCAL, /* pushes the contains of a local variable to the virtual machine stack */ HB_P_PUSHLOCALREF, /* pushes a local variable by reference to the virtual machine stack */ @@ -90,10 +96,10 @@ typedef enum HB_P_PUSHSTATICREF, /* pushes the a static variable by reference to the virtual machine stack */ HB_P_PUSHSTR, /* places a string on the virtual machine stack */ HB_P_PUSHSYM, /* places a symbol on the virtual machine stack */ - HB_P_PUSHWORD, /* places a two bytes number on the virtual machine stack */ HB_P_RETVALUE, /* instructs the virtual machine to return the latest stack value */ 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 */ HB_P_TRUE, /* pushes true on the virtual machine stack */ HB_P_ZERO /* places a zero on the virtual machine stack */ } HB_PCODE; diff --git a/harbour/source/compiler/harbour.y b/harbour/source/compiler/harbour.y index 6b695f9fb1..f52040cfe9 100644 --- a/harbour/source/compiler/harbour.y +++ b/harbour/source/compiler/harbour.y @@ -101,12 +101,6 @@ typedef struct __ELSEIF struct __ELSEIF * pNext; } _ELSEIF, * PELSEIF; /* support structure for else if pcode fixups */ -typedef struct __RETURN -{ - WORD wOffset; - struct __RETURN * pNext; -} _RETURN, * PRETURN; /* support structure for multiple returns from a function */ - typedef struct _LOOPEXIT { WORD wOffset; @@ -131,6 +125,31 @@ typedef struct __EXTERN FILENAME *SplitFilename( char * ); /* splits filename into a path, a name and an extension */ char *MakeFilename( char *, FILENAME *); /* joins a path, a name an an extension int filename */ +/* Support for aliased expressions + */ +typedef struct _ALIASID +{ + char type; + union { + int iAlias; + char *szAlias; + } alias; + struct _ALIASID *pPrev; +} ALIASID, *ALIASID_PTR; + +#define ALIAS_NUMBER 1 +#define ALIAS_NAME 2 +#define ALIAS_EVAL 3 + +void AliasAddInt( int ); +void AliasAddExp( void ); +void AliasAddStr( char * ); +void AliasPush( void ); +void AliasPop( void ); +void AliasSwap( void ); +void AliasAdd( ALIASID_PTR ); +void AliasRemove( void ); + /* lex & yacc related prototypes */ void yyerror( char * ); /* parsing error management function */ int yylex( void ); /* main lex token function, called by yyparse() */ @@ -173,6 +192,7 @@ void DimArray( WORD wDimensions ); /* instructs the virtual machine to build an void Do( BYTE bParams ); /* generates the pcode to execute a Clipper function discarding its result */ void Duplicate( void ); /* duplicates the virtual machine latest stack latest value and places it on the stack */ void DupPCode( WORD wStart ); /* duplicates the current generated pcode from an offset */ +void FieldPCode( BYTE , char * ); /* generates the pcode for database field */ void FixElseIfs( void * pIfElseIfs ); /* implements the ElseIfs pcode fixups */ void FixReturns( void ); /* fixes all last defined function returns jumps offsets */ WORD FixSymbolPos( WORD ); /* converts symbol's compile-time position into generation-time position */ @@ -182,9 +202,8 @@ void FunDef( char * szFunName, SYMBOLSCOPE cScope, int iType ); /* starts a new 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 GenExterns( void ); /* generates the symbols for the EXTERN names */ -void GenReturn( WORD wOffset ); /* generates a return offset to later on fill it with the proper exiting pcode address */ PFUNCTION GetFuncall( char * szFunName ); /* locates a previously defined called function */ -WORD GetAliasedVarPos( PVAR pVars, char * szAlias, char * szVarName ); /* check for aliased variable */ +int GetFieldVarPos( char *, PFUNCTION *); /* return if passed name is a field variable */ PVAR GetVar( PVAR pVars, WORD wOrder ); /* returns a variable if defined or zero */ WORD GetVarPos( PVAR pVars, char * szVarName ); /* returns the order + 1 of a variable if defined or zero */ int GetLocalVarPos( char * szVarName ); /* returns the order + 1 of a local variable */ @@ -200,7 +219,7 @@ PFUNCTION KillFunction( PFUNCTION ); /* releases all memory allocated by func 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 LineBody( void ); /* generates the pcode with the currently compiled source code line */ -void MemvarPCode( BYTE , char * ); /* generates the pcode for memvar variable */ +void VariablePCode( BYTE , char * ); /* generates the pcode for memvar variable */ void Message( char * szMsgName ); /* sends a message to an object */ void MessageFix( char * szMsgName ); /* fix a generated message to an object */ void MessageDupl( char * szMsgName ); /* fix a one generated message to an object and duplicate */ @@ -222,7 +241,7 @@ char * SetData( char * szMsg ); /* generates an underscore-symbol name for a void SetFrame( void ); /* generates the proper _FRAME values */ /* support for FIELD declaration */ -void SetAlias( char *, int ); +void FieldsSetAlias( char *, int ); int FieldsCount( void ); /* Codeblocks */ @@ -292,7 +311,8 @@ char * _szCErrors[] = { "Statement not allowed outside of procedure or function" "Syntax error: \'%s\' in: \'%s\'", "Incomplete statement: %s", "Incorrect number of arguments: %s %s", - "Invalid lvalue" + "Invalid lvalue", + "Invalid use of \'@\' (pass by reference): \'%s\'" }; /* Table with parse warnings */ @@ -421,12 +441,19 @@ BOOL _bShortCuts = TRUE; /* .and. & .or. expressions shortcuts */ BOOL _bWarnings = FALSE; /* enable parse warnings */ BOOL _bAutoMemvarAssume = FALSE; /* holds if undeclared variables are automatically assumed MEMVAR */ BOOL _bForceMemvars = FALSE; /* holds if memvars are assumed when accesing undeclared variable */ -BOOL _bDebugInfo = FALSE; /* holds if generate debugger required info */ /* This variable is used to flag if variables have to be passed by reference * - it is required in DO WITH statement + * For example: + * DO proces WITH aVar, bVar:=cVar + * aVar - have to be passed by reference + * bVar and cBar - have to be passed by value */ BOOL _bForceByRefer = FALSE; +/* This variable is true if the right value of assignment will be build. + * It is used to temporarily cancel the above _bForceByRefer + */ +BOOL _bRValue = FALSE; WORD _wSeqCounter = 0; WORD _wForCounter = 0; @@ -438,11 +465,11 @@ LONG _lMessageFix = 0; /* Position of the message which needs to be changed * BOOL _bObj32 = FALSE; /* generate OBJ 32 bits */ #endif WORD _wStatics = 0; /* number of defined statics variables on the PRG */ -PRETURN pReturns = 0; /* list of multiple returns from a function */ PEXTERN pExterns = 0; PTR_LOOPEXIT pLoops = 0; PATHNAMES *_pIncludePath = NULL; FILENAME *_pFileName =NULL; +ALIASID_PTR pAliasId = NULL; PSTACK_VAL_TYPE pStackValType = 0; /* compile time stack values linked list */ char cVarType = ' '; /* current declared variable type */ @@ -499,9 +526,10 @@ extern int _iState; /* current parser state (defined in harbour.l */ %right '\n' ';' ',' '=' /*the highest precedence*/ -%type IDENTIFIER LITERAL FunStart MethStart IdSend ObjectData +%type IDENTIFIER LITERAL FunStart MethStart IdSend ObjectData AliasVar %type DOUBLE -%type ArgList ElemList ExpList FunCall FunScope IncDec Logical Params ParamList +%type ArgList ElemList PareExpList ExpList FunCall FunScope IncDec +%type Params ParamList Logical %type INTEGER BlockExpList Argument IfBegin VarId VarList MethParams ObjFunCall %type MethCall BlockList FieldList DoArgList VarAt %type INTLONG WhileBegin BlockBegin @@ -578,21 +606,21 @@ Statement : ExecFlow Crlf {} | IfInline Crlf { GenPCode1( HB_P_POP ); } | ObjectMethod Crlf { GenPCode1( HB_P_POP ); } | VarUnary Crlf { GenPCode1( HB_P_POP ); } - | VarAssign Crlf { GenPCode1( HB_P_POP ); } + | VarAssign Crlf { GenPCode1( HB_P_POP ); _bRValue =FALSE; } | IDENTIFIER '=' Expression Crlf { PopId( $1 ); } - | AliasVar '=' Expression Crlf { /* TODO */ GenPCode1( HB_P_POP ); } + | AliasVar '=' Expression Crlf { PopId( $1 ); AliasRemove(); } | AliasFunc '=' Expression Crlf { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); } | VarAt '=' Expression Crlf { GenPCode1( HB_P_ARRAYPUT ); GenPCode1( HB_P_POP ); } - | FunArrayCall '=' Expression Crlf { GenPCode1( HB_P_ARRAYPUT ); GenPCode1( HB_P_POP ); } + | FunCallArray '=' Expression Crlf { GenPCode1( HB_P_ARRAYPUT ); GenPCode1( HB_P_POP ); } | ObjectData '=' { MessageFix( SetData( $1 ) ); } Expression Crlf { Function( 1 ); GenPCode1( HB_P_POP ); } | 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 { GenReturn( Jump( 0 ) ); } - | RETURN Expression Crlf { GenPCode1( HB_P_RETVALUE ); GenReturn( Jump ( 0 ) ); } + | RETURN Crlf { GenPCode1( HB_P_ENDPROC ); } + | RETURN Expression Crlf { GenPCode1( HB_P_RETVALUE ); GenPCode1( HB_P_ENDPROC ); } | PUBLIC { iVarScope = VS_PUBLIC; } VarList Crlf | PRIVATE { iVarScope = VS_PRIVATE; } VarList Crlf | PARAMETERS { functions.pLast->wParamCount=0; iVarScope = (VS_PRIVATE | VS_PARAMETER); } MemvarList Crlf @@ -660,10 +688,10 @@ IdSend : IDENTIFIER ':' { PushId( $1 ); $$ = $1; } ObjFunCall : FunCall ':' { Function( $1 ); $$ = $1; } ; -FunArrayCall : FunCall { Function( $1 ); } ArrayIndex +FunCallArray : FunCall { Function( $1 ); } ArrayIndex ; -ObjFunArray : FunArrayCall ':' { GenPCode1( HB_P_ARRAYAT ); } +ObjFunArray : FunCallArray ':' { GenPCode1( HB_P_ARRAYAT ); } ; Expression : NIL { PushNil(); } @@ -681,9 +709,9 @@ Expression : NIL { PushNil(); } | CodeBlock {} | ObjectMethod {} | Macro {} - | AliasExp {} - | '(' Expression ')' {} - | '(' ExpList ')' {} + | AliasVar { PushId( $1 ); AliasRemove(); } + | AliasFunc {} + | PareExpList {} | SELF { GenPCode1( HB_P_PUSHSELF ); } ; @@ -737,30 +765,34 @@ Macro : '&' Variable | '&' '(' Expression ')' ; -AliasVar : IDENTIFIER ALIAS IDENTIFIER {} - | '(' Expression ')' ALIAS IDENTIFIER {} +AliasVar : INTEGER ALIAS { AliasAddInt( $1 ); } IDENTIFIER { $$ = $4; } + | IDENTIFIER ALIAS { AliasAddStr( $1 ); } IDENTIFIER { $$ = $4; } + | PareExpList ALIAS { AliasAddExp(); } IDENTIFIER { $$ = $4; } ; -AliasExp : AliasVar {} - | AliasFunc {} - ; - -AliasFunc : IDENTIFIER ALIAS '(' ExpList ')' {} - | '(' Expression ')' ALIAS '(' ExpList ')' {} +/* NOTE: In the case: + * alias->( Expression ) + * alias always selects a workarea even if it is MEMVAR or M + */ +AliasFunc : INTEGER ALIAS { AliasPush(); PushInteger( $1 ); AliasPop(); } PareExpList { AliasSwap(); } + | IDENTIFIER ALIAS { AliasPush(); PushSymbol( $1, 0 ); AliasPop(); } PareExpList { AliasSwap(); } + | PareExpList ALIAS { AliasPush(); AliasSwap(); } PareExpList { AliasSwap(); } ; VarUnary : IDENTIFIER IncDec %prec POST { PushId( $1 ); Duplicate(); $2 ? Inc(): Dec(); PopId( $1 ); } | IncDec IDENTIFIER %prec PRE { PushId( $2 ); $1 ? Inc(): Dec(); Duplicate(); PopId( $2 ); } | VarAt IncDec %prec POST { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); $2 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); $2 ? Dec(): Inc(); } | IncDec VarAt %prec PRE { DupPCode( $2 ); GenPCode1( HB_P_ARRAYAT ); $1 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); } - | FunArrayCall IncDec %prec POST { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $2 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); $2 ? Dec(): Inc(); } - | IncDec FunArrayCall %prec PRE { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $1 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); } + | FunCallArray IncDec %prec POST { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $2 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); $2 ? Dec(): Inc(); } + | IncDec FunCallArray %prec PRE { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $1 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); } | ObjectData IncDec %prec POST { MessageDupl( SetData( $1 ) ); Function( 0 ); $2 ? Inc(): Dec(); Function( 1 ); $2 ? Dec(): Inc(); } | IncDec ObjectData %prec PRE { MessageDupl( SetData( $2 ) ); Function( 0 ); $1 ? Inc(): Dec(); Function( 1 ); } | ObjectData ArrayIndex IncDec %prec POST { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $3 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); $3 ? Dec(): Inc(); } | IncDec ObjectData ArrayIndex %prec PRE { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $1 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); } | ObjectMethod ArrayIndex IncDec %prec POST { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $3 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); $3 ? Dec(): Inc(); } | IncDec ObjectMethod ArrayIndex %prec PRE { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); $1 ? Inc(): Dec(); GenPCode1( HB_P_ARRAYPUT ); } + | AliasVar IncDec %prec POST { PushId( $1 ); Duplicate(); $2 ? Inc(): Dec(); PopId( $1 ); AliasRemove(); } + | IncDec AliasVar %prec PRE { PushId( $2 ); $1 ? Inc(): Dec(); Duplicate(); PopId( $2 ); AliasRemove(); } ; IncDec : INC { $$ = 1; } @@ -769,14 +801,14 @@ IncDec : INC { $$ = 1; } Variable : VarId {} | VarAt { GenPCode1( HB_P_ARRAYAT ); } - | FunArrayCall { GenPCode1( HB_P_ARRAYAT ); } + | FunCallArray { GenPCode1( HB_P_ARRAYAT ); } | ObjectData {} | ObjectData ArrayIndex { GenPCode1( HB_P_ARRAYAT ); } | ObjectMethod ArrayIndex { GenPCode1( HB_P_ARRAYAT ); } ; VarId : IDENTIFIER { $$ = functions.pLast->lPCodePos; - if( _bForceByRefer && functions.pLast->szName ) + if( _bForceByRefer && functions.pLast->szName && ! _bRValue ) /* DO .. WITH uses reference to a variable * if not inside a codeblock */ @@ -797,55 +829,59 @@ IndexList : Expression | IndexList { GenPCode1( HB_P_ARRAYAT ); } ',' Expression ; -VarAssign : IDENTIFIER INASSIGN Expression { PopId( $1 ); PushId( $1 ); } - | IDENTIFIER PLUSEQ { PushId( $1 ); } Expression { GenPCode1( HB_P_PLUS ); PopId( $1 ); PushId( $1 ); } - | IDENTIFIER MINUSEQ { PushId( $1 ); } Expression { GenPCode1( HB_P_MINUS ); PopId( $1 ); PushId( $1 ); } - | IDENTIFIER MULTEQ { PushId( $1 ); } Expression { GenPCode1( HB_P_MULT ); PopId( $1 ); PushId( $1 ); } - | IDENTIFIER DIVEQ { PushId( $1 ); } Expression { GenPCode1( HB_P_DIVIDE ); PopId( $1 ); PushId( $1 ); } - | IDENTIFIER EXPEQ { PushId( $1 ); } Expression { GenPCode1( HB_P_POWER ); PopId( $1 ); PushId( $1 ); } - | IDENTIFIER MODEQ { PushId( $1 ); } Expression { GenPCode1( HB_P_MODULUS ); PopId( $1 ); PushId( $1 ); } - | VarAt INASSIGN Expression { GenPCode1( HB_P_ARRAYPUT ); } - | VarAt PLUSEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); } - | VarAt MINUSEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); } - | VarAt MULTEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); } - | VarAt DIVEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); } - | VarAt EXPEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); } - | VarAt MODEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); } - | FunArrayCall INASSIGN Expression { GenPCode1( HB_P_ARRAYPUT ); } - | FunArrayCall PLUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); } - | FunArrayCall MINUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); } - | FunArrayCall MULTEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); } - | FunArrayCall DIVEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); } - | FunArrayCall EXPEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); } - | FunArrayCall MODEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectData INASSIGN { MessageFix ( SetData( $1 ) ); } Expression { Function( 1 ); } - | ObjectData PLUSEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); } Expression { GenPCode1( HB_P_PLUS ); Function( 1 ); } - | ObjectData MINUSEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); } Expression { GenPCode1( HB_P_MINUS ); Function( 1 ); } - | ObjectData MULTEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); } Expression { GenPCode1( HB_P_MULT ); Function( 1 ); } - | ObjectData DIVEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); } Expression { GenPCode1( HB_P_DIVIDE ); Function( 1 ); } - | ObjectData EXPEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); } Expression { GenPCode1( HB_P_POWER ); Function( 1 ); } - | ObjectData MODEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); } Expression { GenPCode1( HB_P_MODULUS ); Function( 1 ); } - | ObjectData ArrayIndex INASSIGN Expression { GenPCode1( HB_P_ARRAYPUT ); } - | ObjectData ArrayIndex PLUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectData ArrayIndex MINUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectData ArrayIndex MULTEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectData ArrayIndex DIVEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectData ArrayIndex EXPEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectData ArrayIndex MODEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectMethod ArrayIndex INASSIGN Expression { GenPCode1( HB_P_ARRAYPUT ); } - | ObjectMethod ArrayIndex PLUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectMethod ArrayIndex MINUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectMethod ArrayIndex MULTEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectMethod ArrayIndex DIVEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectMethod ArrayIndex EXPEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); } - | ObjectMethod ArrayIndex MODEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); } - | AliasVar INASSIGN Expression {} - | AliasVar PLUSEQ Expression {} - | AliasVar MINUSEQ Expression {} - | AliasVar MULTEQ Expression {} - | AliasVar DIVEQ Expression {} - | AliasVar EXPEQ Expression {} - | AliasVar MODEQ Expression {} +/*NOTE: If _bRValue is TRUE then the expression is on the right side of assignment + * operator (or +=, -= ...) - in this case a variable is not pushed by + * a reference it is a part of DO WITH ... statement + */ +VarAssign : IDENTIFIER INASSIGN { _bRValue = TRUE; } Expression { PopId( $1 ); PushId( $1 ); } + | IDENTIFIER PLUSEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); PopId( $1 ); PushId( $1 ); } + | IDENTIFIER MINUSEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); PopId( $1 ); PushId( $1 ); } + | IDENTIFIER MULTEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); PopId( $1 ); PushId( $1 ); } + | IDENTIFIER DIVEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); PopId( $1 ); PushId( $1 ); } + | IDENTIFIER EXPEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); PopId( $1 ); PushId( $1 ); } + | IDENTIFIER MODEQ { PushId( $1 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); PopId( $1 ); PushId( $1 ); } + | VarAt INASSIGN { _bRValue = TRUE; } Expression { GenPCode1( HB_P_ARRAYPUT ); } + | VarAt PLUSEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); } + | VarAt MINUSEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); } + | VarAt MULTEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); } + | VarAt DIVEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); } + | VarAt EXPEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); } + | VarAt MODEQ { DupPCode( $1 ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); } + | FunCallArray INASSIGN { _bRValue = TRUE; } Expression { GenPCode1( HB_P_ARRAYPUT ); } + | FunCallArray PLUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); } + | FunCallArray MINUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); } + | FunCallArray MULTEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); } + | FunCallArray DIVEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); } + | FunCallArray EXPEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); } + | FunCallArray MODEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectData INASSIGN { MessageFix ( SetData( $1 ) ); _bRValue = TRUE; } Expression { Function( 1 ); } + | ObjectData PLUSEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); Function( 1 ); } + | ObjectData MINUSEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); Function( 1 ); } + | ObjectData MULTEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); Function( 1 ); } + | ObjectData DIVEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); Function( 1 ); } + | ObjectData EXPEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); Function( 1 ); } + | ObjectData MODEQ { MessageDupl( SetData( $1 ) ); Function( 0 ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); Function( 1 ); } + | ObjectData ArrayIndex INASSIGN { _bRValue = TRUE; } Expression { GenPCode1( HB_P_ARRAYPUT ); } + | ObjectData ArrayIndex PLUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectData ArrayIndex MINUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectData ArrayIndex MULTEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectData ArrayIndex DIVEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectData ArrayIndex EXPEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectData ArrayIndex MODEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectMethod ArrayIndex INASSIGN { _bRValue = TRUE; } Expression { GenPCode1( HB_P_ARRAYPUT ); } + | ObjectMethod ArrayIndex PLUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_PLUS ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectMethod ArrayIndex MINUSEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MINUS ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectMethod ArrayIndex MULTEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MULT ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectMethod ArrayIndex DIVEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_DIVIDE ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectMethod ArrayIndex EXPEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_POWER ); GenPCode1( HB_P_ARRAYPUT ); } + | ObjectMethod ArrayIndex MODEQ { GenPCode1( HB_P_DUPLTWO ); GenPCode1( HB_P_ARRAYAT ); _bRValue = TRUE; } Expression { GenPCode1( HB_P_MODULUS ); GenPCode1( HB_P_ARRAYPUT ); } + | AliasVar INASSIGN { _bRValue = TRUE; $$=(void*)pAliasId; pAliasId=NULL; } Expression { pAliasId=(ALIASID_PTR) $3; PopId( $1 ); PushId( $1 ); AliasRemove(); } + | AliasVar PLUSEQ { PushId( $1 ); _bRValue = TRUE; $$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_PLUS ); pAliasId=(ALIASID_PTR) $3; PopId( $1 ); PushId( $1 ); AliasRemove(); } + | AliasVar MINUSEQ { PushId( $1 ); _bRValue = TRUE; $$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_MINUS ); pAliasId=(ALIASID_PTR) $3; PopId( $1 ); PushId( $1 ); AliasRemove(); } + | AliasVar MULTEQ { PushId( $1 ); _bRValue = TRUE; $$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_MULT ); pAliasId=(ALIASID_PTR) $3; PopId( $1 ); PushId( $1 ); AliasRemove(); } + | AliasVar DIVEQ { PushId( $1 ); _bRValue = TRUE; $$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_DIVIDE ); pAliasId=(ALIASID_PTR) $3; PopId( $1 ); PushId( $1 ); AliasRemove(); } + | AliasVar EXPEQ { PushId( $1 ); _bRValue = TRUE; $$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_POWER ); pAliasId=(ALIASID_PTR) $3; PopId( $1 ); PushId( $1 ); AliasRemove(); } + | AliasVar MODEQ { PushId( $1 ); _bRValue = TRUE; $$=(void*)pAliasId; pAliasId=NULL; } Expression { GenPCode1( HB_P_MODULUS ); pAliasId=(ALIASID_PTR) $3; PopId( $1 ); PushId( $1 ); AliasRemove(); } | AliasFunc INASSIGN Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); } | AliasFunc PLUSEQ Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); } | AliasFunc MINUSEQ Expression { --iLine; GenError( _szCErrors, 'E', ERR_INVALID_LVALUE, NULL, NULL ); } @@ -878,7 +914,7 @@ Operators : Expression '=' Expression { GenPCode1( HB_P_EQUAL ); } /* comp | NOT Expression { GenPCode1( HB_P_NOT ); } | '-' Expression %prec UNARY { GenPCode1( HB_P_NEGATE ); } | '+' Expression %prec UNARY - | VarAssign + | VarAssign { _bRValue = FALSE; } ; Logical : TRUEVALUE { $$ = 1; } @@ -931,6 +967,9 @@ BlockList : IDENTIFIER { cVarType = ' '; AddVar( $1 | BlockList ',' IDENTIFIER { AddVar( $3 ); $$++; } ; +PareExpList: '(' ExpList ')' { $$ = $2; } + ; + ExpList : Expression %prec POST { $$ = 1; } | ExpList { GenPCode1( HB_P_POP ); } ',' Expression %prec POST { $$++; } ; @@ -975,7 +1014,7 @@ FieldList : IDENTIFIER { cVarType = ' '; $$=FieldsCo | IDENTIFIER AS_BLOCK { cVarType = 'B'; $$=FieldsCount(); AddVar( $1 ); } | IDENTIFIER AS_OBJECT { cVarType = 'O'; $$=FieldsCount(); AddVar( $1 ); } | FieldList ',' IDENTIFIER { AddVar( $3 ); } - | FieldList IN IDENTIFIER { SetAlias( $3, $1 ); } + | FieldList IN IDENTIFIER { FieldsSetAlias( $3, $1 ); } ; MemvarDef : MEMVAR { iVarScope = VS_MEMVAR; } MemvarList Crlf @@ -1134,10 +1173,13 @@ DoProc : DO IDENTIFIER { PushSymbol( $2, 1 ); PushNil(); Do( 0 ); } ; DoArgList : ',' { PushNil(); PushNil(); $$ = 2; } - | Expression { $$ = 1; } + | DoExpression { $$ = 1; } | DoArgList ',' { PushNil(); $$++; } - | DoArgList ',' Expression { $$++; } - | ',' { PushNil(); } Expression { $$ = 2; } + | DoArgList ',' DoExpression { $$++; } + | ',' { PushNil(); } DoExpression { $$ = 2; } + ; + +DoExpression: Expression { _bForceByRefer=TRUE; } ; Crlf : '\n' @@ -1234,12 +1276,6 @@ int harbour_main( int argc, char * argv[] ) _bAutoMemvarAssume = TRUE; break; - case 'b': - case 'B': - _bDebugInfo = TRUE; - _bLineNumbers = TRUE; - break; - case 'd': case 'D': /* defines a Lex #define from the command line */ { @@ -1527,7 +1563,6 @@ void PrintUsage( char * szSelf ) printf( "Syntax: %s [options]\n" "\nOptions: \n" "\t/a\t\tautomatic memvar declaration\n" - "\t/b\t\tdebug info\n" "\t/d[=]\t#define \n" #ifdef HARBOUR_OBJ_GENERATION "\t/f\t\tgenerated object file\n" @@ -1785,7 +1820,8 @@ void AddVar( char * szVarName ) /* variable defined in a function/procedure */ CheckDuplVars( pFunc->pFields, szVarName, iVarScope ); CheckDuplVars( pFunc->pStatics, szVarName, iVarScope ); - CheckDuplVars( pFunc->pMemvars, szVarName, iVarScope ); + if( !( iVarScope == VS_PRIVATE || iVarScope == VS_PUBLIC ) ) + CheckDuplVars( pFunc->pMemvars, szVarName, iVarScope ); } else /* variable defined in a codeblock */ @@ -1863,29 +1899,17 @@ void AddVar( char * szVarName ) { case VS_LOCAL: case VS_PARAMETER: - { WORD wLocal = 1; - - if( ! pFunc->pLocals ) - pFunc->pLocals = pVar; - else - { - pLastVar = pFunc->pLocals; - while( pLastVar->pNext ) - { - pLastVar = pLastVar->pNext; - wLocal++; - } - pLastVar->pNext = pVar; - } - if( iVarScope == VS_PARAMETER ) - ++functions.pLast->wParamCount; - if( _bDebugInfo ) - { - GenPCode3( HB_P_LOCALNAME, LOBYTE( wLocal ), HIBYTE( wLocal ) ); - GenPCodeN( szVarName, strlen( szVarName ) ); - GenPCode1( 0 ); - } + if( ! pFunc->pLocals ) + pFunc->pLocals = pVar; + else + { + pLastVar = pFunc->pLocals; + while( pLastVar->pNext ) + pLastVar = pLastVar->pNext; + pLastVar->pNext = pVar; } + if( iVarScope == VS_PARAMETER ) + ++functions.pLast->wParamCount; break; case VS_STATIC: @@ -1944,6 +1968,80 @@ PCOMSYMBOL AddSymbol( char * szSymbolName, WORD *pwPos ) return pSym; } +/* Adds new alias to the alias stack + */ +void AliasAdd( ALIASID_PTR pAlias ) +{ + pAlias->pPrev =pAliasId; + pAliasId =pAlias; +} + +/* Restores previously selected alias + */ +void AliasRemove( void ) +{ + ALIASID_PTR pAlias = pAliasId; + + pAliasId = pAliasId->pPrev; + OurFree( pAlias ); +} + +/* Adds an integer workarea number into alias stack + */ +void AliasAddInt( int iWorkarea ) +{ + ALIASID_PTR pAlias = (ALIASID_PTR) OurMalloc( sizeof( ALIASID ) ); + + pAlias->type =ALIAS_NUMBER; + pAlias->alias.iAlias =iWorkarea; + AliasAdd( pAlias ); +} + +/* Adds an expression into alias stack + */ +void AliasAddExp( void ) +{ + ALIASID_PTR pAlias = (ALIASID_PTR) OurMalloc( sizeof( ALIASID ) ); + + pAlias->type =ALIAS_EVAL; + AliasAdd( pAlias ); +} + +/* Adds an alias name into alias stack + */ +void AliasAddStr( char * szAlias ) +{ + ALIASID_PTR pAlias = (ALIASID_PTR) OurMalloc( sizeof( ALIASID ) ); + + pAlias->type =ALIAS_NAME; + pAlias->alias.szAlias =szAlias; + AliasAdd( pAlias ); +} + +/* Generates pcodes to store the current workarea number + */ +void AliasPush( void ) +{ + GenPCode1( HB_P_PUSHALIAS ); +} + +/* Generates pcodes to select the workarea number using current value + * from the eval stack + */ +void AliasPop( void ) +{ + GenPCode1( HB_P_POPALIAS ); +} + +/* Generates pcodes to swap two last items from the eval stack. + * Last item (after swaping) is next popped as current workarea + */ +void AliasSwap( void ) +{ + GenPCode1( HB_P_SWAPALIAS ); +} + + int Include( char * szFileName, PATHNAMES *pSearch ) { PFILE pFile; @@ -2062,6 +2160,21 @@ void DupPCode( WORD wStart ) /* duplicates the current generated pcode from an o GenPCode1( functions.pLast->pCode[ wStart + w ] ); } +/* + * Function generates passed pcode for passed database field + */ +void FieldPCode( BYTE bPCode, char * szVarName ) +{ + WORD wVar; + PCOMSYMBOL pVar; + + pVar = GetSymbol( szVarName, &wVar ); + if( ! pVar ) + pVar =AddSymbol( szVarName, &wVar ); + pVar->cScope |=VS_MEMVAR; + GenPCode3( bPCode, LOBYTE( wVar ), HIBYTE( wVar ) ); +} + /* * This function creates and initialises the _FUNC structure */ @@ -2147,15 +2260,6 @@ void FunDef( char * szFunName, SYMBOLSCOPE cScope, int iType ) GenPCode3( HB_P_FRAME, 0, 0 ); /* frame for locals and parameters */ GenPCode3( HB_P_SFRAME, 0, 0 ); /* frame for statics variables */ - - if( _bDebugInfo ) - { - GenPCode1( HB_P_MODULENAME ); - GenPCodeN( files.pLast->szFileName, strlen( files.pLast->szFileName ) ); - GenPCode1( ':' ); - GenPCodeN( szFunName, strlen( szFunName ) ); - GenPCode1( 0 ); - } } void GenJava( char *szFileName, char *szName ) @@ -2184,6 +2288,8 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag WORD iNestedCodeblock = 0; LONG lPCodePos; char chr; + BOOL bEndProcRequired; + FILE * yyc; /* file handle for C output */ #ifdef __WATCOMC__ @@ -2202,7 +2308,8 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag if( ! _bQuiet ) printf( "\nGenerating C language output...\n" ); - fprintf( yyc, "#include \"hb_vmpub.h\"\n\n\n" ); + fprintf( yyc, "#include \"hb_vmpub.h\"\n" ); + fprintf( yyc, "#include \"init.h\"\n\n\n" ); if( ! _bStartProc ) pFunc = pFunc->pNext; /* No implicit starting procedure */ @@ -2305,6 +2412,7 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag else fprintf( yyc, "HARBOUR HB_%s( void )\n{\n static BYTE pcode[] = { \n", pFunc->szName ); + bEndProcRequired =TRUE; lPCodePos = 0; while( lPCodePos < pFunc->lPCodePos ) { @@ -2376,6 +2484,17 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag lPCodePos++; break; + case HB_P_ENDPROC: + lPCodePos++; + if( lPCodePos == pFunc->lPCodePos ) + { + bEndProcRequired =FALSE; + fprintf( yyc, " HB_P_ENDPROC\n" ); + } + else + fprintf( yyc, " HB_P_ENDPROC,\n" ); + break; + case HB_P_FALSE: fprintf( yyc, " HB_P_FALSE,\n" ); lPCodePos++; @@ -2481,25 +2600,6 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag lPCodePos += 3; break; - case HB_P_LOCALNAME: - fprintf( yyc, " HB_P_LOCALNAME, %i, %i,\t/* %s */\n", - pFunc->pCode[ lPCodePos + 1 ], - pFunc->pCode[ lPCodePos + 2 ], - ( char * ) pFunc->pCode + lPCodePos + 3 ); - lPCodePos += 3; - while( pFunc->pCode[ lPCodePos ] ) - { - chr = pFunc->pCode[ lPCodePos++ ]; - if( chr == '\'' || chr == '\\') - fprintf( yyc, " \'\\%c\',", chr ); - else - fprintf( yyc, " \'%c\',", chr ); - } - fprintf( yyc, " 0,\n" ); - lPCodePos++; - break; - break; - case HB_P_MESSAGE: { WORD wFixPos; @@ -2519,21 +2619,6 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag lPCodePos++; break; - case HB_P_MODULENAME: - fprintf( yyc, " HB_P_MODULENAME, /* %s */\n", - ( char * ) pFunc->pCode + lPCodePos++ + 1 ); - while( pFunc->pCode[ lPCodePos ] ) - { - chr = pFunc->pCode[ lPCodePos++ ]; - if( chr == '\'' || chr == '\\') - fprintf( yyc, " \'\\%c\',", chr ); - else - fprintf( yyc, " \'%c\',", chr ); - } - fprintf( yyc, " 0,\n" ); - lPCodePos++; - break; - case HB_P_MODULUS: fprintf( yyc, " HB_P_MODULUS,\n" ); lPCodePos++; @@ -2589,6 +2674,39 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag lPCodePos++; break; + case HB_P_POPALIAS: + fprintf( yyc, " HB_P_POPALIAS,\n" ); + lPCodePos++; + break; + + case HB_P_POPALIASEDFIELD: + { + WORD wFixPos; + + wVar = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256; + wFixPos =FixSymbolPos( wVar ); + fprintf( yyc, " HB_P_POPALIASEDFIELD, %i, %i,\t/* %s */\n", + LOBYTE( wFixPos ), + HIBYTE( wFixPos ), + GetSymbolOrd( wVar )->szName ); + lPCodePos += 3; + } + break; + + case HB_P_POPFIELD: + { + WORD wFixPos; + + wVar = pFunc->pCode[ lPCodePos + 1 ] + pFunc->pCode[ lPCodePos + 2 ] * 256; + wFixPos =FixSymbolPos( wVar ); + fprintf( yyc, " HB_P_POPFIELD, %i, %i,\t/* %s */\n", + LOBYTE( wFixPos ), + HIBYTE( wFixPos ), + GetSymbolOrd( wVar )->szName ); + lPCodePos += 3; + } + break; + case HB_P_POPLOCAL: { SHORT wVar = * ( ( SHORT *) &(pFunc->pCode )[ lPCodePos + 1 ] ); @@ -2655,6 +2773,26 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag lPCodePos++; break; + case HB_P_PUSHALIAS: + fprintf( yyc, " HB_P_PUSHALIAS,\n" ); + lPCodePos++; + break; + + case HB_P_PUSHALIASEDFIELD: + { + WORD wFixPos; + + wVar = pFunc->pCode[ lPCodePos + 1 ] + + pFunc->pCode[ lPCodePos + 2 ] * 256; + wFixPos =FixSymbolPos( wVar ); + fprintf( yyc, " HB_P_PUSHALIASEDFIELD, %i, %i,\t/* %s */\n", + LOBYTE( wFixPos ), + HIBYTE( wFixPos ), + GetSymbolOrd( wVar )->szName ); + lPCodePos += 3; + } + break; + case HB_P_PUSHBLOCK: ++iNestedCodeblock; fprintf( yyc, " HB_P_PUSHBLOCK, %i, %i,\t/* %i */\n", @@ -2698,6 +2836,21 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag } break; + case HB_P_PUSHFIELD: + { + WORD wFixPos; + + wVar = pFunc->pCode[ lPCodePos + 1 ] + + pFunc->pCode[ lPCodePos + 2 ] * 256; + wFixPos =FixSymbolPos( wVar ); + fprintf( yyc, " HB_P_PUSHFIELD, %i, %i,\t/* %s */\n", + LOBYTE( wFixPos ), + HIBYTE( wFixPos ), + GetSymbolOrd( wVar )->szName ); + lPCodePos += 3; + } + break; + case HB_P_PUSHINT: fprintf( yyc, " HB_P_PUSHINT, %i, %i, /* %i */\n", pFunc->pCode[ lPCodePos + 1 ], @@ -2911,6 +3064,11 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag } break; + case HB_P_SWAPALIAS: + fprintf( yyc, " HB_P_SWAPALIAS,\n" ); + lPCodePos++; + break; + case HB_P_TRUE: fprintf( yyc, " HB_P_TRUE,\n" ); lPCodePos++; @@ -2929,7 +3087,10 @@ void GenCCode( char *szFileName, char *szName ) /* generates the C languag } fprintf( yyc, "/* %05li */", lPCodePos ); - fprintf( yyc, " HB_P_ENDPROC };\n\n" ); + if( bEndProcRequired ) + fprintf( yyc, " HB_P_ENDPROC };\n\n" ); + else + fprintf( yyc, " };\n\n" ); fprintf( yyc, " hb_vmExecute( pcode, symbols );\n}\n\n" ); pFunc = pFunc->pNext; } @@ -3028,9 +3189,6 @@ void GenExterns( void ) /* generates the symbols for the EXTERN names */ { PEXTERN pDelete; - if( _bDebugInfo ) - AddExtern( yy_strdup( "DEBUGGER" ) ); - while( pExterns ) { if( GetSymbol( pExterns->szName, NULL ) ) @@ -3049,24 +3207,6 @@ void GenExterns( void ) /* generates the symbols for the EXTERN names */ } } -void GenReturn( WORD wOffset ) /* generates a return offset to later on fill it with the proper exiting pcode address */ -{ - PRETURN pReturn = ( PRETURN ) OurMalloc( sizeof( _RETURN ) ), pLast; - - pReturn->wOffset = wOffset; - pReturn->pNext = 0; - - if( ! pReturns ) - pReturns = pReturn; - else - { - pLast = pReturns; - while( pLast->pNext ) - pLast = pLast->pNext; - pLast->pNext = pReturn; - } -} - PFUNCTION GetFuncall( char * szFunctionName ) /* returns a previously called defined function */ { PFUNCTION pFunc = funcalls.pFirst; @@ -3268,59 +3408,19 @@ int GetStaticVarPos( char *szVarName ) return 0; } -/* Checks if passed aliased variable is declared in passed variable's list - * returns the order + 1 of a variable if defined or zero - */ -WORD GetAliasedVarPos( PVAR pVars, char *szAlias, char *szVarName ) -{ - WORD wVar = 1; - - /*TODO: add checking for alias */ - szAlias =szAlias; - while( pVars ) - { - if( pVars->szName && ! strcmp( pVars->szName, szVarName ) ) - { - if( _bWarnings ) - { - PSTACK_VAL_TYPE pNewStackType; - - pVars->iUsed = 1; - - pNewStackType = ( STACK_VAL_TYPE * )OurMalloc( sizeof( STACK_VAL_TYPE ) ); - pNewStackType->cType = pVars->cType; - pNewStackType->pPrev = pStackValType; - - pStackValType = pNewStackType; - debug_msg( "\n* *GetAliasedVarPos()\n", NULL ); - } - return wVar; - } - else - { - if( pVars->pNext ) - { - pVars = pVars->pNext; - wVar++; - } - else - return 0; - } - } - return 0; -} - /* Checks if passed variable name is declared as FIELD * Returns 0 if not found in FIELD list or its position in this list if found + * It also returns a pointer to the function where this field was declared */ -int GetFieldVarPos( char *szVarName ) +int GetFieldVarPos( char *szVarName, PFUNCTION *pOwner ) { int iVar; PFUNCTION pFunc =functions.pLast; + *pOwner =NULL; if( pFunc->szName ) /* we are in a function/procedure -we don't need any tricks */ - iVar =GetAliasedVarPos( pFunc->pFields, NULL, szVarName ); + iVar =GetVarPos( pFunc->pFields, szVarName ); else { /* we have to check the list of nested codeblock up to a function @@ -3328,13 +3428,18 @@ int GetFieldVarPos( char *szVarName ) */ while( pFunc->pOwner ) pFunc =pFunc->pOwner; - iVar =GetAliasedVarPos( pFunc->pFields, NULL, szVarName ); + iVar =GetVarPos( pFunc->pFields, szVarName ); } /* If not found on the list declared in current function then check * the global list (only if there will be no starting procedure) */ if( ! iVar && ! _bStartProc ) - iVar =GetAliasedVarPos( functions.pFirst->pFields, NULL, szVarName ); + { + pFunc =functions.pFirst; + iVar =GetVarPos( pFunc->pFields, szVarName ); + } + if( iVar ) + *pOwner =pFunc; return iVar; } @@ -3349,7 +3454,7 @@ int GetMemvarPos( char *szVarName ) if( pFunc->szName ) /* we are in a function/procedure -we don't need any tricks */ - iVar =GetAliasedVarPos( pFunc->pMemvars, NULL, szVarName ); + iVar =GetVarPos( pFunc->pMemvars, szVarName ); else { /* we have to check the list of nested codeblock up to a function @@ -3357,13 +3462,13 @@ int GetMemvarPos( char *szVarName ) */ while( pFunc->pOwner ) pFunc =pFunc->pOwner; - iVar =GetAliasedVarPos( pFunc->pMemvars, NULL, szVarName ); + iVar =GetVarPos( pFunc->pMemvars, szVarName ); } /* if not found on the list declared in current function then check * the global list (only if there will be no starting procedure) */ if( ! iVar && ! _bStartProc ) - iVar =GetAliasedVarPos( functions.pFirst->pMemvars, NULL, szVarName ); + iVar =GetVarPos( functions.pFirst->pMemvars, szVarName ); return iVar; } @@ -3592,39 +3697,66 @@ void LineBody( void ) /* generates the pcode with the currently compiled source /** * Function generates passed pcode for passed variable name */ -void MemvarPCode( BYTE bPCode, char * szVarName ) +void VariablePCode( BYTE bPCode, char * szVarName ) { WORD wVar; - PCOMSYMBOL pVar; + PCOMSYMBOL pSym; + PFUNCTION pOwnerFunc = NULL; if( _bForceMemvars ) - { + { /* -v swith was used -> first check the MEMVARs */ wVar =GetMemvarPos( szVarName ); if( ! wVar ) { - wVar =GetFieldVarPos( szVarName ); + wVar =GetFieldVarPos( szVarName, &pOwnerFunc ); if( ! wVar ) GenWarning( ((bPCode==HB_P_POPMEMVAR) ? WARN_MEMVAR_ASSUMED : WARN_AMBIGUOUS_VAR), szVarName, NULL ); } } else - { - wVar =GetFieldVarPos( szVarName ); - if( ! wVar ) + { /* -v was not used -> default action is checking FIELDs list */ + wVar =GetFieldVarPos( szVarName, &pOwnerFunc ); + if( wVar == 0 ) { wVar =GetMemvarPos( szVarName ); - if( ! wVar ) + if( wVar == 0 ) GenWarning( ((bPCode==HB_P_POPMEMVAR) ? WARN_MEMVAR_ASSUMED : WARN_AMBIGUOUS_VAR), szVarName, NULL ); } } + if( wVar && pOwnerFunc ) + { /* variable is declared using FIELD statement */ + PVAR pField = GetVar( pOwnerFunc->pFields, wVar ); - pVar = GetSymbol( szVarName, &wVar ); - if( ! pVar ) - pVar =AddSymbol( szVarName, &wVar ); - pVar->cScope |=VS_MEMVAR; + if( pField->szAlias ) + { /* the alias was specified too */ + if( bPCode == HB_P_POPMEMVAR ) + bPCode =HB_P_POPALIASEDFIELD; + else if( bPCode == HB_P_PUSHMEMVAR ) + bPCode =HB_P_PUSHALIASEDFIELD; + else + /* pushing fields by reference is not allowed */ + GenError( _szCErrors, 'E', ERR_INVALID_REFER, szVarName, NULL ); + PushSymbol( yy_strdup(pField->szAlias), 0 ); + } + else + { /* this is unaliased field */ + if( bPCode == HB_P_POPMEMVAR ) + bPCode =HB_P_POPFIELD; + else if( bPCode == HB_P_PUSHMEMVAR ) + bPCode =HB_P_PUSHFIELD; + else + /* pushing fields by reference is not allowed */ + GenError( _szCErrors, 'E', ERR_INVALID_REFER, szVarName, NULL ); + } + } + + pSym = GetSymbol( szVarName, &wVar ); + if( ! pSym ) + pSym =AddSymbol( szVarName, &wVar ); + pSym->cScope |=VS_MEMVAR; GenPCode3( bPCode, LOBYTE( wVar ), HIBYTE( wVar ) ); } @@ -3699,22 +3831,69 @@ void PopId( char * szVarName ) /* generates the pcode to pop a value from the vi { int iVar; - iVar = GetLocalVarPos( szVarName ); - if( iVar ) - GenPCode3( HB_P_POPLOCAL, LOBYTE( iVar ), HIBYTE( iVar ) ); - else + if( pAliasId == NULL ) { - iVar = GetStaticVarPos( szVarName ); + iVar = GetLocalVarPos( szVarName ); if( iVar ) - { - GenPCode3( HB_P_POPSTATIC, LOBYTE( iVar ), HIBYTE( iVar ) ); - functions.pLast->bFlags |= FUN_USES_STATICS; - } + GenPCode3( HB_P_POPLOCAL, LOBYTE( iVar ), HIBYTE( iVar ) ); else { - MemvarPCode( HB_P_POPMEMVAR, szVarName ); + iVar = GetStaticVarPos( szVarName ); + if( iVar ) + { + GenPCode3( HB_P_POPSTATIC, LOBYTE( iVar ), HIBYTE( iVar ) ); + functions.pLast->bFlags |= FUN_USES_STATICS; + } + else + { + VariablePCode( HB_P_POPMEMVAR, szVarName ); + } } } + else + { + if( pAliasId->type == ALIAS_NAME ) + { + if( pAliasId->alias.szAlias[0] == 'M' && pAliasId->alias.szAlias[1] == '\x0' ) + { /* M->variable */ + VariablePCode( HB_P_POPMEMVAR, szVarName ); + } + else + { + int iCmp = strncmp( pAliasId->alias.szAlias, "MEMVAR", 4 ); + if( iCmp == 0 ) + iCmp = strncmp( pAliasId->alias.szAlias, "MEMVAR", strlen(pAliasId->alias.szAlias) ); + if( iCmp == 0 ) + { /* MEMVAR-> or MEMVA-> or MEMV-> */ + VariablePCode( HB_P_POPMEMVAR, szVarName ); + } + else + { /* field variable */ + iCmp = strncmp( pAliasId->alias.szAlias, "FIELD", 4 ); + if( iCmp == 0 ) + iCmp = strncmp( pAliasId->alias.szAlias, "FIELD", strlen(pAliasId->alias.szAlias) ); + if( iCmp == 0 ) + { /* FIELD-> */ + FieldPCode( HB_P_POPFIELD, szVarName ); + } + else + { /* database alias */ + PushSymbol( yy_strdup(pAliasId->alias.szAlias), 0 ); + FieldPCode( HB_P_POPALIASEDFIELD, szVarName ); + } + } + } + } + else if( pAliasId->type == ALIAS_NUMBER ) + { + PushInteger( pAliasId->alias.iAlias ); + FieldPCode( HB_P_POPALIASEDFIELD, szVarName ); + } + else + /* Alias is already placed on stack */ + FieldPCode( HB_P_POPALIASEDFIELD, szVarName ); + } + if( _bWarnings ) { @@ -3772,30 +3951,76 @@ void PushId( char * szVarName ) /* generates the pcode to push a variable value { int iVar; - if( iVarScope == VS_STATIC && functions.pLast->szName ) + if( pAliasId == NULL ) { - /* Reffering to any variable is not allowed during initialization - * of static variable - */ - _pInitFunc->bFlags |= FUN_ILLEGAL_INIT; - } - - iVar = GetLocalVarPos( szVarName ); - if( iVar ) - GenPCode3( HB_P_PUSHLOCAL, LOBYTE( iVar ), HIBYTE( iVar ) ); - else - { - iVar = GetStaticVarPos( szVarName ); - if( iVar ) + if( iVarScope == VS_STATIC && functions.pLast->szName ) { - GenPCode3( HB_P_PUSHSTATIC, LOBYTE( iVar ), HIBYTE( iVar ) ); - functions.pLast->bFlags |= FUN_USES_STATICS; + /* Reffering to any variable is not allowed during initialization + * of static variable + */ + _pInitFunc->bFlags |= FUN_ILLEGAL_INIT; } + + iVar = GetLocalVarPos( szVarName ); + if( iVar ) + GenPCode3( HB_P_PUSHLOCAL, LOBYTE( iVar ), HIBYTE( iVar ) ); else { - MemvarPCode( HB_P_PUSHMEMVAR, szVarName ); + iVar = GetStaticVarPos( szVarName ); + if( iVar ) + { + GenPCode3( HB_P_PUSHSTATIC, LOBYTE( iVar ), HIBYTE( iVar ) ); + functions.pLast->bFlags |= FUN_USES_STATICS; + } + else + { + VariablePCode( HB_P_PUSHMEMVAR, szVarName ); + } } } + else + { + if( pAliasId->type == ALIAS_NAME ) + { + if( pAliasId->alias.szAlias[0] == 'M' && pAliasId->alias.szAlias[1] == '\x0' ) + { /* M->variable */ + VariablePCode( HB_P_PUSHMEMVAR, szVarName ); + } + else + { + int iCmp = strncmp( pAliasId->alias.szAlias, "MEMVAR", 4 ); + if( iCmp == 0 ) + iCmp = strncmp( pAliasId->alias.szAlias, "MEMVAR", strlen(pAliasId->alias.szAlias) ); + if( iCmp == 0 ) + { /* MEMVAR-> or MEMVA-> or MEMV-> */ + VariablePCode( HB_P_PUSHMEMVAR, szVarName ); + } + else + { /* field variable */ + iCmp = strncmp( pAliasId->alias.szAlias, "FIELD", 4 ); + if( iCmp == 0 ) + iCmp = strncmp( pAliasId->alias.szAlias, "FIELD", strlen(pAliasId->alias.szAlias) ); + if( iCmp == 0 ) + { /* FIELD-> */ + FieldPCode( HB_P_PUSHFIELD, szVarName ); + } + else + { /* database alias */ + PushSymbol( yy_strdup(pAliasId->alias.szAlias), 0 ); + FieldPCode( HB_P_PUSHALIASEDFIELD, szVarName ); + } + } + } + } + else if( pAliasId->type == ALIAS_NUMBER ) + { + PushInteger( pAliasId->alias.iAlias ); + FieldPCode( HB_P_PUSHALIASEDFIELD, szVarName ); + } + else + /* Alias is already placed on stack */ + FieldPCode( HB_P_PUSHALIASEDFIELD, szVarName ); + } if( _bWarnings ) { @@ -3835,7 +4060,7 @@ void PushIdByRef( char * szVarName ) /* generates the pcode to push a variable b } else { - MemvarPCode( HB_P_PUSHMEMVARREF, szVarName ); + VariablePCode( HB_P_PUSHMEMVARREF, szVarName ); } } } @@ -4039,7 +4264,7 @@ void CheckDuplVars( PVAR pVar, char * szVarName, int iVarScope ) { if( ! strcmp( pVar->szName, szVarName ) ) { - if( iVarScope != VS_PARAMETER ) + if( ! (iVarScope & VS_PARAMETER) ) --iLine; GenError( _szCErrors, 'E', ERR_VAR_DUPL, szVarName, NULL ); } @@ -4144,8 +4369,6 @@ void FixElseIfs( void * pFixElseIfs ) void FixReturns( void ) /* fixes all last defined function returns jumps offsets */ { - PRETURN pLast = pReturns, pDelete; - if( _bWarnings && functions.pLast ) { PVAR pVar; @@ -4181,23 +4404,6 @@ void FixReturns( void ) /* fixes all last defined function returns jumps offsets pStackValType = 0; } - if( pReturns ) - { - while( pLast ) - { - JumpHere( pLast->wOffset ); - pLast = pLast->pNext; - } - pLast = pReturns; - pDelete = pReturns; - while( pLast ) - { - pLast = pLast->pNext; - OurFree( (void *) pDelete ); - pDelete = pLast; - } - pReturns = 0; - } /* TODO: check why it triggers this error in keywords.prg if( pLoops ) { @@ -4715,7 +4921,7 @@ void CodeBlockEnd() * szAlias -> name of the alias * iField -> position of the first FIELD name to change */ -void SetAlias( char * szAlias, int iField ) +void FieldsSetAlias( char * szAlias, int iField ) { PVAR pVar; @@ -4731,7 +4937,7 @@ void SetAlias( char * szAlias, int iField ) } /* This functions counts the number of FIELD declaration in a function - * We will required this information in SetAlias function + * We will required this information in FieldsSetAlias function */ int FieldsCount() { @@ -5007,6 +5213,7 @@ void GenPortObj( char *szFileName, char *szName ) LONG lPCodePos; LONG lPad; LONG lSymbols; + BOOL bEndProcRequired = TRUE; FILE * yyc; /* file handle for C output */ if( ! szName ) szName = 0; /* compiler warning */ @@ -5144,15 +5351,24 @@ void GenPortObj( char *szFileName, char *szName ) case HB_P_OR: case HB_P_PLUS: case HB_P_POP: + case HB_P_POPALIAS: case HB_P_POWER: + case HB_P_PUSHALIAS: case HB_P_PUSHNIL: case HB_P_PUSHSELF: case HB_P_RETVALUE: + case HB_P_SWAPALIAS: case HB_P_TRUE: case HB_P_ZERO: fputc( pFunc->pCode[ lPCodePos++ ], yyc ); break; + case HB_P_ENDPROC: + fputc( pFunc->pCode[ lPCodePos++ ], yyc ); + if( lPCodePos == pFunc->lPCodePos ) + bEndProcRequired =FALSE; + break; + case HB_P_DIMARRAY: case HB_P_DO: case HB_P_ENDBLOCK: @@ -5193,6 +5409,10 @@ void GenPortObj( char *szFileName, char *szName ) case HB_P_POPMEMVAR: case HB_P_PUSHMEMVAR: case HB_P_PUSHMEMVARREF: + case HB_P_POPFIELD: + case HB_P_PUSHFIELD: + case HB_P_POPALIASEDFIELD: + case HB_P_PUSHALIASEDFIELD: fputc( pFunc->pCode[ lPCodePos ], yyc ); wVar =FixSymbolPos( pFunc->pCode[ lPCodePos+1 ] + 256 *pFunc->pCode[ lPCodePos+2 ] ); fputc( LOBYTE( wVar ), yyc ); @@ -5288,7 +5508,8 @@ void GenPortObj( char *szFileName, char *szName ) } } - fputc( HB_P_ENDPROC, yyc ); + if( bEndProcRequired ) + fputc( HB_P_ENDPROC, yyc ); for( ; lPad; lPad-- ) fputc( 0, yyc ); /* Pad optimalizations */ pFunc = pFunc->pNext; diff --git a/harbour/source/rtl/console.c b/harbour/source/rtl/console.c index 4f0fcea38d..76a3e2e4c1 100644 --- a/harbour/source/rtl/console.c +++ b/harbour/source/rtl/console.c @@ -54,10 +54,11 @@ #include "set.h" #include "inkey.h" -#if defined(__GNUC__) +#if defined(__GNUC__) && ! defined(__DJGPP__) #include +#else + #include #endif -#include #include #include "gtapi.h" /* HARBOUR_USE_GTAPI is checked inside gtapi.h, so that we can always get the border styles */ diff --git a/harbour/source/rtl/do.c b/harbour/source/rtl/do.c index 2929764c68..f53c34338c 100644 --- a/harbour/source/rtl/do.c +++ b/harbour/source/rtl/do.c @@ -36,6 +36,51 @@ #include "errorapi.h" #include "ctoharb.h" +/* $DOC$ + * $FUNCNAME$ + * DO() + * $CATEGORY$ + * Utility + * $ONELINER$ + * Calls a procedure or a function + * $SYNTAX$ + * DO( [, ] ) + * $ARGUMENTS$ + * = Either a string with a function/procedure name to be called + * or a codeblock to evaluate + * = arguments passed to a called function/procedure or to + * a codeblock + * $RETURNS$ + * A value that was returned from called function + * $DESCRIPTION$ + * This function can be called either by the harbour compiler or by user. + * The compiler always passes the item of IT_SYMBOL type that stores the + * name of procedure specified in DO WITH ... statement. + * If called procedure/function doesn't exist then the runtime error + * is generated. + * This function can be used as replacement of macro operator. + * It is also used internally to implement DO WITH + * In this case is of type HB_SYMB + * $EXAMPLES$ + * cbCode ={|x| MyFunc( x )} + * DO( cbCode, 1 ) + * + * cFunction := "MyFunc" + * xRetVal :=DO( cFunction, 2 ) + * + * Old style (slower): + * DO &cFunction WITH 3 + * + * $TESTS$ + * + * $STATUS$ + * + * $COMPLIANCE$ + * + * $SEEALSO$ + * + * $END$ + */ HARBOUR HB_DO( void ) { PHB_ITEM pItem; diff --git a/harbour/source/rtl/memvars.c b/harbour/source/rtl/memvars.c index 841446cda0..ff26030428 100644 --- a/harbour/source/rtl/memvars.c +++ b/harbour/source/rtl/memvars.c @@ -38,6 +38,7 @@ #include "itemapi.h" #include "errorapi.h" #include "error.ch" +#include "memvars.ch" #define VS_PRIVATE 64 #define VS_PUBLIC 128 @@ -489,7 +490,7 @@ static void hb_memvarCreateFromDynSymbol( PHB_DYNS pDynVar, BYTE bScope, PHB_ITE * It also restores the value that was hidden if there is another * PRIVATE variable with the same name. */ -void hb_memvarRelease( HB_ITEM_PTR pMemvar ) +static void hb_memvarRelease( HB_ITEM_PTR pMemvar ) { ULONG ulBase = _privateStackCnt; PHB_DYNS pDynVar; @@ -526,7 +527,7 @@ void hb_memvarRelease( HB_ITEM_PTR pMemvar ) * procedure only. * The scope of released variables are specified using passed name's mask */ -void hb_memvarReleaseWithMask( char *szMask, BOOL bInclude ) +static void hb_memvarReleaseWithMask( char *szMask, BOOL bInclude ) { ULONG ulBase = _privateStackCnt; PHB_DYNS pDynVar; @@ -551,6 +552,48 @@ void hb_memvarReleaseWithMask( char *szMask, BOOL bInclude ) } } +static int hb_memvarScope( char *szVarName, ULONG ulLength ) +{ + int iMemvar = MV_ERROR; + char *szName; + + szName =(char *)hb_xalloc( ulLength ); + if( szName ) + { + PHB_DYNS pDynVar; + + memcpy( szName, szVarName, ulLength ); + pDynVar =hb_dynsymFind( hb_strUpper( szName, ulLength-1 ) ); + if( pDynVar ) + { + if( pDynVar->hMemvar == 0 ) + iMemvar =MV_UNKNOWN; + else + { + ULONG ulBase = _privateStackCnt; /* start from the top of the stack */ + + iMemvar =MV_PUBLIC; + while( ulBase ) + { + --ulBase; + if( pDynVar == _privateStack[ ulBase ] ) + { + if( ulBase >= _privateStackBase ) + iMemvar =MV_PRIVATE_LOCAL; + else + iMemvar =MV_PRIVATE_GLOBAL; + ulBase =0; + } + } + } + } + else + iMemvar =MV_NOT_FOUND; + hb_xfree( szName ); + } + + return iMemvar; +} /* ************************************************************************** */ @@ -709,14 +752,38 @@ HARBOUR HB___MVPRIVATE( void ) * $DESCRIPTION$ * This function releases values stored in memory variable. It shouldn't * be called directly, rather it should be placed into RELEASE command. - * If the released variable is a PRIVATE variable then previously hidden - * variable with the same name becomes visible (after exit from the - * procedure where released variable was created). + * If the released variable is a PRIVATE variable then previously hidden + * variable with the same name becomes visible after exit from the + * procedure where released variable was created. If you access + * the released variable in the same function/procedure where it + * was created the the NIL value is returned. You can however assign + * a new value to released variable without any side effects. * * It releases variable even if this variable was created in different * procedure * $EXAMPLES$ * + * PROCEDURE MAIN() + * PRIVATE mPrivate + * + * mPrivate :="PRIVATE from MAIN()" + * ? mPrivate //PRIVATE from MAIN() + * Test() + * ? mPrivate //PRIVATE from MAIN() + * + * RETURN + * + * PROCEDURE Test() + * PRIVATE mPrivate + * + * mPrivate :="PRIVATE from Test()" + * ? mPrivate //PRIVATE from TEST() + * RELEASE mPrivate + * ? mPrivate //NIL + * mPrivate :="Again in Test()" + * + * RETURN + * * $TESTS$ * * $STATUS$ @@ -781,8 +848,13 @@ HARBOUR HB___MVXRELEASE( void ) * $DESCRIPTION$ * This function releases values stored in memory variables. It shouldn't * be called directly, it should be placed into RELEASE ALL command. - * If released variable is a PRIVATE variable then the NIL is assigned. - * PUBLIC variables are not changed. + * If the released variable is a PRIVATE variable then previously hidden + * variable with the same name becomes visible after exit from the + * procedure where released variable was created. If you access + * the released variable in the same function/procedure where it + * was created the the NIL value is returned. You can however assign + * a new value to released variable without any side effects. + * PUBLIC variables are not changed by this function. * $EXAMPLES$ * * $TESTS$ @@ -814,7 +886,82 @@ HARBOUR HB___MVRELEASE( void ) if( pMask->item.asString.value[ 0 ] == '*' ) bIncludeVar =TRUE; /* delete all memvar variables */ - hb_memvarReleaseWithMask( pMask->item.asString.value, bIncludeVar ); + hb_memvarReleaseWithMask( pMask->item.asString.value, bIncludeVar ); } } } + +/* $DOC$ + * $FUNCNAME$ + * __MVSCOPE() + * $CATEGORY$ + * Variable management + * $ONELINER$ + * If variable exists then returns its scope. + * $SYNTAX$ + * __MVSCOPE( ) + * $ARGUMENTS$ + * = a string with a variable name to check + * $RETURNS$ + * The symbolic values are defined in include/memvars.ch + * MV_NOT_FOUND =variable is not declared (not found in symbol table) + * MV_UNKNOWN =if variable doesn't exist (but found in symbol table) + * MV_ERROR =if information cannot be obtained (memory error or argument error) + * MV_PUBLIC =for public variables + * MV_PRIVATE_GLOBAL =for private variables declared outside of current function/procedure + * MV_PRIVATE_LOCAL =for private variables declared in current function/procedure + * $DESCRIPTION$ + * + * $EXAMPLES$ + * + * PROCEDURE MAIN() + * PUBLIC mPublic + * PRIVATE mPrivateGlobal + * + * CallProc() + * ? __mvScope( "mPrivateLocal" ) //MV_UNKNOWN + * + * RETURN + * + * PROCEDURE CallProc() + * PRIVATE mPrivateLocal + * + * ? __mvScope( "mPublic" ) //MV_PUBLIC + * ? __mvScope( "mPrivateGlobal" ) //MV_PRIVATE_GLOBAL + * ? __mvScope( "mPrivateLocal" ) //MV_PRIVATE_LOCAL + * ? __mvScope( "mFindMe" ) //MV_NOT_FOUND + * + * IF( __mvScope( "mPublic" ) > MV_ERROR ) + * ? "Variable exists" + * ELSE + * ? "Variable not created yet" + * ENDIF + * + * RETURN + * + * $TESTS$ + * + * $STATUS$ + * + * $COMPLIANCE$ + * + * $SEEALSO$ + * include/memvars.ch + * $END$ + */ +HARBOUR HB___MVSCOPE( void ) +{ + int iMemvar = MV_ERROR; + + if( hb_pcount() ) + { + PHB_ITEM pVarName; + + pVarName =hb_param( 1, IT_STRING ); + if( pVarName ) + { + iMemvar =hb_memvarScope( pVarName->item.asString.value, pVarName->item.asString.length+1 ); + } + } + hb_retni( iMemvar ); +} diff --git a/harbour/source/vm/dynsym.c b/harbour/source/vm/dynsym.c index 58efce7f59..6f641ea34b 100644 --- a/harbour/source/vm/dynsym.c +++ b/harbour/source/vm/dynsym.c @@ -28,6 +28,8 @@ #include "extend.h" +#define SYM_ALLOCATED -1 + typedef struct { PHB_DYNS pDynSym; /* Pointer to dynamic symbol */ @@ -53,7 +55,7 @@ PHB_SYMB hb_symbolNew( char * szName ) /* Create a new symbol */ PHB_SYMB pSymbol = ( PHB_SYMB ) hb_xgrab( sizeof( HB_SYMB ) ); pSymbol->szName = ( char * ) hb_xgrab( strlen( szName ) + 1 ); - pSymbol->cScope = FS_ALLOCATED; /* to know what symbols to release when exiting the app */ + pSymbol->cScope = SYM_ALLOCATED; /* to know what symbols to release when exiting the app */ strcpy( pSymbol->szName, szName ); pSymbol->pFunPtr = NULL; pSymbol->pDynSym = NULL; @@ -193,7 +195,7 @@ void hb_dynsymRelease( void ) for( w = 0; w < wDynSymbols; w++ ) { /* it is a allocated symbol ? */ - if( ( pDynItems + w )->pDynSym->pSymbol->cScope == FS_ALLOCATED ) + if( ( pDynItems + w )->pDynSym->pSymbol->cScope == (SYMBOLSCOPE)SYM_ALLOCATED ) { hb_xfree( ( pDynItems + w )->pDynSym->pSymbol->szName ); hb_xfree( ( pDynItems + w )->pDynSym->pSymbol ); diff --git a/harbour/source/vm/hvm.c b/harbour/source/vm/hvm.c index 480405766a..9428079681 100644 --- a/harbour/source/vm/hvm.c +++ b/harbour/source/vm/hvm.c @@ -64,6 +64,7 @@ HARBOUR HB_EVAL( void ); /* Evaluates a codeblock from Harbour */ HARBOUR HB_LEN( void ); /* Evaluates a codeblock from Harbour */ HARBOUR HB_EMPTY( void ); /* fixed entry point by now */ HARBOUR HB_VALTYPE( void ); /* returns a string description of a value */ + HARBOUR HB_ERRORBLOCK( void ); HARBOUR HB_PROCNAME( void ); HARBOUR HB_PROCLINE( void ); @@ -72,6 +73,14 @@ HARBOUR HB_ERRORLEVEL( void ); HARBOUR HB_PCOUNT( void ); HARBOUR HB_PVALUE( void ); +static void AliasPop( void ); /* pops the workarea number form the eval stack */ +static void AliasPush( void ); /* pushes the current workarea number */ +static void AliasSwap( void ); /* swaps items on the eval stack and pops the workarea number */ +static void PopAliasedField( PHB_SYMB ); /* pops an aliased field from the eval stack*/ +static void PopField( PHB_SYMB ); /* pops an unaliased field from the eval stack */ +static void PushAliasedField( PHB_SYMB ); /* pushes an aliased field on the eval stack */ +static void PushField( PHB_SYMB ); /* pushes an unaliased field on the eval stack */ + #ifdef HARBOUR_OBJ_GENERATION typedef struct @@ -412,10 +421,27 @@ void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols ) break; case HB_P_POP: - hb_stackPop(); + hb_stackPop(); w++; break; + case HB_P_POPALIAS: + AliasPop(); + w++; + break; + + case HB_P_POPALIASEDFIELD: + wParams = pCode[ w + 1 ] + ( pCode[ w + 2 ] * 256 ); + PopAliasedField( pSymbols + wParams ); + w += 3; + break; + + case HB_P_POPFIELD: + wParams = pCode[ w + 1 ] + ( pCode[ w + 2 ] * 256 ); + PopField( pSymbols + wParams ); + w += 3; + break; + case HB_P_POPLOCAL: hb_vmPopLocal( pCode[ w + 1 ] + ( pCode[ w + 2 ] * 256 ) ); w += 3; @@ -437,6 +463,17 @@ void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols ) w++; break; + case HB_P_PUSHALIAS: + AliasPush(); + w++; + break; + + case HB_P_PUSHALIASEDFIELD: + wParams = pCode[ w + 1 ] + ( pCode[ w + 2 ] * 256 ); + PushAliasedField( pSymbols + wParams ); + w += 3; + break; + case HB_P_PUSHBLOCK: /* +0 -> _pushblock * +1 +2 -> size of codeblock @@ -453,6 +490,12 @@ void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols ) w += 1 + sizeof( double ) + 1; break; + case HB_P_PUSHFIELD: + wParams = pCode[ w + 1 ] + ( pCode[ w + 2 ] * 256 ); + PushField( pSymbols + wParams ); + w += 3; + break; + case HB_P_PUSHINT: hb_vmPushInteger( pCode[ w + 1 ] + ( pCode[ w + 2 ] * 256 ) ); w += 3; @@ -517,6 +560,11 @@ void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols ) w += 3; break; + case HB_P_SWAPALIAS: + AliasSwap(); + w++; + break; + case HB_P_RETVALUE: hb_vmRetValue(); w++; @@ -559,6 +607,88 @@ void hb_vmExecute( BYTE * pCode, PHB_SYMB pSymbols ) HB_DEBUG( "EndProc\n" ); } +/* Pops the item from the eval stack and uses it to select the current + * workarea + */ +static void AliasPop( void ) +{ + PHB_ITEM pItem; + + hb_stackDec(); + pItem = stack.pPos; + switch( pItem->type & ~IT_BYREF ) + { + case IT_INTEGER: + /* Alias was used as integer value, for example: 4->field + * or it was saved on the stack using AliasPush() + * or was evaluated from an expression, (nWorkArea)->field + */ + /* TODO: synchronize it with RDD API + hb_SelectWorkAreaNumber( pItem->item.asInteger.value ); + */ + pItem->type = IT_NIL; + break; + + case IT_SYMBOL: + /* Alias was specified using alias identifier, for example: al->field + */ + /* TODO: synchronize it with RDD API + hb_SelectWorkAreaNumber( pItem->item.asSymbol.value->pDynSym.hArea ); + */ + pItem->type = IT_NIL; + break; + + case IT_STRING: + /* Alias was evaluated from an expression, for example: (cVar)->field + */ + /* TODO: synchronize it with RDD API + hb_SelectWorkAreaAlias( pItem->item.asString.value ); + */ + hb_itemClear( pItem ); + break; + + default: + hb_itemClear( pItem ); + hb_errorRT_BASE( EG_BADALIAS, 1000, NULL, NULL ); + break; + } + + HB_DEBUG( "AliasPop\n" ); +} + +/* pushes current workarea number on the eval stack + */ +static void AliasPush( void ) +{ + stack.pPos->type = IT_INTEGER; + /* TODO: synchronize it with RDD API + */ + stack.pPos->item.asInteger.value = 0; /* hb_GetCurrentWorkAreaNumber(); */ + stack.pPos->item.asInteger.length = 10; + stack.pPos->item.asInteger.decimal = 0; + hb_stackPush(); + HB_DEBUG( "AliasPush\n" ); +} + +/* Swaps two last items on the eval stack - the last item after swaping + * is popped as current workarea number + */ +static void AliasSwap( void ) +{ + HB_ITEM_PTR pItem = stack.pPos -1; + HB_ITEM_PTR pWorkArea = stack.pPos -2; + + /* TODO: synchronize it with RDD API + hb_SelectWorkAreaNumber( pWorkArea->item.asInteger.value ); + */ + memcpy( pWorkArea, pItem, sizeof( HB_ITEM ) ); + pItem->type =IT_NIL; + hb_stackDec(); + + HB_DEBUG( "AliasSwap\n" ); +} + + void hb_vmAnd( void ) { PHB_ITEM pItem2 = stack.pPos - 1; @@ -1434,6 +1564,15 @@ long hb_vmPopDate( void ) } } +static void PopAliasedField( PHB_SYMB pSym ) +{ + HB_SYMBOL_UNUSED( pSym ); + /* TODO: pop the proper value */ + hb_stackPop(); /* field */ + hb_stackPop(); /* alias */ + HB_DEBUG( "PopAliasedField\n" ); +} + double hb_vmPopDouble( WORD *pwDec ) { double d; @@ -1466,6 +1605,14 @@ double hb_vmPopDouble( WORD *pwDec ) return d; } +static void PopField( PHB_SYMB pSym ) +{ + HB_SYMBOL_UNUSED( pSym ); + /* TODO: pop the proper value */ + hb_stackPop(); + HB_DEBUG( "PopField\n" ); +} + void hb_vmPopLocal( SHORT iLocal ) { PHB_ITEM pLocal; @@ -1579,6 +1726,18 @@ void hb_vmPower( void ) hb_vmPushNumber( pow( d1, d2 ), hb_set.HB_SET_DECIMALS ); } +static void PushAliasedField( PHB_SYMB pSym ) +{ + HB_SYMBOL_UNUSED( pSym ); + /* TODO: push the proper value */ + stack.pPos->type = IT_INTEGER; + stack.pPos->item.asInteger.value = 0; + stack.pPos->item.asInteger.length = 10; + stack.pPos->item.asInteger.decimal = 0; + hb_stackPush(); + HB_DEBUG( "PushAliasedField\n" ); +} + void hb_vmPushLogical( BOOL bValue ) { stack.pPos->type = IT_LOGICAL; @@ -1587,6 +1746,18 @@ void hb_vmPushLogical( BOOL bValue ) HB_DEBUG( "hb_vmPushLogical\n" ); } +static void PushField( PHB_SYMB pSym ) +{ + HB_SYMBOL_UNUSED( pSym ); + /* TODO: push the proper value */ + stack.pPos->type = IT_INTEGER; + stack.pPos->item.asInteger.value = 0; + stack.pPos->item.asInteger.length = 10; + stack.pPos->item.asInteger.decimal = 0; + hb_stackPush(); + HB_DEBUG( "PushField\n" ); +} + void hb_vmPushLocal( SHORT iLocal ) { if( iLocal >= 0 ) diff --git a/harbour/source/vm/initsymb.c b/harbour/source/vm/initsymb.c index 1b5cb7952a..9d02e4fc91 100644 --- a/harbour/source/vm/initsymb.c +++ b/harbour/source/vm/initsymb.c @@ -9,6 +9,7 @@ #include "hbsetup.h" #include "extend.h" #include "hbdefs.h" +#include "init.h" #include "ctoharb.h" #include "initsymd.h" diff --git a/harbour/tests/working/Makefile b/harbour/tests/working/Makefile index d2ee43a959..fb7d3a4117 100644 --- a/harbour/tests/working/Makefile +++ b/harbour/tests/working/Makefile @@ -150,6 +150,7 @@ PRG_HEADERS=\ test.ch \ BAD_PRG_SOURCES=\ + alias.prg \ dupvars.prg \ extend1.prg \ keywords.prg \ diff --git a/harbour/tests/working/alias.prg b/harbour/tests/working/alias.prg new file mode 100644 index 0000000000..74a4347b14 --- /dev/null +++ b/harbour/tests/working/alias.prg @@ -0,0 +1,133 @@ +//NOTEST +// $Id$ +// +//It is used to check if pcode is generated correctly for aliased expressions +//(you must check it visually :) +// +PROCEDURE MAIN() +LOCAL localVar +STATIC staticVar +FIELD fieldVar +FIELD aliasedField IN aaa +MEMVAR memvarVar +PRIVATE privateVar + + ? privateVar + ? memvarVar + ? localVar + ? staticVar + ? fieldVar + ? aliasedField + ? unknVar + + ? 1->privateVar + ? 1->memvarVar + ? 1->localVar + ? 1->staticVar + ? 1->fieldVar + ? 1->aliasedField + ? 1->unknVar + + ? alias->privateVar + ? alias->memvarVar + ? alias->localVar + ? alias->staticVar + ? alias->fieldVar + ? alias->aliasedField + ? alias->unknVar + + ? ( localVar )->privateVar + ? ( localVar )->memvarVar + ? ( localVar )->localVar + ? ( localVar )->staticVar + ? ( localVar )->fieldVar + ? ( localVar )->aliasedField + ? ( localVar )->unknVar + + ? ( localVar )->( privateVar, memvarVar, localVar, staticVar, fieldVar, aliasedField, unknVar ) + ? alias->( privateVar, memvarVar, localVar, staticVar, fieldVar, aliasedField, unknVar ) + ? 2->( privateVar, memvarVar, localVar, staticVar, fieldVar, aliasedField, unknVar ) + ? ( localVar, 2 )->( privateVar, memvarVar, localVar, staticVar, fieldVar, aliasedField, unknVar ) + + ? privateVar++ + ? memvarVar++ + ? localVar++ + ? staticVar++ + ? fieldVar++ + ? aliasedField++ + ? unknVar++ + + ? 1->privateVar++ + ? 1->memvarVar++ + ? 1->localVar++ + ? 1->staticVar++ + ? 1->fieldVar++ + ? 1->aliasedField++ + ? 1->unknVar++ + + ? alias->privateVar++ + ? alias->memvarVar++ + ? alias->localVar++ + ? alias->staticVar++ + ? alias->fieldVar++ + ? alias->aliasedField++ + ? alias->unknVar++ + + ? ( localVar )->privateVar++ + ? ( localVar )->memvarVar++ + ? ( localVar )->localVar++ + ? ( localVar )->staticVar++ + ? ( localVar )->fieldVar++ + ? ( localVar )->aliasedField++ + ? ( localVar )->unknVar++ + + ? privateVar +=privateVar + ? memvarVar +=memvarVar + ? localVar +=localVar + ? staticVar +=staticVar + ? fieldVar +=fieldVar + ? aliasedField +=aliasedField + ? unknVar +=unknVar + + ? 1->privateVar +=1->privateVar + ? 1->memvarVar +=1->memvarVar + ? 1->localVar +=1->localVar + ? 1->staticVar +=1->staticVar + ? 1->fieldVar +=1->fieldVar + ? 1->aliasedField +=1->aliasedField + ? 1->unknVar +=1->unknVar + + ? alias->privateVar +=alias->privateVar + ? alias->memvarVar +=alias->memvarVar + ? alias->localVar +=alias->localVar + ? alias->staticVar +=alias->staticVar + ? alias->fieldVar +=alias->fieldVar + ? alias->aliasedField +=alias->aliasedField + ? alias->unknVar +=alias->unknVar + + ? ( localVar )->privateVar +=( localVar )->privateVar + ? ( localVar )->memvarVar +=( localVar )->memvarVar + ? ( localVar )->localVar +=( localVar )->localVar + ? ( localVar )->staticVar +=( localVar )->staticVar + ? ( localVar )->fieldVar +=( localVar )->fieldVar + ? ( localVar )->aliasedField +=( localVar )->aliasedField + ? ( localVar )->unknVar +=( localVar )->unknVar + + ? ( localVar )->privateVar +=2->privateVar + ? ( localVar )->memvarVar +=2->memvarVar + ? ( localVar )->localVar +=2->localVar + ? ( localVar )->staticVar +=2->staticVar + ? ( localVar )->fieldVar +=2->fieldVar + ? ( localVar )->aliasedField +=2->aliasedField + ? ( localVar )->unknVar +=2->unknVar + + ? alias->( aliasedField, MEMVAR->privateVar, 1->(Test( 2->fieldVar )) ) + + MEMVAR->privateVar :=0 + M->localVar :=1 + MEMVA->fieldVar :=2 + + FIELD->fieldVar :=0 + FIEL->aliasedFieldVar :=1 + +RETURN