summaryrefslogtreecommitdiff
path: root/basic/source/comp
diff options
context:
space:
mode:
Diffstat (limited to 'basic/source/comp')
-rw-r--r--basic/source/comp/buffer.cxx250
-rw-r--r--basic/source/comp/codegen.cxx539
-rw-r--r--basic/source/comp/dim.cxx1203
-rw-r--r--basic/source/comp/exprgen.cxx270
-rw-r--r--basic/source/comp/exprnode.cxx488
-rw-r--r--basic/source/comp/exprtree.cxx1136
-rw-r--r--basic/source/comp/io.cxx358
-rw-r--r--basic/source/comp/loops.cxx558
-rw-r--r--basic/source/comp/makefile.mk60
-rw-r--r--basic/source/comp/parser.cxx863
-rwxr-xr-xbasic/source/comp/sbcomp.cxx477
-rw-r--r--basic/source/comp/scanner.cxx582
-rw-r--r--basic/source/comp/symtbl.cxx536
-rw-r--r--basic/source/comp/token.cxx714
14 files changed, 8034 insertions, 0 deletions
diff --git a/basic/source/comp/buffer.cxx b/basic/source/comp/buffer.cxx
new file mode 100644
index 000000000000..74559bf0e6c4
--- /dev/null
+++ b/basic/source/comp/buffer.cxx
@@ -0,0 +1,250 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include "sbcomp.hxx"
+#include "buffer.hxx"
+#include <string.h>
+
+const static UINT32 UP_LIMIT=0xFFFFFF00L;
+
+// Der SbiBuffer wird in Inkrements von mindestens 16 Bytes erweitert.
+// Dies ist notwendig, da viele Klassen von einer Pufferlaenge
+// von x*16 Bytes ausgehen.
+
+SbiBuffer::SbiBuffer( SbiParser* p, short n )
+{
+ pParser = p;
+ n = ( (n + 15 ) / 16 ) * 16;
+ if( !n ) n = 16;
+ pBuf = NULL;
+ pCur = NULL;
+ nInc = n;
+ nSize =
+ nOff = 0;
+}
+
+SbiBuffer::~SbiBuffer()
+{
+ delete[] pBuf;
+}
+
+// Rausreichen des Puffers
+// Dies fuehrt zur Loeschung des Puffers!
+
+char* SbiBuffer::GetBuffer()
+{
+ char* p = pBuf;
+ pBuf = NULL;
+ pCur = NULL;
+ return p;
+}
+
+// Test, ob der Puffer n Bytes aufnehmen kann.
+// Im Zweifelsfall wird er vergroessert
+
+BOOL SbiBuffer::Check( USHORT n )
+{
+ if( !n ) return TRUE;
+ if( ( static_cast<UINT32>( nOff )+ n ) > static_cast<UINT32>( nSize ) )
+ {
+ if( nInc == 0 )
+ return FALSE;
+ USHORT nn = 0;
+ while( nn < n ) nn = nn + nInc;
+ char* p;
+ if( ( static_cast<UINT32>( nSize ) + nn ) > UP_LIMIT ) p = NULL;
+ else p = new char [nSize + nn];
+ if( !p )
+ {
+ pParser->Error( SbERR_PROG_TOO_LARGE );
+ nInc = 0;
+ delete[] pBuf; pBuf = NULL;
+ return FALSE;
+ }
+ else
+ {
+ if( nSize ) memcpy( p, pBuf, nSize );
+ delete[] pBuf;
+ pBuf = p;
+ pCur = pBuf + nOff;
+ nSize = nSize + nn;
+ }
+ }
+ return TRUE;
+}
+
+// Angleich des Puffers auf die uebergebene Byte-Grenze
+
+void SbiBuffer::Align( INT32 n )
+{
+ if( nOff % n ) {
+ UINT32 nn =( ( nOff + n ) / n ) * n;
+ if( nn <= UP_LIMIT )
+ {
+ nn = nn - nOff;
+ if( Check( static_cast<USHORT>(nn) ) )
+ {
+ memset( pCur, 0, nn );
+ pCur += nn;
+ nOff = nOff + nn;
+ }
+ }
+ }
+}
+
+// Patch einer Location
+
+void SbiBuffer::Patch( UINT32 off, UINT32 val )
+{
+ if( ( off + sizeof( UINT32 ) ) < nOff )
+ {
+ UINT16 val1 = static_cast<UINT16>( val & 0xFFFF );
+ UINT16 val2 = static_cast<UINT16>( val >> 16 );
+ BYTE* p = (BYTE*) pBuf + off;
+ *p++ = (char) ( val1 & 0xFF );
+ *p++ = (char) ( val1 >> 8 );
+ *p++ = (char) ( val2 & 0xFF );
+ *p = (char) ( val2 >> 8 );
+ }
+}
+
+// Forward References auf Labels und Prozeduren
+// bauen eine Kette auf. Der Anfang der Kette ist beim uebergebenen
+// Parameter, das Ende der Kette ist 0.
+
+void SbiBuffer::Chain( UINT32 off )
+{
+ if( off && pBuf )
+ {
+ BYTE *ip;
+ UINT32 i = off;
+ UINT32 val1 = (nOff & 0xFFFF);
+ UINT32 val2 = (nOff >> 16);
+ do
+ {
+ ip = (BYTE*) pBuf + i;
+ BYTE* pTmp = ip;
+ i = *pTmp++; i |= *pTmp++ << 8; i |= *pTmp++ << 16; i |= *pTmp++ << 24;
+
+ if( i >= nOff )
+ {
+ pParser->Error( SbERR_INTERNAL_ERROR, "BACKCHAIN" );
+ break;
+ }
+ *ip++ = (char) ( val1 & 0xFF );
+ *ip++ = (char) ( val1 >> 8 );
+ *ip++ = (char) ( val2 & 0xFF );
+ *ip = (char) ( val2 >> 8 );
+ } while( i );
+ }
+}
+
+BOOL SbiBuffer::operator +=( INT8 n )
+{
+ if( Check( 1 ) )
+ {
+ *pCur++ = (char) n; nOff++; return TRUE;
+ } else return FALSE;
+}
+
+BOOL SbiBuffer::operator +=( UINT8 n )
+{
+ if( Check( 1 ) )
+ {
+ *pCur++ = (char) n; nOff++; return TRUE;
+ } else return FALSE;
+}
+
+BOOL SbiBuffer::operator +=( INT16 n )
+{
+ if( Check( 2 ) )
+ {
+ *pCur++ = (char) ( n & 0xFF );
+ *pCur++ = (char) ( n >> 8 );
+ nOff += 2; return TRUE;
+ } else return FALSE;
+}
+
+BOOL SbiBuffer::operator +=( UINT16 n )
+{
+ if( Check( 2 ) )
+ {
+ *pCur++ = (char) ( n & 0xFF );
+ *pCur++ = (char) ( n >> 8 );
+ nOff += 2; return TRUE;
+ } else return FALSE;
+}
+
+BOOL SbiBuffer::operator +=( UINT32 n )
+{
+ if( Check( 4 ) )
+ {
+ UINT16 n1 = static_cast<UINT16>( n & 0xFFFF );
+ UINT16 n2 = static_cast<UINT16>( n >> 16 );
+ if ( operator +=( n1 ) && operator +=( n2 ) )
+ return TRUE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL SbiBuffer::operator +=( INT32 n )
+{
+ return operator +=( (UINT32) n );
+}
+
+
+BOOL SbiBuffer::operator +=( const String& n )
+{
+ USHORT l = n.Len() + 1;
+ if( Check( l ) )
+ {
+ ByteString aByteStr( n, gsl_getSystemTextEncoding() );
+ memcpy( pCur, aByteStr.GetBuffer(), l );
+ pCur += l;
+ nOff = nOff + l;
+ return TRUE;
+ }
+ else return FALSE;
+}
+
+BOOL SbiBuffer::Add( const void* p, USHORT len )
+{
+ if( Check( len ) )
+ {
+ memcpy( pCur, p, len );
+ pCur += len;
+ nOff = nOff + len;
+ return TRUE;
+ } else return FALSE;
+}
+
+
+
diff --git a/basic/source/comp/codegen.cxx b/basic/source/comp/codegen.cxx
new file mode 100644
index 000000000000..93fb18baf86e
--- /dev/null
+++ b/basic/source/comp/codegen.cxx
@@ -0,0 +1,539 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include <basic/sbx.hxx>
+#include "sbcomp.hxx"
+#include "image.hxx"
+#include <limits>
+#include <com/sun/star/script/ModuleType.hpp>
+
+// nInc ist die Inkrementgroesse der Puffer
+
+SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
+ : rMod( r ), aCode( p, nInc )
+{
+ pParser = p;
+ bStmnt = FALSE;
+ nLine = 0;
+ nCol = 0;
+ nForLevel = 0;
+}
+
+UINT32 SbiCodeGen::GetPC()
+{
+ return aCode.GetSize();
+}
+
+// Statement merken
+
+void SbiCodeGen::Statement()
+{
+ bStmnt = TRUE;
+
+ nLine = pParser->GetLine();
+ nCol = pParser->GetCol1();
+
+ // #29955 Information der for-Schleifen-Ebene
+ // in oberen Byte der Spalte speichern
+ nCol = (nCol & 0xff) + 0x100 * nForLevel;
+}
+
+// Anfang eines Statements markieren
+
+void SbiCodeGen::GenStmnt()
+{
+ if( bStmnt )
+ {
+ bStmnt = FALSE;
+ Gen( _STMNT, nLine, nCol );
+ }
+}
+
+// Die Gen-Routinen returnen den Offset des 1. Operanden,
+// damit Jumps dort ihr Backchain versenken koennen
+
+UINT32 SbiCodeGen::Gen( SbiOpcode eOpcode )
+{
+#ifdef DBG_UTIL
+ if( eOpcode < SbOP0_START || eOpcode > SbOP0_END )
+ pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE1" );
+#endif
+ GenStmnt();
+ aCode += (UINT8) eOpcode;
+ return GetPC();
+}
+
+UINT32 SbiCodeGen::Gen( SbiOpcode eOpcode, UINT32 nOpnd )
+{
+#ifdef DBG_UTIL
+ if( eOpcode < SbOP1_START || eOpcode > SbOP1_END )
+ pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE2" );
+#endif
+ GenStmnt();
+ aCode += (UINT8) eOpcode;
+ UINT32 n = GetPC();
+ aCode += nOpnd;
+ return n;
+}
+
+UINT32 SbiCodeGen::Gen( SbiOpcode eOpcode, UINT32 nOpnd1, UINT32 nOpnd2 )
+{
+#ifdef DBG_UTIL
+ if( eOpcode < SbOP2_START || eOpcode > SbOP2_END )
+ pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE3" );
+#endif
+ GenStmnt();
+ aCode += (UINT8) eOpcode;
+ UINT32 n = GetPC();
+ aCode += nOpnd1;
+ aCode += nOpnd2;
+ return n;
+}
+
+// Abspeichern des erzeugten Images im Modul
+
+void SbiCodeGen::Save()
+{
+ SbiImage* p = new SbiImage;
+ rMod.StartDefinitions();
+ // OPTION BASE-Wert:
+ p->nDimBase = pParser->nBase;
+ // OPTION EXPLICIT-Flag uebernehmen
+ if( pParser->bExplicit )
+ p->SetFlag( SBIMG_EXPLICIT );
+
+ int nIfaceCount = 0;
+ if( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
+ {
+ OSL_TRACE("COdeGen::save() classmodule processing");
+ rMod.bIsProxyModule = true;
+ p->SetFlag( SBIMG_CLASSMODULE );
+ pCLASSFAC->AddClassModule( &rMod );
+
+ nIfaceCount = pParser->aIfaceVector.size();
+ if( !rMod.pClassData )
+ rMod.pClassData = new SbClassData;
+ if( nIfaceCount )
+ {
+ for( int i = 0 ; i < nIfaceCount ; i++ )
+ {
+ const String& rIfaceName = pParser->aIfaceVector[i];
+ SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT );
+ pIfaceVar->SetName( rIfaceName );
+ SbxArray* pIfaces = rMod.pClassData->mxIfaces;
+ pIfaces->Insert( pIfaceVar, pIfaces->Count() );
+ }
+ }
+
+ rMod.pClassData->maRequiredTypes = pParser->aRequiredTypes;
+ }
+ else
+ {
+ pCLASSFAC->RemoveClassModule( &rMod );
+ // Only a ClassModule can revert to Normal
+ if ( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
+ rMod.mnType = com::sun::star::script::ModuleType::NORMAL;
+ rMod.bIsProxyModule = false;
+ }
+
+ if( pParser->bText )
+ p->SetFlag( SBIMG_COMPARETEXT );
+ // GlobalCode-Flag
+ if( pParser->HasGlobalCode() )
+ p->SetFlag( SBIMG_INITCODE );
+ // Die Entrypoints:
+ for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
+ pDef = pParser->aPublics.Next() )
+ {
+ SbiProcDef* pProc = pDef->GetProcDef();
+ if( pProc && pProc->IsDefined() )
+ {
+ String aProcName = pProc->GetName();
+ String aIfaceProcName;
+ String aIfaceName;
+ USHORT nPassCount = 1;
+ if( nIfaceCount )
+ {
+ int nPropPrefixFound =
+ aProcName.Search( String( RTL_CONSTASCII_USTRINGPARAM("Property ") ) );
+ String aPureProcName = aProcName;
+ String aPropPrefix;
+ if( nPropPrefixFound == 0 )
+ {
+ aPropPrefix = aProcName.Copy( 0, 13 ); // 13 == Len( "Property ?et " )
+ aPureProcName = aProcName.Copy( 13 );
+ }
+ for( int i = 0 ; i < nIfaceCount ; i++ )
+ {
+ const String& rIfaceName = pParser->aIfaceVector[i];
+ int nFound = aPureProcName.Search( rIfaceName );
+ if( nFound == 0 && '_' == aPureProcName.GetChar( rIfaceName.Len() ) )
+ {
+ if( nPropPrefixFound == 0 )
+ aIfaceProcName += aPropPrefix;
+ aIfaceProcName += aPureProcName.Copy( rIfaceName.Len() + 1 );
+ aIfaceName = rIfaceName;
+ nPassCount = 2;
+ break;
+ }
+ }
+ }
+ SbMethod* pMeth = NULL;
+ for( USHORT nPass = 0 ; nPass < nPassCount ; nPass++ )
+ {
+ if( nPass == 1 )
+ aProcName = aIfaceProcName;
+
+ PropertyMode ePropMode = pProc->getPropertyMode();
+ if( ePropMode != PROPERTY_MODE_NONE )
+ {
+ SbxDataType ePropType = SbxEMPTY;
+ switch( ePropMode )
+ {
+ case PROPERTY_MODE_GET:
+ ePropType = pProc->GetType();
+ break;
+ case PROPERTY_MODE_LET:
+ {
+ // type == type of first parameter
+ ePropType = SbxVARIANT; // Default
+ SbiSymPool* pPool = &pProc->GetParams();
+ if( pPool->GetSize() > 1 )
+ {
+ SbiSymDef* pPar = pPool->Get( 1 );
+ if( pPar )
+ ePropType = pPar->GetType();
+ }
+ break;
+ }
+ case PROPERTY_MODE_SET:
+ ePropType = SbxOBJECT;
+ break;
+ case PROPERTY_MODE_NONE:
+ DBG_ERROR( "Illegal PropertyMode PROPERTY_MODE_NONE" );
+ break;
+ }
+ String aPropName = pProc->GetPropName();
+ if( nPass == 1 )
+ aPropName = aPropName.Copy( aIfaceName.Len() + 1 );
+ SbProcedureProperty* pProcedureProperty = NULL;
+ pProcedureProperty = rMod.GetProcedureProperty( aPropName, ePropType );
+ }
+ if( nPass == 1 )
+ {
+ SbIfaceMapperMethod* pMapperMeth = NULL;
+ pMapperMeth = rMod.GetIfaceMapperMethod( aProcName, pMeth );
+ }
+ else
+ {
+ pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
+
+ // #110004
+ if( !pProc->IsPublic() )
+ pMeth->SetFlag( SBX_PRIVATE );
+
+ // Declare? -> Hidden
+ if( pProc->GetLib().Len() > 0 )
+ pMeth->SetFlag( SBX_HIDDEN );
+
+ pMeth->nStart = pProc->GetAddr();
+ pMeth->nLine1 = pProc->GetLine1();
+ pMeth->nLine2 = pProc->GetLine2();
+ // Die Parameter:
+ SbxInfo* pInfo = pMeth->GetInfo();
+ String aHelpFile, aComment;
+ ULONG nHelpId = 0;
+ if( pInfo )
+ {
+ // Die Zusatzdaten retten
+ aHelpFile = pInfo->GetHelpFile();
+ aComment = pInfo->GetComment();
+ nHelpId = pInfo->GetHelpId();
+ }
+ // Und die Parameterliste neu aufbauen
+ pInfo = new SbxInfo( aHelpFile, nHelpId );
+ pInfo->SetComment( aComment );
+ SbiSymPool* pPool = &pProc->GetParams();
+ // Das erste Element ist immer der Funktionswert!
+ for( USHORT i = 1; i < pPool->GetSize(); i++ )
+ {
+ SbiSymDef* pPar = pPool->Get( i );
+ SbxDataType t = pPar->GetType();
+ if( !pPar->IsByVal() )
+ t = (SbxDataType) ( t | SbxBYREF );
+ if( pPar->GetDims() )
+ t = (SbxDataType) ( t | SbxARRAY );
+ // #33677 Optional-Info durchreichen
+ USHORT nFlags = SBX_READ;
+ if( pPar->IsOptional() )
+ nFlags |= SBX_OPTIONAL;
+
+ pInfo->AddParam( pPar->GetName(), t, nFlags );
+
+ UINT32 nUserData = 0;
+ USHORT nDefaultId = pPar->GetDefaultId();
+ if( nDefaultId )
+ nUserData |= nDefaultId;
+ if( pPar->IsParamArray() )
+ nUserData |= PARAM_INFO_PARAMARRAY;
+ if( nUserData )
+ {
+ SbxParamInfo* pParam = (SbxParamInfo*)pInfo->GetParam( i );
+ pParam->nUserData = nUserData;
+ }
+ }
+ pMeth->SetInfo( pInfo );
+ }
+
+ } // for( iPass...
+ }
+ }
+ // Der Code
+ p->AddCode( aCode.GetBuffer(), aCode.GetSize() );
+
+ // Der globale StringPool. 0 ist nicht belegt.
+ SbiStringPool* pPool = &pParser->aGblStrings;
+ USHORT nSize = pPool->GetSize();
+ p->MakeStrings( nSize );
+ USHORT i;
+ for( i = 1; i <= nSize; i++ )
+ p->AddString( pPool->Find( i ) );
+
+ // Typen einfuegen
+ USHORT nCount = pParser->rTypeArray->Count();
+ for (i = 0; i < nCount; i++)
+ p->AddType((SbxObject *)pParser->rTypeArray->Get(i));
+
+ // Insert enum objects
+ nCount = pParser->rEnumArray->Count();
+ for (i = 0; i < nCount; i++)
+ p->AddEnum((SbxObject *)pParser->rEnumArray->Get(i));
+
+ if( !p->IsError() )
+ rMod.pImage = p;
+ else
+ delete p;
+
+ rMod.EndDefinitions();
+}
+
+template < class T >
+class PCodeVisitor
+{
+public:
+ virtual ~PCodeVisitor();
+
+ virtual void start( BYTE* pStart ) = 0;
+ virtual void processOpCode0( SbiOpcode eOp ) = 0;
+ virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
+ virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
+ virtual bool processParams() = 0;
+ virtual void end() = 0;
+};
+
+template <class T> PCodeVisitor< T >::~PCodeVisitor()
+{}
+
+template <class T>
+class PCodeBufferWalker
+{
+private:
+ T m_nBytes;
+ BYTE* m_pCode;
+ T readParam( BYTE*& pCode )
+ {
+ short nBytes = sizeof( T );
+ T nOp1=0;
+ for ( int i=0; i<nBytes; ++i )
+ nOp1 |= *pCode++ << ( i * 8);
+ return nOp1;
+ }
+public:
+ PCodeBufferWalker( BYTE* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
+ {
+ }
+ void visitBuffer( PCodeVisitor< T >& visitor )
+ {
+ BYTE* pCode = m_pCode;
+ if ( !pCode )
+ return;
+ BYTE* pEnd = pCode + m_nBytes;
+ visitor.start( m_pCode );
+ T nOp1 = 0, nOp2 = 0;
+ for( ; pCode < pEnd; )
+ {
+ SbiOpcode eOp = (SbiOpcode)(*pCode++);
+
+ if ( eOp <= SbOP0_END )
+ visitor.processOpCode0( eOp );
+ else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
+ {
+ if ( visitor.processParams() )
+ nOp1 = readParam( pCode );
+ else
+ pCode += sizeof( T );
+ visitor.processOpCode1( eOp, nOp1 );
+ }
+ else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
+ {
+ if ( visitor.processParams() )
+ {
+ nOp1 = readParam( pCode );
+ nOp2 = readParam( pCode );
+ }
+ else
+ pCode += ( sizeof( T ) * 2 );
+ visitor.processOpCode2( eOp, nOp1, nOp2 );
+ }
+ }
+ visitor.end();
+ }
+};
+
+template < class T, class S >
+class OffSetAccumulator : public PCodeVisitor< T >
+{
+ T m_nNumOp0;
+ T m_nNumSingleParams;
+ T m_nNumDoubleParams;
+public:
+
+ OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
+ virtual void start( BYTE* /*pStart*/ ){}
+ virtual void processOpCode0( SbiOpcode /*eOp*/ ){ ++m_nNumOp0; }
+ virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ){ ++m_nNumSingleParams; }
+ virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) { ++m_nNumDoubleParams; }
+ virtual void end(){}
+ S offset()
+ {
+ T result = 0 ;
+ static const S max = std::numeric_limits< S >::max();
+ result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 ) * m_nNumDoubleParams );
+ if ( result > max )
+ return max;
+
+ return static_cast<S>(result);
+ }
+ virtual bool processParams(){ return false; }
+};
+
+
+
+template < class T, class S >
+
+class BufferTransformer : public PCodeVisitor< T >
+{
+ BYTE* m_pStart;
+ SbiBuffer m_ConvertedBuf;
+public:
+ BufferTransformer():m_pStart(NULL), m_ConvertedBuf( NULL, 1024 ) {}
+ virtual void start( BYTE* pStart ){ m_pStart = pStart; }
+ virtual void processOpCode0( SbiOpcode eOp )
+ {
+ m_ConvertedBuf += (UINT8)eOp;
+ }
+ virtual void processOpCode1( SbiOpcode eOp, T nOp1 )
+ {
+ m_ConvertedBuf += (UINT8)eOp;
+ switch( eOp )
+ {
+ case _JUMP:
+ case _JUMPT:
+ case _JUMPF:
+ case _GOSUB:
+ case _CASEIS:
+ case _RETURN:
+ case _ERRHDL:
+ case _TESTFOR:
+ nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
+ break;
+ case _RESUME:
+ if ( nOp1 > 1 )
+ nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
+ break;
+ default:
+ break; //
+
+ }
+ m_ConvertedBuf += (S)nOp1;
+ }
+ virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 )
+ {
+ m_ConvertedBuf += (UINT8)eOp;
+ if ( eOp == _CASEIS )
+ if ( nOp1 )
+ nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
+ m_ConvertedBuf += (S)nOp1;
+ m_ConvertedBuf += (S)nOp2;
+
+ }
+ virtual bool processParams(){ return true; }
+ virtual void end() {}
+ // yeuch, careful here, you can only call
+ // GetBuffer on the returned SbiBuffer once, also
+ // you (as the caller) get to own the memory
+ SbiBuffer& buffer()
+ {
+ return m_ConvertedBuf;
+ }
+ static S convertBufferOffSet( BYTE* pStart, T nOp1 )
+ {
+ PCodeBufferWalker< T > aBuff( pStart, nOp1);
+ OffSetAccumulator< T, S > aVisitor;
+ aBuff.visitBuffer( aVisitor );
+ return aVisitor.offset();
+ }
+};
+
+UINT32
+SbiCodeGen::calcNewOffSet( BYTE* pCode, UINT16 nOffset )
+{
+ return BufferTransformer< UINT16, UINT32 >::convertBufferOffSet( pCode, nOffset );
+}
+
+UINT16
+SbiCodeGen::calcLegacyOffSet( BYTE* pCode, UINT32 nOffset )
+{
+ return BufferTransformer< UINT32, UINT16 >::convertBufferOffSet( pCode, nOffset );
+}
+
+template <class T, class S>
+void
+PCodeBuffConvertor<T,S>::convert()
+{
+ PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
+ BufferTransformer< T, S > aTrnsfrmer;
+ aBuf.visitBuffer( aTrnsfrmer );
+ m_pCnvtdBuf = (BYTE*)aTrnsfrmer.buffer().GetBuffer();
+ m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
+}
+
+template class PCodeBuffConvertor< UINT16, UINT32 >;
+template class PCodeBuffConvertor< UINT32, UINT16 >;
diff --git a/basic/source/comp/dim.cxx b/basic/source/comp/dim.cxx
new file mode 100644
index 000000000000..59d77e3f3757
--- /dev/null
+++ b/basic/source/comp/dim.cxx
@@ -0,0 +1,1203 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+#include <basic/sbx.hxx>
+#include "sbcomp.hxx"
+
+SbxObject* cloneTypeObjectImpl( const SbxObject& rTypeObj );
+
+// 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 )
+{
+ bool bWithEvents = false;
+ if( Peek() == WITHEVENTS )
+ {
+ Next();
+ bWithEvents = true;
+ }
+ 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();
+ if( bWithEvents )
+ pDef->SetWithEvents();
+ 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 )
+{
+ SbxDataType eType = rDef.GetType();
+ short nSize = 0;
+ if( bAsNewAlreadyParsed || Peek() == AS )
+ {
+ if( !bAsNewAlreadyParsed )
+ Next();
+ rDef.SetDefinedAs();
+ String aType;
+ SbiToken eTok = Next();
+ if( !bAsNewAlreadyParsed && eTok == NEW )
+ {
+ 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:
+ if( rDef.IsNew() )
+ Error( SbERR_SYNTAX );
+ eType = (eTok==TBYTE) ? SbxBYTE : SbxDataType( eTok - TINTEGER + SbxINTEGER );
+ if( eType == SbxSTRING )
+ {
+ // STRING*n ?
+ if( Peek() == MUL )
+ { // fixed size!
+ Next();
+ SbiConstExpression aSize( this );
+ nSize = aSize.GetShortValue();
+ if( nSize < 0 || (bVBASupportOn && nSize <= 0) )
+ Error( SbERR_OUT_OF_RANGE );
+ else
+ rDef.SetFixedStringLength( nSize );
+ }
+ }
+ 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 ) )
+ {
+ Next();
+ aCompleteName += aSym;
+ }
+ else
+ {
+ Next();
+ Error( SbERR_UNEXPECTED, SYMBOL );
+ break;
+ }
+ }
+ }
+ else if( rEnumArray->Find( aCompleteName, SbxCLASS_OBJECT ) )
+ {
+ eType = SbxLONG;
+ break;
+ }
+
+ // In den String-Pool uebernehmen
+ rDef.SetTypeId( aGblStrings.Add( aCompleteName ) );
+
+ if( rDef.IsNew() && pProc == NULL )
+ aRequiredTypes.push_back( aCompleteName );
+ }
+ eType = SbxOBJECT;
+ break;
+ case FIXSTRING: // new syntax for complex UNO types
+ rDef.SetTypeId( aGblStrings.Add( aSym ) );
+ eType = SbxOBJECT;
+ break;
+ 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, ( pProc && bVBASupportOn ) ? pProc->IsStatic() : FALSE );
+}
+
+void SbiParser::DefVar( SbiOpcode eOp, BOOL bStatic )
+{
+ SbiSymPool* pOldPool = pPool;
+ BOOL bSwitchPool = FALSE;
+ BOOL bPersistantGlobal = FALSE;
+ SbiToken eFirstTok = eCurTok;
+ if( pProc && ( eCurTok == GLOBAL || eCurTok == PUBLIC || eCurTok == PRIVATE ) )
+ Error( SbERR_NOT_IN_SUBR, eCurTok );
+ if( eCurTok == PUBLIC || eCurTok == GLOBAL )
+ {
+ bSwitchPool = TRUE; // im richtigen Moment auf globalen Pool schalten
+ if( eCurTok == GLOBAL )
+ bPersistantGlobal = TRUE;
+ }
+ // behavior in VBA is that a module scope variable's lifetime is
+ // tied to the document. e.g. a module scope variable is global
+ if( GetBasic()->IsDocBasic() && bVBASupportOn && !pProc )
+ bPersistantGlobal = TRUE;
+ // 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 || eCurTok == DECLARE || eCurTok == TYPE) )
+ {
+ // 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;
+ }
+ else if( eCurTok == DECLARE )
+ {
+ Next();
+ DefDeclare( bPrivate );
+ return;
+ }
+ // #i109049
+ else if( eCurTok == TYPE )
+ {
+ Next();
+ DefType( bPrivate );
+ return;
+ }
+ }
+
+#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;
+ if( !bVBASupportOn && 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;
+ }
+ 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_ )
+ 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 ) )
+ {
+ // Variable oder globale Konstante deklarieren
+ SbiOpcode eOp2;
+ switch ( pDef->GetScope() )
+ {
+ case SbGLOBAL: eOp2 = bPersistantGlobal ? _GLOBAL_P : _GLOBAL;
+ goto global;
+ case SbPUBLIC: eOp2 = bPersistantGlobal ? _PUBLIC_P : _PUBLIC;
+ // AB 9.7.97, #40689, kein eigener Opcode mehr
+ if( bVBASupportOn && bStatic )
+ {
+ eOp2 = _STATIC;
+ break;
+ }
+ global: aGen.BackChain( nGblChain );
+ nGblChain = 0;
+ bGblDefs = bNewGblDefs = TRUE;
+ break;
+ default: eOp2 = _LOCAL;
+ }
+ UINT32 nOpnd2 = sal::static_int_cast< UINT16 >( pDef->GetType() );
+ if( pDef->IsWithEvents() )
+ nOpnd2 |= SBX_TYPE_WITH_EVENTS_FLAG;
+
+ short nFixedStringLength = pDef->GetFixedStringLength();
+ if( nFixedStringLength >= 0 )
+ nOpnd2 |= (SBX_FIXED_LEN_STRING_FLAG + (UINT32(nFixedStringLength) << 17)); // len = all bits above 0x10000
+
+ aGen.Gen( eOp2, pDef->GetId(), nOpnd2 );
+ }
+
+ // Initialisierung fuer selbstdefinierte Datentypen
+ // und per NEW angelegte Variable
+ if( pDef->GetType() == SbxOBJECT
+ && pDef->GetTypeId() )
+ {
+ if( !bCompatible && !pDef->IsNew() )
+ {
+ String aTypeName( aGblStrings.Find( pDef->GetTypeId() ) );
+ if( rTypeArray->Find( aTypeName, SbxCLASS_OBJECT ) == NULL )
+ Error( SbERR_UNDEF_TYPE, aTypeName );
+ }
+
+ 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() );
+ }
+ }
+ else
+ {
+ SbiExpression aExpr( this, *pDef );
+ aExpr.Gen();
+ SbiOpcode eOp_ = pDef->IsNew() ? _CREATE : _TCREATE;
+ aGen.Gen( eOp_, pDef->GetId(), pDef->GetTypeId() );
+ 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();
+ if ( bVBASupportOn )
+ // delete the array but
+ // clear the variable ( this
+ // allows the processing of
+ // the param to happen as normal without errors ( ordinary ERASE just clears the array )
+ aGen.Gen( _ERASE_CLEAR );
+ else
+ aGen.Gen( _ERASE );
+ }
+ else if( eOp == _REDIMP )
+ {
+ SbiExpression aExpr( this, *pDef, NULL );
+ aExpr.Gen();
+ aGen.Gen( _REDIMP_ERASE );
+ }
+ pDef->SetDims( pDim->GetDims() );
+ if( bPersistantGlobal )
+ pDef->SetGlobal( TRUE );
+ SbiExpression aExpr( this, *pDef, pDim );
+ aExpr.Gen();
+ pDef->SetGlobal( FALSE );
+ 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 überspingen
+ MyBreak:
+ pPool = pOldPool;
+ break;
+ }
+
+ // AB 9.7.97, #40689, Sprung ueber Statics-Deklaration abschliessen
+ if( !bVBASupportOn && 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, ( pProc && bVBASupportOn ) ? pProc->IsStatic() : FALSE );
+}
+
+// ERASE array, ...
+
+void SbiParser::Erase()
+{
+ while( !bAbort )
+ {
+ SbiExpression aExpr( this, SbLVALUE );
+ 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;
+
+ // 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 = NULL;
+ BOOL bDone = FALSE;
+
+ while( !bDone && !IsEof() )
+ {
+ switch( Peek() )
+ {
+ case ENDTYPE :
+ pElem = NULL;
+ bDone = TRUE;
+ Next();
+ break;
+
+ case EOLN :
+ case REM :
+ pElem = NULL;
+ Next();
+ break;
+
+ default:
+ pDim = NULL;
+ pElem = VarDecl(&pDim,FALSE,FALSE);
+ if( !pElem )
+ bDone = TRUE; // Error occured
+ }
+ if( pElem )
+ {
+ SbxArray *pTypeMembers = pType->GetProperties();
+ String aElemName = pElem->GetName();
+ if( pTypeMembers->Find( aElemName, SbxCLASS_DONTCARE) )
+ Error (SbERR_VAR_DEFINED);
+ else
+ {
+ SbxDataType eElemType = pElem->GetType();
+ SbxProperty *pTypeElem = new SbxProperty( aElemName, eElemType );
+ if( pDim )
+ {
+ SbxDimArray* pArray = new SbxDimArray( pElem->GetType() );
+ if ( pDim->GetSize() )
+ {
+ // Dimension the target array
+
+ for ( short i=0; i<pDim->GetSize();++i )
+ {
+ INT32 ub = -1;
+ INT32 lb = nBase;
+ SbiExprNode* pNode = pDim->Get(i)->GetExprNode();
+ ub = pNode->GetNumber();
+ if ( !pDim->Get( i )->IsBased() ) // each dim is low/up
+ {
+ if ( ++i >= pDim->GetSize() ) // trouble
+ StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
+ pNode = pDim->Get(i)->GetExprNode();
+ lb = ub;
+ ub = pNode->GetNumber();
+ }
+ else if ( !bCompatible )
+ ub += nBase;
+ pArray->AddDim32( lb, ub );
+ }
+ pArray->setHasFixedSize( true );
+ }
+ else
+ pArray->unoAddDim( 0, -1 ); // variant array
+ USHORT nSavFlags = pTypeElem->GetFlags();
+ // need to reset the FIXED flag
+ // when calling PutObject ( because the type will not match Object )
+ pTypeElem->ResetFlag( SBX_FIXED );
+ pTypeElem->PutObject( pArray );
+ pTypeElem->SetFlags( nSavFlags );
+ }
+ // Nested user type?
+ if( eElemType == SbxOBJECT )
+ {
+ USHORT nElemTypeId = pElem->GetTypeId();
+ if( nElemTypeId != 0 )
+ {
+ String aTypeName( aGblStrings.Find( nElemTypeId ) );
+ SbxObject* pTypeObj = static_cast< SbxObject* >( rTypeArray->Find( aTypeName, SbxCLASS_OBJECT ) );
+ if( pTypeObj != NULL )
+ {
+ SbxObject* pCloneObj = cloneTypeObjectImpl( *pTypeObj );
+ pTypeElem->PutObject( pCloneObj );
+ }
+ }
+ }
+ delete pDim;
+ pTypeMembers->Insert( pTypeElem, pTypeMembers->Count() );
+ }
+ delete pElem;
+ }
+ }
+
+ pType->Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Name") ), SbxCLASS_DONTCARE );
+ pType->Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Parent") ), SbxCLASS_DONTCARE );
+
+ 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) )
+ {
+ Error( SbERR_VAR_DEFINED, aSym );
+ return;
+ }
+
+ SbxObject *pEnum = new SbxObject( aEnumName );
+ if( bPrivate )
+ pEnum->SetFlag( SBX_PRIVATE );
+
+ SbiSymDef* pElem;
+ SbiDimList* pDim;
+ BOOL bDone = FALSE;
+
+ // Starting with -1 to make first default value 0 after ++
+ sal_Int32 nCurrentEnumValue = -1;
+ while( !bDone && !IsEof() )
+ {
+ switch( Peek() )
+ {
+ case ENDENUM :
+ pElem = NULL;
+ bDone = TRUE;
+ Next();
+ break;
+
+ case EOLN :
+ case REM :
+ pElem = NULL;
+ Next();
+ break;
+
+ default:
+ {
+ // TODO: Check existing!
+ BOOL bDefined = FALSE;
+
+ pDim = NULL;
+ pElem = VarDecl( &pDim, FALSE, TRUE );
+ if( !pElem )
+ {
+ bDone = TRUE; // Error occured
+ break;
+ }
+ else if( pDim )
+ {
+ delete pDim;
+ Error( SbERR_SYNTAX );
+ bDone = TRUE; // Error occured
+ break;
+ }
+
+ 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 );
+ }
+ }
+ 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() );
+ }
+ }
+
+ pEnum->Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Name") ), SbxCLASS_DONTCARE );
+ pEnum->Remove( XubString( RTL_CONSTASCII_USTRINGPARAM("Parent") ), SbxCLASS_DONTCARE );
+
+ rEnumArray->Insert( pEnum, rEnumArray->Count() );
+}
+
+
+// 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 );
+ BOOL bProp = BOOL( eCurTok == GET || eCurTok == SET || eCurTok == LET );
+ if( !TestSymbol() ) return NULL;
+ String aName( aSym );
+ SbxDataType eType = eScanType;
+ SbiProcDef* pDef = new SbiProcDef( this, aName, true );
+ 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_ )
+ {
+ if ( Peek() == BYVAL ) Next(), bByVal = TRUE;
+ else if ( Peek() == BYREF ) Next(), bByVal = FALSE;
+ else if ( Peek() == _OPTIONAL_ ) Next(), bOptional = TRUE;
+ }
+ if( bCompatible && Peek() == PARAMARRAY )
+ {
+ if( bByVal || bOptional )
+ Error( SbERR_UNEXPECTED, PARAMARRAY );
+ Next();
+ bParamArray = TRUE;
+ }
+ SbiSymDef* pPar = VarDecl( NULL, FALSE, FALSE );
+ if( !pPar )
+ break;
+ if( bByVal )
+ pPar->SetByVal();
+ if( bOptional )
+ pPar->SetOptional();
+ if( bParamArray )
+ pPar->SetParamArray();
+ 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;
+ }
+ }
+ 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 || bProp ) )
+ pDef->SetType( SbxEMPTY );
+ return pDef;
+}
+
+// DECLARE
+
+void SbiParser::Declare()
+{
+ DefDeclare( FALSE );
+}
+
+void SbiParser::DefDeclare( BOOL bPrivate )
+{
+ Next();
+ if( eCurTok != SUB && eCurTok != FUNCTION )
+ Error( SbERR_UNEXPECTED, eCurTok );
+ else
+ {
+ bool bFunction = (eCurTok == FUNCTION);
+
+ 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;
+ pDef = NULL;
+ }
+ else
+ pDef->Match( p );
+ }
+ else
+ aPublics.Add( pDef );
+
+ if ( pDef )
+ {
+ pDef->SetPublic( !bPrivate );
+
+ // New declare handling
+ if( pDef->GetLib().Len() > 0 )
+ {
+ if( bNewGblDefs && nGblChain == 0 )
+ {
+ nGblChain = aGen.Gen( _JUMP, 0 );
+ bNewGblDefs = FALSE;
+ }
+
+ USHORT nSavLine = nLine;
+ aGen.Statement();
+ pDef->Define();
+ pDef->SetLine1( nSavLine );
+ pDef->SetLine2( nSavLine );
+
+ SbiSymPool& rPool = pDef->GetParams();
+ USHORT nParCount = rPool.GetSize();
+
+ SbxDataType eType = pDef->GetType();
+ if( bFunction )
+ aGen.Gen( _PARAM, 0, sal::static_int_cast< UINT16 >( eType ) );
+
+ if( nParCount > 1 )
+ {
+ aGen.Gen( _ARGC );
+
+ for( USHORT i = 1 ; i < nParCount ; ++i )
+ {
+ SbiSymDef* pParDef = rPool.Get( i );
+ SbxDataType eParType = pParDef->GetType();
+
+ aGen.Gen( _PARAM, i, sal::static_int_cast< UINT16 >( eParType ) );
+ aGen.Gen( _ARGV );
+
+ USHORT nTyp = sal::static_int_cast< USHORT >( pParDef->GetType() );
+ if( pParDef->IsByVal() )
+ {
+ // Reset to avoid additional byval in call to wrapper function
+ pParDef->SetByVal( FALSE );
+ nTyp |= 0x8000;
+ }
+ aGen.Gen( _ARGTYP, nTyp );
+ }
+ }
+
+ aGen.Gen( _LIB, aGblStrings.Add( pDef->GetLib() ) );
+
+ SbiOpcode eOp = pDef->IsCdecl() ? _CALLC : _CALL;
+ USHORT nId = pDef->GetId();
+ if( pDef->GetAlias().Len() )
+ nId = ( nId & 0x8000 ) | aGblStrings.Add( pDef->GetAlias() );
+ if( nParCount > 1 )
+ nId |= 0x8000;
+ aGen.Gen( eOp, nId, sal::static_int_cast< UINT16 >( eType ) );
+
+ if( bFunction )
+ aGen.Gen( _PUT );
+
+ aGen.Gen( _LEAVE );
+ }
+ }
+ }
+ }
+}
+
+// Aufruf einer SUB oder FUNCTION
+
+void SbiParser::Call()
+{
+ String aName( aSym );
+ SbiExpression aVar( this, SbSYMBOL );
+ aVar.Gen( FORCE_CALL );
+ aGen.Gen( _GET );
+}
+
+// SUB/FUNCTION
+
+void SbiParser::SubFunc()
+{
+ DefProc( FALSE, FALSE );
+}
+
+// Einlesen einer Prozedur
+
+BOOL runsInSetup( void );
+
+void SbiParser::DefProc( BOOL bStatic, BOOL bPrivate )
+{
+ 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" );
+ }
+
+ SbiToken eExit = eCurTok;
+ SbiProcDef* pDef = ProcDecl( FALSE );
+ if( !pDef )
+ return;
+ pDef->setPropertyMode( ePropertyMode );
+
+ // Ist die Proc bereits deklariert?
+ SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
+ if( pOld )
+ {
+ bool bError_ = false;
+
+ pProc = pOld->GetProcDef();
+ if( !pProc )
+ {
+ // Als Variable deklariert
+ Error( SbERR_BAD_DECLARATION, pDef->GetName() );
+ delete pDef;
+ pProc = NULL;
+ bError_ = true;
+ }
+ // #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_ )
+ {
+ pDef->Match( pProc );
+ pProc = pDef;
+ }
+ }
+ else
+ aPublics.Add( pDef ), pProc = pDef;
+
+ if( !pProc )
+ return;
+ pProc->SetPublic( !bPrivate );
+
+ // Nun setzen wir die Suchhierarchie fuer Symbole sowie die aktuelle
+ // Prozedur.
+ aPublics.SetProcId( pProc->GetId() );
+ pProc->GetParams().SetParent( &aPublics );
+ if( bStatic )
+ {
+ if ( bVBASupportOn )
+ pProc->SetStatic( TRUE );
+ else
+ Error( SbERR_NOT_IMPLEMENTED ); // STATIC SUB ...
+ }
+ else
+ {
+ pProc->SetStatic( FALSE );
+ }
+ // Normalfall: Lokale Variable->Parameter->Globale Variable
+ pProc->GetLocals().SetParent( &pProc->GetParams() );
+ pPool = &pProc->GetLocals();
+
+ pProc->Define();
+ OpenBlock( eExit );
+ StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) );
+ 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 )
+{
+ 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;
+ }
+ Next();
+ DefProc( TRUE, bPrivate );
+ 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;
+ }
+}
+
diff --git a/basic/source/comp/exprgen.cxx b/basic/source/comp/exprgen.cxx
new file mode 100644
index 000000000000..3e034af204f5
--- /dev/null
+++ b/basic/source/comp/exprgen.cxx
@@ -0,0 +1,270 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include "sbcomp.hxx"
+#include "expr.hxx"
+
+// Umsetztabelle fuer Token-Operatoren und Opcodes
+
+typedef struct {
+ SbiToken eTok; // Token
+ SbiOpcode eOp; // Opcode
+} OpTable;
+
+static OpTable aOpTable [] = {
+ { EXPON,_EXP },
+ { MUL, _MUL },
+ { DIV, _DIV },
+ { IDIV, _IDIV },
+ { MOD, _MOD },
+ { PLUS, _PLUS },
+ { MINUS,_MINUS },
+ { EQ, _EQ },
+ { NE, _NE },
+ { LE, _LE },
+ { GE, _GE },
+ { LT, _LT },
+ { GT, _GT },
+ { AND, _AND },
+ { OR, _OR },
+ { XOR, _XOR },
+ { EQV, _EQV },
+ { IMP, _IMP },
+ { NOT, _NOT },
+ { NEG, _NEG },
+ { CAT, _CAT },
+ { LIKE, _LIKE },
+ { IS, _IS },
+ { NIL, _NOP }};
+
+// Ausgabe eines Elements
+void SbiExprNode::Gen( RecursiveMode eRecMode )
+{
+ if( IsConstant() )
+ {
+ switch( GetType() )
+ {
+ case SbxEMPTY: pGen->Gen( _EMPTY ); break;
+ case SbxINTEGER: pGen->Gen( _CONST, (short) nVal ); break;
+ case SbxSTRING:
+ {
+ USHORT nStringId = pGen->GetParser()->aGblStrings.Add( aStrVal, TRUE );
+ pGen->Gen( _SCONST, nStringId ); break;
+ }
+ default:
+ {
+ USHORT nStringId = pGen->GetParser()->aGblStrings.Add( nVal, eType );
+ pGen->Gen( _NUMBER, nStringId );
+ }
+ }
+ }
+ else if( IsOperand() )
+ {
+ SbiExprNode* pWithParent_ = NULL;
+ SbiOpcode eOp;
+ if( aVar.pDef->GetScope() == SbPARAM )
+ {
+ eOp = _PARAM;
+ if( 0 == aVar.pDef->GetPos() )
+ {
+ bool bTreatFunctionAsParam = true;
+ if( eRecMode == FORCE_CALL )
+ {
+ bTreatFunctionAsParam = false;
+ }
+ else if( eRecMode == UNDEFINED )
+ {
+ if( aVar.pPar && aVar.pPar->IsBracket() )
+ bTreatFunctionAsParam = false;
+ }
+ if( !bTreatFunctionAsParam )
+ eOp = aVar.pDef->IsGlobal() ? _FIND_G : _FIND;
+ }
+ }
+ // AB: 17.12.1995, Spezialbehandlung fuer WITH
+ else if( (pWithParent_ = GetWithParent()) != NULL )
+ {
+ eOp = _ELEM; // .-Ausdruck in WITH
+ }
+ else
+ {
+ eOp = ( aVar.pDef->GetScope() == SbRTL ) ? _RTL :
+ (aVar.pDef->IsGlobal() ? _FIND_G : _FIND);
+ }
+
+ if( eOp == _FIND )
+ {
+
+ SbiProcDef* pProc = aVar.pDef->GetProcDef();
+ if ( pGen->GetParser()->bClassModule )
+ eOp = _FIND_CM;
+ else if ( aVar.pDef->IsStatic() || (pProc && pProc->IsStatic()) )
+ {
+ eOp = _FIND_STATIC;
+ }
+ }
+ for( SbiExprNode* p = this; p; p = p->aVar.pNext )
+ {
+ if( p == this && pWithParent_ != NULL )
+ pWithParent_->Gen();
+ p->GenElement( eOp );
+ eOp = _ELEM;
+ }
+ }
+ else if( IsTypeOf() )
+ {
+ pLeft->Gen();
+ pGen->Gen( _TESTCLASS, nTypeStrId );
+ }
+ else if( IsNew() )
+ {
+ pGen->Gen( _CREATE, 0, nTypeStrId );
+ }
+ else
+ {
+ pLeft->Gen();
+ if( pRight )
+ pRight->Gen();
+ for( OpTable* p = aOpTable; p->eTok != NIL; p++ )
+ {
+ if( p->eTok == eTok )
+ {
+ pGen->Gen( p->eOp ); break;
+ }
+ }
+ }
+}
+
+// Ausgabe eines Operanden-Elements
+
+void SbiExprNode::GenElement( SbiOpcode eOp )
+{
+#ifdef DBG_UTIL
+ if( (eOp < _RTL || eOp > _CALLC) && eOp != _FIND_G && eOp != _FIND_CM )
+ pGen->GetParser()->Error( SbERR_INTERNAL_ERROR, "Opcode" );
+#endif
+ SbiSymDef* pDef = aVar.pDef;
+ // Das ID ist entweder die Position oder das String-ID
+ // Falls das Bit 0x8000 gesetzt ist, hat die Variable
+ // eine Parameterliste.
+ USHORT nId = ( eOp == _PARAM ) ? pDef->GetPos() : pDef->GetId();
+ // Parameterliste aufbauen
+ if( aVar.pPar && aVar.pPar->GetSize() )
+ {
+ nId |= 0x8000;
+ aVar.pPar->Gen();
+ }
+
+ pGen->Gen( eOp, nId, sal::static_int_cast< UINT16 >( GetType() ) );
+
+ if( aVar.pvMorePar )
+ {
+ SbiExprListVector* pvMorePar = aVar.pvMorePar;
+ SbiExprListVector::iterator it;
+ for( it = pvMorePar->begin() ; it != pvMorePar->end() ; ++it )
+ {
+ SbiExprList* pExprList = *it;
+ pExprList->Gen();
+ pGen->Gen( _ARRAYACCESS );
+ }
+ }
+}
+
+// Erzeugen einer Argv-Tabelle
+// Das erste Element bleibt immer frei fuer Returnwerte etc.
+// Siehe auch SbiProcDef::SbiProcDef() in symtbl.cxx
+
+void SbiExprList::Gen()
+{
+ if( pFirst )
+ {
+ pParser->aGen.Gen( _ARGC );
+ // AB 10.1.96: Typ-Anpassung bei DECLARE
+ USHORT nCount = 1 /*, nParAnz = 0*/;
+// SbiSymPool* pPool = NULL;
+ for( SbiExpression* pExpr = pFirst; pExpr; pExpr = pExpr->pNext,nCount++ )
+ {
+ pExpr->Gen();
+ if( pExpr->GetName().Len() )
+ {
+ // named arg
+ USHORT nSid = pParser->aGblStrings.Add( pExpr->GetName() );
+ pParser->aGen.Gen( _ARGN, nSid );
+
+ /* TODO: Check after Declare concept change
+ // AB 10.1.96: Typanpassung bei named -> passenden Parameter suchen
+ if( pProc )
+ {
+ // Vorerst: Error ausloesen
+ pParser->Error( SbERR_NO_NAMED_ARGS );
+
+ // Spaeter, wenn Named Args bei DECLARE moeglich
+ //for( USHORT i = 1 ; i < nParAnz ; i++ )
+ //{
+ // SbiSymDef* pDef = pPool->Get( i );
+ // const String& rName = pDef->GetName();
+ // if( rName.Len() )
+ // {
+ // if( pExpr->GetName().ICompare( rName )
+ // == COMPARE_EQUAL )
+ // {
+ // pParser->aGen.Gen( _ARGTYP, pDef->GetType() );
+ // break;
+ // }
+ // }
+ //}
+ }
+ */
+ }
+ else
+ {
+ pParser->aGen.Gen( _ARGV );
+ }
+ }
+ }
+}
+
+void SbiExpression::Gen( RecursiveMode eRecMode )
+{
+ // AB: 17.12.1995, Spezialbehandlung fuer WITH
+ // Wenn pExpr == .-Ausdruck in With, zunaechst Gen fuer Basis-Objekt
+ pExpr->Gen( eRecMode );
+ if( bByVal )
+ pParser->aGen.Gen( _BYVAL );
+ if( bBased )
+ {
+ USHORT uBase = pParser->nBase;
+ if( pParser->IsCompatible() )
+ uBase |= 0x8000; // #109275 Flag compatiblity
+ pParser->aGen.Gen( _BASED, uBase );
+ pParser->aGen.Gen( _ARGV );
+ }
+}
+
diff --git a/basic/source/comp/exprnode.cxx b/basic/source/comp/exprnode.cxx
new file mode 100644
index 000000000000..d47c86f86ea8
--- /dev/null
+++ b/basic/source/comp/exprnode.cxx
@@ -0,0 +1,488 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include <math.h>
+
+#include <rtl/math.hxx>
+#include "sbcomp.hxx"
+#include "expr.hxx"
+
+//////////////////////////////////////////////////////////////////////////
+
+SbiExprNode::SbiExprNode( void )
+{
+ pLeft = NULL;
+ pRight = NULL;
+ eNodeType = SbxDUMMY;
+}
+
+SbiExprNode::SbiExprNode( SbiParser* p, SbiExprNode* l, SbiToken t, SbiExprNode* r )
+{
+ BaseInit( p );
+
+ pLeft = l;
+ pRight = r;
+ eTok = t;
+ nVal = 0;
+ eType = SbxVARIANT; // Nodes sind immer Variant
+ eNodeType = SbxNODE;
+ bComposite= TRUE;
+}
+
+SbiExprNode::SbiExprNode( SbiParser* p, double n, SbxDataType t )
+{
+ BaseInit( p );
+
+ eType = t;
+ eNodeType = SbxNUMVAL;
+ nVal = n;
+}
+
+SbiExprNode::SbiExprNode( SbiParser* p, const String& rVal )
+{
+ BaseInit( p );
+
+ eType = SbxSTRING;
+ eNodeType = SbxSTRVAL;
+ aStrVal = rVal;
+}
+
+SbiExprNode::SbiExprNode( SbiParser* p, const SbiSymDef& r, SbxDataType t, SbiExprList* l )
+{
+ BaseInit( p );
+
+ eType = ( t == SbxVARIANT ) ? r.GetType() : t;
+ eNodeType = SbxVARVAL;
+ aVar.pDef = (SbiSymDef*) &r;
+ aVar.pPar = l;
+ aVar.pvMorePar = NULL;
+ aVar.pNext= NULL;
+
+ // Funktionsergebnisse sind nie starr
+ bComposite= BOOL( aVar.pDef->GetProcDef() != NULL );
+}
+
+// #120061 TypeOf
+SbiExprNode::SbiExprNode( SbiParser* p, SbiExprNode* l, USHORT nId )
+{
+ BaseInit( p );
+
+ pLeft = l;
+ eType = SbxBOOL;
+ eNodeType = SbxTYPEOF;
+ nTypeStrId = nId;
+}
+
+// new <type>
+SbiExprNode::SbiExprNode( SbiParser* p, USHORT nId )
+{
+ BaseInit( p );
+
+ eType = SbxOBJECT;
+ eNodeType = SbxNEW;
+ nTypeStrId = nId;
+}
+
+// AB: 17.12.95, Hilfsfunktion fuer Ctor fuer einheitliche Initialisierung
+void SbiExprNode::BaseInit( SbiParser* p )
+{
+ pGen = &p->aGen;
+ eTok = NIL;
+ pLeft = NULL;
+ pRight = NULL;
+ pWithParent = NULL;
+ bComposite = FALSE;
+ bError = FALSE;
+}
+
+SbiExprNode::~SbiExprNode()
+{
+ delete pLeft;
+ delete pRight;
+ if( IsVariable() )
+ {
+ delete aVar.pPar;
+ delete aVar.pNext;
+ SbiExprListVector* pvMorePar = aVar.pvMorePar;
+ if( pvMorePar )
+ {
+ SbiExprListVector::iterator it;
+ for( it = pvMorePar->begin() ; it != pvMorePar->end() ; ++it )
+ delete *it;
+ delete pvMorePar;
+ }
+ }
+}
+
+SbiSymDef* SbiExprNode::GetVar()
+{
+ if( eNodeType == SbxVARVAL )
+ return aVar.pDef;
+ else
+ return NULL;
+}
+
+SbiSymDef* SbiExprNode::GetRealVar()
+{
+ SbiExprNode* p = GetRealNode();
+ if( p )
+ return p->GetVar();
+ else
+ return NULL;
+}
+
+// AB: 18.12.95
+SbiExprNode* SbiExprNode::GetRealNode()
+{
+ if( eNodeType == SbxVARVAL )
+ {
+ SbiExprNode* p = this;
+ while( p->aVar.pNext )
+ p = p->aVar.pNext;
+ return p;
+ }
+ else
+ return NULL;
+}
+
+// Diese Methode setzt den Typ um, falls er in den Integer-Bereich hineinpasst
+
+BOOL SbiExprNode::IsIntConst()
+{
+ if( eNodeType == SbxNUMVAL )
+ {
+ if( eType >= SbxINTEGER && eType <= SbxDOUBLE )
+ {
+ double n;
+ if( nVal >= SbxMININT && nVal <= SbxMAXINT && modf( nVal, &n ) == 0 )
+ {
+ nVal = (double) (short) nVal;
+ eType = SbxINTEGER;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+BOOL SbiExprNode::IsNumber()
+{
+ return BOOL( eNodeType == SbxNUMVAL );
+}
+
+BOOL SbiExprNode::IsString()
+{
+ return BOOL( eNodeType == SbxSTRVAL );
+}
+
+BOOL SbiExprNode::IsVariable()
+{
+ return BOOL( eNodeType == SbxVARVAL );
+}
+
+BOOL SbiExprNode::IsLvalue()
+{
+ return IsVariable();
+}
+
+// Ermitteln der Tiefe eines Baumes
+
+short SbiExprNode::GetDepth()
+{
+ if( IsOperand() ) return 0;
+ else
+ {
+ short d1 = pLeft->GetDepth();
+ short d2 = pRight->GetDepth();
+ return( (d1 < d2 ) ? d2 : d1 ) + 1;
+ }
+}
+
+
+// Abgleich eines Baumes:
+// 1. Constant Folding
+// 2. Typabgleich
+// 3. Umwandlung der Operanden in Strings
+// 4. Hochziehen der Composite- und Error-Bits
+
+void SbiExprNode::Optimize()
+{
+ FoldConstants();
+ CollectBits();
+}
+
+// Hochziehen der Composite- und Fehlerbits
+
+void SbiExprNode::CollectBits()
+{
+ if( pLeft )
+ {
+ pLeft->CollectBits();
+ bError |= pLeft->bError;
+ bComposite |= pLeft->bComposite;
+ }
+ if( pRight )
+ {
+ pRight->CollectBits();
+ bError |= pRight->bError;
+ bComposite |= pRight->bComposite;
+ }
+}
+
+// Kann ein Zweig umgeformt werden, wird TRUE zurueckgeliefert. In diesem
+// Fall ist das Ergebnis im linken Zweig.
+
+void SbiExprNode::FoldConstants()
+{
+ if( IsOperand() || eTok == LIKE ) return;
+ if( pLeft )
+ pLeft->FoldConstants();
+ if( pRight )
+ {
+ pRight->FoldConstants();
+ if( pLeft->IsConstant() && pRight->IsConstant()
+ && pLeft->eNodeType == pRight->eNodeType )
+ {
+ CollectBits();
+ if( eTok == CAT )
+ // CAT verbindet auch zwei Zahlen miteinander!
+ eType = SbxSTRING;
+ if( pLeft->eType == SbxSTRING )
+ // Kein Type Mismatch!
+ eType = SbxSTRING;
+ if( eType == SbxSTRING )
+ {
+ String rl( pLeft->GetString() );
+ String rr( pRight->GetString() );
+ delete pLeft; pLeft = NULL;
+ delete pRight; pRight = NULL;
+ bComposite = FALSE;
+ if( eTok == PLUS || eTok == CAT )
+ {
+ eTok = CAT;
+ // Verkettung:
+ aStrVal = rl;
+ aStrVal += rr;
+ eType = SbxSTRING;
+ eNodeType = SbxSTRVAL;
+ }
+ else
+ {
+ eType = SbxDOUBLE;
+ eNodeType = SbxNUMVAL;
+ StringCompare eRes = rr.CompareTo( rl );
+ switch( eTok )
+ {
+ case EQ:
+ nVal = ( eRes == COMPARE_EQUAL ) ? SbxTRUE : SbxFALSE;
+ break;
+ case NE:
+ nVal = ( eRes != COMPARE_EQUAL ) ? SbxTRUE : SbxFALSE;
+ break;
+ case LT:
+ nVal = ( eRes == COMPARE_LESS ) ? SbxTRUE : SbxFALSE;
+ break;
+ case GT:
+ nVal = ( eRes == COMPARE_GREATER ) ? SbxTRUE : SbxFALSE;
+ break;
+ case LE:
+ nVal = ( eRes != COMPARE_GREATER ) ? SbxTRUE : SbxFALSE;
+ break;
+ case GE:
+ nVal = ( eRes != COMPARE_LESS ) ? SbxTRUE : SbxFALSE;
+ break;
+ default:
+ pGen->GetParser()->Error( SbERR_CONVERSION );
+ bError = TRUE;
+ }
+ }
+ }
+ else
+ {
+ double nl = pLeft->nVal;
+ double nr = pRight->nVal;
+ long ll = 0, lr = 0;
+ long llMod = 0, lrMod = 0;
+ if( ( eTok >= AND && eTok <= IMP )
+ || eTok == IDIV || eTok == MOD )
+ {
+ // Integer-Operationen
+ BOOL err = FALSE;
+ if( nl > SbxMAXLNG ) err = TRUE, nl = SbxMAXLNG;
+ else
+ if( nl < SbxMINLNG ) err = TRUE, nl = SbxMINLNG;
+ if( nr > SbxMAXLNG ) err = TRUE, nr = SbxMAXLNG;
+ else
+ if( nr < SbxMINLNG ) err = TRUE, nr = SbxMINLNG;
+ ll = (long) nl; lr = (long) nr;
+ llMod = (long) (nl < 0 ? nl - 0.5 : nl + 0.5);
+ lrMod = (long) (nr < 0 ? nr - 0.5 : nr + 0.5);
+ if( err )
+ {
+ pGen->GetParser()->Error( SbERR_MATH_OVERFLOW );
+ bError = TRUE;
+ }
+ }
+ BOOL bBothInt = BOOL( pLeft->eType < SbxSINGLE
+ && pRight->eType < SbxSINGLE );
+ delete pLeft; pLeft = NULL;
+ delete pRight; pRight = NULL;
+ nVal = 0;
+ eType = SbxDOUBLE;
+ eNodeType = SbxNUMVAL;
+ bComposite = FALSE;
+ BOOL bCheckType = FALSE;
+ switch( eTok )
+ {
+ case EXPON:
+ nVal = pow( nl, nr ); break;
+ case MUL:
+ bCheckType = TRUE;
+ nVal = nl * nr; break;
+ case DIV:
+ if( !nr )
+ {
+ pGen->GetParser()->Error( SbERR_ZERODIV ); nVal = HUGE_VAL;
+ bError = TRUE;
+ } else nVal = nl / nr;
+ break;
+ case PLUS:
+ bCheckType = TRUE;
+ nVal = nl + nr; break;
+ case MINUS:
+ bCheckType = TRUE;
+ nVal = nl - nr; break;
+ case EQ:
+ nVal = ( nl == nr ) ? SbxTRUE : SbxFALSE;
+ eType = SbxINTEGER; break;
+ case NE:
+ nVal = ( nl != nr ) ? SbxTRUE : SbxFALSE;
+ eType = SbxINTEGER; break;
+ case LT:
+ nVal = ( nl < nr ) ? SbxTRUE : SbxFALSE;
+ eType = SbxINTEGER; break;
+ case GT:
+ nVal = ( nl > nr ) ? SbxTRUE : SbxFALSE;
+ eType = SbxINTEGER; break;
+ case LE:
+ nVal = ( nl <= nr ) ? SbxTRUE : SbxFALSE;
+ eType = SbxINTEGER; break;
+ case GE:
+ nVal = ( nl >= nr ) ? SbxTRUE : SbxFALSE;
+ eType = SbxINTEGER; break;
+ case IDIV:
+ if( !lr )
+ {
+ pGen->GetParser()->Error( SbERR_ZERODIV ); nVal = HUGE_VAL;
+ bError = TRUE;
+ } else nVal = ll / lr;
+ eType = SbxLONG; break;
+ case MOD:
+ if( !lr )
+ {
+ pGen->GetParser()->Error( SbERR_ZERODIV ); nVal = HUGE_VAL;
+ bError = TRUE;
+ } else nVal = llMod % lrMod;
+ eType = SbxLONG; break;
+ case AND:
+ nVal = (double) ( ll & lr ); eType = SbxLONG; break;
+ case OR:
+ nVal = (double) ( ll | lr ); eType = SbxLONG; break;
+ case XOR:
+ nVal = (double) ( ll ^ lr ); eType = SbxLONG; break;
+ case EQV:
+ nVal = (double) ( ~ll ^ lr ); eType = SbxLONG; break;
+ case IMP:
+ nVal = (double) ( ~ll | lr ); eType = SbxLONG; break;
+ default: break;
+ }
+
+ if( !::rtl::math::isFinite( nVal ) )
+ pGen->GetParser()->Error( SbERR_MATH_OVERFLOW );
+
+ // Den Datentyp wiederherstellen, um Rundungsfehler
+ // zu killen
+ if( bCheckType && bBothInt
+ && nVal >= SbxMINLNG && nVal <= SbxMAXLNG )
+ {
+ // NK-Stellen weg
+ long n = (long) nVal;
+ nVal = n;
+ eType = ( n >= SbxMININT && n <= SbxMAXINT )
+ ? SbxINTEGER : SbxLONG;
+ }
+ }
+ }
+ }
+ else if( pLeft && pLeft->IsNumber() )
+ {
+ nVal = pLeft->nVal;
+ delete pLeft;
+ pLeft = NULL;
+ eType = SbxDOUBLE;
+ eNodeType = SbxNUMVAL;
+ bComposite = FALSE;
+ switch( eTok )
+ {
+ case NEG:
+ nVal = -nVal; break;
+ case NOT: {
+ // Integer-Operation!
+ BOOL err = FALSE;
+ if( nVal > SbxMAXLNG ) err = TRUE, nVal = SbxMAXLNG;
+ else
+ if( nVal < SbxMINLNG ) err = TRUE, nVal = SbxMINLNG;
+ if( err )
+ {
+ pGen->GetParser()->Error( SbERR_MATH_OVERFLOW );
+ bError = TRUE;
+ }
+ nVal = (double) ~((long) nVal);
+ eType = SbxLONG;
+ } break;
+ default: break;
+ }
+ }
+ if( eNodeType == SbxNUMVAL )
+ {
+ // Evtl auf INTEGER falten (wg. besserem Opcode)?
+ if( eType == SbxSINGLE || eType == SbxDOUBLE )
+ {
+ double x;
+ if( nVal >= SbxMINLNG && nVal <= SbxMAXLNG
+ && !modf( nVal, &x ) )
+ eType = SbxLONG;
+ }
+ if( eType == SbxLONG && nVal >= SbxMININT && nVal <= SbxMAXINT )
+ eType = SbxINTEGER;
+ }
+}
+
+
diff --git a/basic/source/comp/exprtree.cxx b/basic/source/comp/exprtree.cxx
new file mode 100644
index 000000000000..7a4ea5965558
--- /dev/null
+++ b/basic/source/comp/exprtree.cxx
@@ -0,0 +1,1136 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include "sbcomp.hxx"
+#include <basic/sbx.hxx> // w.g. ...IMPL_REF(...sbxvariable)
+#include "expr.hxx"
+
+/***************************************************************************
+|*
+|* SbiExpression
+|*
+***************************************************************************/
+
+SbiExpression::SbiExpression( SbiParser* p, SbiExprType t,
+ SbiExprMode eMode, const KeywordSymbolInfo* pKeywordSymbolInfo )
+{
+ pParser = p;
+ bError = bByVal = bBased = bBracket = FALSE;
+ nParenLevel = 0;
+ eCurExpr = t;
+ m_eMode = eMode;
+ pNext = NULL;
+ pExpr = (t != SbSTDEXPR ) ? Term( pKeywordSymbolInfo ) : Boolean();
+ if( t != SbSYMBOL )
+ pExpr->Optimize();
+ if( t == SbLVALUE && !pExpr->IsLvalue() )
+ p->Error( SbERR_LVALUE_EXPECTED );
+ if( t == SbOPERAND && !IsVariable() )
+ p->Error( SbERR_VAR_EXPECTED );
+}
+
+SbiExpression::SbiExpression( SbiParser* p, double n, SbxDataType t )
+{
+ pParser = p;
+ eCurExpr = SbOPERAND;
+ pNext = NULL;
+ bError = bByVal = bBased = bBracket = FALSE;
+ pExpr = new SbiExprNode( pParser, n, t );
+ pExpr->Optimize();
+}
+
+SbiExpression::SbiExpression( SbiParser* p, const String& r )
+{
+ pParser = p;
+ pNext = NULL;
+ bError = bByVal = bBased = bBracket = FALSE;
+ eCurExpr = SbOPERAND;
+ pExpr = new SbiExprNode( pParser, r );
+}
+
+SbiExpression::SbiExpression( SbiParser* p, const SbiSymDef& r, SbiExprList* pPar )
+{
+ pParser = p;
+ pNext = NULL;
+ bError = bByVal = bBased = bBracket = FALSE;
+ eCurExpr = SbOPERAND;
+ pExpr = new SbiExprNode( pParser, r, SbxVARIANT, pPar );
+}
+
+SbiExpression::SbiExpression( SbiParser* p, SbiToken t )
+{
+ pParser = p;
+ pNext = NULL;
+ bError = bByVal = bBased = bBracket = FALSE;
+ eCurExpr = SbOPERAND;
+ pExpr = new SbiExprNode( pParser, NULL, t, NULL );
+}
+
+SbiExpression::~SbiExpression()
+{
+ delete pExpr;
+}
+
+// Einlesen eines kompletten Bezeichners
+// Ein Bezeichner hat folgende Form:
+// name[(Parameter)][.Name[(parameter)]]...
+// Strukturelemente werden ueber das Element pNext verkoppelt,
+// damit sie nicht im Baum stehen.
+
+// Folgen Parameter ohne Klammer? Dies kann eine Zahl, ein String,
+// ein Symbol oder auch ein Komma sein (wenn der 1. Parameter fehlt)
+
+static BOOL DoParametersFollow( SbiParser* p, SbiExprType eCurExpr, SbiToken eTok )
+{
+ if( eTok == LPAREN )
+ return TRUE;
+ // Aber nur, wenn CALL-aehnlich!
+ if( !p->WhiteSpace() || eCurExpr != SbSYMBOL )
+ return FALSE;
+ if ( eTok == NUMBER || eTok == MINUS || eTok == FIXSTRING
+ || eTok == SYMBOL || eTok == COMMA || eTok == DOT || eTok == NOT || eTok == BYVAL )
+ {
+ return TRUE;
+ }
+ else // check for default params with reserved names ( e.g. names of tokens )
+ {
+ SbiTokenizer tokens( *(SbiTokenizer*)p );
+ // Urk the Next() / Peek() symantics are... weird
+ tokens.Next();
+ if ( tokens.Peek() == ASSIGN )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// Definition eines neuen Symbols
+
+static SbiSymDef* AddSym
+ ( SbiToken eTok, SbiSymPool& rPool, SbiExprType eCurExpr,
+ const String& rName, SbxDataType eType, SbiParameters* pPar )
+{
+ SbiSymDef* pDef;
+ // A= ist keine Prozedur
+ BOOL bHasType = BOOL( eTok == EQ || eTok == DOT );
+ if( ( !bHasType && eCurExpr == SbSYMBOL ) || pPar )
+ {
+ // Dies ist also eine Prozedur
+ // da suche man doch den richtigen Pool raus, da Procs
+ // immer in einem Public-Pool landen muessen
+ SbiSymPool* pPool = &rPool;
+ if( pPool->GetScope() != SbPUBLIC )
+ pPool = &rPool.GetParser()->aPublics;
+ SbiProcDef* pProc = pPool->AddProc( rName );
+
+ // Sonderbehandlung fuer Colls wie Documents(1)
+ if( eCurExpr == SbSTDEXPR )
+ bHasType = TRUE;
+
+ pDef = pProc;
+ pDef->SetType( bHasType ? eType : SbxEMPTY );
+ if( pPar )
+ {
+ // Dummy-Parameter generieren
+ USHORT n = 1;
+ for( short i = 0; i < pPar->GetSize(); i++ )
+ {
+ String aPar = String::CreateFromAscii( "PAR" );
+ aPar += ++n;
+ pProc->GetParams().AddSym( aPar );
+ }
+ }
+ }
+ else
+ {
+ // oder ein normales Symbol
+ pDef = rPool.AddSym( rName );
+ pDef->SetType( eType );
+ }
+ return pDef;
+}
+
+// Zur Zeit sind sogar Keywords zugelassen (wg. gleichnamiger Dflt-Properties)
+
+SbiExprNode* SbiExpression::Term( const KeywordSymbolInfo* pKeywordSymbolInfo )
+{
+ if( pParser->Peek() == DOT )
+ {
+ // eine WITH-Variable
+ SbiExprNode* pWithVar = pParser->GetWithVar();
+ // #26608: Ans Ende der Node-Kette gehen, um richtiges Objekt zu uebergeben
+ SbiSymDef* pDef = pWithVar ? pWithVar->GetRealVar() : NULL;
+ SbiExprNode* pNd = NULL;
+ if( !pDef )
+ {
+ pParser->Next();
+ }
+ else
+ {
+ pNd = ObjTerm( *pDef );
+ if( pNd )
+ pNd->SetWithParent( pWithVar );
+ }
+ if( !pNd )
+ {
+ pParser->Error( SbERR_UNEXPECTED, DOT );
+ pNd = new SbiExprNode( pParser, 1.0, SbxDOUBLE );
+ }
+ return pNd;
+ }
+
+ SbiToken eTok = (pKeywordSymbolInfo == NULL) ? pParser->Next() : pKeywordSymbolInfo->m_eTok;
+ // Anfang des Parsings merken
+ pParser->LockColumn();
+ String aSym( (pKeywordSymbolInfo == NULL) ? pParser->GetSym() : pKeywordSymbolInfo->m_aKeywordSymbol );
+ SbxDataType eType = (pKeywordSymbolInfo == NULL) ? pParser->GetType() : pKeywordSymbolInfo->m_eSbxDataType;
+ SbiParameters* pPar = NULL;
+ SbiExprListVector* pvMoreParLcl = NULL;
+ // Folgen Parameter?
+ SbiToken eNextTok = pParser->Peek();
+ // Ist es ein benannter Parameter?
+ // Dann einfach eine Stringkonstante erzeugen. Diese wird
+ // im SbiParameters-ctor erkannt und weiterverarbeitet
+ if( eNextTok == ASSIGN )
+ {
+ pParser->UnlockColumn();
+ return new SbiExprNode( pParser, aSym );
+ }
+ // ab hier sind keine Keywords zugelassen!
+ if( pParser->IsKwd( eTok ) )
+ {
+ if( pParser->IsCompatible() && eTok == INPUT )
+ {
+ eTok = SYMBOL;
+ }
+ else
+ {
+ pParser->Error( SbERR_SYNTAX );
+ bError = TRUE;
+ }
+ }
+
+ if( DoParametersFollow( pParser, eCurExpr, eTok = eNextTok ) )
+ {
+ bool bStandaloneExpression = (m_eMode == EXPRMODE_STANDALONE);
+ pPar = new SbiParameters( pParser, bStandaloneExpression );
+ bError |= !pPar->IsValid();
+ if( !bError )
+ bBracket = pPar->IsBracket();
+ eTok = pParser->Peek();
+
+ // i75443 check for additional sets of parameters
+ while( eTok == LPAREN )
+ {
+ if( pvMoreParLcl == NULL )
+ pvMoreParLcl = new SbiExprListVector();
+ SbiParameters* pAddPar = new SbiParameters( pParser );
+ pvMoreParLcl->push_back( pAddPar );
+ bError |= !pPar->IsValid();
+ eTok = pParser->Peek();
+ }
+ }
+ // Es koennte ein Objektteil sein, wenn . oder ! folgt
+ // Bei . muss aber die Variable bereits definiert sein; wenn pDef
+ // nach der Suche NULL ist, isses ein Objekt!
+ BOOL bObj = BOOL( ( eTok == DOT || eTok == EXCLAM )
+ && !pParser->WhiteSpace() );
+ if( bObj )
+ {
+ bBracket = FALSE; // Now the bracket for the first term is obsolete
+ if( eType == SbxVARIANT )
+ eType = SbxOBJECT;
+ else
+ {
+ // Name%. geht wirklich nicht!
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ }
+ // Suche:
+ SbiSymDef* pDef = pParser->pPool->Find( aSym );
+ if( !pDef )
+ {
+ // Teil der Runtime-Library?
+ // AB 31.3.1996: In Parser-Methode ausgelagert
+ // (wird auch in SbiParser::DefVar() in DIM.CXX benoetigt)
+ pDef = pParser->CheckRTLForSym( aSym, eType );
+
+ // #i109184: Check if symbol is or later will be defined inside module
+ SbModule& rMod = pParser->aGen.GetModule();
+ SbxArray* pModMethods = rMod.GetMethods();
+ if( pModMethods->Find( aSym, SbxCLASS_DONTCARE ) )
+ pDef = NULL;
+ }
+ if( !pDef )
+ {
+ // Falls ein Punkt angegeben war, isses Teil eines Objekts,
+ // also muss der Returnwert ein Objekt sein
+ if( bObj )
+ eType = SbxOBJECT;
+ pDef = AddSym( eTok, *pParser->pPool, eCurExpr, aSym, eType, pPar );
+ // Looks like this is a local ( but undefined variable )
+ // if it is in a static procedure then make this Symbol
+ // static
+ if ( !bObj && pParser->pProc && pParser->pProc->IsStatic() )
+ pDef->SetStatic();
+ }
+ else
+ {
+
+ // Symbol ist bereits definiert.
+ // Ist es eine Konstante?
+ SbiConstDef* pConst = pDef->GetConstDef();
+ if( pConst )
+ {
+ if( pConst->GetType() == SbxSTRING )
+ return new SbiExprNode( pParser, pConst->GetString() );
+ else
+ return new SbiExprNode( pParser, pConst->GetValue(), pConst->GetType() );
+ }
+ // Hat es Dimensionen,
+ // und sind auch Parameter angegeben?
+ // (Wobei 0 Parameter () entsprechen)
+ if( pDef->GetDims() )
+ {
+ if( pPar && pPar->GetSize() && pPar->GetSize() != pDef->GetDims() )
+ pParser->Error( SbERR_WRONG_DIMS );
+ }
+ if( pDef->IsDefinedAs() )
+ {
+ SbxDataType eDefType = pDef->GetType();
+ // #119187 Only error if types conflict
+ if( eType >= SbxINTEGER && eType <= SbxSTRING && eType != eDefType )
+ {
+ // Wie? Erst mit AS definieren und dann einen Suffix nehmen?
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ else if ( eType == SbxVARIANT )
+ // Falls nix angegeben, den Typ des Eintrags nehmen
+ // aber nur, wenn die Var nicht mit AS XXX definiert ist
+ // damit erwischen wir n% = 5 : print n
+ eType = eDefType;
+ }
+ // Typcheck bei Variablen:
+ // ist explizit im Scanner etwas anderes angegeben?
+ // Bei Methoden ist dies OK!
+ if( eType != SbxVARIANT && // Variant nimmt alles
+ eType != pDef->GetType() &&
+ !pDef->GetProcDef() )
+ {
+ // Es kann sein, dass pDef ein Objekt beschreibt, das bisher
+ // nur als SbxVARIANT erkannt wurde, dann Typ von pDef aendern
+ // AB, 16.12.95 (Vielleicht noch aehnliche Faelle moeglich ?!?)
+ if( eType == SbxOBJECT && pDef->GetType() == SbxVARIANT )
+ {
+ pDef->SetType( SbxOBJECT );
+ }
+ else
+ {
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ }
+ }
+ SbiExprNode* pNd = new SbiExprNode( pParser, *pDef, eType );
+ if( !pPar )
+ pPar = new SbiParameters( pParser,FALSE,FALSE );
+ pNd->aVar.pPar = pPar;
+ pNd->aVar.pvMorePar = pvMoreParLcl;
+ if( bObj )
+ {
+ // AB, 8.1.95: Objekt kann auch vom Typ SbxVARIANT sein
+ if( pDef->GetType() == SbxVARIANT )
+ pDef->SetType( SbxOBJECT );
+ // Falls wir etwas mit Punkt einscannen, muss der
+ // Typ SbxOBJECT sein
+ if( pDef->GetType() != SbxOBJECT && pDef->GetType() != SbxVARIANT )
+ {
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ if( !bError )
+ pNd->aVar.pNext = ObjTerm( *pDef );
+ }
+ // Merken der Spalte 1 wieder freigeben
+ pParser->UnlockColumn();
+ return pNd;
+}
+
+// Aufbau eines Objekt-Terms. Ein derartiger Term ist Teil
+// eines Ausdrucks, der mit einer Objektvariablen beginnt.
+
+SbiExprNode* SbiExpression::ObjTerm( SbiSymDef& rObj )
+{
+ pParser->Next();
+ SbiToken eTok = pParser->Next();
+ if( eTok != SYMBOL && !pParser->IsKwd( eTok ) && !pParser->IsExtra( eTok ) )
+ {
+ // #66745 Einige Operatoren koennen in diesem Kontext auch
+ // als Identifier zugelassen werden, wichtig fuer StarOne
+ if( eTok != MOD && eTok != NOT && eTok != AND && eTok != OR &&
+ eTok != XOR && eTok != EQV && eTok != IMP && eTok != IS )
+ {
+ pParser->Error( SbERR_VAR_EXPECTED );
+ bError = TRUE;
+ }
+ }
+ /* #118410 Allow type for Class methods and RTL object, e.g. RTL.Chr$(97)
+ else
+ {
+ if( pParser->GetType() != SbxVARIANT )
+ pParser->Error( SbERR_SYNTAX ), bError = TRUE;
+ }
+ */
+ if( bError )
+ return NULL;
+
+ String aSym( pParser->GetSym() );
+ SbxDataType eType = pParser->GetType();
+ SbiParameters* pPar = NULL;
+ SbiExprListVector* pvMoreParLcl = NULL;
+ eTok = pParser->Peek();
+ // Parameter?
+ if( DoParametersFollow( pParser, eCurExpr, eTok ) )
+ {
+ bool bStandaloneExpression = false;
+ pPar = new SbiParameters( pParser, bStandaloneExpression );
+ bError |= !pPar->IsValid();
+ eTok = pParser->Peek();
+
+ // i109624 check for additional sets of parameters
+ while( eTok == LPAREN )
+ {
+ if( pvMoreParLcl == NULL )
+ pvMoreParLcl = new SbiExprListVector();
+ SbiParameters* pAddPar = new SbiParameters( pParser );
+ pvMoreParLcl->push_back( pAddPar );
+ bError |= !pPar->IsValid();
+ eTok = pParser->Peek();
+ }
+
+ }
+ BOOL bObj = BOOL( ( eTok == DOT || eTok == EXCLAM ) && !pParser->WhiteSpace() );
+ if( bObj )
+ {
+ if( eType == SbxVARIANT )
+ eType = SbxOBJECT;
+ else
+ {
+ // Name%. geht wirklich nicht!
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ }
+
+ // Der Symbol-Pool eines Objekts ist immer PUBLIC
+ SbiSymPool& rPool = rObj.GetPool();
+ rPool.SetScope( SbPUBLIC );
+ SbiSymDef* pDef = rPool.Find( aSym );
+ if( !pDef )
+ {
+ pDef = AddSym( eTok, rPool, eCurExpr, aSym, eType, pPar );
+ pDef->SetType( eType );
+ }
+
+ SbiExprNode* pNd = new SbiExprNode( pParser, *pDef, eType );
+ pNd->aVar.pPar = pPar;
+ pNd->aVar.pvMorePar = pvMoreParLcl;
+ if( bObj )
+ {
+ // Falls wir etwas mit Punkt einscannen, muss der
+ // Typ SbxOBJECT sein
+
+ // AB, 3.1.96
+ // Es kann sein, dass pDef ein Objekt beschreibt, das bisher
+ // nur als SbxVARIANT erkannt wurde, dann Typ von pDef aendern
+ if( pDef->GetType() == SbxVARIANT )
+ pDef->SetType( SbxOBJECT );
+
+ if( pDef->GetType() != SbxOBJECT )
+ {
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ if( !bError )
+ {
+ pNd->aVar.pNext = ObjTerm( *pDef );
+ pNd->eType = eType;
+ }
+ }
+ return pNd;
+}
+
+// Als Operanden kommen in Betracht:
+// Konstante
+// skalare Variable
+// Strukturelemente
+// Array-Elemente
+// Funktionen
+// geklammerte Ausdruecke
+
+SbiExprNode* SbiExpression::Operand( bool bUsedForTypeOf )
+{
+ SbiExprNode *pRes;
+ SbiToken eTok;
+
+ // Operand testen:
+ switch( eTok = pParser->Peek() )
+ {
+ case SYMBOL:
+ pRes = Term();
+ // process something like "IF Not r Is Nothing Then .."
+ if( !bUsedForTypeOf && pParser->IsVBASupportOn() && pParser->Peek() == IS )
+ {
+ eTok = pParser->Next();
+ pRes = new SbiExprNode( pParser, pRes, eTok, Like() );
+ }
+ break;
+ case DOT: // .with
+ pRes = Term(); break;
+ case NUMBER:
+ pParser->Next();
+ pRes = new SbiExprNode( pParser, pParser->GetDbl(), pParser->GetType() );
+ break;
+ case FIXSTRING:
+ pParser->Next();
+ pRes = new SbiExprNode( pParser, pParser->GetSym() ); break;
+ case LPAREN:
+ pParser->Next();
+ if( nParenLevel == 0 && m_eMode == EXPRMODE_LPAREN_PENDING && pParser->Peek() == RPAREN )
+ {
+ m_eMode = EXPRMODE_EMPTY_PAREN;
+ pRes = new SbiExprNode(); // Dummy node
+ pParser->Next();
+ break;
+ }
+ nParenLevel++;
+ pRes = Boolean();
+ if( pParser->Peek() != RPAREN )
+ {
+ // If there was a LPARAM, it does not belong to the expression
+ if( nParenLevel == 1 && m_eMode == EXPRMODE_LPAREN_PENDING )
+ m_eMode = EXPRMODE_LPAREN_NOT_NEEDED;
+ else
+ pParser->Error( SbERR_BAD_BRACKETS );
+ }
+ else
+ {
+ pParser->Next();
+ if( nParenLevel == 1 && m_eMode == EXPRMODE_LPAREN_PENDING )
+ {
+ SbiToken eTokAfterRParen = pParser->Peek();
+ if( eTokAfterRParen == EQ || eTokAfterRParen == LPAREN || eTokAfterRParen == DOT )
+ m_eMode = EXPRMODE_ARRAY_OR_OBJECT;
+ else
+ m_eMode = EXPRMODE_STANDARD;
+ }
+ }
+ nParenLevel--;
+ pRes->bComposite = TRUE;
+ break;
+ default:
+ // Zur Zeit sind Keywords hier OK!
+ if( pParser->IsKwd( eTok ) )
+ pRes = Term();
+ else
+ {
+ pParser->Next();
+ pRes = new SbiExprNode( pParser, 1.0, SbxDOUBLE ); // bei Fehlern
+ pParser->Error( SbERR_UNEXPECTED, eTok );
+ }
+ }
+ return pRes;
+}
+
+SbiExprNode* SbiExpression::Unary()
+{
+ SbiExprNode* pNd;
+ SbiToken eTok = pParser->Peek();
+ switch( eTok )
+ {
+ case MINUS:
+ eTok = NEG;
+ case NOT:
+ pParser->Next();
+ pNd = new SbiExprNode( pParser, Unary(), eTok, NULL );
+ break;
+ case PLUS:
+ pParser->Next();
+ pNd = Unary();
+ break;
+ case TYPEOF:
+ {
+ pParser->Next();
+ bool bUsedForTypeOf = true;
+ SbiExprNode* pObjNode = Operand( bUsedForTypeOf );
+ pParser->TestToken( IS );
+ String aDummy;
+ SbiSymDef* pTypeDef = new SbiSymDef( aDummy );
+ pParser->TypeDecl( *pTypeDef, TRUE );
+ pNd = new SbiExprNode( pParser, pObjNode, pTypeDef->GetTypeId() );
+ break;
+ }
+ case NEW:
+ {
+ pParser->Next();
+ String aStr;
+ SbiSymDef* pTypeDef = new SbiSymDef( aStr );
+ pParser->TypeDecl( *pTypeDef, TRUE );
+ pNd = new SbiExprNode( pParser, pTypeDef->GetTypeId() );
+ break;
+ }
+ default:
+ pNd = Operand();
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Exp()
+{
+ SbiExprNode* pNd = Unary();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ while( pParser->Peek() == EXPON ) {
+ SbiToken eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Unary() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::MulDiv()
+{
+ SbiExprNode* pNd = Exp();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( eTok != MUL && eTok != DIV )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Exp() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::IntDiv()
+{
+ SbiExprNode* pNd = MulDiv();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ while( pParser->Peek() == IDIV ) {
+ SbiToken eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, MulDiv() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Mod()
+{
+ SbiExprNode* pNd = IntDiv();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ while( pParser->Peek() == MOD ) {
+ SbiToken eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, IntDiv() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::AddSub()
+{
+ SbiExprNode* pNd = Mod();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( eTok != PLUS && eTok != MINUS )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Mod() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Cat()
+{
+ SbiExprNode* pNd = AddSub();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( eTok != CAT )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, AddSub() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Comp()
+{
+ SbiExprNode* pNd = Cat();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ short nCount = 0;
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( m_eMode == EXPRMODE_ARRAY_OR_OBJECT )
+ break;
+ if( eTok != EQ && eTok != NE && eTok != LT
+ && eTok != GT && eTok != LE && eTok != GE )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Cat() );
+ nCount++;
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Like()
+{
+ SbiExprNode* pNd = Comp();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ short nCount = 0;
+ while( pParser->Peek() == LIKE ) {
+ SbiToken eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Comp() ), nCount++;
+ }
+ // Mehrere Operatoren hintereinander gehen nicht
+ if( nCount > 1 )
+ {
+ pParser->Error( SbERR_SYNTAX );
+ bError = TRUE;
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Boolean()
+{
+ SbiExprNode* pNd = Like();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( eTok != AND && eTok != OR && eTok != XOR
+ && eTok != EQV && eTok != IMP && eTok != IS )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Like() );
+ }
+ }
+ return pNd;
+}
+
+/***************************************************************************
+|*
+|* SbiConstExpression
+|*
+***************************************************************************/
+
+// Parsing einer Expression, die sich zu einer numerischen
+// Konstanten verarbeiten laesst.
+
+SbiConstExpression::SbiConstExpression( SbiParser* p ) : SbiExpression( p )
+{
+ if( pExpr->IsConstant() )
+ {
+ eType = pExpr->GetType();
+ if( pExpr->IsNumber() )
+ {
+ nVal = pExpr->nVal;
+ }
+ else
+ {
+ nVal = 0;
+ aVal = pExpr->aStrVal;
+ }
+ }
+ else
+ {
+ // #40204 Spezialbehandlung fuer BOOL-Konstanten
+ BOOL bIsBool = FALSE;
+ if( pExpr->eNodeType == SbxVARVAL )
+ {
+ SbiSymDef* pVarDef = pExpr->GetVar();
+
+ // Ist es eine BOOL-Konstante?
+ BOOL bBoolVal = FALSE;
+ if( pVarDef->GetName().EqualsIgnoreCaseAscii( "true" ) )
+ //if( pVarDef->GetName().ICompare( "true" ) == COMPARE_EQUAL )
+ {
+ bIsBool = TRUE;
+ bBoolVal = TRUE;
+ }
+ else if( pVarDef->GetName().EqualsIgnoreCaseAscii( "false" ) )
+ //else if( pVarDef->GetName().ICompare( "false" ) == COMPARE_EQUAL )
+ {
+ bIsBool = TRUE;
+ bBoolVal = FALSE;
+ }
+
+ // Wenn es ein BOOL ist, Node austauschen
+ if( bIsBool )
+ {
+ delete pExpr;
+ pExpr = new SbiExprNode( pParser, (bBoolVal ? SbxTRUE : SbxFALSE), SbxINTEGER );
+ eType = pExpr->GetType();
+ nVal = pExpr->nVal;
+ }
+ }
+
+ if( !bIsBool )
+ {
+ pParser->Error( SbERR_SYNTAX );
+ eType = SbxDOUBLE;
+ nVal = 0;
+ }
+ }
+}
+
+short SbiConstExpression::GetShortValue()
+{
+ if( eType == SbxSTRING )
+ {
+ SbxVariableRef refConv = new SbxVariable;
+ refConv->PutString( aVal );
+ return refConv->GetInteger();
+ }
+ else
+ {
+ double n = nVal;
+ if( n > 0 ) n += .5; else n -= .5;
+ if( n > SbxMAXINT ) n = SbxMAXINT, pParser->Error( SbERR_OUT_OF_RANGE );
+ else
+ if( n < SbxMININT ) n = SbxMININT, pParser->Error( SbERR_OUT_OF_RANGE );
+ return (short) n;
+ }
+}
+
+
+/***************************************************************************
+|*
+|* SbiExprList
+|*
+***************************************************************************/
+
+SbiExprList::SbiExprList( SbiParser* p )
+{
+ pParser = p;
+ pFirst = NULL;
+ nExpr =
+ nDim = 0;
+ bError =
+ bBracket = FALSE;
+}
+
+SbiExprList::~SbiExprList()
+{
+ SbiExpression* p = pFirst;
+ while( p )
+ {
+ SbiExpression* q = p->pNext;
+ delete p;
+ p = q;
+ }
+}
+
+// Parameter anfordern (ab 0)
+
+SbiExpression* SbiExprList::Get( short n )
+{
+ SbiExpression* p = pFirst;
+ while( n-- && p )
+ p = p->pNext;
+ return p;
+}
+
+void SbiExprList::addExpression( SbiExpression* pExpr )
+{
+ SbiExpression* p = pFirst;
+ while( p && p->pNext )
+ p = p->pNext;
+
+ p->pNext = pExpr;
+}
+
+
+/***************************************************************************
+|*
+|* SbiParameters
+|*
+***************************************************************************/
+
+// Parsender Konstruktor:
+// Die Parameterliste wird komplett geparst.
+// "Prozedurname()" ist OK.
+// Dann handelt es sich um eine Funktion ohne Parameter
+// respektive um die Angabe eines Arrays als Prozedurparameter.
+
+// #i79918/#i80532: bConst has never been set to true
+// -> reused as bStandaloneExpression
+//SbiParameters::SbiParameters( SbiParser* p, BOOL bConst, BOOL bPar) :
+SbiParameters::SbiParameters( SbiParser* p, BOOL bStandaloneExpression, BOOL bPar) :
+ SbiExprList( p )
+{
+ if( !bPar )
+ return;
+
+ SbiExpression *pExpr;
+ SbiToken eTok = pParser->Peek();
+
+ // evtl. Klammer auf weg:
+ bool bAssumeExprLParenMode = false;
+ bool bAssumeArrayMode = false;
+ if( eTok == LPAREN )
+ {
+ if( bStandaloneExpression )
+ {
+ bAssumeExprLParenMode = true;
+ }
+ else
+ {
+ bBracket = TRUE;
+ pParser->Next();
+ eTok = pParser->Peek();
+ }
+ }
+
+ // Ende-Test
+ if( ( bBracket && eTok == RPAREN ) || pParser->IsEoln( eTok ) )
+ {
+ if( eTok == RPAREN )
+ pParser->Next();
+ return;
+ }
+ // Parametertabelle einlesen und in richtiger Folge ablegen!
+ SbiExpression* pLast = NULL;
+ String aName;
+ while( !bError )
+ {
+ aName.Erase();
+ // Fehlendes Argument
+ if( eTok == COMMA )
+ {
+ pExpr = new SbiExpression( pParser, 0, SbxEMPTY );
+ //if( bConst )
+ // pParser->Error( SbERR_SYNTAX ), bError = TRUE;
+ }
+ // Benannte Argumente: entweder .name= oder name:=
+ else
+ {
+ bool bByVal = false;
+ if( eTok == BYVAL )
+ {
+ bByVal = true;
+ pParser->Next();
+ eTok = pParser->Peek();
+ }
+
+ if( bAssumeExprLParenMode )
+ {
+ pExpr = new SbiExpression( pParser, SbSTDEXPR, EXPRMODE_LPAREN_PENDING );
+ bAssumeExprLParenMode = FALSE;
+
+ SbiExprMode eModeAfter = pExpr->m_eMode;
+ if( eModeAfter == EXPRMODE_LPAREN_NOT_NEEDED )
+ {
+ bBracket = TRUE;
+ }
+ else if( eModeAfter == EXPRMODE_ARRAY_OR_OBJECT )
+ {
+ // Expression "looks" like an array assignment
+ // a(...)[(...)] = ? or a(...).b(...)
+ // RPAREN is already parsed
+ bBracket = TRUE;
+ bAssumeArrayMode = true;
+ eTok = NIL;
+ }
+ else if( eModeAfter == EXPRMODE_EMPTY_PAREN )
+ {
+ bBracket = TRUE;
+ delete pExpr;
+ if( bByVal )
+ pParser->Error( SbERR_LVALUE_EXPECTED );
+ return;
+ }
+ }
+ else
+ pExpr = new SbiExpression( pParser );
+
+ if( bByVal && pExpr->IsLvalue() )
+ pExpr->SetByVal();
+
+ //pExpr = bConst ? new SbiConstExpression( pParser )
+ // : new SbiExpression( pParser );
+ if( !bAssumeArrayMode )
+ {
+ if( pParser->Peek() == ASSIGN )
+ {
+ // VBA mode: name:=
+ // SbiExpression::Term() hat einen String daraus gemacht
+ aName = pExpr->GetString();
+ delete pExpr;
+ pParser->Next();
+ pExpr = new SbiExpression( pParser );
+ //if( bConst )
+ // pParser->Error( SbERR_SYNTAX ), bError = TRUE;
+ }
+ pExpr->GetName() = aName;
+ }
+ }
+ pExpr->pNext = NULL;
+ if( !pLast )
+ pFirst = pLast = pExpr;
+ else
+ pLast->pNext = pExpr, pLast = pExpr;
+ nExpr++;
+ bError |= !pExpr->IsValid();
+
+ if( bAssumeArrayMode )
+ break;
+
+ // Naechstes Element?
+ eTok = pParser->Peek();
+ if( eTok != COMMA )
+ {
+ if( ( bBracket && eTok == RPAREN ) || pParser->IsEoln( eTok ) )
+ break;
+ pParser->Error( bBracket
+ ? SbERR_BAD_BRACKETS
+ : SbERR_EXPECTED, COMMA );
+ bError = TRUE;
+ }
+ else
+ {
+ pParser->Next();
+ eTok = pParser->Peek();
+ if( ( bBracket && eTok == RPAREN ) || pParser->IsEoln( eTok ) )
+ break;
+ }
+ }
+ // Schliessende Klammer
+ if( eTok == RPAREN )
+ {
+ pParser->Next();
+ pParser->Peek();
+ if( !bBracket )
+ {
+ pParser->Error( SbERR_BAD_BRACKETS );
+ bError = TRUE;
+ }
+ }
+ nDim = nExpr;
+}
+
+/***************************************************************************
+|*
+|* SbiDimList
+|*
+***************************************************************************/
+
+// Parsender Konstruktor:
+// Eine Liste von Array-Dimensionen wird geparst. Die Ausdruecke werden
+// auf numerisch getestet. Das bCONST-Bit wird gesetzt, wenn alle Ausdruecke
+// Integer-Konstanten sind.
+
+SbiDimList::SbiDimList( SbiParser* p ) : SbiExprList( p )
+{
+ bConst = TRUE;
+
+ if( pParser->Next() != LPAREN )
+ {
+ pParser->Error( SbERR_EXPECTED, LPAREN );
+ bError = TRUE; return;
+ }
+
+ if( pParser->Peek() != RPAREN )
+ {
+ SbiExpression *pExpr1, *pExpr2, *pLast = NULL;
+ SbiToken eTok;
+ for( ;; )
+ {
+ pExpr1 = new SbiExpression( pParser );
+ eTok = pParser->Next();
+ if( eTok == TO )
+ {
+ pExpr2 = new SbiExpression( pParser );
+ eTok = pParser->Next();
+ bConst &= pExpr1->IsIntConstant() & pExpr2->IsIntConstant();
+ bError |= !pExpr1->IsValid();
+ bError |= !pExpr2->IsValid();
+ pExpr1->pNext = pExpr2;
+ if( !pLast )
+ pFirst = pExpr1;
+ else
+ pLast->pNext = pExpr1;
+ pLast = pExpr2;
+ nExpr += 2;
+ }
+ else
+ {
+ // Nur eine Dim-Angabe
+ pExpr1->SetBased();
+ pExpr1->pNext = NULL;
+ bConst &= pExpr1->IsIntConstant();
+ bError |= !pExpr1->IsValid();
+ if( !pLast )
+ pFirst = pLast = pExpr1;
+ else
+ pLast->pNext = pExpr1, pLast = pExpr1;
+ nExpr++;
+ }
+ nDim++;
+ if( eTok == RPAREN ) break;
+ if( eTok != COMMA )
+ {
+ pParser->Error( SbERR_BAD_BRACKETS );
+ pParser->Next();
+ break;
+ }
+ }
+ }
+ else pParser->Next();
+}
+
diff --git a/basic/source/comp/io.cxx b/basic/source/comp/io.cxx
new file mode 100644
index 000000000000..b211ea0b7b08
--- /dev/null
+++ b/basic/source/comp/io.cxx
@@ -0,0 +1,358 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+
+#include <tools/stream.hxx>
+#include "sbcomp.hxx"
+#include "iosys.hxx"
+
+// Test, ob ein I/O-Channel angegeben wurde
+
+BOOL SbiParser::Channel( BOOL bAlways )
+{
+ BOOL bRes = FALSE;
+ Peek();
+ if( IsHash() )
+ {
+ SbiExpression aExpr( this );
+ while( Peek() == COMMA || Peek() == SEMICOLON )
+ Next();
+ aExpr.Gen();
+ aGen.Gen( _CHANNEL );
+ bRes = TRUE;
+ }
+ else if( bAlways )
+ Error( SbERR_EXPECTED, "#" );
+ return bRes;
+}
+
+// Fuer PRINT und WRITE wird bei Objektvariablen versucht,
+// die Default-Property anzusprechen.
+
+// PRINT
+
+void SbiParser::Print()
+{
+ BOOL bChan = Channel();
+ // Die Ausdruecke zum Drucken:
+ while( !bAbort )
+ {
+ if( !IsEoln( Peek() ) )
+ {
+ SbiExpression* pExpr = new SbiExpression( this );
+ pExpr->Gen();
+ delete pExpr;
+ Peek();
+ aGen.Gen( eCurTok == COMMA ? _PRINTF : _BPRINT );
+ }
+ if( eCurTok == COMMA || eCurTok == SEMICOLON )
+ {
+ Next();
+ if( IsEoln( Peek() ) ) break;
+ }
+ else
+ {
+ aGen.Gen( _PRCHAR, '\n' );
+ break;
+ }
+ }
+ if( bChan )
+ aGen.Gen( _CHAN0 );
+}
+
+// WRITE #chan, expr, ...
+
+void SbiParser::Write()
+{
+ BOOL bChan = Channel();
+ // Die Ausdruecke zum Drucken:
+ while( !bAbort )
+ {
+ SbiExpression* pExpr = new SbiExpression( this );
+ pExpr->Gen();
+ delete pExpr;
+ aGen.Gen( _BWRITE );
+ if( Peek() == COMMA )
+ {
+ aGen.Gen( _PRCHAR, ',' );
+ Next();
+ if( IsEoln( Peek() ) ) break;
+ }
+ else
+ {
+ aGen.Gen( _PRCHAR, '\n' );
+ break;
+ }
+ }
+ if( bChan )
+ aGen.Gen( _CHAN0 );
+}
+
+
+// #i92642 Handle LINE keyword outside ::Next()
+void SbiParser::Line()
+{
+ // #i92642: Special handling to allow name as symbol
+ if( Peek() == INPUT )
+ {
+ Next();
+ LineInput();
+ }
+ else
+ {
+ aGen.Statement();
+
+ KeywordSymbolInfo aInfo;
+ aInfo.m_aKeywordSymbol = String( RTL_CONSTASCII_USTRINGPARAM( "line" ) );
+ aInfo.m_eSbxDataType = GetType();
+ aInfo.m_eTok = SYMBOL;
+
+ Symbol( &aInfo );
+ }
+}
+
+
+// LINE INPUT [prompt], var$
+
+void SbiParser::LineInput()
+{
+ Channel( TRUE );
+ // BOOL bChan = Channel( TRUE );
+ SbiExpression* pExpr = new SbiExpression( this, SbOPERAND );
+ /* AB 15.1.96: Keinen allgemeinen Ausdruck mehr zulassen
+ SbiExpression* pExpr = new SbiExpression( this );
+ if( !pExpr->IsVariable() )
+ {
+ SbiToken eTok = Peek();
+ if( eTok == COMMA || eTok == SEMICOLON ) Next();
+ else Error( SbERR_EXPECTED, COMMA );
+ // mit Prompt
+ if( !bChan )
+ {
+ pExpr->Gen();
+ aGen.Gen( _PROMPT );
+ }
+ else
+ Error( SbERR_VAR_EXPECTED );
+ delete pExpr;
+ pExpr = new SbiExpression( this, SbOPERAND );
+ }
+ */
+ if( !pExpr->IsVariable() )
+ Error( SbERR_VAR_EXPECTED );
+ if( pExpr->GetType() != SbxVARIANT && pExpr->GetType() != SbxSTRING )
+ Error( SbERR_CONVERSION );
+ pExpr->Gen();
+ aGen.Gen( _LINPUT );
+ delete pExpr;
+ aGen.Gen( _CHAN0 ); // ResetChannel() nicht mehr in StepLINPUT()
+}
+
+// INPUT
+
+void SbiParser::Input()
+{
+ aGen.Gen( _RESTART );
+ Channel( TRUE );
+ // BOOL bChan = Channel( TRUE );
+ SbiExpression* pExpr = new SbiExpression( this, SbOPERAND );
+ /* ALT: Jetzt keinen allgemeinen Ausdruck mehr zulassen
+ SbiExpression* pExpr = new SbiExpression( this );
+ ...
+ siehe LineInput
+ */
+ while( !bAbort )
+ {
+ if( !pExpr->IsVariable() )
+ Error( SbERR_VAR_EXPECTED );
+ pExpr->Gen();
+ aGen.Gen( _INPUT );
+ if( Peek() == COMMA )
+ {
+ Next();
+ delete pExpr;
+ pExpr = new SbiExpression( this, SbOPERAND );
+ }
+ else break;
+ }
+ delete pExpr;
+ aGen.Gen( _CHAN0 ); // ResetChannel() nicht mehr in StepINPUT()
+}
+
+// OPEN stringexpr FOR mode ACCCESS access mode AS Channel [Len=n]
+
+void SbiParser::Open()
+{
+ SbiExpression aFileName( this );
+ SbiToken eTok;
+ TestToken( FOR );
+ short nMode = 0;
+ short nFlags = 0;
+ switch( Next() )
+ {
+ case INPUT:
+ nMode = STREAM_READ; nFlags |= SBSTRM_INPUT; break;
+ case OUTPUT:
+ nMode = STREAM_WRITE | STREAM_TRUNC; nFlags |= SBSTRM_OUTPUT; break;
+ case APPEND:
+ nMode = STREAM_WRITE; nFlags |= SBSTRM_APPEND; break;
+ case RANDOM:
+ nMode = STREAM_READ | STREAM_WRITE; nFlags |= SBSTRM_RANDOM; break;
+ case BINARY:
+ nMode = STREAM_READ | STREAM_WRITE; nFlags |= SBSTRM_BINARY; break;
+ default:
+ Error( SbERR_SYNTAX );
+ }
+ if( Peek() == ACCESS )
+ {
+ Next();
+ eTok = Next();
+ // #27964# Nur STREAM_READ,STREAM_WRITE-Flags in nMode beeinflussen
+ nMode &= ~(STREAM_READ | STREAM_WRITE); // loeschen
+ if( eTok == READ )
+ {
+ if( Peek() == WRITE )
+ {
+ Next();
+ nMode |= (STREAM_READ | STREAM_WRITE);
+ }
+ else
+ nMode |= STREAM_READ;
+ }
+ else if( eTok == WRITE )
+ nMode |= STREAM_WRITE;
+ else
+ Error( SbERR_SYNTAX );
+ }
+ switch( Peek() )
+ {
+#ifdef SHARED
+#undef SHARED
+#define tmpSHARED
+#endif
+ case SHARED:
+ Next(); nMode |= STREAM_SHARE_DENYNONE; break;
+#ifdef tmpSHARED
+#define SHARED
+#undef tmpSHARED
+#endif
+ case LOCK:
+ Next();
+ eTok = Next();
+ if( eTok == READ )
+ {
+ if( Peek() == WRITE ) Next(), nMode |= STREAM_SHARE_DENYALL;
+ else nMode |= STREAM_SHARE_DENYREAD;
+ }
+ else if( eTok == WRITE )
+ nMode |= STREAM_SHARE_DENYWRITE;
+ else
+ Error( SbERR_SYNTAX );
+ break;
+ default: break;
+ }
+ TestToken( AS );
+ // Die Kanalnummer
+ SbiExpression* pChan = new SbiExpression( this );
+ if( !pChan )
+ Error( SbERR_SYNTAX );
+ SbiExpression* pLen = NULL;
+ if( Peek() == SYMBOL )
+ {
+ Next();
+ String aLen( aSym );
+ if( aLen.EqualsIgnoreCaseAscii( "LEN" ) )
+ {
+ TestToken( EQ );
+ pLen = new SbiExpression( this );
+ }
+ }
+ if( !pLen ) pLen = new SbiExpression( this, 128, SbxINTEGER );
+ // Der Stack fuer den OPEN-Befehl sieht wie folgt aus:
+ // Blocklaenge
+ // Kanalnummer
+ // Dateiname
+ pLen->Gen();
+ if( pChan )
+ pChan->Gen();
+ aFileName.Gen();
+ aGen.Gen( _OPEN, nMode, nFlags );
+ delete pLen;
+ delete pChan;
+}
+
+// NAME file AS file
+
+void SbiParser::Name()
+{
+ // #i92642: Special handling to allow name as symbol
+ if( Peek() == EQ )
+ {
+ aGen.Statement();
+
+ KeywordSymbolInfo aInfo;
+ aInfo.m_aKeywordSymbol = String( RTL_CONSTASCII_USTRINGPARAM( "name" ) );
+ aInfo.m_eSbxDataType = GetType();
+ aInfo.m_eTok = SYMBOL;
+
+ Symbol( &aInfo );
+ return;
+ }
+ SbiExpression aExpr1( this );
+ TestToken( AS );
+ SbiExpression aExpr2( this );
+ aExpr1.Gen();
+ aExpr2.Gen();
+ aGen.Gen( _RENAME );
+}
+
+// CLOSE [n,...]
+
+void SbiParser::Close()
+{
+ Peek();
+ if( IsEoln( eCurTok ) )
+ aGen.Gen( _CLOSE, 0 );
+ else
+ for( ;; )
+ {
+ SbiExpression aExpr( this );
+ while( Peek() == COMMA || Peek() == SEMICOLON )
+ Next();
+ aExpr.Gen();
+ aGen.Gen( _CHANNEL );
+ aGen.Gen( _CLOSE, 1 );
+
+ if( IsEoln( Peek() ) )
+ break;
+ }
+}
+
+
diff --git a/basic/source/comp/loops.cxx b/basic/source/comp/loops.cxx
new file mode 100644
index 000000000000..bd4540a8ffde
--- /dev/null
+++ b/basic/source/comp/loops.cxx
@@ -0,0 +1,558 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include "sbcomp.hxx"
+
+// Single-line IF und Multiline IF
+
+void SbiParser::If()
+{
+ UINT32 nEndLbl;
+ SbiToken eTok = NIL;
+ // Ende-Tokens ignorieren:
+ SbiExpression aCond( this );
+ aCond.Gen();
+ TestToken( THEN );
+ if( IsEoln( Next() ) )
+ {
+ // AB 13.5.1996: #27720# Am Ende jeden Blocks muss ein Jump zu ENDIF
+ // eingefuegt werden, damit bei ELSEIF nicht erneut die Bedingung
+ // ausgewertet wird. Die Tabelle nimmt alle Absprungstellen auf.
+#define JMP_TABLE_SIZE 100
+ UINT32 pnJmpToEndLbl[JMP_TABLE_SIZE]; // 100 ELSEIFs zulaessig
+ USHORT iJmp = 0; // aktueller Tabellen-Index
+
+ // multiline IF
+ nEndLbl = aGen.Gen( _JUMPF, 0 );
+ eTok = Peek();
+ while( !( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) &&
+ !bAbort && Parse() )
+ {
+ eTok = Peek();
+ if( IsEof() )
+ {
+ Error( SbERR_BAD_BLOCK, IF ); bAbort = TRUE; return;
+ }
+ }
+ // ELSEIF?
+ while( eTok == ELSEIF )
+ {
+ // #27720# Bei erfolgreichem IF/ELSEIF auf ENDIF springen
+ if( iJmp >= JMP_TABLE_SIZE )
+ {
+ Error( SbERR_PROG_TOO_LARGE ); bAbort = TRUE; return;
+ }
+ pnJmpToEndLbl[iJmp++] = aGen.Gen( _JUMP, 0 );
+
+ Next();
+ aGen.BackChain( nEndLbl );
+
+ aGen.Statement();
+ SbiExpression* pCond = new SbiExpression( this );
+ pCond->Gen();
+ nEndLbl = aGen.Gen( _JUMPF, 0 );
+ delete pCond;
+ TestToken( THEN );
+ eTok = Peek();
+ while( !( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) &&
+ !bAbort && Parse() )
+ {
+ eTok = Peek();
+ if( IsEof() )
+ {
+ Error( SbERR_BAD_BLOCK, ELSEIF ); bAbort = TRUE; return;
+ }
+ }
+ }
+ if( eTok == ELSE )
+ {
+ Next();
+ UINT32 nElseLbl = nEndLbl;
+ nEndLbl = aGen.Gen( _JUMP, 0 );
+ aGen.BackChain( nElseLbl );
+
+ aGen.Statement();
+ StmntBlock( ENDIF );
+ }
+ else if( eTok == ENDIF )
+ Next();
+
+ // #27720# Jmp-Tabelle abarbeiten
+ while( iJmp > 0 )
+ {
+ iJmp--;
+ aGen.BackChain( pnJmpToEndLbl[iJmp] );
+ }
+ }
+ else
+ {
+ // single line IF
+ bSingleLineIf = TRUE;
+ nEndLbl = aGen.Gen( _JUMPF, 0 );
+ Push( eCurTok );
+ while( !bAbort )
+ {
+ if( !Parse() ) break;
+ eTok = Peek();
+ if( eTok == ELSE || eTok == EOLN || eTok == REM )
+ break;
+ }
+ if( eTok == ELSE )
+ {
+ Next();
+ UINT32 nElseLbl = nEndLbl;
+ nEndLbl = aGen.Gen( _JUMP, 0 );
+ aGen.BackChain( nElseLbl );
+ while( !bAbort )
+ {
+ if( !Parse() ) break;
+ eTok = Peek();
+ if( eTok == EOLN )
+ break;
+ }
+ }
+ bSingleLineIf = FALSE;
+ }
+ aGen.BackChain( nEndLbl );
+}
+
+// ELSE/ELSEIF/ENDIF ohne IF
+
+void SbiParser::NoIf()
+{
+ Error( SbERR_NO_IF );
+ StmntBlock( ENDIF );
+}
+
+// DO WHILE...LOOP
+// DO ... LOOP WHILE
+
+void SbiParser::DoLoop()
+{
+ UINT32 nStartLbl = aGen.GetPC();
+ OpenBlock( DO );
+ SbiToken eTok = Next();
+ if( IsEoln( eTok ) )
+ {
+ // DO ... LOOP [WHILE|UNTIL expr]
+ StmntBlock( LOOP );
+ eTok = Next();
+ if( eTok == UNTIL || eTok == WHILE )
+ {
+ SbiExpression aExpr( this );
+ aExpr.Gen();
+ aGen.Gen( eTok == UNTIL ? _JUMPF : _JUMPT, nStartLbl );
+ } else
+ if (eTok == EOLN || eTok == REM)
+ aGen.Gen (_JUMP, nStartLbl);
+ else
+ Error( SbERR_EXPECTED, WHILE );
+ }
+ else
+ {
+ // DO [WHILE|UNTIL expr] ... LOOP
+ if( eTok == UNTIL || eTok == WHILE )
+ {
+ SbiExpression aCond( this );
+ aCond.Gen();
+ }
+ UINT32 nEndLbl = aGen.Gen( eTok == UNTIL ? _JUMPT : _JUMPF, 0 );
+ StmntBlock( LOOP );
+ TestEoln();
+ aGen.Gen( _JUMP, nStartLbl );
+ aGen.BackChain( nEndLbl );
+ }
+ CloseBlock();
+}
+
+// WHILE ... WEND
+
+void SbiParser::While()
+{
+ SbiExpression aCond( this );
+ UINT32 nStartLbl = aGen.GetPC();
+ aCond.Gen();
+ UINT32 nEndLbl = aGen.Gen( _JUMPF, 0 );
+ StmntBlock( WEND );
+ aGen.Gen( _JUMP, nStartLbl );
+ aGen.BackChain( nEndLbl );
+}
+
+// FOR var = expr TO expr STEP
+
+void SbiParser::For()
+{
+ bool bForEach = ( Peek() == EACH );
+ if( bForEach )
+ Next();
+ SbiExpression aLvalue( this, SbOPERAND );
+ aLvalue.Gen(); // Variable auf dem Stack
+
+ if( bForEach )
+ {
+ TestToken( _IN_ );
+ SbiExpression aCollExpr( this, SbOPERAND );
+ aCollExpr.Gen(); // Colletion var to for stack
+ TestEoln();
+ aGen.Gen( _INITFOREACH );
+ }
+ else
+ {
+ TestToken( EQ );
+ SbiExpression aStartExpr( this );
+ aStartExpr.Gen(); // Startausdruck auf dem Stack
+ TestToken( TO );
+ SbiExpression aStopExpr( this );
+ aStopExpr.Gen(); // Endausdruck auf dem Stack
+ if( Peek() == STEP )
+ {
+ Next();
+ SbiExpression aStepExpr( this );
+ aStepExpr.Gen();
+ }
+ else
+ {
+ SbiExpression aOne( this, 1, SbxINTEGER );
+ aOne.Gen();
+ }
+ TestEoln();
+ // Der Stack hat jetzt 4 Elemente: Variable, Start, Ende, Inkrement
+ // Startwert binden
+ aGen.Gen( _INITFOR );
+ }
+
+ UINT32 nLoop = aGen.GetPC();
+ // Test durchfuehren, evtl. Stack freigeben
+ UINT32 nEndTarget = aGen.Gen( _TESTFOR, 0 );
+ OpenBlock( FOR );
+ StmntBlock( NEXT );
+ aGen.Gen( _NEXT );
+ aGen.Gen( _JUMP, nLoop );
+ // Kommen Variable nach NEXT?
+ if( Peek() == SYMBOL )
+ {
+ SbiExpression aVar( this, SbOPERAND );
+ if( aVar.GetRealVar() != aLvalue.GetRealVar() )
+ Error( SbERR_EXPECTED, aLvalue.GetRealVar()->GetName() );
+ }
+ aGen.BackChain( nEndTarget );
+ CloseBlock();
+}
+
+// WITH .. END WITH
+
+void SbiParser::With()
+{
+ SbiExpression aVar( this, SbOPERAND );
+
+ // Letzten Knoten in der Objekt-Kette ueberpruefen
+ SbiExprNode *pNode = aVar.GetExprNode()->GetRealNode();
+ SbiSymDef* pDef = pNode->GetVar();
+ // Variant, AB 27.6.1997, #41090: bzw. empty -> muß Object sein
+ if( pDef->GetType() == SbxVARIANT || pDef->GetType() == SbxEMPTY )
+ pDef->SetType( SbxOBJECT );
+ else if( pDef->GetType() != SbxOBJECT )
+ Error( SbERR_NEEDS_OBJECT );
+
+ // Knoten auch auf SbxOBJECT setzen, damit spaeter Gen() klappt
+ pNode->SetType( SbxOBJECT );
+
+ OpenBlock( NIL, aVar.GetExprNode() );
+ StmntBlock( ENDWITH );
+ CloseBlock();
+}
+
+// LOOP/NEXT/WEND ohne Konstrukt
+
+void SbiParser::BadBlock()
+{
+ if( eEndTok )
+ Error( SbERR_BAD_BLOCK, eEndTok );
+ else
+ Error( SbERR_BAD_BLOCK, "Loop/Next/Wend" );
+}
+
+// On expr Goto/Gosub n,n,n...
+
+void SbiParser::OnGoto()
+{
+ SbiExpression aCond( this );
+ aCond.Gen();
+ UINT32 nLabelsTarget = aGen.Gen( _ONJUMP, 0 );
+ SbiToken eTok = Next();
+ if( eTok != GOTO && eTok != GOSUB )
+ {
+ Error( SbERR_EXPECTED, "GoTo/GoSub" );
+ eTok = GOTO;
+ }
+ // Label-Tabelle einlesen:
+ UINT32 nLbl = 0;
+ do
+ {
+ SbiToken eTok2 = NIL;
+ eTok2 = Next(); // Label holen
+ if( MayBeLabel() )
+ {
+ UINT32 nOff = pProc->GetLabels().Reference( aSym );
+ aGen.Gen( _JUMP, nOff );
+ nLbl++;
+ }
+ else Error( SbERR_LABEL_EXPECTED );
+ }
+ while( !bAbort && TestComma() );
+ if( eTok == GOSUB )
+ nLbl |= 0x8000;
+ aGen.Patch( nLabelsTarget, nLbl );
+}
+
+// GOTO/GOSUB
+
+void SbiParser::Goto()
+{
+ SbiOpcode eOp = eCurTok == GOTO ? _JUMP : _GOSUB;
+ Next();
+ if( MayBeLabel() )
+ {
+ UINT32 nOff = pProc->GetLabels().Reference( aSym );
+ aGen.Gen( eOp, nOff );
+ }
+ else Error( SbERR_LABEL_EXPECTED );
+}
+
+// RETURN [label]
+
+void SbiParser::Return()
+{
+ Next();
+ if( MayBeLabel() )
+ {
+ UINT32 nOff = pProc->GetLabels().Reference( aSym );
+ aGen.Gen( _RETURN, nOff );
+ }
+ else aGen.Gen( _RETURN, 0 );
+}
+
+// SELECT CASE
+
+void SbiParser::Select()
+{
+ TestToken( CASE );
+ SbiExpression aCase( this );
+ SbiToken eTok = NIL;
+ aCase.Gen();
+ aGen.Gen( _CASE );
+ TestEoln();
+ UINT32 nNextTarget = 0;
+ UINT32 nDoneTarget = 0;
+ BOOL bElse = FALSE;
+ // Die Cases einlesen:
+ while( !bAbort )
+ {
+ eTok = Next();
+ if( eTok == CASE )
+ {
+ if( nNextTarget )
+ aGen.BackChain( nNextTarget ), nNextTarget = 0;
+ aGen.Statement();
+ // Jeden Case einlesen
+ BOOL bDone = FALSE;
+ UINT32 nTrueTarget = 0;
+ if( Peek() == ELSE )
+ {
+ // CASE ELSE
+ Next();
+ bElse = TRUE;
+ }
+ else while( !bDone )
+ {
+ if( bElse )
+ Error( SbERR_SYNTAX );
+ SbiToken eTok2 = Peek();
+ if( eTok2 == IS || ( eTok2 >= EQ && eTok2 <= GE ) )
+ { // CASE [IS] operator expr
+ if( eTok2 == IS )
+ Next();
+ eTok2 = Peek();
+ if( eTok2 < EQ || eTok2 > GE )
+ Error( SbERR_SYNTAX );
+ else Next();
+ SbiExpression aCompare( this );
+ aCompare.Gen();
+ nTrueTarget = aGen.Gen(
+ _CASEIS, nTrueTarget,
+ sal::static_int_cast< UINT16 >(
+ SbxEQ + ( eTok2 - EQ ) ) );
+ }
+ else
+ { // CASE expr | expr TO expr
+ SbiExpression aCase1( this );
+ aCase1.Gen();
+ if( Peek() == TO )
+ {
+ // CASE a TO b
+ Next();
+ SbiExpression aCase2( this );
+ aCase2.Gen();
+ nTrueTarget = aGen.Gen( _CASETO, nTrueTarget );
+ }
+ else
+ // CASE a
+ nTrueTarget = aGen.Gen( _CASEIS, nTrueTarget, SbxEQ );
+
+ }
+ if( Peek() == COMMA ) Next();
+ else TestEoln(), bDone = TRUE;
+ }
+ // Alle Cases abgearbeitet
+ if( !bElse )
+ {
+ nNextTarget = aGen.Gen( _JUMP, nNextTarget );
+ aGen.BackChain( nTrueTarget );
+ }
+ // den Statement-Rumpf bauen
+ while( !bAbort )
+ {
+ eTok = Peek();
+ if( eTok == CASE || eTok == ENDSELECT )
+ break;
+ if( !Parse() ) goto done;
+ eTok = Peek();
+ if( eTok == CASE || eTok == ENDSELECT )
+ break;
+ }
+ if( !bElse )
+ nDoneTarget = aGen.Gen( _JUMP, nDoneTarget );
+ }
+ else if( !IsEoln( eTok ) )
+ break;
+ }
+done:
+ if( eTok != ENDSELECT )
+ Error( SbERR_EXPECTED, ENDSELECT );
+ if( nNextTarget )
+ aGen.BackChain( nNextTarget );
+ aGen.BackChain( nDoneTarget );
+ aGen.Gen( _ENDCASE );
+}
+
+// ON Error/Variable
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+#endif
+
+void SbiParser::On()
+{
+ SbiToken eTok = Peek();
+ String aString = SbiTokenizer::Symbol(eTok);
+ if (aString.EqualsIgnoreCaseAscii("ERROR"))
+ //if (!aString.ICompare("ERROR"))
+ eTok = _ERROR_; // Error kommt als SYMBOL
+ if( eTok != _ERROR_ && eTok != LOCAL ) OnGoto();
+ else
+ {
+ if( eTok == LOCAL ) Next();
+ Next (); // Kein TestToken mehr, da es sonst einen Fehler gibt
+
+ Next(); // Token nach Error holen
+ if( eCurTok == GOTO )
+ {
+ // ON ERROR GOTO label|0
+ Next();
+ bool bError_ = false;
+ if( MayBeLabel() )
+ {
+ if( eCurTok == NUMBER && !nVal )
+ aGen.Gen( _STDERROR );
+ else
+ {
+ UINT32 nOff = pProc->GetLabels().Reference( aSym );
+ aGen.Gen( _ERRHDL, nOff );
+ }
+ }
+ else if( eCurTok == MINUS )
+ {
+ Next();
+ if( eCurTok == NUMBER && nVal == 1 )
+ aGen.Gen( _STDERROR );
+ else
+ bError_ = true;
+ }
+ if( bError_ )
+ Error( SbERR_LABEL_EXPECTED );
+ }
+ else if( eCurTok == RESUME )
+ {
+ TestToken( NEXT );
+ aGen.Gen( _NOERROR );
+ }
+ else Error( SbERR_EXPECTED, "GoTo/Resume" );
+ }
+}
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+#endif
+
+// RESUME [0]|NEXT|label
+
+void SbiParser::Resume()
+{
+ UINT32 nLbl;
+
+ switch( Next() )
+ {
+ case EOS:
+ case EOLN:
+ aGen.Gen( _RESUME, 0 );
+ break;
+ case NEXT:
+ aGen.Gen( _RESUME, 1 );
+ Next();
+ break;
+ case NUMBER:
+ if( !nVal )
+ {
+ aGen.Gen( _RESUME, 0 );
+ break;
+ } // fall thru
+ case SYMBOL:
+ if( MayBeLabel() )
+ {
+ nLbl = pProc->GetLabels().Reference( aSym );
+ aGen.Gen( _RESUME, nLbl );
+ Next();
+ break;
+ } // fall thru
+ default:
+ Error( SbERR_LABEL_EXPECTED );
+ }
+}
+
diff --git a/basic/source/comp/makefile.mk b/basic/source/comp/makefile.mk
new file mode 100644
index 000000000000..d65f6a431e43
--- /dev/null
+++ b/basic/source/comp/makefile.mk
@@ -0,0 +1,60 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=basic
+TARGET=comp
+
+# --- Settings ------------------------------------------------------------
+
+.INCLUDE : settings.mk
+
+SLOFILES= \
+ $(SLO)$/buffer.obj \
+ $(SLO)$/codegen.obj \
+ $(SLO)$/dim.obj \
+ $(SLO)$/exprgen.obj \
+ $(SLO)$/exprnode.obj \
+ $(SLO)$/exprtree.obj \
+ $(SLO)$/io.obj \
+ $(SLO)$/loops.obj \
+ $(SLO)$/parser.obj \
+ $(SLO)$/sbcomp.obj \
+ $(SLO)$/scanner.obj \
+ $(SLO)$/symtbl.obj \
+ $(SLO)$/token.obj
+
+EXCEPTIONSFILES= \
+ $(SLO)$/codegen.obj \
+ $(SLO)$/dim.obj \
+ $(SLO)$/exprtree.obj \
+ $(SLO)$/parser.obj
+
+# --- Targets --------------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/basic/source/comp/parser.cxx b/basic/source/comp/parser.cxx
new file mode 100644
index 000000000000..3d7178ae7688
--- /dev/null
+++ b/basic/source/comp/parser.cxx
@@ -0,0 +1,863 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+#include <basic/sbx.hxx>
+#include "sbcomp.hxx"
+#include <com/sun/star/script/ModuleType.hpp>
+
+struct SbiParseStack { // "Stack" fuer Statement-Blocks
+ SbiParseStack* pNext; // Chain
+ SbiExprNode* pWithVar; // Variable fuer WITH
+ SbiToken eExitTok; // Exit-Token
+ UINT32 nChain; // JUMP-Chain
+};
+
+struct SbiStatement {
+ SbiToken eTok;
+ void( SbiParser::*Func )(); // Verarbeitungsroutine
+ BOOL bMain; // TRUE: ausserhalb SUBs OK
+ BOOL bSubr; // TRUE: in SUBs OK
+};
+
+#define Y TRUE
+#define N FALSE
+
+static SbiStatement StmntTable [] = {
+{ CALL, &SbiParser::Call, N, Y, }, // CALL
+{ CLOSE, &SbiParser::Close, N, Y, }, // CLOSE
+{ _CONST_, &SbiParser::Dim, Y, Y, }, // CONST
+{ DECLARE, &SbiParser::Declare, Y, N, }, // DECLARE
+{ DEFBOOL, &SbiParser::DefXXX, Y, N, }, // DEFBOOL
+{ DEFCUR, &SbiParser::DefXXX, Y, N, }, // DEFCUR
+{ DEFDATE, &SbiParser::DefXXX, Y, N, }, // DEFDATE
+{ DEFDBL, &SbiParser::DefXXX, Y, N, }, // DEFDBL
+{ DEFERR, &SbiParser::DefXXX, Y, N, }, // DEFERR
+{ DEFINT, &SbiParser::DefXXX, Y, N, }, // DEFINT
+{ DEFLNG, &SbiParser::DefXXX, Y, N, }, // DEFLNG
+{ DEFOBJ, &SbiParser::DefXXX, Y, N, }, // DEFOBJ
+{ DEFSNG, &SbiParser::DefXXX, Y, N, }, // DEFSNG
+{ DEFSTR, &SbiParser::DefXXX, Y, N, }, // DEFSTR
+{ DEFVAR, &SbiParser::DefXXX, Y, N, }, // DEFVAR
+{ DIM, &SbiParser::Dim, Y, Y, }, // DIM
+{ DO, &SbiParser::DoLoop, N, Y, }, // DO
+{ ELSE, &SbiParser::NoIf, N, Y, }, // ELSE
+{ ELSEIF, &SbiParser::NoIf, N, Y, }, // ELSEIF
+{ ENDIF, &SbiParser::NoIf, N, Y, }, // ENDIF
+{ END, &SbiParser::Stop, N, Y, }, // END
+{ ENUM, &SbiParser::Enum, Y, N, }, // TYPE
+{ ERASE, &SbiParser::Erase, N, Y, }, // ERASE
+{ _ERROR_, &SbiParser::ErrorStmnt, N, Y, }, // ERROR
+{ EXIT, &SbiParser::Exit, N, Y, }, // EXIT
+{ FOR, &SbiParser::For, N, Y, }, // FOR
+{ FUNCTION, &SbiParser::SubFunc, Y, N, }, // FUNCTION
+{ GOSUB, &SbiParser::Goto, N, Y, }, // GOSUB
+{ GLOBAL, &SbiParser::Dim, Y, N, }, // GLOBAL
+{ GOTO, &SbiParser::Goto, N, Y, }, // GOTO
+{ IF, &SbiParser::If, N, Y, }, // IF
+{ IMPLEMENTS, &SbiParser::Implements, Y, N, }, // IMPLEMENTS
+{ INPUT, &SbiParser::Input, N, Y, }, // INPUT
+{ LET, &SbiParser::Assign, N, Y, }, // LET
+{ LINE, &SbiParser::Line, N, Y, }, // LINE, -> LINE INPUT (#i92642)
+{ LINEINPUT,&SbiParser::LineInput, N, Y, }, // LINE INPUT
+{ LOOP, &SbiParser::BadBlock, N, Y, }, // LOOP
+{ LSET, &SbiParser::LSet, N, Y, }, // LSET
+{ NAME, &SbiParser::Name, N, Y, }, // NAME
+{ NEXT, &SbiParser::BadBlock, N, Y, }, // NEXT
+{ ON, &SbiParser::On, N, Y, }, // ON
+{ OPEN, &SbiParser::Open, N, Y, }, // OPEN
+{ OPTION, &SbiParser::Option, Y, N, }, // OPTION
+{ PRINT, &SbiParser::Print, N, Y, }, // PRINT
+{ PRIVATE, &SbiParser::Dim, Y, N, }, // PRIVATE
+{ PROPERTY, &SbiParser::SubFunc, Y, N, }, // FUNCTION
+{ PUBLIC, &SbiParser::Dim, Y, N, }, // PUBLIC
+{ REDIM, &SbiParser::ReDim, N, Y, }, // DIM
+{ RESUME, &SbiParser::Resume, N, Y, }, // RESUME
+{ RETURN, &SbiParser::Return, N, Y, }, // RETURN
+{ RSET, &SbiParser::RSet, N, Y, }, // RSET
+{ SELECT, &SbiParser::Select, N, Y, }, // SELECT
+{ SET, &SbiParser::Set, N, Y, }, // SET
+{ STATIC, &SbiParser::Static, Y, Y, }, // STATIC
+{ STOP, &SbiParser::Stop, N, Y, }, // STOP
+{ SUB, &SbiParser::SubFunc, Y, N, }, // SUB
+{ TYPE, &SbiParser::Type, Y, N, }, // TYPE
+{ UNTIL, &SbiParser::BadBlock, N, Y, }, // UNTIL
+{ WHILE, &SbiParser::While, N, Y, }, // WHILE
+{ WEND, &SbiParser::BadBlock, N, Y, }, // WEND
+{ WITH, &SbiParser::With, N, Y, }, // WITH
+{ WRITE, &SbiParser::Write, N, Y, }, // WRITE
+
+{ NIL, NULL, N, N }
+};
+
+
+#ifdef _MSC_VER
+// 'this' : used in base member initializer list
+#pragma warning( disable: 4355 )
+#endif
+
+SbiParser::SbiParser( StarBASIC* pb, SbModule* pm )
+ : SbiTokenizer( pm->GetSource32(), pb ),
+ aGblStrings( this ),
+ aLclStrings( this ),
+ aGlobals( aGblStrings, SbGLOBAL ),
+ aPublics( aGblStrings, SbPUBLIC ),
+ aRtlSyms( aGblStrings, SbRTL ),
+ aGen( *pm, this, 1024 )
+{
+ pBasic = pb;
+ eCurExpr = SbSYMBOL;
+ eEndTok = NIL;
+ pProc = NULL;
+ pStack = NULL;
+ pWithVar = NULL;
+ nBase = 0;
+ bText =
+ bGblDefs =
+ bNewGblDefs =
+ bSingleLineIf =
+ bExplicit = FALSE;
+ bClassModule = ( pm->GetModuleType() == com::sun::star::script::ModuleType::CLASS );
+ OSL_TRACE("Parser - %s, bClassModule %d", rtl::OUStringToOString( pm->GetName(), RTL_TEXTENCODING_UTF8 ).getStr(), bClassModule );
+ pPool = &aPublics;
+ for( short i = 0; i < 26; i++ )
+ eDefTypes[ i ] = SbxVARIANT; // Kein expliziter Defaulttyp
+
+ aPublics.SetParent( &aGlobals );
+ aGlobals.SetParent( &aRtlSyms );
+
+ // Die globale Chainkette faengt bei Adresse 0 an:
+ nGblChain = aGen.Gen( _JUMP, 0 );
+
+ rTypeArray = new SbxArray; // Array fuer Benutzerdefinierte Typen
+ rEnumArray = new SbxArray; // Array for Enum types
+ bVBASupportOn = pm->IsVBACompat();
+ if ( bVBASupportOn )
+ EnableCompatibility();
+
+}
+
+
+// Ist Teil der Runtime-Library?
+SbiSymDef* SbiParser::CheckRTLForSym( const String& rSym, SbxDataType eType )
+{
+ SbxVariable* pVar = GetBasic()->GetRtl()->Find( rSym, SbxCLASS_DONTCARE );
+ SbiSymDef* pDef = NULL;
+ if( pVar )
+ {
+ if( pVar->IsA( TYPE(SbxMethod) ) )
+ {
+ SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym );
+ pProc_->SetType( pVar->GetType() );
+ pDef = pProc_;
+ }
+ else
+ {
+ pDef = aRtlSyms.AddSym( rSym );
+ pDef->SetType( eType );
+ }
+ }
+ return pDef;
+}
+
+// Globale Chainkette schliessen
+
+BOOL SbiParser::HasGlobalCode()
+{
+ if( bGblDefs && nGblChain )
+ {
+ aGen.BackChain( nGblChain );
+ aGen.Gen( _LEAVE );
+ // aGen.Gen( _STOP );
+ nGblChain = 0;
+ }
+ return bGblDefs;
+}
+
+void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar )
+{
+ SbiParseStack* p = new SbiParseStack;
+ p->eExitTok = eTok;
+ p->nChain = 0;
+ p->pWithVar = pWithVar;
+ p->pNext = pStack;
+ pStack = p;
+ pWithVar = pVar;
+
+ // #29955 for-Schleifen-Ebene pflegen
+ if( eTok == FOR )
+ aGen.IncForLevel();
+}
+
+void SbiParser::CloseBlock()
+{
+ if( pStack )
+ {
+ SbiParseStack* p = pStack;
+
+ // #29955 for-Schleifen-Ebene pflegen
+ if( p->eExitTok == FOR )
+ aGen.DecForLevel();
+
+ aGen.BackChain( p->nChain );
+ pStack = p->pNext;
+ pWithVar = p->pWithVar;
+ delete p;
+ }
+}
+
+// EXIT ...
+
+void SbiParser::Exit()
+{
+ SbiToken eTok = Next();
+ for( SbiParseStack* p = pStack; p; p = p->pNext )
+ {
+ SbiToken eExitTok = p->eExitTok;
+ if( eTok == eExitTok ||
+ (eTok == PROPERTY && (eExitTok == GET || eExitTok == LET) ) ) // #i109051
+ {
+ p->nChain = aGen.Gen( _JUMP, p->nChain );
+ return;
+ }
+ }
+ if( pStack )
+ Error( SbERR_EXPECTED, pStack->eExitTok );
+ else
+ Error( SbERR_BAD_EXIT );
+}
+
+BOOL SbiParser::TestSymbol( BOOL bKwdOk )
+{
+ Peek();
+ if( eCurTok == SYMBOL || ( bKwdOk && IsKwd( eCurTok ) ) )
+ {
+ Next(); return TRUE;
+ }
+ Error( SbERR_SYMBOL_EXPECTED );
+ return FALSE;
+}
+
+// Testen auf ein bestimmtes Token
+
+BOOL SbiParser::TestToken( SbiToken t )
+{
+ if( Peek() == t )
+ {
+ Next(); return TRUE;
+ }
+ else
+ {
+ Error( SbERR_EXPECTED, t );
+ return FALSE;
+ }
+}
+
+// Testen auf Komma oder EOLN
+
+BOOL SbiParser::TestComma()
+{
+ SbiToken eTok = Peek();
+ if( IsEoln( eTok ) )
+ {
+ Next();
+ return FALSE;
+ }
+ else if( eTok != COMMA )
+ {
+ Error( SbERR_EXPECTED, COMMA );
+ return FALSE;
+ }
+ Next();
+ return TRUE;
+}
+
+// Testen, ob EOLN vorliegt
+
+void SbiParser::TestEoln()
+{
+ if( !IsEoln( Next() ) )
+ {
+ Error( SbERR_EXPECTED, EOLN );
+ while( !IsEoln( Next() ) ) {}
+ }
+}
+
+// Parsing eines Statement-Blocks
+// Das Parsing laeuft bis zum Ende-Token.
+
+void SbiParser::StmntBlock( SbiToken eEnd )
+{
+ SbiToken xe = eEndTok;
+ eEndTok = eEnd;
+ while( !bAbort && Parse() ) {}
+ eEndTok = xe;
+ if( IsEof() )
+ {
+ Error( SbERR_BAD_BLOCK, eEnd );
+ bAbort = TRUE;
+ }
+}
+
+// Die Hauptroutine. Durch wiederholten Aufrufs dieser Routine wird
+// die Quelle geparst. Returnwert FALSE bei Ende/Fehlern.
+
+BOOL SbiParser::Parse()
+{
+ if( bAbort ) return FALSE;
+
+ EnableErrors();
+
+ bErrorIsSymbol = false;
+ Peek();
+ bErrorIsSymbol = true;
+ // Dateiende?
+ if( IsEof() )
+ {
+ // AB #33133: Falls keine Sub angelegt wurde, muss hier
+ // der globale Chain abgeschlossen werden!
+ // AB #40689: Durch die neue static-Behandlung kann noch
+ // ein nGblChain vorhanden sein, daher vorher abfragen
+ if( bNewGblDefs && nGblChain == 0 )
+ nGblChain = aGen.Gen( _JUMP, 0 );
+ return FALSE;
+ }
+
+ // Leerstatement?
+ if( IsEoln( eCurTok ) )
+ {
+ Next(); return TRUE;
+ }
+
+ if( !bSingleLineIf && MayBeLabel( TRUE ) )
+ {
+ // Ist ein Label
+ if( !pProc )
+ Error( SbERR_NOT_IN_MAIN, aSym );
+ else
+ pProc->GetLabels().Define( aSym );
+ Next(); Peek();
+ // Leerstatement?
+ if( IsEoln( eCurTok ) )
+ {
+ Next(); return TRUE;
+ }
+ }
+
+ // Ende des Parsings?
+ if( eCurTok == eEndTok ||
+ ( bVBASupportOn && // #i109075
+ (eCurTok == ENDFUNC || eCurTok == ENDPROPERTY || eCurTok == ENDSUB) &&
+ (eEndTok == ENDFUNC || eEndTok == ENDPROPERTY || eEndTok == ENDSUB) ) )
+ {
+ Next();
+ if( eCurTok != NIL )
+ aGen.Statement();
+ return FALSE;
+ }
+
+ // Kommentar?
+ if( eCurTok == REM )
+ {
+ Next(); return TRUE;
+ }
+
+ // Kommt ein Symbol, ist es entweder eine Variable( LET )
+ // oder eine SUB-Prozedur( CALL ohne Klammern )
+ // DOT fuer Zuweisungen im WITH-Block: .A=5
+ if( eCurTok == SYMBOL || eCurTok == DOT )
+ {
+ if( !pProc )
+ Error( SbERR_EXPECTED, SUB );
+ else
+ {
+ // Damit Zeile & Spalte stimmen...
+ Next();
+ Push( eCurTok );
+ aGen.Statement();
+ Symbol();
+ }
+ }
+ else
+ {
+ Next();
+
+ // Hier folgen nun die Statement-Parser.
+
+ SbiStatement* p;
+ for( p = StmntTable; p->eTok != NIL; p++ )
+ if( p->eTok == eCurTok )
+ break;
+ if( p->eTok != NIL )
+ {
+ if( !pProc && !p->bMain )
+ Error( SbERR_NOT_IN_MAIN, eCurTok );
+ else if( pProc && !p->bSubr )
+ Error( SbERR_NOT_IN_SUBR, eCurTok );
+ else
+ {
+ // globalen Chain pflegen
+ // AB #41606/#40689: Durch die neue static-Behandlung kann noch
+ // ein nGblChain vorhanden sein, daher vorher abfragen
+ if( bNewGblDefs && nGblChain == 0 &&
+ ( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) )
+ {
+ nGblChain = aGen.Gen( _JUMP, 0 );
+ bNewGblDefs = FALSE;
+ }
+ // Statement-Opcode bitte auch am Anfang einer Sub
+ if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) ||
+ eCurTok == SUB || eCurTok == FUNCTION )
+ aGen.Statement();
+ (this->*( p->Func ) )();
+ SbxError nSbxErr = SbxBase::GetError();
+ if( nSbxErr )
+ SbxBase::ResetError(), Error( (SbError)nSbxErr );
+ }
+ }
+ else
+ Error( SbERR_UNEXPECTED, eCurTok );
+ }
+
+ // Test auf Ende des Statements:
+ // Kann auch ein ELSE sein, da vor dem ELSE kein : stehen muss!
+
+ if( !IsEos() )
+ {
+ Peek();
+ if( !IsEos() && eCurTok != ELSE )
+ {
+ // falls das Parsing abgebrochen wurde, bis zum ":" vorgehen:
+ Error( SbERR_UNEXPECTED, eCurTok );
+ while( !IsEos() ) Next();
+ }
+ }
+ // Der Parser bricht am Ende ab, das naechste Token ist noch nicht
+ // geholt!
+ return TRUE;
+}
+
+// Innerste With-Variable liefern
+SbiExprNode* SbiParser::GetWithVar()
+{
+ if( pWithVar )
+ return pWithVar;
+
+ // Sonst im Stack suchen
+ SbiParseStack* p = pStack;
+ while( p )
+ {
+ // LoopVar kann zur Zeit nur fuer with sein
+ if( p->pWithVar )
+ return p->pWithVar;
+ p = p->pNext;
+ }
+ return NULL;
+}
+
+
+// Zuweisung oder Subroutine Call
+
+void SbiParser::Symbol( const KeywordSymbolInfo* pKeywordSymbolInfo )
+{
+ SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD;
+ SbiExpression aVar( this, SbSYMBOL, eMode, pKeywordSymbolInfo );
+
+ bool bEQ = ( Peek() == EQ );
+ if( !bEQ && bVBASupportOn && aVar.IsBracket() )
+ Error( SbERR_EXPECTED, "=" );
+
+ RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL );
+ bool bSpecialMidHandling = false;
+ SbiSymDef* pDef = aVar.GetRealVar();
+ if( bEQ && pDef && pDef->GetScope() == SbRTL )
+ {
+ String aRtlName = pDef->GetName();
+ if( aRtlName.EqualsIgnoreCaseAscii("Mid") )
+ {
+ SbiExprNode* pExprNode = aVar.GetExprNode();
+ // SbiNodeType eNodeType;
+ if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL )
+ {
+ SbiExprList* pPar = pExprNode->GetParameters();
+ short nParCount = pPar ? pPar->GetSize() : 0;
+ if( nParCount == 2 || nParCount == 3 )
+ {
+ if( nParCount == 2 )
+ pPar->addExpression( new SbiExpression( this, -1, SbxLONG ) );
+
+ TestToken( EQ );
+ pPar->addExpression( new SbiExpression( this ) );
+
+ bSpecialMidHandling = true;
+ }
+ }
+ }
+ }
+ aVar.Gen( eRecMode );
+ if( !bSpecialMidHandling )
+ {
+ if( !bEQ )
+ {
+ aGen.Gen( _GET );
+ }
+ else
+ {
+ // Dann muss es eine Zuweisung sein. Was anderes gibts nicht!
+ if( !aVar.IsLvalue() )
+ Error( SbERR_LVALUE_EXPECTED );
+ TestToken( EQ );
+ SbiExpression aExpr( this );
+ aExpr.Gen();
+ SbiOpcode eOp = _PUT;
+ // SbiSymDef* pDef = aVar.GetRealVar();
+ if( pDef )
+ {
+ if( pDef->GetConstDef() )
+ Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
+ if( pDef->GetType() == SbxOBJECT )
+ {
+ eOp = _SET;
+ if( pDef->GetTypeId() )
+ {
+ aGen.Gen( _SETCLASS, pDef->GetTypeId() );
+ return;
+ }
+ }
+ }
+ aGen.Gen( eOp );
+ }
+ }
+}
+
+// Zuweisungen
+
+void SbiParser::Assign()
+{
+ SbiExpression aLvalue( this, SbLVALUE );
+ TestToken( EQ );
+ SbiExpression aExpr( this );
+ aLvalue.Gen();
+ aExpr.Gen();
+ USHORT nLen = 0;
+ SbiSymDef* pDef = aLvalue.GetRealVar();
+ {
+ if( pDef->GetConstDef() )
+ Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
+ nLen = aLvalue.GetRealVar()->GetLen();
+ }
+ if( nLen )
+ aGen.Gen( _PAD, nLen );
+ aGen.Gen( _PUT );
+}
+
+// Zuweisungen einer Objektvariablen
+
+void SbiParser::Set()
+{
+ SbiExpression aLvalue( this, SbLVALUE );
+ SbxDataType eType = aLvalue.GetType();
+ if( eType != SbxOBJECT && eType != SbxEMPTY && eType != SbxVARIANT )
+ Error( SbERR_INVALID_OBJECT );
+ TestToken( EQ );
+ SbiSymDef* pDef = aLvalue.GetRealVar();
+ if( pDef && pDef->GetConstDef() )
+ Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
+
+ SbiToken eTok = Peek();
+ if( eTok == NEW )
+ {
+ Next();
+ String aStr;
+ SbiSymDef* pTypeDef = new SbiSymDef( aStr );
+ TypeDecl( *pTypeDef, TRUE );
+
+ aLvalue.Gen();
+ // aGen.Gen( _CLASS, pDef->GetTypeId() | 0x8000 );
+ aGen.Gen( _CREATE, pDef->GetId(), pTypeDef->GetTypeId() );
+ aGen.Gen( _SETCLASS, pDef->GetTypeId() );
+ }
+ else
+ {
+ SbiExpression aExpr( this );
+ aLvalue.Gen();
+ aExpr.Gen();
+ // Its a good idea to distinguish between
+ // set someting = another &
+ // someting = another
+ // ( its necessary for vba objects where set is object
+ // specific and also doesn't involve processing default params )
+ if( pDef->GetTypeId() )
+ {
+ if ( bVBASupportOn )
+ aGen.Gen( _VBASETCLASS, pDef->GetTypeId() );
+ else
+ aGen.Gen( _SETCLASS, pDef->GetTypeId() );
+ }
+ else
+ {
+ if ( bVBASupportOn )
+ aGen.Gen( _VBASET );
+ else
+ aGen.Gen( _SET );
+ }
+ }
+ // aGen.Gen( _SET );
+}
+
+// JSM 07.10.95
+void SbiParser::LSet()
+{
+ SbiExpression aLvalue( this, SbLVALUE );
+ if( aLvalue.GetType() != SbxSTRING )
+ Error( SbERR_INVALID_OBJECT );
+ TestToken( EQ );
+ SbiSymDef* pDef = aLvalue.GetRealVar();
+ if( pDef && pDef->GetConstDef() )
+ Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
+ SbiExpression aExpr( this );
+ aLvalue.Gen();
+ aExpr.Gen();
+ aGen.Gen( _LSET );
+}
+
+// JSM 07.10.95
+void SbiParser::RSet()
+{
+ SbiExpression aLvalue( this, SbLVALUE );
+ if( aLvalue.GetType() != SbxSTRING )
+ Error( SbERR_INVALID_OBJECT );
+ TestToken( EQ );
+ SbiSymDef* pDef = aLvalue.GetRealVar();
+ if( pDef && pDef->GetConstDef() )
+ Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
+ SbiExpression aExpr( this );
+ aLvalue.Gen();
+ aExpr.Gen();
+ aGen.Gen( _RSET );
+}
+
+// DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR und so weiter
+
+void SbiParser::DefXXX()
+{
+ sal_Unicode ch1, ch2;
+ SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER );
+
+ while( !bAbort )
+ {
+ if( Next() != SYMBOL ) break;
+ ch1 = aSym.ToUpperAscii().GetBuffer()[0];
+ ch2 = 0;
+ if( Peek() == MINUS )
+ {
+ Next();
+ if( Next() != SYMBOL ) Error( SbERR_SYMBOL_EXPECTED );
+ else
+ {
+ ch2 = aSym.ToUpperAscii().GetBuffer()[0];
+ //ch2 = aSym.Upper();
+ if( ch2 < ch1 ) Error( SbERR_SYNTAX ), ch2 = 0;
+ }
+ }
+ if (!ch2) ch2 = ch1;
+ ch1 -= 'A'; ch2 -= 'A';
+ for (; ch1 <= ch2; ch1++) eDefTypes[ ch1 ] = t;
+ if( !TestComma() ) break;
+ }
+}
+
+// STOP/SYSTEM
+
+void SbiParser::Stop()
+{
+ aGen.Gen( _STOP );
+ Peek(); // #35694: Nur Peek(), damit EOL in Single-Line-If erkannt wird
+}
+
+// IMPLEMENTS
+
+void SbiParser::Implements()
+{
+ if( !bClassModule )
+ {
+ Error( SbERR_UNEXPECTED, IMPLEMENTS );
+ return;
+ }
+
+ Peek();
+ if( eCurTok != SYMBOL )
+ {
+ Error( SbERR_SYMBOL_EXPECTED );
+ return;
+ }
+
+ String aImplementedIface = aSym;
+ Next();
+ if( Peek() == DOT )
+ {
+ String aDotStr( '.' );
+ while( Peek() == DOT )
+ {
+ aImplementedIface += aDotStr;
+ Next();
+ SbiToken ePeekTok = Peek();
+ if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
+ {
+ Next();
+ aImplementedIface += aSym;
+ }
+ else
+ {
+ Next();
+ Error( SbERR_SYMBOL_EXPECTED );
+ break;
+ }
+ }
+ }
+ aIfaceVector.push_back( aImplementedIface );
+}
+
+void SbiParser::EnableCompatibility()
+{
+ if( !bCompatible )
+ AddConstants();
+ bCompatible = TRUE;
+}
+
+// OPTION
+
+void SbiParser::Option()
+{
+ switch( Next() )
+ {
+ case EXPLICIT:
+ bExplicit = TRUE; break;
+ case BASE:
+ if( Next() == NUMBER )
+ {
+ if( nVal == 0 || nVal == 1 )
+ {
+ nBase = (short) nVal;
+ break;
+ }
+ }
+ Error( SbERR_EXPECTED, "0/1" );
+ break;
+ case PRIVATE:
+ {
+ String aString = SbiTokenizer::Symbol(Next());
+ if( !aString.EqualsIgnoreCaseAscii("Module") )
+ Error( SbERR_EXPECTED, "Module" );
+ break;
+ }
+ case COMPARE:
+ {
+ SbiToken eTok = Next();
+ if( eTok == BINARY )
+ bText = FALSE;
+ else if( eTok == SYMBOL && GetSym().EqualsIgnoreCaseAscii("text") )
+ bText = TRUE;
+ else
+ Error( SbERR_EXPECTED, "Text/Binary" );
+ break;
+ }
+ case COMPATIBLE:
+ EnableCompatibility();
+ break;
+
+ case CLASSMODULE:
+ bClassModule = TRUE;
+ aGen.GetModule().SetModuleType( com::sun::star::script::ModuleType::CLASS );
+ break;
+ case VBASUPPORT:
+ if( Next() == NUMBER )
+ {
+ if ( nVal == 1 || nVal == 0 )
+ {
+ bVBASupportOn = ( nVal == 1 );
+ if ( bVBASupportOn )
+ EnableCompatibility();
+ // if the module setting is different
+ // reset it to what the Option tells us
+ if ( bVBASupportOn != aGen.GetModule().IsVBACompat() )
+ aGen.GetModule().SetVBACompat( bVBASupportOn );
+ break;
+ }
+ }
+ Error( SbERR_EXPECTED, "0/1" );
+ break;
+ default:
+ Error( SbERR_BAD_OPTION, eCurTok );
+ }
+}
+
+void addStringConst( SbiSymPool& rPool, const char* pSym, const String& rStr )
+{
+ SbiConstDef* pConst = new SbiConstDef( String::CreateFromAscii( pSym ) );
+ pConst->SetType( SbxSTRING );
+ pConst->Set( rStr );
+ rPool.Add( pConst );
+}
+
+inline void addStringConst( SbiSymPool& rPool, const char* pSym, const char* pStr )
+{
+ addStringConst( rPool, pSym, String::CreateFromAscii( pStr ) );
+}
+
+void SbiParser::AddConstants( void )
+{
+ // #113063 Create constant RTL symbols
+ addStringConst( aPublics, "vbCr", "\x0D" );
+ addStringConst( aPublics, "vbCrLf", "\x0D\x0A" );
+ addStringConst( aPublics, "vbFormFeed", "\x0C" );
+ addStringConst( aPublics, "vbLf", "\x0A" );
+#if defined(UNX)
+ addStringConst( aPublics, "vbNewLine", "\x0A" );
+#else
+ addStringConst( aPublics, "vbNewLine", "\x0D\x0A" );
+#endif
+ addStringConst( aPublics, "vbNullString", "" );
+ addStringConst( aPublics, "vbTab", "\x09" );
+ addStringConst( aPublics, "vbVerticalTab", "\x0B" );
+
+ // Force length 1 and make char 0 afterwards
+ String aNullCharStr( String::CreateFromAscii( " " ) );
+ aNullCharStr.SetChar( 0, 0 );
+ addStringConst( aPublics, "vbNullChar", aNullCharStr );
+}
+
+// ERROR n
+
+void SbiParser::ErrorStmnt()
+{
+ SbiExpression aPar( this );
+ aPar.Gen();
+ aGen.Gen( _ERROR );
+}
+
diff --git a/basic/source/comp/sbcomp.cxx b/basic/source/comp/sbcomp.cxx
new file mode 100755
index 000000000000..5b7e5c70591d
--- /dev/null
+++ b/basic/source/comp/sbcomp.cxx
@@ -0,0 +1,477 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include <basic/sbx.hxx>
+#include "sbcomp.hxx"
+#include "image.hxx"
+#include "sbtrace.hxx"
+
+
+//==========================================================================
+// Tracing, for debugging only
+
+// To activate tracing enable in sbtrace.hxx
+#ifdef DBG_TRACE_BASIC
+
+#include <hash_map>
+
+// Trace Settings
+static const char* GpTraceFileName = "d:\\zBasic.Asm\\BasicTrace.txt";
+static const bool GbIncludePCodes = false;
+static const int GnIndentPerCallLevel = 4;
+static const int GnIndentForPCode = 2;
+
+struct TraceTextData
+{
+ rtl::OString m_aTraceStr_STMNT;
+ rtl::OString m_aTraceStr_PCode;
+};
+typedef std::hash_map< sal_Int32, TraceTextData > PCToTextDataMap;
+typedef std::hash_map< ::rtl::OUString, PCToTextDataMap*, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > ModuleTraceMap;
+
+ModuleTraceMap GaModuleTraceMap;
+ModuleTraceMap& rModuleTraceMap = GaModuleTraceMap;
+
+static void lcl_PrepareTraceForModule( SbModule* pModule )
+{
+ String aModuleName = pModule->GetName();
+ ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
+ if( it != rModuleTraceMap.end() )
+ {
+ PCToTextDataMap* pInnerMap = it->second;
+ delete pInnerMap;
+ rModuleTraceMap.erase( it );
+ }
+
+ String aDisassemblyStr;
+ pModule->Disassemble( aDisassemblyStr );
+}
+
+static void lcl_lineOut( const char* pFileName, const char* pStr, const char* pPreStr = NULL )
+{
+ const char* pPrintFirst = (pPreStr != NULL) ? pPreStr : "";
+ FILE* pFile = fopen( pFileName, "a+" );
+ if( pFile != NULL )
+ {
+ fprintf( pFile, "%s%s\n", pPrintFirst, pStr );
+ fclose( pFile );
+ }
+}
+
+const char* lcl_getSpaces( int nSpaceCount )
+{
+ static sal_Char Spaces[] = " "
+ " "
+ " ";
+ static int nAvailableSpaceCount = strlen( Spaces );
+ static sal_Char* pSpacesEnd = Spaces + nAvailableSpaceCount;
+
+ if( nSpaceCount > nAvailableSpaceCount )
+ nSpaceCount = nAvailableSpaceCount;
+
+ return pSpacesEnd - nSpaceCount;
+}
+
+static rtl::OString lcl_toOStringSkipLeadingWhites( const String& aStr )
+{
+ static sal_Char Buffer[1000];
+
+ rtl::OString aOStr = OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US );
+ const sal_Char* pStr = aOStr.getStr();
+
+ // Skip whitespace
+ sal_Char c = *pStr;
+ while( c == ' ' || c == '\t' )
+ {
+ pStr++;
+ c = *pStr;
+ }
+
+ int nLen = strlen( pStr );
+ strncpy( Buffer, pStr, nLen );
+ Buffer[nLen] = 0;
+
+ rtl::OString aORetStr( Buffer );
+ return aORetStr;
+}
+
+String dumpMethodParameters( SbMethod* pMethod )
+{
+ String aStr;
+ if( pMethod == NULL )
+ return aStr;
+
+ SbxError eOld = SbxBase::GetError();
+
+ SbxArray* pParams = pMethod->GetParameters();
+ SbxInfo* pInfo = pMethod->GetInfo();
+ if ( pParams )
+ {
+ aStr += '(';
+ // 0 is sub itself
+ for ( USHORT nParam = 1; nParam < pParams->Count(); nParam++ )
+ {
+ SbxVariable* pVar = pParams->Get( nParam );
+ DBG_ASSERT( pVar, "Parameter?!" );
+ if ( pVar->GetName().Len() )
+ aStr += pVar->GetName();
+ else if ( pInfo )
+ {
+ const SbxParamInfo* pParam = pInfo->GetParam( nParam );
+ if ( pParam )
+ aStr += pParam->aName;
+ }
+ aStr += '=';
+ if( pVar->GetType() & SbxARRAY )
+ aStr += String( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
+ else
+ aStr += pVar->GetString();
+ if ( nParam < ( pParams->Count() - 1 ) )
+ aStr += String( RTL_CONSTASCII_USTRINGPARAM( ", " ) );
+ }
+ aStr += ')';
+ }
+
+ SbxBase::ResetError();
+ if( eOld != SbxERR_OK )
+ SbxBase::SetError( eOld );
+
+ return aStr;
+}
+
+// Public functions
+void dbg_InitTrace( void )
+{
+ FILE* pFile = fopen( GpTraceFileName, "w" );
+ if( pFile != NULL )
+ fclose( pFile );
+}
+
+void dbg_traceStep( SbModule* pModule, UINT32 nPC, INT32 nCallLvl )
+{
+ SbModule* pTraceMod = pModule;
+ if( pTraceMod->ISA(SbClassModuleObject) )
+ {
+ SbClassModuleObject* pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
+ pTraceMod = pClassModuleObj->getClassModule();
+ }
+
+ String aModuleName = pTraceMod->GetName();
+ ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
+ if( it == rModuleTraceMap.end() )
+ {
+ const char* pModuleNameStr = OUStringToOString( rtl::OUString( aModuleName ), RTL_TEXTENCODING_ASCII_US ).getStr();
+ char Buffer[200];
+ sprintf( Buffer, "TRACE ERROR: Unknown module \"%s\"", pModuleNameStr );
+ lcl_lineOut( GpTraceFileName, Buffer );
+ return;
+ }
+
+ PCToTextDataMap* pInnerMap = it->second;
+ if( pInnerMap == NULL )
+ {
+ lcl_lineOut( GpTraceFileName, "TRACE INTERNAL ERROR: No inner map" );
+ return;
+ }
+
+ PCToTextDataMap::iterator itInner = pInnerMap->find( nPC );
+ if( itInner == pInnerMap->end() )
+ {
+ const char* pModuleNameStr = OUStringToOString( rtl::OUString( aModuleName ), RTL_TEXTENCODING_ASCII_US ).getStr();
+ char Buffer[200];
+ sprintf( Buffer, "TRACE ERROR: No info for PC = %d in module \"%s\"", nPC, pModuleNameStr );
+ lcl_lineOut( GpTraceFileName, Buffer );
+ return;
+ }
+
+ //nCallLvl--;
+ //if( nCallLvl < 0 )
+ // nCallLvl = 0;
+ int nIndent = nCallLvl * GnIndentPerCallLevel;
+
+ const TraceTextData& rTraceTextData = itInner->second;
+ const rtl::OString& rStr_STMNT = rTraceTextData.m_aTraceStr_STMNT;
+ if( rStr_STMNT.getLength() )
+ lcl_lineOut( GpTraceFileName, rStr_STMNT.getStr(), lcl_getSpaces( nIndent ) );
+
+ if( !GbIncludePCodes )
+ return;
+
+ nIndent += GnIndentForPCode;
+ const rtl::OString& rStr_PCode = rTraceTextData.m_aTraceStr_PCode;
+ if( rStr_PCode.getLength() )
+ lcl_lineOut( GpTraceFileName, rStr_PCode.getStr(), lcl_getSpaces( nIndent ) );
+}
+
+void dbg_traceNotifyCall( SbModule* pModule, SbMethod* pMethod, INT32 nCallLvl, bool bLeave )
+{
+ static const char* pSeparator = "' ================================================================================";
+
+ SbModule* pTraceMod = pModule;
+ SbClassModuleObject* pClassModuleObj = NULL;
+ if( pTraceMod->ISA(SbClassModuleObject) )
+ {
+ pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
+ pTraceMod = pClassModuleObj->getClassModule();
+ }
+
+ if( nCallLvl > 0 )
+ nCallLvl--;
+ int nIndent = nCallLvl * GnIndentPerCallLevel;
+ if( !bLeave )
+ {
+ lcl_lineOut( GpTraceFileName, "" );
+ lcl_lineOut( GpTraceFileName, pSeparator, lcl_getSpaces( nIndent ) );
+ }
+
+ String aStr;
+ if( bLeave )
+ {
+ lcl_lineOut( GpTraceFileName, "}", lcl_getSpaces( nIndent ) );
+ aStr.AppendAscii( "' Leaving " );
+ }
+ else
+ {
+ aStr.AppendAscii( "Entering " );
+ }
+ String aModuleName = pTraceMod->GetName();
+ aStr += aModuleName;
+ if( pMethod != NULL )
+ {
+ aStr.AppendAscii( "::" );
+ String aMethodName = pMethod->GetName();
+ aStr += aMethodName;
+ }
+ else
+ {
+ aStr.AppendAscii( "/RunInit" );
+ }
+
+ if( pClassModuleObj != NULL )
+ {
+ aStr.AppendAscii( "[this=" );
+ aStr += pClassModuleObj->GetName();
+ aStr.AppendAscii( "]" );
+ }
+ if( !bLeave )
+ aStr += dumpMethodParameters( pMethod );
+
+ lcl_lineOut( GpTraceFileName, OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US ).getStr(), lcl_getSpaces( nIndent ) );
+ if( !bLeave )
+ lcl_lineOut( GpTraceFileName, "{", lcl_getSpaces( nIndent ) );
+
+ if( bLeave )
+ lcl_lineOut( GpTraceFileName, "" );
+}
+
+void dbg_traceNotifyError( SbError nTraceErr, const String& aTraceErrMsg, bool bTraceErrHandled, INT32 nCallLvl )
+{
+ rtl::OString aOTraceErrMsg = OUStringToOString( rtl::OUString( aTraceErrMsg ), RTL_TEXTENCODING_ASCII_US );
+
+ char Buffer[200];
+ const char* pHandledStr = bTraceErrHandled ? " / HANDLED" : "";
+ sprintf( Buffer, "*** ERROR%s, Id = %d, Msg = \"%s\" ***", pHandledStr, (int)nTraceErr, aOTraceErrMsg.getStr() );
+ int nIndent = nCallLvl * GnIndentPerCallLevel;
+ lcl_lineOut( GpTraceFileName, Buffer, lcl_getSpaces( nIndent ) );
+}
+
+void dbg_RegisterTraceTextForPC( SbModule* pModule, UINT32 nPC,
+ const String& aTraceStr_STMNT, const String& aTraceStr_PCode )
+{
+ String aModuleName = pModule->GetName();
+ ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
+ PCToTextDataMap* pInnerMap;
+ if( it == rModuleTraceMap.end() )
+ {
+ pInnerMap = new PCToTextDataMap();
+ rModuleTraceMap[ aModuleName ] = pInnerMap;
+ }
+ else
+ {
+ pInnerMap = it->second;
+ }
+
+ TraceTextData aData;
+
+ rtl::OString aOTraceStr_STMNT = lcl_toOStringSkipLeadingWhites( aTraceStr_STMNT );
+ aData.m_aTraceStr_STMNT = aOTraceStr_STMNT;
+
+ rtl::OString aOTraceStr_PCode = lcl_toOStringSkipLeadingWhites( aTraceStr_PCode );
+ aData.m_aTraceStr_PCode = aOTraceStr_PCode;
+
+ (*pInnerMap)[nPC] = aData;
+}
+
+#endif
+
+
+//==========================================================================
+// For debugging only
+//#define DBG_SAVE_DISASSEMBLY
+
+#ifdef DBG_SAVE_DISASSEMBLY
+static bool dbg_bDisassemble = true;
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
+#include <com/sun/star/io/XTextOutputStream.hpp>
+#include <com/sun/star/io/XActiveDataSource.hpp>
+
+using namespace comphelper;
+using namespace rtl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::io;
+
+void dbg_SaveDisassembly( SbModule* pModule )
+{
+ bool bDisassemble = dbg_bDisassemble;
+ if( bDisassemble )
+ {
+ Reference< XSimpleFileAccess3 > xSFI;
+ Reference< XTextOutputStream > xTextOut;
+ Reference< XOutputStream > xOut;
+ Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory();
+ if( xSMgr.is() )
+ {
+ Reference< XSimpleFileAccess3 > xSFI = Reference< XSimpleFileAccess3 >( xSMgr->createInstance
+ ( OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY );
+ if( xSFI.is() )
+ {
+ String aFile( RTL_CONSTASCII_USTRINGPARAM("file:///d:/zBasic.Asm/Asm_") );
+ StarBASIC* pBasic = (StarBASIC*)pModule->GetParent();
+ if( pBasic )
+ {
+ aFile += pBasic->GetName();
+ aFile.AppendAscii( "_" );
+ }
+ aFile += pModule->GetName();
+ aFile.AppendAscii( ".txt" );
+
+ // String aFile( RTL_CONSTASCII_USTRINGPARAM("file:///d:/BasicAsm.txt") );
+ if( xSFI->exists( aFile ) )
+ xSFI->kill( aFile );
+ xOut = xSFI->openFileWrite( aFile );
+ Reference< XInterface > x = xSMgr->createInstance( OUString::createFromAscii( "com.sun.star.io.TextOutputStream" ) );
+ Reference< XActiveDataSource > xADS( x, UNO_QUERY );
+ xADS->setOutputStream( xOut );
+ xTextOut = Reference< XTextOutputStream >( x, UNO_QUERY );
+ }
+ }
+
+ if( xTextOut.is() )
+ {
+ String aDisassemblyStr;
+ pModule->Disassemble( aDisassemblyStr );
+ xTextOut->writeString( aDisassemblyStr );
+ }
+ xOut->closeOutput();
+ }
+}
+#endif
+
+
+// Diese Routine ist hier definiert, damit der Compiler als eigenes Segment
+// geladen werden kann.
+
+BOOL SbModule::Compile()
+{
+ if( pImage )
+ return TRUE;
+ StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent());
+ if( !pBasic )
+ return FALSE;
+ SbxBase::ResetError();
+ // Aktuelles Modul!
+ SbModule* pOld = pCMOD;
+ pCMOD = this;
+
+ SbiParser* pParser = new SbiParser( (StarBASIC*) GetParent(), this );
+ while( pParser->Parse() ) {}
+ if( !pParser->GetErrors() )
+ pParser->aGen.Save();
+ delete pParser;
+ // fuer den Disassembler
+ if( pImage )
+ pImage->aOUSource = aOUSource;
+
+ pCMOD = pOld;
+
+ // Beim Compilieren eines Moduls werden die Modul-globalen
+ // Variablen aller Module ungueltig
+ BOOL bRet = IsCompiled();
+ if( bRet )
+ {
+ pBasic->ClearAllModuleVars();
+ RemoveVars(); // remove 'this' Modules variables
+ // clear all method statics
+ for( USHORT i = 0; i < pMethods->Count(); i++ )
+ {
+ SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
+ if( p )
+ p->ClearStatics();
+ }
+
+ // #i31510 Init other libs only if Basic isn't running
+ if( pINST == NULL )
+ {
+ SbxObject* pParent_ = pBasic->GetParent();
+ if( pParent_ )
+ pBasic = PTR_CAST(StarBASIC,pParent_);
+ if( pBasic )
+ pBasic->ClearAllModuleVars();
+ }
+ }
+
+#ifdef DBG_SAVE_DISASSEMBLY
+ dbg_SaveDisassembly( this );
+#endif
+
+#ifdef DBG_TRACE_BASIC
+ lcl_PrepareTraceForModule( this );
+#endif
+
+ return bRet;
+}
+
+/**************************************************************************
+*
+* Syntax-Highlighting
+*
+**************************************************************************/
+
+void StarBASIC::Highlight( const String& rSrc, SbTextPortions& rList )
+{
+ SbiTokenizer aTok( rSrc );
+ aTok.Hilite( rList );
+}
+
diff --git a/basic/source/comp/scanner.cxx b/basic/source/comp/scanner.cxx
new file mode 100644
index 000000000000..dd68f20893f5
--- /dev/null
+++ b/basic/source/comp/scanner.cxx
@@ -0,0 +1,582 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include "sbcomp.hxx"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#if defined UNX
+#include <stdlib.h>
+#else
+#include <math.h> // atof()
+#endif
+#include <rtl/math.hxx>
+#include <vcl/svapp.hxx>
+#include <unotools/charclass.hxx>
+
+#include <runtime.hxx>
+
+SbiScanner::SbiScanner( const ::rtl::OUString& rBuf, StarBASIC* p ) : aBuf( rBuf )
+{
+ pBasic = p;
+ pLine = NULL;
+ nVal = 0;
+ eScanType = SbxVARIANT;
+ nErrors = 0;
+ nBufPos = 0;
+ nCurCol1 = 0;
+ nSavedCol1 = 0;
+ nColLock = 0;
+ nLine = 0;
+ nCol1 = 0;
+ nCol2 = 0;
+ nCol = 0;
+ bError =
+ bAbort =
+ bSpaces =
+ bNumber =
+ bSymbol =
+ bUsedForHilite =
+ bCompatible =
+ bVBASupportOn =
+ bPrevLineExtentsComment = FALSE;
+ bHash =
+ bErrors = TRUE;
+}
+
+SbiScanner::~SbiScanner()
+{}
+
+void SbiScanner::LockColumn()
+{
+ if( !nColLock++ )
+ nSavedCol1 = nCol1;
+}
+
+void SbiScanner::UnlockColumn()
+{
+ if( nColLock )
+ nColLock--;
+}
+
+void SbiScanner::GenError( SbError code )
+{
+ if( GetSbData()->bBlockCompilerError )
+ {
+ bAbort = TRUE;
+ return;
+ }
+ if( !bError && bErrors )
+ {
+ BOOL bRes = TRUE;
+ // Nur einen Fehler pro Statement reporten
+ bError = TRUE;
+ if( pBasic )
+ {
+ // Falls EXPECTED oder UNEXPECTED kommen sollte, bezieht es sich
+ // immer auf das letzte Token, also die Col1 uebernehmen
+ USHORT nc = nColLock ? nSavedCol1 : nCol1;
+ switch( code )
+ {
+ case SbERR_EXPECTED:
+ case SbERR_UNEXPECTED:
+ case SbERR_SYMBOL_EXPECTED:
+ case SbERR_LABEL_EXPECTED:
+ nc = nCol1;
+ if( nc > nCol2 ) nCol2 = nc;
+ break;
+ }
+ bRes = pBasic->CError( code, aError, nLine, nc, nCol2 );
+ }
+ bAbort |= !bRes |
+ ( code == SbERR_NO_MEMORY || code == SbERR_PROG_TOO_LARGE );
+ }
+ if( bErrors )
+ nErrors++;
+}
+
+// Falls sofort ein Doppelpunkt folgt, wird TRUE zurueckgeliefert.
+// Wird von SbiTokenizer::MayBeLabel() verwendet, um einen Label zu erkennen
+
+BOOL SbiScanner::DoesColonFollow()
+{
+ if( pLine && *pLine == ':' )
+ {
+ pLine++; nCol++; return TRUE;
+ }
+ else return FALSE;
+}
+
+// Testen auf ein legales Suffix
+
+static SbxDataType GetSuffixType( sal_Unicode c )
+{
+ static String aSuffixesStr = String::CreateFromAscii( "%&!#@ $" );
+ if( c )
+ {
+ sal_uInt32 n = aSuffixesStr.Search( c );
+ if( STRING_NOTFOUND != n && c != ' ' )
+ return SbxDataType( (USHORT) n + SbxINTEGER );
+ }
+ return SbxVARIANT;
+}
+
+// Einlesen des naechsten Symbols in die Variablen aSym, nVal und eType
+// Returnwert ist FALSE bei EOF oder Fehlern
+#define BUF_SIZE 80
+
+BOOL SbiScanner::NextSym()
+{
+ // Fuer den EOLN-Fall merken
+ USHORT nOldLine = nLine;
+ USHORT nOldCol1 = nCol1;
+ USHORT nOldCol2 = nCol2;
+ sal_Unicode buf[ BUF_SIZE ], *p = buf;
+ bHash = FALSE;
+
+ eScanType = SbxVARIANT;
+ aSym.Erase();
+ bSymbol =
+ bNumber = bSpaces = FALSE;
+
+ // Zeile einlesen?
+ if( !pLine )
+ {
+ INT32 n = nBufPos;
+ INT32 nLen = aBuf.getLength();
+ if( nBufPos >= nLen )
+ return FALSE;
+ const sal_Unicode* p2 = aBuf.getStr();
+ p2 += n;
+ while( ( n < nLen ) && ( *p2 != '\n' ) && ( *p2 != '\r' ) )
+ p2++, n++;
+ aLine = aBuf.copy( nBufPos, n - nBufPos );
+ if( n < nLen )
+ {
+ if( *p2 == '\r' && *( p2+1 ) == '\n' )
+ n += 2;
+ else
+ n++;
+ }
+ nBufPos = n;
+ pLine = aLine.getStr();
+ nOldLine = ++nLine;
+ nCol = nCol1 = nCol2 = nOldCol1 = nOldCol2 = 0;
+ nColLock = 0;
+ }
+
+ // Leerstellen weg:
+ while( *pLine && (( *pLine == ' ' ) || ( *pLine == '\t' ) || ( *pLine == '\f' )) )
+ pLine++, nCol++, bSpaces = TRUE;
+
+ nCol1 = nCol;
+
+ // nur Leerzeile?
+ if( !*pLine )
+ goto eoln;
+
+ if( bPrevLineExtentsComment )
+ goto PrevLineCommentLbl;
+
+ if( *pLine == '#' )
+ {
+ pLine++;
+ nCol++;
+ bHash = TRUE;
+ }
+
+ // Symbol? Dann Zeichen kopieren.
+ if( BasicSimpleCharClass::isAlpha( *pLine, bCompatible ) || *pLine == '_' )
+ {
+ // Wenn nach '_' nichts kommt, ist es ein Zeilenabschluss!
+ if( *pLine == '_' && !*(pLine+1) )
+ { pLine++;
+ goto eoln; }
+ bSymbol = TRUE;
+ short n = nCol;
+ for ( ; (BasicSimpleCharClass::isAlphaNumeric( *pLine, bCompatible ) || ( *pLine == '_' ) ); pLine++ )
+ nCol++;
+ aSym = aLine.copy( n, nCol - n );
+ // Abschliessendes '_' durch Space ersetzen, wenn Zeilenende folgt
+ // (sonst falsche Zeilenfortsetzung)
+ if( !bUsedForHilite && !*pLine && *(pLine-1) == '_' )
+ {
+ aSym.GetBufferAccess(); // #109693 force copy if necessary
+ *((sal_Unicode*)(pLine-1)) = ' '; // cast wegen const
+ }
+ // Typkennung?
+ // Das Ausrufezeichen bitte nicht testen, wenn
+ // danach noch ein Symbol anschliesst
+ else if( *pLine != '!' || !BasicSimpleCharClass::isAlpha( pLine[ 1 ], bCompatible ) )
+ {
+ SbxDataType t = GetSuffixType( *pLine );
+ if( t != SbxVARIANT )
+ {
+ eScanType = t;
+ pLine++;
+ nCol++;
+ }
+ }
+ }
+
+ // Zahl? Dann einlesen und konvertieren.
+ else if( BasicSimpleCharClass::isDigit( *pLine & 0xFF )
+ || ( *pLine == '.' && BasicSimpleCharClass::isDigit( *(pLine+1) & 0xFF ) ) )
+ {
+ short exp = 0;
+ short comma = 0;
+ short ndig = 0;
+ short ncdig = 0;
+ eScanType = SbxDOUBLE;
+ BOOL bBufOverflow = FALSE;
+ while( strchr( "0123456789.DEde", *pLine ) && *pLine )
+ {
+ // AB 4.1.1996: Buffer voll? -> leer weiter scannen
+ if( (p-buf) == (BUF_SIZE-1) )
+ {
+ bBufOverflow = TRUE;
+ pLine++, nCol++;
+ continue;
+ }
+ // Komma oder Exponent?
+ if( *pLine == '.' )
+ {
+ if( ++comma > 1 )
+ {
+ pLine++; nCol++; continue;
+ }
+ else *p++ = *pLine++, nCol++;
+ }
+ else if( strchr( "DdEe", *pLine ) )
+ {
+ if (++exp > 1)
+ {
+ pLine++; nCol++; continue;
+ }
+// if( toupper( *pLine ) == 'D' )
+// eScanType = SbxDOUBLE;
+ *p++ = 'E'; pLine++; nCol++;
+ // Vorzeichen hinter Exponent?
+ if( *pLine == '+' )
+ pLine++, nCol++;
+ else
+ if( *pLine == '-' )
+ *p++ = *pLine++, nCol++;
+ }
+ else
+ {
+ *p++ = *pLine++, nCol++;
+ if( comma && !exp ) ncdig++;
+ }
+ if (!exp) ndig++;
+ }
+ *p = 0;
+ aSym = p; bNumber = TRUE;
+ // Komma, Exponent mehrfach vorhanden?
+ if( comma > 1 || exp > 1 )
+ { aError = '.';
+ GenError( SbERR_BAD_CHAR_IN_NUMBER ); }
+
+ // #57844 Lokalisierte Funktion benutzen
+ nVal = rtl_math_uStringToDouble( buf, buf+(p-buf), '.', ',', NULL, NULL );
+ // ALT: nVal = atof( buf );
+
+ ndig = ndig - comma;
+ if( !comma && !exp )
+ {
+ if( nVal >= SbxMININT && nVal <= SbxMAXINT )
+ eScanType = SbxINTEGER;
+ else
+ if( nVal >= SbxMINLNG && nVal <= SbxMAXLNG )
+ eScanType = SbxLONG;
+ }
+ if( bBufOverflow )
+ GenError( SbERR_MATH_OVERFLOW );
+ // zu viele Zahlen fuer SINGLE?
+// if (ndig > 15 || ncdig > 6)
+// eScanType = SbxDOUBLE;
+// else
+// if( nVal > SbxMAXSNG || nVal < SbxMINSNG )
+// eScanType = SbxDOUBLE;
+
+ // Typkennung?
+ SbxDataType t = GetSuffixType( *pLine );
+ if( t != SbxVARIANT )
+ {
+ eScanType = t;
+ pLine++;
+ nCol++;
+ }
+ }
+
+ // Hex/Oktalzahl? Einlesen und konvertieren:
+ else if( *pLine == '&' )
+ {
+ pLine++; nCol++;
+ sal_Unicode cmp1[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', 0 };
+ sal_Unicode cmp2[] = { '0', '1', '2', '3', '4', '5', '6', '7', 0 };
+ sal_Unicode *cmp = cmp1;
+ //char *cmp = "0123456789ABCDEF";
+ sal_Unicode base = 16;
+ sal_Unicode ndig = 8;
+ sal_Unicode xch = *pLine++ & 0xFF; nCol++;
+ switch( toupper( xch ) )
+ {
+ case 'O':
+ cmp = cmp2; base = 8; ndig = 11; break;
+ //cmp = "01234567"; base = 8; ndig = 11; break;
+ case 'H':
+ break;
+ default :
+ // Wird als Operator angesehen
+ pLine--; nCol--; nCol1 = nCol-1; aSym = '&'; return SYMBOL;
+ }
+ bNumber = TRUE;
+ long l = 0;
+ int i;
+ BOOL bBufOverflow = FALSE;
+ while( BasicSimpleCharClass::isAlphaNumeric( *pLine & 0xFF, bCompatible ) )
+ {
+ sal_Unicode ch = sal::static_int_cast< sal_Unicode >(
+ toupper( *pLine & 0xFF ) );
+ pLine++; nCol++;
+ // AB 4.1.1996: Buffer voll, leer weiter scannen
+ if( (p-buf) == (BUF_SIZE-1) )
+ bBufOverflow = TRUE;
+ else if( String( cmp ).Search( ch ) != STRING_NOTFOUND )
+ //else if( strchr( cmp, ch ) )
+ *p++ = ch;
+ else
+ {
+ aError = ch;
+ GenError( SbERR_BAD_CHAR_IN_NUMBER );
+ }
+ }
+ *p = 0;
+ for( p = buf; *p; p++ )
+ {
+ i = (*p & 0xFF) - '0';
+ if( i > 9 ) i -= 7;
+ l = ( l * base ) + i;
+ if( !ndig-- )
+ {
+ GenError( SbERR_MATH_OVERFLOW ); break;
+ }
+ }
+ if( *pLine == '&' ) pLine++, nCol++;
+ nVal = (double) l;
+ eScanType = ( l >= SbxMININT && l <= SbxMAXINT ) ? SbxINTEGER : SbxLONG;
+ if( bBufOverflow )
+ GenError( SbERR_MATH_OVERFLOW );
+ }
+
+ // Strings:
+ else if( *pLine == '"' || *pLine == '[' )
+ {
+ sal_Unicode cSep = *pLine;
+ if( cSep == '[' )
+ bSymbol = TRUE, cSep = ']';
+ short n = nCol+1;
+ while( *pLine )
+ {
+ do pLine++, nCol++;
+ while( *pLine && ( *pLine != cSep ) );
+ if( *pLine == cSep )
+ {
+ pLine++; nCol++;
+ if( *pLine != cSep || cSep == ']' ) break;
+ } else aError = cSep, GenError( SbERR_EXPECTED );
+ }
+ // If VBA Interop then doen't eat the [] chars
+ if ( cSep == ']' && bVBASupportOn )
+ aSym = aLine.copy( n - 1, nCol - n + 1);
+ else
+ aSym = aLine.copy( n, nCol - n - 1 );
+ // Doppelte Stringbegrenzer raus
+ String s( cSep );
+ s += cSep;
+ USHORT nIdx = 0;
+ do
+ {
+ nIdx = aSym.Search( s, nIdx );
+ if( nIdx == STRING_NOTFOUND )
+ break;
+ aSym.Erase( nIdx, 1 );
+ nIdx++;
+ }
+ while( true );
+ if( cSep != ']' )
+ eScanType = ( cSep == '#' ) ? SbxDATE : SbxSTRING;
+ }
+ // ungueltige Zeichen:
+ else if( ( *pLine & 0xFF ) >= 0x7F )
+ {
+ GenError( SbERR_SYNTAX ); pLine++; nCol++;
+ }
+ // andere Gruppen:
+ else
+ {
+ short n = 1;
+ switch( *pLine++ )
+ {
+ case '<': if( *pLine == '>' || *pLine == '=' ) n = 2; break;
+ case '>': if( *pLine == '=' ) n = 2; break;
+ case ':': if( *pLine == '=' ) n = 2; break;
+ }
+ aSym = aLine.copy( nCol, n );
+ pLine += n-1; nCol = nCol + n;
+ }
+
+ nCol2 = nCol-1;
+
+PrevLineCommentLbl:
+ // Kommentar?
+ if( bPrevLineExtentsComment || (eScanType != SbxSTRING &&
+ ( aSym.GetBuffer()[0] == '\'' || aSym.EqualsIgnoreCaseAscii( "REM" ) ) ) )
+ {
+ bPrevLineExtentsComment = FALSE;
+ aSym = String::CreateFromAscii( "REM" );
+ USHORT nLen = String( pLine ).Len();
+ if( bCompatible && pLine[ nLen - 1 ] == '_' && pLine[ nLen - 2 ] == ' ' )
+ bPrevLineExtentsComment = TRUE;
+ nCol2 = nCol2 + nLen;
+ pLine = NULL;
+ }
+ return TRUE;
+
+ // Sonst Zeilen-Ende: aber bitte auf '_' testen, ob die
+ // Zeile nicht weitergeht!
+eoln:
+ if( nCol && *--pLine == '_' )
+ {
+ pLine = NULL;
+ bool bRes = NextSym();
+ if( bVBASupportOn && aSym.GetBuffer()[0] == '.' )
+ {
+ // object _
+ // .Method
+ // ^^^ <- spaces is legal in MSO VBA
+ OSL_TRACE("*** resetting bSpaces***");
+ bSpaces = FALSE;
+ }
+ return bRes;
+ }
+ else
+ {
+ pLine = NULL;
+ nLine = nOldLine;
+ nCol1 = nOldCol1;
+ nCol2 = nOldCol2;
+ aSym = '\n';
+ nColLock = 0;
+ return TRUE;
+ }
+}
+
+LetterTable BasicSimpleCharClass::aLetterTable;
+
+LetterTable::LetterTable( void )
+{
+ for( int i = 0 ; i < 256 ; ++i )
+ IsLetterTab[i] = false;
+
+ IsLetterTab[0xC0] = true; // À , CAPITAL LETTER A WITH GRAVE ACCENT
+ IsLetterTab[0xC1] = true; // Á , CAPITAL LETTER A WITH ACUTE ACCENT
+ IsLetterTab[0xC2] = true; // Â , CAPITAL LETTER A WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xC3] = true; // Ã , CAPITAL LETTER A WITH TILDE
+ IsLetterTab[0xC4] = true; // Ä , CAPITAL LETTER A WITH DIAERESIS
+ IsLetterTab[0xC5] = true; // Å , CAPITAL LETTER A WITH RING ABOVE
+ IsLetterTab[0xC6] = true; // Æ , CAPITAL LIGATURE AE
+ IsLetterTab[0xC7] = true; // Ç , CAPITAL LETTER C WITH CEDILLA
+ IsLetterTab[0xC8] = true; // È , CAPITAL LETTER E WITH GRAVE ACCENT
+ IsLetterTab[0xC9] = true; // É , CAPITAL LETTER E WITH ACUTE ACCENT
+ IsLetterTab[0xCA] = true; // Ê , CAPITAL LETTER E WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xCB] = true; // Ë , CAPITAL LETTER E WITH DIAERESIS
+ IsLetterTab[0xCC] = true; // Ì , CAPITAL LETTER I WITH GRAVE ACCENT
+ IsLetterTab[0xCD] = true; // Í , CAPITAL LETTER I WITH ACUTE ACCENT
+ IsLetterTab[0xCE] = true; // Î , CAPITAL LETTER I WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xCF] = true; // Ï , CAPITAL LETTER I WITH DIAERESIS
+ IsLetterTab[0xD0] = true; // Ð , CAPITAL LETTER ETH
+ IsLetterTab[0xD1] = true; // Ñ , CAPITAL LETTER N WITH TILDE
+ IsLetterTab[0xD2] = true; // Ò , CAPITAL LETTER O WITH GRAVE ACCENT
+ IsLetterTab[0xD3] = true; // Ó , CAPITAL LETTER O WITH ACUTE ACCENT
+ IsLetterTab[0xD4] = true; // Ô , CAPITAL LETTER O WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xD5] = true; // Õ , CAPITAL LETTER O WITH TILDE
+ IsLetterTab[0xD6] = true; // Ö , CAPITAL LETTER O WITH DIAERESIS
+ IsLetterTab[0xD8] = true; // Ø , CAPITAL LETTER O WITH STROKE
+ IsLetterTab[0xD9] = true; // Ù , CAPITAL LETTER U WITH GRAVE ACCENT
+ IsLetterTab[0xDA] = true; // Ú , CAPITAL LETTER U WITH ACUTE ACCENT
+ IsLetterTab[0xDB] = true; // Û , CAPITAL LETTER U WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xDC] = true; // Ü , CAPITAL LETTER U WITH DIAERESIS
+ IsLetterTab[0xDD] = true; // Ý , CAPITAL LETTER Y WITH ACUTE ACCENT
+ IsLetterTab[0xDE] = true; // Þ , CAPITAL LETTER THORN
+ IsLetterTab[0xDF] = true; // ß , SMALL LETTER SHARP S
+ IsLetterTab[0xE0] = true; // à , SMALL LETTER A WITH GRAVE ACCENT
+ IsLetterTab[0xE1] = true; // á , SMALL LETTER A WITH ACUTE ACCENT
+ IsLetterTab[0xE2] = true; // â , SMALL LETTER A WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xE3] = true; // ã , SMALL LETTER A WITH TILDE
+ IsLetterTab[0xE4] = true; // ä , SMALL LETTER A WITH DIAERESIS
+ IsLetterTab[0xE5] = true; // å , SMALL LETTER A WITH RING ABOVE
+ IsLetterTab[0xE6] = true; // æ , SMALL LIGATURE AE
+ IsLetterTab[0xE7] = true; // ç , SMALL LETTER C WITH CEDILLA
+ IsLetterTab[0xE8] = true; // è , SMALL LETTER E WITH GRAVE ACCENT
+ IsLetterTab[0xE9] = true; // é , SMALL LETTER E WITH ACUTE ACCENT
+ IsLetterTab[0xEA] = true; // ê , SMALL LETTER E WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xEB] = true; // ë , SMALL LETTER E WITH DIAERESIS
+ IsLetterTab[0xEC] = true; // ì , SMALL LETTER I WITH GRAVE ACCENT
+ IsLetterTab[0xED] = true; // í , SMALL LETTER I WITH ACUTE ACCENT
+ IsLetterTab[0xEE] = true; // î , SMALL LETTER I WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xEF] = true; // ï , SMALL LETTER I WITH DIAERESIS
+ IsLetterTab[0xF0] = true; // ð , SMALL LETTER ETH
+ IsLetterTab[0xF1] = true; // ñ , SMALL LETTER N WITH TILDE
+ IsLetterTab[0xF2] = true; // ò , SMALL LETTER O WITH GRAVE ACCENT
+ IsLetterTab[0xF3] = true; // ó , SMALL LETTER O WITH ACUTE ACCENT
+ IsLetterTab[0xF4] = true; // ô , SMALL LETTER O WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xF5] = true; // õ , SMALL LETTER O WITH TILDE
+ IsLetterTab[0xF6] = true; // ö , SMALL LETTER O WITH DIAERESIS
+ IsLetterTab[0xF8] = true; // ø , SMALL LETTER O WITH OBLIQUE BAR
+ IsLetterTab[0xF9] = true; // ù , SMALL LETTER U WITH GRAVE ACCENT
+ IsLetterTab[0xFA] = true; // ú , SMALL LETTER U WITH ACUTE ACCENT
+ IsLetterTab[0xFB] = true; // û , SMALL LETTER U WITH CIRCUMFLEX ACCENT
+ IsLetterTab[0xFC] = true; // ü , SMALL LETTER U WITH DIAERESIS
+ IsLetterTab[0xFD] = true; // ý , SMALL LETTER Y WITH ACUTE ACCENT
+ IsLetterTab[0xFE] = true; // þ , SMALL LETTER THORN
+ IsLetterTab[0xFF] = true; // ÿ , SMALL LETTER Y WITH DIAERESIS
+}
+
+bool LetterTable::isLetterUnicode( sal_Unicode c )
+{
+ static CharClass* pCharClass = NULL;
+ if( pCharClass == NULL )
+ pCharClass = new CharClass( Application::GetSettings().GetLocale() );
+ String aStr( c );
+ bool bRet = pCharClass->isLetter( aStr, 0 );
+ return bRet;
+}
diff --git a/basic/source/comp/symtbl.cxx b/basic/source/comp/symtbl.cxx
new file mode 100644
index 000000000000..d6b3dbb878fc
--- /dev/null
+++ b/basic/source/comp/symtbl.cxx
@@ -0,0 +1,536 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include "sbcomp.hxx"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+SV_IMPL_PTRARR(SbiStrings,String*)
+SV_IMPL_PTRARR(SbiSymbols,SbiSymDef*)
+
+// Alle Symbolnamen werden im Stringpool des Symbol-Pools abgelegt, damit
+// alle Symbole im gleichen Case verarbeitet werden. Beim Speichern des
+// Code-Images wird der globale Stringpool mit den entsprechenden Sympools
+// gespeichert. Der lokale Stringpool nimmt alle Symbole auf, die nicht
+// ins Image wandern (Labels, Konstantennamen etc).
+
+/***************************************************************************
+|*
+|* SbiStringPool
+|*
+***************************************************************************/
+
+SbiStringPool::SbiStringPool( SbiParser* p )
+{
+ pParser = p;
+}
+
+SbiStringPool::~SbiStringPool()
+{}
+
+// Suchen
+
+const String& SbiStringPool::Find( USHORT n ) const
+{
+ if( !n || n > aData.Count() )
+ return aEmpty;
+ else
+ return *aData.GetObject( n-1 );
+}
+
+// Hinzufuegen eines Strings. Der String wird Case-Insensitiv
+// verglichen.
+
+short SbiStringPool::Add( const String& rVal, BOOL bNoCase )
+{
+ USHORT n = aData.Count();
+ for( USHORT i = 0; i < n; i++ )
+ {
+ String* p = aData.GetObject( i );
+ if( ( bNoCase && p->Equals( rVal ) )
+ || ( !bNoCase && p->EqualsIgnoreCaseAscii( rVal ) ) )
+ return i+1;
+ }
+ const String* pNew = new String( rVal );
+ aData.Insert( pNew, n++ );
+ return (short) n;
+}
+
+short SbiStringPool::Add( double n, SbxDataType t )
+{
+ char buf[ 40 ];
+ switch( t )
+ {
+ case SbxINTEGER: snprintf( buf, sizeof(buf), "%d", (short) n ); break;
+ case SbxLONG: snprintf( buf, sizeof(buf), "%ld", (long) n ); break;
+ case SbxSINGLE: snprintf( buf, sizeof(buf), "%.6g", (float) n ); break;
+ case SbxDOUBLE: snprintf( buf, sizeof(buf), "%.16g", n ); break;
+ default: break;
+ }
+ return Add( String::CreateFromAscii( buf ) );
+}
+
+/***************************************************************************
+|*
+|* SbiSymPool
+|*
+***************************************************************************/
+
+SbiSymPool::SbiSymPool( SbiStringPool& r, SbiSymScope s ) : rStrings( r )
+{
+ pParser = r.GetParser();
+ eScope = s;
+ pParent = NULL;
+ nCur =
+ nProcId = 0;
+}
+
+SbiSymPool::~SbiSymPool()
+{}
+
+// Inhalt loeschen
+
+void SbiSymPool::Clear()
+{
+ aData.DeleteAndDestroy( 0, aData.Count() );
+}
+
+SbiSymDef* SbiSymPool::First()
+{
+ nCur = (USHORT) -1;
+ return Next();
+}
+
+SbiSymDef* SbiSymPool::Next()
+{
+ if( ++nCur >= aData.Count() )
+ return NULL;
+ else
+ return aData.GetObject( nCur );
+}
+
+// Hinzufuegen eines Symbols
+
+SbiSymDef* SbiSymPool::AddSym( const String& rName )
+{
+ SbiSymDef* p = new SbiSymDef( rName );
+ p->nPos = aData.Count();
+ p->nId = rStrings.Add( rName );
+ p->nProcId = nProcId;
+ p->pIn = this;
+ const SbiSymDef* q = p;
+ aData.Insert( q, q->nPos );
+ return p;
+}
+
+SbiProcDef* SbiSymPool::AddProc( const String& rName )
+{
+ SbiProcDef* p = new SbiProcDef( pParser, rName );
+ p->nPos = aData.Count();
+ p->nId = rStrings.Add( rName );
+ // Procs sind immer global
+ p->nProcId = 0;
+ p->pIn = this;
+ const SbiSymDef* q = p;
+ aData.Insert( q, q->nPos );
+ return p;
+}
+
+// Hinzufuegen einer extern aufgebauten Symboldefinition
+
+void SbiSymPool::Add( SbiSymDef* pDef )
+{
+ if( pDef && pDef->pIn != this )
+ {
+ if( pDef->pIn )
+ {
+#ifdef DBG_UTIL
+ // schon in einem anderen Pool drin!
+ pParser->Error( SbERR_INTERNAL_ERROR, "Dbl Pool" );
+#endif
+ return;
+ }
+
+ pDef->nPos = aData.Count();
+ if( !pDef->nId )
+ {
+ // Bei statischen Variablen muss ein eindeutiger Name
+ // im Stringpool erzeugt werden (Form ProcName:VarName)
+ String aName( pDef->aName );
+ if( pDef->IsStatic() )
+ {
+ aName = pParser->aGblStrings.Find( nProcId );
+ aName += ':';
+ aName += pDef->aName;
+ }
+ pDef->nId = rStrings.Add( aName );
+ }
+ // Procs sind immer global
+ if( !pDef->GetProcDef() )
+ pDef->nProcId = nProcId;
+ pDef->pIn = this;
+ const SbiSymDef* q = pDef;
+ aData.Insert( q, q->nPos );
+ }
+}
+
+// Suchen eines Eintrags ueber den Namen. Es wird auch im Parent gesucht.
+
+SbiSymDef* SbiSymPool::Find( const String& rName ) const
+{
+ for( USHORT i = 0; i < aData.Count(); i++ )
+ {
+ SbiSymDef* p = aData.GetObject( i );
+ if( ( !p->nProcId || ( p->nProcId == nProcId ) )
+ && ( p->aName.EqualsIgnoreCaseAscii( rName ) ) )
+ return p;
+ }
+ if( pParent )
+ return pParent->Find( rName );
+ else
+ return NULL;
+}
+
+// Suchen ueber ID-Nummer
+
+SbiSymDef* SbiSymPool::FindId( USHORT n ) const
+{
+ for( USHORT i = 0; i < aData.Count(); i++ )
+ {
+ SbiSymDef* p = aData.GetObject( i );
+ if( p->nId == n && ( !p->nProcId || ( p->nProcId == nProcId ) ) )
+ return p;
+ }
+ if( pParent )
+ return pParent->FindId( n );
+ else
+ return NULL;
+}
+
+// Suchen ueber Position (ab 0)
+
+SbiSymDef* SbiSymPool::Get( USHORT n ) const
+{
+ if( n >= aData.Count() )
+ return NULL;
+ else
+ return aData.GetObject( n );
+}
+
+UINT32 SbiSymPool::Define( const String& rName )
+{
+ SbiSymDef* p = Find( rName );
+ if( p )
+ { if( p->IsDefined() )
+ pParser->Error( SbERR_LABEL_DEFINED, rName );
+ }
+ else
+ p = AddSym( rName );
+ return p->Define();
+}
+
+UINT32 SbiSymPool::Reference( const String& rName )
+{
+ SbiSymDef* p = Find( rName );
+ if( !p )
+ p = AddSym( rName );
+ //Sicherheitshalber
+ pParser->aGen.GenStmnt();
+ return p->Reference();
+}
+
+// Alle offenen Referenzen anmaulen
+
+void SbiSymPool::CheckRefs()
+{
+ for( USHORT i = 0; i < aData.Count(); i++ )
+ {
+ SbiSymDef* p = aData.GetObject( i );
+ if( !p->IsDefined() )
+ pParser->Error( SbERR_UNDEF_LABEL, p->GetName() );
+ }
+}
+
+/***************************************************************************
+|*
+|* Symbol-Definitionen
+|*
+***************************************************************************/
+
+SbiSymDef::SbiSymDef( const String& rName ) : aName( rName )
+{
+ eType = SbxEMPTY;
+ nDims = 0;
+ nTypeId = 0;
+ nProcId = 0;
+ nId = 0;
+ nPos = 0;
+ nLen = 0;
+ nChain = 0;
+ bAs =
+ bNew =
+ bStatic =
+ bOpt =
+ bParamArray =
+ bWithEvents =
+ bByVal =
+ bChained =
+ bGlobal = FALSE;
+ pIn =
+ pPool = NULL;
+ nDefaultId = 0;
+ nFixedStringLength = -1;
+}
+
+SbiSymDef::~SbiSymDef()
+{
+ delete pPool;
+}
+
+SbiProcDef* SbiSymDef::GetProcDef()
+{
+ return NULL;
+}
+
+SbiConstDef* SbiSymDef::GetConstDef()
+{
+ return NULL;
+}
+
+// Wenn der Name benoetigt wird, den aktuellen Namen
+// aus dem Stringpool nehmen
+
+const String& SbiSymDef::GetName()
+{
+ if( pIn )
+ aName = pIn->rStrings.Find( nId );
+ return aName;
+}
+
+// Eintragen eines Datentyps
+
+void SbiSymDef::SetType( SbxDataType t )
+{
+ if( t == SbxVARIANT && pIn )
+ {
+ sal_Unicode cu = aName.GetBuffer()[0];
+ if( cu < 256 )
+ {
+ char ch = (char)aName.GetBuffer()[0];
+ if( ch == '_' ) ch = 'Z';
+ int ch2 = toupper( ch );
+ unsigned char c = (unsigned char)ch2;
+ if( c > 0 && c < 128 )
+ t = pIn->pParser->eDefTypes[ ch2 - 'A' ];
+ }
+ }
+ eType = t;
+}
+
+// Aufbau einer Backchain, falls noch nicht definiert
+// Es wird der Wert zurueckgeliefert, der als Operand gespeichert
+// werden soll.
+
+UINT32 SbiSymDef::Reference()
+{
+ if( !bChained )
+ {
+ UINT32 n = nChain;
+ nChain = pIn->pParser->aGen.GetOffset();
+ return n;
+ }
+ else return nChain;
+}
+
+// Definition eines Symbols.
+// Hier wird der Backchain aufgeloest, falls vorhanden
+
+UINT32 SbiSymDef::Define()
+{
+ UINT32 n = pIn->pParser->aGen.GetPC();
+ pIn->pParser->aGen.GenStmnt();
+ if( nChain ) pIn->pParser->aGen.BackChain( nChain );
+ nChain = n;
+ bChained = TRUE;
+ return nChain;
+}
+
+// Eine Symboldefinition kann einen eigenen Pool haben. Dies ist
+// der Fall bei Objekten und Prozeduren (lokale Variable)
+
+SbiSymPool& SbiSymDef::GetPool()
+{
+ if( !pPool )
+ pPool = new SbiSymPool( pIn->pParser->aGblStrings, SbLOCAL ); // wird gedumpt
+ return *pPool;
+}
+
+SbiSymScope SbiSymDef::GetScope() const
+{
+ return pIn ? pIn->GetScope() : SbLOCAL;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+// Die Prozedur-Definition hat drei Pools:
+// 1) aParams: wird durch die Definition gefuellt. Enthaelt die Namen
+// der Parameter, wie sie innerhalb des Rumpfes verwendet werden.
+// Das erste Element ist der Returnwert.
+// 2) pPool: saemtliche lokale Variable
+// 3) aLabels: Labels
+
+SbiProcDef::SbiProcDef( SbiParser* pParser, const String& rName,
+ BOOL bProcDecl )
+ : SbiSymDef( rName )
+ , aParams( pParser->aGblStrings, SbPARAM ) // wird gedumpt
+ , aLabels( pParser->aLclStrings, SbLOCAL ) // wird nicht gedumpt
+ , mbProcDecl( bProcDecl )
+{
+ aParams.SetParent( &pParser->aPublics );
+ pPool = new SbiSymPool( pParser->aGblStrings, SbLOCAL ); // Locals
+ pPool->SetParent( &aParams );
+ nLine1 =
+ nLine2 = 0;
+ mePropMode = PROPERTY_MODE_NONE;
+ bPublic = TRUE;
+ bCdecl = FALSE;
+ bStatic = FALSE;
+ // Fuer Returnwerte ist das erste Element der Parameterliste
+ // immer mit dem Namen und dem Typ der Proc definiert
+ aParams.AddSym( aName );
+}
+
+SbiProcDef::~SbiProcDef()
+{}
+
+SbiProcDef* SbiProcDef::GetProcDef()
+{
+ return this;
+}
+
+void SbiProcDef::SetType( SbxDataType t )
+{
+ SbiSymDef::SetType( t );
+ aParams.Get( 0 )->SetType( eType );
+}
+
+// Match mit einer Forward-Deklaration
+// Falls der Match OK ist, wird pOld durch this im Pool ersetzt
+// pOld wird immer geloescht!
+
+void SbiProcDef::Match( SbiProcDef* pOld )
+{
+ SbiSymDef* po, *pn=NULL;
+ // Parameter 0 ist der Funktionsname
+ USHORT i;
+ for( i = 1; i < aParams.GetSize(); i++ )
+ {
+ po = pOld->aParams.Get( i );
+ pn = aParams.Get( i );
+ // Kein Typabgleich; das wird beim Laufen erledigt
+ // aber ist sie evtl. mit zu wenigen Parametern aufgerufen
+ // worden?
+ if( !po && !pn->IsOptional() && !pn->IsParamArray() )
+ break;
+ po = pOld->aParams.Next();
+ }
+ // Wurden zu viele Parameter angegeben?
+ if( pn && i < aParams.GetSize() && pOld->pIn )
+ {
+ // Die ganze Zeile markieren
+ pOld->pIn->GetParser()->SetCol1( 0 );
+ pOld->pIn->GetParser()->Error( SbERR_BAD_DECLARATION, aName );
+ }
+ if( !pIn && pOld->pIn )
+ {
+ // Alten Eintrag durch neuen ersetzen
+ SbiSymDef** pData = (SbiSymDef**) pOld->pIn->aData.GetData();
+ pData[ pOld->nPos ] = this;
+ nPos = pOld->nPos;
+ nId = pOld->nId;
+ pIn = pOld->pIn;
+ }
+ delete pOld;
+}
+
+void SbiProcDef::setPropertyMode( PropertyMode ePropMode )
+{
+ mePropMode = ePropMode;
+ if( mePropMode != PROPERTY_MODE_NONE )
+ {
+ // Prop name = original scanned procedure name
+ maPropName = aName;
+
+ // CompleteProcName includes "Property xxx "
+ // to avoid conflicts with other symbols
+ String aCompleteProcName;
+ aCompleteProcName.AppendAscii( "Property " );
+ switch( mePropMode )
+ {
+ case PROPERTY_MODE_GET: aCompleteProcName.AppendAscii( "Get " ); break;
+ case PROPERTY_MODE_LET: aCompleteProcName.AppendAscii( "Let " ); break;
+ case PROPERTY_MODE_SET: aCompleteProcName.AppendAscii( "Set " ); break;
+ case PROPERTY_MODE_NONE:
+ DBG_ERROR( "Illegal PropertyMode PROPERTY_MODE_NONE" );
+ break;
+ }
+ aCompleteProcName += aName;
+ aName = aCompleteProcName;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+
+SbiConstDef::SbiConstDef( const String& rName )
+ : SbiSymDef( rName )
+{
+ nVal = 0; eType = SbxINTEGER;
+}
+
+void SbiConstDef::Set( double n, SbxDataType t )
+{
+ aVal.Erase(); nVal = n; eType = t;
+}
+
+void SbiConstDef::Set( const String& n )
+{
+ aVal = n; nVal = 0; eType = SbxSTRING;
+}
+
+SbiConstDef::~SbiConstDef()
+{}
+
+SbiConstDef* SbiConstDef::GetConstDef()
+{
+ return this;
+}
+
diff --git a/basic/source/comp/token.cxx b/basic/source/comp/token.cxx
new file mode 100644
index 000000000000..8cb3126f03f1
--- /dev/null
+++ b/basic/source/comp/token.cxx
@@ -0,0 +1,714 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include <ctype.h>
+#include "sbcomp.hxx"
+
+struct TokenTable { SbiToken t; const char *s; };
+
+static short nToken; // Anzahl der Tokens
+
+static TokenTable* pTokTable;
+
+static TokenTable aTokTable_Basic [] = { // Token-Tabelle:
+
+ { CAT, "&" },
+ { MUL, "*" },
+ { PLUS, "+" },
+ { MINUS, "-" },
+ { DIV, "/" },
+ { EOS, ":" },
+ { ASSIGN, ":=" },
+ { LT, "<" },
+ { LE, "<=" },
+ { NE, "<>" },
+ { EQ, "=" },
+ { GT, ">" },
+ { GE, ">=" },
+ { ACCESS, "Access" },
+ { ALIAS, "Alias" },
+ { AND, "And" },
+ { ANY, "Any" },
+ { APPEND, "Append" },
+ { AS, "As" },
+ { BASE, "Base" },
+ { BINARY, "Binary" },
+ { TBOOLEAN, "Boolean" },
+ { BYREF, "ByRef", },
+ { TBYTE, "Byte", },
+ { BYVAL, "ByVal", },
+ { CALL, "Call" },
+ { CASE, "Case" },
+ { _CDECL_, "Cdecl" },
+ { CLASSMODULE, "ClassModule" },
+ { CLOSE, "Close" },
+ { COMPARE, "Compare" },
+ { COMPATIBLE,"Compatible" },
+ { _CONST_, "Const" },
+ { TCURRENCY,"Currency" },
+ { TDATE, "Date" },
+ { DECLARE, "Declare" },
+ { DEFBOOL, "DefBool" },
+ { DEFCUR, "DefCur" },
+ { DEFDATE, "DefDate" },
+ { DEFDBL, "DefDbl" },
+ { DEFERR, "DefErr" },
+ { DEFINT, "DefInt" },
+ { DEFLNG, "DefLng" },
+ { DEFOBJ, "DefObj" },
+ { DEFSNG, "DefSng" },
+ { DEFSTR, "DefStr" },
+ { DEFVAR, "DefVar" },
+ { DIM, "Dim" },
+ { DO, "Do" },
+ { TDOUBLE, "Double" },
+ { EACH, "Each" },
+ { ELSE, "Else" },
+ { ELSEIF, "ElseIf" },
+ { END, "End" },
+ { ENDENUM, "End Enum" },
+ { ENDFUNC, "End Function" },
+ { ENDIF, "End If" },
+ { ENDPROPERTY, "End Property" },
+ { ENDSELECT,"End Select" },
+ { ENDSUB, "End Sub" },
+ { ENDTYPE, "End Type" },
+ { ENDIF, "EndIf" },
+ { ENUM, "Enum" },
+ { EQV, "Eqv" },
+ { ERASE, "Erase" },
+ { _ERROR_, "Error" },
+ { EXIT, "Exit" },
+ { EXPLICIT, "Explicit" },
+ { FOR, "For" },
+ { FUNCTION, "Function" },
+ { GET, "Get" },
+ { GLOBAL, "Global" },
+ { GOSUB, "GoSub" },
+ { GOTO, "GoTo" },
+ { IF, "If" },
+ { IMP, "Imp" },
+ { IMPLEMENTS, "Implements" },
+ { _IN_, "In" },
+ { INPUT, "Input" }, // auch INPUT #
+ { TINTEGER, "Integer" },
+ { IS, "Is" },
+ { LET, "Let" },
+ { LIB, "Lib" },
+ { LIKE, "Like" },
+ { LINE, "Line" },
+ { LINEINPUT,"Line Input" },
+ { LOCAL, "Local" },
+ { LOCK, "Lock" },
+ { TLONG, "Long" },
+ { LOOP, "Loop" },
+ { LPRINT, "LPrint" },
+ { LSET, "LSet" }, // JSM
+ { MOD, "Mod" },
+ { NAME, "Name" },
+ { NEW, "New" },
+ { NEXT, "Next" },
+ { NOT, "Not" },
+ { TOBJECT, "Object" },
+ { ON, "On" },
+ { OPEN, "Open" },
+ { OPTION, "Option" },
+ { _OPTIONAL_, "Optional" },
+ { OR, "Or" },
+ { OUTPUT, "Output" },
+ { PARAMARRAY, "ParamArray" },
+ { PRESERVE, "Preserve" },
+ { PRINT, "Print" },
+ { PRIVATE, "Private" },
+ { PROPERTY, "Property" },
+ { PUBLIC, "Public" },
+ { RANDOM, "Random" },
+ { READ, "Read" },
+ { REDIM, "ReDim" },
+ { REM, "Rem" },
+ { RESUME, "Resume" },
+ { RETURN, "Return" },
+ { RSET, "RSet" }, // JSM
+ { SELECT, "Select" },
+ { SET, "Set" },
+#ifdef SHARED
+#undef SHARED
+#define tmpSHARED
+#endif
+ { SHARED, "Shared" },
+#ifdef tmpSHARED
+#define SHARED
+#undef tmpSHARED
+#endif
+ { TSINGLE, "Single" },
+ { STATIC, "Static" },
+ { STEP, "Step" },
+ { STOP, "Stop" },
+ { TSTRING, "String" },
+ { SUB, "Sub" },
+ { STOP, "System" },
+ { TEXT, "Text" },
+ { THEN, "Then" },
+ { TO, "To", },
+ { TYPE, "Type" },
+ { TYPEOF, "TypeOf" },
+ { UNTIL, "Until" },
+ { TVARIANT, "Variant" },
+ { VBASUPPORT, "VbaSupport" },
+ { WEND, "Wend" },
+ { WHILE, "While" },
+ { WITH, "With" },
+ { WITHEVENTS, "WithEvents" },
+ { WRITE, "Write" }, // auch WRITE #
+ { XOR, "Xor" },
+ { NIL, "" }
+};
+
+/*
+TokenTable aTokTable_Java [] = { // Token-Tabelle:
+
+ { JS_LOG_NOT, "!" },
+ { JS_NE, "!=" },
+ { JS_MOD, "%" },
+ { JS_ASS_MOD, "%=" },
+ { JS_BIT_AND, "&" },
+ { JS_LOG_AND, "&&" },
+ { JS_ASS_AND, "&=" },
+ { JS_LPAREN, "(" },
+ { JS_RPAREN, ")" },
+ { JS_MUL, "*" },
+ { JS_ASS_MUL, "*=" },
+ { JS_PLUS, "+" },
+ { JS_INC, "++" },
+ { JS_ASS_PLUS, "+=" },
+ { JS_COMMA, "," },
+ { JS_MINUS, "-" },
+ { JS_DEC, "--" },
+ { JS_ASS_MINUS, "-=" },
+ { JS_DIV, "/" },
+ { JS_ASS_DIV, "/=" },
+ { JS_COND_SEL, ":" },
+ { JS_LT, "<" },
+ { JS_LSHIFT, "<<" },
+ { JS_ASS_LSHIFT,"<<=" },
+ { JS_LE, "<=" },
+ { JS_NE, "<>" },
+ { JS_ASSIGNMENT,"=" },
+ { JS_EQ, "==" },
+ { JS_GT, ">" },
+ { JS_RSHIFT, ">>" },
+ { JS_ASS_RSHIFT,">>=" },
+ { JS_RSHIFT_Z, ">>>" },
+ { JS_ASS_RSHIFT_Z,">>>=" },
+ { JS_GE, ">=" },
+ { JS_COND_QUEST,"?" },
+ { ACCESS, "Access" },
+ { ALIAS, "Alias" },
+ { AND, "And" },
+ { ANY, "Any" },
+ { APPEND, "Append" },
+ { AS, "As" },
+ { BASE, "Base" },
+ { BINARY, "Binary" },
+ { TBOOLEAN, "Boolean" },
+ { BYVAL, "ByVal", },
+ { CALL, "Call" },
+ { CASE, "Case" },
+ { _CDECL_, "Cdecl" },
+ { CLOSE, "Close" },
+ { COMPARE, "Compare" },
+ { _CONST_, "Const" },
+ { TCURRENCY,"Currency" },
+ { TDATE, "Date" },
+ { DECLARE, "Declare" },
+ { DEFBOOL, "DefBool" },
+ { DEFCUR, "DefCur" },
+ { DEFDATE, "DefDate" },
+ { DEFDBL, "DefDbl" },
+ { DEFERR, "DefErr" },
+ { DEFINT, "DefInt" },
+ { DEFLNG, "DefLng" },
+ { DEFOBJ, "DefObj" },
+ { DEFSNG, "DefSng" },
+ { DEFSTR, "DefStr" },
+ { DEFVAR, "DefVar" },
+ { DIM, "Dim" },
+ { DO, "Do" },
+ { TDOUBLE, "Double" },
+ { EACH, "Each" },
+ { ELSE, "Else" },
+ { ELSEIF, "ElseIf" },
+ { END, "End" },
+ { ENDFUNC, "End Function" },
+ { ENDIF, "End If" },
+ { ENDSELECT,"End Select" },
+ { ENDSUB, "End Sub" },
+ { ENDTYPE, "End Type" },
+ { ENDIF, "EndIf" },
+ { EQV, "Eqv" },
+ { ERASE, "Erase" },
+ { _ERROR_, "Error" },
+ { EXIT, "Exit" },
+ { EXPLICIT, "Explicit" },
+ { FOR, "For" },
+ { FUNCTION, "Function" },
+ { GLOBAL, "Global" },
+ { GOSUB, "GoSub" },
+ { GOTO, "GoTo" },
+ { IF, "If" },
+ { IMP, "Imp" },
+ { _IN_, "In" },
+ { INPUT, "Input" }, // auch INPUT #
+ { TINTEGER, "Integer" },
+ { IS, "Is" },
+ { LET, "Let" },
+ { LIB, "Lib" },
+ { LINE, "Line" },
+ { LINEINPUT,"Line Input" },
+ { LOCAL, "Local" },
+ { LOCK, "Lock" },
+ { TLONG, "Long" },
+ { LOOP, "Loop" },
+ { LPRINT, "LPrint" },
+ { LSET, "LSet" }, // JSM
+ { MOD, "Mod" },
+ { NAME, "Name" },
+ { NEW, "New" },
+ { NEXT, "Next" },
+ { NOT, "Not" },
+ { TOBJECT, "Object" },
+ { ON, "On" },
+ { OPEN, "Open" },
+ { OPTION, "Option" },
+ { _OPTIONAL_, "Optional" },
+ { OR, "Or" },
+ { OUTPUT, "Output" },
+ { PRESERVE, "Preserve" },
+ { PRINT, "Print" },
+ { PRIVATE, "Private" },
+ { PUBLIC, "Public" },
+ { RANDOM, "Random" },
+ { READ, "Read" },
+ { REDIM, "ReDim" },
+ { REM, "Rem" },
+ { RESUME, "Resume" },
+ { RETURN, "Return" },
+ { RSET, "RSet" }, // JSM
+ { SELECT, "Select" },
+ { SET, "Set" },
+ { SHARED, "Shared" },
+ { TSINGLE, "Single" },
+ { STATIC, "Static" },
+ { STEP, "Step" },
+ { STOP, "Stop" },
+ { TSTRING, "String" },
+ { SUB, "Sub" },
+ { STOP, "System" },
+ { TEXT, "Text" },
+ { THEN, "Then" },
+ { TO, "To", },
+ { TYPE, "Type" },
+ { UNTIL, "Until" },
+ { TVARIANT, "Variant" },
+ { WEND, "Wend" },
+ { WHILE, "While" },
+ { WITH, "With" },
+ { WRITE, "Write" }, // auch WRITE #
+ { XOR, "Xor" },
+ { JS_LINDEX, "[" },
+ { JS_RINDEX, "]" },
+ { JS_BIT_XOR, "^" },
+ { JS_ASS_XOR, "^=" },
+ { JS_BIT_OR, "|" },
+ { JS_ASS_OR, "|=" },
+ { JS_LOG_OR, "||" },
+ { JS_BIT_NOT, "~" },
+ { NIL }
+};
+*/
+
+// #i109076
+TokenLabelInfo::TokenLabelInfo( void )
+{
+ m_pTokenCanBeLabelTab = new bool[VBASUPPORT+1];
+ for( int i = 0 ; i <= VBASUPPORT ; ++i )
+ m_pTokenCanBeLabelTab[i] = false;
+
+ // Token accepted as label by VBA
+ SbiToken eLabelToken[] = { ACCESS, ALIAS, APPEND, BASE, BINARY, CLASSMODULE,
+ COMPARE, COMPATIBLE, DEFERR, _ERROR_, EXPLICIT, LIB, LINE, LPRINT, NAME,
+ TOBJECT, OUTPUT, PROPERTY, RANDOM, READ, STEP, STOP, TEXT, VBASUPPORT, NIL };
+ SbiToken* pTok = eLabelToken;
+ SbiToken eTok;
+ for( pTok = eLabelToken ; (eTok = *pTok) != NIL ; ++pTok )
+ m_pTokenCanBeLabelTab[eTok] = true;
+}
+
+TokenLabelInfo::~TokenLabelInfo()
+{
+ delete[] m_pTokenCanBeLabelTab;
+}
+
+
+// Der Konstruktor ermittelt die Laenge der Token-Tabelle.
+
+SbiTokenizer::SbiTokenizer( const ::rtl::OUString& rSrc, StarBASIC* pb )
+ : SbiScanner( rSrc, pb )
+{
+ pTokTable = aTokTable_Basic;
+ //if( StarBASIC::GetGlobalLanguageMode() == SB_LANG_JAVASCRIPT )
+ // pTokTable = aTokTable_Java;
+ TokenTable *tp;
+ bEof = bAs = FALSE;
+ eCurTok = NIL;
+ ePush = NIL;
+ bEos = bKeywords = bErrorIsSymbol = TRUE;
+ if( !nToken )
+ for( nToken = 0, tp = pTokTable; tp->t; nToken++, tp++ ) {}
+}
+
+SbiTokenizer::~SbiTokenizer()
+{
+}
+
+// Wiederablage (Pushback) eines Tokens. (Bis zu 2 Tokens)
+
+void SbiTokenizer::Push( SbiToken t )
+{
+ if( ePush != NIL )
+ Error( SbERR_INTERNAL_ERROR, "PUSH" );
+ else ePush = t;
+}
+
+void SbiTokenizer::Error( SbError code, const char* pMsg )
+{
+ aError = String::CreateFromAscii( pMsg );
+ Error( code );
+}
+
+void SbiTokenizer::Error( SbError code, String aMsg )
+{
+ aError = aMsg;
+ Error( code );
+}
+
+void SbiTokenizer::Error( SbError code, SbiToken tok )
+{
+ aError = Symbol( tok );
+ Error( code );
+}
+
+// Einlesen des naechsten Tokens, ohne dass das Token geschluckt wird
+
+SbiToken SbiTokenizer::Peek()
+{
+ if( ePush == NIL )
+ {
+ USHORT nOldLine = nLine;
+ USHORT nOldCol1 = nCol1;
+ USHORT nOldCol2 = nCol2;
+ ePush = Next();
+ nPLine = nLine; nLine = nOldLine;
+ nPCol1 = nCol1; nCol1 = nOldCol1;
+ nPCol2 = nCol2; nCol2 = nOldCol2;
+ }
+ return eCurTok = ePush;
+}
+
+// Dies ist fuer die Decompilation.
+// Zahlen und Symbole liefern einen Leerstring zurueck.
+
+const String& SbiTokenizer::Symbol( SbiToken t )
+{
+ // Zeichen-Token?
+ if( t < FIRSTKWD )
+ {
+ aSym = (char) t;
+ return aSym;
+ }
+ switch( t )
+ {
+ case NEG : aSym = '-'; return aSym;
+ case EOS : aSym = String::CreateFromAscii( ":/CRLF" ); return aSym;
+ case EOLN : aSym = String::CreateFromAscii( "CRLF" ); return aSym;
+ default: break;
+ }
+ TokenTable* tp = pTokTable;
+ for( short i = 0; i < nToken; i++, tp++ )
+ {
+ if( tp->t == t )
+ {
+ aSym = String::CreateFromAscii( tp->s );
+ return aSym;
+ }
+ }
+ const sal_Unicode *p = aSym.GetBuffer();
+ if (*p <= ' ') aSym = String::CreateFromAscii( "???" );
+ return aSym;
+}
+
+// Einlesen des naechsten Tokens und Ablage desselben
+// Tokens, die nicht in der Token-Tabelle vorkommen, werden
+// direkt als Zeichen zurueckgeliefert.
+// Einige Worte werden gesondert behandelt.
+
+SbiToken SbiTokenizer::Next()
+{
+ if (bEof) return EOLN;
+ // Schon eines eingelesen?
+ if( ePush != NIL )
+ {
+ eCurTok = ePush;
+ ePush = NIL;
+ nLine = nPLine;
+ nCol1 = nPCol1;
+ nCol2 = nPCol2;
+ bEos = IsEoln( eCurTok );
+ return eCurTok;
+ }
+ TokenTable *tp;
+
+ // Sonst einlesen:
+ if( !NextSym() )
+ {
+ bEof = bEos = TRUE;
+ return eCurTok = EOLN;
+ }
+ // Zeilenende?
+ if( aSym.GetBuffer()[0] == '\n' )
+ {
+ bEos = TRUE; return eCurTok = EOLN;
+ }
+ bEos = FALSE;
+
+ // Zahl?
+ if( bNumber )
+ return eCurTok = NUMBER;
+
+ // String?
+ else if( ( eScanType == SbxDATE || eScanType == SbxSTRING ) && !bSymbol )
+ return eCurTok = FIXSTRING;
+ // Sonderfaelle von Zeichen, die zwischen "Z" und "a" liegen. ICompare()
+ // wertet die Position dieser Zeichen unterschiedlich aus.
+ else if( aSym.GetBuffer()[0] == '^' )
+ return eCurTok = EXPON;
+ else if( aSym.GetBuffer()[0] == '\\' )
+ return eCurTok = IDIV;
+ else
+ {
+ // Mit Typkennung oder ein Symbol und keine Keyword-Erkennung?
+ // Dann kein Token-Test
+ if( eScanType != SbxVARIANT
+ || ( !bKeywords && bSymbol ) )
+ return eCurTok = SYMBOL;
+ // Gueltiges Token?
+ short lb = 0;
+ short ub = nToken-1;
+ short delta;
+ do
+ {
+ delta = (ub - lb) >> 1;
+ tp = &pTokTable[ lb + delta ];
+ StringCompare res = aSym.CompareIgnoreCaseToAscii( tp->s );
+ // Gefunden?
+ if( res == COMPARE_EQUAL )
+ goto special;
+ // Groesser? Dann untere Haelfte
+ if( res == COMPARE_LESS )
+ {
+ if ((ub - lb) == 2) ub = lb;
+ else ub = ub - delta;
+ }
+ // Kleiner? Dann obere Haelfte
+ else
+ {
+ if ((ub -lb) == 2) lb = ub;
+ else lb = lb + delta;
+ }
+ } while( delta );
+ // Symbol? Wenn nicht >= Token
+ sal_Unicode ch = aSym.GetBuffer()[0];
+ if( !BasicSimpleCharClass::isAlpha( ch, bCompatible ) && !bSymbol )
+ return eCurTok = (SbiToken) (ch & 0x00FF);
+ return eCurTok = SYMBOL;
+ }
+special:
+ // #i92642
+ if( eCurTok != NIL && eCurTok != REM && eCurTok != EOLN && (tp->t == NAME || tp->t == LINE) )
+ return eCurTok = SYMBOL;
+ else if( tp->t == TEXT )
+ return eCurTok = SYMBOL;
+
+ // #i92642: Special LINE token handling -> SbiParser::Line()
+
+ // END IF, CASE, SUB, DEF, FUNCTION, TYPE, CLASS, WITH
+ if( tp->t == END )
+ {
+ // AB, 15.3.96, Spezialbehandlung fuer END, beim Peek() geht die
+ // aktuelle Zeile verloren, daher alles merken und danach restaurieren
+ USHORT nOldLine = nLine;
+ USHORT nOldCol = nCol;
+ USHORT nOldCol1 = nCol1;
+ USHORT nOldCol2 = nCol2;
+ String aOldSym = aSym;
+ SaveLine(); // pLine im Scanner sichern
+
+ eCurTok = Peek();
+ switch( eCurTok )
+ {
+ case IF: Next(); eCurTok = ENDIF; break;
+ case SELECT: Next(); eCurTok = ENDSELECT; break;
+ case SUB: Next(); eCurTok = ENDSUB; break;
+ case FUNCTION: Next(); eCurTok = ENDFUNC; break;
+ case PROPERTY: Next(); eCurTok = ENDPROPERTY; break;
+ case TYPE: Next(); eCurTok = ENDTYPE; break;
+ case ENUM: Next(); eCurTok = ENDENUM; break;
+ case WITH: Next(); eCurTok = ENDWITH; break;
+ default : eCurTok = END;
+ }
+ nCol1 = nOldCol1;
+ if( eCurTok == END )
+ {
+ // Alles zuruecksetzen, damit Token nach END ganz neu gelesen wird
+ ePush = NIL;
+ nLine = nOldLine;
+ nCol = nOldCol;
+ nCol2 = nOldCol2;
+ aSym = aOldSym;
+ RestoreLine(); // pLine im Scanner restaurieren
+ }
+ return eCurTok;
+ }
+ // Sind Datentypen Keywords?
+ // Nur nach AS, sonst sind es Symbole!
+ // Es gibt ja ERROR(), DATA(), STRING() etc.
+ eCurTok = tp->t;
+ // AS: Datentypen sind Keywords
+ if( tp->t == AS )
+ bAs = TRUE;
+ else
+ {
+ if( bAs )
+ bAs = FALSE;
+ else if( eCurTok >= DATATYPE1 && eCurTok <= DATATYPE2 && (bErrorIsSymbol || eCurTok != _ERROR_) )
+ eCurTok = SYMBOL;
+ }
+
+ // CLASSMODULE, PROPERTY, GET, ENUM token only visible in compatible mode
+ SbiToken eTok = tp->t;
+ if( bCompatible )
+ {
+ // #129904 Suppress system
+ if( eTok == STOP && aSym.CompareIgnoreCaseToAscii( "system" ) == COMPARE_EQUAL )
+ eCurTok = SYMBOL;
+ }
+ else
+ {
+ if( eTok == CLASSMODULE ||
+ eTok == IMPLEMENTS ||
+ eTok == PARAMARRAY ||
+ eTok == ENUM ||
+ eTok == PROPERTY ||
+ eTok == GET ||
+ eTok == TYPEOF )
+ {
+ eCurTok = SYMBOL;
+ }
+ }
+
+ bEos = IsEoln( eCurTok );
+ return eCurTok;
+}
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+#endif
+
+// Kann das aktuell eingelesene Token ein Label sein?
+
+BOOL SbiTokenizer::MayBeLabel( BOOL bNeedsColon )
+{
+ if( eCurTok == SYMBOL || m_aTokenLabelInfo.canTokenBeLabel( eCurTok ) )
+ return bNeedsColon ? DoesColonFollow() : TRUE;
+ else
+ return BOOL( eCurTok == NUMBER
+ && eScanType == SbxINTEGER
+ && nVal >= 0 );
+}
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+#endif
+
+
+void SbiTokenizer::Hilite( SbTextPortions& rList )
+{
+ bErrors = FALSE;
+ bUsedForHilite = TRUE;
+ SbiToken eLastTok = NIL;
+ for( ;; )
+ {
+ Next();
+ if( IsEof() )
+ break;
+ SbTextPortion aRes;
+ aRes.nLine = nLine;
+ aRes.nStart = nCol1;
+ aRes.nEnd = nCol2;
+ switch( eCurTok )
+ {
+ case REM:
+ aRes.eType = SB_COMMENT; break;
+ case SYMBOL:
+ aRes.eType = SB_SYMBOL; break;
+ case FIXSTRING:
+ aRes.eType = SB_STRING; break;
+ case NUMBER:
+ aRes.eType = SB_NUMBER; break;
+ default:
+ if( ( eCurTok >= FIRSTKWD && eCurTok <= LASTKWD )
+ || (eCurTok >= _CDECL_ ) )
+ aRes.eType = SB_KEYWORD;
+ else
+ aRes.eType = SB_PUNCTUATION;
+ }
+ // Die Folge xxx.Keyword sollte nicht als Kwd geflagt werden
+ if( aRes.eType == SB_KEYWORD
+ && ( eLastTok == DOT|| eLastTok == EXCLAM ) )
+ aRes.eType = SB_SYMBOL;
+ if( eCurTok != EOLN && aRes.nStart <= aRes.nEnd )
+ rList.Insert( aRes, rList.Count() );
+ if( aRes.eType == SB_COMMENT )
+ break;
+ eLastTok = eCurTok;
+ }
+ bUsedForHilite = FALSE;
+}
+