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