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: 36 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 42 sal_Bool isDigit( sal_Unicode c ) const 43 { 44 sal_Bool bRet = (c >= '0' && c <= '9'); 45 return bRet; 46 } 47 48 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 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 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 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 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 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 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 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 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 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 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