/************************************************************** * * 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 #ifndef _APP_HXX //autogen #include #endif #include 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; }