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