Files
libreoffice/basic/source/comp/dim.cxx

1054 lines
31 KiB
C++
Raw Normal View History

2000-09-18 15:18:56 +00:00
/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: dim.cxx,v $
*
* $Revision: 1.27 $
2000-09-18 15:18:56 +00:00
*
* last change: $Author: hr $ $Date: 2007-06-27 14:20:05 $
2000-09-18 15:18:56 +00:00
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
2000-09-18 15:18:56 +00:00
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
2000-09-18 15:18:56 +00:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
2000-09-18 15:18:56 +00:00
*
* This library 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
* Lesser General Public License for more details.
2000-09-18 15:18:56 +00:00
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
2000-09-18 15:18:56 +00:00
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#include <basic/sbx.hxx>
2000-09-18 15:18:56 +00:00
#include "sbcomp.hxx"
// Deklaration einer Variablen
// Bei Fehlern wird bis zum Komma oder Newline geparst.
// Returnwert: eine neue Instanz, die eingefuegt und dann geloescht wird.
// Array-Indexe werden als SbiDimList zurueckgegeben
SbiSymDef* SbiParser::VarDecl( SbiDimList** ppDim, BOOL bStatic, BOOL bConst )
{
if( !TestSymbol() ) return NULL;
SbxDataType t = eScanType;
SbiSymDef* pDef = bConst ? new SbiConstDef( aSym ) : new SbiSymDef( aSym );
SbiDimList* pDim = NULL;
// Klammern?
if( Peek() == LPAREN )
pDim = new SbiDimList( this );
pDef->SetType( t );
if( bStatic )
pDef->SetStatic();
TypeDecl( *pDef );
if( !ppDim && pDim )
{
if(pDim->GetDims() )
Error( SbERR_EXPECTED, "()" );
delete pDim;
}
else if( ppDim )
*ppDim = pDim;
return pDef;
}
// Aufloesen einer AS-Typdeklaration
// Der Datentyp wird in die uebergebene Variable eingetragen
void SbiParser::TypeDecl( SbiSymDef& rDef, BOOL bAsNewAlreadyParsed )
2000-09-18 15:18:56 +00:00
{
SbxDataType eType = rDef.GetType();
short nSize = 0;
if( bAsNewAlreadyParsed || Peek() == AS )
2000-09-18 15:18:56 +00:00
{
if( !bAsNewAlreadyParsed )
Next();
2000-09-18 15:18:56 +00:00
rDef.SetDefinedAs();
String aType;
SbiToken eTok = Next();
if( !bAsNewAlreadyParsed && eTok == NEW )
2000-09-18 15:18:56 +00:00
{
rDef.SetNew();
eTok = Next();
}
switch( eTok )
{
case ANY:
if( rDef.IsNew() )
Error( SbERR_SYNTAX );
eType = SbxVARIANT; break;
case TINTEGER:
case TLONG:
case TSINGLE:
case TDOUBLE:
case TCURRENCY:
case TDATE:
case TSTRING:
case TOBJECT:
case _ERROR_:
case TBOOLEAN:
case TVARIANT:
case TBYTE:
2000-09-18 15:18:56 +00:00
if( rDef.IsNew() )
Error( SbERR_SYNTAX );
eType = (eTok==TBYTE) ? SbxBYTE : SbxDataType( eTok - TINTEGER + SbxINTEGER );
2000-09-18 15:18:56 +00:00
if( eType == SbxSTRING )
{
// STRING*n ?
if( Peek() == MUL )
{ // fixed size!
Next();
SbiConstExpression aSize( this );
nSize = aSize.GetShortValue();
if( nSize < 0 )
Error( SbERR_OUT_OF_RANGE );
}
}
break;
case SYMBOL: // kann nur ein TYPE oder eine Objektklasse sein!
if( eScanType != SbxVARIANT )
Error( SbERR_SYNTAX );
else
{
String aCompleteName = aSym;
// #52709 DIM AS NEW fuer Uno mit voll-qualifizierten Namen
if( Peek() == DOT )
{
String aDotStr( '.' );
while( Peek() == DOT )
{
aCompleteName += aDotStr;
Next();
SbiToken ePeekTok = Peek();
if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
2000-09-18 15:18:56 +00:00
{
Next();
aCompleteName += aSym;
}
else
{
Next();
Error( SbERR_UNEXPECTED, SYMBOL );
break;
}
}
}
else if( rEnumArray->Find( aCompleteName, SbxCLASS_OBJECT ) )
{
eType = SbxLONG;
break;
}
2000-09-18 15:18:56 +00:00
// In den String-Pool uebernehmen
rDef.SetTypeId( aGblStrings.Add( aCompleteName ) );
}
eType = SbxOBJECT;
break;
case FIXSTRING: // new syntax for complex UNO types
rDef.SetTypeId( aGblStrings.Add( aSym ) );
eType = SbxOBJECT;
break;
2000-09-18 15:18:56 +00:00
default:
Error( SbERR_UNEXPECTED, eTok );
Next();
}
// Die Variable koennte mit Suffix deklariert sein
if( rDef.GetType() != SbxVARIANT )
{
if( rDef.GetType() != eType )
Error( SbERR_VAR_DEFINED, rDef.GetName() );
else if( eType == SbxSTRING && rDef.GetLen() != nSize )
Error( SbERR_VAR_DEFINED, rDef.GetName() );
}
rDef.SetType( eType );
rDef.SetLen( nSize );
}
}
// Hier werden Variable, Arrays und Strukturen definiert.
// DIM/PRIVATE/PUBLIC/GLOBAL
void SbiParser::Dim()
{
DefVar( _DIM, FALSE );
}
void SbiParser::DefVar( SbiOpcode eOp, BOOL bStatic )
{
SbiSymPool* pOldPool = pPool;
BOOL bSwitchPool = FALSE;
BOOL bPersistantGlobal = FALSE;
SbiToken eFirstTok = eCurTok;
2000-09-18 15:18:56 +00:00
if( pProc && ( eCurTok == GLOBAL || eCurTok == PUBLIC || eCurTok == PRIVATE ) )
Error( SbERR_NOT_IN_SUBR, eCurTok );
if( eCurTok == PUBLIC || eCurTok == GLOBAL )
{
2000-09-18 15:18:56 +00:00
bSwitchPool = TRUE; // im richtigen Moment auf globalen Pool schalten
if( eCurTok == GLOBAL )
bPersistantGlobal = TRUE;
}
2000-09-18 15:18:56 +00:00
// PRIVATE ist Synonym fuer DIM
// _CONST_?
BOOL bConst = FALSE;
if( eCurTok == _CONST_ )
bConst = TRUE;
else if( Peek() == _CONST_ )
Next(), bConst = TRUE;
// #110004 It can also be a sub/function
if( !bConst && (eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ||
eCurTok == STATIC || eCurTok == ENUM ) )
{
// Next token is read here, because !bConst
bool bPrivate = ( eFirstTok == PRIVATE );
if( eCurTok == STATIC )
{
Next();
DefStatic( bPrivate );
}
else if( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY )
{
// End global chain if necessary (not done in
// SbiParser::Parse() under these conditions
if( bNewGblDefs && nGblChain == 0 )
{
nGblChain = aGen.Gen( _JUMP, 0 );
bNewGblDefs = FALSE;
}
Next();
DefProc( FALSE, bPrivate );
return;
}
else if( eCurTok == ENUM )
{
Next();
DefEnum( bPrivate );
return;
}
}
2000-09-18 15:18:56 +00:00
#ifdef SHARED
#define tmpSHARED
#undef SHARED
#endif
// SHARED wird ignoriert
if( Peek() == SHARED ) Next();
#ifdef tmpSHARED
#define SHARED
#undef tmpSHARED
#endif
// PRESERVE nur bei REDIM
if( Peek() == PRESERVE )
{
Next();
if( eOp == _REDIM )
eOp = _REDIMP;
else
Error( SbERR_UNEXPECTED, eCurTok );
}
SbiSymDef* pDef;
SbiDimList* pDim;
// AB 9.7.97, #40689, Statics -> Modul-Initialisierung, in Sub ueberspringen
UINT32 nEndOfStaticLbl = 0;
2000-09-18 15:18:56 +00:00
if( bStatic )
{
nEndOfStaticLbl = aGen.Gen( _JUMP, 0 );
aGen.Statement(); // bei static hier nachholen
}
BOOL bDefined = FALSE;
while( ( pDef = VarDecl( &pDim, bStatic, bConst ) ) != NULL )
{
EnableErrors();
// Variable suchen:
if( bSwitchPool )
pPool = &aGlobals;
SbiSymDef* pOld = pPool->Find( pDef->GetName() );
// AB 31.3.1996, #25651#, auch in Runtime-Library suchen
BOOL bRtlSym = FALSE;
if( !pOld )
{
pOld = CheckRTLForSym( pDef->GetName(), SbxVARIANT );
if( pOld )
bRtlSym = TRUE;
}
if( pOld && !(eOp == _REDIM || eOp == _REDIMP) )
{
if( pDef->GetScope() == SbLOCAL && pOld->GetScope() != SbLOCAL )
pOld = NULL;
}
2000-09-18 15:18:56 +00:00
if( pOld )
{
bDefined = TRUE;
// Bei RTL-Symbol immer Fehler
if( !bRtlSym && (eOp == _REDIM || eOp == _REDIMP) )
{
// Bei REDIM die Attribute vergleichen
SbxDataType eDefType;
bool bError_ = false;
if( pOld->IsStatic() )
{
bError_ = true;
}
else if( pOld->GetType() != ( eDefType = pDef->GetType() ) )
{
if( !( eDefType == SbxVARIANT && !pDef->IsDefinedAs() ) )
bError_ = true;
}
if( bError_ )
2000-09-18 15:18:56 +00:00
Error( SbERR_VAR_DEFINED, pDef->GetName() );
}
else
Error( SbERR_VAR_DEFINED, pDef->GetName() );
delete pDef; pDef = pOld;
}
else
pPool->Add( pDef );
// #36374: Variable vor Unterscheidung IsNew() anlegen
// Sonst Error bei Dim Identifier As New Type und option explicit
if( !bDefined && !(eOp == _REDIM || eOp == _REDIMP)
&& ( !bConst || pDef->GetScope() == SbGLOBAL ) )
2000-09-18 15:18:56 +00:00
{
// Variable oder globale Konstante deklarieren
SbiOpcode eOp2;
2000-09-18 15:18:56 +00:00
switch ( pDef->GetScope() )
{
case SbGLOBAL: eOp2 = bPersistantGlobal ? _GLOBAL_P : _GLOBAL;
goto global;
case SbPUBLIC: eOp2 = _PUBLIC;
2000-09-18 15:18:56 +00:00
// AB 9.7.97, #40689, kein eigener Opcode mehr
/*
if( bStatic )
{
eOp2 = _STATIC;
2000-09-18 15:18:56 +00:00
break;
}
*/
global: aGen.BackChain( nGblChain );
nGblChain = 0;
bGblDefs = bNewGblDefs = TRUE;
break;
default: eOp2 = _LOCAL;
2000-09-18 15:18:56 +00:00
}
aGen.Gen(
eOp2, pDef->GetId(),
sal::static_int_cast< UINT16 >( pDef->GetType() ) );
2000-09-18 15:18:56 +00:00
}
// Initialisierung fuer selbstdefinierte Datentypen
// und per NEW angelegte Variable
if( pDef->GetType() == SbxOBJECT
&& pDef->GetTypeId() )
2000-09-18 15:18:56 +00:00
{
if( !bCompatible && !pDef->IsNew() )
{
String aTypeName( aGblStrings.Find( pDef->GetTypeId() ) );
if( rTypeArray->Find( aTypeName, SbxCLASS_OBJECT ) == NULL )
Error( SbERR_UNDEF_TYPE, aTypeName );
}
2000-09-18 15:18:56 +00:00
if( bConst )
{
Error( SbERR_SYNTAX );
}
if( pDim )
{
if( eOp == _REDIMP )
{
SbiExpression aExpr( this, *pDef, NULL );
aExpr.Gen();
aGen.Gen( _REDIMP_ERASE );
pDef->SetDims( pDim->GetDims() );
SbiExpression aExpr2( this, *pDef, pDim );
aExpr2.Gen();
aGen.Gen( _DCREATE_REDIMP, pDef->GetId(), pDef->GetTypeId() );
}
else
{
pDef->SetDims( pDim->GetDims() );
SbiExpression aExpr( this, *pDef, pDim );
aExpr.Gen();
aGen.Gen( _DCREATE, pDef->GetId(), pDef->GetTypeId() );
}
2000-09-18 15:18:56 +00:00
}
else
{
SbiExpression aExpr( this, *pDef );
aExpr.Gen();
SbiOpcode eOp_ = pDef->IsNew() ? _CREATE : _TCREATE;
aGen.Gen( eOp_, pDef->GetId(), pDef->GetTypeId() );
2000-09-18 15:18:56 +00:00
aGen.Gen( _SET );
}
}
else
{
if( bConst )
{
// Konstanten-Definition
if( pDim )
{
Error( SbERR_SYNTAX );
delete pDim;
}
SbiExpression aVar( this, *pDef );
if( !TestToken( EQ ) )
goto MyBreak; // AB 24.6.1996 (s.u.)
SbiConstExpression aExpr( this );
if( !bDefined && aExpr.IsValid() )
{
if( pDef->GetScope() == SbGLOBAL )
{
// Nur Code fuer globale Konstante erzeugen!
aVar.Gen();
aExpr.Gen();
aGen.Gen( _PUTC );
}
SbiConstDef* pConst = pDef->GetConstDef();
if( aExpr.GetType() == SbxSTRING )
pConst->Set( aExpr.GetString() );
else
pConst->Set( aExpr.GetValue(), aExpr.GetType() );
}
}
else if( pDim )
{
// Die Variable dimensionieren
// Bei REDIM die Var vorher loeschen
if( eOp == _REDIM )
{
SbiExpression aExpr( this, *pDef, NULL );
aExpr.Gen();
aGen.Gen( _ERASE );
}
else if( eOp == _REDIMP )
{
SbiExpression aExpr( this, *pDef, NULL );
aExpr.Gen();
aGen.Gen( _REDIMP_ERASE );
}
2000-09-18 15:18:56 +00:00
pDef->SetDims( pDim->GetDims() );
if( bPersistantGlobal )
pDef->SetGlobal( TRUE );
2000-09-18 15:18:56 +00:00
SbiExpression aExpr( this, *pDef, pDim );
aExpr.Gen();
pDef->SetGlobal( FALSE );
2000-09-18 15:18:56 +00:00
aGen.Gen( (eOp == _STATIC) ? _DIM : eOp );
}
}
if( !TestComma() )
goto MyBreak; // AB 24.6.1996 (s.u.)
// #27963# AB, 24.6.1996
// Einfuehrung bSwitchPool (s.o.): pPool darf beim VarDecl-Aufruf
// noch nicht auf &aGlobals gesetzt sein.
// Ansonsten soll das Verhalten aber absolut identisch bleiben,
// d.h. pPool muss immer am Schleifen-Ende zurueckgesetzt werden.
// auch bei break
pPool = pOldPool;
continue; // MyBreak <20>berspingen
MyBreak:
pPool = pOldPool;
break;
}
// AB 9.7.97, #40689, Sprung ueber Statics-Deklaration abschliessen
if( bStatic )
{
// globalen Chain pflegen
nGblChain = aGen.Gen( _JUMP, 0 );
bGblDefs = bNewGblDefs = TRUE;
// fuer Sub Sprung auf Ende der statics eintragen
aGen.BackChain( nEndOfStaticLbl );
}
//pPool = pOldPool;
}
// Hier werden Arrays redimensioniert.
void SbiParser::ReDim()
{
DefVar( _REDIM, FALSE );
}
// ERASE array, ...
void SbiParser::Erase()
{
while( !bAbort )
{
if( !TestSymbol() ) return;
String aName( aSym );
SbxDataType eType = eScanType;
SbiSymDef* pDef = pPool->Find( aName );
if( !pDef )
{
if( bExplicit )
Error( SbERR_UNDEF_VAR, aName );
pDef = pPool->AddSym( aName );
pDef->SetType( eType );
}
SbiExpression aExpr( this, *pDef );
aExpr.Gen();
aGen.Gen( _ERASE );
if( !TestComma() ) break;
}
}
// Deklaration eines Datentyps
void SbiParser::Type()
{
DefType( FALSE );
}
void SbiParser::DefType( BOOL bPrivate )
{
// TODO: Use bPrivate
(void)bPrivate;
2000-09-18 15:18:56 +00:00
// Neues Token lesen, es muss ein Symbol sein
if (!TestSymbol())
return;
if (rTypeArray->Find(aSym,SbxCLASS_OBJECT))
{
Error( SbERR_VAR_DEFINED, aSym );
return;
}
SbxObject *pType = new SbxObject(aSym);
SbiSymDef* pElem;
SbiDimList* pDim;
BOOL bDone = FALSE;
while( !bDone && !IsEof() )
{
switch( Peek() )
2000-09-18 15:18:56 +00:00
{
case ENDTYPE :
pElem = NULL;
bDone = TRUE;
Next();
2000-09-18 15:18:56 +00:00
break;
case EOLN :
case REM :
2000-09-18 15:18:56 +00:00
pElem = NULL;
Next();
2000-09-18 15:18:56 +00:00
break;
default:
pDim = NULL;
pElem = VarDecl(&pDim,FALSE,FALSE);
if( !pElem )
bDone = TRUE; // Error occured
2000-09-18 15:18:56 +00:00
if( pDim )
{
// HOT FIX, to be updated
delete pDim;
Error( SbERR_NO_STRINGS_ARRAYS );
}
}
if( pElem )
{
SbxArray *pTypeMembers = pType -> GetProperties();
if (pTypeMembers -> Find (pElem->GetName(),SbxCLASS_DONTCARE))
Error (SbERR_VAR_DEFINED);
else
{
SbxProperty *pTypeElem = new SbxProperty (pElem->GetName(),pElem->GetType());
pTypeMembers->Insert( pTypeElem, pTypeMembers->Count() );
2000-09-18 15:18:56 +00:00
}
delete pElem;
}
}
pType->Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Name") ), SbxCLASS_DONTCARE );
pType->Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Parent") ), SbxCLASS_DONTCARE );
2000-09-18 15:18:56 +00:00
rTypeArray->Insert (pType,rTypeArray->Count());
}
// Declaration of Enum type
void SbiParser::Enum()
{
DefEnum( FALSE );
}
void SbiParser::DefEnum( BOOL bPrivate )
{
// Neues Token lesen, es muss ein Symbol sein
if (!TestSymbol())
return;
String aEnumName = aSym;
if( rEnumArray->Find(aEnumName,SbxCLASS_OBJECT) )
2000-09-18 15:18:56 +00:00
{
Error( SbERR_VAR_DEFINED, aSym );
return;
2000-09-18 15:18:56 +00:00
}
SbxObject *pEnum = new SbxObject( aEnumName );
if( bPrivate )
pEnum->SetFlag( SBX_PRIVATE );
2000-09-18 15:18:56 +00:00
SbiSymDef* pElem;
SbiDimList* pDim;
BOOL bDone = FALSE;
// Starting with -1 to make first default value 0 after ++
sal_Int32 nCurrentEnumValue = -1;
while( !bDone && !IsEof() )
2000-09-18 15:18:56 +00:00
{
switch( Peek() )
2000-09-18 15:18:56 +00:00
{
case ENDENUM :
2000-09-18 15:18:56 +00:00
pElem = NULL;
bDone = TRUE;
Next();
break;
case EOLN :
case REM :
pElem = NULL;
Next();
break;
2000-09-18 15:18:56 +00:00
default:
{
// TODO: Check existing!
BOOL bDefined = FALSE;
pDim = NULL;
pElem = VarDecl( &pDim, FALSE, TRUE );
if( !pElem )
{
bDone = TRUE; // Error occured
break;
}
else if( pDim )
2000-09-18 15:18:56 +00:00
{
delete pDim;
Error( SbERR_SYNTAX );
bDone = TRUE; // Error occured
break;
2000-09-18 15:18:56 +00:00
}
SbiExpression aVar( this, *pElem );
if( Peek() == EQ )
{
Next();
SbiConstExpression aExpr( this );
if( !bDefined && aExpr.IsValid() )
{
SbxVariableRef xConvertVar = new SbxVariable();
if( aExpr.GetType() == SbxSTRING )
xConvertVar->PutString( aExpr.GetString() );
else
xConvertVar->PutDouble( aExpr.GetValue() );
nCurrentEnumValue = xConvertVar->GetLong();
}
}
else
nCurrentEnumValue++;
SbiSymPool* pPoolToUse = bPrivate ? pPool : &aGlobals;
SbiSymDef* pOld = pPoolToUse->Find( pElem->GetName() );
if( pOld )
{
Error( SbERR_VAR_DEFINED, pElem->GetName() );
bDone = TRUE; // Error occured
break;
}
pPool->Add( pElem );
if( !bPrivate )
{
SbiOpcode eOp = _GLOBAL;
aGen.BackChain( nGblChain );
nGblChain = 0;
bGblDefs = bNewGblDefs = TRUE;
aGen.Gen(
eOp, pElem->GetId(),
sal::static_int_cast< UINT16 >( pElem->GetType() ) );
aVar.Gen();
USHORT nStringId = aGen.GetParser()->aGblStrings.Add( nCurrentEnumValue, SbxLONG );
aGen.Gen( _NUMBER, nStringId );
aGen.Gen( _PUTC );
}
SbiConstDef* pConst = pElem->GetConstDef();
pConst->Set( nCurrentEnumValue, SbxLONG );
}
2000-09-18 15:18:56 +00:00
}
if( pElem )
{
SbxArray *pEnumMembers = pEnum->GetProperties();
SbxProperty *pEnumElem = new SbxProperty( pElem->GetName(), SbxLONG );
pEnumElem->PutLong( nCurrentEnumValue );
pEnumElem->ResetFlag( SBX_WRITE );
pEnumElem->SetFlag( SBX_CONST );
pEnumMembers->Insert( pEnumElem, pEnumMembers->Count() );
}
2000-09-18 15:18:56 +00:00
}
pEnum->Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Name") ), SbxCLASS_DONTCARE );
pEnum->Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Parent") ), SbxCLASS_DONTCARE );
rEnumArray->Insert( pEnum, rEnumArray->Count() );
2000-09-18 15:18:56 +00:00
}
2000-09-18 15:18:56 +00:00
// Prozedur-Deklaration
// das erste Token ist bereits eingelesen (SUB/FUNCTION)
// xxx Name [LIB "name"[ALIAS "name"]][(Parameter)][AS TYPE]
SbiProcDef* SbiParser::ProcDecl( BOOL bDecl )
{
BOOL bFunc = BOOL( eCurTok == FUNCTION );
if( !TestSymbol() ) return NULL;
String aName( aSym );
SbxDataType eType = eScanType;
SbiProcDef* pDef = new SbiProcDef( this, aName, true );
2000-09-18 15:18:56 +00:00
pDef->SetType( eType );
if( Peek() == _CDECL_ )
{
Next(); pDef->SetCdecl();
}
if( Peek() == LIB )
{
Next();
if( Next() == FIXSTRING )
pDef->GetLib() = aSym;
else
Error( SbERR_SYNTAX );
}
if( Peek() == ALIAS )
{
Next();
if( Next() == FIXSTRING )
pDef->GetAlias() = aSym;
else
Error( SbERR_SYNTAX );
}
if( !bDecl )
{
// CDECL, LIB und ALIAS sind unzulaessig
if( pDef->GetLib().Len() )
Error( SbERR_UNEXPECTED, LIB );
if( pDef->GetAlias().Len() )
Error( SbERR_UNEXPECTED, ALIAS );
if( pDef->IsCdecl() )
Error( SbERR_UNEXPECTED, _CDECL_ );
pDef->SetCdecl( FALSE );
pDef->GetLib().Erase();
pDef->GetAlias().Erase();
}
else if( !pDef->GetLib().Len() )
{
// ALIAS und CDECL nur zusammen mit LIB
if( pDef->GetAlias().Len() )
Error( SbERR_UNEXPECTED, ALIAS );
if( pDef->IsCdecl() )
Error( SbERR_UNEXPECTED, _CDECL_ );
pDef->SetCdecl( FALSE );
pDef->GetAlias().Erase();
}
// Klammern?
if( Peek() == LPAREN )
{
Next();
if( Peek() == RPAREN )
Next();
else
for(;;) {
BOOL bByVal = FALSE;
BOOL bOptional = FALSE;
BOOL bParamArray = FALSE;
while( Peek() == BYVAL || Peek() == BYREF || Peek() == _OPTIONAL_ )
2000-09-18 15:18:56 +00:00
{
if ( Peek() == BYVAL ) Next(), bByVal = TRUE;
else if ( Peek() == BYREF ) Next(), bByVal = FALSE;
2000-09-18 15:18:56 +00:00
else if ( Peek() == _OPTIONAL_ ) Next(), bOptional = TRUE;
}
if( bCompatible && Peek() == PARAMARRAY )
{
if( bByVal || bByVal || bOptional )
Error( SbERR_UNEXPECTED, PARAMARRAY );
Next();
bParamArray = TRUE;
}
2000-09-18 15:18:56 +00:00
SbiSymDef* pPar = VarDecl( NULL, FALSE, FALSE );
if( !pPar )
break;
if( bByVal )
pPar->SetByVal();
if( bOptional )
pPar->SetOptional();
if( bParamArray )
pPar->SetParamArray();
2000-09-18 15:18:56 +00:00
pDef->GetParams().Add( pPar );
SbiToken eTok = Next();
if( eTok != COMMA && eTok != RPAREN )
{
BOOL bError2 = TRUE;
if( bOptional && bCompatible && eTok == EQ )
{
SbiConstExpression* pDefaultExpr = new SbiConstExpression( this );
SbxDataType eType2 = pDefaultExpr->GetType();
USHORT nStringId;
if( eType2 == SbxSTRING )
nStringId = aGblStrings.Add( pDefaultExpr->GetString() );
else
nStringId = aGblStrings.Add( pDefaultExpr->GetValue(), eType2 );
pPar->SetDefaultId( nStringId );
delete pDefaultExpr;
eTok = Next();
if( eTok == COMMA || eTok == RPAREN )
bError2 = FALSE;
}
if( bError2 )
{
Error( SbERR_EXPECTED, RPAREN );
break;
}
2000-09-18 15:18:56 +00:00
}
if( eTok == RPAREN )
break;
}
}
TypeDecl( *pDef );
if( eType != SbxVARIANT && pDef->GetType() != eType )
Error( SbERR_BAD_DECLARATION, aName );
// if( pDef->GetType() == SbxOBJECT )
// pDef->SetType( SbxVARIANT ),
// Error( SbERR_SYNTAX );
if( pDef->GetType() == SbxVARIANT && !bFunc )
pDef->SetType( SbxEMPTY );
return pDef;
}
// DECLARE
void SbiParser::Declare()
{
Next();
if( eCurTok != SUB && eCurTok != FUNCTION )
Error( SbERR_UNEXPECTED, eCurTok );
else
{
SbiProcDef* pDef = ProcDecl( TRUE );
if( pDef )
{
if( !pDef->GetLib().Len() )
Error( SbERR_EXPECTED, LIB );
// gibts den schon?
SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
if( pOld )
{
SbiProcDef* p = pOld->GetProcDef();
if( !p )
{
// Als Variable deklariert
Error( SbERR_BAD_DECLARATION, pDef->GetName() );
delete pDef;
}
else
pDef->Match( p );
}
else
aPublics.Add( pDef );
}
}
}
// Aufruf einer SUB oder FUNCTION
void SbiParser::Call()
{
String aName( aSym );
SbiExpression aVar( this, SbSYMBOL );
aVar.Gen( FORCE_CALL );
2000-09-18 15:18:56 +00:00
aGen.Gen( _GET );
}
// SUB/FUNCTION
void SbiParser::SubFunc()
{
DefProc( FALSE, FALSE );
2000-09-18 15:18:56 +00:00
}
// Einlesen einer Prozedur
BOOL runsInSetup( void );
void SbiParser::DefProc( BOOL bStatic, BOOL bPrivate )
2000-09-18 15:18:56 +00:00
{
USHORT l1 = nLine, l2 = nLine;
BOOL bSub = BOOL( eCurTok == SUB );
BOOL bProperty = BOOL( eCurTok == PROPERTY );
PropertyMode ePropertyMode = PROPERTY_MODE_NONE;
if( bProperty )
{
Next();
if( eCurTok == GET )
ePropertyMode = PROPERTY_MODE_GET;
else if( eCurTok == LET )
ePropertyMode = PROPERTY_MODE_LET;
else if( eCurTok == SET )
ePropertyMode = PROPERTY_MODE_SET;
else
Error( SbERR_EXPECTED, "Get or Let or Set" );
}
2000-09-18 15:18:56 +00:00
SbiToken eExit = eCurTok;
SbiProcDef* pDef = ProcDecl( FALSE );
if( !pDef )
return;
pDef->setPropertyMode( ePropertyMode );
2000-09-18 15:18:56 +00:00
// Ist die Proc bereits deklariert?
SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
if( pOld )
{
bool bError_ = false;
2000-09-18 15:18:56 +00:00
pProc = pOld->GetProcDef();
if( !pProc )
{
// Als Variable deklariert
Error( SbERR_BAD_DECLARATION, pDef->GetName() );
delete pDef;
pProc = NULL;
bError_ = true;
2000-09-18 15:18:56 +00:00
}
// #100027: Multiple declaration -> Error
// #112787: Not for setup, REMOVE for 8
else if( !runsInSetup() && pProc->IsUsedForProcDecl() )
{
PropertyMode ePropMode = pDef->getPropertyMode();
if( ePropMode == PROPERTY_MODE_NONE || ePropMode == pProc->getPropertyMode() )
{
Error( SbERR_PROC_DEFINED, pDef->GetName() );
delete pDef;
pProc = NULL;
bError_ = true;
}
}
if( !bError_ )
2000-09-18 15:18:56 +00:00
{
pDef->Match( pProc );
pProc = pDef;
}
}
else
aPublics.Add( pDef ), pProc = pDef;
if( !pProc )
return;
pProc->SetPublic( !bPrivate );
2000-09-18 15:18:56 +00:00
// Nun setzen wir die Suchhierarchie fuer Symbole sowie die aktuelle
// Prozedur.
aPublics.SetProcId( pProc->GetId() );
pProc->GetParams().SetParent( &aPublics );
if( !bStatic )
{
// Normalfall: Lokale Variable->Parameter->Globale Variable
pProc->GetLocals().SetParent( &pProc->GetParams() );
pPool = &pProc->GetLocals();
}
else
{
Error( SbERR_NOT_IMPLEMENTED ); // STATIC SUB ...
}
pProc->Define();
OpenBlock( eExit );
StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) );
2000-09-18 15:18:56 +00:00
l2 = nLine;
pProc->SetLine1( l1 );
pProc->SetLine2( l2 );
pPool = &aPublics;
aPublics.SetProcId( 0 );
// Offene Labels?
pProc->GetLabels().CheckRefs();
CloseBlock();
aGen.Gen( _LEAVE );
pProc = NULL;
}
// STATIC variable|procedure
void SbiParser::Static()
{
DefStatic( FALSE );
}
void SbiParser::DefStatic( BOOL bPrivate )
2000-09-18 15:18:56 +00:00
{
switch( Peek() )
{
case SUB:
case FUNCTION:
case PROPERTY:
// End global chain if necessary (not done in
// SbiParser::Parse() under these conditions
if( bNewGblDefs && nGblChain == 0 )
{
nGblChain = aGen.Gen( _JUMP, 0 );
bNewGblDefs = FALSE;
}
2000-09-18 15:18:56 +00:00
Next();
DefProc( TRUE, bPrivate );
2000-09-18 15:18:56 +00:00
break;
default: {
if( !pProc )
Error( SbERR_NOT_IN_SUBR );
// Pool umsetzen, damit STATIC-Deklarationen im globalen
// Pool landen
SbiSymPool* p = pPool; pPool = &aPublics;
DefVar( _STATIC, TRUE );
pPool = p;
} break;
}
}