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

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

503 lines
12 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* 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 .
*/
2000-09-18 15:18:56 +00:00
#include <memory>
#include <parser.hxx>
#include <osl/diagnose.h>
2000-09-18 15:18:56 +00:00
#include <stdio.h>
#include <rtl/character.hxx>
#include <basic/sberrors.hxx>
2000-09-18 15:18:56 +00:00
// All symbol names are laid down int the symbol-pool's stringpool, so that
// all symbols are handled in the same case. On saving the code-image, the
// global stringpool with the respective symbols is also saved.
// The local stringpool holds all the symbols that don't move to the image
// (labels, constant names etc.).
2000-09-18 15:18:56 +00:00
SbiStringPool::SbiStringPool( )
{}
2000-09-18 15:18:56 +00:00
SbiStringPool::~SbiStringPool()
{}
OUString SbiStringPool::Find( sal_uInt32 n ) const
2000-09-18 15:18:56 +00:00
{
2011-11-20 23:44:21 -05:00
if( n == 0 || n > aData.size() )
return OUString();
2000-09-18 15:18:56 +00:00
else
2011-11-20 23:44:21 -05:00
return aData[n - 1];
2000-09-18 15:18:56 +00:00
}
short SbiStringPool::Add( const OUString& rVal )
2000-09-18 15:18:56 +00:00
{
2011-11-20 23:44:21 -05:00
sal_uInt32 n = aData.size();
for( sal_uInt32 i = 0; i < n; ++i )
2000-09-18 15:18:56 +00:00
{
OUString& p = aData[i];
if( p == rVal )
2000-09-18 15:18:56 +00:00
return i+1;
}
2011-11-20 23:44:21 -05:00
aData.push_back(rVal);
return static_cast<short>(++n);
2000-09-18 15:18:56 +00:00
}
short SbiStringPool::Add( double n, SbxDataType t )
{
char buf[40]{};
2000-09-18 15:18:56 +00:00
switch( t )
{
// tdf#131296 - store numeric value including its type character
// See GetSuffixType in basic/source/comp/scanner.cxx for type characters
case SbxINTEGER: snprintf( buf, sizeof(buf), "%d%%", static_cast<short>(n) ); break;
case SbxLONG: snprintf( buf, sizeof(buf), "%ld&", static_cast<long>(n) ); break;
case SbxSINGLE: snprintf( buf, sizeof(buf), "%.6g!", static_cast<float>(n) ); break;
case SbxDOUBLE: snprintf( buf, sizeof(buf), "%.16g", n ); break; // default processing in SbiRuntime::StepLOADNC - no type character
case SbxCURRENCY: snprintf(buf, sizeof(buf), "%.16g@", n); break;
default: assert(false); break; // should not happen
2000-09-18 15:18:56 +00:00
}
return Add( OUString::createFromAscii( buf ) );
2000-09-18 15:18:56 +00:00
}
SbiSymPool::SbiSymPool( SbiStringPool& r, SbiSymScope s, SbiParser* pP ) : rStrings( r ), pParser( pP )
2000-09-18 15:18:56 +00:00
{
eScope = s;
pParent = nullptr;
2000-09-18 15:18:56 +00:00
nCur =
nProcId = 0;
}
SbiSymPool::~SbiSymPool()
{}
SbiSymDef* SbiSymPool::First()
{
nCur = sal_uInt16(-1);
2000-09-18 15:18:56 +00:00
return Next();
}
SbiSymDef* SbiSymPool::Next()
{
if (m_Data.size() <= ++nCur)
return nullptr;
2000-09-18 15:18:56 +00:00
else
return m_Data[ nCur ].get();
2000-09-18 15:18:56 +00:00
}
SbiSymDef* SbiSymPool::AddSym( const OUString& rName )
2000-09-18 15:18:56 +00:00
{
SbiSymDef* p = new SbiSymDef( rName );
p->nPos = m_Data.size();
2000-09-18 15:18:56 +00:00
p->nId = rStrings.Add( rName );
p->nProcId = nProcId;
p->pIn = this;
m_Data.insert( m_Data.begin() + p->nPos, std::unique_ptr<SbiSymDef>(p) );
2000-09-18 15:18:56 +00:00
return p;
}
SbiProcDef* SbiSymPool::AddProc( const OUString& rName )
2000-09-18 15:18:56 +00:00
{
SbiProcDef* p = new SbiProcDef( pParser, rName );
p->nPos = m_Data.size();
2000-09-18 15:18:56 +00:00
p->nId = rStrings.Add( rName );
// procs are always local
2000-09-18 15:18:56 +00:00
p->nProcId = 0;
p->pIn = this;
m_Data.insert( m_Data.begin() + p->nPos, std::unique_ptr<SbiProcDef>(p) );
2000-09-18 15:18:56 +00:00
return p;
}
// adding an externally constructed symbol definition
2000-09-18 15:18:56 +00:00
void SbiSymPool::Add( SbiSymDef* pDef )
{
if( pDef && pDef->pIn != this )
{
if( pDef->pIn )
{
#ifdef DBG_UTIL
pParser->Error( ERRCODE_BASIC_INTERNAL_ERROR, "Dbl Pool" );
2000-09-18 15:18:56 +00:00
#endif
return;
}
pDef->nPos = m_Data.size();
2000-09-18 15:18:56 +00:00
if( !pDef->nId )
{
// A unique name must be created in the string pool
// for static variables (Form ProcName:VarName)
OUString aName( pDef->aName );
2000-09-18 15:18:56 +00:00
if( pDef->IsStatic() )
{
aName = pParser->aGblStrings.Find( nProcId )
+ ":"
+ pDef->aName;
2000-09-18 15:18:56 +00:00
}
pDef->nId = rStrings.Add( aName );
}
2000-09-18 15:18:56 +00:00
if( !pDef->GetProcDef() )
{
2000-09-18 15:18:56 +00:00
pDef->nProcId = nProcId;
}
2000-09-18 15:18:56 +00:00
pDef->pIn = this;
m_Data.insert( m_Data.begin() + pDef->nPos, std::unique_ptr<SbiSymDef>(pDef) );
2000-09-18 15:18:56 +00:00
}
}
SbiSymDef* SbiSymPool::Find( const OUString& rName, bool bSearchInParents )
2000-09-18 15:18:56 +00:00
{
sal_uInt16 nCount = m_Data.size();
for( sal_uInt16 i = 0; i < nCount; i++ )
2000-09-18 15:18:56 +00:00
{
SbiSymDef &r = *m_Data[ nCount - i - 1 ];
if( ( !r.nProcId || ( r.nProcId == nProcId)) &&
( r.aName.equalsIgnoreAsciiCase(rName)))
{
return &r;
}
2000-09-18 15:18:56 +00:00
}
if( bSearchInParents && pParent )
{
2000-09-18 15:18:56 +00:00
return pParent->Find( rName );
}
2000-09-18 15:18:56 +00:00
else
{
return nullptr;
}
2000-09-18 15:18:56 +00:00
}
// find via position (from 0)
2000-09-18 15:18:56 +00:00
SbiSymDef* SbiSymPool::Get( sal_uInt16 n )
2000-09-18 15:18:56 +00:00
{
if (m_Data.size() <= n)
{
return nullptr;
}
2000-09-18 15:18:56 +00:00
else
{
return m_Data[ n ].get();
}
2000-09-18 15:18:56 +00:00
}
sal_uInt32 SbiSymPool::Define( const OUString& rName )
2000-09-18 15:18:56 +00:00
{
SbiSymDef* p = Find( rName );
if( p )
{
if( p->IsDefined() )
{
pParser->Error( ERRCODE_BASIC_LABEL_DEFINED, rName );
}
2000-09-18 15:18:56 +00:00
}
else
{
2000-09-18 15:18:56 +00:00
p = AddSym( rName );
}
2000-09-18 15:18:56 +00:00
return p->Define();
}
sal_uInt32 SbiSymPool::Reference( const OUString& rName )
2000-09-18 15:18:56 +00:00
{
SbiSymDef* p = Find( rName );
if( !p )
{
2000-09-18 15:18:56 +00:00
p = AddSym( rName );
}
// to be sure
2000-09-18 15:18:56 +00:00
pParser->aGen.GenStmnt();
return p->Reference();
}
void SbiSymPool::CheckRefs()
{
for (std::unique_ptr<SbiSymDef> & r : m_Data)
2000-09-18 15:18:56 +00:00
{
if( !r->IsDefined() )
{
pParser->Error( ERRCODE_BASIC_UNDEF_LABEL, r->GetName() );
}
2000-09-18 15:18:56 +00:00
}
}
SbiSymDef::SbiSymDef( const OUString& rName ) : aName( rName )
2000-09-18 15:18:56 +00:00
{
eType = SbxEMPTY;
2006-11-03 14:11:10 +00:00
nDims = 0;
nTypeId = 0;
nProcId = 0;
nId = 0;
nPos = 0;
nLen = 0;
2000-09-18 15:18:56 +00:00
nChain = 0;
bAs =
bNew =
bStatic =
bOpt =
bParamArray =
bWithEvents =
bWithBrackets =
2000-09-18 15:18:56 +00:00
bByVal =
bChained =
bGlobal = false;
pIn = nullptr;
nDefaultId = 0;
nFixedStringLength = -1;
2000-09-18 15:18:56 +00:00
}
SbiSymDef::~SbiSymDef()
{
}
SbiProcDef* SbiSymDef::GetProcDef()
{
return nullptr;
2000-09-18 15:18:56 +00:00
}
SbiConstDef* SbiSymDef::GetConstDef()
{
return nullptr;
2000-09-18 15:18:56 +00:00
}
const OUString& SbiSymDef::GetName()
2000-09-18 15:18:56 +00:00
{
if( pIn )
{
2000-09-18 15:18:56 +00:00
aName = pIn->rStrings.Find( nId );
}
2000-09-18 15:18:56 +00:00
return aName;
}
void SbiSymDef::SetType( SbxDataType t )
{
if( t == SbxVARIANT && pIn )
{
//See if there have been any deftype statements to set the default type
//of a variable based on its starting letter
sal_Unicode cu = aName[0];
if( cu < 256 )
{
unsigned char ch = static_cast<unsigned char>(cu);
if( ch == '_' )
{
ch = 'Z';
}
int ch2 = rtl::toAsciiUpperCase( ch );
int nIndex = ch2 - 'A';
if (nIndex >= 0 && nIndex < N_DEF_TYPES)
t = pIn->pParser->eDefTypes[nIndex];
}
2000-09-18 15:18:56 +00:00
}
eType = t;
}
// construct a backchain, if not yet defined
// the value that shall be stored as an operand is returned
2000-09-18 15:18:56 +00:00
sal_uInt32 SbiSymDef::Reference()
2000-09-18 15:18:56 +00:00
{
if( !bChained )
{
sal_uInt32 n = nChain;
2000-09-18 15:18:56 +00:00
nChain = pIn->pParser->aGen.GetOffset();
return n;
}
else return nChain;
}
sal_uInt32 SbiSymDef::Define()
2000-09-18 15:18:56 +00:00
{
sal_uInt32 n = pIn->pParser->aGen.GetPC();
2000-09-18 15:18:56 +00:00
pIn->pParser->aGen.GenStmnt();
if( nChain )
{
pIn->pParser->aGen.BackChain( nChain );
}
2000-09-18 15:18:56 +00:00
nChain = n;
bChained = true;
2000-09-18 15:18:56 +00:00
return nChain;
}
// A symbol definition may have its own pool. This is the case
// for objects and procedures (local variable)
2000-09-18 15:18:56 +00:00
SbiSymPool& SbiSymDef::GetPool()
{
if( !pPool )
{
pPool = std::make_unique<SbiSymPool>( pIn->pParser->aGblStrings, SbLOCAL, pIn->pParser );// is dumped
}
2000-09-18 15:18:56 +00:00
return *pPool;
}
SbiSymScope SbiSymDef::GetScope() const
{
return pIn ? pIn->GetScope() : SbLOCAL;
}
// The procedure definition has three pools:
// 1) aParams: is filled by the definition. Contains the
// parameters' names, like they're used inside the body.
// The first element is the return value.
// 2) pPool: all local variables
// 3) aLabels: labels
2000-09-18 15:18:56 +00:00
SbiProcDef::SbiProcDef( SbiParser* pParser, const OUString& rName,
bool bProcDecl )
: SbiSymDef( rName )
, aParams( pParser->aGblStrings, SbPARAM, pParser ) // is dumped
, aLabels( pParser->aLclStrings, SbLOCAL, pParser ) // is not dumped
, mbProcDecl( bProcDecl )
2000-09-18 15:18:56 +00:00
{
aParams.SetParent( &pParser->aPublics );
pPool = std::make_unique<SbiSymPool>( pParser->aGblStrings, SbLOCAL, pParser );
2000-09-18 15:18:56 +00:00
pPool->SetParent( &aParams );
nLine1 =
nLine2 = 0;
mePropMode = PropertyMode::NONE;
bPublic = true;
bCdecl = false;
bStatic = false;
// For return values the first element of the parameter
// list is always defined with name and type of the proc
2000-09-18 15:18:56 +00:00
aParams.AddSym( aName );
}
SbiProcDef::~SbiProcDef()
{}
SbiProcDef* SbiProcDef::GetProcDef()
{
return this;
}
void SbiProcDef::SetType( SbxDataType t )
{
SbiSymDef::SetType( t );
aParams.Get( 0 )->SetType( eType );
}
// match with a forward-declaration
// if the match is OK, pOld is replaced by this in the pool
// pOld is deleted in any case!
2000-09-18 15:18:56 +00:00
void SbiProcDef::Match( SbiProcDef* pOld )
2000-09-18 15:18:56 +00:00
{
SbiSymDef *pn=nullptr;
// parameter 0 is the function name
sal_uInt16 i;
2000-09-18 15:18:56 +00:00
for( i = 1; i < aParams.GetSize(); i++ )
{
SbiSymDef* po = pOld->aParams.Get( i );
2000-09-18 15:18:56 +00:00
pn = aParams.Get( i );
// no type matching - that is done during running
// but is it maybe called with too little parameters?
if( !po && !pn->IsOptional() && !pn->IsParamArray() )
{
2000-09-18 15:18:56 +00:00
break;
}
pOld->aParams.Next();
2000-09-18 15:18:56 +00:00
}
2000-09-18 15:18:56 +00:00
if( pn && i < aParams.GetSize() && pOld->pIn )
{
// mark the whole line
2000-09-18 15:18:56 +00:00
pOld->pIn->GetParser()->SetCol1( 0 );
pOld->pIn->GetParser()->Error( ERRCODE_BASIC_BAD_DECLARATION, aName );
2000-09-18 15:18:56 +00:00
}
2000-09-18 15:18:56 +00:00
if( !pIn && pOld->pIn )
{
// Replace old entry with the new one
2000-09-18 15:18:56 +00:00
nPos = pOld->nPos;
nId = pOld->nId;
pIn = pOld->pIn;
// don't delete pOld twice, if it's stored in m_Data
if (pOld == pIn->m_Data[nPos].get())
pOld = nullptr;
pIn->m_Data[nPos].reset(this);
2000-09-18 15:18:56 +00:00
}
delete pOld;
2000-09-18 15:18:56 +00:00
}
void SbiProcDef::setPropertyMode( PropertyMode ePropMode )
{
mePropMode = ePropMode;
if( mePropMode != PropertyMode::NONE )
{
// Prop name = original scanned procedure name
maPropName = aName;
// CompleteProcName includes "Property xxx "
// to avoid conflicts with other symbols
OUString aCompleteProcName = "Property ";
switch( mePropMode )
{
case PropertyMode::Get: aCompleteProcName += "Get "; break;
case PropertyMode::Let: aCompleteProcName += "Let "; break;
case PropertyMode::Set: aCompleteProcName += "Set "; break;
case PropertyMode::NONE: OSL_FAIL( "Illegal PropertyMode PropertyMode::NONE" ); break;
}
aCompleteProcName += aName;
aName = aCompleteProcName;
}
}
SbiConstDef::SbiConstDef( const OUString& rName )
2000-09-18 15:18:56 +00:00
: SbiSymDef( rName )
{
nVal = 0; eType = SbxINTEGER;
}
void SbiConstDef::Set( double n, SbxDataType t )
{
aVal.clear(); nVal = n; eType = t;
2000-09-18 15:18:56 +00:00
}
void SbiConstDef::Set( const OUString& n )
2000-09-18 15:18:56 +00:00
{
aVal = n; nVal = 0; eType = SbxSTRING;
}
SbiConstDef::~SbiConstDef()
{}
SbiConstDef* SbiConstDef::GetConstDef()
{
return this;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */