From dde0793b53a1e65309d960aa2dbf7efb1c0c79e6 Mon Sep 17 00:00:00 2001 From: Ryszard Glab Date: Mon, 14 Nov 2005 09:47:46 +0000 Subject: [PATCH] 2005-11-14 11:00 UTC+0100 Ryszard Glab * include/hbcomp.h * include/hberrors.h * include/hbexpra.c * include/hbexprb.c * include/hbexprop.h * include/hbhash.h * include/hbmacro.h * include/hbpcode.h * source/common/Makefile * source/common/expropt1.c * source/common/expropt2.c * source/common/hbhash.c * source/compiler/expropta.c * source/compiler/exproptb.c * source/compiler/genc.c * source/compiler/harbour.c * source/compiler/harbour.l * source/compiler/harbour.y * source/compiler/hbfix.c * source/compiler/hbgenerr.c * source/compiler/hbident.c * source/compiler/hbpcode.c * source/macro/macro.l * source/macro/macro.y * source/macro/macroa.c * source/macro/macrob.c * source/rtl/dates.c * source/vm/hvm.c * source/vm/macro.c + source/common/hbdate.c + tests/ddate.prg + tests/switch.prg +added support for DATE type constants in the following format: 0dYYYYMMDD for example (see tests/ddate.prg for more): IF( dDate > 0d20051112 ) +added support for SWITCH command (see tests/switch.prg) SWITCH CASE ... [EXIT] CASE ... [EXIT] [OTHERWISE] ... END Notice: - Integer and string expressions can be mixed in a single SWITCH command with no runtime errors; - CASE expression have to be resolved at compile time and the result has to be either an integer or string constant - if there is no EXIT statement then next CASE is executed (or OTHERWISE for the last CASE) For example: CASE 1+32+2*4 CASE CHR(64) CASE ASC('A') CASE "A"+CHR(13) Notice: The above changes apply only to FLEX version! --- harbour/ChangeLog | 68 ++++++++ harbour/include/hbcomp.h | 4 + harbour/include/hberrors.h | 3 + harbour/include/hbexpra.c | 1 + harbour/include/hbexprb.c | 42 ++++- harbour/include/hbexprop.h | 7 + harbour/include/hbhash.h | 12 +- harbour/include/hbmacro.h | 1 + harbour/include/hbpcode.h | 4 +- harbour/source/common/Makefile | 1 + harbour/source/common/expropt1.c | 49 +++++- harbour/source/common/expropt2.c | 40 +++++ harbour/source/common/hbdate.c | 170 ++++++++++++++++++++ harbour/source/common/hbhash.c | 41 +++-- harbour/source/compiler/expropta.c | 2 +- harbour/source/compiler/exproptb.c | 2 +- harbour/source/compiler/genc.c | 46 +++++- harbour/source/compiler/harbour.c | 92 +++++------ harbour/source/compiler/harbour.l | 68 +++++++- harbour/source/compiler/harbour.y | 243 ++++++++++++++++++++++++++++- harbour/source/compiler/hbfix.c | 4 +- harbour/source/compiler/hbgenerr.c | 5 +- harbour/source/compiler/hbident.c | 5 +- harbour/source/compiler/hbpcode.c | 4 +- harbour/source/macro/macro.l | 11 ++ harbour/source/macro/macro.y | 10 +- harbour/source/macro/macroa.c | 2 +- harbour/source/macro/macrob.c | 2 +- harbour/source/rtl/dates.c | 109 ------------- harbour/source/vm/hvm.c | 92 ++++++++++- harbour/source/vm/macro.c | 9 ++ harbour/tests/ddate.prg | 31 ++++ harbour/tests/switch.prg | 116 ++++++++++++++ 33 files changed, 1098 insertions(+), 198 deletions(-) create mode 100644 harbour/source/common/hbdate.c create mode 100644 harbour/tests/ddate.prg create mode 100644 harbour/tests/switch.prg diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 6f9eb3bf14..df062238f6 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -7,6 +7,74 @@ For example: 2002-12-01 13:30 UTC+0100 Foo Bar */ + +2005-11-14 11:00 UTC+0100 Ryszard Glab + * include/hbcomp.h + * include/hberrors.h + * include/hbexpra.c + * include/hbexprb.c + * include/hbexprop.h + * include/hbhash.h + * include/hbmacro.h + * include/hbpcode.h + * source/common/Makefile + * source/common/expropt1.c + * source/common/expropt2.c + * source/common/hbhash.c + * source/compiler/expropta.c + * source/compiler/exproptb.c + * source/compiler/genc.c + * source/compiler/harbour.c + * source/compiler/harbour.l + * source/compiler/harbour.y + * source/compiler/hbfix.c + * source/compiler/hbgenerr.c + * source/compiler/hbident.c + * source/compiler/hbpcode.c + * source/macro/macro.l + * source/macro/macro.y + * source/macro/macroa.c + * source/macro/macrob.c + * source/rtl/dates.c + * source/vm/hvm.c + * source/vm/macro.c + + source/common/hbdate.c + + tests/ddate.prg + + tests/switch.prg + +added support for DATE type constants in the following format: + 0dYYYYMMDD + for example (see tests/ddate.prg for more): + IF( dDate > 0d20051112 ) + + +added support for SWITCH command (see tests/switch.prg) + SWITCH + CASE + ... + [EXIT] + CASE + ... + [EXIT] + [OTHERWISE] + ... + END + + Notice: + - Integer and string expressions can be mixed in a single + SWITCH command with no runtime errors; + - CASE expression have to be resolved at compile time and + the result has to be either an integer or string constant + - if there is no EXIT statement then next CASE is executed + (or OTHERWISE for the last CASE) + For example: + CASE 1+32+2*4 + CASE CHR(64) + CASE ASC('A') + CASE "A"+CHR(13) + + Notice: + The above changes apply only to FLEX version! + + 2005-11-13 21:21 UTC+0100 Jacek Kubica (kubica/at/wssk.wroc.pl) * harbour/contrib/ole/bldtest.bat * harbour/contrib/ole/hbtest.prg diff --git a/harbour/include/hbcomp.h b/harbour/include/hbcomp.h index efab81a3e7..e37e8a211d 100644 --- a/harbour/include/hbcomp.h +++ b/harbour/include/hbcomp.h @@ -380,6 +380,7 @@ extern void hb_compGenPushVarRef( char * szVarName ); /* generates the pcode extern void hb_compGenPushInteger( int iNumber ); /* Pushes a integer number on the virtual machine stack */ extern void hb_compGenPushLogical( int iTrueFalse ); /* pushes a logical value on the virtual machine stack */ extern void hb_compGenPushLong( HB_LONG lNumber ); /* Pushes a long number on the virtual machine stack */ +extern void hb_compGenPushDate( HB_LONG lNumber ); /* Pushes a date constant on the virtual machine stack */ extern void hb_compGenPushNil( void ); /* Pushes nil on the virtual machine stack */ extern void hb_compGenPushString( char * szText, ULONG ulLen ); /* Pushes a string on the virtual machine stack */ extern void hb_compGenPushSymbol( char * szSymbolName, BOOL bFunction, BOOL bAlias ); /* Pushes a symbol on to the Virtual machine stack */ @@ -534,6 +535,9 @@ extern USHORT hb_comp_wForCounter; extern USHORT hb_comp_wIfCounter; extern USHORT hb_comp_wWhileCounter; extern USHORT hb_comp_wCaseCounter; +extern USHORT hb_comp_wSwitchCounter; +extern BOOL hb_comp_long_optimize; +extern BOOL hb_comp_bTextSubst; extern char * hb_comp_szDeclaredFun; diff --git a/harbour/include/hberrors.h b/harbour/include/hberrors.h index 0a6f526433..fea45a19fe 100644 --- a/harbour/include/hberrors.h +++ b/harbour/include/hberrors.h @@ -114,6 +114,9 @@ HB_EXTERN_BEGIN #define HB_COMP_ERR_OPTIMIZEDLOCAL_OUT_OF_RANGE 52 #define HB_COMP_ERR_FORVAR_TOOMANY 53 #define HB_COMP_ERR_FORVAR_DIFF 54 +#define HB_COMP_ERR_NOT_LITERAL_CASE 55 +#define HB_COMP_ERR_INVALID_STR 56 +#define HB_COMP_ERR_INVALID_DATE 57 #define HB_COMP_WARN_AMBIGUOUS_VAR 1 #define HB_COMP_WARN_MEMVAR_ASSUMED 2 diff --git a/harbour/include/hbexpra.c b/harbour/include/hbexpra.c index 7156d147f0..88f2f48106 100644 --- a/harbour/include/hbexpra.c +++ b/harbour/include/hbexpra.c @@ -77,6 +77,7 @@ static BYTE s_PrecedTable[] = { HB_ET_NIL, /* HB_ET_NONE = 0, */ HB_ET_NIL, /* HB_ET_NIL, */ HB_ET_NIL, /* HB_ET_NUMERIC, */ + HB_ET_NIL, /* HB_ET_DATE, */ HB_ET_NIL, /* HB_ET_STRING, */ HB_ET_NIL, /* HB_ET_CODEBLOCK, */ HB_ET_NIL, /* HB_ET_LOGICAL, */ diff --git a/harbour/include/hbexprb.c b/harbour/include/hbexprb.c index c8bc62292f..a89579fc6a 100644 --- a/harbour/include/hbexprb.c +++ b/harbour/include/hbexprb.c @@ -123,6 +123,7 @@ HB_EXPR_PTR hb_compExprReduceIIF( HB_EXPR_PTR, HB_MACRO_DECL ); static HB_EXPR_FUNC( hb_compExprUseDummy ); static HB_EXPR_FUNC( hb_compExprUseNil ); static HB_EXPR_FUNC( hb_compExprUseNumeric ); +static HB_EXPR_FUNC( hb_compExprUseDate ); static HB_EXPR_FUNC( hb_compExprUseString ); static HB_EXPR_FUNC( hb_compExprUseCodeblock ); static HB_EXPR_FUNC( hb_compExprUseLogical ); @@ -189,6 +190,7 @@ HB_EXPR_FUNC_PTR hb_comp_ExprTable[] = { hb_compExprUseDummy, hb_compExprUseNil, hb_compExprUseNumeric, + hb_compExprUseDate, hb_compExprUseString, hb_compExprUseCodeblock, hb_compExprUseLogical, @@ -333,6 +335,38 @@ static HB_EXPR_FUNC( hb_compExprUseNumeric ) return pSelf; } +/* actions for HB_ET_DATE expression + */ +static HB_EXPR_FUNC( hb_compExprUseDate ) +{ + switch( iMessage ) + { + case HB_EA_REDUCE: + break; + case HB_EA_ARRAY_AT: + hb_compErrorType( pSelf ); + break; + case HB_EA_ARRAY_INDEX: + hb_compErrorIndex( pSelf ); /* Date cannot be used as index element */ + break; + case HB_EA_LVALUE: + hb_compErrorLValue( pSelf ); + break; + case HB_EA_PUSH_PCODE: + HB_EXPR_PCODE1( hb_compGenPushDate, pSelf->value.asNum.lVal ); + break; + case HB_EA_POP_PCODE: + break; + case HB_EA_PUSH_POP: + case HB_EA_STATEMENT: + hb_compWarnMeaningless( pSelf ); + case HB_EA_DELETE: + break; + } + + return pSelf; +} + /* actions for HB_ET_STRING expression */ static HB_EXPR_FUNC( hb_compExprUseString ) @@ -358,7 +392,10 @@ static HB_EXPR_FUNC( hb_compExprUseString ) szDupl = hb_strupr( hb_strdup( pSelf->value.asString.string ) ); HB_EXPR_PCODE2( hb_compGenPushString, pSelf->value.asString.string, pSelf->ulLength + 1 ); - +#if ! defined( HB_MACRO_SUPPORT ) + if( hb_comp_bTextSubst ) + { +#endif bValidMacro = hb_compExprIsValidMacro( szDupl, &bUseTextSubst, HB_MACRO_PARAM ); if( bUseTextSubst ) { @@ -383,6 +420,9 @@ static HB_EXPR_FUNC( hb_compExprUseString ) } } } +#if ! defined( HB_MACRO_SUPPORT ) + } +#endif hb_xfree( szDupl ); } break; diff --git a/harbour/include/hbexprop.h b/harbour/include/hbexprop.h index 644315b98f..f286f96a29 100644 --- a/harbour/include/hbexprop.h +++ b/harbour/include/hbexprop.h @@ -70,6 +70,7 @@ HB_EXTERN_BEGIN #define HB_EV_SYMBOL 128 #define HB_EV_VARREF 256 #define HB_EV_FUNREF 512 +#define HB_EV_DATE 1024 /* messages sent to expressions */ @@ -114,6 +115,7 @@ typedef enum HB_ET_NONE = 0, HB_ET_NIL, HB_ET_NUMERIC, + HB_ET_DATE, HB_ET_STRING, HB_ET_CODEBLOCK, HB_ET_LOGICAL, @@ -308,6 +310,7 @@ HB_EXPR_PTR hb_compExprNewEmpty( void ); HB_EXPR_PTR hb_compExprNewNil( void ); HB_EXPR_PTR hb_compExprNewDouble( double, BYTE, BYTE ); HB_EXPR_PTR hb_compExprNewLong( HB_LONG ); +HB_EXPR_PTR hb_compExprNewDate( HB_LONG ); HB_EXPR_PTR hb_compExprNewString( char * ); HB_EXPR_PTR hb_compExprNewLogical( int ); HB_EXPR_PTR hb_compExprNewSelf( void ); @@ -371,8 +374,12 @@ void hb_compExprClear( HB_EXPR_PTR ); char * hb_compExprDescription( HB_EXPR_PTR ); int hb_compExprType( HB_EXPR_PTR ); int hb_compExprIsInteger( HB_EXPR_PTR ); +int hb_compExprIsLong( HB_EXPR_PTR ); int hb_compExprAsInteger( HB_EXPR_PTR ); +int hb_compExprIsString( HB_EXPR_PTR ); +int hb_compExprAsStringLen( HB_EXPR_PTR ); char *hb_compExprAsString( HB_EXPR_PTR ); +char *hb_compExprAsSymbol( HB_EXPR_PTR ); void hb_compExprFree( HB_EXPR_PTR, HB_MACRO_DECL ); void hb_compExprErrorType( HB_EXPR_PTR, HB_MACRO_DECL ); diff --git a/harbour/include/hbhash.h b/harbour/include/hbhash.h index 1f9510118b..7b67ef9171 100644 --- a/harbour/include/hbhash.h +++ b/harbour/include/hbhash.h @@ -57,13 +57,16 @@ HB_EXTERN_BEGIN -#define HB_HASH_FUNC( hbfunc ) ULONG hbfunc( void *Value, void *Cargo ) +struct HB_HASH_TABLE_; + +#define HB_HASH_FUNC( hbfunc ) ULONG hbfunc( struct HB_HASH_TABLE_ *HashPtr, void *Value, void *Cargo ) typedef HB_HASH_FUNC( HB_HASH_FUNC_ ); typedef HB_HASH_FUNC_ *HB_HASH_FUNC_PTR; typedef struct HB_HASH_ITEM_ { - void *cargo; /* value stored in the hash table */ + void *ValPtr; /* value stored in the hash table */ + void *KeyPtr; ULONG key; struct HB_HASH_ITEM_ *next; } HB_HASH_ITEM, *HB_HASH_ITEM_PTR; @@ -79,13 +82,14 @@ typedef struct HB_HASH_TABLE_ HB_HASH_FUNC_PTR pCompFunc; /* ptr to func that compares two itmes */ } HB_HASH_TABLE, *HB_HASH_TABLE_PTR; + extern HB_HASH_TABLE_PTR hb_hashTableCreate( ULONG ulSize, HB_HASH_FUNC_PTR pHashFunc, HB_HASH_FUNC_PTR pDelete, HB_HASH_FUNC_PTR pComp ); extern void hb_hashTableKill( HB_HASH_TABLE_PTR pTable ); /* release all items and the hash table */ -extern BOOL hb_hashTableAdd( HB_HASH_TABLE_PTR pTable, void *pValue ); /* add a new item into the table */ -extern void * hb_hashTableFind( HB_HASH_TABLE_PTR pTable, void *pValue ); /* return the pointer to item's value or NULL if not found */ +extern BOOL hb_hashTableAdd( HB_HASH_TABLE_PTR pTable, void *pKey, void *pValue ); /* add a new item into the table */ +extern void * hb_hashTableFind( HB_HASH_TABLE_PTR pTable, void *pKey ); /* return the pointer to item's value or NULL if not found */ extern HB_HASH_TABLE_PTR hb_hashTableResize( HB_HASH_TABLE_PTR pTable, ULONG ulNewSize ); /* resize the hash table */ HB_EXTERN_END diff --git a/harbour/include/hbmacro.h b/harbour/include/hbmacro.h index 21712d1179..c813f396dd 100644 --- a/harbour/include/hbmacro.h +++ b/harbour/include/hbmacro.h @@ -133,6 +133,7 @@ extern ULONG hb_compGenJumpTrue( LONG lOffset, HB_BISON_PTR pMacro ); extern void hb_compMemvarGenPCode( BYTE bPCode, char * szVarName, HB_BISON_PTR pMacro ); extern void hb_compGenPushSymbol( char * szSymbolName, BOOL bFunction, BOOL bAlias, HB_BISON_PTR pMacro ); extern void hb_compGenPushLong( HB_LONG lNumber, HB_BISON_PTR pMacro ); +extern void hb_compGenPushDate( HB_LONG lNumber, HB_BISON_PTR pMacro ); extern void hb_compGenMessage( char * szMsgName, HB_BISON_PTR pMacro ); extern void hb_compGenMessageData( char * szMsg, HB_BISON_PTR pMacro ); extern void hb_compGenPopVar( char * szVarName, HB_BISON_PTR pMacro ); diff --git a/harbour/include/hbpcode.h b/harbour/include/hbpcode.h index 78de2faa03..364a149daf 100644 --- a/harbour/include/hbpcode.h +++ b/harbour/include/hbpcode.h @@ -196,8 +196,10 @@ typedef enum HB_P_ENUMNEXT, /* 129 Next item of FOR EACH loop */ HB_P_ENUMPREV, /* 130 Previous item of FOR EACH loop */ HB_P_ENUMEND, /* 131 End of FOR EACH loop */ + HB_P_SWITCH, /* 132 SWITCH using long values */ + HB_P_PUSHDATE, /* 133 SWITCH using long values */ /* NOTE: This have to be the last definition */ - HB_P_LAST_PCODE /* 132 this defines the number of defined pcodes */ + HB_P_LAST_PCODE /* 134 this defines the number of defined pcodes */ } HB_PCODE; #endif /* HB_PCODE_H_ */ diff --git a/harbour/source/common/Makefile b/harbour/source/common/Makefile index 5cec42e86d..7014184ec6 100644 --- a/harbour/source/common/Makefile +++ b/harbour/source/common/Makefile @@ -10,6 +10,7 @@ C_SOURCES=\ hbgete.c \ hbhash.c \ hbstr.c \ + hbdate.c \ hbtrace.c \ hbver.c \ hbverdsp.c \ diff --git a/harbour/source/common/expropt1.c b/harbour/source/common/expropt1.c index 143b135baa..b9071bfa29 100644 --- a/harbour/source/common/expropt1.c +++ b/harbour/source/common/expropt1.c @@ -76,6 +76,7 @@ static char * s_OperTable[] = { "", "NIL", "Numeric", + "Date", "String", "Codeblock", "Logical", @@ -192,12 +193,50 @@ HB_EXPR_PTR hb_compExprNewLong( HB_LONG lValue ) return pExpr; } +HB_EXPR_PTR hb_compExprNewDate( HB_LONG lValue ) +{ + HB_EXPR_PTR pExpr; + + HB_TRACE(HB_TR_DEBUG, ("hb_compExprNewDate(%" PFHL "d)", lValue)); + + pExpr = hb_compExprNew( HB_ET_DATE ); + + pExpr->value.asNum.lVal = lValue; + pExpr->ValType = HB_EV_DATE; + + return pExpr; +} + int hb_compExprIsInteger( HB_EXPR_PTR pExpr ) { return ( pExpr->ExprType == HB_ET_NUMERIC && pExpr->value.asNum.NumType == HB_ET_LONG && HB_LIM_INT16( pExpr->value.asNum.lVal ) ); } +int hb_compExprIsLong( HB_EXPR_PTR pExpr ) +{ + return ( pExpr->ExprType == HB_ET_NUMERIC && pExpr->value.asNum.NumType == HB_ET_LONG ); +} + +int hb_compExprIsString( HB_EXPR_PTR pExpr ) +{ + return ( pExpr->ExprType == HB_ET_STRING ); +} + +char * hb_compExprAsString( HB_EXPR_PTR pExpr ) +{ + if( pExpr->ExprType == HB_ET_STRING ) + return pExpr->value.asString.string; + return NULL; +} + +int hb_compExprAsStringLen( HB_EXPR_PTR pExpr ) +{ + if( pExpr->ExprType == HB_ET_STRING ) + return pExpr->ulLength; + return 0; +} + int hb_compExprAsInteger( HB_EXPR_PTR pExpr ) { if( pExpr->ExprType == HB_ET_NUMERIC && pExpr->value.asNum.NumType == HB_ET_LONG ) @@ -206,7 +245,15 @@ int hb_compExprAsInteger( HB_EXPR_PTR pExpr ) return 0; } -char *hb_compExprAsString( HB_EXPR_PTR pExpr ) +long hb_compExprAsLong( HB_EXPR_PTR pExpr ) +{ + if( pExpr->ExprType == HB_ET_NUMERIC && pExpr->value.asNum.NumType == HB_ET_LONG ) + return pExpr->value.asNum.lVal; + else + return 0; +} + +char *hb_compExprAsSymbol( HB_EXPR_PTR pExpr ) { switch( pExpr->ExprType ) { diff --git a/harbour/source/common/expropt2.c b/harbour/source/common/expropt2.c index 0383097d94..f0be3f2623 100644 --- a/harbour/source/common/expropt2.c +++ b/harbour/source/common/expropt2.c @@ -335,6 +335,31 @@ HB_EXPR_PTR hb_compExprReduceMinus( HB_EXPR_PTR pSelf, HB_MACRO_DECL ) hb_compExprFree( pLeft, HB_MACRO_PARAM ); hb_compExprFree( pRight, HB_MACRO_PARAM ); } + else if( pLeft->ExprType == HB_ET_DATE && pRight->ExprType == HB_ET_DATE ) + { + pSelf->value.asNum.lVal = pLeft->value.asNum.lVal - pRight->value.asNum.lVal; + pSelf->value.asNum.bDec = 0; + pSelf->value.asNum.NumType = HB_ET_LONG; + pSelf->ExprType = HB_ET_NUMERIC; + pSelf->ValType = HB_EV_NUMERIC; + hb_compExprFree( pLeft, HB_MACRO_PARAM ); + hb_compExprFree( pRight, HB_MACRO_PARAM ); + } + else if( pLeft->ExprType == HB_ET_DATE && pRight->ExprType == HB_ET_NUMERIC ) + { + if( pRight->value.asNum.NumType == HB_ET_LONG ) + { + pSelf->value.asNum.lVal = pLeft->value.asNum.lVal - pRight->value.asNum.lVal; + } + else + { + pSelf->value.asNum.lVal = pLeft->value.asNum.lVal - pRight->value.asNum.dVal; + } + pSelf->ExprType = HB_ET_DATE; + pSelf->ValType = HB_EV_DATE; + hb_compExprFree( pLeft, HB_MACRO_PARAM ); + hb_compExprFree( pRight, HB_MACRO_PARAM ); + } else if( pLeft->ExprType == HB_ET_STRING && pRight->ExprType == HB_ET_STRING ) { /* TODO: @@ -445,6 +470,21 @@ HB_EXPR_PTR hb_compExprReducePlus( HB_EXPR_PTR pSelf, HB_MACRO_DECL ) } } } + else if( pLeft->ExprType == HB_ET_DATE && pRight->ExprType == HB_ET_NUMERIC ) + { + if( pRight->value.asNum.NumType == HB_ET_LONG ) + { + pSelf->value.asNum.lVal = pLeft->value.asNum.lVal + pRight->value.asNum.lVal; + } + else + { + pSelf->value.asNum.lVal = pLeft->value.asNum.lVal + pRight->value.asNum.dVal; + } + pSelf->ExprType = HB_ET_DATE; + pSelf->ValType = HB_EV_DATE; + hb_compExprFree( pLeft, HB_MACRO_PARAM ); + hb_compExprFree( pRight, HB_MACRO_PARAM ); + } else { /* TODO: Check for incompatible types e.g. "txt" + 3 diff --git a/harbour/source/common/hbdate.c b/harbour/source/common/hbdate.c new file mode 100644 index 0000000000..2d3e697969 --- /dev/null +++ b/harbour/source/common/hbdate.c @@ -0,0 +1,170 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * The Date conversion module + * + * Copyright 1999 Antonio Linares + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + * Copyright 1999-2001 Viktor Szakats + * hb_dateEncStr() + * hb_dateDecStr() + * hb_dateStrPut() + * hb_dateStrGet() + * + */ + +#include "hbapi.h" +#include "hbdate.h" + +#ifdef HB_C52_STRICT + #define HB_DATE_YEAR_LIMIT 2999 +#else + #define HB_DATE_YEAR_LIMIT 9999 +#endif + +LONG HB_EXPORT hb_dateEncode( int iYear, int iMonth, int iDay ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_dateEncode(%d, %d, %d)", iYear, iMonth, iDay)); + + /* Perform date validation */ + if( iYear >= 1 && iYear <= HB_DATE_YEAR_LIMIT && + iMonth >= 1 && iMonth <= 12 && + iDay >= 1 ) + { + /* Month, year, and lower day limits are simple, + but upper day limit is dependent upon month and leap year */ + int auiDayLimit[ 12 ] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if( ( ( iYear % 4 == 0 && iYear % 100 != 0 ) || iYear % 400 == 0 ) ) + auiDayLimit[ 1 ] = 29; + + if( iDay <= auiDayLimit[ iMonth - 1 ] ) + { + int iFactor = ( iMonth < 3 ) ? -1 : 0; + + return ( ( LONG )( iFactor + 4800 + iYear ) * 1461 / 4 ) + + ( ( LONG )( iMonth - 2 - ( iFactor * 12 ) ) * 367 ) / 12 - + ( ( LONG )( ( iFactor + 4900 + iYear ) / 100 ) * 3 / 4 ) + + ( LONG ) iDay - 32075; + } + } + + return 0; +} + +void HB_EXPORT hb_dateDecode( LONG lJulian, int *piYear, int *piMonth, int *piDay ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_dateDecode(%ld, %p, %p, %p)", lJulian, piYear, piMonth, piDay)); + + if( lJulian > 0 ) + { + LONG U, V, W, X; + + lJulian += 68569; + W = ( lJulian * 4 ) / 146097; + lJulian -= ( ( 146097 * W ) + 3 ) / 4; + X = 4000 * ( lJulian + 1 ) / 1461001; + lJulian -= ( ( 1461 * X ) / 4 ) - 31; + V = 80 * lJulian / 2447; + U = V / 11; + + *piYear = (int) ( X + U + ( W - 49 ) * 100 ); + *piMonth = (int) ( V + 2 - ( U * 12 ) ); + *piDay = (int) ( lJulian - ( 2447 * V / 80 ) ); + } + else + { + *piYear = + *piMonth = + *piDay = 0; + } +} + +void HB_EXPORT hb_dateStrPut( char * szDate, int iYear, int iMonth, int iDay ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_dateStrPut(%p, %d, %d, %d)", szDate, iYear, iMonth, iDay)); + + if( iYear >= 0 && iMonth && iDay ) + { + szDate[ 0 ] = ( ( iYear % 10000 ) / 1000 ) + '0'; + szDate[ 1 ] = ( ( iYear % 1000 ) / 100 ) + '0'; + szDate[ 2 ] = ( ( iYear % 100 ) / 10 ) + '0'; + szDate[ 3 ] = ( iYear % 10 ) + '0'; + + szDate[ 4 ] = ( iMonth / 10 ) + '0'; + szDate[ 5 ] = ( iMonth % 10 ) + '0'; + + szDate[ 6 ] = ( iDay / 10 ) + '0'; + szDate[ 7 ] = ( iDay % 10 ) + '0'; + } + else if ( iYear || iMonth || iDay ) + memset( szDate, '0', 8 ); + else + memset( szDate, ' ', 8 ); +} + +void HB_EXPORT hb_dateStrGet( const char * szDate, int * piYear, int * piMonth, int * piDay ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_dateStrGet(%s, %p, %p, %p)", szDate, piYear, piMonth, piDay)); + + if( szDate && szDate[ 8 ] == '\0' ) + { + /* Date string has correct length, so attempt to convert */ + *piYear = ( ( USHORT ) ( szDate[ 0 ] - '0' ) * 1000 ) + + ( ( USHORT ) ( szDate[ 1 ] - '0' ) * 100 ) + + ( ( USHORT ) ( szDate[ 2 ] - '0' ) * 10 ) + + ( USHORT ) ( szDate[ 3 ] - '0' ); + *piMonth = ( ( szDate[ 4 ] - '0' ) * 10 ) + ( szDate[ 5 ] - '0' ); + *piDay = ( ( szDate[ 6 ] - '0' ) * 10 ) + ( szDate[ 7 ] - '0' ); + } + else + { + /* Date string missing or bad length, so force an empty date */ + *piYear = + *piMonth = + *piDay = 0; + } +} diff --git a/harbour/source/common/hbhash.c b/harbour/source/common/hbhash.c index 7b332a5421..53a72882d9 100644 --- a/harbour/source/common/hbhash.c +++ b/harbour/source/common/hbhash.c @@ -52,12 +52,13 @@ #include "hbhash.h" -static HB_HASH_ITEM_PTR hb_hashItemNew( ULONG ulKey, void * pValue ) +static HB_HASH_ITEM_PTR hb_hashItemNew( ULONG ulKey, void *pKey, void * pValue ) { HB_HASH_ITEM_PTR pItem = (HB_HASH_ITEM_PTR) hb_xgrab( sizeof( HB_HASH_ITEM ) ); pItem->key = ulKey; - pItem->cargo = pValue; + pItem->KeyPtr = pKey; + pItem->ValPtr = pValue; pItem->next = NULL; return pItem; @@ -113,7 +114,7 @@ void hb_hashTableKill( HB_HASH_TABLE_PTR pTable ) while( pItem ) { if( pTable->pDeleteItemFunc ) - ( pTable->pDeleteItemFunc )( pItem->cargo, NULL ); + ( pTable->pDeleteItemFunc )( pTable, pItem->KeyPtr, pItem->ValPtr ); pNext = pItem->next; hb_xfree( ( void * ) pItem ); pItem = pNext; @@ -151,7 +152,7 @@ HB_HASH_TABLE_PTR hb_hashTableResize( HB_HASH_TABLE_PTR pTable, ULONG ulNewSize HB_HASH_ITEM_PTR pNewItem, pNext; pNext = pItem->next; - ulKey = ( pTable->pKeyFunc )( pItem->cargo, NULL ); + ulKey = ( pTable->pKeyFunc )( pNew, pItem->KeyPtr, pItem->ValPtr ); pNewItem = pNew->pItems[ ulKey ]; if( pNewItem ) { @@ -179,22 +180,22 @@ HB_HASH_TABLE_PTR hb_hashTableResize( HB_HASH_TABLE_PTR pTable, ULONG ulNewSize } /* add a new value into th ehash table */ -BOOL hb_hashTableAdd( HB_HASH_TABLE_PTR pTable, void *pValue ) +BOOL hb_hashTableAdd( HB_HASH_TABLE_PTR pTable, void *pKey, void *pValue ) { ULONG ulKey; HB_HASH_ITEM_PTR pItem; - ulKey = ( pTable->pKeyFunc )( pValue, NULL ); + ulKey = ( pTable->pKeyFunc )( pTable, pKey, pValue ); pItem = pTable->pItems[ ulKey ]; if( pItem ) { while( pItem->next ) pItem = pItem->next; - pItem->next = hb_hashItemNew( ulKey, pValue ); + pItem->next = hb_hashItemNew( ulKey, pKey, pValue ); } else { - pTable->pItems[ ulKey ] = hb_hashItemNew( ulKey, pValue ); + pTable->pItems[ ulKey ] = hb_hashItemNew( ulKey, pKey, pValue ); ++pTable->ulUsed; } ++pTable->ulCount; @@ -204,21 +205,21 @@ BOOL hb_hashTableAdd( HB_HASH_TABLE_PTR pTable, void *pValue ) /* return the pointer to item's value or NULL if not found */ -void * hb_hashTableFind( HB_HASH_TABLE_PTR pTable, void *pValue ) +void * hb_hashTableFind( HB_HASH_TABLE_PTR pTable, void *pKey ) { ULONG ulKey; HB_HASH_ITEM_PTR pItem; void * pFound = NULL; - ulKey = ( pTable->pKeyFunc )( pValue, NULL ); + ulKey = ( pTable->pKeyFunc )( pTable, pKey, NULL ); pItem = pTable->pItems[ ulKey ]; if( pItem ) { - while( pItem && (( pTable->pCompFunc )( pItem->cargo, pValue ) != 0) ) + while( pItem && (( pTable->pCompFunc )( pTable, pItem->KeyPtr, pKey ) != 0) ) pItem = pItem->next; if( pItem ) - pFound = pItem->cargo; + pFound = pItem->ValPtr; } return pFound; @@ -228,28 +229,38 @@ void * hb_hashTableFind( HB_HASH_TABLE_PTR pTable, void *pValue ) * Returns TRUE if item was found and returns FALSE when passed item * is not stored in the table */ -BOOL hb_hashTableDel( HB_HASH_TABLE_PTR pTable, void *pValue ) +BOOL hb_hashTableDel( HB_HASH_TABLE_PTR pTable, void *pKey ) { ULONG ulKey; HB_HASH_ITEM_PTR pItem; HB_HASH_ITEM_PTR pPrev = NULL; BOOL bFound = FALSE; - ulKey = ( pTable->pKeyFunc )( pValue, NULL ); + ulKey = ( pTable->pKeyFunc )( pTable, pKey, NULL ); + if( ulKey > pTable->ulTableSize ) + return FALSE; + pItem = pTable->pItems[ ulKey ]; while( pItem && !bFound ) { - if( ( pTable->pCompFunc )( pItem->cargo, pValue ) == 0 ) + if( ( pTable->pCompFunc )( pTable, pItem->KeyPtr, pKey ) == 0 ) { if( pPrev ) + { pPrev->next = pItem->next; + } else { pTable->pItems[ ulKey ] = pItem->next; if( !pItem->next ) + { --pTable->ulUsed; + pTable->pItems[ ulKey ] = NULL; + } } + if( pTable->pDeleteItemFunc ) + ( pTable->pDeleteItemFunc )( pTable, pItem->KeyPtr, pItem->ValPtr ); hb_hashItemDelete( pItem ); bFound = TRUE; --pTable->ulCount; diff --git a/harbour/source/compiler/expropta.c b/harbour/source/compiler/expropta.c index 2bd4ca0132..332b5352dc 100644 --- a/harbour/source/compiler/expropta.c +++ b/harbour/source/compiler/expropta.c @@ -5,6 +5,6 @@ /* hbexpra.c is also included from ../macro/macro.c * However it produces a slighty different code if used in * macro compiler (there is an additional parameter passed to some functions) - * 1.16 - ignore this magic number - this is used to force compilation + * 1.17 - ignore this magic number - this is used to force compilation */ #include "hbexpra.c" diff --git a/harbour/source/compiler/exproptb.c b/harbour/source/compiler/exproptb.c index ed85d26f97..e0b01bad67 100644 --- a/harbour/source/compiler/exproptb.c +++ b/harbour/source/compiler/exproptb.c @@ -5,6 +5,6 @@ /* hbexprb.c is also included from ../macro/macro.c * However it produces a slighty different code if used in * macro compiler (there is an additional parameter passed to some functions) - * 1.13 - ignore this magic number - this is used to force compilation + * 1.14 - ignore this magic number - this is used to force compilation */ #include "hbexprb.c" diff --git a/harbour/source/compiler/genc.c b/harbour/source/compiler/genc.c index 26a5a58a27..3cb9dc6401 100644 --- a/harbour/source/compiler/genc.c +++ b/harbour/source/compiler/genc.c @@ -29,6 +29,7 @@ #include #include "hbcomp.h" +#include "hbdate.h" static void hb_compGenCReadable( PFUNCTION pFunc, FILE * yyc ); static void hb_compGenCCompact( PFUNCTION pFunc, FILE * yyc ); @@ -1867,6 +1868,47 @@ static HB_GENC_FUNC( hb_p_enumend ) return 1; } +static HB_GENC_FUNC( hb_p_switch ) +{ + if( cargo->bVerbose ) + fprintf( cargo->yyc, "/* %05li */ ", lPCodePos ); + else + fprintf( cargo->yyc, "\t" ); + + fprintf( cargo->yyc, "HB_P_SWITCH, %i, %i,", pFunc->pCode[ lPCodePos + 1 ], pFunc->pCode[ lPCodePos + 2 ] ); + + if( cargo->bVerbose ) + { + fprintf( cargo->yyc, "\t/* %i*/", HB_PCODE_MKSHORT( &( pFunc->pCode[ lPCodePos + 2 ] ) ) ); + } + + fprintf( cargo->yyc, "\n" ); + return 3; +} + +static HB_GENC_FUNC( hb_p_pushdate ) +{ + + fprintf( cargo->yyc, "\tHB_P_PUSHDATE, %i, %i, %i, %i,", + pFunc->pCode[ lPCodePos + 1 ], + pFunc->pCode[ lPCodePos + 2 ], + pFunc->pCode[ lPCodePos + 3 ], + pFunc->pCode[ lPCodePos + 4 ] ); + if( cargo->bVerbose ) + { + int year, month, day; + char date[9]; + + hb_dateDecode( HB_PCODE_MKLONG( &( pFunc->pCode[ lPCodePos + 1 ] ) ), &year, &month, &day ); + hb_dateStrPut( date, year, month, day ); + date[8] = '\0'; + fprintf( cargo->yyc, "\t/* %s */", date ); + } + fprintf( cargo->yyc, "\n" ); + + return 5; +} + static HB_GENC_FUNC( hb_p_localnearaddint ) { @@ -2025,7 +2067,9 @@ static HB_GENC_FUNC_PTR s_verbose_table[] = { hb_p_enumstart, hb_p_enumnext, hb_p_enumprev, - hb_p_enumend + hb_p_enumend, + hb_p_switch, + hb_p_pushdate }; static void hb_compGenCReadable( PFUNCTION pFunc, FILE * yyc ) diff --git a/harbour/source/compiler/harbour.c b/harbour/source/compiler/harbour.c index fdf57f39fe..45eefc64ea 100644 --- a/harbour/source/compiler/harbour.c +++ b/harbour/source/compiler/harbour.c @@ -2393,35 +2393,6 @@ void hb_compGenJumpThere( ULONG ulFrom, ULONG ulTo ) { switch( pCode[ ( ULONG ) ( ulFrom - 1 ) ] ) { - /* - case HB_P_JUMPNEAR : - break; - - case HB_P_JUMPTRUENEAR : - break; - - case HB_P_JUMPFALSENEAR : - break; - - case HB_P_JUMP : - pCode[ ( ULONG ) ( ulFrom - 1 ) ] = HB_P_JUMPNEAR; - pCode[ ( ULONG ) ( ulFrom + 1 ) ] = HB_P_NOOP; - pCode[ ( ULONG ) ( ulFrom + 2 ) ] = HB_P_NOOP; - break; - - case HB_P_JUMPTRUE : - pCode[ ( ULONG ) ( ulFrom - 1 ) ] = HB_P_JUMPTRUENEAR; - pCode[ ( ULONG ) ( ulFrom + 1 ) ] = HB_P_NOOP; - pCode[ ( ULONG ) ( ulFrom + 2 ) ] = HB_P_NOOP; - break; - - case HB_P_JUMPFALSE : - pCode[ ( ULONG ) ( ulFrom - 1 ) ] = HB_P_JUMPFALSENEAR; - pCode[ ( ULONG ) ( ulFrom + 1 ) ] = HB_P_NOOP; - pCode[ ( ULONG ) ( ulFrom + 2 ) ] = HB_P_NOOP; - break; - */ - case HB_P_JUMPFAR : pCode[ ( ULONG ) ( ulFrom - 1 ) ] = HB_P_JUMPNEAR; pCode[ ( ULONG ) ( ulFrom + 1 ) ] = HB_P_NOOP; @@ -3211,30 +3182,59 @@ void hb_compGenPushFunCall( char * szFunName ) /* generates the pcode to push a long number on the virtual machine stack */ void hb_compGenPushLong( HB_LONG lNumber ) { - if( lNumber == 0 ) - hb_compGenPCode1( HB_P_ZERO ); - else if( lNumber == 1 ) - hb_compGenPCode1( HB_P_ONE ); - else if( HB_LIM_INT8( lNumber ) ) - hb_compGenPCode2( HB_P_PUSHBYTE, (BYTE) lNumber, TRUE ); - else if( HB_LIM_INT16( lNumber ) ) - hb_compGenPCode3( HB_P_PUSHINT, HB_LOBYTE( lNumber ), HB_HIBYTE( lNumber ), TRUE ); - else if( HB_LIM_INT32( lNumber ) ) + if( hb_comp_long_optimize ) { - BYTE pBuffer[ 5 ]; - pBuffer[ 0 ] = HB_P_PUSHLONG; - HB_PUT_LE_UINT32( pBuffer + 1, lNumber ); - hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), TRUE ); + if( lNumber == 0 ) + hb_compGenPCode1( HB_P_ZERO ); + else if( lNumber == 1 ) + hb_compGenPCode1( HB_P_ONE ); + else if( HB_LIM_INT8( lNumber ) ) + hb_compGenPCode2( HB_P_PUSHBYTE, (BYTE) lNumber, TRUE ); + else if( HB_LIM_INT16( lNumber ) ) + hb_compGenPCode3( HB_P_PUSHINT, HB_LOBYTE( lNumber ), HB_HIBYTE( lNumber ), TRUE ); + else if( HB_LIM_INT32( lNumber ) ) + { + BYTE pBuffer[ 5 ]; + pBuffer[ 0 ] = HB_P_PUSHLONG; + HB_PUT_LE_UINT32( pBuffer + 1, lNumber ); + hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), TRUE ); + } + else + { + BYTE pBuffer[ 9 ]; + pBuffer[ 0 ] = HB_P_PUSHLONGLONG; + HB_PUT_LE_UINT64( pBuffer + 1, lNumber ); + hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), TRUE ); + } } else { - BYTE pBuffer[ 9 ]; - pBuffer[ 0 ] = HB_P_PUSHLONGLONG; - HB_PUT_LE_UINT64( pBuffer + 1, lNumber ); - hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), TRUE ); + if( HB_LIM_INT32( lNumber ) ) + { + BYTE pBuffer[ 5 ]; + pBuffer[ 0 ] = HB_P_PUSHLONG; + HB_PUT_LE_UINT32( pBuffer + 1, lNumber ); + hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), TRUE ); + } + else + { + BYTE pBuffer[ 9 ]; + pBuffer[ 0 ] = HB_P_PUSHLONGLONG; + HB_PUT_LE_UINT64( pBuffer + 1, lNumber ); + hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), TRUE ); + } } } +void hb_compGenPushDate( HB_LONG lNumber ) +{ + BYTE pBuffer[ 5 ]; + + pBuffer[ 0 ] = HB_P_PUSHDATE; + HB_PUT_LE_UINT32( pBuffer + 1, lNumber ); + hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), TRUE ); +} + /* generates the pcode to push a string on the virtual machine stack */ void hb_compGenPushString( char * szText, ULONG ulStrLen ) { diff --git a/harbour/source/compiler/harbour.l b/harbour/source/compiler/harbour.l index 1688fc6788..8c015b8e60 100644 --- a/harbour/source/compiler/harbour.l +++ b/harbour/source/compiler/harbour.l @@ -41,9 +41,11 @@ #include "hbsetup.h" /* main configuration file */ #include "hberrors.h" #include "hbdefs.h" +#include "hbdate.h" /* helper functions */ static int yy_ConvertNumber( char * szBuffer ); +static int yy_ConvertDate( char * szBuffer ); extern int hb_ppInsideTextBlock; extern BOOL hb_ppNestedLiteralString; @@ -102,6 +104,7 @@ SpaceTab [ \t]+ Number ([0-9]+)|([0-9]*\.[0-9]+)|(0x[0-9A-Fa-f]+) InvalidNumber [0-9]+\. Identifier (([a-zA-Z])|([_a-zA-Z][_a-zA-Z0-9]+)) +Date 0d[0-9]{8} MacroVar \&{Identifier}[\.]? MacroEnd \&{Identifier}\.([_a-zA-Z0-9]*) @@ -122,6 +125,7 @@ Separator {SpaceTab} %x NEXT_ BREAK_ CASE_ DO_ DOIDENT_ WHILE_ WITH_ END_ FIELD_ %x FOR_ FOREACH_ FUNCTION_ IIF_ IF_ IN_ INIT_ %x RETURN_ RECOVER_ +%x SWITCH_ %x INVALIDNUM_ OTHERWISE_ PROCEDURE_ %x DECLARE_ DECLARE_ID_ @@ -465,7 +469,7 @@ Separator {SpaceTab} BEGIN 0; unput( yytext[ yyleng-1 ] ); unput( yytext[ yyleng-2 ] ); - if( hb_comp_wCaseCounter == 0 ) + if( hb_comp_wCaseCounter == 0 && hb_comp_wSwitchCounter == 0 ) hb_compGenError( hb_comp_szErrors, 'E', HB_COMP_ERR_CASE, NULL, NULL ); hb_comp_iState =CASE; return CASE; @@ -475,7 +479,7 @@ Separator {SpaceTab} unput( yytext[ yyleng-1 ] ); if( hb_comp_iState == LOOKUP ) { /* it is first item in the line */ - if( hb_comp_wCaseCounter == 0 ) + if( hb_comp_wCaseCounter == 0 && hb_comp_wSwitchCounter == 0 ) hb_compGenError( hb_comp_szErrors, 'E', HB_COMP_ERR_CASE, NULL, NULL ); hb_comp_iState =CASE; return CASE; @@ -1208,7 +1212,7 @@ Separator {SpaceTab} unput( yytext[ yyleng-1 ] ); if( hb_comp_iState == LOOKUP ) { /* it is the first item in the line */ - if( hb_comp_wCaseCounter == 0 ) + if( hb_comp_wCaseCounter == 0 && hb_comp_wSwitchCounter == 0 ) hb_compGenError( hb_comp_szErrors, 'E', HB_COMP_ERR_CASE, NULL, NULL ); hb_comp_iState = OTHERWISE; return OTHERWISE; @@ -1384,6 +1388,51 @@ Separator {SpaceTab} /* ************************************************************************ */ %} "step" { hb_comp_iState = IDENTIFIER; return STEP; } +%{ +/* ************************************************************************ */ +%} +"switch" BEGIN SWITCH_; +{Separator}* ; +[\:\=\|\$\%\*\,\/\]\)\}\^] { /* there is an operator after "switch" */ + BEGIN 0; + yylval.string = hb_compIdentifierNew( "SWITCH", TRUE ); + hb_comp_iState =IDENTIFIER; + unput( yytext[ yyleng-1 ] ); + return IDENTIFIER; + } +("+="|"-="|"->") { /* operators */ + BEGIN 0; + yylval.string = hb_compIdentifierNew( "SWITCH", TRUE ); + hb_comp_iState =IDENTIFIER; + unput( yytext[ yyleng-1 ] ); + unput( yytext[ yyleng-2 ] ); + return IDENTIFIER; + } +("::") { /* send operators */ + BEGIN 0; + unput( yytext[ yyleng-1 ] ); + unput( yytext[ yyleng-2 ] ); + hb_comp_iState =DOSWITCH; + return DOSWITCH; + } +(\n|.) { /* not operator */ + BEGIN 0; + unput( yytext[ yyleng-1 ] ); + if( hb_comp_iState == LOOKUP ) + { /* it is first item in the line */ + hb_comp_iState =DOSWITCH; + return DOSWITCH; + } + else + { /* there is another item in line already */ + yylval.string = hb_compIdentifierNew( "SWITCH", TRUE ); + hb_comp_iState =IDENTIFIER; + return IDENTIFIER; + } + } +%{ +/* ************************************************************************ */ +%} "to" { hb_comp_iState = IDENTIFIER; return TO; } %{ /* ************************************************************************ */ @@ -1684,6 +1733,8 @@ Separator {SpaceTab} {TrueValue} { hb_comp_iState =RSEPARATOR; return TRUEVALUE; } {FalseValue} { hb_comp_iState =RSEPARATOR; return FALSEVALUE; } +{Date} { return yy_ConvertDate( yytext ); } + {MacroVar} { if( yytext[ yyleng-1 ] == '.' ) yytext[ yyleng-1 ] = '\0'; @@ -1765,3 +1816,14 @@ static int yy_ConvertNumber( char * szBuffer ) return NUM_LONG; } } + +static int yy_ConvertDate( char * szBuffer ) +{ + int year, month, day; + + hb_dateStrGet( szBuffer+2, &year, &month, &day ); + yylval.valLong.lNumber = hb_dateEncode( year, month, day ); + yylval.valLong.szValue = szBuffer; + + return NUM_DATE; +} diff --git a/harbour/source/compiler/harbour.y b/harbour/source/compiler/harbour.y index 3c70ebb866..d0d5a4bb27 100644 --- a/harbour/source/compiler/harbour.y +++ b/harbour/source/compiler/harbour.y @@ -94,6 +94,11 @@ static void hb_compEnumStart( HB_EXPR_PTR pVars, HB_EXPR_PTR pExprs, int descend static void hb_compEnumNext( HB_EXPR_PTR pExpr, int descend ); static void hb_compEnumEnd( HB_EXPR_PTR pExpr ); +static void hb_compSwitchStart( void ); +static void hb_compSwitchAdd( HB_EXPR_PTR ); +static void hb_compSwitchEnd( void ); + + #ifdef HARBOUR_YYDEBUG #define YYDEBUG 1 /* Parser debug information support */ #endif @@ -114,6 +119,24 @@ typedef struct _LOOPEXIT struct _LOOPEXIT * pNext; } LOOPEXIT, * PTR_LOOPEXIT; /* support structure for EXIT and LOOP statements */ +/* support structure for SWITCH statement */ +typedef struct _SWITCHCASE +{ + ULONG ulOffset; + HB_EXPR_PTR pExpr; + struct _SWITCHCASE *pNext; +} SWITCHCASE, * SWITCHCASE_PTR; + +typedef struct _SWITCHCMD +{ + ULONG ulOffset; + int iCount; + SWITCHCASE_PTR pCases; + SWITCHCASE_PTR pLast; + ULONG ulDefault; + struct _SWITCHCMD *pPrev; +} SWITCHCMD, *SWITCHCMD_PTR; + typedef struct HB_RTVAR_ { HB_EXPR_PTR pVar; @@ -127,11 +150,15 @@ USHORT hb_comp_wForCounter = 0; USHORT hb_comp_wIfCounter = 0; USHORT hb_comp_wWhileCounter = 0; USHORT hb_comp_wCaseCounter = 0; +USHORT hb_comp_wSwitchCounter= 0; +BOOL hb_comp_long_optimize = TRUE; +BOOL hb_comp_bTextSubst = TRUE; char * hb_comp_buffer; /* yacc input buffer */ static PTR_LOOPEXIT hb_comp_pLoops = NULL; static HB_RTVAR_PTR hb_comp_rtvars = NULL; +static SWITCHCMD_PTR hb_comp_pSwitch = NULL; extern int hb_compLocalGetPos( char * szVarName ); /* returns the order + 1 of a local variable */ @@ -188,6 +215,8 @@ static void hb_compDebugStart( void ) { }; %token PROCREQ GET %token CBSTART DOIDENT %token FOREACH DESCEND +%token DOSWITCH +%token NUM_DATE /*the lowest precedence*/ /*postincrement and postdecrement*/ @@ -220,6 +249,7 @@ static void hb_compDebugStart( void ) { }; %type NUM_DOUBLE %type NUM_INTEGER %type NUM_LONG +%type NUM_DATE %type FunScope %type Params ParamList %type IfBegin VarList ExtVarList @@ -260,6 +290,8 @@ static void hb_compDebugStart( void ) { }; %type PostOp %type ForVar ForList ForExpr %type CBSTART +%type SwitchCases SwitchStart SwitchBegin SwitchDefault +%type DateValue %% @@ -482,6 +514,14 @@ NumValue : NUM_DOUBLE { $$ = hb_compExprNewDouble( $1.dNumber, $1.bWi | NUM_LONG { $$ = hb_compExprNewLong( $1.lNumber ); } ; +DateValue : NUM_DATE { $$ = hb_compExprNewDate( $1.lNumber ); + if( $1.lNumber == 0 ) + { + hb_compGenError( hb_comp_szErrors, 'E', HB_COMP_ERR_INVALID_DATE, $1.szValue, NULL ); + } + } + ; + NumAlias : NUM_INTEGER ALIASOP { $$ = hb_compExprNewLong( $1.iNumber ); } | NUM_LONG ALIASOP { $$ = hb_compExprNewLong( $1.lNumber ); } | NUM_DOUBLE ALIASOP { $$ = hb_compErrorAlias( hb_compExprNewDouble( $1.dNumber, $1.bWidth, $1.bDec ) ); } @@ -682,6 +722,7 @@ SendId : IdentName { $$ = $1; } ObjectData : NumValue ':' SendId { $$ = hb_compExprNewSend( $1, $3 ); } | NilValue ':' SendId { $$ = hb_compExprNewSend( $1, $3 ); } + | DateValue ':' SendId { $$ = hb_compExprNewSend( $1, $3 ); } | LiteralValue ':' SendId { $$ = hb_compExprNewSend( $1, $3 ); } | CodeBlock ':' SendId { $$ = hb_compExprNewSend( $1, $3 ); } | Logical ':' SendId { $$ = hb_compExprNewSend( $1, $3 ); } @@ -719,6 +760,7 @@ ObjectMethodAlias : ObjectMethod ALIASOP { $$ = $1; } SimpleExpression : NumValue | NilValue { $$ = $1; } + | DateValue { $$ = $1; } | LiteralValue { $$ = $1; } | CodeBlock { $$ = $1; } | Logical { $$ = $1; } @@ -836,6 +878,7 @@ ExprAssign : NumValue INASSIGN Expression { $$ = hb_compExprAssign( $1, $ ExprEqual : NumValue '=' Expression %prec INASSIGN { $$ = hb_compExprAssign( $1, $3 ); } | NilValue '=' Expression %prec INASSIGN { $$ = hb_compExprAssign( $1, $3 ); } + | DateValue '=' Expression %prec INASSIGN { $$ = hb_compExprAssign( $1, $3 ); } | LiteralValue '=' Expression %prec INASSIGN { $$ = hb_compExprAssign( $1, $3 ); } | CodeBlock '=' Expression %prec INASSIGN { $$ = hb_compExprAssign( $1, $3 ); } | Logical '=' Expression %prec INASSIGN { $$ = hb_compExprAssign( $1, $3 ); } @@ -1364,6 +1407,7 @@ ExecFlow : IfEndif | ForNext | BeginSeq | ForEach + | DoSwitch ; IfEndif : IfBegin EndIf { hb_compGenJumpHere( $1 ); } @@ -1531,9 +1575,9 @@ ForNext : FOR LValue ForAssign Expression /* 1 2 3 4 */ hb_compDebugStart(); ++hb_comp_wForCounter; /* 5 */ $$ = hb_compExprGenStatement( hb_compExprAssign( $2, $4 ) ); - if( hb_compExprAsString($2) ) + if( hb_compExprAsSymbol($2) ) { - hb_compForStart( hb_compExprAsString($2), FALSE ); + hb_compForStart( hb_compExprAsSymbol($2), FALSE ); } } TO Expression StepExpr /* 6 7 8 */ @@ -1571,7 +1615,7 @@ ForNext : FOR LValue ForAssign Expression /* 1 2 3 4 */ iStep = 1; } - if( iStep && ( iLocal = hb_compLocalGetPos( hb_compExprAsString($2) ) ) > 0 && iLocal < 256 ) + if( iStep && ( iLocal = hb_compLocalGetPos( hb_compExprAsSymbol($2) ) ) > 0 && iLocal < 256 ) { hb_compGenPCode4( HB_P_LOCALNEARADDINT, ( BYTE ) iLocal, HB_LOBYTE( iStep ), HB_HIBYTE( iStep ), ( BOOL ) 0 ); } @@ -1587,9 +1631,9 @@ ForNext : FOR LValue ForAssign Expression /* 1 2 3 4 */ hb_compGenJump( $9 - hb_comp_functions.pLast->lPCodePos ); hb_compGenJumpHere( $11 ); hb_compLoopEnd(); - if( hb_compExprAsString($2) ) + if( hb_compExprAsSymbol($2) ) { - hb_compForEnd( hb_compExprAsString($2) ); + hb_compForEnd( hb_compExprAsSymbol($2) ); } hb_compExprDelete( $7 ); hb_compExprDelete( $5 ); /* deletes $5, $2, $4 */ @@ -1665,6 +1709,68 @@ Descend : /* default up */ { $$ = 1; } | DESCEND { $$ = -1; } ; +DoSwitch : SwitchBegin + { + hb_compLoopStart(); + hb_compSwitchStart(); + hb_compGenJump( 0 ); + } + SwitchCases + EndSwitch + { + hb_compSwitchEnd(); + hb_compLoopEnd(); + } + + | SwitchBegin + EndSwitch + { + hb_compGenPData1( HB_P_POP ); + } + + ; + +EndSwitch : END + { + --hb_comp_wSwitchCounter; + hb_comp_functions.pLast->bFlags &= ~ ( FUN_WITH_RETURN | FUN_BREAK_CODE ); + } + ; + +SwitchStart : DOSWITCH + { ++hb_comp_wSwitchCounter; + hb_compLinePush(); + } + Expression Crlf + { + hb_compExprDelete( hb_compExprGenPush( $3 ) ); + } + ; + +SwitchBegin : SwitchStart { } + | SwitchStart Statements { + if( $2 > 0 ) + { + hb_compGenError( hb_comp_szErrors, 'E', HB_COMP_ERR_MAYHEM_IN_CASE, NULL, NULL ); + } + } + ; + +SwitchCases : CASE Expression { hb_compSwitchAdd( $2 ); hb_compLinePush(); } Crlf + EmptyStats + + | SwitchCases CASE Expression { hb_compSwitchAdd( $3 ); hb_compLinePush(); }Crlf + EmptyStats + + | SwitchDefault + + | SwitchCases SwitchDefault + ; + +SwitchDefault : OTHERWISE {hb_compSwitchAdd(NULL); hb_compLinePush(); } Crlf { hb_comp_functions.pLast->bFlags &= ~ FUN_BREAK_CODE; } + EmptyStats + ; + BeginSeq : BEGINSEQ { ++hb_comp_wSeqCounter; $$ = hb_compSequenceBegin(); } Crlf EmptyStats { @@ -2296,7 +2402,7 @@ static void hb_compForEnd( char *szVar ) static HB_CARGO2_FUNC( hb_compEnumEvalStart ) { - char * szName = hb_compExprAsString( (HB_EXPR_PTR)cargo ); + char * szName = hb_compExprAsSymbol( (HB_EXPR_PTR)cargo ); if( szName ) hb_compForStart( szName, TRUE ); @@ -2342,7 +2448,7 @@ static void hb_compEnumNext( HB_EXPR_PTR pExpr, int descend ) static HB_CARGO_FUNC( hb_compEnumEvalEnd ) { - char * szName = hb_compExprAsString( (HB_EXPR_PTR)cargo ); + char * szName = hb_compExprAsSymbol( (HB_EXPR_PTR)cargo ); if( szName ) hb_compForEnd( szName ); @@ -2354,3 +2460,126 @@ static void hb_compEnumEnd( HB_EXPR_PTR pExpr ) hb_compGenPCode1( HB_P_ENUMEND ); } +static void hb_compSwitchStart() +{ + SWITCHCMD_PTR pLast = hb_comp_pSwitch; + + hb_comp_pSwitch = (SWITCHCMD_PTR) hb_xgrab( sizeof(SWITCHCMD) ); + hb_comp_pSwitch->pPrev = pLast; + hb_comp_pSwitch->pCases = NULL; + hb_comp_pSwitch->pLast = NULL; + hb_comp_pSwitch->ulDefault = 0; + hb_comp_pSwitch->ulOffset = hb_comp_functions.pLast->lPCodePos; + hb_comp_pSwitch->iCount = 0; +} + +static void hb_compSwitchAdd( HB_EXPR_PTR pExpr ) +{ + SWITCHCASE_PTR pCase; + + if( pExpr ) + { + /* normal CASE */ + pCase = (SWITCHCASE_PTR) hb_xgrab( sizeof(SWITCHCASE) ); + pCase->ulOffset = hb_comp_functions.pLast->lPCodePos; + pCase->pNext = NULL; + pExpr = hb_compExprReduce( pExpr ); + if( !(hb_compExprIsLong(pExpr) || hb_compExprIsString(pExpr)) ) + { + hb_compGenError( hb_comp_szErrors, 'E', HB_COMP_ERR_NOT_LITERAL_CASE, NULL, NULL ); + } + pCase->pExpr = pExpr; + + if( hb_comp_pSwitch->pLast ) + { + hb_comp_pSwitch->pLast->pNext = pCase; + hb_comp_pSwitch->pLast = pCase; + } + else + { + hb_comp_pSwitch->pCases = hb_comp_pSwitch->pLast = pCase; + } + hb_comp_pSwitch->iCount++; + if( hb_compExprIsString( pExpr ) && hb_compExprAsStringLen(pExpr) > 255 ) + { + hb_compGenError( hb_comp_szErrors, 'E', HB_COMP_ERR_INVALID_STR, NULL, NULL ); + } + } + else + { + /* DEFAULT */ + if( hb_comp_pSwitch->ulDefault ) + { + /* more than one default clause */ + hb_compGenError( hb_comp_szErrors, 'E', HB_COMP_ERR_MAYHEM_IN_CASE, NULL, NULL ); + } + else + { + hb_comp_pSwitch->ulDefault = hb_comp_functions.pLast->lPCodePos; + hb_comp_pSwitch->iCount++; + } + } + +} + +static void hb_compSwitchEnd( void ) +{ + BOOL longOptimize = hb_comp_long_optimize; + BOOL bTextSubst = hb_comp_bTextSubst; + SWITCHCASE_PTR pCase = hb_comp_pSwitch->pCases; + SWITCHCASE_PTR pTmp; + SWITCHCMD_PTR pTmpSw; + ULONG ulExitPos; + ULONG ulDef; + + /* skip switch pcode if there was no EXIT in the last CASE + * or in the DEFAULT case + */ + ulExitPos = hb_compGenJump( 0 ); + + hb_compGenJumpHere( hb_comp_pSwitch->ulOffset + 1 ); + hb_compGenPCode3( HB_P_SWITCH, HB_LOBYTE(hb_comp_pSwitch->iCount), HB_HIBYTE(hb_comp_pSwitch->iCount), FALSE ); + hb_comp_long_optimize = FALSE; + hb_comp_bTextSubst = FALSE; + while( pCase ) + { + if( pCase->pExpr ) + { + if( hb_compExprIsLong(pCase->pExpr) || hb_compExprIsString(pCase->pExpr) ) + { + hb_compExprDelete( hb_compExprGenPush( pCase->pExpr ) ); + hb_compGenJumpThere( hb_compGenJump( 0 ), pCase->ulOffset ); + } + else + { + hb_compExprDelete( pCase->pExpr ); + } + } + pCase = pCase->pNext; + } + hb_compGenPData1( HB_P_PUSHNIL ); /* end of cases */ + ulDef = hb_compGenJump( 0 ); + + if( hb_comp_pSwitch->ulDefault ) + { + hb_compGenJumpThere( ulDef, hb_comp_pSwitch->ulDefault ); + } + else + hb_compGenJumpHere( ulDef ); + + hb_comp_long_optimize = longOptimize; + hb_comp_bTextSubst = bTextSubst; + + hb_compGenJumpHere( ulExitPos ); + + pCase = hb_comp_pSwitch->pCases; + while( pCase ) + { + pTmp = pCase->pNext; + hb_xfree( (void *)pCase ); + pCase = pTmp; + } + pTmpSw = hb_comp_pSwitch; + hb_comp_pSwitch = hb_comp_pSwitch->pPrev; + hb_xfree( pTmpSw ); +} diff --git a/harbour/source/compiler/hbfix.c b/harbour/source/compiler/hbfix.c index ad0df5cbb7..98d3f2f222 100644 --- a/harbour/source/compiler/hbfix.c +++ b/harbour/source/compiler/hbfix.c @@ -432,7 +432,9 @@ static HB_FIX_FUNC_PTR s_fixlocals_table[] = NULL, /* HB_P_ENUMSTART */ NULL, /* HB_P_ENUMNEXT */ NULL, /* HB_P_ENUMPREV */ - NULL /* HB_P_ENUMEND */ + NULL, /* HB_P_ENUMEND */ + NULL, /* HB_P_SWITCH */ + NULL /* HB_P_PUSHDATE */ }; void hb_compFixFuncPCode( PFUNCTION pFunc ) diff --git a/harbour/source/compiler/hbgenerr.c b/harbour/source/compiler/hbgenerr.c index bddd5bcd61..269c69c626 100644 --- a/harbour/source/compiler/hbgenerr.c +++ b/harbour/source/compiler/hbgenerr.c @@ -86,7 +86,10 @@ char * hb_comp_szErrors[] = "Inline C requires C output generation, use -gc[n]", "Too many local variables [%s] or parameters [%s]", "Too many enumerate variables in FOR EACH loop", - "Incorrect number of enumerate variables" + "Incorrect number of enumerate variables", + "CASE requires either numeric or string constant", + "String too long for SWITCH", + "Invalid date constant \'%s\'" }; /* Table with parse warnings */ diff --git a/harbour/source/compiler/hbident.c b/harbour/source/compiler/hbident.c index dc0cb8fc8d..c5b238b2ce 100644 --- a/harbour/source/compiler/hbident.c +++ b/harbour/source/compiler/hbident.c @@ -49,7 +49,7 @@ char * hb_compIdentifierNew( char * szName, BOOL bCopy ) else szIdent = szName; - hb_hashTableAdd( s_comp_Identifiers, (void *)szIdent ); + hb_hashTableAdd( s_comp_Identifiers, (void *)szIdent, (void *)szIdent ); } return szIdent; @@ -64,6 +64,7 @@ HB_HASH_FUNC( hb_comp_IdentKey ) /* ULONG func (void *Value, void *Cargo) */ while( *szName ) ulSum += *szName++; + HB_SYMBOL_UNUSED( HashPtr ); HB_SYMBOL_UNUSED( Cargo ); return ulSum % HB_IDENT_TABLE_SIZE; @@ -73,6 +74,7 @@ HB_HASH_FUNC( hb_comp_IdentKey ) /* ULONG func (void *Value, void *Cargo) */ HB_HASH_FUNC( hb_comp_IdentDel ) { hb_xfree( Value ); + HB_SYMBOL_UNUSED( HashPtr ); HB_SYMBOL_UNUSED( Cargo ); return 1; } @@ -80,6 +82,7 @@ HB_HASH_FUNC( hb_comp_IdentDel ) /* compares two identifiers */ HB_HASH_FUNC( hb_comp_IdentComp ) { + HB_SYMBOL_UNUSED( HashPtr ); return strcmp( (char *)Value, (char *)Cargo ); } diff --git a/harbour/source/compiler/hbpcode.c b/harbour/source/compiler/hbpcode.c index c46d41fd8a..26e05d4628 100644 --- a/harbour/source/compiler/hbpcode.c +++ b/harbour/source/compiler/hbpcode.c @@ -176,7 +176,9 @@ static BYTE s_pcode_len[] = { 3, /* HB_P_ENUMSTART */ 1, /* HB_P_ENUMNEXT */ 1, /* HB_P_ENUMPREV */ - 1 /* HB_P_ENUMEND */ + 1, /* HB_P_ENUMEND */ + 3, /* HB_P_SWITCH */ + 5 /* HB_P_PUSHDATE, */ }; #if defined(HB_COMP_STRONG_TYPES) diff --git a/harbour/source/macro/macro.l b/harbour/source/macro/macro.l index d8ed6579b8..323dc96a0d 100644 --- a/harbour/source/macro/macro.l +++ b/harbour/source/macro/macro.l @@ -73,6 +73,7 @@ NOTE: -C controls the speed/size ratio of generated scanner #include "hbmacro.h" #include "hbcomp.h" +#include "hbdate.h" #include "macroy.h" #include "hbsetup.h" /* main configuration file */ @@ -117,6 +118,7 @@ SpaceTab [ \t]+ Number ([0-9]+)|([0-9]*\.[0-9]+)|(0x[0-9A-Fa-f]+) InvalidNumber [0-9]+\. Identifier (([a-zA-Z])|([_a-zA-Z][_a-zA-Z0-9]+)) +Date 0d[0-9]{8} MacroVar \&{Identifier}[\.]? MacroEnd \&{Identifier}\.({Identifier})|([0-9]+) @@ -268,6 +270,15 @@ MacroTxt ({MacroVar}|{MacroEnd}|{MacroId})+ } } +{Date} { + int year, month, day; + + hb_dateStrGet( yytext+2, &year, &month, &day ); + yylval_ptr->valLong.lNumber = hb_dateEncode( year, month, day ); + + return NUM_DATE; +} + {MacroVar} { HB_TRACE(HB_TR_DEBUG, ("{MacroVar}(%s)", yytext)); if( yytext[ yyleng-1 ] == '.' ) diff --git a/harbour/source/macro/macro.y b/harbour/source/macro/macro.y index 58953e30cc..818b7648d7 100644 --- a/harbour/source/macro/macro.y +++ b/harbour/source/macro/macro.y @@ -64,6 +64,7 @@ #include "hbmacro.h" #include "hbcomp.h" +#include "hbdate.h" /* Compile using: bison -d -p hb_comp macro.y */ @@ -159,7 +160,7 @@ int yylex( YYSTYPE *, HB_MACRO_PTR ); #endif %} -%token IDENTIFIER NIL NUM_DOUBLE INASSIGN NUM_LONG +%token IDENTIFIER NIL NUM_DOUBLE INASSIGN NUM_LONG NUM_DATE %token IIF IF LITERAL TRUEVALUE FALSEVALUE %token AND OR NOT EQ NE1 NE2 INC DEC ALIASOP SELF %token LE GE FIELD MACROVAR MACROTEXT @@ -194,6 +195,7 @@ int yylex( YYSTYPE *, HB_MACRO_PTR ); %type IDENTIFIER LITERAL MACROVAR MACROTEXT %type NUM_DOUBLE %type NUM_LONG +%type NUM_DATE %type Argument ArgList ElemList BlockExpList BlockVarList BlockNoVar %type NumValue NumAlias %type NilValue @@ -221,6 +223,7 @@ int yylex( YYSTYPE *, HB_MACRO_PTR ); %type ArrayIndex IndexList %type FieldAlias FieldVarAlias %type PostOp +%type DateValue %% @@ -267,6 +270,9 @@ NumValue : NUM_DOUBLE { $$ = hb_compExprNewDouble( $1.dNumber, $1.bWidth, | NUM_LONG { $$ = hb_compExprNewLong( $1.lNumber ); } ; +DateValue : NUM_DATE { $$ = hb_compExprNewDate( $1.lNumber ); } + ; + NumAlias : NUM_LONG ALIASOP { $$ = hb_compExprNewLong( $1.lNumber ); } ; @@ -431,6 +437,7 @@ Argument : EmptyExpression { $$ = $1; } */ ObjectData : NumValue ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); } | NilValue ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); } + | DateValue ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); } | LiteralValue ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); } | CodeBlock ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); } | Logical ':' IDENTIFIER { $$ = hb_compExprNewSend( $1, $3 ); } @@ -458,6 +465,7 @@ ObjectMethod : ObjectData '(' ArgList ')' { $$ = hb_compExprNewMethodCall( $1 SimpleExpression : NumValue | NilValue { $$ = $1; } + | DateValue { $$ = $1; } | LiteralValue { $$ = $1; } | CodeBlock { $$ = $1; } | Logical { $$ = $1; } diff --git a/harbour/source/macro/macroa.c b/harbour/source/macro/macroa.c index ff768e11e2..752ee8f69e 100644 --- a/harbour/source/macro/macroa.c +++ b/harbour/source/macro/macroa.c @@ -5,7 +5,7 @@ /* hbexpra.c is also included from ../compiler/expropta.c * However it produces a slighty different code if used in * macro compiler (there is an additional parameter passed to some functions) - * 1.16 - ignore this magic number - this is used to force compilation + * 1.17 - ignore this magic number - this is used to force compilation */ #define HB_MACRO_SUPPORT diff --git a/harbour/source/macro/macrob.c b/harbour/source/macro/macrob.c index 8f5bd1b8fe..2af9d8f49b 100644 --- a/harbour/source/macro/macrob.c +++ b/harbour/source/macro/macrob.c @@ -5,7 +5,7 @@ /* hbexprb.c is also included from ../compiler/exproptb.c * However it produces a slighty different code if used in * macro compiler (there is an additional parameter passed to some functions) - * 1.12 - ignore this magic number - this is used to force compilation + * 1.13 - ignore this magic number - this is used to force compilation */ #define HB_MACRO_SUPPORT diff --git a/harbour/source/rtl/dates.c b/harbour/source/rtl/dates.c index bd8495afe9..bfa769d3f8 100644 --- a/harbour/source/rtl/dates.c +++ b/harbour/source/rtl/dates.c @@ -78,115 +78,6 @@ #include "hbapi.h" #include "hbdate.h" -#ifdef HB_C52_STRICT - #define HB_DATE_YEAR_LIMIT 2999 -#else - #define HB_DATE_YEAR_LIMIT 9999 -#endif - -LONG HB_EXPORT hb_dateEncode( int iYear, int iMonth, int iDay ) -{ - HB_TRACE(HB_TR_DEBUG, ("hb_dateEncode(%d, %d, %d)", iYear, iMonth, iDay)); - - /* Perform date validation */ - if( iYear >= 1 && iYear <= HB_DATE_YEAR_LIMIT && - iMonth >= 1 && iMonth <= 12 && - iDay >= 1 ) - { - /* Month, year, and lower day limits are simple, - but upper day limit is dependent upon month and leap year */ - int auiDayLimit[ 12 ] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - - if( ( ( iYear % 4 == 0 && iYear % 100 != 0 ) || iYear % 400 == 0 ) ) - auiDayLimit[ 1 ] = 29; - - if( iDay <= auiDayLimit[ iMonth - 1 ] ) - { - int iFactor = ( iMonth < 3 ) ? -1 : 0; - - return ( ( LONG )( iFactor + 4800 + iYear ) * 1461 / 4 ) + - ( ( LONG )( iMonth - 2 - ( iFactor * 12 ) ) * 367 ) / 12 - - ( ( LONG )( ( iFactor + 4900 + iYear ) / 100 ) * 3 / 4 ) + - ( LONG ) iDay - 32075; - } - } - - return 0; -} - -void HB_EXPORT hb_dateDecode( LONG lJulian, int *piYear, int *piMonth, int *piDay ) -{ - HB_TRACE(HB_TR_DEBUG, ("hb_dateDecode(%ld, %p, %p, %p)", lJulian, piYear, piMonth, piDay)); - - if( lJulian > 0 ) - { - LONG U, V, W, X; - - lJulian += 68569; - W = ( lJulian * 4 ) / 146097; - lJulian -= ( ( 146097 * W ) + 3 ) / 4; - X = 4000 * ( lJulian + 1 ) / 1461001; - lJulian -= ( ( 1461 * X ) / 4 ) - 31; - V = 80 * lJulian / 2447; - U = V / 11; - - *piYear = (int) ( X + U + ( W - 49 ) * 100 ); - *piMonth = (int) ( V + 2 - ( U * 12 ) ); - *piDay = (int) ( lJulian - ( 2447 * V / 80 ) ); - } - else - { - *piYear = - *piMonth = - *piDay = 0; - } -} - -void HB_EXPORT hb_dateStrPut( char * szDate, int iYear, int iMonth, int iDay ) -{ - HB_TRACE(HB_TR_DEBUG, ("hb_dateStrPut(%p, %d, %d, %d)", szDate, iYear, iMonth, iDay)); - - if( iYear >= 0 && iMonth && iDay ) - { - szDate[ 0 ] = ( ( iYear % 10000 ) / 1000 ) + '0'; - szDate[ 1 ] = ( ( iYear % 1000 ) / 100 ) + '0'; - szDate[ 2 ] = ( ( iYear % 100 ) / 10 ) + '0'; - szDate[ 3 ] = ( iYear % 10 ) + '0'; - - szDate[ 4 ] = ( iMonth / 10 ) + '0'; - szDate[ 5 ] = ( iMonth % 10 ) + '0'; - - szDate[ 6 ] = ( iDay / 10 ) + '0'; - szDate[ 7 ] = ( iDay % 10 ) + '0'; - } - else if ( iYear || iMonth || iDay ) - memset( szDate, '0', 8 ); - else - memset( szDate, ' ', 8 ); -} - -void HB_EXPORT hb_dateStrGet( const char * szDate, int * piYear, int * piMonth, int * piDay ) -{ - HB_TRACE(HB_TR_DEBUG, ("hb_dateStrGet(%s, %p, %p, %p)", szDate, piYear, piMonth, piDay)); - - if( szDate && szDate[ 8 ] == '\0' ) - { - /* Date string has correct length, so attempt to convert */ - *piYear = ( ( USHORT ) ( szDate[ 0 ] - '0' ) * 1000 ) + - ( ( USHORT ) ( szDate[ 1 ] - '0' ) * 100 ) + - ( ( USHORT ) ( szDate[ 2 ] - '0' ) * 10 ) + - ( USHORT ) ( szDate[ 3 ] - '0' ); - *piMonth = ( ( szDate[ 4 ] - '0' ) * 10 ) + ( szDate[ 5 ] - '0' ); - *piDay = ( ( szDate[ 6 ] - '0' ) * 10 ) + ( szDate[ 7 ] - '0' ); - } - else - { - /* Date string missing or bad length, so force an empty date */ - *piYear = - *piMonth = - *piDay = 0; - } -} /* This function always closes the date with a zero byte, so it needs a 9 character long buffer. */ diff --git a/harbour/source/vm/hvm.c b/harbour/source/vm/hvm.c index a9ac173bf1..ac7dc5ce32 100644 --- a/harbour/source/vm/hvm.c +++ b/harbour/source/vm/hvm.c @@ -131,6 +131,7 @@ static LONG hb_vmEnumStart( BYTE, BYTE, LONG ); /* prepare FOR EACH loop */ static void hb_vmEnumNext( void ); /* increment FOR EACH loop counter */ static void hb_vmEnumPrev( void ); /* decrement FOR EACH loop counter */ static LONG hb_vmEnumEnd( void ); /* rewind the stack after FOR EACH loop counter */ +static LONG hb_vmSwitch( const BYTE * pCode, LONG, USHORT ); /* make a SWITCH statement */ /* Operators (logical) */ static void hb_vmNot( void ); /* changes the latest logical value on the stack */ @@ -628,7 +629,7 @@ void HB_EXPORT hb_vmExecute( const BYTE * pCode, PHB_SYMB pSymbols ) if( ! --uiPolls ) { hb_inkeyPoll(); - //uiPolls = 255; + uiPolls = 255; /* IMHO we should have a _SET_ controlled by user * sth like: @@ -770,6 +771,10 @@ void HB_EXPORT hb_vmExecute( const BYTE * pCode, PHB_SYMB pSymbols ) w++; break; + case HB_P_SWITCH: + w = hb_vmSwitch( pCode, w+3, HB_PCODE_MKUSHORT( &( pCode[ w + 1 ] ) ) ); + break; + /* Operators (logical) */ case HB_P_NOT: @@ -1251,6 +1256,12 @@ void HB_EXPORT hb_vmExecute( const BYTE * pCode, PHB_SYMB pSymbols ) w += ( 2 + pCode[ w + 1 ] ); break; + case HB_P_PUSHDATE: + HB_TRACE( HB_TR_DEBUG, ("(HB_P_PUSHDATE)") ); + hb_vmPushDate( ( long ) HB_PCODE_MKLONG( &pCode[ w + 1 ] ) ); + w += 5; + break; + case HB_P_PUSHBLOCK: /* +0 -> _pushblock * +1 +2 -> size of codeblock @@ -3263,6 +3274,85 @@ static LONG hb_vmEnumEnd( void ) return lOldBase; } +static LONG hb_vmSwitch( const BYTE * pCode, LONG offset, USHORT casesCnt ) +{ + HB_ITEM_PTR pSwitch = hb_stackItemFromTop( -1 ); + + if( !(HB_IS_NUMINT(pSwitch) || HB_IS_STRING(pSwitch)) ) + { + HB_ITEM_PTR pResult = hb_errRT_BASE_Subst( EG_ARG, 3104, NULL, "SWITCH", 1, pSwitch ); + + if( pResult ) + { + hb_stackPop(); + hb_vmPush( pResult ); + hb_itemRelease( pResult ); + pSwitch = hb_stackItemFromTop( -1 ); + } + else + return offset; + } + + while( casesCnt-- ) + { + switch( pCode[ offset ] ) + { + case HB_P_PUSHLONG: + { + if( HB_IS_NUMINT(pSwitch) ) + { + if( HB_ITEM_GET_NUMINTRAW(pSwitch) == HB_PCODE_MKLONG( &pCode[ offset + 1 ] ) ) + { + hb_stackPop(); + return offset + 5; + } + } + offset += 5; + } + break; + + case HB_P_PUSHSTRSHORT: + { + if( HB_IS_STRING(pSwitch) ) + { +// int i = hb_itemStrCmp( pItem1, pItem2, bExact ); + + if( strcmp( pSwitch->item.asString.value, ( char * ) pCode + offset + 2 ) == 0 ) + { + hb_stackPop(); + return offset + 2 + pCode[ offset + 1 ]; + } + } + offset += ( 2 + pCode[ offset + 1 ] ); + } + break; + + case HB_P_PUSHNIL: + { + /* default clause */ + hb_stackPop(); + return offset + 1; + } + break; + } + + switch( pCode[ offset ] ) + { + case HB_P_JUMP: + offset += 3; + break; + case HB_P_JUMPNEAR: + offset += 2; + break; + default: + offset += 4; + break; + } + } + hb_stackPop(); + return offset; +} + /* ------------------------------- */ /* Operators (logical) */ /* ------------------------------- */ diff --git a/harbour/source/vm/macro.c b/harbour/source/vm/macro.c index b816706e01..b7638954e1 100644 --- a/harbour/source/vm/macro.c +++ b/harbour/source/vm/macro.c @@ -1284,6 +1284,15 @@ void hb_compGenPushLong( HB_LONG lNumber, HB_MACRO_DECL ) } } +/* generates the pcode to push a date on the virtual machine stack */ +void hb_compGenPushDate( HB_LONG lNumber, HB_MACRO_DECL ) +{ + BYTE pBuffer[ 5 ]; + + pBuffer[ 0 ] = HB_P_PUSHDATE; + HB_PUT_LE_UINT32( pBuffer + 1, lNumber ); + hb_compGenPCodeN( pBuffer, sizeof( pBuffer ), HB_MACRO_PARAM ); +} /* sends a message to an object */ void hb_compGenMessage( char * szMsgName, HB_MACRO_DECL ) diff --git a/harbour/tests/ddate.prg b/harbour/tests/ddate.prg new file mode 100644 index 0000000000..10ae0475dc --- /dev/null +++ b/harbour/tests/ddate.prg @@ -0,0 +1,31 @@ +PROCEDURE MAIN() +LOCAL dDate +LOCAL A + + SET DATE FORMAT TO "YYYY.MM.DD" + SET CENTURY ON + + dDate = 0d20051112 + ? "Should be '2005.11.12' :", dDate + + dDate = 0d18341112 + ? "Should be '1834.11.12' :", dDate + + dDate = 0d20040229 + 1 + ? "Should be '2004.03.01' :", dDate + + dDate = 0d20040229 - 1 + ? "Should be '2004.02.28' :", dDate + + ? "Should be '4' :", 0d20040229 - 0d20040225 + ? "Should be '0' :", 0d20040229 - 0d20040229 + + dDate = 0d20000229 + ? "Should be '2000.02.29' :", dDate + + a := '0d20040229+1' + ? "Should be '2004.03.01' :", &a + + a :="DATE() - 0d20051112" + ? "Number of days from 2005.11.12:", &a + diff --git a/harbour/tests/switch.prg b/harbour/tests/switch.prg new file mode 100644 index 0000000000..7d99cb8fcb --- /dev/null +++ b/harbour/tests/switch.prg @@ -0,0 +1,116 @@ +#ifdef __XHARBOUR__ + #define OTHERWISE DEFAULT +#endif + +PROCEDURE MAIN +LOCAL a:=1 +PRIVATE b:="b" + +#ifndef __XHARBOUR__ + SWITCH a + END +#endif + + ? + ? "1111111111111111111111111111111" + SWITCH a + CASE 1 + ? "FOUND: 1" + END + + ? + ? "2222222222222222222222222222222" + SWITCH a + CASE 1 + ? "FOUND: 1" + EXIT + CASE "2" + ? a + END + + ? + ? "3333333333333333333333333333333" + SWITCH a + CASE 1 + ? "FOUND: 1" + CASE "2" + ? "FOUND: 2" + OTHERWISE + ? "other" + END + +#ifndef __XHARBOUR__ + ? + ? "44444444444444444444444444444444444" + SWITCH a + OTHERWISE + ? "OTHERWISE" + END +#endif + + ? + ? "55555555555555555555555555555555555" + a := 'EE' +#ifndef __XHARBOUR__ + SWITCH a + CASE 11 + ? "11" + exit + + CASE 'CCCC'+'DDDD' + ? a+a + EXIT + + CASE "a&b" + CASE 1+1 + CASE {11111111,22222222222}[1] + CASE 1+1+1 + ? "3" + EXIT + + CASE 1+1*3 + CASE 123+12*4-1*4+2 + CASE 1-4 + ? "4" + EXIT + CASE 123456789 + CASE 0 + EXIT + CASE 'AAAA' + CASE 'BBBBB' + ? a + EXIT + CASE CHR(12)+CHR(15) + ? "CHR()" + EXIT + OTHERWISE + ? "NOT FOUND: running OTHER" + END +#endif + + ? + ? "666666666666666666666666666666666666666666" + a := "2" + SWITCH a + CASE 1 + ? "FOUND: 1" + ? a + EXIT + CASE "2" + SWITCH a+a + CASE 1 + ? "Nested FOUND 1" + EXIT + CASE "22" + ? "Nested FOUND: 22" + EXIT + OTHERWISE + ? "Nested OTHERWISE" + END + ?? "In CASE 1" + ? a + END + + ? "=========================================" + +RETURN \ No newline at end of file