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 #include <basic/sberrors.hxx> 21 #include <basic/sbstar.hxx> 22 #include <basic/sbx.hxx> 23 #include <sbunoobj.hxx> 24 #include <parser.hxx> 25 #include <sb.hxx> 26 #include <osl/diagnose.h> 27 #include <com/sun/star/reflection/theCoreReflection.hpp> 28 #include <comphelper/processfactory.hxx> 29 #include <com/sun/star/uno/Exception.hpp> 30 #include <basic/codecompletecache.hxx> 31 #include <memory> 32 33 using namespace ::com::sun::star; 34 using namespace ::com::sun::star::uno; 35 36 // Declaration of a variable 37 // If there are errors it will be parsed up to the comma or the newline. 38 // Return-value: a new instance, which were inserted and then deleted. 39 // Array-Index were returned as SbiExprList 40 41 SbiSymDef* SbiParser::VarDecl( SbiExprListPtr* ppDim, bool bStatic, bool bConst ) 42 { 43 bool bWithEvents = false; 44 if( Peek() == WITHEVENTS ) 45 { 46 Next(); 47 bWithEvents = true; 48 } 49 if( !TestSymbol() ) return nullptr; 50 SbxDataType t = eScanType; 51 SbiSymDef* pDef = bConst ? new SbiConstDef( aSym ) : new SbiSymDef( aSym ); 52 SbiExprListPtr pDim; 53 // Brackets? 54 if( Peek() == LPAREN ) 55 { 56 pDim = SbiExprList::ParseDimList( this ); 57 if( !pDim->GetDims() ) 58 pDef->SetWithBrackets(); 59 } 60 pDef->SetType( t ); 61 if( bStatic ) 62 pDef->SetStatic(); 63 if( bWithEvents ) 64 pDef->SetWithEvents(); 65 TypeDecl( *pDef ); 66 if( !ppDim && pDim ) 67 { 68 if(pDim->GetDims() ) 69 Error( ERRCODE_BASIC_EXPECTED, "()" ); 70 } 71 else if( ppDim ) 72 *ppDim = std::move(pDim); 73 return pDef; 74 } 75 76 // Resolving of an AS-Type-Declaration 77 // The data type were inserted into the handed over variable 78 79 void SbiParser::TypeDecl( SbiSymDef& rDef, bool bAsNewAlreadyParsed ) 80 { 81 SbxDataType eType = rDef.GetType(); 82 if( !(bAsNewAlreadyParsed || Peek() == AS) ) 83 return; 84 85 short nSize = 0; 86 if( !bAsNewAlreadyParsed ) 87 Next(); 88 rDef.SetDefinedAs(); 89 SbiToken eTok = Next(); 90 if( !bAsNewAlreadyParsed && eTok == NEW ) 91 { 92 rDef.SetNew(); 93 eTok = Next(); 94 } 95 switch( eTok ) 96 { 97 case ANY: 98 if( rDef.IsNew() ) 99 Error( ERRCODE_BASIC_SYNTAX ); 100 eType = SbxVARIANT; break; 101 case TINTEGER: 102 case TLONG: 103 case TSINGLE: 104 case TDOUBLE: 105 case TCURRENCY: 106 case TDATE: 107 case TSTRING: 108 case TOBJECT: 109 case ERROR_: 110 case TBOOLEAN: 111 case TVARIANT: 112 case TBYTE: 113 if( rDef.IsNew() ) 114 Error( ERRCODE_BASIC_SYNTAX ); 115 eType = (eTok==TBYTE) ? SbxBYTE : SbxDataType( eTok - TINTEGER + SbxINTEGER ); 116 if( eType == SbxSTRING ) 117 { 118 // STRING*n ? 119 if( Peek() == MUL ) 120 { // fixed size! 121 Next(); 122 SbiConstExpression aSize( this ); 123 nSize = aSize.GetShortValue(); 124 if( nSize < 0 || (bVBASupportOn && nSize <= 0) ) 125 Error( ERRCODE_BASIC_OUT_OF_RANGE ); 126 else 127 rDef.SetFixedStringLength( nSize ); 128 } 129 } 130 break; 131 case SYMBOL: // can only be a TYPE or an object class! 132 if( eScanType != SbxVARIANT ) 133 Error( ERRCODE_BASIC_SYNTAX ); 134 else 135 { 136 OUString aCompleteName = aSym; 137 138 // #52709 DIM AS NEW for Uno with full-qualified name 139 if( Peek() == DOT ) 140 { 141 OUString aDotStr( '.' ); 142 while( Peek() == DOT ) 143 { 144 aCompleteName += aDotStr; 145 Next(); 146 SbiToken ePeekTok = Peek(); 147 if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) ) 148 { 149 Next(); 150 aCompleteName += aSym; 151 } 152 else 153 { 154 Next(); 155 Error( ERRCODE_BASIC_UNEXPECTED, SYMBOL ); 156 break; 157 } 158 } 159 } 160 else if( rEnumArray->Find( aCompleteName, SbxClassType::Object ) || ( IsVBASupportOn() && VBAConstantHelper::instance().isVBAConstantType( aCompleteName ) ) ) 161 { 162 eType = SbxLONG; 163 break; 164 } 165 166 // Take over in the string pool 167 rDef.SetTypeId( aGblStrings.Add( aCompleteName ) ); 168 169 if( rDef.IsNew() && pProc == nullptr ) 170 aRequiredTypes.push_back( aCompleteName ); 171 } 172 eType = SbxOBJECT; 173 break; 174 case FIXSTRING: // new syntax for complex UNO types 175 rDef.SetTypeId( aGblStrings.Add( aSym ) ); 176 eType = SbxOBJECT; 177 break; 178 default: 179 Error( ERRCODE_BASIC_UNEXPECTED, eTok ); 180 Next(); 181 } 182 // The variable could have been declared with a suffix 183 if( rDef.GetType() != SbxVARIANT ) 184 { 185 if( rDef.GetType() != eType ) 186 Error( ERRCODE_BASIC_VAR_DEFINED, rDef.GetName() ); 187 else if( eType == SbxSTRING && rDef.GetLen() != nSize ) 188 Error( ERRCODE_BASIC_VAR_DEFINED, rDef.GetName() ); 189 } 190 rDef.SetType( eType ); 191 rDef.SetLen( nSize ); 192 } 193 194 // Here variables, arrays and structures were defined. 195 // DIM/PRIVATE/PUBLIC/GLOBAL 196 197 void SbiParser::Dim() 198 { 199 DefVar( SbiOpcode::DIM_, pProc && bVBASupportOn && pProc->IsStatic() ); 200 } 201 202 void SbiParser::DefVar( SbiOpcode eOp, bool bStatic ) 203 { 204 SbiSymPool* pOldPool = pPool; 205 bool bSwitchPool = false; 206 bool bPersistentGlobal = false; 207 SbiToken eFirstTok = eCurTok; 208 209 if( pProc && ( eCurTok == GLOBAL || eCurTok == PUBLIC || eCurTok == PRIVATE ) ) 210 Error( ERRCODE_BASIC_NOT_IN_SUBR, eCurTok ); 211 if( eCurTok == PUBLIC || eCurTok == GLOBAL ) 212 { 213 bSwitchPool = true; // at the right moment switch to the global pool 214 if( eCurTok == GLOBAL ) 215 bPersistentGlobal = true; 216 } 217 // behavior in VBA is that a module scope variable's lifetime is 218 // tied to the document. e.g. a module scope variable is global 219 if( GetBasic()->IsDocBasic() && bVBASupportOn && !pProc ) 220 bPersistentGlobal = true; 221 // PRIVATE is a synonymous for DIM 222 // _CONST_? 223 bool bConst = false; 224 if( eCurTok == CONST_ ) 225 bConst = true; 226 else if( Peek() == CONST_ ) 227 { 228 Next(); 229 bConst = true; 230 } 231 232 // #110004 It can also be a sub/function 233 if( !bConst && (eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY || 234 eCurTok == STATIC || eCurTok == ENUM || eCurTok == DECLARE || eCurTok == TYPE) ) 235 { 236 // Next token is read here, because !bConst 237 bool bPrivate = ( eFirstTok == PRIVATE ); 238 239 if( eCurTok == STATIC ) 240 { 241 Next(); 242 DefStatic( bPrivate ); 243 } 244 else if( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) 245 { 246 // End global chain if necessary (not done in 247 // SbiParser::Parse() under these conditions 248 if( bNewGblDefs && nGblChain == 0 ) 249 { 250 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); 251 bNewGblDefs = false; 252 } 253 Next(); 254 DefProc( false, bPrivate ); 255 return; 256 } 257 else if( eCurTok == ENUM ) 258 { 259 Next(); 260 DefEnum( bPrivate ); 261 return; 262 } 263 else if( eCurTok == DECLARE ) 264 { 265 Next(); 266 DefDeclare( bPrivate ); 267 return; 268 } 269 // #i109049 270 else if( eCurTok == TYPE ) 271 { 272 Next(); 273 DefType(); // TODO: Use bPrivate in DefType() 274 return; 275 } 276 } 277 278 // SHARED were ignored 279 if( Peek() == SHARED ) Next(); 280 281 // PRESERVE only at REDIM 282 if( Peek() == PRESERVE ) 283 { 284 Next(); 285 if( eOp == SbiOpcode::REDIM_ ) 286 eOp = SbiOpcode::REDIMP_; 287 else 288 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok ); 289 } 290 SbiSymDef* pDef; 291 SbiExprListPtr pDim; 292 293 // #40689, Statics -> Module-Initialising, skip in Sub 294 sal_uInt32 nEndOfStaticLbl = 0; 295 if( !bVBASupportOn && bStatic ) 296 { 297 nEndOfStaticLbl = aGen.Gen( SbiOpcode::JUMP_, 0 ); 298 aGen.Statement(); // catch up on static here 299 } 300 301 bool bDefined = false; 302 while( ( pDef = VarDecl( &pDim, bStatic, bConst ) ) != nullptr ) 303 { 304 /*fprintf(stderr, "Actual sub: \n"); 305 fprintf(stderr, "Symbol name: %s\n",OUStringToOString(pDef->GetName(),RTL_TEXTENCODING_UTF8).getStr());*/ 306 EnableErrors(); 307 // search variable: 308 if( bSwitchPool ) 309 pPool = &aGlobals; 310 SbiSymDef* pOld = pPool->Find( pDef->GetName() ); 311 // search also in the Runtime-Library 312 bool bRtlSym = false; 313 if( !pOld ) 314 { 315 pOld = CheckRTLForSym( pDef->GetName(), SbxVARIANT ); 316 if( pOld ) 317 bRtlSym = true; 318 } 319 if( pOld && eOp != SbiOpcode::REDIM_ && eOp != SbiOpcode::REDIMP_ ) 320 { 321 if( pDef->GetScope() == SbLOCAL ) 322 if (auto eOldScope = pOld->GetScope(); eOldScope != SbLOCAL && eOldScope != SbPARAM) 323 pOld = nullptr; 324 } 325 if( pOld ) 326 { 327 bDefined = true; 328 // always an error at a RTL-S 329 if( !bRtlSym && (eOp == SbiOpcode::REDIM_ || eOp == SbiOpcode::REDIMP_) ) 330 { 331 // compare the attributes at a REDIM 332 SbxDataType eDefType; 333 bool bError_ = false; 334 if( pOld->IsStatic() ) 335 { 336 bError_ = true; 337 } 338 else if( pOld->GetType() != ( eDefType = pDef->GetType() ) ) 339 { 340 if( eDefType != SbxVARIANT || pDef->IsDefinedAs() ) 341 bError_ = true; 342 } 343 if( bError_ ) 344 Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() ); 345 } 346 else 347 Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() ); 348 delete pDef; pDef = pOld; 349 } 350 else 351 pPool->Add( pDef ); 352 353 // #36374: Create the variable in front of the distinction IsNew() 354 // Otherwise error at Dim Identifier As New Type and option explicit 355 if( !bDefined && eOp != SbiOpcode::REDIM_ && eOp != SbiOpcode::REDIMP_ 356 && ( !bConst || pDef->GetScope() == SbGLOBAL ) ) 357 { 358 // Declare variable or global constant 359 SbiOpcode eOp2; 360 switch ( pDef->GetScope() ) 361 { 362 case SbGLOBAL: eOp2 = bPersistentGlobal ? SbiOpcode::GLOBAL_P_ : SbiOpcode::GLOBAL_; 363 goto global; 364 case SbPUBLIC: eOp2 = bPersistentGlobal ? SbiOpcode::PUBLIC_P_ : SbiOpcode::PUBLIC_; 365 // #40689, no own Opcode anymore 366 if( bVBASupportOn && bStatic ) 367 { 368 eOp2 = SbiOpcode::STATIC_; 369 break; 370 } 371 global: aGen.BackChain( nGblChain ); 372 nGblChain = 0; 373 bGblDefs = bNewGblDefs = true; 374 break; 375 default: eOp2 = SbiOpcode::LOCAL_; 376 } 377 sal_uInt32 nOpnd2 = sal::static_int_cast< sal_uInt16 >( pDef->GetType() ); 378 if( pDef->IsWithEvents() ) 379 nOpnd2 |= SBX_TYPE_WITH_EVENTS_FLAG; 380 381 if( bCompatible && pDef->IsNew() ) 382 nOpnd2 |= SBX_TYPE_DIM_AS_NEW_FLAG; 383 384 short nFixedStringLength = pDef->GetFixedStringLength(); 385 if( nFixedStringLength >= 0 ) 386 nOpnd2 |= (SBX_FIXED_LEN_STRING_FLAG + (sal_uInt32(nFixedStringLength) << 17)); // len = all bits above 0x10000 387 388 if( pDim != nullptr && pDim->GetDims() > 0 ) 389 nOpnd2 |= SBX_TYPE_VAR_TO_DIM_FLAG; 390 391 aGen.Gen( eOp2, pDef->GetId(), nOpnd2 ); 392 } 393 394 // Initialising for self-defined data types 395 // and per NEW created variable 396 if( pDef->GetType() == SbxOBJECT 397 && pDef->GetTypeId() ) 398 { 399 if( !bCompatible && !pDef->IsNew() ) 400 { 401 OUString aTypeName( aGblStrings.Find( pDef->GetTypeId() ) ); 402 if( rTypeArray->Find( aTypeName, SbxClassType::Object ) == nullptr ) 403 { 404 if( CodeCompleteOptions::IsExtendedTypeDeclaration() ) 405 { 406 if(!IsUnoInterface(aTypeName)) 407 Error( ERRCODE_BASIC_UNDEF_TYPE, aTypeName ); 408 } 409 else 410 Error( ERRCODE_BASIC_UNDEF_TYPE, aTypeName ); 411 } 412 } 413 414 if( bConst ) 415 { 416 Error( ERRCODE_BASIC_SYNTAX ); 417 } 418 419 if( pDim ) 420 { 421 if( eOp == SbiOpcode::REDIMP_ ) 422 { 423 SbiExpression aExpr( this, *pDef, nullptr ); 424 aExpr.Gen(); 425 aGen.Gen( SbiOpcode::REDIMP_ERASE_ ); 426 427 pDef->SetDims( pDim->GetDims() ); 428 SbiExpression aExpr2( this, *pDef, std::move(pDim) ); 429 aExpr2.Gen(); 430 aGen.Gen( SbiOpcode::DCREATE_REDIMP_, pDef->GetId(), pDef->GetTypeId() ); 431 } 432 else 433 { 434 // tdf#136755 - delete the variable beforehand REDIM 435 SbiExpression aExpr(this, *pDef, nullptr); 436 aExpr.Gen(); 437 aGen.Gen(bVBASupportOn ? SbiOpcode::ERASE_CLEAR_ : SbiOpcode::ERASE_); 438 439 pDef->SetDims( pDim->GetDims() ); 440 SbiExpression aExpr2( this, *pDef, std::move(pDim) ); 441 aExpr2.Gen(); 442 aGen.Gen( SbiOpcode::DCREATE_, pDef->GetId(), pDef->GetTypeId() ); 443 } 444 } 445 else 446 { 447 SbiExpression aExpr( this, *pDef ); 448 aExpr.Gen(); 449 450 /* tdf#88442 451 * Don't initialize a 452 * Global X as New SomeObjectType 453 * if it has already been initialized. 454 * This approach relies on JUMPT evaluating Object->NULL as being 'false' 455 * But the effect of this code is similar to inserting 456 * If IsNull(YourGlobal) 457 * Set YourGlobal = ' new obj 458 * End If ' If IsNull(YourGlobal) 459 * Only for globals. For locals that check is skipped as it's unnecessary 460 */ 461 sal_uInt32 come_from = 0; 462 if ( pDef->GetScope() == SbGLOBAL ) 463 { 464 come_from = aGen.Gen( SbiOpcode::JUMPT_, 0 ); 465 aGen.Gen( SbiOpcode::FIND_, pDef->GetId(), pDef->GetTypeId() ); 466 } 467 468 SbiOpcode eOp_ = pDef->IsNew() ? SbiOpcode::CREATE_ : SbiOpcode::TCREATE_; 469 aGen.Gen( eOp_, pDef->GetId(), pDef->GetTypeId() ); 470 if ( bVBASupportOn ) 471 aGen.Gen( SbiOpcode::VBASET_ ); 472 else 473 aGen.Gen( SbiOpcode::SET_ ); 474 475 if ( come_from ) 476 { 477 // See other tdf#88442 comment above where come_from is 478 // initialized. This is effectively 'inserting' the 479 // End If ' If IsNull(YourGlobal) 480 aGen.BackChain( come_from ); 481 } 482 } 483 } 484 else 485 { 486 if( bConst ) 487 { 488 // Definition of the constants 489 if( pDim ) 490 { 491 Error( ERRCODE_BASIC_SYNTAX ); 492 } 493 SbiExpression aVar( this, *pDef ); 494 if( !TestToken( EQ ) ) 495 goto MyBreak; // (see below) 496 SbiConstExpression aExpr( this ); 497 if( !bDefined && aExpr.IsValid() ) 498 { 499 if( pDef->GetScope() == SbGLOBAL ) 500 { 501 // Create code only for the global constant! 502 aVar.Gen(); 503 aExpr.Gen(); 504 aGen.Gen( SbiOpcode::PUTC_ ); 505 } 506 SbiConstDef* pConst = pDef->GetConstDef(); 507 if( aExpr.GetType() == SbxSTRING ) 508 pConst->Set( aExpr.GetString() ); 509 else 510 pConst->Set( aExpr.GetValue(), aExpr.GetType() ); 511 } 512 } 513 else if( pDim ) 514 { 515 // Dimension the variable 516 // Delete the var at REDIM beforehand 517 if( eOp == SbiOpcode::REDIM_ ) 518 { 519 SbiExpression aExpr( this, *pDef, nullptr ); 520 aExpr.Gen(); 521 if ( bVBASupportOn ) 522 // delete the array but 523 // clear the variable ( this 524 // allows the processing of 525 // the param to happen as normal without errors ( ordinary ERASE just clears the array ) 526 aGen.Gen( SbiOpcode::ERASE_CLEAR_ ); 527 else 528 aGen.Gen( SbiOpcode::ERASE_ ); 529 } 530 else if( eOp == SbiOpcode::REDIMP_ ) 531 { 532 SbiExpression aExpr( this, *pDef, nullptr ); 533 aExpr.Gen(); 534 aGen.Gen( SbiOpcode::REDIMP_ERASE_ ); 535 } 536 pDef->SetDims( pDim->GetDims() ); 537 if( bPersistentGlobal ) 538 pDef->SetGlobal( true ); 539 SbiExpression aExpr( this, *pDef, std::move(pDim) ); 540 aExpr.Gen(); 541 pDef->SetGlobal( false ); 542 aGen.Gen( (eOp == SbiOpcode::STATIC_) ? SbiOpcode::DIM_ : eOp ); 543 } 544 } 545 if( !TestComma() ) 546 goto MyBreak; 547 548 // Implementation of bSwitchPool (see above): pPool must not be set to &aGlobals 549 // at the VarDecl-Call. 550 // Apart from that the behavior should be absolutely identical, 551 // i.e., pPool had to be reset always at the end of the loop. 552 // also at a break 553 pPool = pOldPool; 554 continue; // Skip MyBreak 555 MyBreak: 556 pPool = pOldPool; 557 break; 558 } 559 560 // #40689, finalize the jump over statics declarations 561 if( !bVBASupportOn && bStatic ) 562 { 563 // maintain the global chain 564 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); 565 bGblDefs = bNewGblDefs = true; 566 567 // Register for Sub a jump to the end of statics 568 aGen.BackChain( nEndOfStaticLbl ); 569 } 570 571 } 572 573 // Here were Arrays redimensioned. 574 575 void SbiParser::ReDim() 576 { 577 DefVar( SbiOpcode::REDIM_, pProc && bVBASupportOn && pProc->IsStatic() ); 578 } 579 580 // ERASE array, ... 581 582 void SbiParser::Erase() 583 { 584 while( !bAbort ) 585 { 586 SbiExpression aExpr( this, SbLVALUE ); 587 aExpr.Gen(); 588 aGen.Gen( SbiOpcode::ERASE_ ); 589 if( !TestComma() ) break; 590 } 591 } 592 593 // Declaration of a data type 594 595 void SbiParser::Type() 596 { 597 DefType(); 598 } 599 600 void SbiParser::DefType() 601 { 602 // Read the new Token lesen. It had to be a symbol 603 if (!TestSymbol()) 604 return; 605 606 if (rTypeArray->Find(aSym,SbxClassType::Object)) 607 { 608 Error( ERRCODE_BASIC_VAR_DEFINED, aSym ); 609 return; 610 } 611 612 SbxObject *pType = new SbxObject(aSym); 613 614 bool bDone = false; 615 616 while( !bDone && !IsEof() ) 617 { 618 std::unique_ptr<SbiSymDef> pElem; 619 SbiExprListPtr pDim; 620 switch( Peek() ) 621 { 622 case ENDTYPE : 623 bDone = true; 624 Next(); 625 break; 626 627 case EOLN : 628 case REM : 629 Next(); 630 break; 631 632 default: 633 pElem.reset(VarDecl(&pDim, false, false)); 634 if( !pElem ) 635 bDone = true; // Error occurred 636 } 637 if( pElem ) 638 { 639 SbxArray *pTypeMembers = pType->GetProperties(); 640 OUString aElemName = pElem->GetName(); 641 if( pTypeMembers->Find( aElemName, SbxClassType::DontCare) ) 642 { 643 Error (ERRCODE_BASIC_VAR_DEFINED); 644 } 645 else 646 { 647 SbxDataType eElemType = pElem->GetType(); 648 SbxProperty *pTypeElem = new SbxProperty( aElemName, eElemType ); 649 if( pDim ) 650 { 651 SbxDimArray* pArray = new SbxDimArray( pElem->GetType() ); 652 if ( pDim->GetSize() ) 653 { 654 // Dimension the target array 655 656 for ( short i=0; i<pDim->GetSize();++i ) 657 { 658 sal_Int32 lb = nBase; 659 SbiExprNode* pNode = pDim->Get(i)->GetExprNode(); 660 sal_Int32 ub = pNode->GetNumber(); 661 if ( !pDim->Get( i )->IsBased() ) // each dim is low/up 662 { 663 if ( ++i >= pDim->GetSize() ) // trouble 664 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 665 pNode = pDim->Get(i)->GetExprNode(); 666 lb = ub; 667 ub = pNode->GetNumber(); 668 } 669 else if ( !bCompatible ) 670 ub += nBase; 671 pArray->AddDim(lb, ub); 672 } 673 pArray->setHasFixedSize( true ); 674 } 675 else 676 pArray->unoAddDim(0, -1); // variant array 677 SbxFlagBits nSavFlags = pTypeElem->GetFlags(); 678 // need to reset the FIXED flag 679 // when calling PutObject ( because the type will not match Object ) 680 pTypeElem->ResetFlag( SbxFlagBits::Fixed ); 681 pTypeElem->PutObject( pArray ); 682 pTypeElem->SetFlags( nSavFlags ); 683 } 684 // Nested user type? 685 if( eElemType == SbxOBJECT ) 686 { 687 sal_uInt16 nElemTypeId = pElem->GetTypeId(); 688 if( nElemTypeId != 0 ) 689 { 690 OUString aTypeName( aGblStrings.Find( nElemTypeId ) ); 691 SbxObject* pTypeObj = static_cast< SbxObject* >( rTypeArray->Find( aTypeName, SbxClassType::Object ) ); 692 if( pTypeObj != nullptr ) 693 { 694 SbxObject* pCloneObj = cloneTypeObjectImpl( *pTypeObj ); 695 pTypeElem->PutObject( pCloneObj ); 696 } 697 } 698 } 699 pTypeMembers->Insert(pTypeElem, pTypeMembers->Count()); 700 } 701 } 702 } 703 704 pType->Remove( "Name", SbxClassType::DontCare ); 705 pType->Remove( "Parent", SbxClassType::DontCare ); 706 707 rTypeArray->Insert(pType, rTypeArray->Count()); 708 } 709 710 711 // Declaration of Enum type 712 713 void SbiParser::Enum() 714 { 715 DefEnum( false ); 716 } 717 718 void SbiParser::DefEnum( bool bPrivate ) 719 { 720 // Read the new Token. It had to be a symbol 721 if (!TestSymbol()) 722 return; 723 724 OUString aEnumName = aSym; 725 if( rEnumArray->Find(aEnumName,SbxClassType::Object) ) 726 { 727 Error( ERRCODE_BASIC_VAR_DEFINED, aSym ); 728 return; 729 } 730 731 SbxObject *pEnum = new SbxObject( aEnumName ); 732 if( bPrivate ) 733 { 734 pEnum->SetFlag( SbxFlagBits::Private ); 735 } 736 SbiSymDef* pElem; 737 bool bDone = false; 738 739 // Starting with -1 to make first default value 0 after ++ 740 sal_Int32 nCurrentEnumValue = -1; 741 while( !bDone && !IsEof() ) 742 { 743 switch( Peek() ) 744 { 745 case ENDENUM : 746 pElem = nullptr; 747 bDone = true; 748 Next(); 749 break; 750 751 case EOLN : 752 case REM : 753 pElem = nullptr; 754 Next(); 755 break; 756 757 default: 758 { 759 SbiExprListPtr pDim; 760 pElem = VarDecl( &pDim, false, true ); 761 if( !pElem ) 762 { 763 bDone = true; // Error occurred 764 break; 765 } 766 else if( pDim ) 767 { 768 Error( ERRCODE_BASIC_SYNTAX ); 769 bDone = true; // Error occurred 770 break; 771 } 772 773 SbiExpression aVar( this, *pElem ); 774 if( Peek() == EQ ) 775 { 776 Next(); 777 778 SbiConstExpression aExpr( this ); 779 if( aExpr.IsValid() ) 780 { 781 SbxVariableRef xConvertVar = new SbxVariable(); 782 if( aExpr.GetType() == SbxSTRING ) 783 xConvertVar->PutString( aExpr.GetString() ); 784 else 785 xConvertVar->PutDouble( aExpr.GetValue() ); 786 787 nCurrentEnumValue = xConvertVar->GetLong(); 788 } 789 } 790 else 791 nCurrentEnumValue++; 792 793 SbiSymPool* pPoolToUse = bPrivate ? pPool : &aGlobals; 794 795 SbiSymDef* pOld = pPoolToUse->Find( pElem->GetName() ); 796 if( pOld ) 797 { 798 Error( ERRCODE_BASIC_VAR_DEFINED, pElem->GetName() ); 799 bDone = true; // Error occurred 800 break; 801 } 802 803 pPool->Add( pElem ); 804 805 if( !bPrivate ) 806 { 807 aGen.BackChain( nGblChain ); 808 nGblChain = 0; 809 bGblDefs = bNewGblDefs = true; 810 aGen.Gen( 811 SbiOpcode::GLOBAL_, pElem->GetId(), 812 sal::static_int_cast< sal_uInt16 >( pElem->GetType() ) ); 813 814 aVar.Gen(); 815 sal_uInt16 nStringId = aGen.GetParser()->aGblStrings.Add( nCurrentEnumValue, SbxLONG ); 816 aGen.Gen( SbiOpcode::NUMBER_, nStringId ); 817 aGen.Gen( SbiOpcode::PUTC_ ); 818 } 819 820 SbiConstDef* pConst = pElem->GetConstDef(); 821 pConst->Set( nCurrentEnumValue, SbxLONG ); 822 } 823 } 824 if( pElem ) 825 { 826 SbxArray *pEnumMembers = pEnum->GetProperties(); 827 SbxProperty *pEnumElem = new SbxProperty( pElem->GetName(), SbxLONG ); 828 pEnumElem->PutLong( nCurrentEnumValue ); 829 pEnumElem->ResetFlag( SbxFlagBits::Write ); 830 pEnumElem->SetFlag( SbxFlagBits::Const ); 831 pEnumMembers->Insert(pEnumElem, pEnumMembers->Count()); 832 } 833 } 834 835 pEnum->Remove( "Name", SbxClassType::DontCare ); 836 pEnum->Remove( "Parent", SbxClassType::DontCare ); 837 838 rEnumArray->Insert(pEnum, rEnumArray->Count()); 839 } 840 841 842 // Procedure-Declaration 843 // the first Token is already read in (SUB/FUNCTION) 844 // xxx Name [LIB "name"[ALIAS "name"]][(Parameter)][AS TYPE] 845 846 SbiProcDef* SbiParser::ProcDecl( bool bDecl ) 847 { 848 bool bFunc = ( eCurTok == FUNCTION ); 849 bool bProp = ( eCurTok == GET || eCurTok == SET || eCurTok == LET ); 850 if( !TestSymbol() ) return nullptr; 851 OUString aName( aSym ); 852 SbxDataType eType = eScanType; 853 SbiProcDef* pDef = new SbiProcDef( this, aName, true ); 854 pDef->SetType( eType ); 855 if( Peek() == CDECL_ ) 856 { 857 Next(); pDef->SetCdecl(true); 858 } 859 if( Peek() == LIB ) 860 { 861 Next(); 862 if( Next() == FIXSTRING ) 863 { 864 pDef->GetLib() = aSym; 865 } 866 else 867 { 868 Error( ERRCODE_BASIC_SYNTAX ); 869 } 870 } 871 if( Peek() == ALIAS ) 872 { 873 Next(); 874 if( Next() == FIXSTRING ) 875 { 876 pDef->GetAlias() = aSym; 877 } 878 else 879 { 880 Error( ERRCODE_BASIC_SYNTAX ); 881 } 882 } 883 if( !bDecl ) 884 { 885 // CDECL, LIB and ALIAS are invalid 886 if( !pDef->GetLib().isEmpty() ) 887 { 888 Error( ERRCODE_BASIC_UNEXPECTED, LIB ); 889 } 890 if( !pDef->GetAlias().isEmpty() ) 891 { 892 Error( ERRCODE_BASIC_UNEXPECTED, ALIAS ); 893 } 894 if( pDef->IsCdecl() ) 895 { 896 Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ ); 897 } 898 pDef->SetCdecl( false ); 899 pDef->GetLib().clear(); 900 pDef->GetAlias().clear(); 901 } 902 else if( pDef->GetLib().isEmpty() ) 903 { 904 // ALIAS and CDECL only together with LIB 905 if( !pDef->GetAlias().isEmpty() ) 906 { 907 Error( ERRCODE_BASIC_UNEXPECTED, ALIAS ); 908 } 909 if( pDef->IsCdecl() ) 910 { 911 Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ ); 912 } 913 pDef->SetCdecl( false ); 914 pDef->GetAlias().clear(); 915 } 916 // Brackets? 917 if( Peek() == LPAREN ) 918 { 919 Next(); 920 if( Peek() == RPAREN ) 921 { 922 Next(); 923 } 924 else 925 { 926 for(;;) 927 { 928 bool bByVal = false; 929 bool bOptional = false; 930 bool bParamArray = false; 931 while( Peek() == BYVAL || Peek() == BYREF || Peek() == OPTIONAL_ ) 932 { 933 if( Peek() == BYVAL ) 934 { 935 bByVal = true; 936 } 937 else if ( Peek() == BYREF ) 938 { 939 bByVal = false; 940 } 941 else if ( Peek() == OPTIONAL_ ) 942 { 943 bOptional = true; 944 } 945 Next(); 946 } 947 if( bCompatible && Peek() == PARAMARRAY ) 948 { 949 if( bByVal || bOptional ) 950 { 951 Error( ERRCODE_BASIC_UNEXPECTED, PARAMARRAY ); 952 } 953 Next(); 954 bParamArray = true; 955 } 956 SbiSymDef* pPar = VarDecl( nullptr, false, false ); 957 if( !pPar ) 958 { 959 break; 960 } 961 if( bByVal ) 962 { 963 pPar->SetByVal(true); 964 } 965 if( bOptional ) 966 { 967 pPar->SetOptional(); 968 } 969 if( bParamArray ) 970 { 971 pPar->SetParamArray(); 972 } 973 if (SbiSymDef* pOldDef = pDef->GetParams().Find(pPar->GetName(), false)) 974 { 975 Error(ERRCODE_BASIC_VAR_DEFINED, pPar->GetName()); 976 delete pPar; 977 pPar = pOldDef; 978 } 979 else 980 pDef->GetParams().Add( pPar ); 981 SbiToken eTok = Next(); 982 if( eTok != COMMA && eTok != RPAREN ) 983 { 984 bool bError2 = true; 985 if( bOptional && bCompatible && eTok == EQ ) 986 { 987 auto pDefaultExpr = std::make_unique<SbiConstExpression>(this); 988 SbxDataType eType2 = pDefaultExpr->GetType(); 989 990 sal_uInt16 nStringId; 991 if( eType2 == SbxSTRING ) 992 { 993 nStringId = aGblStrings.Add( pDefaultExpr->GetString() ); 994 } 995 else 996 { 997 nStringId = aGblStrings.Add( pDefaultExpr->GetValue(), eType2 ); 998 } 999 pPar->SetDefaultId( nStringId ); 1000 pDefaultExpr.reset(); 1001 1002 eTok = Next(); 1003 if( eTok == COMMA || eTok == RPAREN ) 1004 { 1005 bError2 = false; 1006 } 1007 } 1008 if( bError2 ) 1009 { 1010 Error( ERRCODE_BASIC_EXPECTED, RPAREN ); 1011 break; 1012 } 1013 } 1014 if( eTok == RPAREN ) 1015 { 1016 break; 1017 } 1018 } 1019 } 1020 } 1021 TypeDecl( *pDef ); 1022 if( eType != SbxVARIANT && pDef->GetType() != eType ) 1023 { 1024 Error( ERRCODE_BASIC_BAD_DECLARATION, aName ); 1025 } 1026 if( pDef->GetType() == SbxVARIANT && !( bFunc || bProp ) ) 1027 { 1028 pDef->SetType( SbxEMPTY ); 1029 } 1030 return pDef; 1031 } 1032 1033 // DECLARE 1034 1035 void SbiParser::Declare() 1036 { 1037 DefDeclare( false ); 1038 } 1039 1040 void SbiParser::DefDeclare( bool bPrivate ) 1041 { 1042 Next(); 1043 if( eCurTok == PTRSAFE ) 1044 Next(); 1045 1046 if( eCurTok != SUB && eCurTok != FUNCTION ) 1047 { 1048 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok ); 1049 } 1050 else 1051 { 1052 bool bFunction = (eCurTok == FUNCTION); 1053 1054 SbiProcDef* pDef = ProcDecl( true ); 1055 if( pDef ) 1056 { 1057 if( pDef->GetLib().isEmpty() ) 1058 { 1059 Error( ERRCODE_BASIC_EXPECTED, LIB ); 1060 } 1061 // Is it already there? 1062 SbiSymDef* pOld = aPublics.Find( pDef->GetName() ); 1063 if( pOld ) 1064 { 1065 SbiProcDef* p = pOld->GetProcDef(); 1066 if( !p ) 1067 { 1068 // Declared as a variable 1069 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() ); 1070 delete pDef; 1071 pDef = nullptr; 1072 } 1073 else 1074 { 1075 pDef->Match( p ); 1076 } 1077 } 1078 else 1079 { 1080 aPublics.Add( pDef ); 1081 } 1082 if ( pDef ) 1083 { 1084 pDef->SetPublic( !bPrivate ); 1085 1086 // New declare handling 1087 if( !pDef->GetLib().isEmpty()) 1088 { 1089 if( bNewGblDefs && nGblChain == 0 ) 1090 { 1091 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); 1092 bNewGblDefs = false; 1093 } 1094 1095 sal_uInt16 nSavLine = nLine; 1096 aGen.Statement(); 1097 pDef->Define(); 1098 pDef->SetLine1( nSavLine ); 1099 pDef->SetLine2( nSavLine ); 1100 1101 SbiSymPool& rPool = pDef->GetParams(); 1102 sal_uInt16 nParCount = rPool.GetSize(); 1103 1104 SbxDataType eType = pDef->GetType(); 1105 if( bFunction ) 1106 { 1107 aGen.Gen( SbiOpcode::PARAM_, 0, sal::static_int_cast< sal_uInt16 >( eType ) ); 1108 } 1109 if( nParCount > 1 ) 1110 { 1111 aGen.Gen( SbiOpcode::ARGC_ ); 1112 1113 for( sal_uInt16 i = 1 ; i < nParCount ; ++i ) 1114 { 1115 SbiSymDef* pParDef = rPool.Get( i ); 1116 SbxDataType eParType = pParDef->GetType(); 1117 1118 aGen.Gen( SbiOpcode::PARAM_, i, sal::static_int_cast< sal_uInt16 >( eParType ) ); 1119 aGen.Gen( SbiOpcode::ARGV_ ); 1120 1121 sal_uInt16 nTyp = sal::static_int_cast< sal_uInt16 >( pParDef->GetType() ); 1122 if( pParDef->IsByVal() ) 1123 { 1124 // Reset to avoid additional byval in call to wrapper function 1125 pParDef->SetByVal( false ); 1126 nTyp |= 0x8000; 1127 } 1128 aGen.Gen( SbiOpcode::ARGTYP_, nTyp ); 1129 } 1130 } 1131 1132 aGen.Gen( SbiOpcode::LIB_, aGblStrings.Add( pDef->GetLib() ) ); 1133 1134 SbiOpcode eOp = pDef->IsCdecl() ? SbiOpcode::CALLC_ : SbiOpcode::CALL_; 1135 sal_uInt16 nId = pDef->GetId(); 1136 if( !pDef->GetAlias().isEmpty() ) 1137 { 1138 nId = ( nId & 0x8000 ) | aGblStrings.Add( pDef->GetAlias() ); 1139 } 1140 if( nParCount > 1 ) 1141 { 1142 nId |= 0x8000; 1143 } 1144 aGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( eType ) ); 1145 1146 if( bFunction ) 1147 { 1148 aGen.Gen( SbiOpcode::PUT_ ); 1149 } 1150 aGen.Gen( SbiOpcode::LEAVE_ ); 1151 } 1152 } 1153 } 1154 } 1155 } 1156 1157 void SbiParser::Attribute() 1158 { 1159 // TODO: Need to implement the method as an attributed object. 1160 while( Next() != EQ ) 1161 { 1162 if( Next() != DOT) 1163 { 1164 break; 1165 } 1166 } 1167 1168 if( eCurTok != EQ ) 1169 { 1170 Error( ERRCODE_BASIC_SYNTAX ); 1171 } 1172 else 1173 { 1174 SbiExpression aValue( this ); 1175 } 1176 // Don't generate any code - just discard it. 1177 } 1178 1179 // Call of a SUB or a FUNCTION 1180 1181 void SbiParser::Call() 1182 { 1183 SbiExpression aVar( this, SbSYMBOL ); 1184 aVar.Gen( FORCE_CALL ); 1185 aGen.Gen( SbiOpcode::GET_ ); 1186 } 1187 1188 // SUB/FUNCTION 1189 1190 void SbiParser::SubFunc() 1191 { 1192 DefProc( false, false ); 1193 } 1194 1195 // Read in of a procedure 1196 1197 void SbiParser::DefProc( bool bStatic, bool bPrivate ) 1198 { 1199 sal_uInt16 l1 = nLine; 1200 bool bSub = ( eCurTok == SUB ); 1201 bool bProperty = ( eCurTok == PROPERTY ); 1202 PropertyMode ePropertyMode = PropertyMode::NONE; 1203 if( bProperty ) 1204 { 1205 Next(); 1206 if( eCurTok == GET ) 1207 { 1208 ePropertyMode = PropertyMode::Get; 1209 } 1210 else if( eCurTok == LET ) 1211 { 1212 ePropertyMode = PropertyMode::Let; 1213 } 1214 else if( eCurTok == SET ) 1215 { 1216 ePropertyMode = PropertyMode::Set; 1217 } 1218 else 1219 { 1220 Error( ERRCODE_BASIC_EXPECTED, "Get or Let or Set" ); 1221 } 1222 } 1223 1224 SbiToken eExit = eCurTok; 1225 SbiProcDef* pDef = ProcDecl( false ); 1226 if( !pDef ) 1227 { 1228 return; 1229 } 1230 pDef->setPropertyMode( ePropertyMode ); 1231 1232 // Is the Proc already declared? 1233 SbiSymDef* pOld = aPublics.Find( pDef->GetName() ); 1234 if( pOld ) 1235 { 1236 pProc = pOld->GetProcDef(); 1237 if( !pProc ) 1238 { 1239 // Declared as a variable 1240 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() ); 1241 delete pDef; 1242 return; 1243 } 1244 // #100027: Multiple declaration -> Error 1245 // #112787: Not for setup, REMOVE for 8 1246 else if( pProc->IsUsedForProcDecl() ) 1247 { 1248 PropertyMode ePropMode = pDef->getPropertyMode(); 1249 if( ePropMode == PropertyMode::NONE || ePropMode == pProc->getPropertyMode() ) 1250 { 1251 Error( ERRCODE_BASIC_PROC_DEFINED, pDef->GetName() ); 1252 delete pDef; 1253 return; 1254 } 1255 } 1256 1257 pDef->Match( pProc ); 1258 } 1259 else 1260 { 1261 aPublics.Add( pDef ); 1262 } 1263 assert(pDef); 1264 pProc = pDef; 1265 pProc->SetPublic( !bPrivate ); 1266 1267 // Now we set the search hierarchy for symbols as well as the 1268 // current procedure. 1269 aPublics.SetProcId( pProc->GetId() ); 1270 pProc->GetParams().SetParent( &aPublics ); 1271 if( bStatic ) 1272 { 1273 if ( bVBASupportOn ) 1274 { 1275 pProc->SetStatic(); 1276 } 1277 else 1278 { 1279 Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); // STATIC SUB ... 1280 } 1281 } 1282 else 1283 { 1284 pProc->SetStatic( false ); 1285 } 1286 // Normal case: Local variable->parameter->global variable 1287 pProc->GetLocals().SetParent( &pProc->GetParams() ); 1288 pPool = &pProc->GetLocals(); 1289 1290 pProc->Define(); 1291 OpenBlock( eExit ); 1292 StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) ); 1293 sal_uInt16 l2 = nLine; 1294 pProc->SetLine1( l1 ); 1295 pProc->SetLine2( l2 ); 1296 pPool = &aPublics; 1297 aPublics.SetProcId( 0 ); 1298 // Open labels? 1299 pProc->GetLabels().CheckRefs(); 1300 CloseBlock(); 1301 aGen.Gen( SbiOpcode::LEAVE_ ); 1302 pProc = nullptr; 1303 } 1304 1305 // STATIC variable|procedure 1306 1307 void SbiParser::Static() 1308 { 1309 DefStatic( false ); 1310 } 1311 1312 void SbiParser::DefStatic( bool bPrivate ) 1313 { 1314 SbiSymPool* p; 1315 1316 switch( Peek() ) 1317 { 1318 case SUB: 1319 case FUNCTION: 1320 case PROPERTY: 1321 // End global chain if necessary (not done in 1322 // SbiParser::Parse() under these conditions 1323 if( bNewGblDefs && nGblChain == 0 ) 1324 { 1325 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); 1326 bNewGblDefs = false; 1327 } 1328 Next(); 1329 DefProc( true, bPrivate ); 1330 break; 1331 default: 1332 if( !pProc ) 1333 { 1334 Error( ERRCODE_BASIC_NOT_IN_SUBR ); 1335 } 1336 // Reset the Pool, so that STATIC-Declarations go into the 1337 // global Pool 1338 p = pPool; 1339 pPool = &aPublics; 1340 DefVar( SbiOpcode::STATIC_, true ); 1341 pPool = p; 1342 break; 1343 } 1344 } 1345 1346 bool SbiParser::IsUnoInterface(const OUString& sTypeName) 1347 { 1348 try 1349 { 1350 return css::reflection::theCoreReflection::get( 1351 comphelper::getProcessComponentContext())->forName(sTypeName).is(); 1352 } 1353 catch(const Exception&) 1354 { 1355 OSL_FAIL("Could not create reflection.CoreReflection."); 1356 } 1357 return false; 1358 } 1359 1360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1361
