xref: /core/basic/source/comp/parser.cxx (revision 587ac01f)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <basic/sbx.hxx>
21 #include <parser.hxx>
22 #include <com/sun/star/script/ModuleType.hpp>
23 #include <svtools/miscopt.hxx>
24 #include <rtl/character.hxx>
25 
26 struct SbiParseStack {              // "Stack" for statement-blocks
27     SbiParseStack* pNext;           // Chain
28     SbiExprNode* pWithVar;
29     SbiToken eExitTok;
30     sal_uInt32  nChain;                 // JUMP-Chain
31 };
32 
33 struct SbiStatement {
34     SbiToken eTok;
35     void( SbiParser::*Func )();
36     bool  bMain;                    // true: OK outside the SUB
37     bool  bSubr;                    // true: OK inside the SUB
38 };
39 
40 #define Y   true
41 #define N   false
42 
43 static const SbiStatement StmntTable [] = {
44 { ATTRIBUTE, &SbiParser::Attribute, Y, Y, }, // ATTRIBUTE
45 { CALL,     &SbiParser::Call,       N, Y, }, // CALL
46 { CLOSE,    &SbiParser::Close,      N, Y, }, // CLOSE
47 { CONST_,   &SbiParser::Dim,        Y, Y, }, // CONST
48 { DECLARE,  &SbiParser::Declare,    Y, N, }, // DECLARE
49 { DEFBOOL,  &SbiParser::DefXXX,     Y, N, }, // DEFBOOL
50 { DEFCUR,   &SbiParser::DefXXX,     Y, N, }, // DEFCUR
51 { DEFDATE,  &SbiParser::DefXXX,     Y, N, }, // DEFDATE
52 { DEFDBL,   &SbiParser::DefXXX,     Y, N, }, // DEFDBL
53 { DEFERR,   &SbiParser::DefXXX,     Y, N, }, // DEFERR
54 { DEFINT,   &SbiParser::DefXXX,     Y, N, }, // DEFINT
55 { DEFLNG,   &SbiParser::DefXXX,     Y, N, }, // DEFLNG
56 { DEFOBJ,   &SbiParser::DefXXX,     Y, N, }, // DEFOBJ
57 { DEFSNG,   &SbiParser::DefXXX,     Y, N, }, // DEFSNG
58 { DEFSTR,   &SbiParser::DefXXX,     Y, N, }, // DEFSTR
59 { DEFVAR,   &SbiParser::DefXXX,     Y, N, }, // DEFVAR
60 { DIM,      &SbiParser::Dim,        Y, Y, }, // DIM
61 { DO,       &SbiParser::DoLoop,     N, Y, }, // DO
62 { ELSE,     &SbiParser::NoIf,       N, Y, }, // ELSE
63 { ELSEIF,   &SbiParser::NoIf,       N, Y, }, // ELSEIF
64 { ENDIF,    &SbiParser::NoIf,       N, Y, }, // ENDIF
65 { END,      &SbiParser::Stop,       N, Y, }, // END
66 { ENUM,     &SbiParser::Enum,       Y, N, }, // TYPE
67 { ERASE,    &SbiParser::Erase,      N, Y, }, // ERASE
68 { ERROR_,   &SbiParser::ErrorStmnt, N, Y, }, // ERROR
69 { EXIT,     &SbiParser::Exit,       N, Y, }, // EXIT
70 { FOR,      &SbiParser::For,        N, Y, }, // FOR
71 { FUNCTION, &SbiParser::SubFunc,    Y, N, }, // FUNCTION
72 { GOSUB,    &SbiParser::Goto,       N, Y, }, // GOSUB
73 { GLOBAL,   &SbiParser::Dim,        Y, N, }, // GLOBAL
74 { GOTO,     &SbiParser::Goto,       N, Y, }, // GOTO
75 { IF,       &SbiParser::If,         N, Y, }, // IF
76 { IMPLEMENTS, &SbiParser::Implements, Y, N, }, // IMPLEMENTS
77 { INPUT,    &SbiParser::Input,      N, Y, }, // INPUT
78 { LET,      &SbiParser::Assign,     N, Y, }, // LET
79 { LINE,     &SbiParser::Line,       N, Y, }, // LINE, -> LINE INPUT (#i92642)
80 { LINEINPUT,&SbiParser::LineInput,  N, Y, }, // LINE INPUT
81 { LOOP,     &SbiParser::BadBlock,   N, Y, }, // LOOP
82 { LSET,     &SbiParser::LSet,       N, Y, }, // LSET
83 { NAME,     &SbiParser::Name,       N, Y, }, // NAME
84 { NEXT,     &SbiParser::BadBlock,   N, Y, }, // NEXT
85 { ON,       &SbiParser::On,         N, Y, }, // ON
86 { OPEN,     &SbiParser::Open,       N, Y, }, // OPEN
87 { OPTION,   &SbiParser::Option,     Y, N, }, // OPTION
88 { PRINT,    &SbiParser::Print,      N, Y, }, // PRINT
89 { PRIVATE,  &SbiParser::Dim,        Y, N, }, // PRIVATE
90 { PROPERTY, &SbiParser::SubFunc,    Y, N, }, // FUNCTION
91 { PUBLIC,   &SbiParser::Dim,        Y, N, }, // PUBLIC
92 { REDIM,    &SbiParser::ReDim,      N, Y, }, // DIM
93 { RESUME,   &SbiParser::Resume,     N, Y, }, // RESUME
94 { RETURN,   &SbiParser::Return,     N, Y, }, // RETURN
95 { RSET,     &SbiParser::RSet,       N, Y, }, // RSET
96 { SELECT,   &SbiParser::Select,     N, Y, }, // SELECT
97 { SET,      &SbiParser::Set,        N, Y, }, // SET
98 { STATIC,   &SbiParser::Static,     Y, Y, }, // STATIC
99 { STOP,     &SbiParser::Stop,       N, Y, }, // STOP
100 { SUB,      &SbiParser::SubFunc,    Y, N, }, // SUB
101 { TYPE,     &SbiParser::Type,       Y, N, }, // TYPE
102 { UNTIL,    &SbiParser::BadBlock,   N, Y, }, // UNTIL
103 { WHILE,    &SbiParser::While,      N, Y, }, // WHILE
104 { WEND,     &SbiParser::BadBlock,   N, Y, }, // WEND
105 { WITH,     &SbiParser::With,       N, Y, }, // WITH
106 { WRITE,    &SbiParser::Write,      N, Y, }, // WRITE
107 
108 { NIL, nullptr, N, N }
109 };
110 
111 
112 SbiParser::SbiParser( StarBASIC* pb, SbModule* pm )
113         : SbiTokenizer( pm->GetSource32(), pb ),
114           aGlobals( aGblStrings, SbGLOBAL, this ),
115           aPublics( aGblStrings, SbPUBLIC, this ),
116           aRtlSyms( aGblStrings, SbRTL, this ),
117           aGen( *pm, this, 1024 )
118 {
119     eEndTok  = NIL;
120     pProc    = nullptr;
121     pStack   = nullptr;
122     pWithVar = nullptr;
123     nBase    = 0;
124     bGblDefs =
125     bNewGblDefs =
126     bSingleLineIf =
127     bCodeCompleting =
128     bExplicit = false;
129     bClassModule = ( pm->GetModuleType() == css::script::ModuleType::CLASS );
130     pPool    = &aPublics;
131     for(SbxDataType & eDefType : eDefTypes)
132         eDefType = SbxVARIANT;    // no explicit default type
133 
134     aPublics.SetParent( &aGlobals );
135     aGlobals.SetParent( &aRtlSyms );
136 
137 
138     nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
139 
140     rTypeArray = new SbxArray; // array for user defined types
141     rEnumArray = new SbxArray; // array for Enum types
142     bVBASupportOn = pm->IsVBACompat();
143     if ( bVBASupportOn )
144         EnableCompatibility();
145 
146 }
147 
148 SbiParser::~SbiParser() { }
149 
150 // part of the runtime-library?
151 SbiSymDef* SbiParser::CheckRTLForSym(const OUString& rSym, SbxDataType eType)
152 {
153     SbxVariable* pVar = GetBasic()->GetRtl()->Find(rSym, SbxClassType::DontCare);
154     if (!pVar)
155         return nullptr;
156 
157     if (SbxMethod* pMethod = dynamic_cast<SbxMethod*>(pVar))
158     {
159         SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym );
160         if (pMethod->IsRuntimeFunction())
161         {
162             pProc_->SetType( pMethod->GetRuntimeFunctionReturnType() );
163         }
164         else
165         {
166             pProc_->SetType( pVar->GetType() );
167         }
168         return pProc_;
169     }
170 
171 
172     SbiSymDef* pDef = aRtlSyms.AddSym(rSym);
173     pDef->SetType(eType);
174     return pDef;
175 }
176 
177 // close global chain
178 
179 bool SbiParser::HasGlobalCode()
180 {
181     if( bGblDefs && nGblChain )
182     {
183         aGen.BackChain( nGblChain );
184         aGen.Gen( SbiOpcode::LEAVE_ );
185         nGblChain = 0;
186     }
187     return bGblDefs;
188 }
189 
190 void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar )
191 {
192     SbiParseStack* p = new SbiParseStack;
193     p->eExitTok = eTok;
194     p->nChain   = 0;
195     p->pWithVar = pWithVar;
196     p->pNext    = pStack;
197     pStack      = p;
198     pWithVar    = pVar;
199 
200     // #29955 service the for-loop level
201     if( eTok == FOR )
202         aGen.IncForLevel();
203 }
204 
205 void SbiParser::CloseBlock()
206 {
207     if( pStack )
208     {
209         SbiParseStack* p = pStack;
210 
211         // #29955 service the for-loop level
212         if( p->eExitTok == FOR )
213             aGen.DecForLevel();
214 
215         aGen.BackChain( p->nChain );
216         pStack = p->pNext;
217         pWithVar = p->pWithVar;
218         delete p;
219     }
220 }
221 
222 // EXIT ...
223 
224 void SbiParser::Exit()
225 {
226     SbiToken eTok = Next();
227     for( SbiParseStack* p = pStack; p; p = p->pNext )
228     {
229         SbiToken eExitTok = p->eExitTok;
230         if( eTok == eExitTok ||
231             (eTok == PROPERTY && (eExitTok == GET || eExitTok == LET) ) )   // #i109051
232         {
233             p->nChain = aGen.Gen( SbiOpcode::JUMP_, p->nChain );
234             return;
235         }
236     }
237     if( pStack )
238         Error( ERRCODE_BASIC_EXPECTED, pStack->eExitTok );
239     else
240         Error( ERRCODE_BASIC_BAD_EXIT );
241 }
242 
243 bool SbiParser::TestSymbol()
244 {
245     Peek();
246     if( eCurTok == SYMBOL )
247     {
248         Next(); return true;
249     }
250     Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
251     return false;
252 }
253 
254 
255 bool SbiParser::TestToken( SbiToken t )
256 {
257     if( Peek() == t )
258     {
259         Next(); return true;
260     }
261     else
262     {
263         Error( ERRCODE_BASIC_EXPECTED, t );
264         return false;
265     }
266 }
267 
268 
269 bool SbiParser::TestComma()
270 {
271     SbiToken eTok = Peek();
272     if( IsEoln( eTok ) )
273     {
274         Next();
275         return false;
276     }
277     else if( eTok != COMMA )
278     {
279         Error( ERRCODE_BASIC_EXPECTED, COMMA );
280         return false;
281     }
282     Next();
283     return true;
284 }
285 
286 
287 void SbiParser::TestEoln()
288 {
289     if( !IsEoln( Next() ) )
290     {
291         Error( ERRCODE_BASIC_EXPECTED, EOLN );
292         while( !IsEoln( Next() ) ) {}
293     }
294 }
295 
296 
297 void SbiParser::StmntBlock( SbiToken eEnd )
298 {
299     SbiToken xe = eEndTok;
300     eEndTok = eEnd;
301     while( !bAbort && Parse() ) {}
302     eEndTok = xe;
303     if( IsEof() )
304     {
305         Error( ERRCODE_BASIC_BAD_BLOCK, eEnd );
306         bAbort = true;
307     }
308 }
309 
310 void SbiParser::SetCodeCompleting( bool b )
311 {
312     bCodeCompleting = b;
313 }
314 
315 
316 bool SbiParser::Parse()
317 {
318     if( bAbort ) return false;
319 
320     EnableErrors();
321 
322     bErrorIsSymbol = false;
323     Peek();
324     bErrorIsSymbol = true;
325 
326     if( IsEof() )
327     {
328         // AB #33133: If no sub has been created before,
329         // the global chain must be closed here!
330         // AB #40689: Due to the new static-handling there
331         // can be another nGblChain, so ask for it before.
332         if( bNewGblDefs && nGblChain == 0 )
333             nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
334         return false;
335     }
336 
337 
338     if( IsEoln( eCurTok ) )
339     {
340         Next(); return true;
341     }
342 
343     if( !bSingleLineIf && MayBeLabel( true ) )
344     {
345         // is a label
346         if( !pProc )
347             Error( ERRCODE_BASIC_NOT_IN_MAIN, aSym );
348         else
349             pProc->GetLabels().Define( aSym );
350         Next(); Peek();
351 
352         if( IsEoln( eCurTok ) )
353         {
354             Next(); return true;
355         }
356     }
357 
358     // end of parsing?
359     if( eCurTok == eEndTok ||
360         ( bVBASupportOn &&      // #i109075
361           (eCurTok == ENDFUNC || eCurTok == ENDPROPERTY || eCurTok == ENDSUB) &&
362           (eEndTok == ENDFUNC || eEndTok == ENDPROPERTY || eEndTok == ENDSUB) ) )
363     {
364         Next();
365         if( eCurTok != NIL )
366             aGen.Statement();
367         return false;
368     }
369 
370     // comment?
371     if( eCurTok == REM )
372     {
373         Next(); return true;
374     }
375 
376     // In vba it's possible to do Error.foobar ( even if it results in
377     // a runtime error
378     if ( eCurTok == ERROR_ && IsVBASupportOn() ) // we probably need to define a subset of keywords where this madness applies e.g. if ( IsVBASupportOn() && SymbolCanBeRedined( eCurTok ) )
379     {
380         SbiTokenizer tokens( *this );
381         tokens.Next();
382         if ( tokens.Peek()  == DOT )
383         {
384             eCurTok = SYMBOL;
385             ePush = eCurTok;
386         }
387     }
388     // if there's a symbol, it's either a variable (LET)
389     // or a SUB-procedure (CALL without brackets)
390     // DOT for assignments in the WITH-block: .A=5
391     if( eCurTok == SYMBOL || eCurTok == DOT )
392     {
393         if( !pProc )
394             Error( ERRCODE_BASIC_EXPECTED, SUB );
395         else
396         {
397             // for correct line and column...
398             Next();
399             Push( eCurTok );
400             aGen.Statement();
401             Symbol(nullptr);
402         }
403     }
404     else
405     {
406         Next();
407 
408         // statement parsers
409 
410         const SbiStatement* p;
411         for( p = StmntTable; p->eTok != NIL; p++ )
412             if( p->eTok == eCurTok )
413                 break;
414         if( p->eTok != NIL )
415         {
416             if( !pProc && !p->bMain )
417                 Error( ERRCODE_BASIC_NOT_IN_MAIN, eCurTok );
418             else if( pProc && !p->bSubr )
419                 Error( ERRCODE_BASIC_NOT_IN_SUBR, eCurTok );
420             else
421             {
422                 // AB #41606/#40689: Due to the new static-handling there
423                 // can be another nGblChain, so ask for it before.
424                 if( bNewGblDefs && nGblChain == 0 &&
425                     ( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) )
426                 {
427                     nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
428                     bNewGblDefs = false;
429                 }
430                 // statement-opcode at the beginning of a sub, too, please
431                 if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) ||
432                         eCurTok == SUB || eCurTok == FUNCTION )
433                     aGen.Statement();
434                 (this->*( p->Func ) )();
435                 ErrCode nSbxErr = SbxBase::GetError();
436                 if( nSbxErr )
437                 {
438                     SbxBase::ResetError();
439                     Error( nSbxErr );
440                 }
441             }
442         }
443         else
444             Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
445     }
446 
447     // test for the statement's end -
448     // might also be an ELSE, as there must not necessary be a : before the ELSE!
449 
450     if( !IsEos() )
451     {
452         Peek();
453         if( !IsEos() && eCurTok != ELSE )
454         {
455             // if the parsing has been aborted, jump over to the ":"
456             Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
457             while( !IsEos() ) Next();
458         }
459     }
460     // The parser aborts at the end, the
461     // next token has not been fetched yet!
462     return true;
463 }
464 
465 
466 SbiExprNode* SbiParser::GetWithVar()
467 {
468     if( pWithVar )
469         return pWithVar;
470 
471     SbiParseStack* p = pStack;
472     while( p )
473     {
474         // LoopVar can at the moment only be for with
475         if( p->pWithVar )
476             return p->pWithVar;
477         p = p->pNext;
478     }
479     return nullptr;
480 }
481 
482 
483 // assignment or subroutine call
484 
485 void SbiParser::Symbol( const KeywordSymbolInfo* pKeywordSymbolInfo )
486 {
487     SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD;
488     SbiExpression aVar( this, SbSYMBOL, eMode, pKeywordSymbolInfo );
489 
490     bool bEQ = ( Peek() == EQ );
491     if( !bEQ && bVBASupportOn && aVar.IsBracket() )
492         Error( ERRCODE_BASIC_EXPECTED, "=" );
493 
494     RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL );
495     bool bSpecialMidHandling = false;
496     SbiSymDef* pDef = aVar.GetRealVar();
497     if( bEQ && pDef && pDef->GetScope() == SbRTL )
498     {
499         OUString aRtlName = pDef->GetName();
500         if( aRtlName.equalsIgnoreAsciiCase("Mid") )
501         {
502             SbiExprNode* pExprNode = aVar.GetExprNode();
503             if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL )
504             {
505                 SbiExprList* pPar = pExprNode->GetParameters();
506                 short nParCount = pPar ? pPar->GetSize() : 0;
507                 if( nParCount == 2 || nParCount == 3 )
508                 {
509                     if( nParCount == 2 )
510                         pPar->addExpression( std::make_unique<SbiExpression>( this, -1, SbxLONG ) );
511 
512                     TestToken( EQ );
513                     pPar->addExpression( std::make_unique<SbiExpression>( this ) );
514 
515                     bSpecialMidHandling = true;
516                 }
517             }
518         }
519     }
520     aVar.Gen( eRecMode );
521     if( !bSpecialMidHandling )
522     {
523         if( !bEQ )
524         {
525             aGen.Gen( SbiOpcode::GET_ );
526         }
527         else
528         {
529             // so it must be an assignment!
530             if( !aVar.IsLvalue() )
531                 Error( ERRCODE_BASIC_LVALUE_EXPECTED );
532             TestToken( EQ );
533             SbiExpression aExpr( this );
534             aExpr.Gen();
535             SbiOpcode eOp = SbiOpcode::PUT_;
536             if( pDef )
537             {
538                 if( pDef->GetConstDef() )
539                     Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
540                 if( pDef->GetType() == SbxOBJECT )
541                 {
542                     eOp = SbiOpcode::SET_;
543                     if( pDef->GetTypeId() )
544                     {
545                         aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
546                         return;
547                     }
548                 }
549             }
550             aGen.Gen( eOp );
551         }
552     }
553 }
554 
555 
556 void SbiParser::Assign()
557 {
558     SbiExpression aLvalue( this, SbLVALUE );
559     TestToken( EQ );
560     SbiExpression aExpr( this );
561     aLvalue.Gen();
562     aExpr.Gen();
563     sal_uInt16 nLen = 0;
564     SbiSymDef* pDef = aLvalue.GetRealVar();
565     {
566         if( pDef->GetConstDef() )
567             Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
568         nLen = aLvalue.GetRealVar()->GetLen();
569     }
570     if( nLen )
571         aGen.Gen( SbiOpcode::PAD_, nLen );
572     aGen.Gen( SbiOpcode::PUT_ );
573 }
574 
575 // assignments of an object-variable
576 
577 void SbiParser::Set()
578 {
579     SbiExpression aLvalue( this, SbLVALUE );
580     SbxDataType eType = aLvalue.GetType();
581     if( eType != SbxOBJECT && eType != SbxEMPTY && eType != SbxVARIANT )
582         Error( ERRCODE_BASIC_INVALID_OBJECT );
583     TestToken( EQ );
584     SbiSymDef* pDef = aLvalue.GetRealVar();
585     if( pDef->GetConstDef() )
586         Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
587 
588     SbiToken eTok = Peek();
589     if( eTok == NEW )
590     {
591         Next();
592         SbiSymDef* pTypeDef = new SbiSymDef( OUString() );
593         TypeDecl( *pTypeDef, true );
594 
595         aLvalue.Gen();
596         aGen.Gen( SbiOpcode::CREATE_, pDef->GetId(), pTypeDef->GetTypeId() );
597         aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
598     }
599     else
600     {
601         SbiExpression aExpr( this );
602         aLvalue.Gen();
603         aExpr.Gen();
604         // It's a good idea to distinguish between
605         // set something = another &
606         // something = another
607         // ( it's necessary for vba objects where set is object
608         // specific and also doesn't involve processing default params )
609         if( pDef->GetTypeId() )
610         {
611             if ( bVBASupportOn )
612                 aGen.Gen( SbiOpcode::VBASETCLASS_, pDef->GetTypeId() );
613             else
614                 aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
615         }
616         else
617         {
618             if ( bVBASupportOn )
619                 aGen.Gen( SbiOpcode::VBASET_ );
620             else
621                 aGen.Gen( SbiOpcode::SET_ );
622         }
623     }
624 }
625 
626 // JSM 07.10.95
627 void SbiParser::LSet()
628 {
629     SbiExpression aLvalue( this, SbLVALUE );
630     if( aLvalue.GetType() != SbxSTRING )
631     {
632         Error( ERRCODE_BASIC_INVALID_OBJECT );
633     }
634     TestToken( EQ );
635     SbiSymDef* pDef = aLvalue.GetRealVar();
636     if( pDef && pDef->GetConstDef() )
637     {
638         Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
639     }
640     SbiExpression aExpr( this );
641     aLvalue.Gen();
642     aExpr.Gen();
643     aGen.Gen( SbiOpcode::LSET_ );
644 }
645 
646 // JSM 07.10.95
647 void SbiParser::RSet()
648 {
649     SbiExpression aLvalue( this, SbLVALUE );
650     if( aLvalue.GetType() != SbxSTRING )
651     {
652         Error( ERRCODE_BASIC_INVALID_OBJECT );
653     }
654     TestToken( EQ );
655     SbiSymDef* pDef = aLvalue.GetRealVar();
656     if( pDef && pDef->GetConstDef() )
657         Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
658     SbiExpression aExpr( this );
659     aLvalue.Gen();
660     aExpr.Gen();
661     aGen.Gen( SbiOpcode::RSET_ );
662 }
663 
664 // DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR and so on
665 
666 void SbiParser::DefXXX()
667 {
668     sal_Unicode ch1, ch2;
669     SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER );
670 
671     while( !bAbort )
672     {
673         if( Next() != SYMBOL ) break;
674         ch1 = rtl::toAsciiUpperCase(aSym[0]);
675         ch2 = 0;
676         if( Peek() == MINUS )
677         {
678             Next();
679             if( Next() != SYMBOL ) Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
680             else
681             {
682                 ch2 = rtl::toAsciiUpperCase(aSym[0]);
683                 if( ch2 < ch1 )
684                 {
685                     Error( ERRCODE_BASIC_SYNTAX );
686                     ch2 = 0;
687                 }
688             }
689         }
690         if (!ch2) ch2 = ch1;
691         ch1 -= 'A'; ch2 -= 'A';
692         for (; ch1 <= ch2; ch1++) eDefTypes[ ch1 ] = t;
693         if( !TestComma() ) break;
694     }
695 }
696 
697 // STOP/SYSTEM
698 
699 void SbiParser::Stop()
700 {
701     aGen.Gen( SbiOpcode::STOP_ );
702     Peek();     // #35694: only Peek(), so that EOL is recognized in Single-Line-If
703 }
704 
705 // IMPLEMENTS
706 
707 void SbiParser::Implements()
708 {
709     if( !bClassModule )
710     {
711         Error( ERRCODE_BASIC_UNEXPECTED, IMPLEMENTS );
712         return;
713     }
714 
715     Peek();
716     if( eCurTok != SYMBOL )
717     {
718         Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
719         return;
720     }
721 
722     OUString aImplementedIface = aSym;
723     Next();
724     if( Peek() == DOT )
725     {
726         OUString aDotStr( '.' );
727         while( Peek() == DOT )
728         {
729             aImplementedIface += aDotStr;
730             Next();
731             SbiToken ePeekTok = Peek();
732             if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
733             {
734                 Next();
735                 aImplementedIface += aSym;
736             }
737             else
738             {
739                 Next();
740                 Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
741                 break;
742             }
743         }
744     }
745     aIfaceVector.push_back( aImplementedIface );
746 }
747 
748 void SbiParser::EnableCompatibility()
749 {
750     if( !bCompatible )
751         AddConstants();
752     bCompatible = true;
753 }
754 
755 // OPTION
756 
757 void SbiParser::Option()
758 {
759     switch( Next() )
760     {
761         case BASIC_EXPLICIT:
762             bExplicit = true; break;
763         case BASE:
764             if( Next() == NUMBER && ( nVal == 0 || nVal == 1 ) )
765             {
766                 nBase = static_cast<short>(nVal);
767                 break;
768             }
769             Error( ERRCODE_BASIC_EXPECTED, "0/1" );
770             break;
771         case PRIVATE:
772         {
773             OUString aString = SbiTokenizer::Symbol(Next());
774             if( !aString.equalsIgnoreAsciiCase("Module") )
775             {
776                 Error( ERRCODE_BASIC_EXPECTED, "Module" );
777             }
778             break;
779         }
780         case COMPARE:
781         {
782             SbiToken eTok = Next();
783             if( eTok == BINARY )
784             {
785             }
786             else if( eTok == SYMBOL && GetSym().equalsIgnoreAsciiCase("text") )
787             {
788             }
789             else
790             {
791                 Error( ERRCODE_BASIC_EXPECTED, "Text/Binary" );
792             }
793             break;
794         }
795         case COMPATIBLE:
796             EnableCompatibility();
797             break;
798 
799         case CLASSMODULE:
800             bClassModule = true;
801             aGen.GetModule().SetModuleType( css::script::ModuleType::CLASS );
802             break;
803         case VBASUPPORT: // Option VBASupport used to override the module mode ( in fact this must reset the mode
804             if( Next() == NUMBER )
805             {
806                 if ( nVal == 1 || nVal == 0 )
807                 {
808                     bVBASupportOn = ( nVal == 1 );
809                     if ( bVBASupportOn )
810                     {
811                         EnableCompatibility();
812                     }
813                     // if the module setting is different
814                     // reset it to what the Option tells us
815                     if ( bVBASupportOn != aGen.GetModule().IsVBACompat() )
816                     {
817                         aGen.GetModule().SetVBACompat( bVBASupportOn );
818                     }
819                     break;
820                 }
821             }
822             Error( ERRCODE_BASIC_EXPECTED, "0/1" );
823             break;
824         default:
825             Error( ERRCODE_BASIC_BAD_OPTION, eCurTok );
826     }
827 }
828 
829 static void addStringConst( SbiSymPool& rPool, const OUString& pSym, const OUString& rStr )
830 {
831     SbiConstDef* pConst = new SbiConstDef( pSym );
832     pConst->SetType( SbxSTRING );
833     pConst->Set( rStr );
834     rPool.Add( pConst );
835 }
836 
837 void SbiParser::AddConstants()
838 {
839     // #113063 Create constant RTL symbols
840     addStringConst( aPublics, "vbCr", "\x0D" );
841     addStringConst( aPublics, "vbCrLf", "\x0D\x0A" );
842     addStringConst( aPublics, "vbFormFeed", "\x0C" );
843     addStringConst( aPublics, "vbLf", "\x0A" );
844 #ifdef _WIN32
845     addStringConst( aPublics, "vbNewLine", "\x0D\x0A" );
846 #else
847     addStringConst( aPublics, "vbNewLine", "\x0A" );
848 #endif
849     addStringConst( aPublics, "vbNullString", "" );
850     addStringConst( aPublics, "vbTab", "\x09" );
851     addStringConst( aPublics, "vbVerticalTab", "\x0B" );
852 
853     // Force length 1 and make char 0 afterwards
854     OUString aNullCharStr(u'\0');
855     addStringConst( aPublics, "vbNullChar", aNullCharStr );
856 }
857 
858 // ERROR n
859 
860 void SbiParser::ErrorStmnt()
861 {
862     SbiExpression aPar( this );
863     aPar.Gen();
864     aGen.Gen( SbiOpcode::ERROR_ );
865 }
866 
867 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
868