/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_basic.hxx" #include "sbcomp.hxx" #include #include #include 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( sal_uInt16 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, sal_Bool bNoCase ) { sal_uInt16 n = aData.Count(); for( sal_uInt16 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 = (sal_uInt16) -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 { sal_uInt16 nCount = aData.Count(); for( sal_uInt16 i = 0; i < nCount; i++ ) { SbiSymDef* p = aData.GetObject( nCount - i - 1 ); 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( sal_uInt16 n ) const { for( sal_uInt16 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( sal_uInt16 n ) const { if( n >= aData.Count() ) return NULL; else return aData.GetObject( n ); } sal_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(); } sal_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( sal_uInt16 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 = bWithBrackets = bByVal = bChained = bGlobal = sal_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. sal_uInt32 SbiSymDef::Reference() { if( !bChained ) { sal_uInt32 n = nChain; nChain = pIn->pParser->aGen.GetOffset(); return n; } else return nChain; } // Definition eines Symbols. // Hier wird der Backchain aufgeloest, falls vorhanden sal_uInt32 SbiSymDef::Define() { sal_uInt32 n = pIn->pParser->aGen.GetPC(); pIn->pParser->aGen.GenStmnt(); if( nChain ) pIn->pParser->aGen.BackChain( nChain ); nChain = n; bChained = sal_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, sal_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 = sal_True; bCdecl = sal_False; bStatic = sal_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 sal_uInt16 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; }