xref: /trunk/main/basic/source/sbx/sbxexec.cxx (revision e1f63238)
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