diff options
Diffstat (limited to 'basic/source/sbx/sbxexec.cxx')
-rw-r--r-- | basic/source/sbx/sbxexec.cxx | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/basic/source/sbx/sbxexec.cxx b/basic/source/sbx/sbxexec.cxx new file mode 100644 index 000000000000..9b43a94873f0 --- /dev/null +++ b/basic/source/sbx/sbxexec.cxx @@ -0,0 +1,401 @@ +/************************************************************************* + * + * 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 <tools/errcode.hxx> +#ifndef _APP_HXX //autogen +#include <vcl/svapp.hxx> +#endif +#include <basic/sbx.hxx> + + +class SbxSimpleCharClass +{ +public: + sal_Bool isAlpha( sal_Unicode c ) const + { + sal_Bool bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + return bRet; + } + + sal_Bool isDigit( sal_Unicode c ) const + { + sal_Bool bRet = (c >= '0' && c <= '9'); + return bRet; + } + + sal_Bool isAlphaNumeric( sal_Unicode c ) const + { + sal_Bool bRet = isDigit( c ) || isAlpha( c ); + return bRet; + } +}; + + +static SbxVariable* Element + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, + SbxClassType, const SbxSimpleCharClass& rCharClass ); + +static const xub_Unicode* SkipWhitespace( const xub_Unicode* p ) +{ + while( *p && ( *p == ' ' || *p == '\t' ) ) + p++; + return p; +} + +// Scannen eines Symbol. Das Symbol wird in rSym eingetragen, der Returnwert +// ist die neue Scanposition. Bei Fehlern ist das Symbol leer. + +static const xub_Unicode* Symbol( const xub_Unicode* p, XubString& rSym, const SbxSimpleCharClass& rCharClass ) +{ + sal_uInt16 nLen = 0; + // Haben wir ein Sondersymbol? + if( *p == '[' ) + { + rSym = ++p; + while( *p && *p != ']' ) + p++, nLen++; + p++; + } + else + { + // Ein Symbol muss mit einem Buchstaben oder einem Underline beginnen + if( !rCharClass.isAlpha( *p ) && *p != '_' ) + SbxBase::SetError( SbxERR_SYNTAX ); + else + { + rSym = p; + // Dann darf es Buchstaben, Zahlen oder Underlines enthalten + while( *p && (rCharClass.isAlphaNumeric( *p ) || *p == '_') ) + p++, nLen++; + // BASIC-Standard-Suffixe werden ignoriert + if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) ) + p++; + } + } + rSym.Erase( nLen ); + return p; +} + +// Qualifizierter Name. Element.Element.... + +static SbxVariable* QualifiedName + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, SbxClassType t ) +{ + static SbxSimpleCharClass aCharClass; + + SbxVariableRef refVar; + const xub_Unicode* p = SkipWhitespace( *ppBuf ); + if( aCharClass.isAlpha( *p ) || *p == '_' || *p == '[' ) + { + // Element einlesen + refVar = Element( pObj, pGbl, &p, t, aCharClass ); + while( refVar.Is() && (*p == '.' || *p == '!') ) + { + // Es folgt noch ein Objektelement. Das aktuelle Element + // muss also ein SBX-Objekt sein oder liefern! + pObj = PTR_CAST(SbxObject,(SbxVariable*) refVar); + if( !pObj ) + // Dann muss es ein Objekt liefern + pObj = PTR_CAST(SbxObject,refVar->GetObject()); + refVar.Clear(); + if( !pObj ) + break; + p++; + // Und das naechste Element bitte + refVar = Element( pObj, pGbl, &p, t, aCharClass ); + } + } + else + SbxBase::SetError( SbxERR_SYNTAX ); + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Einlesen eines Operanden. Dies kann eine Zahl, ein String oder +// eine Funktion (mit optionalen Parametern) sein. + +static SbxVariable* Operand + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, sal_Bool bVar ) +{ + static SbxSimpleCharClass aCharClass; + + SbxVariableRef refVar( new SbxVariable ); + const xub_Unicode* p = SkipWhitespace( *ppBuf ); + if( !bVar && ( aCharClass.isDigit( *p ) + || ( *p == '.' && aCharClass.isDigit( *( p+1 ) ) ) + || *p == '-' + || *p == '&' ) ) + { + // Eine Zahl kann direkt eingescant werden! + sal_uInt16 nLen; + if( !refVar->Scan( XubString( p ), &nLen ) ) + refVar.Clear(); + else + p += nLen; + } + else if( !bVar && *p == '"' ) + { + // Ein String + XubString aString; + p++; + for( ;; ) + { + // Das ist wohl ein Fehler + if( !*p ) + return NULL; + // Doppelte Quotes sind OK + if( *p == '"' ) + if( *++p != '"' ) + break; + aString += *p++; + } + refVar->PutString( aString ); + } + else + refVar = QualifiedName( pObj, pGbl, &p, SbxCLASS_DONTCARE ); + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Einlesen einer einfachen Term. Die Operatoren +, -, * und / +// werden unterstuetzt. + +static SbxVariable* MulDiv( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf ) +{ + const xub_Unicode* p = *ppBuf; + SbxVariableRef refVar( Operand( pObj, pGbl, &p, sal_False ) ); + p = SkipWhitespace( p ); + while( refVar.Is() && ( *p == '*' || *p == '/' ) ) + { + xub_Unicode cOp = *p++; + SbxVariableRef refVar2( Operand( pObj, pGbl, &p, sal_False ) ); + if( refVar2.Is() ) + { + // temporaere Variable! + SbxVariable* pVar = refVar; + pVar = new SbxVariable( *pVar ); + refVar = pVar; + if( cOp == '*' ) + *refVar *= *refVar2; + else + *refVar /= *refVar2; + } + else + { + refVar.Clear(); + break; + } + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +static SbxVariable* PlusMinus( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf ) +{ + const xub_Unicode* p = *ppBuf; + SbxVariableRef refVar( MulDiv( pObj, pGbl, &p ) ); + p = SkipWhitespace( p ); + while( refVar.Is() && ( *p == '+' || *p == '-' ) ) + { + xub_Unicode cOp = *p++; + SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p ) ); + if( refVar2.Is() ) + { + // temporaere Variable! + SbxVariable* pVar = refVar; + pVar = new SbxVariable( *pVar ); + refVar = pVar; + if( cOp == '+' ) + *refVar += *refVar2; + else + *refVar -= *refVar2; + } + else + { + refVar.Clear(); + break; + } + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +static SbxVariable* Assign( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf ) +{ + const xub_Unicode* p = *ppBuf; + SbxVariableRef refVar( Operand( pObj, pGbl, &p, sal_True ) ); + p = SkipWhitespace( p ); + if( refVar.Is() ) + { + if( *p == '=' ) + { + // Nur auf Props zuweisen! + if( refVar->GetClass() != SbxCLASS_PROPERTY ) + { + SbxBase::SetError( SbxERR_BAD_ACTION ); + refVar.Clear(); + } + else + { + p++; + SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p ) ); + if( refVar2.Is() ) + { + SbxVariable* pVar = refVar; + SbxVariable* pVar2 = refVar2; + *pVar = *pVar2; + pVar->SetParameters( NULL ); + } + } + } + else + // Einfacher Aufruf: einmal aktivieren + refVar->Broadcast( SBX_HINT_DATAWANTED ); + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Einlesen eines Elements. Dies ist ein Symbol, optional gefolgt +// von einer Parameterliste. Das Symbol wird im angegebenen Objekt +// gesucht und die Parameterliste wird ggf. angefuegt. + +static SbxVariable* Element + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, + SbxClassType t, const SbxSimpleCharClass& rCharClass ) +{ + XubString aSym; + const xub_Unicode* p = Symbol( *ppBuf, aSym, rCharClass ); + SbxVariableRef refVar; + if( aSym.Len() ) + { + sal_uInt16 nOld = pObj->GetFlags(); + if( pObj == pGbl ) + pObj->SetFlag( SBX_GBLSEARCH ); + refVar = pObj->Find( aSym, t ); + pObj->SetFlags( nOld ); + if( refVar.Is() ) + { + refVar->SetParameters( NULL ); + // folgen noch Parameter? + p = SkipWhitespace( p ); + if( *p == '(' ) + { + p++; + SbxArrayRef refPar = new SbxArray; + sal_uInt16 nArg = 0; + // Wird sind mal relaxed und akzeptieren auch + // das Zeilen- oder Komandoende als Begrenzer + // Parameter immer global suchen! + while( *p && *p != ')' && *p != ']' ) + { + SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p ); + if( !refArg ) + { + // Fehler beim Parsing + refVar.Clear(); break; + } + else + { + // Man kopiere den Parameter, damit + // man den aktuellen Zustand hat (loest auch + // den Aufruf per Zugriff aus) + SbxVariable* pArg = refArg; + refPar->Put( new SbxVariable( *pArg ), ++nArg ); + } + p = SkipWhitespace( p ); + if( *p == ',' ) + p++; + } + if( *p == ')' ) + p++; + if( refVar.Is() ) + refVar->SetParameters( refPar ); + } + } + else + SbxBase::SetError( SbxERR_NO_METHOD ); + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Hauptroutine + +SbxVariable* SbxObject::Execute( const XubString& rTxt ) +{ + SbxVariable* pVar = NULL; + const xub_Unicode* p = rTxt.GetBuffer(); + for( ;; ) + { + p = SkipWhitespace( p ); + if( !*p ) + break; + if( *p++ != '[' ) + { + SetError( SbxERR_SYNTAX ); break; + } + pVar = Assign( this, this, &p ); + if( !pVar ) + break; + p = SkipWhitespace( p ); + if( *p++ != ']' ) + { + SetError( SbxERR_SYNTAX ); break; + } + } + return pVar; +} + +SbxVariable* SbxObject::FindQualified( const XubString& rName, SbxClassType t ) +{ + SbxVariable* pVar = NULL; + const xub_Unicode* p = rName.GetBuffer(); + p = SkipWhitespace( p ); + if( !*p ) + return NULL;; + pVar = QualifiedName( this, this, &p, t ); + p = SkipWhitespace( p ); + if( *p ) + SetError( SbxERR_SYNTAX ); + return pVar; +} + |