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 <basic/sbx.hxx>
21 #include <basic/sberrors.hxx>
22 #include <rtl/character.hxx>
23 #include <rtl/ustrbuf.hxx>
26 static SbxVariableRef Element
27 ( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
,
30 static const sal_Unicode
* SkipWhitespace( const sal_Unicode
* p
)
32 while( *p
&& ( *p
== ' ' || *p
== '\t' ) )
37 // Scanning of a symbol. The symbol were inserted in rSym, the return value
38 // is the new scan position. The symbol is at errors empty.
40 static const sal_Unicode
* Symbol( const sal_Unicode
* p
, OUString
& rSym
)
43 // Did we have a nonstandard symbol?
47 while( *p
&& *p
!= ']' )
56 // A symbol had to begin with an alphabetic character or an underline
57 if( !rtl::isAsciiAlpha( *p
) && *p
!= '_' )
59 SbxBase::SetError( ERRCODE_BASIC_SYNTAX
);
64 // The it can contain alphabetic characters, numbers or underlines
65 while( *p
&& (rtl::isAsciiAlphanumeric( *p
) || *p
== '_') )
70 // Ignore standard BASIC suffixes
71 if( *p
&& (*p
== '%' || *p
== '&' || *p
== '!' || *p
== '#' || *p
== '$' ) )
77 rSym
= rSym
.copy( 0, nLen
);
81 // Qualified name. Element.Element...
83 static SbxVariableRef QualifiedName
84 ( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
, SbxClassType t
)
87 SbxVariableRef refVar
;
88 const sal_Unicode
* p
= SkipWhitespace( *ppBuf
);
89 if( rtl::isAsciiAlpha( *p
) || *p
== '_' || *p
== '[' )
91 // Read in the element
92 refVar
= Element( pObj
, pGbl
, &p
, t
);
93 while( refVar
.is() && (*p
== '.' || *p
== '!') )
95 // It follows still an objectelement. The current element
96 // had to be a SBX-Object or had to deliver such an object!
97 pObj
= dynamic_cast<SbxObject
*>( refVar
.get() );
99 // Then it had to deliver an object
100 pObj
= dynamic_cast<SbxObject
*>( refVar
->GetObject() );
105 // And the next element please
106 refVar
= Element( pObj
, pGbl
, &p
, t
);
110 SbxBase::SetError( ERRCODE_BASIC_SYNTAX
);
115 // Read in of an operand. This could be a number, a string or
116 // a function (with optional parameters).
118 static SbxVariableRef Operand
119 ( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
, bool bVar
)
121 SbxVariableRef
refVar( new SbxVariable
);
122 const sal_Unicode
* p
= SkipWhitespace( *ppBuf
);
123 if( !bVar
&& ( rtl::isAsciiDigit( *p
)
124 || ( *p
== '.' && rtl::isAsciiDigit( *( p
+1 ) ) )
128 // A number could be scanned in directly!
130 if( !refVar
->Scan( OUString( p
), &nLen
) )
139 else if( !bVar
&& *p
== '"' )
142 OUStringBuffer aString
;
146 // This is perhaps an error
151 // Double quotes are OK
152 if( *p
== '"' && (*++p
) != '"' )
156 aString
.append(*p
++);
158 refVar
->PutString( aString
.makeStringAndClear() );
162 refVar
= QualifiedName( pObj
, pGbl
, &p
, SbxClassType::DontCare
);
168 // Read in of a simple term. The operands +, -, * and /
171 static SbxVariableRef
MulDiv( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
)
173 const sal_Unicode
* p
= *ppBuf
;
174 SbxVariableRef
refVar( Operand( pObj
, pGbl
, &p
, false ) );
175 p
= SkipWhitespace( p
);
176 while( refVar
.is() && ( *p
== '*' || *p
== '/' ) )
178 sal_Unicode cOp
= *p
++;
179 SbxVariableRef
refVar2( Operand( pObj
, pGbl
, &p
, false ) );
182 // temporary variable!
183 SbxVariable
* pVar
= refVar
.get();
184 pVar
= new SbxVariable( *pVar
);
201 static SbxVariableRef
PlusMinus( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
)
203 const sal_Unicode
* p
= *ppBuf
;
204 SbxVariableRef
refVar( MulDiv( pObj
, pGbl
, &p
) );
205 p
= SkipWhitespace( p
);
206 while( refVar
.is() && ( *p
== '+' || *p
== '-' ) )
208 sal_Unicode cOp
= *p
++;
209 SbxVariableRef
refVar2( MulDiv( pObj
, pGbl
, &p
) );
212 // temporary Variable!
213 SbxVariable
* pVar
= refVar
.get();
214 pVar
= new SbxVariable( *pVar
);
231 static SbxVariableRef
Assign( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
)
233 const sal_Unicode
* p
= *ppBuf
;
234 SbxVariableRef
refVar( Operand( pObj
, pGbl
, &p
, true ) );
235 p
= SkipWhitespace( p
);
240 // Assign only onto properties!
241 if( refVar
->GetClass() != SbxClassType::Property
)
243 SbxBase::SetError( ERRCODE_BASIC_BAD_ACTION
);
249 SbxVariableRef
refVar2( PlusMinus( pObj
, pGbl
, &p
) );
252 SbxVariable
* pVar
= refVar
.get();
253 SbxVariable
* pVar2
= refVar2
.get();
255 pVar
->SetParameters( nullptr );
260 // Simple call: once activating
261 refVar
->Broadcast( SfxHintId::BasicDataWanted
);
267 // Read in of an element. This is a symbol, optional followed
268 // by a parameter list. The symbol will be searched in the
269 // specified object and the parameter list will be attached if necessary.
271 static SbxVariableRef Element
272 ( SbxObject
* pObj
, SbxObject
* pGbl
, const sal_Unicode
** ppBuf
,
276 const sal_Unicode
* p
= Symbol( *ppBuf
, aSym
);
277 SbxVariableRef refVar
;
278 if( !aSym
.isEmpty() )
280 SbxFlagBits nOld
= pObj
->GetFlags();
283 pObj
->SetFlag( SbxFlagBits::GlobalSearch
);
285 refVar
= pObj
->Find( aSym
, t
);
286 pObj
->SetFlags( nOld
);
289 refVar
->SetParameters( nullptr );
290 // Follow still parameter?
291 p
= SkipWhitespace( p
);
295 auto refPar
= tools::make_ref
<SbxArray
>();
297 // We are once relaxed and accept as well
298 // the line- or command end as delimiter
299 // Search parameter always global!
300 while( *p
&& *p
!= ')' && *p
!= ']' )
302 SbxVariableRef refArg
= PlusMinus( pGbl
, pGbl
, &p
);
305 // Error during the parsing
306 refVar
.clear(); break;
310 // One copies the parameter, so that
311 // one have the current status (triggers also
312 // the call per access)
313 refPar
->Put( new SbxVariable( *refArg
), ++nArg
);
315 p
= SkipWhitespace( p
);
322 refVar
->SetParameters( refPar
.get() );
326 SbxBase::SetError( ERRCODE_BASIC_NO_METHOD
);
334 SbxVariable
* SbxObject::Execute( const OUString
& rTxt
)
337 const sal_Unicode
* p
= rTxt
.getStr();
340 p
= SkipWhitespace( p
);
347 SetError( ERRCODE_BASIC_SYNTAX
); break;
349 pVar
= Assign( this, this, &p
);
354 p
= SkipWhitespace( p
);
357 SetError( ERRCODE_BASIC_SYNTAX
); break;
363 SbxVariable
* SbxObject::FindQualified( const OUString
& rName
, SbxClassType t
)
366 const sal_Unicode
* p
= rName
.getStr();
367 p
= SkipWhitespace( p
);
372 pVar
= QualifiedName( this, this, &p
, t
);
373 p
= SkipWhitespace( p
);
376 SetError( ERRCODE_BASIC_SYNTAX
);
381 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */