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

Generated by: LCOV version 1.11