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