summaryrefslogtreecommitdiffstats
path: root/basic/source/comp/symtbl.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--basic/source/comp/symtbl.cxx534
1 files changed, 534 insertions, 0 deletions
diff --git a/basic/source/comp/symtbl.cxx b/basic/source/comp/symtbl.cxx
new file mode 100644
index 000000000..6caa3b2ed
--- /dev/null
+++ b/basic/source/comp/symtbl.cxx
@@ -0,0 +1,534 @@
+/* -*- 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 .
+ */
+
+
+#include <memory>
+#include <parser.hxx>
+
+#include <osl/diagnose.h>
+
+#include <stdio.h>
+#include <rtl/character.hxx>
+#include <basic/sberrors.hxx>
+#include <utility>
+
+// 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.).
+
+SbiStringPool::SbiStringPool( )
+{}
+
+SbiStringPool::~SbiStringPool()
+{}
+
+OUString SbiStringPool::Find( sal_uInt32 n ) const
+{
+ if( n == 0 || n > aData.size() )
+ return OUString();
+ else
+ return aData[n - 1];
+}
+
+short SbiStringPool::Add( const OUString& rVal )
+{
+ sal_uInt32 n = aData.size();
+ for( sal_uInt32 i = 0; i < n; ++i )
+ {
+ OUString& p = aData[i];
+ if( p == rVal )
+ return i+1;
+ }
+
+ aData.push_back(rVal);
+ return static_cast<short>(++n);
+}
+
+short SbiStringPool::Add(double n, SbxDataType t)
+{
+ size_t size = 0;
+ const size_t aBufLength = 40;
+ char buf[aBufLength]{};
+
+ // tdf#143707 - add the type character after the null termination of the string in order to
+ // keep compatibility. After the type character has been added, the buffer contains the value
+ // of the double n, the string termination symbol, and the type character.
+ switch( t )
+ {
+ // tdf#142460 - properly handle boolean values in string pool
+ case SbxBOOL:
+ size = snprintf(buf, sizeof(buf), "%d", static_cast<short>(n)) + 1;
+ buf[size++] = 'b';
+ break;
+ // tdf#131296 - store numeric value including its type character
+ // See GetSuffixType in basic/source/comp/scanner.cxx for type characters
+ case SbxINTEGER:
+ size = snprintf(buf, sizeof(buf), "%d", static_cast<short>(n)) + 1;
+ buf[size++] = '%';
+ break;
+ case SbxLONG:
+ size = snprintf(buf, sizeof(buf), "%" SAL_PRIdINT32, static_cast<sal_Int32>(n)) + 1;
+ buf[size++] = '&';
+ break;
+ case SbxSINGLE:
+ size = snprintf(buf, sizeof(buf), "%.6g", static_cast<float>(n)) + 1;
+ buf[size++] = '!';
+ break;
+ case SbxDOUBLE:
+ size = snprintf(buf, sizeof(buf), "%.16g", n) + 1;
+ buf[size++] = '#';
+ break;
+ case SbxCURRENCY:
+ size = snprintf(buf, sizeof(buf), "%.16g", n) + 1;
+ buf[size++] = '@';
+ break;
+ default: assert(false); break; // should not happen
+ }
+
+ // tdf#143707 - add the content of the buffer to the string pool including its calculated length
+ return Add(OUString::fromUtf8(std::string_view(buf, size)));
+}
+
+SbiSymPool::SbiSymPool( SbiStringPool& r, SbiSymScope s, SbiParser* pP ) :
+ rStrings(r),
+ pParent(nullptr),
+ pParser(pP),
+ eScope(s),
+ nProcId(0),
+ nCur(0)
+{
+}
+
+SbiSymPool::~SbiSymPool()
+{}
+
+
+SbiSymDef* SbiSymPool::First()
+{
+ nCur = sal_uInt16(-1);
+ return Next();
+}
+
+SbiSymDef* SbiSymPool::Next()
+{
+ if (m_Data.size() <= ++nCur)
+ return nullptr;
+ else
+ return m_Data[ nCur ].get();
+}
+
+
+SbiSymDef* SbiSymPool::AddSym( const OUString& rName )
+{
+ SbiSymDef* p = new SbiSymDef( rName );
+ p->nPos = m_Data.size();
+ p->nId = rStrings.Add( rName );
+ p->nProcId = nProcId;
+ p->pIn = this;
+ m_Data.insert( m_Data.begin() + p->nPos, std::unique_ptr<SbiSymDef>(p) );
+ return p;
+}
+
+SbiProcDef* SbiSymPool::AddProc( const OUString& rName )
+{
+ SbiProcDef* p = new SbiProcDef( pParser, rName );
+ p->nPos = m_Data.size();
+ p->nId = rStrings.Add( rName );
+ // procs are always local
+ p->nProcId = 0;
+ p->pIn = this;
+ m_Data.insert( m_Data.begin() + p->nPos, std::unique_ptr<SbiProcDef>(p) );
+ return p;
+}
+
+// adding an externally constructed symbol definition
+
+void SbiSymPool::Add( SbiSymDef* pDef )
+{
+ if( !(pDef && pDef->pIn != this) )
+ return;
+
+ if( pDef->pIn )
+ {
+#ifdef DBG_UTIL
+
+ pParser->Error( ERRCODE_BASIC_INTERNAL_ERROR, "Dbl Pool" );
+#endif
+ return;
+ }
+
+ pDef->nPos = m_Data.size();
+ if( !pDef->nId )
+ {
+ // A unique name must be created in the string pool
+ // for static variables (Form ProcName:VarName)
+ OUString aName( pDef->aName );
+ if( pDef->IsStatic() )
+ {
+ aName = pParser->aGblStrings.Find( nProcId )
+ + ":"
+ + pDef->aName;
+ }
+ pDef->nId = rStrings.Add( aName );
+ }
+
+ if( !pDef->GetProcDef() )
+ {
+ pDef->nProcId = nProcId;
+ }
+ pDef->pIn = this;
+ m_Data.insert( m_Data.begin() + pDef->nPos, std::unique_ptr<SbiSymDef>(pDef) );
+}
+
+
+SbiSymDef* SbiSymPool::Find( const OUString& rName, bool bSearchInParents )
+{
+ sal_uInt16 nCount = m_Data.size();
+ for( sal_uInt16 i = 0; i < nCount; i++ )
+ {
+ SbiSymDef &r = *m_Data[ nCount - i - 1 ];
+ if( ( !r.nProcId || ( r.nProcId == nProcId)) &&
+ ( r.aName.equalsIgnoreAsciiCase(rName)))
+ {
+ return &r;
+ }
+ }
+ if( bSearchInParents && pParent )
+ {
+ return pParent->Find( rName );
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+
+// find via position (from 0)
+
+SbiSymDef* SbiSymPool::Get( sal_uInt16 n )
+{
+ if (m_Data.size() <= n)
+ {
+ return nullptr;
+ }
+ else
+ {
+ return m_Data[ n ].get();
+ }
+}
+
+sal_uInt32 SbiSymPool::Define( const OUString& rName )
+{
+ SbiSymDef* p = Find( rName );
+ if( p )
+ {
+ if( p->IsDefined() )
+ {
+ pParser->Error( ERRCODE_BASIC_LABEL_DEFINED, rName );
+ }
+ }
+ else
+ {
+ p = AddSym( rName );
+ }
+ return p->Define();
+}
+
+sal_uInt32 SbiSymPool::Reference( const OUString& rName )
+{
+ SbiSymDef* p = Find( rName );
+ if( !p )
+ {
+ p = AddSym( rName );
+ }
+ // to be sure
+ pParser->aGen.GenStmnt();
+ return p->Reference();
+}
+
+
+void SbiSymPool::CheckRefs()
+{
+ for (std::unique_ptr<SbiSymDef> & r : m_Data)
+ {
+ if( !r->IsDefined() )
+ {
+ pParser->Error( ERRCODE_BASIC_UNDEF_LABEL, r->GetName() );
+ }
+ }
+}
+
+SbiSymDef::SbiSymDef( OUString _aName ) :
+ aName(std::move(_aName)),
+ eType(SbxEMPTY),
+ pIn(nullptr),
+ nLen(0),
+ nDims(0),
+ nId(0),
+ nTypeId(0),
+ nProcId(0),
+ nPos(0),
+ nChain(0),
+ bNew(false),
+ bChained(false),
+ bByVal(false),
+ bOpt(false),
+ bStatic(false),
+ bAs(false),
+ bGlobal(false),
+ bParamArray(false),
+ bWithEvents(false),
+ bWithBrackets(false),
+ nDefaultId(0),
+ nFixedStringLength(-1)
+{
+}
+
+SbiSymDef::~SbiSymDef()
+{
+}
+
+SbiProcDef* SbiSymDef::GetProcDef()
+{
+ return nullptr;
+}
+
+SbiConstDef* SbiSymDef::GetConstDef()
+{
+ return nullptr;
+}
+
+
+const OUString& SbiSymDef::GetName()
+{
+ if( pIn )
+ {
+ aName = pIn->rStrings.Find( nId );
+ }
+ 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];
+ }
+ }
+ eType = t;
+}
+
+// construct a backchain, if not yet defined
+// the value that shall be stored as an operand is returned
+
+sal_uInt32 SbiSymDef::Reference()
+{
+ if( !bChained )
+ {
+ sal_uInt32 n = nChain;
+ nChain = pIn->pParser->aGen.GetOffset();
+ return n;
+ }
+ else return nChain;
+}
+
+
+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 = true;
+ return nChain;
+}
+
+// A symbol definition may have its own pool. This is the case
+// for objects and procedures (local variable)
+
+SbiSymPool& SbiSymDef::GetPool()
+{
+ if( !pPool )
+ {
+ pPool = std::make_unique<SbiSymPool>( pIn->pParser->aGblStrings, SbLOCAL, pIn->pParser );// is dumped
+ }
+ 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
+
+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 )
+{
+ aParams.SetParent( &pParser->aPublics );
+ pPool = std::make_unique<SbiSymPool>( pParser->aGblStrings, SbLOCAL, pParser );
+ 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
+ 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!
+
+void SbiProcDef::Match( SbiProcDef* pOld )
+{
+ SbiSymDef *pn=nullptr;
+ // parameter 0 is the function name
+ sal_uInt16 i;
+ for( i = 1; i < aParams.GetSize(); i++ )
+ {
+ SbiSymDef* po = pOld->aParams.Get( i );
+ 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() )
+ {
+ break;
+ }
+ pOld->aParams.Next();
+ }
+
+ if( pn && i < aParams.GetSize() && pOld->pIn )
+ {
+ // mark the whole line
+ pOld->pIn->GetParser()->SetCol1( 0 );
+ pOld->pIn->GetParser()->Error( ERRCODE_BASIC_BAD_DECLARATION, aName );
+ }
+
+ if( !pIn && pOld->pIn )
+ {
+ // Replace old entry with the new one
+ 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);
+ }
+ delete pOld;
+}
+
+void SbiProcDef::setPropertyMode( PropertyMode ePropMode )
+{
+ mePropMode = ePropMode;
+ if( mePropMode == PropertyMode::NONE )
+ return;
+
+ // 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 )
+ : SbiSymDef( rName )
+{
+ nVal = 0; eType = SbxINTEGER;
+}
+
+void SbiConstDef::Set( double n, SbxDataType t )
+{
+ aVal.clear(); nVal = n; eType = t;
+}
+
+void SbiConstDef::Set( const OUString& n )
+{
+ aVal = n; nVal = 0; eType = SbxSTRING;
+}
+
+SbiConstDef::~SbiConstDef()
+{}
+
+SbiConstDef* SbiConstDef::GetConstDef()
+{
+ return this;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */