xref: /AOO41X/main/basic/source/sbx/sbxexec.cxx (revision e1f63238eb022c8a12b30d46a012444ff20e0951)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basic.hxx"
26 #include <tools/errcode.hxx>
27 #ifndef _APP_HXX //autogen
28 #include <vcl/svapp.hxx>
29 #endif
30 #include <basic/sbx.hxx>
31 
32 
33 class SbxSimpleCharClass
34 {
35 public:
isAlpha(sal_Unicode c) const36     sal_Bool isAlpha( sal_Unicode c ) const
37     {
38         sal_Bool bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
39         return bRet;
40     }
41 
isDigit(sal_Unicode c) const42     sal_Bool isDigit( sal_Unicode c ) const
43     {
44         sal_Bool bRet = (c >= '0' && c <= '9');
45         return bRet;
46     }
47 
isAlphaNumeric(sal_Unicode c) const48     sal_Bool isAlphaNumeric( sal_Unicode c ) const
49     {
50         sal_Bool bRet = isDigit( c ) || isAlpha( c );
51         return bRet;
52     }
53 };
54 
55 
56 static SbxVariable* Element
57     ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf,
58       SbxClassType, const SbxSimpleCharClass& rCharClass );
59 
SkipWhitespace(const xub_Unicode * p)60 static const xub_Unicode* SkipWhitespace( const xub_Unicode* p )
61 {
62     while( *p && ( *p == ' ' || *p == '\t' ) )
63         p++;
64     return p;
65 }
66 
67 // Scannen eines Symbol. Das Symbol wird in rSym eingetragen, der Returnwert
68 // ist die neue Scanposition. Bei Fehlern ist das Symbol leer.
69 
Symbol(const xub_Unicode * p,XubString & rSym,const SbxSimpleCharClass & rCharClass)70 static const xub_Unicode* Symbol( const xub_Unicode* p, XubString& rSym, const SbxSimpleCharClass& rCharClass )
71 {
72     sal_uInt16 nLen = 0;
73     // Haben wir ein Sondersymbol?
74     if( *p == '[' )
75     {
76         rSym = ++p;
77         while( *p && *p != ']' )
78             p++, nLen++;
79         p++;
80     }
81     else
82     {
83         // Ein Symbol muss mit einem Buchstaben oder einem Underline beginnen
84         if( !rCharClass.isAlpha( *p ) && *p != '_' )
85             SbxBase::SetError( SbxERR_SYNTAX );
86         else
87         {
88             rSym = p;
89             // Dann darf es Buchstaben, Zahlen oder Underlines enthalten
90             while( *p && (rCharClass.isAlphaNumeric( *p ) || *p == '_') )
91                 p++, nLen++;
92             // BASIC-Standard-Suffixe werden ignoriert
93             if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) )
94                 p++;
95         }
96     }
97     rSym.Erase( nLen );
98     return p;
99 }
100 
101 // Qualifizierter Name. Element.Element....
102 
QualifiedName(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf,SbxClassType t)103 static SbxVariable* QualifiedName
104     ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, SbxClassType t )
105 {
106     static SbxSimpleCharClass aCharClass;
107 
108     SbxVariableRef refVar;
109     const xub_Unicode* p = SkipWhitespace( *ppBuf );
110     if( aCharClass.isAlpha( *p ) || *p == '_' || *p == '[' )
111     {
112         // Element einlesen
113         refVar = Element( pObj, pGbl, &p, t, aCharClass );
114         while( refVar.Is() && (*p == '.' || *p == '!') )
115         {
116             // Es folgt noch ein Objektelement. Das aktuelle Element
117             // muss also ein SBX-Objekt sein oder liefern!
118             pObj = PTR_CAST(SbxObject,(SbxVariable*) refVar);
119             if( !pObj )
120                 // Dann muss es ein Objekt liefern
121                 pObj = PTR_CAST(SbxObject,refVar->GetObject());
122             refVar.Clear();
123             if( !pObj )
124                 break;
125             p++;
126             // Und das naechste Element bitte
127             refVar = Element( pObj, pGbl, &p, t, aCharClass );
128         }
129     }
130     else
131         SbxBase::SetError( SbxERR_SYNTAX );
132     *ppBuf = p;
133     if( refVar.Is() )
134         refVar->AddRef();
135     return refVar;
136 }
137 
138 // Einlesen eines Operanden. Dies kann eine Zahl, ein String oder
139 // eine Funktion (mit optionalen Parametern) sein.
140 
Operand(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf,sal_Bool bVar)141 static SbxVariable* Operand
142     ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, sal_Bool bVar )
143 {
144     static SbxSimpleCharClass aCharClass;
145 
146     SbxVariableRef refVar( new SbxVariable );
147     const xub_Unicode* p = SkipWhitespace( *ppBuf );
148     if( !bVar && ( aCharClass.isDigit( *p )
149      || ( *p == '.' && aCharClass.isDigit( *( p+1 ) ) )
150      || *p == '-'
151      || *p == '&' ) )
152     {
153         // Eine Zahl kann direkt eingescant werden!
154         sal_uInt16 nLen;
155         if( !refVar->Scan( XubString( p ), &nLen ) )
156             refVar.Clear();
157         else
158             p += nLen;
159     }
160     else if( !bVar && *p == '"' )
161     {
162         // Ein String
163         XubString aString;
164         p++;
165         for( ;; )
166         {
167             // Das ist wohl ein Fehler
168             if( !*p )
169                 return NULL;
170             // Doppelte Quotes sind OK
171             if( *p == '"' )
172                 if( *++p != '"' )
173                     break;
174             aString += *p++;
175         }
176         refVar->PutString( aString );
177     }
178     else
179         refVar = QualifiedName( pObj, pGbl, &p, SbxCLASS_DONTCARE );
180     *ppBuf = p;
181     if( refVar.Is() )
182         refVar->AddRef();
183     return refVar;
184 }
185 
186 // Einlesen einer einfachen Term. Die Operatoren +, -, * und /
187 // werden unterstuetzt.
188 
MulDiv(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf)189 static SbxVariable* MulDiv( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf )
190 {
191     const xub_Unicode* p = *ppBuf;
192     SbxVariableRef refVar( Operand( pObj, pGbl, &p, sal_False ) );
193     p = SkipWhitespace( p );
194     while( refVar.Is() && ( *p == '*' || *p == '/' ) )
195     {
196         xub_Unicode cOp = *p++;
197         SbxVariableRef refVar2( Operand( pObj, pGbl, &p, sal_False ) );
198         if( refVar2.Is() )
199         {
200             // temporaere Variable!
201             SbxVariable* pVar = refVar;
202             pVar = new SbxVariable( *pVar );
203             refVar = pVar;
204             if( cOp == '*' )
205                 *refVar *= *refVar2;
206             else
207                 *refVar /= *refVar2;
208         }
209         else
210         {
211             refVar.Clear();
212             break;
213         }
214     }
215     *ppBuf = p;
216     if( refVar.Is() )
217         refVar->AddRef();
218     return refVar;
219 }
220 
PlusMinus(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf)221 static SbxVariable* PlusMinus( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf )
222 {
223     const xub_Unicode* p = *ppBuf;
224     SbxVariableRef refVar( MulDiv( pObj, pGbl, &p ) );
225     p = SkipWhitespace( p );
226     while( refVar.Is() && ( *p == '+' || *p == '-' ) )
227     {
228         xub_Unicode cOp = *p++;
229         SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p ) );
230         if( refVar2.Is() )
231         {
232             // temporaere Variable!
233             SbxVariable* pVar = refVar;
234             pVar = new SbxVariable( *pVar );
235             refVar = pVar;
236             if( cOp == '+' )
237                 *refVar += *refVar2;
238             else
239                 *refVar -= *refVar2;
240         }
241         else
242         {
243             refVar.Clear();
244             break;
245         }
246     }
247     *ppBuf = p;
248     if( refVar.Is() )
249         refVar->AddRef();
250     return refVar;
251 }
252 
Assign(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf)253 static SbxVariable* Assign( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf )
254 {
255     const xub_Unicode* p = *ppBuf;
256     SbxVariableRef refVar( Operand( pObj, pGbl, &p, sal_True ) );
257     p = SkipWhitespace( p );
258     if( refVar.Is() )
259     {
260         if( *p == '=' )
261         {
262             // Nur auf Props zuweisen!
263             if( refVar->GetClass() != SbxCLASS_PROPERTY )
264             {
265                 SbxBase::SetError( SbxERR_BAD_ACTION );
266                 refVar.Clear();
267             }
268             else
269             {
270                 p++;
271                 SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p ) );
272                 if( refVar2.Is() )
273                 {
274                     SbxVariable* pVar = refVar;
275                     SbxVariable* pVar2 = refVar2;
276                     *pVar = *pVar2;
277                     pVar->SetParameters( NULL );
278                 }
279             }
280         }
281         else
282             // Einfacher Aufruf: einmal aktivieren
283             refVar->Broadcast( SBX_HINT_DATAWANTED );
284     }
285     *ppBuf = p;
286     if( refVar.Is() )
287         refVar->AddRef();
288     return refVar;
289 }
290 
291 // Einlesen eines Elements. Dies ist ein Symbol, optional gefolgt
292 // von einer Parameterliste. Das Symbol wird im angegebenen Objekt
293 // gesucht und die Parameterliste wird ggf. angefuegt.
294 
Element(SbxObject * pObj,SbxObject * pGbl,const xub_Unicode ** ppBuf,SbxClassType t,const SbxSimpleCharClass & rCharClass)295 static SbxVariable* Element
296     ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf,
297       SbxClassType t, const SbxSimpleCharClass& rCharClass )
298 {
299     XubString aSym;
300     const xub_Unicode* p = Symbol( *ppBuf, aSym, rCharClass );
301     SbxVariableRef refVar;
302     if( aSym.Len() )
303     {
304         sal_uInt16 nOld = pObj->GetFlags();
305         if( pObj == pGbl )
306             pObj->SetFlag( SBX_GBLSEARCH );
307         refVar = pObj->Find( aSym, t );
308         pObj->SetFlags( nOld );
309         if( refVar.Is() )
310         {
311             refVar->SetParameters( NULL );
312             // folgen noch Parameter?
313             p = SkipWhitespace( p );
314             if( *p == '(' )
315             {
316                 p++;
317                 SbxArrayRef refPar = new SbxArray;
318                 sal_uInt16 nArg = 0;
319                 // Wird sind mal relaxed und akzeptieren auch
320                 // das Zeilen- oder Komandoende als Begrenzer
321                 // Parameter immer global suchen!
322                 while( *p && *p != ')' && *p != ']' )
323                 {
324                     SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p );
325                     if( !refArg )
326                     {
327                         // Fehler beim Parsing
328                         refVar.Clear(); break;
329                     }
330                     else
331                     {
332                         // Man kopiere den Parameter, damit
333                         // man den aktuellen Zustand hat (loest auch
334                         // den Aufruf per Zugriff aus)
335                         SbxVariable* pArg = refArg;
336                         refPar->Put( new SbxVariable( *pArg ), ++nArg );
337                     }
338                     p = SkipWhitespace( p );
339                     if( *p == ',' )
340                         p++;
341                 }
342                 if( *p == ')' )
343                     p++;
344                 if( refVar.Is() )
345                     refVar->SetParameters( refPar );
346             }
347         }
348         else
349             SbxBase::SetError( SbxERR_NO_METHOD );
350     }
351     *ppBuf = p;
352     if( refVar.Is() )
353         refVar->AddRef();
354     return refVar;
355 }
356 
357 // Hauptroutine
358 
Execute(const XubString & rTxt)359 SbxVariable* SbxObject::Execute( const XubString& rTxt )
360 {
361     SbxVariable* pVar = NULL;
362     const xub_Unicode* p = rTxt.GetBuffer();
363     for( ;; )
364     {
365         p = SkipWhitespace( p );
366         if( !*p )
367             break;
368         if( *p++ != '[' )
369         {
370             SetError( SbxERR_SYNTAX ); break;
371         }
372         pVar = Assign( this, this, &p );
373         if( !pVar )
374             break;
375         p = SkipWhitespace( p );
376         if( *p++ != ']' )
377         {
378             SetError( SbxERR_SYNTAX ); break;
379         }
380     }
381     return pVar;
382 }
383 
FindQualified(const XubString & rName,SbxClassType t)384 SbxVariable* SbxObject::FindQualified( const XubString& rName, SbxClassType t )
385 {
386     SbxVariable* pVar = NULL;
387     const xub_Unicode* p = rName.GetBuffer();
388     p = SkipWhitespace( p );
389     if( !*p )
390         return NULL;;
391     pVar = QualifiedName( this, this, &p, t );
392     p = SkipWhitespace( p );
393     if( *p )
394         SetError( SbxERR_SYNTAX );
395     return pVar;
396 }
397 
398