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 <string.h> 28 #include <rtl/character.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 36 SbiStringPool::SbiStringPool( ) 37 {} 38 39 SbiStringPool::~SbiStringPool() 40 {} 41 42 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 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 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 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 86 SbiSymPool::~SbiSymPool() 87 {} 88 89 90 SbiSymDef* SbiSymPool::First() 91 { 92 nCur = sal_uInt16(-1); 93 return Next(); 94 } 95 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 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 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 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 168 SbiSymDef* SbiSymPool::Find( const OUString& rName ) 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( 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 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 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 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 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 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 271 SbiSymDef::~SbiSymDef() 272 { 273 } 274 275 SbiProcDef* SbiSymDef::GetProcDef() 276 { 277 return nullptr; 278 } 279 280 SbiConstDef* SbiSymDef::GetConstDef() 281 { 282 return nullptr; 283 } 284 285 286 const OUString& SbiSymDef::GetName() 287 { 288 if( pIn ) 289 { 290 aName = pIn->rStrings.Find( nId ); 291 } 292 return aName; 293 } 294 295 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 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 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 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 359 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 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 393 SbiProcDef::~SbiProcDef() 394 {} 395 396 SbiProcDef* SbiProcDef::GetProcDef() 397 { 398 return this; 399 } 400 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 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 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 475 SbiConstDef::SbiConstDef( const OUString& rName ) 476 : SbiSymDef( rName ) 477 { 478 nVal = 0; eType = SbxINTEGER; 479 } 480 481 void SbiConstDef::Set( double n, SbxDataType t ) 482 { 483 aVal.clear(); nVal = n; eType = t; 484 } 485 486 void SbiConstDef::Set( const OUString& n ) 487 { 488 aVal = n; nVal = 0; eType = SbxSTRING; 489 } 490 491 SbiConstDef::~SbiConstDef() 492 {} 493 494 SbiConstDef* SbiConstDef::GetConstDef() 495 { 496 return this; 497 } 498 499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 500
