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