Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <basic/sbx.hxx>
21 : #include "sbcomp.hxx"
22 : #include "sbunoobj.hxx"
23 :
24 :
25 : SbxObject* cloneTypeObjectImpl( const SbxObject& rTypeObj );
26 :
27 : // Declaration of a variable
28 : // If there are errors it will be parsed up to the comma or the newline.
29 : // Return-value: a new instance, which were inserted and then deleted.
30 : // Array-Indexex were returned as SbiDimList
31 :
32 1064 : SbiSymDef* SbiParser::VarDecl( SbiDimList** ppDim, bool bStatic, bool bConst )
33 : {
34 1064 : bool bWithEvents = false;
35 1064 : if( Peek() == WITHEVENTS )
36 : {
37 0 : Next();
38 0 : bWithEvents = true;
39 : }
40 1064 : if( !TestSymbol() ) return NULL;
41 1064 : SbxDataType t = eScanType;
42 1064 : SbiSymDef* pDef = bConst ? new SbiConstDef( aSym ) : new SbiSymDef( aSym );
43 1064 : SbiDimList* pDim = NULL;
44 : // Brackets?
45 1064 : if( Peek() == LPAREN )
46 : {
47 44 : pDim = new SbiDimList( this );
48 44 : if( !pDim->GetDims() )
49 19 : pDef->SetWithBrackets();
50 : }
51 1064 : pDef->SetType( t );
52 1064 : if( bStatic )
53 0 : pDef->SetStatic();
54 1064 : if( bWithEvents )
55 0 : pDef->SetWithEvents();
56 1064 : TypeDecl( *pDef );
57 1064 : if( !ppDim && pDim )
58 : {
59 0 : if(pDim->GetDims() )
60 0 : Error( SbERR_EXPECTED, "()" );
61 0 : delete pDim;
62 : }
63 1064 : else if( ppDim )
64 857 : *ppDim = pDim;
65 1064 : return pDef;
66 : }
67 :
68 : // Resolving of a AS-Type-Declaration
69 : // The data type were inserted into the handed over variable
70 :
71 1450 : void SbiParser::TypeDecl( SbiSymDef& rDef, bool bAsNewAlreadyParsed )
72 : {
73 1450 : SbxDataType eType = rDef.GetType();
74 1450 : if( bAsNewAlreadyParsed || Peek() == AS )
75 : {
76 958 : short nSize = 0;
77 958 : if( !bAsNewAlreadyParsed )
78 958 : Next();
79 958 : rDef.SetDefinedAs();
80 958 : SbiToken eTok = Next();
81 958 : if( !bAsNewAlreadyParsed && eTok == NEW )
82 : {
83 28 : rDef.SetNew();
84 28 : eTok = Next();
85 : }
86 958 : switch( eTok )
87 : {
88 : case ANY:
89 0 : if( rDef.IsNew() )
90 0 : Error( SbERR_SYNTAX );
91 0 : eType = SbxVARIANT; break;
92 : case TINTEGER:
93 : case TLONG:
94 : case TSINGLE:
95 : case TDOUBLE:
96 : case TCURRENCY:
97 : case TDATE:
98 : case TSTRING:
99 : case TOBJECT:
100 : case _ERROR_:
101 : case TBOOLEAN:
102 : case TVARIANT:
103 : case TBYTE:
104 823 : if( rDef.IsNew() )
105 0 : Error( SbERR_SYNTAX );
106 823 : eType = (eTok==TBYTE) ? SbxBYTE : SbxDataType( eTok - TINTEGER + SbxINTEGER );
107 823 : if( eType == SbxSTRING )
108 : {
109 : // STRING*n ?
110 438 : if( Peek() == MUL )
111 : { // fixed size!
112 0 : Next();
113 0 : SbiConstExpression aSize( this );
114 0 : nSize = aSize.GetShortValue();
115 0 : if( nSize < 0 || (bVBASupportOn && nSize <= 0) )
116 0 : Error( SbERR_OUT_OF_RANGE );
117 : else
118 0 : rDef.SetFixedStringLength( nSize );
119 : }
120 : }
121 823 : break;
122 : case SYMBOL: // can only be a TYPE or a object class!
123 121 : if( eScanType != SbxVARIANT )
124 0 : Error( SbERR_SYNTAX );
125 : else
126 : {
127 121 : OUString aCompleteName = aSym;
128 :
129 : // #52709 DIM AS NEW for Uno with full-qualified name
130 121 : if( Peek() == DOT )
131 : {
132 15 : OUString aDotStr( '.' );
133 15 : while( Peek() == DOT )
134 : {
135 57 : aCompleteName += aDotStr;
136 57 : Next();
137 57 : SbiToken ePeekTok = Peek();
138 57 : if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
139 : {
140 57 : Next();
141 57 : aCompleteName += aSym;
142 : }
143 : else
144 : {
145 0 : Next();
146 0 : Error( SbERR_UNEXPECTED, SYMBOL );
147 0 : break;
148 : }
149 15 : }
150 : }
151 106 : else if( rEnumArray->Find( aCompleteName, SbxCLASS_OBJECT ) || ( IsVBASupportOn() && VBAConstantHelper::instance().isVBAConstantType( aCompleteName ) ) )
152 : {
153 0 : eType = SbxLONG;
154 0 : break;
155 : }
156 :
157 : // Take over in the string pool
158 121 : rDef.SetTypeId( aGblStrings.Add( aCompleteName ) );
159 :
160 121 : if( rDef.IsNew() && pProc == NULL )
161 0 : aRequiredTypes.push_back( aCompleteName );
162 : }
163 121 : eType = SbxOBJECT;
164 121 : break;
165 : case FIXSTRING: // new syntax for complex UNO types
166 14 : rDef.SetTypeId( aGblStrings.Add( aSym ) );
167 14 : eType = SbxOBJECT;
168 14 : break;
169 : default:
170 0 : Error( SbERR_UNEXPECTED, eTok );
171 0 : Next();
172 : }
173 : // The variable could have been declared with a suffix
174 958 : if( rDef.GetType() != SbxVARIANT )
175 : {
176 135 : if( rDef.GetType() != eType )
177 0 : Error( SbERR_VAR_DEFINED, rDef.GetName() );
178 135 : else if( eType == SbxSTRING && rDef.GetLen() != nSize )
179 0 : Error( SbERR_VAR_DEFINED, rDef.GetName() );
180 : }
181 958 : rDef.SetType( eType );
182 958 : rDef.SetLen( nSize );
183 : }
184 1450 : }
185 :
186 : // Here variables, arrays and structures were definied.
187 : // DIM/PRIVATE/PUBLIC/GLOBAL
188 :
189 788 : void SbiParser::Dim()
190 : {
191 788 : DefVar( _DIM, ( pProc && bVBASupportOn ) ? pProc->IsStatic() : false );
192 788 : }
193 :
194 789 : void SbiParser::DefVar( SbiOpcode eOp, bool bStatic )
195 : {
196 789 : SbiSymPool* pOldPool = pPool;
197 789 : bool bSwitchPool = false;
198 789 : bool bPersistantGlobal = false;
199 789 : SbiToken eFirstTok = eCurTok;
200 789 : if( pProc && ( eCurTok == GLOBAL || eCurTok == PUBLIC || eCurTok == PRIVATE ) )
201 0 : Error( SbERR_NOT_IN_SUBR, eCurTok );
202 789 : if( eCurTok == PUBLIC || eCurTok == GLOBAL )
203 : {
204 86 : bSwitchPool = true; // at the right moment switch to the global pool
205 86 : if( eCurTok == GLOBAL )
206 64 : bPersistantGlobal = true;
207 : }
208 : // behavior in VBA is that a module scope variable's lifetime is
209 : // tied to the document. e.g. a module scope variable is global
210 789 : if( GetBasic()->IsDocBasic() && bVBASupportOn && !pProc )
211 145 : bPersistantGlobal = true;
212 : // PRIVATE is a synonymous for DIM
213 : // _CONST_?
214 789 : bool bConst = false;
215 789 : if( eCurTok == _CONST_ )
216 30 : bConst = true;
217 759 : else if( Peek() == _CONST_ )
218 44 : Next(), bConst = true;
219 :
220 : // #110004 It can also be a sub/function
221 1476 : if( !bConst && (eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ||
222 1374 : eCurTok == STATIC || eCurTok == ENUM || eCurTok == DECLARE || eCurTok == TYPE) )
223 : {
224 : // Next token is read here, because !bConst
225 28 : bool bPrivate = ( eFirstTok == PRIVATE );
226 :
227 28 : if( eCurTok == STATIC )
228 : {
229 0 : Next();
230 0 : DefStatic( bPrivate );
231 : }
232 28 : else if( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY )
233 : {
234 : // End global chain if necessary (not done in
235 : // SbiParser::Parse() under these conditions
236 28 : if( bNewGblDefs && nGblChain == 0 )
237 : {
238 0 : nGblChain = aGen.Gen( _JUMP, 0 );
239 0 : bNewGblDefs = false;
240 : }
241 28 : Next();
242 28 : DefProc( false, bPrivate );
243 56 : return;
244 : }
245 0 : else if( eCurTok == ENUM )
246 : {
247 0 : Next();
248 0 : DefEnum( bPrivate );
249 0 : return;
250 : }
251 0 : else if( eCurTok == DECLARE )
252 : {
253 0 : Next();
254 0 : DefDeclare( bPrivate );
255 0 : return;
256 : }
257 : // #i109049
258 0 : else if( eCurTok == TYPE )
259 : {
260 0 : Next();
261 0 : DefType( bPrivate );
262 0 : return;
263 : }
264 : }
265 :
266 : #ifdef SHARED
267 : #define tmpSHARED
268 : #undef SHARED
269 : #endif
270 : // SHARED were ignored
271 761 : if( Peek() == SHARED ) Next();
272 : #ifdef tmpSHARED
273 : #define SHARED
274 : #undef tmpSHARED
275 : #endif
276 : // PRESERVE only at REDIM
277 761 : if( Peek() == PRESERVE )
278 : {
279 0 : Next();
280 0 : if( eOp == _REDIM )
281 0 : eOp = _REDIMP;
282 : else
283 0 : Error( SbERR_UNEXPECTED, eCurTok );
284 : }
285 : SbiSymDef* pDef;
286 : SbiDimList* pDim;
287 :
288 : // #40689, Statics -> Modul-Initialising, skip in Sub
289 761 : sal_uInt32 nEndOfStaticLbl = 0;
290 761 : if( !bVBASupportOn && bStatic )
291 : {
292 0 : nEndOfStaticLbl = aGen.Gen( _JUMP, 0 );
293 0 : aGen.Statement(); // catch up on static here
294 : }
295 :
296 761 : bool bDefined = false;
297 1618 : while( ( pDef = VarDecl( &pDim, bStatic, bConst ) ) != NULL )
298 : {
299 857 : EnableErrors();
300 : // search variable:
301 857 : if( bSwitchPool )
302 139 : pPool = &aGlobals;
303 857 : SbiSymDef* pOld = pPool->Find( pDef->GetName() );
304 : // search also in the Runtime-Library
305 857 : bool bRtlSym = false;
306 857 : if( !pOld )
307 : {
308 852 : pOld = CheckRTLForSym( pDef->GetName(), SbxVARIANT );
309 852 : if( pOld )
310 1 : bRtlSym = true;
311 : }
312 857 : if( pOld && !(eOp == _REDIM || eOp == _REDIMP) )
313 : {
314 5 : if( pDef->GetScope() == SbLOCAL && pOld->GetScope() != SbLOCAL )
315 5 : pOld = NULL;
316 : }
317 857 : if( pOld )
318 : {
319 1 : bDefined = true;
320 : // always an error at a RTL-S
321 1 : if( !bRtlSym && (eOp == _REDIM || eOp == _REDIMP) )
322 : {
323 : // compare the attributes at a REDIM
324 : SbxDataType eDefType;
325 1 : bool bError_ = false;
326 1 : if( pOld->IsStatic() )
327 : {
328 0 : bError_ = true;
329 : }
330 1 : else if( pOld->GetType() != ( eDefType = pDef->GetType() ) )
331 : {
332 0 : if( !( eDefType == SbxVARIANT && !pDef->IsDefinedAs() ) )
333 0 : bError_ = true;
334 : }
335 1 : if( bError_ )
336 0 : Error( SbERR_VAR_DEFINED, pDef->GetName() );
337 : }
338 : else
339 0 : Error( SbERR_VAR_DEFINED, pDef->GetName() );
340 1 : delete pDef; pDef = pOld;
341 : }
342 : else
343 856 : pPool->Add( pDef );
344 :
345 : // #36374: Create the variable in front of the distinction IsNew()
346 : // Otherwise error at Dim Identifier As New Type and option explicit
347 2570 : if( !bDefined && !(eOp == _REDIM || eOp == _REDIMP)
348 1713 : && ( !bConst || pDef->GetScope() == SbGLOBAL ) )
349 : {
350 : // Declare variable or global constant
351 : SbiOpcode eOp2;
352 820 : switch ( pDef->GetScope() )
353 : {
354 139 : case SbGLOBAL: eOp2 = bPersistantGlobal ? _GLOBAL_P : _GLOBAL;
355 139 : goto global;
356 121 : case SbPUBLIC: eOp2 = bPersistantGlobal ? _PUBLIC_P : _PUBLIC;
357 : // #40689, no own Opcode anymore
358 121 : if( bVBASupportOn && bStatic )
359 : {
360 0 : eOp2 = _STATIC;
361 0 : break;
362 : }
363 260 : global: aGen.BackChain( nGblChain );
364 260 : nGblChain = 0;
365 260 : bGblDefs = bNewGblDefs = true;
366 260 : break;
367 560 : default: eOp2 = _LOCAL;
368 : }
369 820 : sal_uInt32 nOpnd2 = sal::static_int_cast< sal_uInt16 >( pDef->GetType() );
370 820 : if( pDef->IsWithEvents() )
371 0 : nOpnd2 |= SBX_TYPE_WITH_EVENTS_FLAG;
372 :
373 820 : if( bCompatible && pDef->IsNew() )
374 1 : nOpnd2 |= SBX_TYPE_DIM_AS_NEW_FLAG;
375 :
376 820 : short nFixedStringLength = pDef->GetFixedStringLength();
377 820 : if( nFixedStringLength >= 0 )
378 0 : nOpnd2 |= (SBX_FIXED_LEN_STRING_FLAG + (sal_uInt32(nFixedStringLength) << 17)); // len = all bits above 0x10000
379 :
380 820 : if( pDim != NULL && pDim->GetDims() > 0 )
381 24 : nOpnd2 |= SBX_TYPE_VAR_TO_DIM_FLAG;
382 :
383 820 : aGen.Gen( eOp2, pDef->GetId(), nOpnd2 );
384 : }
385 :
386 : // Initialising for self-defined daty types
387 : // and per NEW created variable
388 1714 : if( pDef->GetType() == SbxOBJECT
389 857 : && pDef->GetTypeId() )
390 : {
391 130 : if( !bCompatible && !pDef->IsNew() )
392 : {
393 0 : OUString aTypeName( aGblStrings.Find( pDef->GetTypeId() ) );
394 0 : if( rTypeArray->Find( aTypeName, SbxCLASS_OBJECT ) == NULL )
395 : {
396 0 : Error( SbERR_UNDEF_TYPE, aTypeName );
397 0 : }
398 : }
399 :
400 130 : if( bConst )
401 : {
402 0 : Error( SbERR_SYNTAX );
403 : }
404 :
405 130 : if( pDim )
406 : {
407 4 : if( eOp == _REDIMP )
408 : {
409 0 : SbiExpression aExpr( this, *pDef, NULL );
410 0 : aExpr.Gen();
411 0 : aGen.Gen( _REDIMP_ERASE );
412 :
413 0 : pDef->SetDims( pDim->GetDims() );
414 0 : SbiExpression aExpr2( this, *pDef, pDim );
415 0 : aExpr2.Gen();
416 0 : aGen.Gen( _DCREATE_REDIMP, pDef->GetId(), pDef->GetTypeId() );
417 : }
418 : else
419 : {
420 4 : pDef->SetDims( pDim->GetDims() );
421 4 : SbiExpression aExpr( this, *pDef, pDim );
422 4 : aExpr.Gen();
423 4 : aGen.Gen( _DCREATE, pDef->GetId(), pDef->GetTypeId() );
424 : }
425 : }
426 : else
427 : {
428 126 : SbiExpression aExpr( this, *pDef );
429 126 : aExpr.Gen();
430 126 : SbiOpcode eOp_ = pDef->IsNew() ? _CREATE : _TCREATE;
431 126 : aGen.Gen( eOp_, pDef->GetId(), pDef->GetTypeId() );
432 126 : if ( bVBASupportOn )
433 103 : aGen.Gen( _VBASET );
434 : else
435 23 : aGen.Gen( _SET );
436 : }
437 : }
438 : else
439 : {
440 727 : if( bConst )
441 : {
442 : // Definition of the constants
443 125 : if( pDim )
444 : {
445 0 : Error( SbERR_SYNTAX );
446 0 : delete pDim;
447 : }
448 125 : SbiExpression aVar( this, *pDef );
449 125 : if( !TestToken( EQ ) )
450 0 : goto MyBreak; // (see below)
451 250 : SbiConstExpression aExpr( this );
452 125 : if( !bDefined && aExpr.IsValid() )
453 : {
454 125 : if( pDef->GetScope() == SbGLOBAL )
455 : {
456 : // Create code only for the global constant!
457 89 : aVar.Gen();
458 89 : aExpr.Gen();
459 89 : aGen.Gen( _PUTC );
460 : }
461 125 : SbiConstDef* pConst = pDef->GetConstDef();
462 125 : if( aExpr.GetType() == SbxSTRING )
463 64 : pConst->Set( aExpr.GetString() );
464 : else
465 61 : pConst->Set( aExpr.GetValue(), aExpr.GetType() );
466 125 : }
467 : }
468 602 : else if( pDim )
469 : {
470 : // Dimension the variable
471 : // Delete the var at REDIM beforehand
472 40 : if( eOp == _REDIM )
473 : {
474 1 : SbiExpression aExpr( this, *pDef, NULL );
475 1 : aExpr.Gen();
476 1 : if ( bVBASupportOn )
477 : // delete the array but
478 : // clear the variable ( this
479 : // allows the processing of
480 : // the param to happen as normal without errors ( ordinary ERASE just clears the array )
481 1 : aGen.Gen( _ERASE_CLEAR );
482 : else
483 0 : aGen.Gen( _ERASE );
484 : }
485 39 : else if( eOp == _REDIMP )
486 : {
487 0 : SbiExpression aExpr( this, *pDef, NULL );
488 0 : aExpr.Gen();
489 0 : aGen.Gen( _REDIMP_ERASE );
490 : }
491 40 : pDef->SetDims( pDim->GetDims() );
492 40 : if( bPersistantGlobal )
493 2 : pDef->SetGlobal( sal_True );
494 40 : SbiExpression aExpr( this, *pDef, pDim );
495 40 : aExpr.Gen();
496 40 : pDef->SetGlobal( sal_False );
497 40 : aGen.Gen( (eOp == _STATIC) ? _DIM : eOp );
498 : }
499 : }
500 857 : if( !TestComma() )
501 761 : goto MyBreak;
502 :
503 : // Implementation of bSwitchPool (see above): pPool must not be set to &aGlobals
504 : // at the VarDecl-Call.
505 : // Apart from that the behavior should be absolutely identical,
506 : // i.e., pPool had to be reset always at the end of the loop.
507 : // also at a break
508 96 : pPool = pOldPool;
509 96 : continue; // Skip MyBreak
510 : MyBreak:
511 761 : pPool = pOldPool;
512 761 : break;
513 : }
514 :
515 : // #40689, finalize the jump over statics declarations
516 761 : if( !bVBASupportOn && bStatic )
517 : {
518 : // maintain the global chain
519 0 : nGblChain = aGen.Gen( _JUMP, 0 );
520 0 : bGblDefs = bNewGblDefs = true;
521 :
522 : // Register for Sub a jump to the end of statics
523 0 : aGen.BackChain( nEndOfStaticLbl );
524 : }
525 :
526 : }
527 :
528 : // Here were Arrays redimensioned.
529 :
530 1 : void SbiParser::ReDim()
531 : {
532 1 : DefVar( _REDIM, ( pProc && bVBASupportOn ) ? pProc->IsStatic() : false );
533 1 : }
534 :
535 : // ERASE array, ...
536 :
537 0 : void SbiParser::Erase()
538 : {
539 0 : while( !bAbort )
540 : {
541 0 : SbiExpression aExpr( this, SbLVALUE );
542 0 : aExpr.Gen();
543 0 : aGen.Gen( _ERASE );
544 0 : if( !TestComma() ) break;
545 0 : }
546 0 : }
547 :
548 : // Declaration of a data type
549 :
550 0 : void SbiParser::Type()
551 : {
552 0 : DefType( false );
553 0 : }
554 :
555 0 : void SbiParser::DefType( bool bPrivate )
556 : {
557 : // TODO: Use bPrivate
558 : (void)bPrivate;
559 :
560 : // Read the new Token lesen. It had to be a symbol
561 0 : if (!TestSymbol())
562 0 : return;
563 :
564 0 : if (rTypeArray->Find(aSym,SbxCLASS_OBJECT))
565 : {
566 0 : Error( SbERR_VAR_DEFINED, aSym );
567 0 : return;
568 : }
569 :
570 0 : SbxObject *pType = new SbxObject(aSym);
571 :
572 : SbiSymDef* pElem;
573 0 : SbiDimList* pDim = NULL;
574 0 : bool bDone = false;
575 :
576 0 : while( !bDone && !IsEof() )
577 : {
578 0 : switch( Peek() )
579 : {
580 : case ENDTYPE :
581 0 : pElem = NULL;
582 0 : bDone = true;
583 0 : Next();
584 0 : break;
585 :
586 : case EOLN :
587 : case REM :
588 0 : pElem = NULL;
589 0 : Next();
590 0 : break;
591 :
592 : default:
593 0 : pElem = VarDecl(&pDim, false, false);
594 0 : if( !pElem )
595 0 : bDone = true; // Error occurred
596 : }
597 0 : if( pElem )
598 : {
599 0 : SbxArray *pTypeMembers = pType->GetProperties();
600 0 : OUString aElemName = pElem->GetName();
601 0 : if( pTypeMembers->Find( aElemName, SbxCLASS_DONTCARE) )
602 : {
603 0 : Error (SbERR_VAR_DEFINED);
604 : }
605 : else
606 : {
607 0 : SbxDataType eElemType = pElem->GetType();
608 0 : SbxProperty *pTypeElem = new SbxProperty( aElemName, eElemType );
609 0 : if( pDim )
610 : {
611 0 : SbxDimArray* pArray = new SbxDimArray( pElem->GetType() );
612 0 : if ( pDim->GetSize() )
613 : {
614 : // Dimension the target array
615 :
616 0 : for ( short i=0; i<pDim->GetSize();++i )
617 : {
618 0 : sal_Int32 lb = nBase;
619 0 : SbiExprNode* pNode = pDim->Get(i)->GetExprNode();
620 0 : sal_Int32 ub = pNode->GetNumber();
621 0 : if ( !pDim->Get( i )->IsBased() ) // each dim is low/up
622 : {
623 0 : if ( ++i >= pDim->GetSize() ) // trouble
624 0 : StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
625 0 : pNode = pDim->Get(i)->GetExprNode();
626 0 : lb = ub;
627 0 : ub = pNode->GetNumber();
628 : }
629 0 : else if ( !bCompatible )
630 0 : ub += nBase;
631 0 : pArray->AddDim32( lb, ub );
632 : }
633 0 : pArray->setHasFixedSize( true );
634 : }
635 : else
636 0 : pArray->unoAddDim( 0, -1 ); // variant array
637 0 : sal_uInt16 nSavFlags = pTypeElem->GetFlags();
638 : // need to reset the FIXED flag
639 : // when calling PutObject ( because the type will not match Object )
640 0 : pTypeElem->ResetFlag( SBX_FIXED );
641 0 : pTypeElem->PutObject( pArray );
642 0 : pTypeElem->SetFlags( nSavFlags );
643 : }
644 : // Nested user type?
645 0 : if( eElemType == SbxOBJECT )
646 : {
647 0 : sal_uInt16 nElemTypeId = pElem->GetTypeId();
648 0 : if( nElemTypeId != 0 )
649 : {
650 0 : OUString aTypeName( aGblStrings.Find( nElemTypeId ) );
651 0 : SbxObject* pTypeObj = static_cast< SbxObject* >( rTypeArray->Find( aTypeName, SbxCLASS_OBJECT ) );
652 0 : if( pTypeObj != NULL )
653 : {
654 0 : SbxObject* pCloneObj = cloneTypeObjectImpl( *pTypeObj );
655 0 : pTypeElem->PutObject( pCloneObj );
656 0 : }
657 : }
658 : }
659 0 : pTypeMembers->Insert( pTypeElem, pTypeMembers->Count() );
660 : }
661 0 : delete pDim, pDim = NULL;
662 0 : delete pElem;
663 : }
664 : }
665 :
666 0 : pType->Remove( OUString("Name"), SbxCLASS_DONTCARE );
667 0 : pType->Remove( OUString("Parent"), SbxCLASS_DONTCARE );
668 :
669 0 : rTypeArray->Insert (pType,rTypeArray->Count());
670 : }
671 :
672 :
673 : // Declaration of Enum type
674 :
675 0 : void SbiParser::Enum()
676 : {
677 0 : DefEnum( false );
678 0 : }
679 :
680 0 : void SbiParser::DefEnum( bool bPrivate )
681 : {
682 : // Read a the new Token. It had to be a symbol
683 0 : if (!TestSymbol())
684 0 : return;
685 :
686 0 : OUString aEnumName = aSym;
687 0 : if( rEnumArray->Find(aEnumName,SbxCLASS_OBJECT) )
688 : {
689 0 : Error( SbERR_VAR_DEFINED, aSym );
690 0 : return;
691 : }
692 :
693 0 : SbxObject *pEnum = new SbxObject( aEnumName );
694 0 : if( bPrivate )
695 : {
696 0 : pEnum->SetFlag( SBX_PRIVATE );
697 : }
698 : SbiSymDef* pElem;
699 : SbiDimList* pDim;
700 0 : bool bDone = false;
701 :
702 : // Starting with -1 to make first default value 0 after ++
703 0 : sal_Int32 nCurrentEnumValue = -1;
704 0 : while( !bDone && !IsEof() )
705 : {
706 0 : switch( Peek() )
707 : {
708 : case ENDENUM :
709 0 : pElem = NULL;
710 0 : bDone = true;
711 0 : Next();
712 0 : break;
713 :
714 : case EOLN :
715 : case REM :
716 0 : pElem = NULL;
717 0 : Next();
718 0 : break;
719 :
720 : default:
721 : {
722 : // TODO: Check existing!
723 0 : bool bDefined = false;
724 :
725 0 : pDim = NULL;
726 0 : pElem = VarDecl( &pDim, false, true );
727 0 : if( !pElem )
728 : {
729 0 : bDone = true; // Error occurred
730 0 : break;
731 : }
732 0 : else if( pDim )
733 : {
734 0 : delete pDim;
735 0 : Error( SbERR_SYNTAX );
736 0 : bDone = true; // Error occurred
737 0 : break;
738 : }
739 :
740 0 : SbiExpression aVar( this, *pElem );
741 0 : if( Peek() == EQ )
742 : {
743 0 : Next();
744 :
745 0 : SbiConstExpression aExpr( this );
746 0 : if( !bDefined && aExpr.IsValid() )
747 : {
748 0 : SbxVariableRef xConvertVar = new SbxVariable();
749 0 : if( aExpr.GetType() == SbxSTRING )
750 0 : xConvertVar->PutString( aExpr.GetString() );
751 : else
752 0 : xConvertVar->PutDouble( aExpr.GetValue() );
753 :
754 0 : nCurrentEnumValue = xConvertVar->GetLong();
755 0 : }
756 : }
757 : else
758 0 : nCurrentEnumValue++;
759 :
760 0 : SbiSymPool* pPoolToUse = bPrivate ? pPool : &aGlobals;
761 :
762 0 : SbiSymDef* pOld = pPoolToUse->Find( pElem->GetName() );
763 0 : if( pOld )
764 : {
765 0 : Error( SbERR_VAR_DEFINED, pElem->GetName() );
766 0 : bDone = true; // Error occurred
767 0 : break;
768 : }
769 :
770 0 : pPool->Add( pElem );
771 :
772 0 : if( !bPrivate )
773 : {
774 0 : SbiOpcode eOp = _GLOBAL;
775 0 : aGen.BackChain( nGblChain );
776 0 : nGblChain = 0;
777 0 : bGblDefs = bNewGblDefs = true;
778 : aGen.Gen(
779 0 : eOp, pElem->GetId(),
780 0 : sal::static_int_cast< sal_uInt16 >( pElem->GetType() ) );
781 :
782 0 : aVar.Gen();
783 0 : sal_uInt16 nStringId = aGen.GetParser()->aGblStrings.Add( nCurrentEnumValue, SbxLONG );
784 0 : aGen.Gen( _NUMBER, nStringId );
785 0 : aGen.Gen( _PUTC );
786 : }
787 :
788 0 : SbiConstDef* pConst = pElem->GetConstDef();
789 0 : pConst->Set( nCurrentEnumValue, SbxLONG );
790 : }
791 : }
792 0 : if( pElem )
793 : {
794 0 : SbxArray *pEnumMembers = pEnum->GetProperties();
795 0 : SbxProperty *pEnumElem = new SbxProperty( pElem->GetName(), SbxLONG );
796 0 : pEnumElem->PutLong( nCurrentEnumValue );
797 0 : pEnumElem->ResetFlag( SBX_WRITE );
798 0 : pEnumElem->SetFlag( SBX_CONST );
799 0 : pEnumMembers->Insert( pEnumElem, pEnumMembers->Count() );
800 : }
801 : }
802 :
803 0 : pEnum->Remove( OUString("Name"), SbxCLASS_DONTCARE );
804 0 : pEnum->Remove( OUString("Parent"), SbxCLASS_DONTCARE );
805 :
806 0 : rEnumArray->Insert( pEnum, rEnumArray->Count() );
807 : }
808 :
809 :
810 : // Procedure-Declaration
811 : // the first Token is already read in (SUB/FUNCTION)
812 : // xxx Name [LIB "name"[ALIAS "name"]][(Parameter)][AS TYPE]
813 :
814 386 : SbiProcDef* SbiParser::ProcDecl( bool bDecl )
815 : {
816 386 : bool bFunc = ( eCurTok == FUNCTION );
817 386 : bool bProp = ( eCurTok == GET || eCurTok == SET || eCurTok == LET );
818 386 : if( !TestSymbol() ) return NULL;
819 386 : OUString aName( aSym );
820 386 : SbxDataType eType = eScanType;
821 386 : SbiProcDef* pDef = new SbiProcDef( this, aName, true );
822 386 : pDef->SetType( eType );
823 386 : if( Peek() == _CDECL_ )
824 : {
825 0 : Next(); pDef->SetCdecl();
826 : }
827 386 : if( Peek() == LIB )
828 : {
829 0 : Next();
830 0 : if( Next() == FIXSTRING )
831 : {
832 0 : pDef->GetLib() = aSym;
833 : }
834 : else
835 : {
836 0 : Error( SbERR_SYNTAX );
837 : }
838 : }
839 386 : if( Peek() == ALIAS )
840 : {
841 0 : Next();
842 0 : if( Next() == FIXSTRING )
843 : {
844 0 : pDef->GetAlias() = aSym;
845 : }
846 : else
847 : {
848 0 : Error( SbERR_SYNTAX );
849 : }
850 : }
851 386 : if( !bDecl )
852 : {
853 : // CDECL, LIB and ALIAS are invalid
854 386 : if( !pDef->GetLib().isEmpty() )
855 : {
856 0 : Error( SbERR_UNEXPECTED, LIB );
857 : }
858 386 : if( !pDef->GetAlias().isEmpty() )
859 : {
860 0 : Error( SbERR_UNEXPECTED, ALIAS );
861 : }
862 386 : if( pDef->IsCdecl() )
863 : {
864 0 : Error( SbERR_UNEXPECTED, _CDECL_ );
865 : }
866 386 : pDef->SetCdecl( false );
867 386 : pDef->GetLib() = "";
868 386 : pDef->GetAlias() = "";
869 : }
870 0 : else if( pDef->GetLib().isEmpty() )
871 : {
872 : // ALIAS and CDECL only together with LIB
873 0 : if( !pDef->GetAlias().isEmpty() )
874 : {
875 0 : Error( SbERR_UNEXPECTED, ALIAS );
876 : }
877 0 : if( pDef->IsCdecl() )
878 : {
879 0 : Error( SbERR_UNEXPECTED, _CDECL_ );
880 : }
881 0 : pDef->SetCdecl( false );
882 0 : pDef->GetAlias() = "";
883 : }
884 : // Brackets?
885 386 : if( Peek() == LPAREN )
886 : {
887 344 : Next();
888 344 : if( Peek() == RPAREN )
889 : {
890 252 : Next();
891 : }
892 : else
893 : {
894 : for(;;)
895 : {
896 207 : bool bByVal = false;
897 207 : bool bOptional = false;
898 207 : bool bParamArray = false;
899 458 : while( Peek() == BYVAL || Peek() == BYREF || Peek() == _OPTIONAL_ )
900 : {
901 44 : if( Peek() == BYVAL )
902 : {
903 4 : bByVal = true;
904 : }
905 40 : else if ( Peek() == BYREF )
906 : {
907 0 : bByVal = false;
908 : }
909 40 : else if ( Peek() == _OPTIONAL_ )
910 : {
911 40 : bOptional = true;
912 : }
913 44 : Next();
914 : }
915 207 : if( bCompatible && Peek() == PARAMARRAY )
916 : {
917 0 : if( bByVal || bOptional )
918 : {
919 0 : Error( SbERR_UNEXPECTED, PARAMARRAY );
920 : }
921 0 : Next();
922 0 : bParamArray = true;
923 : }
924 207 : SbiSymDef* pPar = VarDecl( NULL, false, false );
925 207 : if( !pPar )
926 : {
927 0 : break;
928 : }
929 207 : if( bByVal )
930 : {
931 4 : pPar->SetByVal();
932 : }
933 207 : if( bOptional )
934 : {
935 40 : pPar->SetOptional();
936 : }
937 207 : if( bParamArray )
938 : {
939 0 : pPar->SetParamArray();
940 : }
941 207 : pDef->GetParams().Add( pPar );
942 207 : SbiToken eTok = Next();
943 207 : if( eTok != COMMA && eTok != RPAREN )
944 : {
945 0 : bool bError2 = true;
946 0 : if( bOptional && bCompatible && eTok == EQ )
947 : {
948 0 : SbiConstExpression* pDefaultExpr = new SbiConstExpression( this );
949 0 : SbxDataType eType2 = pDefaultExpr->GetType();
950 :
951 : sal_uInt16 nStringId;
952 0 : if( eType2 == SbxSTRING )
953 : {
954 0 : nStringId = aGblStrings.Add( pDefaultExpr->GetString() );
955 : }
956 : else
957 : {
958 0 : nStringId = aGblStrings.Add( pDefaultExpr->GetValue(), eType2 );
959 : }
960 0 : pPar->SetDefaultId( nStringId );
961 0 : delete pDefaultExpr;
962 :
963 0 : eTok = Next();
964 0 : if( eTok == COMMA || eTok == RPAREN )
965 : {
966 0 : bError2 = false;
967 : }
968 : }
969 0 : if( bError2 )
970 : {
971 0 : Error( SbERR_EXPECTED, RPAREN );
972 0 : break;
973 : }
974 : }
975 207 : if( eTok == RPAREN )
976 : {
977 92 : break;
978 : }
979 115 : }
980 : }
981 : }
982 386 : TypeDecl( *pDef );
983 386 : if( eType != SbxVARIANT && pDef->GetType() != eType )
984 : {
985 0 : Error( SbERR_BAD_DECLARATION, aName );
986 : }
987 386 : if( pDef->GetType() == SbxVARIANT && !( bFunc || bProp ) )
988 : {
989 262 : pDef->SetType( SbxEMPTY );
990 : }
991 386 : return pDef;
992 : }
993 :
994 : // DECLARE
995 :
996 0 : void SbiParser::Declare()
997 : {
998 0 : DefDeclare( false );
999 0 : }
1000 :
1001 0 : void SbiParser::DefDeclare( bool bPrivate )
1002 : {
1003 0 : Next();
1004 0 : if( eCurTok != SUB && eCurTok != FUNCTION )
1005 : {
1006 0 : Error( SbERR_UNEXPECTED, eCurTok );
1007 : }
1008 : else
1009 : {
1010 0 : bool bFunction = (eCurTok == FUNCTION);
1011 :
1012 0 : SbiProcDef* pDef = ProcDecl( true );
1013 0 : if( pDef )
1014 : {
1015 0 : if( pDef->GetLib().isEmpty() )
1016 : {
1017 0 : Error( SbERR_EXPECTED, LIB );
1018 : }
1019 : // Is it already there?
1020 0 : SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1021 0 : if( pOld )
1022 : {
1023 0 : SbiProcDef* p = pOld->GetProcDef();
1024 0 : if( !p )
1025 : {
1026 : // Declared as a variable
1027 0 : Error( SbERR_BAD_DECLARATION, pDef->GetName() );
1028 0 : delete pDef;
1029 0 : pDef = NULL;
1030 : }
1031 : else
1032 : {
1033 0 : pDef->Match( p );
1034 : }
1035 : }
1036 : else
1037 : {
1038 0 : aPublics.Add( pDef );
1039 : }
1040 0 : if ( pDef )
1041 : {
1042 0 : pDef->SetPublic( !bPrivate );
1043 :
1044 : // New declare handling
1045 0 : if( !pDef->GetLib().isEmpty())
1046 : {
1047 0 : if( bNewGblDefs && nGblChain == 0 )
1048 : {
1049 0 : nGblChain = aGen.Gen( _JUMP, 0 );
1050 0 : bNewGblDefs = false;
1051 : }
1052 :
1053 0 : sal_uInt16 nSavLine = nLine;
1054 0 : aGen.Statement();
1055 0 : pDef->Define();
1056 0 : pDef->SetLine1( nSavLine );
1057 0 : pDef->SetLine2( nSavLine );
1058 :
1059 0 : SbiSymPool& rPool = pDef->GetParams();
1060 0 : sal_uInt16 nParCount = rPool.GetSize();
1061 :
1062 0 : SbxDataType eType = pDef->GetType();
1063 0 : if( bFunction )
1064 : {
1065 0 : aGen.Gen( _PARAM, 0, sal::static_int_cast< sal_uInt16 >( eType ) );
1066 : }
1067 0 : if( nParCount > 1 )
1068 : {
1069 0 : aGen.Gen( _ARGC );
1070 :
1071 0 : for( sal_uInt16 i = 1 ; i < nParCount ; ++i )
1072 : {
1073 0 : SbiSymDef* pParDef = rPool.Get( i );
1074 0 : SbxDataType eParType = pParDef->GetType();
1075 :
1076 0 : aGen.Gen( _PARAM, i, sal::static_int_cast< sal_uInt16 >( eParType ) );
1077 0 : aGen.Gen( _ARGV );
1078 :
1079 0 : sal_uInt16 nTyp = sal::static_int_cast< sal_uInt16 >( pParDef->GetType() );
1080 0 : if( pParDef->IsByVal() )
1081 : {
1082 : // Reset to avoid additional byval in call to wrapper function
1083 0 : pParDef->SetByVal( sal_False );
1084 0 : nTyp |= 0x8000;
1085 : }
1086 0 : aGen.Gen( _ARGTYP, nTyp );
1087 : }
1088 : }
1089 :
1090 0 : aGen.Gen( _LIB, aGblStrings.Add( pDef->GetLib() ) );
1091 :
1092 0 : SbiOpcode eOp = pDef->IsCdecl() ? _CALLC : _CALL;
1093 0 : sal_uInt16 nId = pDef->GetId();
1094 0 : if( !pDef->GetAlias().isEmpty() )
1095 : {
1096 0 : nId = ( nId & 0x8000 ) | aGblStrings.Add( pDef->GetAlias() );
1097 : }
1098 0 : if( nParCount > 1 )
1099 : {
1100 0 : nId |= 0x8000;
1101 : }
1102 0 : aGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( eType ) );
1103 :
1104 0 : if( bFunction )
1105 : {
1106 0 : aGen.Gen( _PUT );
1107 : }
1108 0 : aGen.Gen( _LEAVE );
1109 : }
1110 : }
1111 : }
1112 : }
1113 0 : }
1114 :
1115 0 : void SbiParser::Attribute()
1116 : {
1117 : // TODO: Need to implement the method as an attributed object.
1118 0 : while( Next() != EQ )
1119 : {
1120 0 : if( Next() != DOT)
1121 : {
1122 0 : break;
1123 : }
1124 : }
1125 :
1126 0 : if( eCurTok != EQ )
1127 : {
1128 0 : Error( SbERR_SYNTAX );
1129 : }
1130 : else
1131 : {
1132 0 : SbiExpression aValue( this );
1133 : }
1134 : // Don't generate any code - just discard it.
1135 0 : }
1136 :
1137 : // Call of a SUB or a FUNCTION
1138 :
1139 375 : void SbiParser::Call()
1140 : {
1141 375 : SbiExpression aVar( this, SbSYMBOL );
1142 375 : aVar.Gen( FORCE_CALL );
1143 375 : aGen.Gen( _GET );
1144 375 : }
1145 :
1146 : // SUB/FUNCTION
1147 :
1148 358 : void SbiParser::SubFunc()
1149 : {
1150 358 : DefProc( false, false );
1151 358 : }
1152 :
1153 : // Read in of a procedure
1154 :
1155 386 : void SbiParser::DefProc( bool bStatic, bool bPrivate )
1156 : {
1157 386 : sal_uInt16 l1 = nLine, l2 = nLine;
1158 386 : bool bSub = ( eCurTok == SUB );
1159 386 : bool bProperty = ( eCurTok == PROPERTY );
1160 386 : PropertyMode ePropertyMode = PROPERTY_MODE_NONE;
1161 386 : if( bProperty )
1162 : {
1163 0 : Next();
1164 0 : if( eCurTok == GET )
1165 : {
1166 0 : ePropertyMode = PROPERTY_MODE_GET;
1167 : }
1168 0 : else if( eCurTok == LET )
1169 : {
1170 0 : ePropertyMode = PROPERTY_MODE_LET;
1171 : }
1172 0 : else if( eCurTok == SET )
1173 : {
1174 0 : ePropertyMode = PROPERTY_MODE_SET;
1175 : }
1176 : else
1177 : {
1178 0 : Error( SbERR_EXPECTED, "Get or Let or Set" );
1179 : }
1180 : }
1181 :
1182 386 : SbiToken eExit = eCurTok;
1183 386 : SbiProcDef* pDef = ProcDecl( false );
1184 386 : if( !pDef )
1185 : {
1186 0 : return;
1187 : }
1188 386 : pDef->setPropertyMode( ePropertyMode );
1189 :
1190 : // Is the Proc already declared?
1191 386 : SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1192 386 : if( pOld )
1193 : {
1194 208 : bool bError_ = false;
1195 :
1196 208 : pProc = pOld->GetProcDef();
1197 208 : if( !pProc )
1198 : {
1199 : // Declared as a variable
1200 0 : Error( SbERR_BAD_DECLARATION, pDef->GetName() );
1201 0 : delete pDef;
1202 0 : pProc = NULL;
1203 0 : bError_ = true;
1204 : }
1205 : // #100027: Multiple declaration -> Error
1206 : // #112787: Not for setup, REMOVE for 8
1207 208 : else if( pProc->IsUsedForProcDecl() )
1208 : {
1209 0 : PropertyMode ePropMode = pDef->getPropertyMode();
1210 0 : if( ePropMode == PROPERTY_MODE_NONE || ePropMode == pProc->getPropertyMode() )
1211 : {
1212 0 : Error( SbERR_PROC_DEFINED, pDef->GetName() );
1213 0 : delete pDef;
1214 0 : pProc = NULL;
1215 0 : bError_ = true;
1216 : }
1217 : }
1218 :
1219 208 : if( !bError_ )
1220 : {
1221 208 : pDef->Match( pProc );
1222 208 : pProc = pDef;
1223 : }
1224 : }
1225 : else
1226 : {
1227 178 : aPublics.Add( pDef ), pProc = pDef;
1228 : }
1229 386 : if( !pProc )
1230 : {
1231 0 : return;
1232 : }
1233 386 : pProc->SetPublic( !bPrivate );
1234 :
1235 : // Now we set the search hierarchy for symbols as well as the
1236 : // current procedure.
1237 386 : aPublics.SetProcId( pProc->GetId() );
1238 386 : pProc->GetParams().SetParent( &aPublics );
1239 386 : if( bStatic )
1240 : {
1241 0 : if ( bVBASupportOn )
1242 : {
1243 0 : pProc->SetStatic( sal_True );
1244 : }
1245 : else
1246 : {
1247 0 : Error( SbERR_NOT_IMPLEMENTED ); // STATIC SUB ...
1248 : }
1249 : }
1250 : else
1251 : {
1252 386 : pProc->SetStatic( sal_False );
1253 : }
1254 : // Normal case: Local variable->parameter->global variable
1255 386 : pProc->GetLocals().SetParent( &pProc->GetParams() );
1256 386 : pPool = &pProc->GetLocals();
1257 :
1258 386 : pProc->Define();
1259 386 : OpenBlock( eExit );
1260 386 : StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) );
1261 386 : l2 = nLine;
1262 386 : pProc->SetLine1( l1 );
1263 386 : pProc->SetLine2( l2 );
1264 386 : pPool = &aPublics;
1265 386 : aPublics.SetProcId( 0 );
1266 : // Open labels?
1267 386 : pProc->GetLabels().CheckRefs();
1268 386 : CloseBlock();
1269 386 : aGen.Gen( _LEAVE );
1270 386 : pProc = NULL;
1271 : }
1272 :
1273 : // STATIC variable|procedure
1274 :
1275 0 : void SbiParser::Static()
1276 : {
1277 0 : DefStatic( false );
1278 0 : }
1279 :
1280 0 : void SbiParser::DefStatic( bool bPrivate )
1281 : {
1282 : SbiSymPool* p;
1283 :
1284 0 : switch( Peek() )
1285 : {
1286 : case SUB:
1287 : case FUNCTION:
1288 : case PROPERTY:
1289 : // End global chain if necessary (not done in
1290 : // SbiParser::Parse() under these conditions
1291 0 : if( bNewGblDefs && nGblChain == 0 )
1292 : {
1293 0 : nGblChain = aGen.Gen( _JUMP, 0 );
1294 0 : bNewGblDefs = false;
1295 : }
1296 0 : Next();
1297 0 : DefProc( true, bPrivate );
1298 0 : break;
1299 : default:
1300 0 : if( !pProc )
1301 : {
1302 0 : Error( SbERR_NOT_IN_SUBR );
1303 : }
1304 : // Reset the Pool, so that STATIC-Declarations go into the
1305 : // global Pool
1306 0 : p = pPool;
1307 0 : pPool = &aPublics;
1308 0 : DefVar( _STATIC, true );
1309 0 : pPool = p;
1310 0 : break;
1311 : }
1312 0 : }
1313 :
1314 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|