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