blob: 2ec80c777e07c74a41e5ae92dd108834e226dad4 [file] [log] [blame]
/**************************************************************
*
* 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 <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( 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;
}