| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_basic.hxx" |
| |
| #include "sbcomp.hxx" |
| |
| // Single-line IF und Multiline IF |
| |
| void SbiParser::If() |
| { |
| sal_uInt32 nEndLbl; |
| SbiToken eTok = NIL; |
| // 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 |
| sal_uInt32 pnJmpToEndLbl[JMP_TABLE_SIZE]; // 100 ELSEIFs zulaessig |
| sal_uInt16 iJmp = 0; // aktueller Tabellen-Index |
| |
| // multiline IF |
| nEndLbl = aGen.Gen( _JUMPF, 0 ); |
| eTok = Peek(); |
| while( !( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) && |
| !bAbort && Parse() ) |
| { |
| eTok = Peek(); |
| if( IsEof() ) |
| { |
| Error( SbERR_BAD_BLOCK, IF ); bAbort = sal_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 = sal_True; return; |
| } |
| pnJmpToEndLbl[iJmp++] = aGen.Gen( _JUMP, 0 ); |
| |
| Next(); |
| aGen.BackChain( nEndLbl ); |
| |
| aGen.Statement(); |
| SbiExpression* pCond = new SbiExpression( this ); |
| pCond->Gen(); |
| nEndLbl = aGen.Gen( _JUMPF, 0 ); |
| delete pCond; |
| TestToken( THEN ); |
| eTok = Peek(); |
| while( !( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) && |
| !bAbort && Parse() ) |
| { |
| eTok = Peek(); |
| if( IsEof() ) |
| { |
| Error( SbERR_BAD_BLOCK, ELSEIF ); bAbort = sal_True; return; |
| } |
| } |
| } |
| if( eTok == ELSE ) |
| { |
| Next(); |
| sal_uInt32 nElseLbl = nEndLbl; |
| nEndLbl = aGen.Gen( _JUMP, 0 ); |
| aGen.BackChain( nElseLbl ); |
| |
| aGen.Statement(); |
| StmntBlock( ENDIF ); |
| } |
| else if( eTok == ENDIF ) |
| Next(); |
| |
| // #27720# Jmp-Tabelle abarbeiten |
| while( iJmp > 0 ) |
| { |
| iJmp--; |
| aGen.BackChain( pnJmpToEndLbl[iJmp] ); |
| } |
| } |
| else |
| { |
| // single line IF |
| bSingleLineIf = sal_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(); |
| sal_uInt32 nElseLbl = nEndLbl; |
| nEndLbl = aGen.Gen( _JUMP, 0 ); |
| aGen.BackChain( nElseLbl ); |
| while( !bAbort ) |
| { |
| if( !Parse() ) break; |
| eTok = Peek(); |
| if( eTok == EOLN || eTok == REM ) |
| break; |
| } |
| } |
| bSingleLineIf = sal_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() |
| { |
| sal_uInt32 nStartLbl = aGen.GetPC(); |
| 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(); |
| } |
| sal_uInt32 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 ); |
| sal_uInt32 nStartLbl = aGen.GetPC(); |
| aCond.Gen(); |
| sal_uInt32 nEndLbl = aGen.Gen( _JUMPF, 0 ); |
| StmntBlock( WEND ); |
| aGen.Gen( _JUMP, nStartLbl ); |
| aGen.BackChain( nEndLbl ); |
| } |
| |
| // FOR var = expr TO expr STEP |
| |
| void SbiParser::For() |
| { |
| bool bForEach = ( Peek() == EACH ); |
| if( bForEach ) |
| Next(); |
| SbiExpression aLvalue( this, SbOPERAND ); |
| aLvalue.Gen(); // Variable auf dem Stack |
| |
| if( bForEach ) |
| { |
| TestToken( _IN_ ); |
| SbiExpression aCollExpr( this, SbOPERAND ); |
| aCollExpr.Gen(); // Colletion var to for stack |
| TestEoln(); |
| aGen.Gen( _INITFOREACH ); |
| } |
| else |
| { |
| 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 ); |
| } |
| |
| sal_uInt32 nLoop = aGen.GetPC(); |
| // Test durchfuehren, evtl. Stack freigeben |
| sal_uInt32 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, aLvalue.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(); |
| sal_uInt32 nLabelsTarget = aGen.Gen( _ONJUMP, 0 ); |
| SbiToken eTok = Next(); |
| if( eTok != GOTO && eTok != GOSUB ) |
| { |
| Error( SbERR_EXPECTED, "GoTo/GoSub" ); |
| eTok = GOTO; |
| } |
| // Label-Tabelle einlesen: |
| sal_uInt32 nLbl = 0; |
| do |
| { |
| SbiToken eTok2 = NIL; |
| eTok2 = Next(); // Label holen |
| if( MayBeLabel() ) |
| { |
| sal_uInt32 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() ) |
| { |
| sal_uInt32 nOff = pProc->GetLabels().Reference( aSym ); |
| aGen.Gen( eOp, nOff ); |
| } |
| else Error( SbERR_LABEL_EXPECTED ); |
| } |
| |
| // RETURN [label] |
| |
| void SbiParser::Return() |
| { |
| Next(); |
| if( MayBeLabel() ) |
| { |
| sal_uInt32 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 = NIL; |
| aCase.Gen(); |
| aGen.Gen( _CASE ); |
| TestEoln(); |
| sal_uInt32 nNextTarget = 0; |
| sal_uInt32 nDoneTarget = 0; |
| sal_Bool bElse = sal_False; |
| // Die Cases einlesen: |
| while( !bAbort ) |
| { |
| eTok = Next(); |
| if( eTok == CASE ) |
| { |
| if( nNextTarget ) |
| aGen.BackChain( nNextTarget ), nNextTarget = 0; |
| aGen.Statement(); |
| // Jeden Case einlesen |
| sal_Bool bDone = sal_False; |
| sal_uInt32 nTrueTarget = 0; |
| if( Peek() == ELSE ) |
| { |
| // CASE ELSE |
| Next(); |
| bElse = sal_True; |
| } |
| else while( !bDone ) |
| { |
| if( bElse ) |
| Error( SbERR_SYNTAX ); |
| SbiToken eTok2 = Peek(); |
| if( eTok2 == IS || ( eTok2 >= EQ && eTok2 <= GE ) ) |
| { // CASE [IS] operator expr |
| if( eTok2 == IS ) |
| Next(); |
| eTok2 = Peek(); |
| if( eTok2 < EQ || eTok2 > GE ) |
| Error( SbERR_SYNTAX ); |
| else Next(); |
| SbiExpression aCompare( this ); |
| aCompare.Gen(); |
| nTrueTarget = aGen.Gen( |
| _CASEIS, nTrueTarget, |
| sal::static_int_cast< sal_uInt16 >( |
| SbxEQ + ( eTok2 - 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 = sal_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(); |
| bool bError_ = false; |
| if( MayBeLabel() ) |
| { |
| if( eCurTok == NUMBER && !nVal ) |
| aGen.Gen( _STDERROR ); |
| else |
| { |
| sal_uInt32 nOff = pProc->GetLabels().Reference( aSym ); |
| aGen.Gen( _ERRHDL, nOff ); |
| } |
| } |
| else if( eCurTok == MINUS ) |
| { |
| Next(); |
| if( eCurTok == NUMBER && nVal == 1 ) |
| aGen.Gen( _STDERROR ); |
| else |
| bError_ = true; |
| } |
| if( bError_ ) |
| 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() |
| { |
| sal_uInt32 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 ); |
| } |
| } |
| |