blob: cab49cf400dff1319038840b98d672a2f614ac95 [file] [log] [blame]
/**************************************************************
*
* 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 <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;
}