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