cid#1636693 COPY_INSTEAD_OF_MOVE
[LibreOffice.git] / basic / source / comp / parser.cxx
blob73896f616df3b2b9863cfbf290888656656a01d8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <basic/sberrors.hxx>
21 #include <basic/sbxmeth.hxx>
22 #include <basic/sbmod.hxx>
23 #include <basic/sbstar.hxx>
24 #include <basic/sbx.hxx>
25 #include <parser.hxx>
26 #include <com/sun/star/script/ModuleType.hpp>
27 #include <rtl/character.hxx>
29 struct SbiParseStack { // "Stack" for statement-blocks
30 SbiParseStack* pNext; // Chain
31 SbiExprNode* pWithVar;
32 SbiToken eExitTok;
33 sal_uInt32 nChain; // JUMP-Chain
36 namespace {
38 struct SbiStatement {
39 SbiToken eTok;
40 void( SbiParser::*Func )();
41 bool bMain; // true: OK outside the SUB
42 bool bSubr; // true: OK inside the SUB
47 #define Y true
48 #define N false
50 const SbiStatement StmntTable [] = {
51 { ATTRIBUTE, &SbiParser::Attribute, Y, Y, }, // ATTRIBUTE
52 { CALL, &SbiParser::Call, N, Y, }, // CALL
53 { CLOSE, &SbiParser::Close, N, Y, }, // CLOSE
54 { CONST_, &SbiParser::Dim, Y, Y, }, // CONST
55 { DECLARE, &SbiParser::Declare, Y, N, }, // DECLARE
56 { DEFBOOL, &SbiParser::DefXXX, Y, N, }, // DEFBOOL
57 { DEFCUR, &SbiParser::DefXXX, Y, N, }, // DEFCUR
58 { DEFDATE, &SbiParser::DefXXX, Y, N, }, // DEFDATE
59 { DEFDBL, &SbiParser::DefXXX, Y, N, }, // DEFDBL
60 { DEFERR, &SbiParser::DefXXX, Y, N, }, // DEFERR
61 { DEFINT, &SbiParser::DefXXX, Y, N, }, // DEFINT
62 { DEFLNG, &SbiParser::DefXXX, Y, N, }, // DEFLNG
63 { DEFOBJ, &SbiParser::DefXXX, Y, N, }, // DEFOBJ
64 { DEFSNG, &SbiParser::DefXXX, Y, N, }, // DEFSNG
65 { DEFSTR, &SbiParser::DefXXX, Y, N, }, // DEFSTR
66 { DEFVAR, &SbiParser::DefXXX, Y, N, }, // DEFVAR
67 { DIM, &SbiParser::Dim, Y, Y, }, // DIM
68 { DO, &SbiParser::DoLoop, N, Y, }, // DO
69 { ELSE, &SbiParser::NoIf, N, Y, }, // ELSE
70 { ELSEIF, &SbiParser::NoIf, N, Y, }, // ELSEIF
71 { ENDIF, &SbiParser::NoIf, N, Y, }, // ENDIF
72 { END, &SbiParser::Stop, N, Y, }, // END
73 { ENUM, &SbiParser::Enum, Y, N, }, // TYPE
74 { ERASE, &SbiParser::Erase, N, Y, }, // ERASE
75 { ERROR_, &SbiParser::ErrorStmnt, N, Y, }, // ERROR
76 { EXIT, &SbiParser::Exit, N, Y, }, // EXIT
77 { FOR, &SbiParser::For, N, Y, }, // FOR
78 { FUNCTION, &SbiParser::SubFunc, Y, N, }, // FUNCTION
79 { GOSUB, &SbiParser::Goto, N, Y, }, // GOSUB
80 { GLOBAL, &SbiParser::Dim, Y, N, }, // GLOBAL
81 { GOTO, &SbiParser::Goto, N, Y, }, // GOTO
82 { IF, &SbiParser::If, N, Y, }, // IF
83 { IMPLEMENTS, &SbiParser::Implements, Y, N, }, // IMPLEMENTS
84 { INPUT, &SbiParser::Input, N, Y, }, // INPUT
85 { LET, &SbiParser::Assign, N, Y, }, // LET
86 { LINE, &SbiParser::Line, N, Y, }, // LINE, -> LINE INPUT (#i92642)
87 { LINEINPUT,&SbiParser::LineInput, N, Y, }, // LINE INPUT
88 { LOOP, &SbiParser::BadBlock, N, Y, }, // LOOP
89 { LSET, &SbiParser::LSet, N, Y, }, // LSET
90 { NAME, &SbiParser::Name, N, Y, }, // NAME
91 { NEXT, &SbiParser::BadBlock, N, Y, }, // NEXT
92 { ON, &SbiParser::On, N, Y, }, // ON
93 { OPEN, &SbiParser::Open, N, Y, }, // OPEN
94 { OPTION, &SbiParser::Option, Y, N, }, // OPTION
95 { PRINT, &SbiParser::Print, N, Y, }, // PRINT
96 { PRIVATE, &SbiParser::Dim, Y, N, }, // PRIVATE
97 { PROPERTY, &SbiParser::SubFunc, Y, N, }, // FUNCTION
98 { PUBLIC, &SbiParser::Dim, Y, N, }, // PUBLIC
99 { REDIM, &SbiParser::ReDim, N, Y, }, // DIM
100 { RESUME, &SbiParser::Resume, N, Y, }, // RESUME
101 { RETURN, &SbiParser::Return, N, Y, }, // RETURN
102 { RSET, &SbiParser::RSet, N, Y, }, // RSET
103 { SELECT, &SbiParser::Select, N, Y, }, // SELECT
104 { SET, &SbiParser::Set, N, Y, }, // SET
105 { STATIC, &SbiParser::Static, Y, Y, }, // STATIC
106 { STOP, &SbiParser::Stop, N, Y, }, // STOP
107 { SUB, &SbiParser::SubFunc, Y, N, }, // SUB
108 { TYPE, &SbiParser::Type, Y, N, }, // TYPE
109 { UNTIL, &SbiParser::BadBlock, N, Y, }, // UNTIL
110 { WHILE, &SbiParser::While, N, Y, }, // WHILE
111 { WEND, &SbiParser::BadBlock, N, Y, }, // WEND
112 { WITH, &SbiParser::With, N, Y, }, // WITH
113 { WRITE, &SbiParser::Write, N, Y, }, // WRITE
115 { NIL, nullptr, N, N }
118 SbiParser::SbiParser( StarBASIC* pb, SbModule* pm )
119 : SbiTokenizer( pm->GetSource32(), pb ),
120 pStack(nullptr),
121 pProc(nullptr),
122 pWithVar(nullptr),
123 eEndTok(NIL),
124 bGblDefs(false),
125 bNewGblDefs(false),
126 bSingleLineIf(false),
127 bCodeCompleting(false),
128 aGlobals( aGblStrings, SbGLOBAL, this ),
129 aPublics( aGblStrings, SbPUBLIC, this ),
130 aRtlSyms( aGblStrings, SbRTL, this ),
131 aGen( *pm, this ),
132 nBase(0),
133 bExplicit(false)
135 bClassModule = ( pm->GetModuleType() == css::script::ModuleType::CLASS );
136 pPool = &aPublics;
137 for(SbxDataType & eDefType : eDefTypes)
138 eDefType = SbxVARIANT; // no explicit default type
140 aPublics.SetParent( &aGlobals );
141 aGlobals.SetParent( &aRtlSyms );
144 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
146 rTypeArray = new SbxArray; // array for user defined types
147 rEnumArray = new SbxArray; // array for Enum types
148 bVBASupportOn = pm->IsVBASupport();
149 if ( bVBASupportOn )
150 EnableCompatibility();
154 SbiParser::~SbiParser() { }
156 // part of the runtime-library?
157 SbiSymDef* SbiParser::CheckRTLForSym(const OUString& rSym, SbxDataType eType)
159 SbxVariable* pVar = GetBasic()->GetRtl()->Find(rSym, SbxClassType::DontCare);
160 if (!pVar)
161 return nullptr;
163 if (SbxMethod* pMethod = dynamic_cast<SbxMethod*>(pVar))
165 SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym );
166 if (pMethod->IsRuntimeFunction())
168 pProc_->SetType( pMethod->GetRuntimeFunctionReturnType() );
170 else
172 pProc_->SetType( pVar->GetType() );
174 return pProc_;
178 SbiSymDef* pDef = aRtlSyms.AddSym(rSym);
179 pDef->SetType(eType);
180 return pDef;
183 // close global chain
185 bool SbiParser::HasGlobalCode()
187 if( bGblDefs && nGblChain )
189 aGen.BackChain( nGblChain );
190 aGen.Gen( SbiOpcode::LEAVE_ );
191 nGblChain = 0;
193 return bGblDefs;
196 void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar )
198 SbiParseStack* p = new SbiParseStack;
199 p->eExitTok = (eTok == GET || eTok == LET || eTok == SET) ? PROPERTY : eTok; // #i109051
200 p->nChain = 0;
201 p->pWithVar = pWithVar;
202 p->pNext = pStack;
203 pStack = p;
204 pWithVar = pVar;
206 // #29955 service the for-loop level
207 if( eTok == FOR )
208 aGen.IncForLevel();
211 void SbiParser::CloseBlock()
213 if( !pStack )
214 return;
216 SbiParseStack* p = pStack;
218 // #29955 service the for-loop level
219 if( p->eExitTok == FOR )
220 aGen.DecForLevel();
222 aGen.BackChain( p->nChain );
223 pStack = p->pNext;
224 pWithVar = p->pWithVar;
225 delete p;
228 // EXIT ...
230 void SbiParser::Exit()
232 SbiToken eTok = Next();
233 for( SbiParseStack* p = pStack; p; p = p->pNext )
235 if (eTok == p->eExitTok)
237 p->nChain = aGen.Gen( SbiOpcode::JUMP_, p->nChain );
238 return;
241 if( pStack )
242 Error( ERRCODE_BASIC_EXPECTED, pStack->eExitTok );
243 else
244 Error( ERRCODE_BASIC_BAD_EXIT );
247 bool SbiParser::TestSymbol()
249 Peek();
250 if( eCurTok == SYMBOL )
252 Next(); return true;
254 Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
255 return false;
259 bool SbiParser::TestToken( SbiToken t )
261 if( Peek() == t )
263 Next(); return true;
265 else
267 Error( ERRCODE_BASIC_EXPECTED, t );
268 return false;
273 bool SbiParser::TestComma()
275 SbiToken eTok = Peek();
276 if( IsEoln( eTok ) )
278 Next();
279 return false;
281 else if( eTok != COMMA )
283 Error( ERRCODE_BASIC_EXPECTED, COMMA );
284 return false;
286 Next();
287 return true;
291 void SbiParser::TestEoln()
293 if( !IsEoln( Next() ) )
295 Error( ERRCODE_BASIC_EXPECTED, EOLN );
296 while( !IsEoln( Next() ) ) {}
301 void SbiParser::StmntBlock( SbiToken eEnd )
303 SbiToken xe = eEndTok;
304 eEndTok = eEnd;
305 while( !bAbort && Parse() ) {}
306 eEndTok = xe;
307 if( IsEof() )
309 Error( ERRCODE_BASIC_BAD_BLOCK, eEnd );
310 bAbort = true;
314 void SbiParser::SetCodeCompleting( bool b )
316 bCodeCompleting = b;
320 bool SbiParser::Parse()
322 if( bAbort ) return false;
324 EnableErrors();
326 bErrorIsSymbol = false;
327 Peek();
328 bErrorIsSymbol = true;
330 if( IsEof() )
332 // AB #33133: If no sub has been created before,
333 // the global chain must be closed here!
334 // AB #40689: Due to the new static-handling there
335 // can be another nGblChain, so ask for it before.
336 if( bNewGblDefs && nGblChain == 0 )
337 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
338 return false;
342 if( IsEoln( eCurTok ) )
344 Next(); return true;
347 if( !bSingleLineIf && MayBeLabel( true ) )
349 // is a label
350 if( !pProc )
351 Error( ERRCODE_BASIC_NOT_IN_MAIN, aSym );
352 else
353 pProc->GetLabels().Define( aSym );
354 Next(); Peek();
356 if( IsEoln( eCurTok ) )
358 Next(); return true;
362 // end of parsing?
363 if( eCurTok == eEndTok ||
364 ( bVBASupportOn && // #i109075
365 (eCurTok == ENDFUNC || eCurTok == ENDPROPERTY || eCurTok == ENDSUB) &&
366 (eEndTok == ENDFUNC || eEndTok == ENDPROPERTY || eEndTok == ENDSUB) ) )
368 Next();
369 if( eCurTok != NIL )
370 aGen.Statement();
371 return false;
374 // comment?
375 if( eCurTok == REM )
377 Next(); return true;
380 // In vba it's possible to do Error.foobar ( even if it results in
381 // a runtime error
382 if ( eCurTok == ERROR_ && IsVBASupportOn() ) // we probably need to define a subset of keywords where this madness applies e.g. if ( IsVBASupportOn() && SymbolCanBeRedined( eCurTok ) )
384 SbiTokenizer tokens( *this );
385 tokens.Next();
386 if ( tokens.Peek() == DOT )
388 eCurTok = SYMBOL;
389 ePush = eCurTok;
392 // if there's a symbol, it's either a variable (LET)
393 // or a SUB-procedure (CALL without brackets)
394 // DOT for assignments in the WITH-block: .A=5
395 if( eCurTok == SYMBOL || eCurTok == DOT )
397 if( !pProc )
398 Error( ERRCODE_BASIC_EXPECTED, SUB );
399 else
401 // for correct line and column...
402 Next();
403 Push( eCurTok );
404 aGen.Statement();
405 Symbol(nullptr);
408 else
410 Next();
412 // statement parsers
414 const SbiStatement* p;
415 for( p = StmntTable; p->eTok != NIL; p++ )
416 if( p->eTok == eCurTok )
417 break;
418 if( p->eTok != NIL )
420 if( !pProc && !p->bMain )
421 Error( ERRCODE_BASIC_NOT_IN_MAIN, eCurTok );
422 else if( pProc && !p->bSubr )
423 Error( ERRCODE_BASIC_NOT_IN_SUBR, eCurTok );
424 else
426 // AB #41606/#40689: Due to the new static-handling there
427 // can be another nGblChain, so ask for it before.
428 if( bNewGblDefs && nGblChain == 0 &&
429 ( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) )
431 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
432 bNewGblDefs = false;
434 // statement-opcode at the beginning of a sub, too, please
435 if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) ||
436 eCurTok == SUB || eCurTok == FUNCTION )
437 aGen.Statement();
438 (this->*( p->Func ) )();
439 ErrCode nSbxErr = SbxBase::GetError();
440 if( nSbxErr )
442 SbxBase::ResetError();
443 Error( nSbxErr );
447 else
448 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
451 // test for the statement's end -
452 // might also be an ELSE, as there must not necessary be a : before the ELSE!
454 if( !IsEos() )
456 Peek();
457 if( !IsEos() && eCurTok != ELSE )
459 // if the parsing has been aborted, jump over to the ":"
460 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
461 while( !IsEos() ) Next();
464 // The parser aborts at the end, the
465 // next token has not been fetched yet!
466 return true;
470 SbiExprNode* SbiParser::GetWithVar()
472 if( pWithVar )
473 return pWithVar;
475 SbiParseStack* p = pStack;
476 while( p )
478 // LoopVar can at the moment only be for with
479 if( p->pWithVar )
480 return p->pWithVar;
481 p = p->pNext;
483 return nullptr;
487 // assignment or subroutine call
489 void SbiParser::Symbol( const KeywordSymbolInfo* pKeywordSymbolInfo )
491 SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD;
492 SbiExpression aVar( this, SbSYMBOL, eMode, pKeywordSymbolInfo );
494 bool bEQ = ( Peek() == EQ );
495 if( !bEQ && bVBASupportOn && aVar.IsBracket() )
496 Error( ERRCODE_BASIC_EXPECTED, u"="_ustr );
498 RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL );
499 bool bSpecialMidHandling = false;
500 SbiSymDef* pDef = aVar.GetRealVar();
501 if( bEQ && pDef && pDef->GetScope() == SbRTL )
503 OUString aRtlName = pDef->GetName();
504 if( aRtlName.equalsIgnoreAsciiCase("Mid") )
506 SbiExprNode* pExprNode = aVar.GetExprNode();
507 if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL )
509 SbiExprList* pPar = pExprNode->GetParameters();
510 short nParCount = pPar ? pPar->GetSize() : 0;
511 if( nParCount == 2 || nParCount == 3 )
513 if( nParCount == 2 )
514 pPar->addExpression( std::make_unique<SbiExpression>( this, -1, SbxLONG ) );
516 TestToken( EQ );
517 pPar->addExpression( std::make_unique<SbiExpression>( this ) );
519 bSpecialMidHandling = true;
524 aVar.Gen( eRecMode );
525 if( bSpecialMidHandling )
526 return;
528 if( !bEQ )
530 aGen.Gen( SbiOpcode::GET_ );
532 else
534 // so it must be an assignment!
535 if( !aVar.IsLvalue() )
536 Error( ERRCODE_BASIC_LVALUE_EXPECTED );
537 TestToken( EQ );
538 SbiExpression aExpr( this );
539 aExpr.Gen();
540 SbiOpcode eOp = SbiOpcode::PUT_;
541 if( pDef )
543 if( pDef->GetConstDef() )
544 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
545 if( pDef->GetType() == SbxOBJECT )
547 eOp = SbiOpcode::SET_;
548 if( pDef->GetTypeId() )
550 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
551 return;
554 else if (auto nLen = pDef->GetLen()) // Dim s As String * 123 ' 123 -> nLen
556 aGen.Gen(SbiOpcode::PAD_, nLen);
559 aGen.Gen( eOp );
564 void SbiParser::Assign()
566 SbiExpression aLvalue( this, SbLVALUE );
567 TestToken( EQ );
568 SbiExpression aExpr( this );
569 aLvalue.Gen();
570 aExpr.Gen();
571 if (SbiSymDef* pDef = aLvalue.GetRealVar())
573 if( pDef->GetConstDef() )
574 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
575 if (auto nLen = pDef->GetLen()) // Dim s As String * 123 ' 123 -> nLen
577 aGen.Gen( SbiOpcode::PAD_, nLen );
580 aGen.Gen( SbiOpcode::PUT_ );
583 // assignments of an object-variable
585 void SbiParser::Set()
587 SbiExpression aLvalue( this, SbLVALUE );
588 SbxDataType eType = aLvalue.GetType();
589 if( eType != SbxOBJECT && eType != SbxEMPTY && eType != SbxVARIANT )
590 Error( ERRCODE_BASIC_INVALID_OBJECT );
591 TestToken( EQ );
592 SbiSymDef* pDef = aLvalue.GetRealVar();
593 if( pDef->GetConstDef() )
594 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
596 SbiToken eTok = Peek();
597 if( eTok == NEW )
599 Next();
600 SbiSymDef aTypeDef( u""_ustr );
601 TypeDecl( aTypeDef, true );
603 aLvalue.Gen();
604 aGen.Gen( SbiOpcode::CREATE_, pDef->GetId(), aTypeDef.GetTypeId() );
605 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
607 else
609 SbiExpression aExpr( this );
610 aLvalue.Gen();
611 aExpr.Gen();
612 // It's a good idea to distinguish between
613 // set something = another &
614 // something = another
615 // ( it's necessary for vba objects where set is object
616 // specific and also doesn't involve processing default params )
617 if( pDef->GetTypeId() )
619 if ( bVBASupportOn )
620 aGen.Gen( SbiOpcode::VBASETCLASS_, pDef->GetTypeId() );
621 else
622 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
624 else
626 if ( bVBASupportOn )
627 aGen.Gen( SbiOpcode::VBASET_ );
628 else
629 aGen.Gen( SbiOpcode::SET_ );
634 // JSM 07.10.95
635 void SbiParser::LSet()
637 SbiExpression aLvalue( this, SbLVALUE );
638 if( aLvalue.GetType() != SbxSTRING )
640 Error( ERRCODE_BASIC_INVALID_OBJECT );
642 TestToken( EQ );
643 SbiSymDef* pDef = aLvalue.GetRealVar();
644 if( pDef && pDef->GetConstDef() )
646 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
648 SbiExpression aExpr( this );
649 aLvalue.Gen();
650 aExpr.Gen();
651 aGen.Gen( SbiOpcode::LSET_ );
654 // JSM 07.10.95
655 void SbiParser::RSet()
657 SbiExpression aLvalue( this, SbLVALUE );
658 if( aLvalue.GetType() != SbxSTRING )
660 Error( ERRCODE_BASIC_INVALID_OBJECT );
662 TestToken( EQ );
663 SbiSymDef* pDef = aLvalue.GetRealVar();
664 if( pDef && pDef->GetConstDef() )
665 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
666 SbiExpression aExpr( this );
667 aLvalue.Gen();
668 aExpr.Gen();
669 aGen.Gen( SbiOpcode::RSET_ );
672 // DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR and so on
674 void SbiParser::DefXXX()
676 sal_Unicode ch1, ch2;
677 SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER );
679 while( !bAbort )
681 if( Next() != SYMBOL ) break;
682 ch1 = rtl::toAsciiUpperCase(aSym[0]);
683 ch2 = 0;
684 if( Peek() == MINUS )
686 Next();
687 if( Next() != SYMBOL ) Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
688 else
690 ch2 = rtl::toAsciiUpperCase(aSym[0]);
691 if( ch2 < ch1 )
693 Error( ERRCODE_BASIC_SYNTAX );
694 ch2 = 0;
698 if (!ch2) ch2 = ch1;
699 ch1 -= 'A'; ch2 -= 'A';
700 for (; ch1 <= ch2; ch1++) eDefTypes[ ch1 ] = t;
701 if( !TestComma() ) break;
705 // STOP/SYSTEM
707 void SbiParser::Stop()
709 aGen.Gen( SbiOpcode::STOP_ );
710 Peek(); // #35694: only Peek(), so that EOL is recognized in Single-Line-If
713 // IMPLEMENTS
715 void SbiParser::Implements()
717 if( !bClassModule )
719 Error( ERRCODE_BASIC_UNEXPECTED, IMPLEMENTS );
720 return;
723 Peek();
724 if( eCurTok != SYMBOL )
726 Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
727 return;
730 OUString aImplementedIface = aSym;
731 Next();
732 if( Peek() == DOT )
734 OUString aDotStr( '.' );
735 while( Peek() == DOT )
737 aImplementedIface += aDotStr;
738 Next();
739 SbiToken ePeekTok = Peek();
740 if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
742 Next();
743 aImplementedIface += aSym;
745 else
747 Next();
748 Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
749 break;
753 aIfaceVector.push_back( aImplementedIface );
756 void SbiParser::EnableCompatibility()
758 if( !bCompatible )
759 AddConstants();
760 bCompatible = true;
763 // OPTION
765 void SbiParser::Option()
767 switch( Next() )
769 case BASIC_EXPLICIT:
770 bExplicit = true; break;
771 case BASE:
772 if( Next() == NUMBER && ( nVal == 0 || nVal == 1 ) )
774 nBase = static_cast<short>(nVal);
775 break;
777 Error( ERRCODE_BASIC_EXPECTED, u"0/1"_ustr );
778 break;
779 case PRIVATE:
781 OUString aString = SbiTokenizer::Symbol(Next());
782 if( !aString.equalsIgnoreAsciiCase("Module") )
784 Error( ERRCODE_BASIC_EXPECTED, u"Module"_ustr );
786 break;
788 case COMPARE:
790 SbiToken eTok = Next();
791 if( eTok == BINARY )
794 else if( eTok == SYMBOL && GetSym().equalsIgnoreAsciiCase("text") )
797 else
799 Error( ERRCODE_BASIC_EXPECTED, u"Text/Binary"_ustr );
801 break;
803 case COMPATIBLE:
804 EnableCompatibility();
805 break;
807 case CLASSMODULE:
808 bClassModule = true;
809 aGen.GetModule().SetModuleType( css::script::ModuleType::CLASS );
810 break;
811 case VBASUPPORT: // Option VBASupport used to override the module mode ( in fact this must reset the mode
812 if( Next() == NUMBER )
814 if ( nVal == 1 || nVal == 0 )
816 bVBASupportOn = ( nVal == 1 );
817 if ( bVBASupportOn )
819 EnableCompatibility();
821 // if the module setting is different
822 // reset it to what the Option tells us
823 if ( bVBASupportOn != aGen.GetModule().IsVBASupport() )
825 aGen.GetModule().SetVBASupport( bVBASupportOn );
827 break;
830 Error( ERRCODE_BASIC_EXPECTED, u"0/1"_ustr );
831 break;
832 default:
833 Error( ERRCODE_BASIC_BAD_OPTION, eCurTok );
837 static void addStringConst( SbiSymPool& rPool, const OUString& pSym, const OUString& rStr )
839 SbiConstDef* pConst = new SbiConstDef( pSym );
840 pConst->SetType( SbxSTRING );
841 pConst->Set( rStr );
842 rPool.Add( pConst );
845 static void addNumericConst(SbiSymPool& rPool, const OUString& pSym, double nVal)
847 SbiConstDef* pConst = new SbiConstDef(pSym);
848 pConst->Set(nVal, SbxDOUBLE);
849 rPool.Add(pConst);
852 void SbiParser::AddConstants()
854 // tdf#153543 - shell constants
855 // See https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/shell-constants
856 addNumericConst(aPublics, u"vbHide"_ustr, 0);
857 addNumericConst(aPublics, u"vbNormalFocus"_ustr, 1);
858 addNumericConst(aPublics, u"vbMinimizedFocus"_ustr, 2);
859 addNumericConst(aPublics, u"vbMaximizedFocus"_ustr, 3);
860 addNumericConst(aPublics, u"vbNormalNoFocus"_ustr, 4);
861 addNumericConst(aPublics, u"vbMinimizedNoFocus"_ustr, 6);
863 // tdf#131563 - add vba color constants
864 // See https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/color-constants
865 addNumericConst(aPublics, u"vbBlack"_ustr, 0x0);
866 addNumericConst(aPublics, u"vbRed"_ustr, 0xFF);
867 addNumericConst(aPublics, u"vbGreen"_ustr, 0xFF00);
868 addNumericConst(aPublics, u"vbYellow"_ustr, 0xFFFF);
869 addNumericConst(aPublics, u"vbBlue"_ustr, 0xFF0000);
870 addNumericConst(aPublics, u"vbMagenta"_ustr, 0xFF00FF);
871 addNumericConst(aPublics, u"vbCyan"_ustr, 0xFFFF00);
872 addNumericConst(aPublics, u"vbWhite"_ustr, 0xFFFFFF);
874 // #113063 Create constant RTL symbols
875 addStringConst( aPublics, u"vbCr"_ustr, u"\x0D"_ustr );
876 addStringConst( aPublics, u"vbCrLf"_ustr, u"\x0D\x0A"_ustr );
877 addStringConst( aPublics, u"vbFormFeed"_ustr, u"\x0C"_ustr );
878 addStringConst( aPublics, u"vbLf"_ustr, u"\x0A"_ustr );
879 #ifdef _WIN32
880 addStringConst( aPublics, "vbNewLine", "\x0D\x0A" );
881 #else
882 addStringConst( aPublics, u"vbNewLine"_ustr, u"\x0A"_ustr );
883 #endif
884 addStringConst( aPublics, u"vbNullString"_ustr, u""_ustr );
885 addStringConst( aPublics, u"vbTab"_ustr, u"\x09"_ustr );
886 addStringConst( aPublics, u"vbVerticalTab"_ustr, u"\x0B"_ustr );
888 addStringConst( aPublics, u"vbNullChar"_ustr, OUString(u'\0') );
891 // ERROR n
893 void SbiParser::ErrorStmnt()
895 SbiExpression aPar( this );
896 aPar.Gen();
897 aGen.Gen( SbiOpcode::ERROR_ );
900 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */