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