1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_basic.hxx" 30 31 #include "sbcomp.hxx" 32 33 // Single-line IF und Multiline IF 34 35 void SbiParser::If() 36 { 37 sal_uInt32 nEndLbl; 38 SbiToken eTok = NIL; 39 // Ende-Tokens ignorieren: 40 SbiExpression aCond( this ); 41 aCond.Gen(); 42 TestToken( THEN ); 43 if( IsEoln( Next() ) ) 44 { 45 // AB 13.5.1996: #27720# Am Ende jeden Blocks muss ein Jump zu ENDIF 46 // eingefuegt werden, damit bei ELSEIF nicht erneut die Bedingung 47 // ausgewertet wird. Die Tabelle nimmt alle Absprungstellen auf. 48 #define JMP_TABLE_SIZE 100 49 sal_uInt32 pnJmpToEndLbl[JMP_TABLE_SIZE]; // 100 ELSEIFs zulaessig 50 sal_uInt16 iJmp = 0; // aktueller Tabellen-Index 51 52 // multiline IF 53 nEndLbl = aGen.Gen( _JUMPF, 0 ); 54 eTok = Peek(); 55 while( !( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) && 56 !bAbort && Parse() ) 57 { 58 eTok = Peek(); 59 if( IsEof() ) 60 { 61 Error( SbERR_BAD_BLOCK, IF ); bAbort = sal_True; return; 62 } 63 } 64 // ELSEIF? 65 while( eTok == ELSEIF ) 66 { 67 // #27720# Bei erfolgreichem IF/ELSEIF auf ENDIF springen 68 if( iJmp >= JMP_TABLE_SIZE ) 69 { 70 Error( SbERR_PROG_TOO_LARGE ); bAbort = sal_True; return; 71 } 72 pnJmpToEndLbl[iJmp++] = aGen.Gen( _JUMP, 0 ); 73 74 Next(); 75 aGen.BackChain( nEndLbl ); 76 77 aGen.Statement(); 78 SbiExpression* pCond = new SbiExpression( this ); 79 pCond->Gen(); 80 nEndLbl = aGen.Gen( _JUMPF, 0 ); 81 delete pCond; 82 TestToken( THEN ); 83 eTok = Peek(); 84 while( !( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) && 85 !bAbort && Parse() ) 86 { 87 eTok = Peek(); 88 if( IsEof() ) 89 { 90 Error( SbERR_BAD_BLOCK, ELSEIF ); bAbort = sal_True; return; 91 } 92 } 93 } 94 if( eTok == ELSE ) 95 { 96 Next(); 97 sal_uInt32 nElseLbl = nEndLbl; 98 nEndLbl = aGen.Gen( _JUMP, 0 ); 99 aGen.BackChain( nElseLbl ); 100 101 aGen.Statement(); 102 StmntBlock( ENDIF ); 103 } 104 else if( eTok == ENDIF ) 105 Next(); 106 107 // #27720# Jmp-Tabelle abarbeiten 108 while( iJmp > 0 ) 109 { 110 iJmp--; 111 aGen.BackChain( pnJmpToEndLbl[iJmp] ); 112 } 113 } 114 else 115 { 116 // single line IF 117 bSingleLineIf = sal_True; 118 nEndLbl = aGen.Gen( _JUMPF, 0 ); 119 Push( eCurTok ); 120 while( !bAbort ) 121 { 122 if( !Parse() ) break; 123 eTok = Peek(); 124 if( eTok == ELSE || eTok == EOLN || eTok == REM ) 125 break; 126 } 127 if( eTok == ELSE ) 128 { 129 Next(); 130 sal_uInt32 nElseLbl = nEndLbl; 131 nEndLbl = aGen.Gen( _JUMP, 0 ); 132 aGen.BackChain( nElseLbl ); 133 while( !bAbort ) 134 { 135 if( !Parse() ) break; 136 eTok = Peek(); 137 if( eTok == EOLN ) 138 break; 139 } 140 } 141 bSingleLineIf = sal_False; 142 } 143 aGen.BackChain( nEndLbl ); 144 } 145 146 // ELSE/ELSEIF/ENDIF ohne IF 147 148 void SbiParser::NoIf() 149 { 150 Error( SbERR_NO_IF ); 151 StmntBlock( ENDIF ); 152 } 153 154 // DO WHILE...LOOP 155 // DO ... LOOP WHILE 156 157 void SbiParser::DoLoop() 158 { 159 sal_uInt32 nStartLbl = aGen.GetPC(); 160 OpenBlock( DO ); 161 SbiToken eTok = Next(); 162 if( IsEoln( eTok ) ) 163 { 164 // DO ... LOOP [WHILE|UNTIL expr] 165 StmntBlock( LOOP ); 166 eTok = Next(); 167 if( eTok == UNTIL || eTok == WHILE ) 168 { 169 SbiExpression aExpr( this ); 170 aExpr.Gen(); 171 aGen.Gen( eTok == UNTIL ? _JUMPF : _JUMPT, nStartLbl ); 172 } else 173 if (eTok == EOLN || eTok == REM) 174 aGen.Gen (_JUMP, nStartLbl); 175 else 176 Error( SbERR_EXPECTED, WHILE ); 177 } 178 else 179 { 180 // DO [WHILE|UNTIL expr] ... LOOP 181 if( eTok == UNTIL || eTok == WHILE ) 182 { 183 SbiExpression aCond( this ); 184 aCond.Gen(); 185 } 186 sal_uInt32 nEndLbl = aGen.Gen( eTok == UNTIL ? _JUMPT : _JUMPF, 0 ); 187 StmntBlock( LOOP ); 188 TestEoln(); 189 aGen.Gen( _JUMP, nStartLbl ); 190 aGen.BackChain( nEndLbl ); 191 } 192 CloseBlock(); 193 } 194 195 // WHILE ... WEND 196 197 void SbiParser::While() 198 { 199 SbiExpression aCond( this ); 200 sal_uInt32 nStartLbl = aGen.GetPC(); 201 aCond.Gen(); 202 sal_uInt32 nEndLbl = aGen.Gen( _JUMPF, 0 ); 203 StmntBlock( WEND ); 204 aGen.Gen( _JUMP, nStartLbl ); 205 aGen.BackChain( nEndLbl ); 206 } 207 208 // FOR var = expr TO expr STEP 209 210 void SbiParser::For() 211 { 212 bool bForEach = ( Peek() == EACH ); 213 if( bForEach ) 214 Next(); 215 SbiExpression aLvalue( this, SbOPERAND ); 216 aLvalue.Gen(); // Variable auf dem Stack 217 218 if( bForEach ) 219 { 220 TestToken( _IN_ ); 221 SbiExpression aCollExpr( this, SbOPERAND ); 222 aCollExpr.Gen(); // Colletion var to for stack 223 TestEoln(); 224 aGen.Gen( _INITFOREACH ); 225 } 226 else 227 { 228 TestToken( EQ ); 229 SbiExpression aStartExpr( this ); 230 aStartExpr.Gen(); // Startausdruck auf dem Stack 231 TestToken( TO ); 232 SbiExpression aStopExpr( this ); 233 aStopExpr.Gen(); // Endausdruck auf dem Stack 234 if( Peek() == STEP ) 235 { 236 Next(); 237 SbiExpression aStepExpr( this ); 238 aStepExpr.Gen(); 239 } 240 else 241 { 242 SbiExpression aOne( this, 1, SbxINTEGER ); 243 aOne.Gen(); 244 } 245 TestEoln(); 246 // Der Stack hat jetzt 4 Elemente: Variable, Start, Ende, Inkrement 247 // Startwert binden 248 aGen.Gen( _INITFOR ); 249 } 250 251 sal_uInt32 nLoop = aGen.GetPC(); 252 // Test durchfuehren, evtl. Stack freigeben 253 sal_uInt32 nEndTarget = aGen.Gen( _TESTFOR, 0 ); 254 OpenBlock( FOR ); 255 StmntBlock( NEXT ); 256 aGen.Gen( _NEXT ); 257 aGen.Gen( _JUMP, nLoop ); 258 // Kommen Variable nach NEXT? 259 if( Peek() == SYMBOL ) 260 { 261 SbiExpression aVar( this, SbOPERAND ); 262 if( aVar.GetRealVar() != aLvalue.GetRealVar() ) 263 Error( SbERR_EXPECTED, aLvalue.GetRealVar()->GetName() ); 264 } 265 aGen.BackChain( nEndTarget ); 266 CloseBlock(); 267 } 268 269 // WITH .. END WITH 270 271 void SbiParser::With() 272 { 273 SbiExpression aVar( this, SbOPERAND ); 274 275 // Letzten Knoten in der Objekt-Kette ueberpruefen 276 SbiExprNode *pNode = aVar.GetExprNode()->GetRealNode(); 277 SbiSymDef* pDef = pNode->GetVar(); 278 // Variant, AB 27.6.1997, #41090: bzw. empty -> mu� Object sein 279 if( pDef->GetType() == SbxVARIANT || pDef->GetType() == SbxEMPTY ) 280 pDef->SetType( SbxOBJECT ); 281 else if( pDef->GetType() != SbxOBJECT ) 282 Error( SbERR_NEEDS_OBJECT ); 283 284 // Knoten auch auf SbxOBJECT setzen, damit spaeter Gen() klappt 285 pNode->SetType( SbxOBJECT ); 286 287 OpenBlock( NIL, aVar.GetExprNode() ); 288 StmntBlock( ENDWITH ); 289 CloseBlock(); 290 } 291 292 // LOOP/NEXT/WEND ohne Konstrukt 293 294 void SbiParser::BadBlock() 295 { 296 if( eEndTok ) 297 Error( SbERR_BAD_BLOCK, eEndTok ); 298 else 299 Error( SbERR_BAD_BLOCK, "Loop/Next/Wend" ); 300 } 301 302 // On expr Goto/Gosub n,n,n... 303 304 void SbiParser::OnGoto() 305 { 306 SbiExpression aCond( this ); 307 aCond.Gen(); 308 sal_uInt32 nLabelsTarget = aGen.Gen( _ONJUMP, 0 ); 309 SbiToken eTok = Next(); 310 if( eTok != GOTO && eTok != GOSUB ) 311 { 312 Error( SbERR_EXPECTED, "GoTo/GoSub" ); 313 eTok = GOTO; 314 } 315 // Label-Tabelle einlesen: 316 sal_uInt32 nLbl = 0; 317 do 318 { 319 SbiToken eTok2 = NIL; 320 eTok2 = Next(); // Label holen 321 if( MayBeLabel() ) 322 { 323 sal_uInt32 nOff = pProc->GetLabels().Reference( aSym ); 324 aGen.Gen( _JUMP, nOff ); 325 nLbl++; 326 } 327 else Error( SbERR_LABEL_EXPECTED ); 328 } 329 while( !bAbort && TestComma() ); 330 if( eTok == GOSUB ) 331 nLbl |= 0x8000; 332 aGen.Patch( nLabelsTarget, nLbl ); 333 } 334 335 // GOTO/GOSUB 336 337 void SbiParser::Goto() 338 { 339 SbiOpcode eOp = eCurTok == GOTO ? _JUMP : _GOSUB; 340 Next(); 341 if( MayBeLabel() ) 342 { 343 sal_uInt32 nOff = pProc->GetLabels().Reference( aSym ); 344 aGen.Gen( eOp, nOff ); 345 } 346 else Error( SbERR_LABEL_EXPECTED ); 347 } 348 349 // RETURN [label] 350 351 void SbiParser::Return() 352 { 353 Next(); 354 if( MayBeLabel() ) 355 { 356 sal_uInt32 nOff = pProc->GetLabels().Reference( aSym ); 357 aGen.Gen( _RETURN, nOff ); 358 } 359 else aGen.Gen( _RETURN, 0 ); 360 } 361 362 // SELECT CASE 363 364 void SbiParser::Select() 365 { 366 TestToken( CASE ); 367 SbiExpression aCase( this ); 368 SbiToken eTok = NIL; 369 aCase.Gen(); 370 aGen.Gen( _CASE ); 371 TestEoln(); 372 sal_uInt32 nNextTarget = 0; 373 sal_uInt32 nDoneTarget = 0; 374 sal_Bool bElse = sal_False; 375 // Die Cases einlesen: 376 while( !bAbort ) 377 { 378 eTok = Next(); 379 if( eTok == CASE ) 380 { 381 if( nNextTarget ) 382 aGen.BackChain( nNextTarget ), nNextTarget = 0; 383 aGen.Statement(); 384 // Jeden Case einlesen 385 sal_Bool bDone = sal_False; 386 sal_uInt32 nTrueTarget = 0; 387 if( Peek() == ELSE ) 388 { 389 // CASE ELSE 390 Next(); 391 bElse = sal_True; 392 } 393 else while( !bDone ) 394 { 395 if( bElse ) 396 Error( SbERR_SYNTAX ); 397 SbiToken eTok2 = Peek(); 398 if( eTok2 == IS || ( eTok2 >= EQ && eTok2 <= GE ) ) 399 { // CASE [IS] operator expr 400 if( eTok2 == IS ) 401 Next(); 402 eTok2 = Peek(); 403 if( eTok2 < EQ || eTok2 > GE ) 404 Error( SbERR_SYNTAX ); 405 else Next(); 406 SbiExpression aCompare( this ); 407 aCompare.Gen(); 408 nTrueTarget = aGen.Gen( 409 _CASEIS, nTrueTarget, 410 sal::static_int_cast< sal_uInt16 >( 411 SbxEQ + ( eTok2 - EQ ) ) ); 412 } 413 else 414 { // CASE expr | expr TO expr 415 SbiExpression aCase1( this ); 416 aCase1.Gen(); 417 if( Peek() == TO ) 418 { 419 // CASE a TO b 420 Next(); 421 SbiExpression aCase2( this ); 422 aCase2.Gen(); 423 nTrueTarget = aGen.Gen( _CASETO, nTrueTarget ); 424 } 425 else 426 // CASE a 427 nTrueTarget = aGen.Gen( _CASEIS, nTrueTarget, SbxEQ ); 428 429 } 430 if( Peek() == COMMA ) Next(); 431 else TestEoln(), bDone = sal_True; 432 } 433 // Alle Cases abgearbeitet 434 if( !bElse ) 435 { 436 nNextTarget = aGen.Gen( _JUMP, nNextTarget ); 437 aGen.BackChain( nTrueTarget ); 438 } 439 // den Statement-Rumpf bauen 440 while( !bAbort ) 441 { 442 eTok = Peek(); 443 if( eTok == CASE || eTok == ENDSELECT ) 444 break; 445 if( !Parse() ) goto done; 446 eTok = Peek(); 447 if( eTok == CASE || eTok == ENDSELECT ) 448 break; 449 } 450 if( !bElse ) 451 nDoneTarget = aGen.Gen( _JUMP, nDoneTarget ); 452 } 453 else if( !IsEoln( eTok ) ) 454 break; 455 } 456 done: 457 if( eTok != ENDSELECT ) 458 Error( SbERR_EXPECTED, ENDSELECT ); 459 if( nNextTarget ) 460 aGen.BackChain( nNextTarget ); 461 aGen.BackChain( nDoneTarget ); 462 aGen.Gen( _ENDCASE ); 463 } 464 465 // ON Error/Variable 466 467 #ifdef _MSC_VER 468 #pragma optimize("",off) 469 #endif 470 471 void SbiParser::On() 472 { 473 SbiToken eTok = Peek(); 474 String aString = SbiTokenizer::Symbol(eTok); 475 if (aString.EqualsIgnoreCaseAscii("ERROR")) 476 //if (!aString.ICompare("ERROR")) 477 eTok = _ERROR_; // Error kommt als SYMBOL 478 if( eTok != _ERROR_ && eTok != LOCAL ) OnGoto(); 479 else 480 { 481 if( eTok == LOCAL ) Next(); 482 Next (); // Kein TestToken mehr, da es sonst einen Fehler gibt 483 484 Next(); // Token nach Error holen 485 if( eCurTok == GOTO ) 486 { 487 // ON ERROR GOTO label|0 488 Next(); 489 bool bError_ = false; 490 if( MayBeLabel() ) 491 { 492 if( eCurTok == NUMBER && !nVal ) 493 aGen.Gen( _STDERROR ); 494 else 495 { 496 sal_uInt32 nOff = pProc->GetLabels().Reference( aSym ); 497 aGen.Gen( _ERRHDL, nOff ); 498 } 499 } 500 else if( eCurTok == MINUS ) 501 { 502 Next(); 503 if( eCurTok == NUMBER && nVal == 1 ) 504 aGen.Gen( _STDERROR ); 505 else 506 bError_ = true; 507 } 508 if( bError_ ) 509 Error( SbERR_LABEL_EXPECTED ); 510 } 511 else if( eCurTok == RESUME ) 512 { 513 TestToken( NEXT ); 514 aGen.Gen( _NOERROR ); 515 } 516 else Error( SbERR_EXPECTED, "GoTo/Resume" ); 517 } 518 } 519 520 #ifdef _MSC_VER 521 #pragma optimize("",off) 522 #endif 523 524 // RESUME [0]|NEXT|label 525 526 void SbiParser::Resume() 527 { 528 sal_uInt32 nLbl; 529 530 switch( Next() ) 531 { 532 case EOS: 533 case EOLN: 534 aGen.Gen( _RESUME, 0 ); 535 break; 536 case NEXT: 537 aGen.Gen( _RESUME, 1 ); 538 Next(); 539 break; 540 case NUMBER: 541 if( !nVal ) 542 { 543 aGen.Gen( _RESUME, 0 ); 544 break; 545 } // fall thru 546 case SYMBOL: 547 if( MayBeLabel() ) 548 { 549 nLbl = pProc->GetLabels().Reference( aSym ); 550 aGen.Gen( _RESUME, nLbl ); 551 Next(); 552 break; 553 } // fall thru 554 default: 555 Error( SbERR_LABEL_EXPECTED ); 556 } 557 } 558 559