LCOV - code coverage report
Current view: top level - libreoffice/basic/source/comp - loops.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 23 310 7.4 %
Date: 2012-12-27 Functions: 1 13 7.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10