1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
24 #include <osl/diagnose.h>
27 #include <rtl/character.hxx>
28 #include <basic/sberrors.hxx>
30 // All symbol names are laid down int the symbol-pool's stringpool, so that
31 // all symbols are handled in the same case. On saving the code-image, the
32 // global stringpool with the respective symbols is also saved.
33 // The local stringpool holds all the symbols that don't move to the image
34 // (labels, constant names etc.).
36 SbiStringPool::SbiStringPool( )
39 SbiStringPool::~SbiStringPool()
42 OUString
SbiStringPool::Find( sal_uInt32 n
) const
44 if( n
== 0 || n
> aData
.size() )
50 short SbiStringPool::Add( const OUString
& rVal
)
52 sal_uInt32 n
= aData
.size();
53 for( sal_uInt32 i
= 0; i
< n
; ++i
)
55 OUString
& p
= aData
[i
];
60 aData
.push_back(rVal
);
61 return static_cast<short>(++n
);
64 short SbiStringPool::Add( double n
, SbxDataType t
)
69 case SbxINTEGER
: snprintf( buf
, sizeof(buf
), "%d", static_cast<short>(n
) ); break;
70 case SbxLONG
: snprintf( buf
, sizeof(buf
), "%ld", static_cast<long>(n
) ); break;
71 case SbxSINGLE
: snprintf( buf
, sizeof(buf
), "%.6g", static_cast<float>(n
) ); break;
72 case SbxDOUBLE
: snprintf( buf
, sizeof(buf
), "%.16g", n
); break;
75 return Add( OUString::createFromAscii( buf
) );
78 SbiSymPool::SbiSymPool( SbiStringPool
& r
, SbiSymScope s
, SbiParser
* pP
) : rStrings( r
), pParser( pP
)
86 SbiSymPool::~SbiSymPool()
90 SbiSymDef
* SbiSymPool::First()
92 nCur
= sal_uInt16(-1);
96 SbiSymDef
* SbiSymPool::Next()
98 if (m_Data
.size() <= ++nCur
)
101 return m_Data
[ nCur
].get();
105 SbiSymDef
* SbiSymPool::AddSym( const OUString
& rName
)
107 SbiSymDef
* p
= new SbiSymDef( rName
);
108 p
->nPos
= m_Data
.size();
109 p
->nId
= rStrings
.Add( rName
);
110 p
->nProcId
= nProcId
;
112 m_Data
.insert( m_Data
.begin() + p
->nPos
, std::unique_ptr
<SbiSymDef
>(p
) );
116 SbiProcDef
* SbiSymPool::AddProc( const OUString
& rName
)
118 SbiProcDef
* p
= new SbiProcDef( pParser
, rName
);
119 p
->nPos
= m_Data
.size();
120 p
->nId
= rStrings
.Add( rName
);
121 // procs are always local
124 m_Data
.insert( m_Data
.begin() + p
->nPos
, std::unique_ptr
<SbiProcDef
>(p
) );
128 // adding an externally constructed symbol definition
130 void SbiSymPool::Add( SbiSymDef
* pDef
)
132 if( pDef
&& pDef
->pIn
!= this )
138 pParser
->Error( ERRCODE_BASIC_INTERNAL_ERROR
, "Dbl Pool" );
143 pDef
->nPos
= m_Data
.size();
146 // A unique name must be created in the string pool
147 // for static variables (Form ProcName:VarName)
148 OUString
aName( pDef
->aName
);
149 if( pDef
->IsStatic() )
151 aName
= pParser
->aGblStrings
.Find( nProcId
)
155 pDef
->nId
= rStrings
.Add( aName
);
158 if( !pDef
->GetProcDef() )
160 pDef
->nProcId
= nProcId
;
163 m_Data
.insert( m_Data
.begin() + pDef
->nPos
, std::unique_ptr
<SbiSymDef
>(pDef
) );
168 SbiSymDef
* SbiSymPool::Find( const OUString
& rName
, bool bSearchInParents
)
170 sal_uInt16 nCount
= m_Data
.size();
171 for( sal_uInt16 i
= 0; i
< nCount
; i
++ )
173 SbiSymDef
&r
= *m_Data
[ nCount
- i
- 1 ];
174 if( ( !r
.nProcId
|| ( r
.nProcId
== nProcId
)) &&
175 ( r
.aName
.equalsIgnoreAsciiCase(rName
)))
180 if( bSearchInParents
&& pParent
)
182 return pParent
->Find( rName
);
191 // find via position (from 0)
193 SbiSymDef
* SbiSymPool::Get( sal_uInt16 n
)
195 if (m_Data
.size() <= n
)
201 return m_Data
[ n
].get();
205 sal_uInt32
SbiSymPool::Define( const OUString
& rName
)
207 SbiSymDef
* p
= Find( rName
);
212 pParser
->Error( ERRCODE_BASIC_LABEL_DEFINED
, rName
);
222 sal_uInt32
SbiSymPool::Reference( const OUString
& rName
)
224 SbiSymDef
* p
= Find( rName
);
230 pParser
->aGen
.GenStmnt();
231 return p
->Reference();
235 void SbiSymPool::CheckRefs()
237 for (std::unique_ptr
<SbiSymDef
> & r
: m_Data
)
239 if( !r
->IsDefined() )
241 pParser
->Error( ERRCODE_BASIC_UNDEF_LABEL
, r
->GetName() );
246 SbiSymDef::SbiSymDef( const OUString
& rName
) : aName( rName
)
268 nFixedStringLength
= -1;
271 SbiSymDef::~SbiSymDef()
275 SbiProcDef
* SbiSymDef::GetProcDef()
280 SbiConstDef
* SbiSymDef::GetConstDef()
286 const OUString
& SbiSymDef::GetName()
290 aName
= pIn
->rStrings
.Find( nId
);
296 void SbiSymDef::SetType( SbxDataType t
)
298 if( t
== SbxVARIANT
&& pIn
)
300 //See if there have been any deftype statements to set the default type
301 //of a variable based on its starting letter
302 sal_Unicode cu
= aName
[0];
305 unsigned char ch
= static_cast<unsigned char>(cu
);
310 int ch2
= rtl::toAsciiUpperCase( ch
);
311 int nIndex
= ch2
- 'A';
312 if (nIndex
>= 0 && nIndex
< N_DEF_TYPES
)
313 t
= pIn
->pParser
->eDefTypes
[nIndex
];
319 // construct a backchain, if not yet defined
320 // the value that shall be stored as an operand is returned
322 sal_uInt32
SbiSymDef::Reference()
326 sal_uInt32 n
= nChain
;
327 nChain
= pIn
->pParser
->aGen
.GetOffset();
334 sal_uInt32
SbiSymDef::Define()
336 sal_uInt32 n
= pIn
->pParser
->aGen
.GetPC();
337 pIn
->pParser
->aGen
.GenStmnt();
340 pIn
->pParser
->aGen
.BackChain( nChain
);
347 // A symbol definition may have its own pool. This is the case
348 // for objects and procedures (local variable)
350 SbiSymPool
& SbiSymDef::GetPool()
354 pPool
= std::make_unique
<SbiSymPool
>( pIn
->pParser
->aGblStrings
, SbLOCAL
, pIn
->pParser
);// is dumped
359 SbiSymScope
SbiSymDef::GetScope() const
361 return pIn
? pIn
->GetScope() : SbLOCAL
;
365 // The procedure definition has three pools:
366 // 1) aParams: is filled by the definition. Contains the
367 // parameters' names, like they're used inside the body.
368 // The first element is the return value.
369 // 2) pPool: all local variables
370 // 3) aLabels: labels
372 SbiProcDef::SbiProcDef( SbiParser
* pParser
, const OUString
& rName
,
375 , aParams( pParser
->aGblStrings
, SbPARAM
, pParser
) // is dumped
376 , aLabels( pParser
->aLclStrings
, SbLOCAL
, pParser
) // is not dumped
377 , mbProcDecl( bProcDecl
)
379 aParams
.SetParent( &pParser
->aPublics
);
380 pPool
= std::make_unique
<SbiSymPool
>( pParser
->aGblStrings
, SbLOCAL
, pParser
);
381 pPool
->SetParent( &aParams
);
384 mePropMode
= PropertyMode::NONE
;
388 // For return values the first element of the parameter
389 // list is always defined with name and type of the proc
390 aParams
.AddSym( aName
);
393 SbiProcDef::~SbiProcDef()
396 SbiProcDef
* SbiProcDef::GetProcDef()
401 void SbiProcDef::SetType( SbxDataType t
)
403 SbiSymDef::SetType( t
);
404 aParams
.Get( 0 )->SetType( eType
);
407 // match with a forward-declaration
408 // if the match is OK, pOld is replaced by this in the pool
409 // pOld is deleted in any case!
411 void SbiProcDef::Match( SbiProcDef
* pOld
)
413 SbiSymDef
*pn
=nullptr;
414 // parameter 0 is the function name
416 for( i
= 1; i
< aParams
.GetSize(); i
++ )
418 SbiSymDef
* po
= pOld
->aParams
.Get( i
);
419 pn
= aParams
.Get( i
);
420 // no type matching - that is done during running
421 // but is it maybe called with too little parameters?
422 if( !po
&& !pn
->IsOptional() && !pn
->IsParamArray() )
426 pOld
->aParams
.Next();
429 if( pn
&& i
< aParams
.GetSize() && pOld
->pIn
)
431 // mark the whole line
432 pOld
->pIn
->GetParser()->SetCol1( 0 );
433 pOld
->pIn
->GetParser()->Error( ERRCODE_BASIC_BAD_DECLARATION
, aName
);
436 if( !pIn
&& pOld
->pIn
)
438 // Replace old entry with the new one
443 // don't delete pOld twice, if it's stored in m_Data
444 if (pOld
== pIn
->m_Data
[nPos
].get())
446 pIn
->m_Data
[nPos
].reset(this);
451 void SbiProcDef::setPropertyMode( PropertyMode ePropMode
)
453 mePropMode
= ePropMode
;
454 if( mePropMode
!= PropertyMode::NONE
)
456 // Prop name = original scanned procedure name
459 // CompleteProcName includes "Property xxx "
460 // to avoid conflicts with other symbols
461 OUString aCompleteProcName
= "Property ";
464 case PropertyMode::Get
: aCompleteProcName
+= "Get "; break;
465 case PropertyMode::Let
: aCompleteProcName
+= "Let "; break;
466 case PropertyMode::Set
: aCompleteProcName
+= "Set "; break;
467 case PropertyMode::NONE
: OSL_FAIL( "Illegal PropertyMode PropertyMode::NONE" ); break;
469 aCompleteProcName
+= aName
;
470 aName
= aCompleteProcName
;
475 SbiConstDef::SbiConstDef( const OUString
& rName
)
478 nVal
= 0; eType
= SbxINTEGER
;
481 void SbiConstDef::Set( double n
, SbxDataType t
)
483 aVal
.clear(); nVal
= n
; eType
= t
;
486 void SbiConstDef::Set( const OUString
& n
)
488 aVal
= n
; nVal
= 0; eType
= SbxSTRING
;
491 SbiConstDef::~SbiConstDef()
494 SbiConstDef
* SbiConstDef::GetConstDef()
499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */