| /************************************************************** |
| * |
| * 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 <basic/sbx.hxx> |
| #include "sbcomp.hxx" |
| #include <com/sun/star/script/ModuleType.hpp> |
| |
| struct SbiParseStack { // "Stack" fuer Statement-Blocks |
| SbiParseStack* pNext; // Chain |
| SbiExprNode* pWithVar; // Variable fuer WITH |
| SbiToken eExitTok; // Exit-Token |
| sal_uInt32 nChain; // JUMP-Chain |
| }; |
| |
| struct SbiStatement { |
| SbiToken eTok; |
| void( SbiParser::*Func )(); // Verarbeitungsroutine |
| sal_Bool bMain; // sal_True: ausserhalb SUBs OK |
| sal_Bool bSubr; // sal_True: in SUBs OK |
| }; |
| |
| #define Y sal_True |
| #define N sal_False |
| |
| static SbiStatement StmntTable [] = { |
| { CALL, &SbiParser::Call, N, Y, }, // CALL |
| { CLOSE, &SbiParser::Close, N, Y, }, // CLOSE |
| { _CONST_, &SbiParser::Dim, Y, Y, }, // CONST |
| { DECLARE, &SbiParser::Declare, Y, N, }, // DECLARE |
| { DEFBOOL, &SbiParser::DefXXX, Y, N, }, // DEFBOOL |
| { DEFCUR, &SbiParser::DefXXX, Y, N, }, // DEFCUR |
| { DEFDATE, &SbiParser::DefXXX, Y, N, }, // DEFDATE |
| { DEFDBL, &SbiParser::DefXXX, Y, N, }, // DEFDBL |
| { DEFERR, &SbiParser::DefXXX, Y, N, }, // DEFERR |
| { DEFINT, &SbiParser::DefXXX, Y, N, }, // DEFINT |
| { DEFLNG, &SbiParser::DefXXX, Y, N, }, // DEFLNG |
| { DEFOBJ, &SbiParser::DefXXX, Y, N, }, // DEFOBJ |
| { DEFSNG, &SbiParser::DefXXX, Y, N, }, // DEFSNG |
| { DEFSTR, &SbiParser::DefXXX, Y, N, }, // DEFSTR |
| { DEFVAR, &SbiParser::DefXXX, Y, N, }, // DEFVAR |
| { DIM, &SbiParser::Dim, Y, Y, }, // DIM |
| { DO, &SbiParser::DoLoop, N, Y, }, // DO |
| { ELSE, &SbiParser::NoIf, N, Y, }, // ELSE |
| { ELSEIF, &SbiParser::NoIf, N, Y, }, // ELSEIF |
| { ENDIF, &SbiParser::NoIf, N, Y, }, // ENDIF |
| { END, &SbiParser::Stop, N, Y, }, // END |
| { ENUM, &SbiParser::Enum, Y, N, }, // TYPE |
| { ERASE, &SbiParser::Erase, N, Y, }, // ERASE |
| { _ERROR_, &SbiParser::ErrorStmnt, N, Y, }, // ERROR |
| { EXIT, &SbiParser::Exit, N, Y, }, // EXIT |
| { FOR, &SbiParser::For, N, Y, }, // FOR |
| { FUNCTION, &SbiParser::SubFunc, Y, N, }, // FUNCTION |
| { GOSUB, &SbiParser::Goto, N, Y, }, // GOSUB |
| { GLOBAL, &SbiParser::Dim, Y, N, }, // GLOBAL |
| { GOTO, &SbiParser::Goto, N, Y, }, // GOTO |
| { IF, &SbiParser::If, N, Y, }, // IF |
| { IMPLEMENTS, &SbiParser::Implements, Y, N, }, // IMPLEMENTS |
| { INPUT, &SbiParser::Input, N, Y, }, // INPUT |
| { LET, &SbiParser::Assign, N, Y, }, // LET |
| { LINE, &SbiParser::Line, N, Y, }, // LINE, -> LINE INPUT (#i92642) |
| { LINEINPUT,&SbiParser::LineInput, N, Y, }, // LINE INPUT |
| { LOOP, &SbiParser::BadBlock, N, Y, }, // LOOP |
| { LSET, &SbiParser::LSet, N, Y, }, // LSET |
| { NAME, &SbiParser::Name, N, Y, }, // NAME |
| { NEXT, &SbiParser::BadBlock, N, Y, }, // NEXT |
| { ON, &SbiParser::On, N, Y, }, // ON |
| { OPEN, &SbiParser::Open, N, Y, }, // OPEN |
| { OPTION, &SbiParser::Option, Y, N, }, // OPTION |
| { PRINT, &SbiParser::Print, N, Y, }, // PRINT |
| { PRIVATE, &SbiParser::Dim, Y, N, }, // PRIVATE |
| { PROPERTY, &SbiParser::SubFunc, Y, N, }, // FUNCTION |
| { PUBLIC, &SbiParser::Dim, Y, N, }, // PUBLIC |
| { REDIM, &SbiParser::ReDim, N, Y, }, // DIM |
| { RESUME, &SbiParser::Resume, N, Y, }, // RESUME |
| { RETURN, &SbiParser::Return, N, Y, }, // RETURN |
| { RSET, &SbiParser::RSet, N, Y, }, // RSET |
| { SELECT, &SbiParser::Select, N, Y, }, // SELECT |
| { SET, &SbiParser::Set, N, Y, }, // SET |
| { STATIC, &SbiParser::Static, Y, Y, }, // STATIC |
| { STOP, &SbiParser::Stop, N, Y, }, // STOP |
| { SUB, &SbiParser::SubFunc, Y, N, }, // SUB |
| { TYPE, &SbiParser::Type, Y, N, }, // TYPE |
| { UNTIL, &SbiParser::BadBlock, N, Y, }, // UNTIL |
| { WHILE, &SbiParser::While, N, Y, }, // WHILE |
| { WEND, &SbiParser::BadBlock, N, Y, }, // WEND |
| { WITH, &SbiParser::With, N, Y, }, // WITH |
| { WRITE, &SbiParser::Write, N, Y, }, // WRITE |
| |
| { NIL, NULL, N, N } |
| }; |
| |
| |
| #ifdef _MSC_VER |
| // 'this' : used in base member initializer list |
| #pragma warning( disable: 4355 ) |
| #endif |
| |
| SbiParser::SbiParser( StarBASIC* pb, SbModule* pm ) |
| : SbiTokenizer( pm->GetSource32(), pb ), |
| aGblStrings( this ), |
| aLclStrings( this ), |
| aGlobals( aGblStrings, SbGLOBAL ), |
| aPublics( aGblStrings, SbPUBLIC ), |
| aRtlSyms( aGblStrings, SbRTL ), |
| aGen( *pm, this, 1024 ) |
| { |
| pBasic = pb; |
| eCurExpr = SbSYMBOL; |
| eEndTok = NIL; |
| pProc = NULL; |
| pStack = NULL; |
| pWithVar = NULL; |
| nBase = 0; |
| bText = |
| bGblDefs = |
| bNewGblDefs = |
| bSingleLineIf = |
| bExplicit = sal_False; |
| bClassModule = ( pm->GetModuleType() == com::sun::star::script::ModuleType::CLASS ); |
| OSL_TRACE("Parser - %s, bClassModule %d", rtl::OUStringToOString( pm->GetName(), RTL_TEXTENCODING_UTF8 ).getStr(), bClassModule ); |
| pPool = &aPublics; |
| for( short i = 0; i < 26; i++ ) |
| eDefTypes[ i ] = SbxVARIANT; // Kein expliziter Defaulttyp |
| |
| aPublics.SetParent( &aGlobals ); |
| aGlobals.SetParent( &aRtlSyms ); |
| |
| // Die globale Chainkette faengt bei Adresse 0 an: |
| nGblChain = aGen.Gen( _JUMP, 0 ); |
| |
| rTypeArray = new SbxArray; // Array fuer Benutzerdefinierte Typen |
| rEnumArray = new SbxArray; // Array for Enum types |
| bVBASupportOn = pm->IsVBACompat(); |
| if ( bVBASupportOn ) |
| EnableCompatibility(); |
| |
| } |
| |
| |
| // Ist Teil der Runtime-Library? |
| SbiSymDef* SbiParser::CheckRTLForSym( const String& rSym, SbxDataType eType ) |
| { |
| SbxVariable* pVar = GetBasic()->GetRtl()->Find( rSym, SbxCLASS_DONTCARE ); |
| SbiSymDef* pDef = NULL; |
| if( pVar ) |
| { |
| if( pVar->IsA( TYPE(SbxMethod) ) ) |
| { |
| SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym ); |
| pProc_->SetType( pVar->GetType() ); |
| pDef = pProc_; |
| } |
| else |
| { |
| pDef = aRtlSyms.AddSym( rSym ); |
| pDef->SetType( eType ); |
| } |
| } |
| return pDef; |
| } |
| |
| // Globale Chainkette schliessen |
| |
| sal_Bool SbiParser::HasGlobalCode() |
| { |
| if( bGblDefs && nGblChain ) |
| { |
| aGen.BackChain( nGblChain ); |
| aGen.Gen( _LEAVE ); |
| // aGen.Gen( _STOP ); |
| nGblChain = 0; |
| } |
| return bGblDefs; |
| } |
| |
| void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar ) |
| { |
| SbiParseStack* p = new SbiParseStack; |
| p->eExitTok = eTok; |
| p->nChain = 0; |
| p->pWithVar = pWithVar; |
| p->pNext = pStack; |
| pStack = p; |
| pWithVar = pVar; |
| |
| // #29955 for-Schleifen-Ebene pflegen |
| if( eTok == FOR ) |
| aGen.IncForLevel(); |
| } |
| |
| void SbiParser::CloseBlock() |
| { |
| if( pStack ) |
| { |
| SbiParseStack* p = pStack; |
| |
| // #29955 for-Schleifen-Ebene pflegen |
| if( p->eExitTok == FOR ) |
| aGen.DecForLevel(); |
| |
| aGen.BackChain( p->nChain ); |
| pStack = p->pNext; |
| pWithVar = p->pWithVar; |
| delete p; |
| } |
| } |
| |
| // EXIT ... |
| |
| void SbiParser::Exit() |
| { |
| SbiToken eTok = Next(); |
| for( SbiParseStack* p = pStack; p; p = p->pNext ) |
| { |
| SbiToken eExitTok = p->eExitTok; |
| if( eTok == eExitTok || |
| (eTok == PROPERTY && (eExitTok == GET || eExitTok == LET) ) ) // #i109051 |
| { |
| p->nChain = aGen.Gen( _JUMP, p->nChain ); |
| return; |
| } |
| } |
| if( pStack ) |
| Error( SbERR_EXPECTED, pStack->eExitTok ); |
| else |
| Error( SbERR_BAD_EXIT ); |
| } |
| |
| sal_Bool SbiParser::TestSymbol( sal_Bool bKwdOk ) |
| { |
| Peek(); |
| if( eCurTok == SYMBOL || ( bKwdOk && IsKwd( eCurTok ) ) ) |
| { |
| Next(); return sal_True; |
| } |
| Error( SbERR_SYMBOL_EXPECTED ); |
| return sal_False; |
| } |
| |
| // Testen auf ein bestimmtes Token |
| |
| sal_Bool SbiParser::TestToken( SbiToken t ) |
| { |
| if( Peek() == t ) |
| { |
| Next(); return sal_True; |
| } |
| else |
| { |
| Error( SbERR_EXPECTED, t ); |
| return sal_False; |
| } |
| } |
| |
| // Testen auf Komma oder EOLN |
| |
| sal_Bool SbiParser::TestComma() |
| { |
| SbiToken eTok = Peek(); |
| if( IsEoln( eTok ) ) |
| { |
| Next(); |
| return sal_False; |
| } |
| else if( eTok != COMMA ) |
| { |
| Error( SbERR_EXPECTED, COMMA ); |
| return sal_False; |
| } |
| Next(); |
| return sal_True; |
| } |
| |
| // Testen, ob EOLN vorliegt |
| |
| void SbiParser::TestEoln() |
| { |
| if( !IsEoln( Next() ) ) |
| { |
| Error( SbERR_EXPECTED, EOLN ); |
| while( !IsEoln( Next() ) ) {} |
| } |
| } |
| |
| // Parsing eines Statement-Blocks |
| // Das Parsing laeuft bis zum Ende-Token. |
| |
| void SbiParser::StmntBlock( SbiToken eEnd ) |
| { |
| SbiToken xe = eEndTok; |
| eEndTok = eEnd; |
| while( !bAbort && Parse() ) {} |
| eEndTok = xe; |
| if( IsEof() ) |
| { |
| Error( SbERR_BAD_BLOCK, eEnd ); |
| bAbort = sal_True; |
| } |
| } |
| |
| // Die Hauptroutine. Durch wiederholten Aufrufs dieser Routine wird |
| // die Quelle geparst. Returnwert sal_False bei Ende/Fehlern. |
| |
| sal_Bool SbiParser::Parse() |
| { |
| if( bAbort ) return sal_False; |
| |
| EnableErrors(); |
| |
| bErrorIsSymbol = false; |
| Peek(); |
| bErrorIsSymbol = true; |
| // Dateiende? |
| if( IsEof() ) |
| { |
| // AB #33133: Falls keine Sub angelegt wurde, muss hier |
| // der globale Chain abgeschlossen werden! |
| // AB #40689: Durch die neue static-Behandlung kann noch |
| // ein nGblChain vorhanden sein, daher vorher abfragen |
| if( bNewGblDefs && nGblChain == 0 ) |
| nGblChain = aGen.Gen( _JUMP, 0 ); |
| return sal_False; |
| } |
| |
| // Leerstatement? |
| if( IsEoln( eCurTok ) ) |
| { |
| Next(); return sal_True; |
| } |
| |
| if( !bSingleLineIf && MayBeLabel( sal_True ) ) |
| { |
| // Ist ein Label |
| if( !pProc ) |
| Error( SbERR_NOT_IN_MAIN, aSym ); |
| else |
| pProc->GetLabels().Define( aSym ); |
| Next(); Peek(); |
| // Leerstatement? |
| if( IsEoln( eCurTok ) ) |
| { |
| Next(); return sal_True; |
| } |
| } |
| |
| // Ende des Parsings? |
| if( eCurTok == eEndTok || |
| ( bVBASupportOn && // #i109075 |
| (eCurTok == ENDFUNC || eCurTok == ENDPROPERTY || eCurTok == ENDSUB) && |
| (eEndTok == ENDFUNC || eEndTok == ENDPROPERTY || eEndTok == ENDSUB) ) ) |
| { |
| Next(); |
| if( eCurTok != NIL ) |
| aGen.Statement(); |
| return sal_False; |
| } |
| |
| // Kommentar? |
| if( eCurTok == REM ) |
| { |
| Next(); return sal_True; |
| } |
| |
| // Kommt ein Symbol, ist es entweder eine Variable( LET ) |
| // oder eine SUB-Prozedur( CALL ohne Klammern ) |
| // DOT fuer Zuweisungen im WITH-Block: .A=5 |
| if( eCurTok == SYMBOL || eCurTok == DOT ) |
| { |
| if( !pProc ) |
| Error( SbERR_EXPECTED, SUB ); |
| else |
| { |
| // Damit Zeile & Spalte stimmen... |
| Next(); |
| Push( eCurTok ); |
| aGen.Statement(); |
| Symbol(); |
| } |
| } |
| else |
| { |
| Next(); |
| |
| // Hier folgen nun die Statement-Parser. |
| |
| SbiStatement* p; |
| for( p = StmntTable; p->eTok != NIL; p++ ) |
| if( p->eTok == eCurTok ) |
| break; |
| if( p->eTok != NIL ) |
| { |
| if( !pProc && !p->bMain ) |
| Error( SbERR_NOT_IN_MAIN, eCurTok ); |
| else if( pProc && !p->bSubr ) |
| Error( SbERR_NOT_IN_SUBR, eCurTok ); |
| else |
| { |
| // globalen Chain pflegen |
| // AB #41606/#40689: Durch die neue static-Behandlung kann noch |
| // ein nGblChain vorhanden sein, daher vorher abfragen |
| if( bNewGblDefs && nGblChain == 0 && |
| ( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) ) |
| { |
| nGblChain = aGen.Gen( _JUMP, 0 ); |
| bNewGblDefs = sal_False; |
| } |
| // Statement-Opcode bitte auch am Anfang einer Sub |
| if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) || |
| eCurTok == SUB || eCurTok == FUNCTION ) |
| aGen.Statement(); |
| (this->*( p->Func ) )(); |
| SbxError nSbxErr = SbxBase::GetError(); |
| if( nSbxErr ) |
| SbxBase::ResetError(), Error( (SbError)nSbxErr ); |
| } |
| } |
| else |
| Error( SbERR_UNEXPECTED, eCurTok ); |
| } |
| |
| // Test auf Ende des Statements: |
| // Kann auch ein ELSE sein, da vor dem ELSE kein : stehen muss! |
| |
| if( !IsEos() ) |
| { |
| Peek(); |
| if( !IsEos() && eCurTok != ELSE ) |
| { |
| // falls das Parsing abgebrochen wurde, bis zum ":" vorgehen: |
| Error( SbERR_UNEXPECTED, eCurTok ); |
| while( !IsEos() ) Next(); |
| } |
| } |
| // Der Parser bricht am Ende ab, das naechste Token ist noch nicht |
| // geholt! |
| return sal_True; |
| } |
| |
| // Innerste With-Variable liefern |
| SbiExprNode* SbiParser::GetWithVar() |
| { |
| if( pWithVar ) |
| return pWithVar; |
| |
| // Sonst im Stack suchen |
| SbiParseStack* p = pStack; |
| while( p ) |
| { |
| // LoopVar kann zur Zeit nur fuer with sein |
| if( p->pWithVar ) |
| return p->pWithVar; |
| p = p->pNext; |
| } |
| return NULL; |
| } |
| |
| |
| // Zuweisung oder Subroutine Call |
| |
| void SbiParser::Symbol( const KeywordSymbolInfo* pKeywordSymbolInfo ) |
| { |
| SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD; |
| SbiExpression aVar( this, SbSYMBOL, eMode, pKeywordSymbolInfo ); |
| |
| bool bEQ = ( Peek() == EQ ); |
| if( !bEQ && bVBASupportOn && aVar.IsBracket() ) |
| Error( SbERR_EXPECTED, "=" ); |
| |
| RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL ); |
| bool bSpecialMidHandling = false; |
| SbiSymDef* pDef = aVar.GetRealVar(); |
| if( bEQ && pDef && pDef->GetScope() == SbRTL ) |
| { |
| String aRtlName = pDef->GetName(); |
| if( aRtlName.EqualsIgnoreCaseAscii("Mid") ) |
| { |
| SbiExprNode* pExprNode = aVar.GetExprNode(); |
| // SbiNodeType eNodeType; |
| if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL ) |
| { |
| SbiExprList* pPar = pExprNode->GetParameters(); |
| short nParCount = pPar ? pPar->GetSize() : 0; |
| if( nParCount == 2 || nParCount == 3 ) |
| { |
| if( nParCount == 2 ) |
| pPar->addExpression( new SbiExpression( this, -1, SbxLONG ) ); |
| |
| TestToken( EQ ); |
| pPar->addExpression( new SbiExpression( this ) ); |
| |
| bSpecialMidHandling = true; |
| } |
| } |
| } |
| } |
| aVar.Gen( eRecMode ); |
| if( !bSpecialMidHandling ) |
| { |
| if( !bEQ ) |
| { |
| aGen.Gen( _GET ); |
| } |
| else |
| { |
| // Dann muss es eine Zuweisung sein. Was anderes gibts nicht! |
| if( !aVar.IsLvalue() ) |
| Error( SbERR_LVALUE_EXPECTED ); |
| TestToken( EQ ); |
| SbiExpression aExpr( this ); |
| aExpr.Gen(); |
| SbiOpcode eOp = _PUT; |
| // SbiSymDef* pDef = aVar.GetRealVar(); |
| if( pDef ) |
| { |
| if( pDef->GetConstDef() ) |
| Error( SbERR_DUPLICATE_DEF, pDef->GetName() ); |
| if( pDef->GetType() == SbxOBJECT ) |
| { |
| eOp = _SET; |
| if( pDef->GetTypeId() ) |
| { |
| aGen.Gen( _SETCLASS, pDef->GetTypeId() ); |
| return; |
| } |
| } |
| } |
| aGen.Gen( eOp ); |
| } |
| } |
| } |
| |
| // Zuweisungen |
| |
| void SbiParser::Assign() |
| { |
| SbiExpression aLvalue( this, SbLVALUE ); |
| TestToken( EQ ); |
| SbiExpression aExpr( this ); |
| aLvalue.Gen(); |
| aExpr.Gen(); |
| sal_uInt16 nLen = 0; |
| SbiSymDef* pDef = aLvalue.GetRealVar(); |
| { |
| if( pDef->GetConstDef() ) |
| Error( SbERR_DUPLICATE_DEF, pDef->GetName() ); |
| nLen = aLvalue.GetRealVar()->GetLen(); |
| } |
| if( nLen ) |
| aGen.Gen( _PAD, nLen ); |
| aGen.Gen( _PUT ); |
| } |
| |
| // Zuweisungen einer Objektvariablen |
| |
| void SbiParser::Set() |
| { |
| SbiExpression aLvalue( this, SbLVALUE ); |
| SbxDataType eType = aLvalue.GetType(); |
| if( eType != SbxOBJECT && eType != SbxEMPTY && eType != SbxVARIANT ) |
| Error( SbERR_INVALID_OBJECT ); |
| TestToken( EQ ); |
| SbiSymDef* pDef = aLvalue.GetRealVar(); |
| if( pDef && pDef->GetConstDef() ) |
| Error( SbERR_DUPLICATE_DEF, pDef->GetName() ); |
| |
| SbiToken eTok = Peek(); |
| if( eTok == NEW ) |
| { |
| Next(); |
| String aStr; |
| SbiSymDef* pTypeDef = new SbiSymDef( aStr ); |
| TypeDecl( *pTypeDef, sal_True ); |
| |
| aLvalue.Gen(); |
| // aGen.Gen( _CLASS, pDef->GetTypeId() | 0x8000 ); |
| aGen.Gen( _CREATE, pDef->GetId(), pTypeDef->GetTypeId() ); |
| aGen.Gen( _SETCLASS, pDef->GetTypeId() ); |
| } |
| else |
| { |
| SbiExpression aExpr( this ); |
| aLvalue.Gen(); |
| aExpr.Gen(); |
| // Its a good idea to distinguish between |
| // set someting = another & |
| // someting = another |
| // ( its necessary for vba objects where set is object |
| // specific and also doesn't involve processing default params ) |
| if( pDef->GetTypeId() ) |
| { |
| if ( bVBASupportOn ) |
| aGen.Gen( _VBASETCLASS, pDef->GetTypeId() ); |
| else |
| aGen.Gen( _SETCLASS, pDef->GetTypeId() ); |
| } |
| else |
| { |
| if ( bVBASupportOn ) |
| aGen.Gen( _VBASET ); |
| else |
| aGen.Gen( _SET ); |
| } |
| } |
| // aGen.Gen( _SET ); |
| } |
| |
| // JSM 07.10.95 |
| void SbiParser::LSet() |
| { |
| SbiExpression aLvalue( this, SbLVALUE ); |
| if( aLvalue.GetType() != SbxSTRING ) |
| Error( SbERR_INVALID_OBJECT ); |
| TestToken( EQ ); |
| SbiSymDef* pDef = aLvalue.GetRealVar(); |
| if( pDef && pDef->GetConstDef() ) |
| Error( SbERR_DUPLICATE_DEF, pDef->GetName() ); |
| SbiExpression aExpr( this ); |
| aLvalue.Gen(); |
| aExpr.Gen(); |
| aGen.Gen( _LSET ); |
| } |
| |
| // JSM 07.10.95 |
| void SbiParser::RSet() |
| { |
| SbiExpression aLvalue( this, SbLVALUE ); |
| if( aLvalue.GetType() != SbxSTRING ) |
| Error( SbERR_INVALID_OBJECT ); |
| TestToken( EQ ); |
| SbiSymDef* pDef = aLvalue.GetRealVar(); |
| if( pDef && pDef->GetConstDef() ) |
| Error( SbERR_DUPLICATE_DEF, pDef->GetName() ); |
| SbiExpression aExpr( this ); |
| aLvalue.Gen(); |
| aExpr.Gen(); |
| aGen.Gen( _RSET ); |
| } |
| |
| // DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR und so weiter |
| |
| void SbiParser::DefXXX() |
| { |
| sal_Unicode ch1, ch2; |
| SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER ); |
| |
| while( !bAbort ) |
| { |
| if( Next() != SYMBOL ) break; |
| ch1 = aSym.ToUpperAscii().GetBuffer()[0]; |
| ch2 = 0; |
| if( Peek() == MINUS ) |
| { |
| Next(); |
| if( Next() != SYMBOL ) Error( SbERR_SYMBOL_EXPECTED ); |
| else |
| { |
| ch2 = aSym.ToUpperAscii().GetBuffer()[0]; |
| //ch2 = aSym.Upper(); |
| if( ch2 < ch1 ) Error( SbERR_SYNTAX ), ch2 = 0; |
| } |
| } |
| if (!ch2) ch2 = ch1; |
| ch1 -= 'A'; ch2 -= 'A'; |
| for (; ch1 <= ch2; ch1++) eDefTypes[ ch1 ] = t; |
| if( !TestComma() ) break; |
| } |
| } |
| |
| // STOP/SYSTEM |
| |
| void SbiParser::Stop() |
| { |
| aGen.Gen( _STOP ); |
| Peek(); // #35694: Nur Peek(), damit EOL in Single-Line-If erkannt wird |
| } |
| |
| // IMPLEMENTS |
| |
| void SbiParser::Implements() |
| { |
| if( !bClassModule ) |
| { |
| Error( SbERR_UNEXPECTED, IMPLEMENTS ); |
| return; |
| } |
| |
| Peek(); |
| if( eCurTok != SYMBOL ) |
| { |
| Error( SbERR_SYMBOL_EXPECTED ); |
| return; |
| } |
| |
| String aImplementedIface = aSym; |
| Next(); |
| if( Peek() == DOT ) |
| { |
| String aDotStr( '.' ); |
| while( Peek() == DOT ) |
| { |
| aImplementedIface += aDotStr; |
| Next(); |
| SbiToken ePeekTok = Peek(); |
| if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) ) |
| { |
| Next(); |
| aImplementedIface += aSym; |
| } |
| else |
| { |
| Next(); |
| Error( SbERR_SYMBOL_EXPECTED ); |
| break; |
| } |
| } |
| } |
| aIfaceVector.push_back( aImplementedIface ); |
| } |
| |
| void SbiParser::EnableCompatibility() |
| { |
| if( !bCompatible ) |
| AddConstants(); |
| bCompatible = sal_True; |
| } |
| |
| // OPTION |
| |
| void SbiParser::Option() |
| { |
| switch( Next() ) |
| { |
| case BASIC_EXPLICIT: |
| bExplicit = sal_True; break; |
| case BASE: |
| if( Next() == NUMBER ) |
| { |
| if( nVal == 0 || nVal == 1 ) |
| { |
| nBase = (short) nVal; |
| break; |
| } |
| } |
| Error( SbERR_EXPECTED, "0/1" ); |
| break; |
| case PRIVATE: |
| { |
| String aString = SbiTokenizer::Symbol(Next()); |
| if( !aString.EqualsIgnoreCaseAscii("Module") ) |
| Error( SbERR_EXPECTED, "Module" ); |
| break; |
| } |
| case COMPARE: |
| { |
| SbiToken eTok = Next(); |
| if( eTok == BINARY ) |
| bText = sal_False; |
| else if( eTok == SYMBOL && GetSym().EqualsIgnoreCaseAscii("text") ) |
| bText = sal_True; |
| else |
| Error( SbERR_EXPECTED, "Text/Binary" ); |
| break; |
| } |
| case COMPATIBLE: |
| EnableCompatibility(); |
| break; |
| |
| case CLASSMODULE: |
| bClassModule = sal_True; |
| aGen.GetModule().SetModuleType( com::sun::star::script::ModuleType::CLASS ); |
| break; |
| case VBASUPPORT: |
| if( Next() == NUMBER ) |
| { |
| if ( nVal == 1 || nVal == 0 ) |
| { |
| bVBASupportOn = ( nVal == 1 ); |
| if ( bVBASupportOn ) |
| EnableCompatibility(); |
| // if the module setting is different |
| // reset it to what the Option tells us |
| if ( bVBASupportOn != aGen.GetModule().IsVBACompat() ) |
| aGen.GetModule().SetVBACompat( bVBASupportOn ); |
| break; |
| } |
| } |
| Error( SbERR_EXPECTED, "0/1" ); |
| break; |
| default: |
| Error( SbERR_BAD_OPTION, eCurTok ); |
| } |
| } |
| |
| void addStringConst( SbiSymPool& rPool, const char* pSym, const String& rStr ) |
| { |
| SbiConstDef* pConst = new SbiConstDef( String::CreateFromAscii( pSym ) ); |
| pConst->SetType( SbxSTRING ); |
| pConst->Set( rStr ); |
| rPool.Add( pConst ); |
| } |
| |
| inline void addStringConst( SbiSymPool& rPool, const char* pSym, const char* pStr ) |
| { |
| addStringConst( rPool, pSym, String::CreateFromAscii( pStr ) ); |
| } |
| |
| void SbiParser::AddConstants( void ) |
| { |
| // #113063 Create constant RTL symbols |
| addStringConst( aPublics, "vbCr", "\x0D" ); |
| addStringConst( aPublics, "vbCrLf", "\x0D\x0A" ); |
| addStringConst( aPublics, "vbFormFeed", "\x0C" ); |
| addStringConst( aPublics, "vbLf", "\x0A" ); |
| #if defined(UNX) |
| addStringConst( aPublics, "vbNewLine", "\x0A" ); |
| #else |
| addStringConst( aPublics, "vbNewLine", "\x0D\x0A" ); |
| #endif |
| addStringConst( aPublics, "vbNullString", "" ); |
| addStringConst( aPublics, "vbTab", "\x09" ); |
| addStringConst( aPublics, "vbVerticalTab", "\x0B" ); |
| |
| // Force length 1 and make char 0 afterwards |
| String aNullCharStr( String::CreateFromAscii( " " ) ); |
| aNullCharStr.SetChar( 0, 0 ); |
| addStringConst( aPublics, "vbNullChar", aNullCharStr ); |
| } |
| |
| // ERROR n |
| |
| void SbiParser::ErrorStmnt() |
| { |
| SbiExpression aPar( this ); |
| aPar.Gen(); |
| aGen.Gen( _ERROR ); |
| } |
| |