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