diff options
Diffstat (limited to 'basic/source/comp/parser.cxx')
-rw-r--r-- | basic/source/comp/parser.cxx | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/basic/source/comp/parser.cxx b/basic/source/comp/parser.cxx new file mode 100644 index 000000000000..2ea78357882f --- /dev/null +++ b/basic/source/comp/parser.cxx @@ -0,0 +1,872 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 [] = { +{ ATTRIBUTE, &SbiParser::Attribute, Y, Y, }, // ATTRIBUTE +{ 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 ); + 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; + } + + // In vba it's possible to do Error.foobar ( even if it results in + // a runtime error + if ( eCurTok == _ERROR_ && IsVBASupportOn() ) // we probably need to define a subset of keywords where this madness applies e.g. if ( IsVBASupportOn() && SymbolCanBeRedined( eCurTok ) ) + { + SbiTokenizer tokens( *(SbiTokenizer*)this ); + tokens.Next(); + if ( tokens.Peek() == DOT ) + { + eCurTok = SYMBOL; + ePush = eCurTok; + } + } + // 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(); + 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; + 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( _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 ); + } + } +} + +// 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]; + 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 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: // Option VBASupport used to override the module mode ( in fact this must reset the mode + 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 ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |