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/sbxmeth.hxx> 22 #include <basic/sbmod.hxx> 23 #include <basic/sbstar.hxx> 24 #include <basic/sbx.hxx> 25 #include <parser.hxx> 26 #include <com/sun/star/script/ModuleType.hpp> 27 #include <rtl/character.hxx> 28 29 struct SbiParseStack { // "Stack" for statement-blocks 30 SbiParseStack* pNext; // Chain 31 SbiExprNode* pWithVar; 32 SbiToken eExitTok; 33 sal_uInt32 nChain; // JUMP-Chain 34 }; 35 36 namespace { 37 38 struct SbiStatement { 39 SbiToken eTok; 40 void( SbiParser::*Func )(); 41 bool bMain; // true: OK outside the SUB 42 bool bSubr; // true: OK inside the SUB 43 }; 44 45 } 46 47 #define Y true 48 #define N false 49 50 static const SbiStatement StmntTable [] = { 51 { ATTRIBUTE, &SbiParser::Attribute, Y, Y, }, // ATTRIBUTE 52 { CALL, &SbiParser::Call, N, Y, }, // CALL 53 { CLOSE, &SbiParser::Close, N, Y, }, // CLOSE 54 { CONST_, &SbiParser::Dim, Y, Y, }, // CONST 55 { DECLARE, &SbiParser::Declare, Y, N, }, // DECLARE 56 { DEFBOOL, &SbiParser::DefXXX, Y, N, }, // DEFBOOL 57 { DEFCUR, &SbiParser::DefXXX, Y, N, }, // DEFCUR 58 { DEFDATE, &SbiParser::DefXXX, Y, N, }, // DEFDATE 59 { DEFDBL, &SbiParser::DefXXX, Y, N, }, // DEFDBL 60 { DEFERR, &SbiParser::DefXXX, Y, N, }, // DEFERR 61 { DEFINT, &SbiParser::DefXXX, Y, N, }, // DEFINT 62 { DEFLNG, &SbiParser::DefXXX, Y, N, }, // DEFLNG 63 { DEFOBJ, &SbiParser::DefXXX, Y, N, }, // DEFOBJ 64 { DEFSNG, &SbiParser::DefXXX, Y, N, }, // DEFSNG 65 { DEFSTR, &SbiParser::DefXXX, Y, N, }, // DEFSTR 66 { DEFVAR, &SbiParser::DefXXX, Y, N, }, // DEFVAR 67 { DIM, &SbiParser::Dim, Y, Y, }, // DIM 68 { DO, &SbiParser::DoLoop, N, Y, }, // DO 69 { ELSE, &SbiParser::NoIf, N, Y, }, // ELSE 70 { ELSEIF, &SbiParser::NoIf, N, Y, }, // ELSEIF 71 { ENDIF, &SbiParser::NoIf, N, Y, }, // ENDIF 72 { END, &SbiParser::Stop, N, Y, }, // END 73 { ENUM, &SbiParser::Enum, Y, N, }, // TYPE 74 { ERASE, &SbiParser::Erase, N, Y, }, // ERASE 75 { ERROR_, &SbiParser::ErrorStmnt, N, Y, }, // ERROR 76 { EXIT, &SbiParser::Exit, N, Y, }, // EXIT 77 { FOR, &SbiParser::For, N, Y, }, // FOR 78 { FUNCTION, &SbiParser::SubFunc, Y, N, }, // FUNCTION 79 { GOSUB, &SbiParser::Goto, N, Y, }, // GOSUB 80 { GLOBAL, &SbiParser::Dim, Y, N, }, // GLOBAL 81 { GOTO, &SbiParser::Goto, N, Y, }, // GOTO 82 { IF, &SbiParser::If, N, Y, }, // IF 83 { IMPLEMENTS, &SbiParser::Implements, Y, N, }, // IMPLEMENTS 84 { INPUT, &SbiParser::Input, N, Y, }, // INPUT 85 { LET, &SbiParser::Assign, N, Y, }, // LET 86 { LINE, &SbiParser::Line, N, Y, }, // LINE, -> LINE INPUT (#i92642) 87 { LINEINPUT,&SbiParser::LineInput, N, Y, }, // LINE INPUT 88 { LOOP, &SbiParser::BadBlock, N, Y, }, // LOOP 89 { LSET, &SbiParser::LSet, N, Y, }, // LSET 90 { NAME, &SbiParser::Name, N, Y, }, // NAME 91 { NEXT, &SbiParser::BadBlock, N, Y, }, // NEXT 92 { ON, &SbiParser::On, N, Y, }, // ON 93 { OPEN, &SbiParser::Open, N, Y, }, // OPEN 94 { OPTION, &SbiParser::Option, Y, N, }, // OPTION 95 { PRINT, &SbiParser::Print, N, Y, }, // PRINT 96 { PRIVATE, &SbiParser::Dim, Y, N, }, // PRIVATE 97 { PROPERTY, &SbiParser::SubFunc, Y, N, }, // FUNCTION 98 { PUBLIC, &SbiParser::Dim, Y, N, }, // PUBLIC 99 { REDIM, &SbiParser::ReDim, N, Y, }, // DIM 100 { RESUME, &SbiParser::Resume, N, Y, }, // RESUME 101 { RETURN, &SbiParser::Return, N, Y, }, // RETURN 102 { RSET, &SbiParser::RSet, N, Y, }, // RSET 103 { SELECT, &SbiParser::Select, N, Y, }, // SELECT 104 { SET, &SbiParser::Set, N, Y, }, // SET 105 { STATIC, &SbiParser::Static, Y, Y, }, // STATIC 106 { STOP, &SbiParser::Stop, N, Y, }, // STOP 107 { SUB, &SbiParser::SubFunc, Y, N, }, // SUB 108 { TYPE, &SbiParser::Type, Y, N, }, // TYPE 109 { UNTIL, &SbiParser::BadBlock, N, Y, }, // UNTIL 110 { WHILE, &SbiParser::While, N, Y, }, // WHILE 111 { WEND, &SbiParser::BadBlock, N, Y, }, // WEND 112 { WITH, &SbiParser::With, N, Y, }, // WITH 113 { WRITE, &SbiParser::Write, N, Y, }, // WRITE 114 115 { NIL, nullptr, N, N } 116 }; 117 118 119 SbiParser::SbiParser( StarBASIC* pb, SbModule* pm ) 120 : SbiTokenizer( pm->GetSource32(), pb ), 121 aGlobals( aGblStrings, SbGLOBAL, this ), 122 aPublics( aGblStrings, SbPUBLIC, this ), 123 aRtlSyms( aGblStrings, SbRTL, this ), 124 aGen( *pm, this, 1024 ) 125 { 126 eEndTok = NIL; 127 pProc = nullptr; 128 pStack = nullptr; 129 pWithVar = nullptr; 130 nBase = 0; 131 bGblDefs = 132 bNewGblDefs = 133 bSingleLineIf = 134 bCodeCompleting = 135 bExplicit = false; 136 bClassModule = ( pm->GetModuleType() == css::script::ModuleType::CLASS ); 137 pPool = &aPublics; 138 for(SbxDataType & eDefType : eDefTypes) 139 eDefType = SbxVARIANT; // no explicit default type 140 141 aPublics.SetParent( &aGlobals ); 142 aGlobals.SetParent( &aRtlSyms ); 143 144 145 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); 146 147 rTypeArray = new SbxArray; // array for user defined types 148 rEnumArray = new SbxArray; // array for Enum types 149 bVBASupportOn = pm->IsVBACompat(); 150 if ( bVBASupportOn ) 151 EnableCompatibility(); 152 153 } 154 155 SbiParser::~SbiParser() { } 156 157 // part of the runtime-library? 158 SbiSymDef* SbiParser::CheckRTLForSym(const OUString& rSym, SbxDataType eType) 159 { 160 SbxVariable* pVar = GetBasic()->GetRtl()->Find(rSym, SbxClassType::DontCare); 161 if (!pVar) 162 return nullptr; 163 164 if (SbxMethod* pMethod = dynamic_cast<SbxMethod*>(pVar)) 165 { 166 SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym ); 167 if (pMethod->IsRuntimeFunction()) 168 { 169 pProc_->SetType( pMethod->GetRuntimeFunctionReturnType() ); 170 } 171 else 172 { 173 pProc_->SetType( pVar->GetType() ); 174 } 175 return pProc_; 176 } 177 178 179 SbiSymDef* pDef = aRtlSyms.AddSym(rSym); 180 pDef->SetType(eType); 181 return pDef; 182 } 183 184 // close global chain 185 186 bool SbiParser::HasGlobalCode() 187 { 188 if( bGblDefs && nGblChain ) 189 { 190 aGen.BackChain( nGblChain ); 191 aGen.Gen( SbiOpcode::LEAVE_ ); 192 nGblChain = 0; 193 } 194 return bGblDefs; 195 } 196 197 void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar ) 198 { 199 SbiParseStack* p = new SbiParseStack; 200 p->eExitTok = eTok; 201 p->nChain = 0; 202 p->pWithVar = pWithVar; 203 p->pNext = pStack; 204 pStack = p; 205 pWithVar = pVar; 206 207 // #29955 service the for-loop level 208 if( eTok == FOR ) 209 aGen.IncForLevel(); 210 } 211 212 void SbiParser::CloseBlock() 213 { 214 if( pStack ) 215 { 216 SbiParseStack* p = pStack; 217 218 // #29955 service the for-loop level 219 if( p->eExitTok == FOR ) 220 aGen.DecForLevel(); 221 222 aGen.BackChain( p->nChain ); 223 pStack = p->pNext; 224 pWithVar = p->pWithVar; 225 delete p; 226 } 227 } 228 229 // EXIT ... 230 231 void SbiParser::Exit() 232 { 233 SbiToken eTok = Next(); 234 for( SbiParseStack* p = pStack; p; p = p->pNext ) 235 { 236 SbiToken eExitTok = p->eExitTok; 237 if( eTok == eExitTok || 238 (eTok == PROPERTY && (eExitTok == GET || eExitTok == LET) ) ) // #i109051 239 { 240 p->nChain = aGen.Gen( SbiOpcode::JUMP_, p->nChain ); 241 return; 242 } 243 } 244 if( pStack ) 245 Error( ERRCODE_BASIC_EXPECTED, pStack->eExitTok ); 246 else 247 Error( ERRCODE_BASIC_BAD_EXIT ); 248 } 249 250 bool SbiParser::TestSymbol() 251 { 252 Peek(); 253 if( eCurTok == SYMBOL ) 254 { 255 Next(); return true; 256 } 257 Error( ERRCODE_BASIC_SYMBOL_EXPECTED ); 258 return false; 259 } 260 261 262 bool SbiParser::TestToken( SbiToken t ) 263 { 264 if( Peek() == t ) 265 { 266 Next(); return true; 267 } 268 else 269 { 270 Error( ERRCODE_BASIC_EXPECTED, t ); 271 return false; 272 } 273 } 274 275 276 bool SbiParser::TestComma() 277 { 278 SbiToken eTok = Peek(); 279 if( IsEoln( eTok ) ) 280 { 281 Next(); 282 return false; 283 } 284 else if( eTok != COMMA ) 285 { 286 Error( ERRCODE_BASIC_EXPECTED, COMMA ); 287 return false; 288 } 289 Next(); 290 return true; 291 } 292 293 294 void SbiParser::TestEoln() 295 { 296 if( !IsEoln( Next() ) ) 297 { 298 Error( ERRCODE_BASIC_EXPECTED, EOLN ); 299 while( !IsEoln( Next() ) ) {} 300 } 301 } 302 303 304 void SbiParser::StmntBlock( SbiToken eEnd ) 305 { 306 SbiToken xe = eEndTok; 307 eEndTok = eEnd; 308 while( !bAbort && Parse() ) {} 309 eEndTok = xe; 310 if( IsEof() ) 311 { 312 Error( ERRCODE_BASIC_BAD_BLOCK, eEnd ); 313 bAbort = true; 314 } 315 } 316 317 void SbiParser::SetCodeCompleting( bool b ) 318 { 319 bCodeCompleting = b; 320 } 321 322 323 bool SbiParser::Parse() 324 { 325 if( bAbort ) return false; 326 327 EnableErrors(); 328 329 bErrorIsSymbol = false; 330 Peek(); 331 bErrorIsSymbol = true; 332 333 if( IsEof() ) 334 { 335 // AB #33133: If no sub has been created before, 336 // the global chain must be closed here! 337 // AB #40689: Due to the new static-handling there 338 // can be another nGblChain, so ask for it before. 339 if( bNewGblDefs && nGblChain == 0 ) 340 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); 341 return false; 342 } 343 344 345 if( IsEoln( eCurTok ) ) 346 { 347 Next(); return true; 348 } 349 350 if( !bSingleLineIf && MayBeLabel( true ) ) 351 { 352 // is a label 353 if( !pProc ) 354 Error( ERRCODE_BASIC_NOT_IN_MAIN, aSym ); 355 else 356 pProc->GetLabels().Define( aSym ); 357 Next(); Peek(); 358 359 if( IsEoln( eCurTok ) ) 360 { 361 Next(); return true; 362 } 363 } 364 365 // end of parsing? 366 if( eCurTok == eEndTok || 367 ( bVBASupportOn && // #i109075 368 (eCurTok == ENDFUNC || eCurTok == ENDPROPERTY || eCurTok == ENDSUB) && 369 (eEndTok == ENDFUNC || eEndTok == ENDPROPERTY || eEndTok == ENDSUB) ) ) 370 { 371 Next(); 372 if( eCurTok != NIL ) 373 aGen.Statement(); 374 return false; 375 } 376 377 // comment? 378 if( eCurTok == REM ) 379 { 380 Next(); return true; 381 } 382 383 // In vba it's possible to do Error.foobar ( even if it results in 384 // a runtime error 385 if ( eCurTok == ERROR_ && IsVBASupportOn() ) // we probably need to define a subset of keywords where this madness applies e.g. if ( IsVBASupportOn() && SymbolCanBeRedined( eCurTok ) ) 386 { 387 SbiTokenizer tokens( *this ); 388 tokens.Next(); 389 if ( tokens.Peek() == DOT ) 390 { 391 eCurTok = SYMBOL; 392 ePush = eCurTok; 393 } 394 } 395 // if there's a symbol, it's either a variable (LET) 396 // or a SUB-procedure (CALL without brackets) 397 // DOT for assignments in the WITH-block: .A=5 398 if( eCurTok == SYMBOL || eCurTok == DOT ) 399 { 400 if( !pProc ) 401 Error( ERRCODE_BASIC_EXPECTED, SUB ); 402 else 403 { 404 // for correct line and column... 405 Next(); 406 Push( eCurTok ); 407 aGen.Statement(); 408 Symbol(nullptr); 409 } 410 } 411 else 412 { 413 Next(); 414 415 // statement parsers 416 417 const SbiStatement* p; 418 for( p = StmntTable; p->eTok != NIL; p++ ) 419 if( p->eTok == eCurTok ) 420 break; 421 if( p->eTok != NIL ) 422 { 423 if( !pProc && !p->bMain ) 424 Error( ERRCODE_BASIC_NOT_IN_MAIN, eCurTok ); 425 else if( pProc && !p->bSubr ) 426 Error( ERRCODE_BASIC_NOT_IN_SUBR, eCurTok ); 427 else 428 { 429 // AB #41606/#40689: Due to the new static-handling there 430 // can be another nGblChain, so ask for it before. 431 if( bNewGblDefs && nGblChain == 0 && 432 ( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) ) 433 { 434 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); 435 bNewGblDefs = false; 436 } 437 // statement-opcode at the beginning of a sub, too, please 438 if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) || 439 eCurTok == SUB || eCurTok == FUNCTION ) 440 aGen.Statement(); 441 (this->*( p->Func ) )(); 442 ErrCode nSbxErr = SbxBase::GetError(); 443 if( nSbxErr ) 444 { 445 SbxBase::ResetError(); 446 Error( nSbxErr ); 447 } 448 } 449 } 450 else 451 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok ); 452 } 453 454 // test for the statement's end - 455 // might also be an ELSE, as there must not necessary be a : before the ELSE! 456 457 if( !IsEos() ) 458 { 459 Peek(); 460 if( !IsEos() && eCurTok != ELSE ) 461 { 462 // if the parsing has been aborted, jump over to the ":" 463 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok ); 464 while( !IsEos() ) Next(); 465 } 466 } 467 // The parser aborts at the end, the 468 // next token has not been fetched yet! 469 return true; 470 } 471 472 473 SbiExprNode* SbiParser::GetWithVar() 474 { 475 if( pWithVar ) 476 return pWithVar; 477 478 SbiParseStack* p = pStack; 479 while( p ) 480 { 481 // LoopVar can at the moment only be for with 482 if( p->pWithVar ) 483 return p->pWithVar; 484 p = p->pNext; 485 } 486 return nullptr; 487 } 488 489 490 // assignment or subroutine call 491 492 void SbiParser::Symbol( const KeywordSymbolInfo* pKeywordSymbolInfo ) 493 { 494 SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD; 495 SbiExpression aVar( this, SbSYMBOL, eMode, pKeywordSymbolInfo ); 496 497 bool bEQ = ( Peek() == EQ ); 498 if( !bEQ && bVBASupportOn && aVar.IsBracket() ) 499 Error( ERRCODE_BASIC_EXPECTED, "=" ); 500 501 RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL ); 502 bool bSpecialMidHandling = false; 503 SbiSymDef* pDef = aVar.GetRealVar(); 504 if( bEQ && pDef && pDef->GetScope() == SbRTL ) 505 { 506 OUString aRtlName = pDef->GetName(); 507 if( aRtlName.equalsIgnoreAsciiCase("Mid") ) 508 { 509 SbiExprNode* pExprNode = aVar.GetExprNode(); 510 if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL ) 511 { 512 SbiExprList* pPar = pExprNode->GetParameters(); 513 short nParCount = pPar ? pPar->GetSize() : 0; 514 if( nParCount == 2 || nParCount == 3 ) 515 { 516 if( nParCount == 2 ) 517 pPar->addExpression( std::make_unique<SbiExpression>( this, -1, SbxLONG ) ); 518 519 TestToken( EQ ); 520 pPar->addExpression( std::make_unique<SbiExpression>( this ) ); 521 522 bSpecialMidHandling = true; 523 } 524 } 525 } 526 } 527 aVar.Gen( eRecMode ); 528 if( !bSpecialMidHandling ) 529 { 530 if( !bEQ ) 531 { 532 aGen.Gen( SbiOpcode::GET_ ); 533 } 534 else 535 { 536 // so it must be an assignment! 537 if( !aVar.IsLvalue() ) 538 Error( ERRCODE_BASIC_LVALUE_EXPECTED ); 539 TestToken( EQ ); 540 SbiExpression aExpr( this ); 541 aExpr.Gen(); 542 SbiOpcode eOp = SbiOpcode::PUT_; 543 if( pDef ) 544 { 545 if( pDef->GetConstDef() ) 546 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() ); 547 if( pDef->GetType() == SbxOBJECT ) 548 { 549 eOp = SbiOpcode::SET_; 550 if( pDef->GetTypeId() ) 551 { 552 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() ); 553 return; 554 } 555 } 556 } 557 aGen.Gen( eOp ); 558 } 559 } 560 } 561 562 563 void SbiParser::Assign() 564 { 565 SbiExpression aLvalue( this, SbLVALUE ); 566 TestToken( EQ ); 567 SbiExpression aExpr( this ); 568 aLvalue.Gen(); 569 aExpr.Gen(); 570 sal_uInt16 nLen = 0; 571 SbiSymDef* pDef = aLvalue.GetRealVar(); 572 { 573 if( pDef->GetConstDef() ) 574 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() ); 575 nLen = aLvalue.GetRealVar()->GetLen(); 576 } 577 if( nLen ) 578 aGen.Gen( SbiOpcode::PAD_, nLen ); 579 aGen.Gen( SbiOpcode::PUT_ ); 580 } 581 582 // assignments of an object-variable 583 584 void SbiParser::Set() 585 { 586 SbiExpression aLvalue( this, SbLVALUE ); 587 SbxDataType eType = aLvalue.GetType(); 588 if( eType != SbxOBJECT && eType != SbxEMPTY && eType != SbxVARIANT ) 589 Error( ERRCODE_BASIC_INVALID_OBJECT ); 590 TestToken( EQ ); 591 SbiSymDef* pDef = aLvalue.GetRealVar(); 592 if( pDef->GetConstDef() ) 593 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() ); 594 595 SbiToken eTok = Peek(); 596 if( eTok == NEW ) 597 { 598 Next(); 599 SbiSymDef* pTypeDef = new SbiSymDef( OUString() ); 600 TypeDecl( *pTypeDef, true ); 601 602 aLvalue.Gen(); 603 aGen.Gen( SbiOpcode::CREATE_, pDef->GetId(), pTypeDef->GetTypeId() ); 604 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() ); 605 } 606 else 607 { 608 SbiExpression aExpr( this ); 609 aLvalue.Gen(); 610 aExpr.Gen(); 611 // It's a good idea to distinguish between 612 // set something = another & 613 // something = another 614 // ( it's necessary for vba objects where set is object 615 // specific and also doesn't involve processing default params ) 616 if( pDef->GetTypeId() ) 617 { 618 if ( bVBASupportOn ) 619 aGen.Gen( SbiOpcode::VBASETCLASS_, pDef->GetTypeId() ); 620 else 621 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() ); 622 } 623 else 624 { 625 if ( bVBASupportOn ) 626 aGen.Gen( SbiOpcode::VBASET_ ); 627 else 628 aGen.Gen( SbiOpcode::SET_ ); 629 } 630 } 631 } 632 633 // JSM 07.10.95 634 void SbiParser::LSet() 635 { 636 SbiExpression aLvalue( this, SbLVALUE ); 637 if( aLvalue.GetType() != SbxSTRING ) 638 { 639 Error( ERRCODE_BASIC_INVALID_OBJECT ); 640 } 641 TestToken( EQ ); 642 SbiSymDef* pDef = aLvalue.GetRealVar(); 643 if( pDef && pDef->GetConstDef() ) 644 { 645 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() ); 646 } 647 SbiExpression aExpr( this ); 648 aLvalue.Gen(); 649 aExpr.Gen(); 650 aGen.Gen( SbiOpcode::LSET_ ); 651 } 652 653 // JSM 07.10.95 654 void SbiParser::RSet() 655 { 656 SbiExpression aLvalue( this, SbLVALUE ); 657 if( aLvalue.GetType() != SbxSTRING ) 658 { 659 Error( ERRCODE_BASIC_INVALID_OBJECT ); 660 } 661 TestToken( EQ ); 662 SbiSymDef* pDef = aLvalue.GetRealVar(); 663 if( pDef && pDef->GetConstDef() ) 664 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() ); 665 SbiExpression aExpr( this ); 666 aLvalue.Gen(); 667 aExpr.Gen(); 668 aGen.Gen( SbiOpcode::RSET_ ); 669 } 670 671 // DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR and so on 672 673 void SbiParser::DefXXX() 674 { 675 sal_Unicode ch1, ch2; 676 SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER ); 677 678 while( !bAbort ) 679 { 680 if( Next() != SYMBOL ) break; 681 ch1 = rtl::toAsciiUpperCase(aSym[0]); 682 ch2 = 0; 683 if( Peek() == MINUS ) 684 { 685 Next(); 686 if( Next() != SYMBOL ) Error( ERRCODE_BASIC_SYMBOL_EXPECTED ); 687 else 688 { 689 ch2 = rtl::toAsciiUpperCase(aSym[0]); 690 if( ch2 < ch1 ) 691 { 692 Error( ERRCODE_BASIC_SYNTAX ); 693 ch2 = 0; 694 } 695 } 696 } 697 if (!ch2) ch2 = ch1; 698 ch1 -= 'A'; ch2 -= 'A'; 699 for (; ch1 <= ch2; ch1++) eDefTypes[ ch1 ] = t; 700 if( !TestComma() ) break; 701 } 702 } 703 704 // STOP/SYSTEM 705 706 void SbiParser::Stop() 707 { 708 aGen.Gen( SbiOpcode::STOP_ ); 709 Peek(); // #35694: only Peek(), so that EOL is recognized in Single-Line-If 710 } 711 712 // IMPLEMENTS 713 714 void SbiParser::Implements() 715 { 716 if( !bClassModule ) 717 { 718 Error( ERRCODE_BASIC_UNEXPECTED, IMPLEMENTS ); 719 return; 720 } 721 722 Peek(); 723 if( eCurTok != SYMBOL ) 724 { 725 Error( ERRCODE_BASIC_SYMBOL_EXPECTED ); 726 return; 727 } 728 729 OUString aImplementedIface = aSym; 730 Next(); 731 if( Peek() == DOT ) 732 { 733 OUString aDotStr( '.' ); 734 while( Peek() == DOT ) 735 { 736 aImplementedIface += aDotStr; 737 Next(); 738 SbiToken ePeekTok = Peek(); 739 if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) ) 740 { 741 Next(); 742 aImplementedIface += aSym; 743 } 744 else 745 { 746 Next(); 747 Error( ERRCODE_BASIC_SYMBOL_EXPECTED ); 748 break; 749 } 750 } 751 } 752 aIfaceVector.push_back( aImplementedIface ); 753 } 754 755 void SbiParser::EnableCompatibility() 756 { 757 if( !bCompatible ) 758 AddConstants(); 759 bCompatible = true; 760 } 761 762 // OPTION 763 764 void SbiParser::Option() 765 { 766 switch( Next() ) 767 { 768 case BASIC_EXPLICIT: 769 bExplicit = true; break; 770 case BASE: 771 if( Next() == NUMBER && ( nVal == 0 || nVal == 1 ) ) 772 { 773 nBase = static_cast<short>(nVal); 774 break; 775 } 776 Error( ERRCODE_BASIC_EXPECTED, "0/1" ); 777 break; 778 case PRIVATE: 779 { 780 OUString aString = SbiTokenizer::Symbol(Next()); 781 if( !aString.equalsIgnoreAsciiCase("Module") ) 782 { 783 Error( ERRCODE_BASIC_EXPECTED, "Module" ); 784 } 785 break; 786 } 787 case COMPARE: 788 { 789 SbiToken eTok = Next(); 790 if( eTok == BINARY ) 791 { 792 } 793 else if( eTok == SYMBOL && GetSym().equalsIgnoreAsciiCase("text") ) 794 { 795 } 796 else 797 { 798 Error( ERRCODE_BASIC_EXPECTED, "Text/Binary" ); 799 } 800 break; 801 } 802 case COMPATIBLE: 803 EnableCompatibility(); 804 break; 805 806 case CLASSMODULE: 807 bClassModule = true; 808 aGen.GetModule().SetModuleType( css::script::ModuleType::CLASS ); 809 break; 810 case VBASUPPORT: // Option VBASupport used to override the module mode ( in fact this must reset the mode 811 if( Next() == NUMBER ) 812 { 813 if ( nVal == 1 || nVal == 0 ) 814 { 815 bVBASupportOn = ( nVal == 1 ); 816 if ( bVBASupportOn ) 817 { 818 EnableCompatibility(); 819 } 820 // if the module setting is different 821 // reset it to what the Option tells us 822 if ( bVBASupportOn != aGen.GetModule().IsVBACompat() ) 823 { 824 aGen.GetModule().SetVBACompat( bVBASupportOn ); 825 } 826 break; 827 } 828 } 829 Error( ERRCODE_BASIC_EXPECTED, "0/1" ); 830 break; 831 default: 832 Error( ERRCODE_BASIC_BAD_OPTION, eCurTok ); 833 } 834 } 835 836 static void addStringConst( SbiSymPool& rPool, const OUString& pSym, const OUString& rStr ) 837 { 838 SbiConstDef* pConst = new SbiConstDef( pSym ); 839 pConst->SetType( SbxSTRING ); 840 pConst->Set( rStr ); 841 rPool.Add( pConst ); 842 } 843 844 void SbiParser::AddConstants() 845 { 846 // #113063 Create constant RTL symbols 847 addStringConst( aPublics, "vbCr", "\x0D" ); 848 addStringConst( aPublics, "vbCrLf", "\x0D\x0A" ); 849 addStringConst( aPublics, "vbFormFeed", "\x0C" ); 850 addStringConst( aPublics, "vbLf", "\x0A" ); 851 #ifdef _WIN32 852 addStringConst( aPublics, "vbNewLine", "\x0D\x0A" ); 853 #else 854 addStringConst( aPublics, "vbNewLine", "\x0A" ); 855 #endif 856 addStringConst( aPublics, "vbNullString", "" ); 857 addStringConst( aPublics, "vbTab", "\x09" ); 858 addStringConst( aPublics, "vbVerticalTab", "\x0B" ); 859 860 // Force length 1 and make char 0 afterwards 861 OUString aNullCharStr(u'\0'); 862 addStringConst( aPublics, "vbNullChar", aNullCharStr ); 863 } 864 865 // ERROR n 866 867 void SbiParser::ErrorStmnt() 868 { 869 SbiExpression aPar( this ); 870 aPar.Gen(); 871 aGen.Gen( SbiOpcode::ERROR_ ); 872 } 873 874 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 875
