diff options
Diffstat (limited to 'basic/source/comp/loops.cxx')
-rw-r--r-- | basic/source/comp/loops.cxx | 561 |
1 files changed, 561 insertions, 0 deletions
diff --git a/basic/source/comp/loops.cxx b/basic/source/comp/loops.cxx new file mode 100644 index 000000000000..64c4001ee14a --- /dev/null +++ b/basic/source/comp/loops.cxx @@ -0,0 +1,561 @@ +/************************************************************************* + * + * $RCSfile: loops.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:12:10 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include "sbcomp.hxx" +#pragma hdrstop + +#include "segmentc.hxx" +#pragma SW_SEGMENT_CLASS( SBCOMP, SBCOMP_CODE ) + +// Single-line IF und Multiline IF + +void SbiParser::If() +{ + USHORT nEndLbl; + SbiToken eTok; + // Ende-Tokens ignorieren: + SbiExpression aCond( this ); + aCond.Gen(); + TestToken( THEN ); + if( IsEoln( Next() ) ) + { + // AB 13.5.1996: #27720# Am Ende jeden Blocks muss ein Jump zu ENDIF + // eingefuegt werden, damit bei ELSEIF nicht erneut die Bedingung + // ausgewertet wird. Die Tabelle nimmt alle Absprungstellen auf. +#define JMP_TABLE_SIZE 100 + USHORT pnJmpToEndLbl[JMP_TABLE_SIZE]; // 100 ELSEIFs zulaessig + USHORT iJmp = 0; // aktueller Tabellen-Index + + // multiline IF + nEndLbl = aGen.Gen( _JUMPF, 0 ); + while( !bAbort && Parse() ) + { + eTok = Peek(); + if( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) + break; + if( IsEof() ) + { + Error( SbERR_BAD_BLOCK, IF ); bAbort = TRUE; return; + } + } + // ELSEIF? + while( eTok == ELSEIF ) + { + // #27720# Bei erfolgreichem IF/ELSEIF auf ENDIF springen + if( iJmp >= JMP_TABLE_SIZE ) + { + Error( SbERR_PROG_TOO_LARGE ); bAbort = TRUE; return; + } + pnJmpToEndLbl[iJmp++] = aGen.Gen( _JUMP, 0 ); + + Next(); + aGen.BackChain( nEndLbl ); + SbiExpression* pCond = new SbiExpression( this ); + pCond->Gen(); + nEndLbl = aGen.Gen( _JUMPF, 0 ); + delete pCond; + TestToken( THEN ); + while( !bAbort && Parse() ) + { + eTok = Peek(); + if( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) + break; + if( IsEof() ) + { + Error( SbERR_BAD_BLOCK, ELSEIF ); bAbort = TRUE; return; + } + } + } + if( eTok == ELSE ) + { + Next(); + USHORT nElseLbl = nEndLbl; + nEndLbl = aGen.Gen( _JUMP, 0 ); + aGen.BackChain( nElseLbl ); + StmntBlock( ENDIF ); + } + else if( eTok == ENDIF ) + Next(); + + // #27720# Jmp-Tabelle abarbeiten + while( iJmp > 0 ) + { + iJmp--; + aGen.BackChain( pnJmpToEndLbl[iJmp] ); + } + } + else + { + // single line IF + bSingleLineIf = TRUE; + nEndLbl = aGen.Gen( _JUMPF, 0 ); + Push( eCurTok ); + while( !bAbort ) + { + if( !Parse() ) break; + eTok = Peek(); + if( eTok == ELSE || eTok == EOLN || eTok == REM ) + break; + } + if( eTok == ELSE ) + { + Next(); + USHORT nElseLbl = nEndLbl; + nEndLbl = aGen.Gen( _JUMP, 0 ); + aGen.BackChain( nElseLbl ); + while( !bAbort ) + { + if( !Parse() ) break; + eTok = Peek(); + if( eTok == EOLN ) + break; + } + } + bSingleLineIf = FALSE; + } + aGen.BackChain( nEndLbl ); +} + +// ELSE/ELSEIF/ENDIF ohne IF + +void SbiParser::NoIf() +{ + Error( SbERR_NO_IF ); + StmntBlock( ENDIF ); +} + +// DO WHILE...LOOP +// DO ... LOOP WHILE + +void SbiParser::DoLoop() +{ + USHORT nStartLbl = aGen.GetPC(); + USHORT nEndChain = 0; + OpenBlock( DO ); + SbiToken eTok = Next(); + if( IsEoln( eTok ) ) + { + // DO ... LOOP [WHILE|UNTIL expr] + StmntBlock( LOOP ); + eTok = Next(); + if( eTok == UNTIL || eTok == WHILE ) + { + SbiExpression aExpr( this ); + aExpr.Gen(); + aGen.Gen( eTok == UNTIL ? _JUMPF : _JUMPT, nStartLbl ); + } else + if (eTok == EOLN || eTok == REM) + aGen.Gen (_JUMP, nStartLbl); + else + Error( SbERR_EXPECTED, WHILE ); + } + else + { + // DO [WHILE|UNTIL expr] ... LOOP + if( eTok == UNTIL || eTok == WHILE ) + { + SbiExpression aCond( this ); + aCond.Gen(); + } + USHORT nEndLbl = aGen.Gen( eTok == UNTIL ? _JUMPT : _JUMPF, 0 ); + StmntBlock( LOOP ); + TestEoln(); + aGen.Gen( _JUMP, nStartLbl ); + aGen.BackChain( nEndLbl ); + } + CloseBlock(); +} + +// WHILE ... WEND + +void SbiParser::While() +{ + SbiExpression aCond( this ); + USHORT nStartLbl = aGen.GetPC(); + aCond.Gen(); + USHORT nEndLbl = aGen.Gen( _JUMPF, 0 ); + StmntBlock( WEND ); + aGen.Gen( _JUMP, nStartLbl ); + aGen.BackChain( nEndLbl ); +} + +// FOR var = expr TO expr STEP + +void SbiParser::For() +{ + SbiExpression aLvalue( this, SbOPERAND ); + aLvalue.Gen(); // Variable auf dem Stack + TestToken( EQ ); + SbiExpression aStartExpr( this ); + aStartExpr.Gen(); // Startausdruck auf dem Stack + TestToken( TO ); + SbiExpression aStopExpr( this ); + aStopExpr.Gen(); // Endausdruck auf dem Stack + if( Peek() == STEP ) + { + Next(); + SbiExpression aStepExpr( this ); + aStepExpr.Gen(); + } + else + { + SbiExpression aOne( this, 1, SbxINTEGER ); + aOne.Gen(); + } + TestEoln(); + // Der Stack hat jetzt 4 Elemente: Variable, Start, Ende, Inkrement + // Startwert binden + aGen.Gen( _INITFOR ); + USHORT nLoop = aGen.GetPC(); + // Test durchfuehren, evtl. Stack freigeben + USHORT nEndTarget = aGen.Gen( _TESTFOR, 0 ); + OpenBlock( FOR ); + StmntBlock( NEXT ); + aGen.Gen( _NEXT ); + aGen.Gen( _JUMP, nLoop ); + // Kommen Variable nach NEXT? + if( Peek() == SYMBOL ) + { + SbiExpression aVar( this, SbOPERAND ); + if( aVar.GetRealVar() != aLvalue.GetRealVar() ) + Error( SbERR_EXPECTED, aVar.GetRealVar()->GetName() ); + } + aGen.BackChain( nEndTarget ); + CloseBlock(); +} + +// WITH .. END WITH + +void SbiParser::With() +{ + SbiExpression aVar( this, SbOPERAND ); + + // Letzten Knoten in der Objekt-Kette ueberpruefen + SbiExprNode *pNode = aVar.GetExprNode()->GetRealNode(); + SbiSymDef* pDef = pNode->GetVar(); + // Variant, AB 27.6.1997, #41090: bzw. empty -> mu Object sein + if( pDef->GetType() == SbxVARIANT || pDef->GetType() == SbxEMPTY ) + pDef->SetType( SbxOBJECT ); + else if( pDef->GetType() != SbxOBJECT ) + Error( SbERR_NEEDS_OBJECT ); + + // Knoten auch auf SbxOBJECT setzen, damit spaeter Gen() klappt + pNode->SetType( SbxOBJECT ); + + OpenBlock( NIL, aVar.GetExprNode() ); + StmntBlock( ENDWITH ); + CloseBlock(); +} + +// LOOP/NEXT/WEND ohne Konstrukt + +void SbiParser::BadBlock() +{ + if( eEndTok ) + Error( SbERR_BAD_BLOCK, eEndTok ); + else + Error( SbERR_BAD_BLOCK, "Loop/Next/Wend" ); +} + +// On expr Goto/Gosub n,n,n... + +void SbiParser::OnGoto() +{ + SbiExpression aCond( this ); + aCond.Gen(); + USHORT nLabelsTarget = aGen.Gen( _ONJUMP, 0 ); + SbiToken eTok = Next(); + if( eTok != GOTO && eTok != GOSUB ) + { + Error( SbERR_EXPECTED, "GoTo/GoSub" ); + eTok = GOTO; + } + // Label-Tabelle einlesen: + short nLbl = 0; + do + { + SbiToken eTok2 = Next(); // Label holen + if( MayBeLabel() ) + { + USHORT nOff = pProc->GetLabels().Reference( aSym ); + aGen.Gen( _JUMP, nOff ); + nLbl++; + } + else Error( SbERR_LABEL_EXPECTED ); + } + while( !bAbort && TestComma() ); + if( eTok == GOSUB ) + nLbl |= 0x8000; + aGen.Patch( nLabelsTarget, nLbl ); +} + +// GOTO/GOSUB + +void SbiParser::Goto() +{ + SbiOpcode eOp = eCurTok == GOTO ? _JUMP : _GOSUB; + Next(); + if( MayBeLabel() ) + { + USHORT nOff = pProc->GetLabels().Reference( aSym ); + aGen.Gen( eOp, nOff ); + } + else Error( SbERR_LABEL_EXPECTED ); +} + +// RETURN [label] + +void SbiParser::Return() +{ + Next(); + if( MayBeLabel() ) + { + USHORT nOff = pProc->GetLabels().Reference( aSym ); + aGen.Gen( _RETURN, nOff ); + } + else aGen.Gen( _RETURN, 0 ); +} + +// SELECT CASE + +void SbiParser::Select() +{ + TestToken( CASE ); + SbiExpression aCase( this ); + SbiToken eTok; + aCase.Gen(); + aGen.Gen( _CASE ); + TestEoln(); + USHORT nNextTarget = 0; + USHORT nDoneTarget = 0; + BOOL bElse = FALSE; + // Die Cases einlesen: + while( !bAbort ) + { + eTok = Next(); + if( eTok == CASE ) + { + if( nNextTarget ) + aGen.BackChain( nNextTarget ), nNextTarget = 0; + aGen.Statement(); + // Jeden Case einlesen + BOOL bDone = FALSE; + USHORT nTrueTarget = 0; + if( Peek() == ELSE ) + { + // CASE ELSE + Next(); + bElse = TRUE; + } + else while( !bDone ) + { + if( bElse ) + Error( SbERR_SYNTAX ); + SbiToken eTok = Peek(); + if( eTok == IS || ( eTok >= EQ && eTok <= GE ) ) + { // CASE [IS] operator expr + if( eTok == IS ) + Next(); + eTok = Peek(); + if( eTok < EQ || eTok > GE ) + Error( SbERR_SYNTAX ); + else Next(); + SbiExpression aCompare( this ); + aCompare.Gen(); + nTrueTarget = aGen.Gen( _CASEIS, nTrueTarget, + SbxEQ + ( eTok - EQ ) ); + } + else + { // CASE expr | expr TO expr + SbiExpression aCase1( this ); + aCase1.Gen(); + if( Peek() == TO ) + { + // CASE a TO b + Next(); + SbiExpression aCase2( this ); + aCase2.Gen(); + nTrueTarget = aGen.Gen( _CASETO, nTrueTarget ); + } + else + // CASE a + nTrueTarget = aGen.Gen( _CASEIS, nTrueTarget, SbxEQ ); + + } + if( Peek() == COMMA ) Next(); + else TestEoln(), bDone = TRUE; + } + // Alle Cases abgearbeitet + if( !bElse ) + { + nNextTarget = aGen.Gen( _JUMP, nNextTarget ); + aGen.BackChain( nTrueTarget ); + } + // den Statement-Rumpf bauen + while( !bAbort ) + { + eTok = Peek(); + if( eTok == CASE || eTok == ENDSELECT ) + break; + if( !Parse() ) goto done; + eTok = Peek(); + if( eTok == CASE || eTok == ENDSELECT ) + break; + } + if( !bElse ) + nDoneTarget = aGen.Gen( _JUMP, nDoneTarget ); + } + else if( !IsEoln( eTok ) ) + break; + } +done: + if( eTok != ENDSELECT ) + Error( SbERR_EXPECTED, ENDSELECT ); + if( nNextTarget ) + aGen.BackChain( nNextTarget ); + aGen.BackChain( nDoneTarget ); + aGen.Gen( _ENDCASE ); +} + +// ON Error/Variable + +#ifdef _MSC_VER +#pragma optimize("",off) +#endif + +void SbiParser::On() +{ + SbiToken eTok = Peek(); + String aString = SbiTokenizer::Symbol(eTok); + if (aString.EqualsIgnoreCaseAscii("ERROR")) + //if (!aString.ICompare("ERROR")) + eTok = _ERROR_; // Error kommt als SYMBOL + if( eTok != _ERROR_ && eTok != LOCAL ) OnGoto(); + else + { + if( eTok == LOCAL ) Next(); + Next (); // Kein TestToken mehr, da es sonst einen Fehler gibt + + Next(); // Token nach Error holen + if( eCurTok == GOTO ) + { + // ON ERROR GOTO label|0 + Next(); + if( MayBeLabel() ) + { + if( eCurTok == NUMBER && !nVal ) + aGen.Gen( _STDERROR ); + else + { + USHORT nOff = pProc->GetLabels().Reference( aSym ); + aGen.Gen( _ERRHDL, nOff ); + } + } + else Error( SbERR_LABEL_EXPECTED ); + } + else if( eCurTok == RESUME ) + { + TestToken( NEXT ); + aGen.Gen( _NOERROR ); + } + else Error( SbERR_EXPECTED, "GoTo/Resume" ); + } +} + +#ifdef _MSC_VER +#pragma optimize("",off) +#endif + +// RESUME [0]|NEXT|label + +void SbiParser::Resume() +{ + USHORT nLbl; + + switch( Next() ) + { + case EOS: + case EOLN: + aGen.Gen( _RESUME, 0 ); + break; + case NEXT: + aGen.Gen( _RESUME, 1 ); + Next(); + break; + case NUMBER: + if( !nVal ) + { + aGen.Gen( _RESUME, 0 ); + break; + } // fall thru + case SYMBOL: + if( MayBeLabel() ) + { + nLbl = pProc->GetLabels().Reference( aSym ); + aGen.Gen( _RESUME, nLbl ); + Next(); + break; + } // fall thru + default: + Error( SbERR_LABEL_EXPECTED ); + } +} + |