1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 
21 #include <memory>
22 #include <parser.hxx>
23 
24 #include <osl/diagnose.h>
25 
26 #include <stdio.h>
27 #include <rtl/character.hxx>
28 #include <basic/sberrors.hxx>
29 
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.).
35 
SbiStringPool()36 SbiStringPool::SbiStringPool( )
37 {}
38 
~SbiStringPool()39 SbiStringPool::~SbiStringPool()
40 {}
41 
Find(sal_uInt32 n) const42 OUString SbiStringPool::Find( sal_uInt32 n ) const
43 {
44     if( n == 0 || n > aData.size() )
45         return OUString();
46     else
47         return aData[n - 1];
48 }
49 
Add(const OUString & rVal)50 short SbiStringPool::Add( const OUString& rVal )
51 {
52     sal_uInt32 n = aData.size();
53     for( sal_uInt32 i = 0; i < n; ++i )
54     {
55         OUString& p = aData[i];
56         if( p == rVal )
57             return i+1;
58     }
59 
60     aData.push_back(rVal);
61     return static_cast<short>(++n);
62 }
63 
Add(double n,SbxDataType t)64 short SbiStringPool::Add( double n, SbxDataType t )
65 {
66     char buf[ 40 ];
67     switch( t )
68     {
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;
73         default: break;
74     }
75     return Add( OUString::createFromAscii( buf ) );
76 }
77 
SbiSymPool(SbiStringPool & r,SbiSymScope s,SbiParser * pP)78 SbiSymPool::SbiSymPool( SbiStringPool& r, SbiSymScope s, SbiParser* pP ) : rStrings( r ), pParser( pP )
79 {
80     eScope   = s;
81     pParent  = nullptr;
82     nCur     =
83     nProcId  = 0;
84 }
85 
~SbiSymPool()86 SbiSymPool::~SbiSymPool()
87 {}
88 
89 
First()90 SbiSymDef* SbiSymPool::First()
91 {
92     nCur = sal_uInt16(-1);
93     return Next();
94 }
95 
Next()96 SbiSymDef* SbiSymPool::Next()
97 {
98     if (m_Data.size() <= ++nCur)
99         return nullptr;
100     else
101         return m_Data[ nCur ].get();
102 }
103 
104 
AddSym(const OUString & rName)105 SbiSymDef* SbiSymPool::AddSym( const OUString& rName )
106 {
107     SbiSymDef* p = new SbiSymDef( rName );
108     p->nPos    = m_Data.size();
109     p->nId     = rStrings.Add( rName );
110     p->nProcId = nProcId;
111     p->pIn     = this;
112     m_Data.insert( m_Data.begin() + p->nPos, std::unique_ptr<SbiSymDef>(p) );
113     return p;
114 }
115 
AddProc(const OUString & rName)116 SbiProcDef* SbiSymPool::AddProc( const OUString& rName )
117 {
118     SbiProcDef* p = new SbiProcDef( pParser, rName );
119     p->nPos    = m_Data.size();
120     p->nId     = rStrings.Add( rName );
121     // procs are always local
122     p->nProcId = 0;
123     p->pIn     = this;
124     m_Data.insert( m_Data.begin() + p->nPos, std::unique_ptr<SbiProcDef>(p) );
125     return p;
126 }
127 
128 // adding an externally constructed symbol definition
129 
Add(SbiSymDef * pDef)130 void SbiSymPool::Add( SbiSymDef* pDef )
131 {
132     if( pDef && pDef->pIn != this )
133     {
134         if( pDef->pIn )
135         {
136 #ifdef DBG_UTIL
137 
138             pParser->Error( ERRCODE_BASIC_INTERNAL_ERROR, "Dbl Pool" );
139 #endif
140             return;
141         }
142 
143         pDef->nPos = m_Data.size();
144         if( !pDef->nId )
145         {
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() )
150             {
151                 aName = pParser->aGblStrings.Find( nProcId )
152                       + ":"
153                       + pDef->aName;
154             }
155             pDef->nId = rStrings.Add( aName );
156         }
157 
158         if( !pDef->GetProcDef() )
159         {
160             pDef->nProcId = nProcId;
161         }
162         pDef->pIn = this;
163         m_Data.insert( m_Data.begin() + pDef->nPos, std::unique_ptr<SbiSymDef>(pDef) );
164     }
165 }
166 
167 
Find(const OUString & rName,bool bSearchInParents)168 SbiSymDef* SbiSymPool::Find( const OUString& rName, bool bSearchInParents )
169 {
170     sal_uInt16 nCount = m_Data.size();
171     for( sal_uInt16 i = 0; i < nCount; i++ )
172     {
173         SbiSymDef &r = *m_Data[ nCount - i - 1 ];
174         if( ( !r.nProcId || ( r.nProcId == nProcId)) &&
175             ( r.aName.equalsIgnoreAsciiCase(rName)))
176         {
177             return &r;
178         }
179     }
180     if( bSearchInParents && pParent )
181     {
182         return pParent->Find( rName );
183     }
184     else
185     {
186         return nullptr;
187     }
188 }
189 
190 
191 // find via position (from 0)
192 
Get(sal_uInt16 n)193 SbiSymDef* SbiSymPool::Get( sal_uInt16 n )
194 {
195     if (m_Data.size() <= n)
196     {
197         return nullptr;
198     }
199     else
200     {
201         return m_Data[ n ].get();
202     }
203 }
204 
Define(const OUString & rName)205 sal_uInt32 SbiSymPool::Define( const OUString& rName )
206 {
207     SbiSymDef* p = Find( rName );
208     if( p )
209     {
210         if( p->IsDefined() )
211         {
212             pParser->Error( ERRCODE_BASIC_LABEL_DEFINED, rName );
213         }
214     }
215     else
216     {
217         p = AddSym( rName );
218     }
219     return p->Define();
220 }
221 
Reference(const OUString & rName)222 sal_uInt32 SbiSymPool::Reference( const OUString& rName )
223 {
224     SbiSymDef* p = Find( rName );
225     if( !p )
226     {
227         p = AddSym( rName );
228     }
229     // to be sure
230     pParser->aGen.GenStmnt();
231     return p->Reference();
232 }
233 
234 
CheckRefs()235 void SbiSymPool::CheckRefs()
236 {
237     for (std::unique_ptr<SbiSymDef> & r : m_Data)
238     {
239         if( !r->IsDefined() )
240         {
241             pParser->Error( ERRCODE_BASIC_UNDEF_LABEL, r->GetName() );
242         }
243     }
244 }
245 
SbiSymDef(const OUString & rName)246 SbiSymDef::SbiSymDef( const OUString& rName ) : aName( rName )
247 {
248     eType    = SbxEMPTY;
249     nDims    = 0;
250     nTypeId  = 0;
251     nProcId  = 0;
252     nId      = 0;
253     nPos     = 0;
254     nLen     = 0;
255     nChain   = 0;
256     bAs      =
257     bNew     =
258     bStatic  =
259     bOpt     =
260     bParamArray =
261     bWithEvents =
262     bWithBrackets =
263     bByVal   =
264     bChained =
265     bGlobal  = false;
266     pIn      = nullptr;
267     nDefaultId = 0;
268     nFixedStringLength = -1;
269 }
270 
~SbiSymDef()271 SbiSymDef::~SbiSymDef()
272 {
273 }
274 
GetProcDef()275 SbiProcDef* SbiSymDef::GetProcDef()
276 {
277     return nullptr;
278 }
279 
GetConstDef()280 SbiConstDef* SbiSymDef::GetConstDef()
281 {
282     return nullptr;
283 }
284 
285 
GetName()286 const OUString& SbiSymDef::GetName()
287 {
288     if( pIn )
289     {
290         aName = pIn->rStrings.Find( nId );
291     }
292     return aName;
293 }
294 
295 
SetType(SbxDataType t)296 void SbiSymDef::SetType( SbxDataType t )
297 {
298     if( t == SbxVARIANT && pIn )
299     {
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];
303         if( cu < 256 )
304         {
305             unsigned char ch = static_cast<unsigned char>(cu);
306             if( ch == '_' )
307             {
308                 ch = 'Z';
309             }
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];
314         }
315     }
316     eType = t;
317 }
318 
319 // construct a backchain, if not yet defined
320 // the value that shall be stored as an operand is returned
321 
Reference()322 sal_uInt32 SbiSymDef::Reference()
323 {
324     if( !bChained )
325     {
326         sal_uInt32 n = nChain;
327         nChain = pIn->pParser->aGen.GetOffset();
328         return n;
329     }
330     else return nChain;
331 }
332 
333 
Define()334 sal_uInt32 SbiSymDef::Define()
335 {
336     sal_uInt32 n = pIn->pParser->aGen.GetPC();
337     pIn->pParser->aGen.GenStmnt();
338     if( nChain )
339     {
340         pIn->pParser->aGen.BackChain( nChain );
341     }
342     nChain = n;
343     bChained = true;
344     return nChain;
345 }
346 
347 // A symbol definition may have its own pool. This is the case
348 // for objects and procedures (local variable)
349 
GetPool()350 SbiSymPool& SbiSymDef::GetPool()
351 {
352     if( !pPool )
353     {
354         pPool = std::make_unique<SbiSymPool>( pIn->pParser->aGblStrings, SbLOCAL, pIn->pParser );// is dumped
355     }
356     return *pPool;
357 }
358 
GetScope() const359 SbiSymScope SbiSymDef::GetScope() const
360 {
361     return pIn ? pIn->GetScope() : SbLOCAL;
362 }
363 
364 
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
371 
SbiProcDef(SbiParser * pParser,const OUString & rName,bool bProcDecl)372 SbiProcDef::SbiProcDef( SbiParser* pParser, const OUString& rName,
373                         bool bProcDecl )
374          : SbiSymDef( rName )
375          , aParams( pParser->aGblStrings, SbPARAM, pParser )  // is dumped
376          , aLabels( pParser->aLclStrings, SbLOCAL, pParser )  // is not dumped
377          , mbProcDecl( bProcDecl )
378 {
379     aParams.SetParent( &pParser->aPublics );
380     pPool = std::make_unique<SbiSymPool>( pParser->aGblStrings, SbLOCAL, pParser );
381     pPool->SetParent( &aParams );
382     nLine1  =
383     nLine2  = 0;
384     mePropMode = PropertyMode::NONE;
385     bPublic = true;
386     bCdecl  = false;
387     bStatic = false;
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 );
391 }
392 
~SbiProcDef()393 SbiProcDef::~SbiProcDef()
394 {}
395 
GetProcDef()396 SbiProcDef* SbiProcDef::GetProcDef()
397 {
398     return this;
399 }
400 
SetType(SbxDataType t)401 void SbiProcDef::SetType( SbxDataType t )
402 {
403     SbiSymDef::SetType( t );
404     aParams.Get( 0 )->SetType( eType );
405 }
406 
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!
410 
Match(SbiProcDef * pOld)411 void SbiProcDef::Match( SbiProcDef* pOld )
412 {
413     SbiSymDef *pn=nullptr;
414     // parameter 0 is the function name
415     sal_uInt16 i;
416     for( i = 1; i < aParams.GetSize(); i++ )
417     {
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() )
423         {
424             break;
425         }
426         pOld->aParams.Next();
427     }
428 
429     if( pn && i < aParams.GetSize() && pOld->pIn )
430     {
431         // mark the whole line
432         pOld->pIn->GetParser()->SetCol1( 0 );
433         pOld->pIn->GetParser()->Error( ERRCODE_BASIC_BAD_DECLARATION, aName );
434     }
435 
436     if( !pIn && pOld->pIn )
437     {
438         // Replace old entry with the new one
439         nPos = pOld->nPos;
440         nId  = pOld->nId;
441         pIn  = pOld->pIn;
442 
443         // don't delete pOld twice, if it's stored in m_Data
444         if (pOld == pIn->m_Data[nPos].get())
445             pOld = nullptr;
446         pIn->m_Data[nPos].reset(this);
447     }
448     delete pOld;
449 }
450 
setPropertyMode(PropertyMode ePropMode)451 void SbiProcDef::setPropertyMode( PropertyMode ePropMode )
452 {
453     mePropMode = ePropMode;
454     if( mePropMode != PropertyMode::NONE )
455     {
456         // Prop name = original scanned procedure name
457         maPropName = aName;
458 
459         // CompleteProcName includes "Property xxx "
460         // to avoid conflicts with other symbols
461         OUString aCompleteProcName = "Property ";
462         switch( mePropMode )
463         {
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;
468         }
469         aCompleteProcName += aName;
470         aName = aCompleteProcName;
471     }
472 }
473 
474 
SbiConstDef(const OUString & rName)475 SbiConstDef::SbiConstDef( const OUString& rName )
476            : SbiSymDef( rName )
477 {
478     nVal = 0; eType = SbxINTEGER;
479 }
480 
Set(double n,SbxDataType t)481 void SbiConstDef::Set( double n, SbxDataType t )
482 {
483     aVal.clear(); nVal = n; eType = t;
484 }
485 
Set(const OUString & n)486 void SbiConstDef::Set( const OUString& n )
487 {
488     aVal = n; nVal = 0; eType = SbxSTRING;
489 }
490 
~SbiConstDef()491 SbiConstDef::~SbiConstDef()
492 {}
493 
GetConstDef()494 SbiConstDef* SbiConstDef::GetConstDef()
495 {
496     return this;
497 }
498 
499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
500