1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_basic.hxx" 30 31 #include "sbcomp.hxx" 32 #include <stdio.h> 33 #include <string.h> 34 #include <ctype.h> 35 36 SV_IMPL_PTRARR(SbiStrings,String*) 37 SV_IMPL_PTRARR(SbiSymbols,SbiSymDef*) 38 39 // Alle Symbolnamen werden im Stringpool des Symbol-Pools abgelegt, damit 40 // alle Symbole im gleichen Case verarbeitet werden. Beim Speichern des 41 // Code-Images wird der globale Stringpool mit den entsprechenden Sympools 42 // gespeichert. Der lokale Stringpool nimmt alle Symbole auf, die nicht 43 // ins Image wandern (Labels, Konstantennamen etc). 44 45 /*************************************************************************** 46 |* 47 |* SbiStringPool 48 |* 49 ***************************************************************************/ 50 51 SbiStringPool::SbiStringPool( SbiParser* p ) 52 { 53 pParser = p; 54 } 55 56 SbiStringPool::~SbiStringPool() 57 {} 58 59 // Suchen 60 61 const String& SbiStringPool::Find( sal_uInt16 n ) const 62 { 63 if( !n || n > aData.Count() ) 64 return aEmpty; 65 else 66 return *aData.GetObject( n-1 ); 67 } 68 69 // Hinzufuegen eines Strings. Der String wird Case-Insensitiv 70 // verglichen. 71 72 short SbiStringPool::Add( const String& rVal, sal_Bool bNoCase ) 73 { 74 sal_uInt16 n = aData.Count(); 75 for( sal_uInt16 i = 0; i < n; i++ ) 76 { 77 String* p = aData.GetObject( i ); 78 if( ( bNoCase && p->Equals( rVal ) ) 79 || ( !bNoCase && p->EqualsIgnoreCaseAscii( rVal ) ) ) 80 return i+1; 81 } 82 const String* pNew = new String( rVal ); 83 aData.Insert( pNew, n++ ); 84 return (short) n; 85 } 86 87 short SbiStringPool::Add( double n, SbxDataType t ) 88 { 89 char buf[ 40 ]; 90 switch( t ) 91 { 92 case SbxINTEGER: snprintf( buf, sizeof(buf), "%d", (short) n ); break; 93 case SbxLONG: snprintf( buf, sizeof(buf), "%ld", (long) n ); break; 94 case SbxSINGLE: snprintf( buf, sizeof(buf), "%.6g", (float) n ); break; 95 case SbxDOUBLE: snprintf( buf, sizeof(buf), "%.16g", n ); break; 96 default: break; 97 } 98 return Add( String::CreateFromAscii( buf ) ); 99 } 100 101 /*************************************************************************** 102 |* 103 |* SbiSymPool 104 |* 105 ***************************************************************************/ 106 107 SbiSymPool::SbiSymPool( SbiStringPool& r, SbiSymScope s ) : rStrings( r ) 108 { 109 pParser = r.GetParser(); 110 eScope = s; 111 pParent = NULL; 112 nCur = 113 nProcId = 0; 114 } 115 116 SbiSymPool::~SbiSymPool() 117 {} 118 119 // Inhalt loeschen 120 121 void SbiSymPool::Clear() 122 { 123 aData.DeleteAndDestroy( 0, aData.Count() ); 124 } 125 126 SbiSymDef* SbiSymPool::First() 127 { 128 nCur = (sal_uInt16) -1; 129 return Next(); 130 } 131 132 SbiSymDef* SbiSymPool::Next() 133 { 134 if( ++nCur >= aData.Count() ) 135 return NULL; 136 else 137 return aData.GetObject( nCur ); 138 } 139 140 // Hinzufuegen eines Symbols 141 142 SbiSymDef* SbiSymPool::AddSym( const String& rName ) 143 { 144 SbiSymDef* p = new SbiSymDef( rName ); 145 p->nPos = aData.Count(); 146 p->nId = rStrings.Add( rName ); 147 p->nProcId = nProcId; 148 p->pIn = this; 149 const SbiSymDef* q = p; 150 aData.Insert( q, q->nPos ); 151 return p; 152 } 153 154 SbiProcDef* SbiSymPool::AddProc( const String& rName ) 155 { 156 SbiProcDef* p = new SbiProcDef( pParser, rName ); 157 p->nPos = aData.Count(); 158 p->nId = rStrings.Add( rName ); 159 // Procs sind immer global 160 p->nProcId = 0; 161 p->pIn = this; 162 const SbiSymDef* q = p; 163 aData.Insert( q, q->nPos ); 164 return p; 165 } 166 167 // Hinzufuegen einer extern aufgebauten Symboldefinition 168 169 void SbiSymPool::Add( SbiSymDef* pDef ) 170 { 171 if( pDef && pDef->pIn != this ) 172 { 173 if( pDef->pIn ) 174 { 175 #ifdef DBG_UTIL 176 // schon in einem anderen Pool drin! 177 pParser->Error( SbERR_INTERNAL_ERROR, "Dbl Pool" ); 178 #endif 179 return; 180 } 181 182 pDef->nPos = aData.Count(); 183 if( !pDef->nId ) 184 { 185 // Bei statischen Variablen muss ein eindeutiger Name 186 // im Stringpool erzeugt werden (Form ProcName:VarName) 187 String aName( pDef->aName ); 188 if( pDef->IsStatic() ) 189 { 190 aName = pParser->aGblStrings.Find( nProcId ); 191 aName += ':'; 192 aName += pDef->aName; 193 } 194 pDef->nId = rStrings.Add( aName ); 195 } 196 // Procs sind immer global 197 if( !pDef->GetProcDef() ) 198 pDef->nProcId = nProcId; 199 pDef->pIn = this; 200 const SbiSymDef* q = pDef; 201 aData.Insert( q, q->nPos ); 202 } 203 } 204 205 // Suchen eines Eintrags ueber den Namen. Es wird auch im Parent gesucht. 206 207 SbiSymDef* SbiSymPool::Find( const String& rName ) const 208 { 209 sal_uInt16 nCount = aData.Count(); 210 for( sal_uInt16 i = 0; i < nCount; i++ ) 211 { 212 SbiSymDef* p = aData.GetObject( nCount - i - 1 ); 213 if( ( !p->nProcId || ( p->nProcId == nProcId ) ) 214 && ( p->aName.EqualsIgnoreCaseAscii( rName ) ) ) 215 return p; 216 } 217 if( pParent ) 218 return pParent->Find( rName ); 219 else 220 return NULL; 221 } 222 223 // Suchen ueber ID-Nummer 224 225 SbiSymDef* SbiSymPool::FindId( sal_uInt16 n ) const 226 { 227 for( sal_uInt16 i = 0; i < aData.Count(); i++ ) 228 { 229 SbiSymDef* p = aData.GetObject( i ); 230 if( p->nId == n && ( !p->nProcId || ( p->nProcId == nProcId ) ) ) 231 return p; 232 } 233 if( pParent ) 234 return pParent->FindId( n ); 235 else 236 return NULL; 237 } 238 239 // Suchen ueber Position (ab 0) 240 241 SbiSymDef* SbiSymPool::Get( sal_uInt16 n ) const 242 { 243 if( n >= aData.Count() ) 244 return NULL; 245 else 246 return aData.GetObject( n ); 247 } 248 249 sal_uInt32 SbiSymPool::Define( const String& rName ) 250 { 251 SbiSymDef* p = Find( rName ); 252 if( p ) 253 { if( p->IsDefined() ) 254 pParser->Error( SbERR_LABEL_DEFINED, rName ); 255 } 256 else 257 p = AddSym( rName ); 258 return p->Define(); 259 } 260 261 sal_uInt32 SbiSymPool::Reference( const String& rName ) 262 { 263 SbiSymDef* p = Find( rName ); 264 if( !p ) 265 p = AddSym( rName ); 266 //Sicherheitshalber 267 pParser->aGen.GenStmnt(); 268 return p->Reference(); 269 } 270 271 // Alle offenen Referenzen anmaulen 272 273 void SbiSymPool::CheckRefs() 274 { 275 for( sal_uInt16 i = 0; i < aData.Count(); i++ ) 276 { 277 SbiSymDef* p = aData.GetObject( i ); 278 if( !p->IsDefined() ) 279 pParser->Error( SbERR_UNDEF_LABEL, p->GetName() ); 280 } 281 } 282 283 /*************************************************************************** 284 |* 285 |* Symbol-Definitionen 286 |* 287 ***************************************************************************/ 288 289 SbiSymDef::SbiSymDef( const String& rName ) : aName( rName ) 290 { 291 eType = SbxEMPTY; 292 nDims = 0; 293 nTypeId = 0; 294 nProcId = 0; 295 nId = 0; 296 nPos = 0; 297 nLen = 0; 298 nChain = 0; 299 bAs = 300 bNew = 301 bStatic = 302 bOpt = 303 bParamArray = 304 bWithEvents = 305 bWithBrackets = 306 bByVal = 307 bChained = 308 bGlobal = sal_False; 309 pIn = 310 pPool = NULL; 311 nDefaultId = 0; 312 nFixedStringLength = -1; 313 } 314 315 SbiSymDef::~SbiSymDef() 316 { 317 delete pPool; 318 } 319 320 SbiProcDef* SbiSymDef::GetProcDef() 321 { 322 return NULL; 323 } 324 325 SbiConstDef* SbiSymDef::GetConstDef() 326 { 327 return NULL; 328 } 329 330 // Wenn der Name benoetigt wird, den aktuellen Namen 331 // aus dem Stringpool nehmen 332 333 const String& SbiSymDef::GetName() 334 { 335 if( pIn ) 336 aName = pIn->rStrings.Find( nId ); 337 return aName; 338 } 339 340 // Eintragen eines Datentyps 341 342 void SbiSymDef::SetType( SbxDataType t ) 343 { 344 if( t == SbxVARIANT && pIn ) 345 { 346 sal_Unicode cu = aName.GetBuffer()[0]; 347 if( cu < 256 ) 348 { 349 char ch = (char)aName.GetBuffer()[0]; 350 if( ch == '_' ) ch = 'Z'; 351 int ch2 = toupper( ch ); 352 unsigned char c = (unsigned char)ch2; 353 if( c > 0 && c < 128 ) 354 t = pIn->pParser->eDefTypes[ ch2 - 'A' ]; 355 } 356 } 357 eType = t; 358 } 359 360 // Aufbau einer Backchain, falls noch nicht definiert 361 // Es wird der Wert zurueckgeliefert, der als Operand gespeichert 362 // werden soll. 363 364 sal_uInt32 SbiSymDef::Reference() 365 { 366 if( !bChained ) 367 { 368 sal_uInt32 n = nChain; 369 nChain = pIn->pParser->aGen.GetOffset(); 370 return n; 371 } 372 else return nChain; 373 } 374 375 // Definition eines Symbols. 376 // Hier wird der Backchain aufgeloest, falls vorhanden 377 378 sal_uInt32 SbiSymDef::Define() 379 { 380 sal_uInt32 n = pIn->pParser->aGen.GetPC(); 381 pIn->pParser->aGen.GenStmnt(); 382 if( nChain ) pIn->pParser->aGen.BackChain( nChain ); 383 nChain = n; 384 bChained = sal_True; 385 return nChain; 386 } 387 388 // Eine Symboldefinition kann einen eigenen Pool haben. Dies ist 389 // der Fall bei Objekten und Prozeduren (lokale Variable) 390 391 SbiSymPool& SbiSymDef::GetPool() 392 { 393 if( !pPool ) 394 pPool = new SbiSymPool( pIn->pParser->aGblStrings, SbLOCAL ); // wird gedumpt 395 return *pPool; 396 } 397 398 SbiSymScope SbiSymDef::GetScope() const 399 { 400 return pIn ? pIn->GetScope() : SbLOCAL; 401 } 402 403 //////////////////////////////////////////////////////////////////////////// 404 405 // Die Prozedur-Definition hat drei Pools: 406 // 1) aParams: wird durch die Definition gefuellt. Enthaelt die Namen 407 // der Parameter, wie sie innerhalb des Rumpfes verwendet werden. 408 // Das erste Element ist der Returnwert. 409 // 2) pPool: saemtliche lokale Variable 410 // 3) aLabels: Labels 411 412 SbiProcDef::SbiProcDef( SbiParser* pParser, const String& rName, 413 sal_Bool bProcDecl ) 414 : SbiSymDef( rName ) 415 , aParams( pParser->aGblStrings, SbPARAM ) // wird gedumpt 416 , aLabels( pParser->aLclStrings, SbLOCAL ) // wird nicht gedumpt 417 , mbProcDecl( bProcDecl ) 418 { 419 aParams.SetParent( &pParser->aPublics ); 420 pPool = new SbiSymPool( pParser->aGblStrings, SbLOCAL ); // Locals 421 pPool->SetParent( &aParams ); 422 nLine1 = 423 nLine2 = 0; 424 mePropMode = PROPERTY_MODE_NONE; 425 bPublic = sal_True; 426 bCdecl = sal_False; 427 bStatic = sal_False; 428 // Fuer Returnwerte ist das erste Element der Parameterliste 429 // immer mit dem Namen und dem Typ der Proc definiert 430 aParams.AddSym( aName ); 431 } 432 433 SbiProcDef::~SbiProcDef() 434 {} 435 436 SbiProcDef* SbiProcDef::GetProcDef() 437 { 438 return this; 439 } 440 441 void SbiProcDef::SetType( SbxDataType t ) 442 { 443 SbiSymDef::SetType( t ); 444 aParams.Get( 0 )->SetType( eType ); 445 } 446 447 // Match mit einer Forward-Deklaration 448 // Falls der Match OK ist, wird pOld durch this im Pool ersetzt 449 // pOld wird immer geloescht! 450 451 void SbiProcDef::Match( SbiProcDef* pOld ) 452 { 453 SbiSymDef* po, *pn=NULL; 454 // Parameter 0 ist der Funktionsname 455 sal_uInt16 i; 456 for( i = 1; i < aParams.GetSize(); i++ ) 457 { 458 po = pOld->aParams.Get( i ); 459 pn = aParams.Get( i ); 460 // Kein Typabgleich; das wird beim Laufen erledigt 461 // aber ist sie evtl. mit zu wenigen Parametern aufgerufen 462 // worden? 463 if( !po && !pn->IsOptional() && !pn->IsParamArray() ) 464 break; 465 po = pOld->aParams.Next(); 466 } 467 // Wurden zu viele Parameter angegeben? 468 if( pn && i < aParams.GetSize() && pOld->pIn ) 469 { 470 // Die ganze Zeile markieren 471 pOld->pIn->GetParser()->SetCol1( 0 ); 472 pOld->pIn->GetParser()->Error( SbERR_BAD_DECLARATION, aName ); 473 } 474 if( !pIn && pOld->pIn ) 475 { 476 // Alten Eintrag durch neuen ersetzen 477 SbiSymDef** pData = (SbiSymDef**) pOld->pIn->aData.GetData(); 478 pData[ pOld->nPos ] = this; 479 nPos = pOld->nPos; 480 nId = pOld->nId; 481 pIn = pOld->pIn; 482 } 483 delete pOld; 484 } 485 486 void SbiProcDef::setPropertyMode( PropertyMode ePropMode ) 487 { 488 mePropMode = ePropMode; 489 if( mePropMode != PROPERTY_MODE_NONE ) 490 { 491 // Prop name = original scanned procedure name 492 maPropName = aName; 493 494 // CompleteProcName includes "Property xxx " 495 // to avoid conflicts with other symbols 496 String aCompleteProcName; 497 aCompleteProcName.AppendAscii( "Property " ); 498 switch( mePropMode ) 499 { 500 case PROPERTY_MODE_GET: aCompleteProcName.AppendAscii( "Get " ); break; 501 case PROPERTY_MODE_LET: aCompleteProcName.AppendAscii( "Let " ); break; 502 case PROPERTY_MODE_SET: aCompleteProcName.AppendAscii( "Set " ); break; 503 case PROPERTY_MODE_NONE: 504 DBG_ERROR( "Illegal PropertyMode PROPERTY_MODE_NONE" ); 505 break; 506 } 507 aCompleteProcName += aName; 508 aName = aCompleteProcName; 509 } 510 } 511 512 513 ////////////////////////////////////////////////////////////////////////// 514 515 SbiConstDef::SbiConstDef( const String& rName ) 516 : SbiSymDef( rName ) 517 { 518 nVal = 0; eType = SbxINTEGER; 519 } 520 521 void SbiConstDef::Set( double n, SbxDataType t ) 522 { 523 aVal.Erase(); nVal = n; eType = t; 524 } 525 526 void SbiConstDef::Set( const String& n ) 527 { 528 aVal = n; nVal = 0; eType = SbxSTRING; 529 } 530 531 SbiConstDef::~SbiConstDef() 532 {} 533 534 SbiConstDef* SbiConstDef::GetConstDef() 535 { 536 return this; 537 } 538 539