1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <basic/sbx.hxx>
23 #include <basic/sberrors.hxx>
24 #include <rtl/character.hxx>
25 #include <rtl/ustrbuf.hxx>
27 #include <basiccharclass.hxx>
29 static SbxVariableRef Element
30 ( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
,
31 SbxClassType
, bool bCompatible
);
33 static const sal_Unicode
* SkipWhitespace( const sal_Unicode
* p
)
35 while( BasicCharClass::isWhitespace(*p
) )
40 // Scanning of a symbol. The symbol were inserted in rSym, the return value
41 // is the new scan position. The symbol is at errors empty.
43 static const sal_Unicode
* Symbol( const sal_Unicode
* p
, OUString
& rSym
, bool bCompatible
)
46 // Did we have a nonstandard symbol?
50 while( *p
&& *p
!= ']' )
59 // A symbol had to begin with an alphabetic character or an underline
60 if( !BasicCharClass::isAlpha( *p
, bCompatible
) && *p
!= '_' )
62 SbxBase::SetError( ERRCODE_BASIC_SYNTAX
);
67 // The it can contain alphabetic characters, numbers or underlines
68 while( *p
&& (BasicCharClass::isAlphaNumeric( *p
, bCompatible
) || *p
== '_') )
73 // Ignore standard BASIC suffixes
74 if( *p
&& (*p
== '%' || *p
== '&' || *p
== '!' || *p
== '#' || *p
== '$' ) )
80 rSym
= rSym
.copy( 0, nLen
);
84 // Qualified name. Element.Element...
86 static SbxVariableRef QualifiedName
87 ( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
, SbxClassType t
, bool bCompatible
)
90 SbxVariableRef refVar
;
91 const sal_Unicode
* p
= SkipWhitespace( *ppBuf
);
92 if( BasicCharClass::isAlpha( *p
, bCompatible
) || *p
== '_' || *p
== '[' )
94 // Read in the element
95 refVar
= Element( pObj
, pGbl
, &p
, t
, bCompatible
);
96 while( refVar
.is() && (*p
== '.' || *p
== '!') )
98 // It follows still an objectelement. The current element
99 // had to be a SBX-Object or had to deliver such an object!
100 pObj
= dynamic_cast<SbxObject
*>( refVar
.get() );
102 // Then it had to deliver an object
103 pObj
= dynamic_cast<SbxObject
*>( refVar
->GetObject() );
108 // And the next element please
109 refVar
= Element( pObj
, pGbl
, &p
, t
, bCompatible
);
113 SbxBase::SetError( ERRCODE_BASIC_SYNTAX
);
118 // Read in of an operand. This could be a number, a string or
119 // a function (with optional parameters).
121 static SbxVariableRef Operand
122 ( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
, bool bVar
, bool bCompatible
)
124 SbxVariableRef
refVar( new SbxVariable
);
125 const sal_Unicode
* p
= SkipWhitespace( *ppBuf
);
126 if( !bVar
&& ( rtl::isAsciiDigit( *p
)
127 || ( *p
== '.' && rtl::isAsciiDigit( *( p
+1 ) ) )
131 // A number could be scanned in directly!
133 if (!refVar
->Scan(p
, &nLen
))
142 else if( !bVar
&& *p
== '"' )
145 OUStringBuffer aString
;
149 // This is perhaps an error
154 // Double quotes are OK
155 if( *p
== '"' && (*++p
) != '"' )
159 aString
.append(*p
++);
161 refVar
->PutString( aString
.makeStringAndClear() );
165 refVar
= QualifiedName( pObj
, pGbl
, &p
, SbxClassType::DontCare
, bCompatible
);
171 // Read in of a simple term. The operands +, -, * and /
174 static SbxVariableRef
MulDiv( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
, bool bCompatible
)
176 const sal_Unicode
* p
= *ppBuf
;
177 SbxVariableRef
refVar( Operand( pObj
, pGbl
, &p
, false, bCompatible
) );
178 p
= SkipWhitespace( p
);
179 while( refVar
.is() && ( *p
== '*' || *p
== '/' ) )
181 sal_Unicode cOp
= *p
++;
182 SbxVariableRef
refVar2( Operand( pObj
, pGbl
, &p
, false, bCompatible
) );
185 // temporary variable!
186 SbxVariable
* pVar
= refVar
.get();
187 pVar
= new SbxVariable( *pVar
);
204 static SbxVariableRef
PlusMinus( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
, bool bCompatible
)
206 const sal_Unicode
* p
= *ppBuf
;
207 SbxVariableRef
refVar( MulDiv( pObj
, pGbl
, &p
, bCompatible
) );
208 p
= SkipWhitespace( p
);
209 while( refVar
.is() && ( *p
== '+' || *p
== '-' ) )
211 sal_Unicode cOp
= *p
++;
212 SbxVariableRef
refVar2( MulDiv( pObj
, pGbl
, &p
, bCompatible
) );
215 // temporary Variable!
216 SbxVariable
* pVar
= refVar
.get();
217 pVar
= new SbxVariable( *pVar
);
234 static SbxVariableRef
Assign( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
, bool bCompatible
)
236 const sal_Unicode
* p
= *ppBuf
;
237 SbxVariableRef
refVar( Operand( pObj
, pGbl
, &p
, true, bCompatible
) );
238 p
= SkipWhitespace( p
);
243 // Assign only onto properties!
244 if( refVar
->GetClass() != SbxClassType::Property
)
246 SbxBase::SetError( ERRCODE_BASIC_BAD_ACTION
);
252 SbxVariableRef
refVar2( PlusMinus( pObj
, pGbl
, &p
, bCompatible
) );
255 SbxVariable
* pVar
= refVar
.get();
256 SbxVariable
* pVar2
= refVar2
.get();
258 pVar
->SetParameters( nullptr );
263 // Simple call: once activating
264 refVar
->Broadcast( SfxHintId::BasicDataWanted
);
270 // Read in of an element. This is a symbol, optional followed
271 // by a parameter list. The symbol will be searched in the
272 // specified object and the parameter list will be attached if necessary.
274 static SbxVariableRef Element
275 ( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
,
276 SbxClassType t
, bool bCompatible
)
279 const sal_Unicode
* p
= Symbol( *ppBuf
, aSym
, bCompatible
);
280 SbxVariableRef refVar
;
281 if( !aSym
.isEmpty() )
283 SbxFlagBits nOld
= pObj
->GetFlags();
286 pObj
->SetFlag( SbxFlagBits::GlobalSearch
);
288 refVar
= pObj
->Find( aSym
, t
);
289 pObj
->SetFlags( nOld
);
292 refVar
->SetParameters( nullptr );
293 // Follow still parameter?
294 p
= SkipWhitespace( p
);
298 auto refPar
= tools::make_ref
<SbxArray
>();
300 // We are once relaxed and accept as well
301 // the line- or command end as delimiter
302 // Search parameter always global!
303 while( *p
&& *p
!= ')' && *p
!= ']' )
305 SbxVariableRef refArg
= PlusMinus( pGbl
, pGbl
, &p
, bCompatible
);
308 // Error during the parsing
309 refVar
.clear(); break;
313 // One copies the parameter, so that
314 // one have the current status (triggers also
315 // the call per access)
316 refPar
->Put(new SbxVariable(*refArg
), ++nArg
);
318 p
= SkipWhitespace( p
);
325 refVar
->SetParameters( refPar
.get() );
329 SbxBase::SetError( ERRCODE_BASIC_NO_METHOD
, aSym
);
337 SbxVariable
* SbxObject::Execute( const OUString
& rTxt
)
340 const sal_Unicode
* p
= rTxt
.getStr();
343 p
= SkipWhitespace( p
);
350 SetError( ERRCODE_BASIC_SYNTAX
); break;
352 pVar
= Assign( this, this, &p
, IsOptionCompatible() );
357 p
= SkipWhitespace( p
);
360 SetError( ERRCODE_BASIC_SYNTAX
); break;
366 SbxVariable
* SbxObject::FindQualified( const OUString
& rName
, SbxClassType t
)
369 const sal_Unicode
* p
= rName
.getStr();
370 p
= SkipWhitespace( p
);
375 pVar
= QualifiedName( this, this, &p
, t
, IsOptionCompatible() );
376 p
= SkipWhitespace( p
);
379 SetError( ERRCODE_BASIC_SYNTAX
);
384 bool SbxObject::IsOptionCompatible() const
386 if (const SbxObject
* pObj
= GetParent())
387 return pObj
->IsOptionCompatible();
391 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */