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