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..f12ffc0bf817 --- /dev/null +++ b/basic/source/sbx/sbxexec.cxx @@ -0,0 +1,401 @@ +/* -*- 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 <tools/errcode.hxx> +#include <vcl/svapp.hxx> +#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; +} + +// Scanning of a symbol. The symbol were inserted in rSym, the return value +// is the new scan position. The symbol is at errors empty. + +static const xub_Unicode* Symbol( const xub_Unicode* p, XubString& rSym, const SbxSimpleCharClass& rCharClass ) +{ + sal_uInt16 nLen = 0; + // Did we have a nonstandard symbol? + if( *p == '[' ) + { + rSym = ++p; + while( *p && *p != ']' ) + p++, nLen++; + p++; + } + else + { + // A symbol had to begin with a alphabetic character or an underline + if( !rCharClass.isAlpha( *p ) && *p != '_' ) + SbxBase::SetError( SbxERR_SYNTAX ); + else + { + rSym = p; + // The it can contain alphabetic characters, numbers or underlines + while( *p && (rCharClass.isAlphaNumeric( *p ) || *p == '_') ) + p++, nLen++; + // BASIC-Standard-Suffixes were ignored + if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) ) + p++; + } + } + rSym.Erase( nLen ); + return p; +} + +// Qualified 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 == '[' ) + { + // Read in the element + refVar = Element( pObj, pGbl, &p, t, aCharClass ); + while( refVar.Is() && (*p == '.' || *p == '!') ) + { + // It follows still an objectelement. The current element + // had to be a SBX-Object or had to deliver such an object! + pObj = PTR_CAST(SbxObject,(SbxVariable*) refVar); + if( !pObj ) + // Then it had to deliver an object + pObj = PTR_CAST(SbxObject,refVar->GetObject()); + refVar.Clear(); + if( !pObj ) + break; + p++; + // And the next element please + refVar = Element( pObj, pGbl, &p, t, aCharClass ); + } + } + else + SbxBase::SetError( SbxERR_SYNTAX ); + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Read in of an operand. This could be a number, a string or +// a function (with optional parameters). + +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 == '&' ) ) + { + // A number could be scanned in directly! + sal_uInt16 nLen; + if( !refVar->Scan( XubString( p ), &nLen ) ) + refVar.Clear(); + else + p += nLen; + } + else if( !bVar && *p == '"' ) + { + // A string + XubString aString; + p++; + for( ;; ) + { + // This is perhaps an error + if( !*p ) + return NULL; + // Double quotes are 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; +} + +// Read in of a simple term. The operands +, -, * and / +// are supported. + +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() ) + { + // temporary 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 == '=' ) + { + // Assign only onto properties! + 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 + // Simple call: once activating + refVar->Broadcast( SBX_HINT_DATAWANTED ); + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Read in of an element. This is a symbol, optional followed +// by a parameter list. The symbol will be searched in the +// specified object and the parameter list will be attached if necessary. + +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 ); + // Follow still parameter? + p = SkipWhitespace( p ); + if( *p == '(' ) + { + p++; + SbxArrayRef refPar = new SbxArray; + sal_uInt16 nArg = 0; + // We are once relaxed and accept as well + // the line- or commandend as delimiter + // Search parameter always global! + while( *p && *p != ')' && *p != ']' ) + { + SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p ); + if( !refArg ) + { + // Error during the parsing + refVar.Clear(); break; + } + else + { + // One copies the parameter, so that + // one have the current status (triggers also + // the call per access) + 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; +} + +// Mainroutine + +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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |