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/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>
28
29 struct SbiParseStack { // "Stack" for statement-blocks
30 SbiParseStack* pNext; // Chain
31 SbiExprNode* pWithVar;
32 SbiToken eExitTok;
33 sal_uInt32 nChain; // JUMP-Chain
34 };
35
36 namespace {
37
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
43 };
44
45 }
46
47 #define Y true
48 #define N false
49
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
114
115 { NIL, nullptr, N, N }
116 };
117
SbiParser(StarBASIC * pb,SbModule * pm)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)
134 {
135 bClassModule = ( pm->GetModuleType() == css::script::ModuleType::CLASS );
136 pPool = &aPublics;
137 for(SbxDataType & eDefType : eDefTypes)
138 eDefType = SbxVARIANT; // no explicit default type
139
140 aPublics.SetParent( &aGlobals );
141 aGlobals.SetParent( &aRtlSyms );
142
143
144 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
145
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();
151
152 }
153
~SbiParser()154 SbiParser::~SbiParser() { }
155
156 // part of the runtime-library?
CheckRTLForSym(const OUString & rSym,SbxDataType eType)157 SbiSymDef* SbiParser::CheckRTLForSym(const OUString& rSym, SbxDataType eType)
158 {
159 SbxVariable* pVar = GetBasic()->GetRtl()->Find(rSym, SbxClassType::DontCare);
160 if (!pVar)
161 return nullptr;
162
163 if (SbxMethod* pMethod = dynamic_cast<SbxMethod*>(pVar))
164 {
165 SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym );
166 if (pMethod->IsRuntimeFunction())
167 {
168 pProc_->SetType( pMethod->GetRuntimeFunctionReturnType() );
169 }
170 else
171 {
172 pProc_->SetType( pVar->GetType() );
173 }
174 return pProc_;
175 }
176
177
178 SbiSymDef* pDef = aRtlSyms.AddSym(rSym);
179 pDef->SetType(eType);
180 return pDef;
181 }
182
183 // close global chain
184
HasGlobalCode()185 bool SbiParser::HasGlobalCode()
186 {
187 if( bGblDefs && nGblChain )
188 {
189 aGen.BackChain( nGblChain );
190 aGen.Gen( SbiOpcode::LEAVE_ );
191 nGblChain = 0;
192 }
193 return bGblDefs;
194 }
195
OpenBlock(SbiToken eTok,SbiExprNode * pVar)196 void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar )
197 {
198 SbiParseStack* p = new SbiParseStack;
199 p->eExitTok = eTok;
200 p->nChain = 0;
201 p->pWithVar = pWithVar;
202 p->pNext = pStack;
203 pStack = p;
204 pWithVar = pVar;
205
206 // #29955 service the for-loop level
207 if( eTok == FOR )
208 aGen.IncForLevel();
209 }
210
CloseBlock()211 void SbiParser::CloseBlock()
212 {
213 if( !pStack )
214 return;
215
216 SbiParseStack* p = pStack;
217
218 // #29955 service the for-loop level
219 if( p->eExitTok == FOR )
220 aGen.DecForLevel();
221
222 aGen.BackChain( p->nChain );
223 pStack = p->pNext;
224 pWithVar = p->pWithVar;
225 delete p;
226 }
227
228 // EXIT ...
229
Exit()230 void SbiParser::Exit()
231 {
232 SbiToken eTok = Next();
233 for( SbiParseStack* p = pStack; p; p = p->pNext )
234 {
235 SbiToken eExitTok = p->eExitTok;
236 if( eTok == eExitTok ||
237 (eTok == PROPERTY && (eExitTok == GET || eExitTok == LET) ) ) // #i109051
238 {
239 p->nChain = aGen.Gen( SbiOpcode::JUMP_, p->nChain );
240 return;
241 }
242 }
243 if( pStack )
244 Error( ERRCODE_BASIC_EXPECTED, pStack->eExitTok );
245 else
246 Error( ERRCODE_BASIC_BAD_EXIT );
247 }
248
TestSymbol()249 bool SbiParser::TestSymbol()
250 {
251 Peek();
252 if( eCurTok == SYMBOL )
253 {
254 Next(); return true;
255 }
256 Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
257 return false;
258 }
259
260
TestToken(SbiToken t)261 bool SbiParser::TestToken( SbiToken t )
262 {
263 if( Peek() == t )
264 {
265 Next(); return true;
266 }
267 else
268 {
269 Error( ERRCODE_BASIC_EXPECTED, t );
270 return false;
271 }
272 }
273
274
TestComma()275 bool SbiParser::TestComma()
276 {
277 SbiToken eTok = Peek();
278 if( IsEoln( eTok ) )
279 {
280 Next();
281 return false;
282 }
283 else if( eTok != COMMA )
284 {
285 Error( ERRCODE_BASIC_EXPECTED, COMMA );
286 return false;
287 }
288 Next();
289 return true;
290 }
291
292
TestEoln()293 void SbiParser::TestEoln()
294 {
295 if( !IsEoln( Next() ) )
296 {
297 Error( ERRCODE_BASIC_EXPECTED, EOLN );
298 while( !IsEoln( Next() ) ) {}
299 }
300 }
301
302
StmntBlock(SbiToken eEnd)303 void SbiParser::StmntBlock( SbiToken eEnd )
304 {
305 SbiToken xe = eEndTok;
306 eEndTok = eEnd;
307 while( !bAbort && Parse() ) {}
308 eEndTok = xe;
309 if( IsEof() )
310 {
311 Error( ERRCODE_BASIC_BAD_BLOCK, eEnd );
312 bAbort = true;
313 }
314 }
315
SetCodeCompleting(bool b)316 void SbiParser::SetCodeCompleting( bool b )
317 {
318 bCodeCompleting = b;
319 }
320
321
Parse()322 bool SbiParser::Parse()
323 {
324 if( bAbort ) return false;
325
326 EnableErrors();
327
328 bErrorIsSymbol = false;
329 Peek();
330 bErrorIsSymbol = true;
331
332 if( IsEof() )
333 {
334 // AB #33133: If no sub has been created before,
335 // the global chain must be closed here!
336 // AB #40689: Due to the new static-handling there
337 // can be another nGblChain, so ask for it before.
338 if( bNewGblDefs && nGblChain == 0 )
339 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
340 return false;
341 }
342
343
344 if( IsEoln( eCurTok ) )
345 {
346 Next(); return true;
347 }
348
349 if( !bSingleLineIf && MayBeLabel( true ) )
350 {
351 // is a label
352 if( !pProc )
353 Error( ERRCODE_BASIC_NOT_IN_MAIN, aSym );
354 else
355 pProc->GetLabels().Define( aSym );
356 Next(); Peek();
357
358 if( IsEoln( eCurTok ) )
359 {
360 Next(); return true;
361 }
362 }
363
364 // end of parsing?
365 if( eCurTok == eEndTok ||
366 ( bVBASupportOn && // #i109075
367 (eCurTok == ENDFUNC || eCurTok == ENDPROPERTY || eCurTok == ENDSUB) &&
368 (eEndTok == ENDFUNC || eEndTok == ENDPROPERTY || eEndTok == ENDSUB) ) )
369 {
370 Next();
371 if( eCurTok != NIL )
372 aGen.Statement();
373 return false;
374 }
375
376 // comment?
377 if( eCurTok == REM )
378 {
379 Next(); return true;
380 }
381
382 // In vba it's possible to do Error.foobar ( even if it results in
383 // a runtime error
384 if ( eCurTok == ERROR_ && IsVBASupportOn() ) // we probably need to define a subset of keywords where this madness applies e.g. if ( IsVBASupportOn() && SymbolCanBeRedined( eCurTok ) )
385 {
386 SbiTokenizer tokens( *this );
387 tokens.Next();
388 if ( tokens.Peek() == DOT )
389 {
390 eCurTok = SYMBOL;
391 ePush = eCurTok;
392 }
393 }
394 // if there's a symbol, it's either a variable (LET)
395 // or a SUB-procedure (CALL without brackets)
396 // DOT for assignments in the WITH-block: .A=5
397 if( eCurTok == SYMBOL || eCurTok == DOT )
398 {
399 if( !pProc )
400 Error( ERRCODE_BASIC_EXPECTED, SUB );
401 else
402 {
403 // for correct line and column...
404 Next();
405 Push( eCurTok );
406 aGen.Statement();
407 Symbol(nullptr);
408 }
409 }
410 else
411 {
412 Next();
413
414 // statement parsers
415
416 const SbiStatement* p;
417 for( p = StmntTable; p->eTok != NIL; p++ )
418 if( p->eTok == eCurTok )
419 break;
420 if( p->eTok != NIL )
421 {
422 if( !pProc && !p->bMain )
423 Error( ERRCODE_BASIC_NOT_IN_MAIN, eCurTok );
424 else if( pProc && !p->bSubr )
425 Error( ERRCODE_BASIC_NOT_IN_SUBR, eCurTok );
426 else
427 {
428 // AB #41606/#40689: Due to the new static-handling there
429 // can be another nGblChain, so ask for it before.
430 if( bNewGblDefs && nGblChain == 0 &&
431 ( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) )
432 {
433 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
434 bNewGblDefs = false;
435 }
436 // statement-opcode at the beginning of a sub, too, please
437 if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) ||
438 eCurTok == SUB || eCurTok == FUNCTION )
439 aGen.Statement();
440 (this->*( p->Func ) )();
441 ErrCode nSbxErr = SbxBase::GetError();
442 if( nSbxErr )
443 {
444 SbxBase::ResetError();
445 Error( nSbxErr );
446 }
447 }
448 }
449 else
450 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
451 }
452
453 // test for the statement's end -
454 // might also be an ELSE, as there must not necessary be a : before the ELSE!
455
456 if( !IsEos() )
457 {
458 Peek();
459 if( !IsEos() && eCurTok != ELSE )
460 {
461 // if the parsing has been aborted, jump over to the ":"
462 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
463 while( !IsEos() ) Next();
464 }
465 }
466 // The parser aborts at the end, the
467 // next token has not been fetched yet!
468 return true;
469 }
470
471
GetWithVar()472 SbiExprNode* SbiParser::GetWithVar()
473 {
474 if( pWithVar )
475 return pWithVar;
476
477 SbiParseStack* p = pStack;
478 while( p )
479 {
480 // LoopVar can at the moment only be for with
481 if( p->pWithVar )
482 return p->pWithVar;
483 p = p->pNext;
484 }
485 return nullptr;
486 }
487
488
489 // assignment or subroutine call
490
Symbol(const KeywordSymbolInfo * pKeywordSymbolInfo)491 void SbiParser::Symbol( const KeywordSymbolInfo* pKeywordSymbolInfo )
492 {
493 SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD;
494 SbiExpression aVar( this, SbSYMBOL, eMode, pKeywordSymbolInfo );
495
496 bool bEQ = ( Peek() == EQ );
497 if( !bEQ && bVBASupportOn && aVar.IsBracket() )
498 Error( ERRCODE_BASIC_EXPECTED, u"="_ustr );
499
500 RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL );
501 bool bSpecialMidHandling = false;
502 SbiSymDef* pDef = aVar.GetRealVar();
503 if( bEQ && pDef && pDef->GetScope() == SbRTL )
504 {
505 OUString aRtlName = pDef->GetName();
506 if( aRtlName.equalsIgnoreAsciiCase("Mid") )
507 {
508 SbiExprNode* pExprNode = aVar.GetExprNode();
509 if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL )
510 {
511 SbiExprList* pPar = pExprNode->GetParameters();
512 short nParCount = pPar ? pPar->GetSize() : 0;
513 if( nParCount == 2 || nParCount == 3 )
514 {
515 if( nParCount == 2 )
516 pPar->addExpression( std::make_unique<SbiExpression>( this, -1, SbxLONG ) );
517
518 TestToken( EQ );
519 pPar->addExpression( std::make_unique<SbiExpression>( this ) );
520
521 bSpecialMidHandling = true;
522 }
523 }
524 }
525 }
526 aVar.Gen( eRecMode );
527 if( bSpecialMidHandling )
528 return;
529
530 if( !bEQ )
531 {
532 aGen.Gen( SbiOpcode::GET_ );
533 }
534 else
535 {
536 // so it must be an assignment!
537 if( !aVar.IsLvalue() )
538 Error( ERRCODE_BASIC_LVALUE_EXPECTED );
539 TestToken( EQ );
540 SbiExpression aExpr( this );
541 aExpr.Gen();
542 SbiOpcode eOp = SbiOpcode::PUT_;
543 if( pDef )
544 {
545 if( pDef->GetConstDef() )
546 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
547 if( pDef->GetType() == SbxOBJECT )
548 {
549 eOp = SbiOpcode::SET_;
550 if( pDef->GetTypeId() )
551 {
552 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
553 return;
554 }
555 }
556 }
557 aGen.Gen( eOp );
558 }
559 }
560
561
Assign()562 void SbiParser::Assign()
563 {
564 SbiExpression aLvalue( this, SbLVALUE );
565 TestToken( EQ );
566 SbiExpression aExpr( this );
567 aLvalue.Gen();
568 aExpr.Gen();
569 sal_uInt16 nLen = 0;
570 SbiSymDef* pDef = aLvalue.GetRealVar();
571 {
572 if( pDef->GetConstDef() )
573 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
574 nLen = aLvalue.GetRealVar()->GetLen();
575 }
576 if( nLen )
577 aGen.Gen( SbiOpcode::PAD_, nLen );
578 aGen.Gen( SbiOpcode::PUT_ );
579 }
580
581 // assignments of an object-variable
582
Set()583 void SbiParser::Set()
584 {
585 SbiExpression aLvalue( this, SbLVALUE );
586 SbxDataType eType = aLvalue.GetType();
587 if( eType != SbxOBJECT && eType != SbxEMPTY && eType != SbxVARIANT )
588 Error( ERRCODE_BASIC_INVALID_OBJECT );
589 TestToken( EQ );
590 SbiSymDef* pDef = aLvalue.GetRealVar();
591 if( pDef->GetConstDef() )
592 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
593
594 SbiToken eTok = Peek();
595 if( eTok == NEW )
596 {
597 Next();
598 auto pTypeDef = std::make_unique<SbiSymDef>( OUString() );
599 TypeDecl( *pTypeDef, true );
600
601 aLvalue.Gen();
602 aGen.Gen( SbiOpcode::CREATE_, pDef->GetId(), pTypeDef->GetTypeId() );
603 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
604 }
605 else
606 {
607 SbiExpression aExpr( this );
608 aLvalue.Gen();
609 aExpr.Gen();
610 // It's a good idea to distinguish between
611 // set something = another &
612 // something = another
613 // ( it's necessary for vba objects where set is object
614 // specific and also doesn't involve processing default params )
615 if( pDef->GetTypeId() )
616 {
617 if ( bVBASupportOn )
618 aGen.Gen( SbiOpcode::VBASETCLASS_, pDef->GetTypeId() );
619 else
620 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
621 }
622 else
623 {
624 if ( bVBASupportOn )
625 aGen.Gen( SbiOpcode::VBASET_ );
626 else
627 aGen.Gen( SbiOpcode::SET_ );
628 }
629 }
630 }
631
632 // JSM 07.10.95
LSet()633 void SbiParser::LSet()
634 {
635 SbiExpression aLvalue( this, SbLVALUE );
636 if( aLvalue.GetType() != SbxSTRING )
637 {
638 Error( ERRCODE_BASIC_INVALID_OBJECT );
639 }
640 TestToken( EQ );
641 SbiSymDef* pDef = aLvalue.GetRealVar();
642 if( pDef && pDef->GetConstDef() )
643 {
644 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
645 }
646 SbiExpression aExpr( this );
647 aLvalue.Gen();
648 aExpr.Gen();
649 aGen.Gen( SbiOpcode::LSET_ );
650 }
651
652 // JSM 07.10.95
RSet()653 void SbiParser::RSet()
654 {
655 SbiExpression aLvalue( this, SbLVALUE );
656 if( aLvalue.GetType() != SbxSTRING )
657 {
658 Error( ERRCODE_BASIC_INVALID_OBJECT );
659 }
660 TestToken( EQ );
661 SbiSymDef* pDef = aLvalue.GetRealVar();
662 if( pDef && pDef->GetConstDef() )
663 Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
664 SbiExpression aExpr( this );
665 aLvalue.Gen();
666 aExpr.Gen();
667 aGen.Gen( SbiOpcode::RSET_ );
668 }
669
670 // DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR and so on
671
DefXXX()672 void SbiParser::DefXXX()
673 {
674 sal_Unicode ch1, ch2;
675 SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER );
676
677 while( !bAbort )
678 {
679 if( Next() != SYMBOL ) break;
680 ch1 = rtl::toAsciiUpperCase(aSym[0]);
681 ch2 = 0;
682 if( Peek() == MINUS )
683 {
684 Next();
685 if( Next() != SYMBOL ) Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
686 else
687 {
688 ch2 = rtl::toAsciiUpperCase(aSym[0]);
689 if( ch2 < ch1 )
690 {
691 Error( ERRCODE_BASIC_SYNTAX );
692 ch2 = 0;
693 }
694 }
695 }
696 if (!ch2) ch2 = ch1;
697 ch1 -= 'A'; ch2 -= 'A';
698 for (; ch1 <= ch2; ch1++) eDefTypes[ ch1 ] = t;
699 if( !TestComma() ) break;
700 }
701 }
702
703 // STOP/SYSTEM
704
Stop()705 void SbiParser::Stop()
706 {
707 aGen.Gen( SbiOpcode::STOP_ );
708 Peek(); // #35694: only Peek(), so that EOL is recognized in Single-Line-If
709 }
710
711 // IMPLEMENTS
712
Implements()713 void SbiParser::Implements()
714 {
715 if( !bClassModule )
716 {
717 Error( ERRCODE_BASIC_UNEXPECTED, IMPLEMENTS );
718 return;
719 }
720
721 Peek();
722 if( eCurTok != SYMBOL )
723 {
724 Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
725 return;
726 }
727
728 OUString aImplementedIface = aSym;
729 Next();
730 if( Peek() == DOT )
731 {
732 OUString aDotStr( '.' );
733 while( Peek() == DOT )
734 {
735 aImplementedIface += aDotStr;
736 Next();
737 SbiToken ePeekTok = Peek();
738 if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
739 {
740 Next();
741 aImplementedIface += aSym;
742 }
743 else
744 {
745 Next();
746 Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
747 break;
748 }
749 }
750 }
751 aIfaceVector.push_back( aImplementedIface );
752 }
753
EnableCompatibility()754 void SbiParser::EnableCompatibility()
755 {
756 if( !bCompatible )
757 AddConstants();
758 bCompatible = true;
759 }
760
761 // OPTION
762
Option()763 void SbiParser::Option()
764 {
765 switch( Next() )
766 {
767 case BASIC_EXPLICIT:
768 bExplicit = true; break;
769 case BASE:
770 if( Next() == NUMBER && ( nVal == 0 || nVal == 1 ) )
771 {
772 nBase = static_cast<short>(nVal);
773 break;
774 }
775 Error( ERRCODE_BASIC_EXPECTED, u"0/1"_ustr );
776 break;
777 case PRIVATE:
778 {
779 OUString aString = SbiTokenizer::Symbol(Next());
780 if( !aString.equalsIgnoreAsciiCase("Module") )
781 {
782 Error( ERRCODE_BASIC_EXPECTED, u"Module"_ustr );
783 }
784 break;
785 }
786 case COMPARE:
787 {
788 SbiToken eTok = Next();
789 if( eTok == BINARY )
790 {
791 }
792 else if( eTok == SYMBOL && GetSym().equalsIgnoreAsciiCase("text") )
793 {
794 }
795 else
796 {
797 Error( ERRCODE_BASIC_EXPECTED, u"Text/Binary"_ustr );
798 }
799 break;
800 }
801 case COMPATIBLE:
802 EnableCompatibility();
803 break;
804
805 case CLASSMODULE:
806 bClassModule = true;
807 aGen.GetModule().SetModuleType( css::script::ModuleType::CLASS );
808 break;
809 case VBASUPPORT: // Option VBASupport used to override the module mode ( in fact this must reset the mode
810 if( Next() == NUMBER )
811 {
812 if ( nVal == 1 || nVal == 0 )
813 {
814 bVBASupportOn = ( nVal == 1 );
815 if ( bVBASupportOn )
816 {
817 EnableCompatibility();
818 }
819 // if the module setting is different
820 // reset it to what the Option tells us
821 if ( bVBASupportOn != aGen.GetModule().IsVBASupport() )
822 {
823 aGen.GetModule().SetVBASupport( bVBASupportOn );
824 }
825 break;
826 }
827 }
828 Error( ERRCODE_BASIC_EXPECTED, u"0/1"_ustr );
829 break;
830 default:
831 Error( ERRCODE_BASIC_BAD_OPTION, eCurTok );
832 }
833 }
834
addStringConst(SbiSymPool & rPool,const OUString & pSym,const OUString & rStr)835 static void addStringConst( SbiSymPool& rPool, const OUString& pSym, const OUString& rStr )
836 {
837 SbiConstDef* pConst = new SbiConstDef( pSym );
838 pConst->SetType( SbxSTRING );
839 pConst->Set( rStr );
840 rPool.Add( pConst );
841 }
842
addNumericConst(SbiSymPool & rPool,const OUString & pSym,double nVal)843 static void addNumericConst(SbiSymPool& rPool, const OUString& pSym, double nVal)
844 {
845 SbiConstDef* pConst = new SbiConstDef(pSym);
846 pConst->Set(nVal, SbxDOUBLE);
847 rPool.Add(pConst);
848 }
849
AddConstants()850 void SbiParser::AddConstants()
851 {
852 // tdf#153543 - shell constants
853 // See https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/shell-constants
854 addNumericConst(aPublics, u"vbHide"_ustr, 0);
855 addNumericConst(aPublics, u"vbNormalFocus"_ustr, 1);
856 addNumericConst(aPublics, u"vbMinimizedFocus"_ustr, 2);
857 addNumericConst(aPublics, u"vbMaximizedFocus"_ustr, 3);
858 addNumericConst(aPublics, u"vbNormalNoFocus"_ustr, 4);
859 addNumericConst(aPublics, u"vbMinimizedNoFocus"_ustr, 6);
860
861 // tdf#131563 - add vba color constants
862 // See https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/color-constants
863 addNumericConst(aPublics, u"vbBlack"_ustr, 0x0);
864 addNumericConst(aPublics, u"vbRed"_ustr, 0xFF);
865 addNumericConst(aPublics, u"vbGreen"_ustr, 0xFF00);
866 addNumericConst(aPublics, u"vbYellow"_ustr, 0xFFFF);
867 addNumericConst(aPublics, u"vbBlue"_ustr, 0xFF0000);
868 addNumericConst(aPublics, u"vbMagenta"_ustr, 0xFF00FF);
869 addNumericConst(aPublics, u"vbCyan"_ustr, 0xFFFF00);
870 addNumericConst(aPublics, u"vbWhite"_ustr, 0xFFFFFF);
871
872 // #113063 Create constant RTL symbols
873 addStringConst( aPublics, u"vbCr"_ustr, u"\x0D"_ustr );
874 addStringConst( aPublics, u"vbCrLf"_ustr, u"\x0D\x0A"_ustr );
875 addStringConst( aPublics, u"vbFormFeed"_ustr, u"\x0C"_ustr );
876 addStringConst( aPublics, u"vbLf"_ustr, u"\x0A"_ustr );
877 #ifdef _WIN32
878 addStringConst( aPublics, "vbNewLine", "\x0D\x0A" );
879 #else
880 addStringConst( aPublics, u"vbNewLine"_ustr, u"\x0A"_ustr );
881 #endif
882 addStringConst( aPublics, u"vbNullString"_ustr, u""_ustr );
883 addStringConst( aPublics, u"vbTab"_ustr, u"\x09"_ustr );
884 addStringConst( aPublics, u"vbVerticalTab"_ustr, u"\x0B"_ustr );
885
886 addStringConst( aPublics, u"vbNullChar"_ustr, OUString(u'\0') );
887 }
888
889 // ERROR n
890
ErrorStmnt()891 void SbiParser::ErrorStmnt()
892 {
893 SbiExpression aPar( this );
894 aPar.Gen();
895 aGen.Gen( SbiOpcode::ERROR_ );
896 }
897
898 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
899