xref: /trunk/main/basic/source/comp/parser.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basic.hxx"
30 #include <basic/sbx.hxx>
31 #include "sbcomp.hxx"
32 #include <com/sun/star/script/ModuleType.hpp>
33 
34 struct SbiParseStack {              // "Stack" fuer Statement-Blocks
35     SbiParseStack* pNext;           // Chain
36     SbiExprNode* pWithVar;          // Variable fuer WITH
37     SbiToken eExitTok;              // Exit-Token
38     sal_uInt32  nChain;                 // JUMP-Chain
39 };
40 
41 struct SbiStatement {
42     SbiToken eTok;
43     void( SbiParser::*Func )();     // Verarbeitungsroutine
44     sal_Bool  bMain;                    // sal_True: ausserhalb SUBs OK
45     sal_Bool  bSubr;                    // sal_True: in SUBs OK
46 };
47 
48 #define Y   sal_True
49 #define N   sal_False
50 
51 static SbiStatement StmntTable [] = {
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, NULL, N, N }
116 };
117 
118 
119 #ifdef _MSC_VER
120 // 'this' : used in base member initializer list
121 #pragma warning( disable: 4355 )
122 #endif
123 
124 SbiParser::SbiParser( StarBASIC* pb, SbModule* pm )
125         : SbiTokenizer( pm->GetSource32(), pb ),
126           aGblStrings( this ),
127           aLclStrings( this ),
128           aGlobals( aGblStrings, SbGLOBAL ),
129           aPublics( aGblStrings, SbPUBLIC ),
130           aRtlSyms( aGblStrings, SbRTL ),
131           aGen( *pm, this, 1024 )
132 {
133     pBasic   = pb;
134     eCurExpr = SbSYMBOL;
135     eEndTok  = NIL;
136     pProc    = NULL;
137     pStack   = NULL;
138     pWithVar = NULL;
139     nBase    = 0;
140     bText    =
141     bGblDefs =
142     bNewGblDefs =
143     bSingleLineIf =
144     bExplicit = sal_False;
145     bClassModule = ( pm->GetModuleType() == com::sun::star::script::ModuleType::CLASS );
146     OSL_TRACE("Parser - %s, bClassModule %d", rtl::OUStringToOString( pm->GetName(), RTL_TEXTENCODING_UTF8 ).getStr(), bClassModule );
147     pPool    = &aPublics;
148     for( short i = 0; i < 26; i++ )
149         eDefTypes[ i ] = SbxVARIANT;    // Kein expliziter Defaulttyp
150 
151     aPublics.SetParent( &aGlobals );
152     aGlobals.SetParent( &aRtlSyms );
153 
154     // Die globale Chainkette faengt bei Adresse 0 an:
155     nGblChain = aGen.Gen( _JUMP, 0 );
156 
157     rTypeArray = new SbxArray; // Array fuer Benutzerdefinierte Typen
158     rEnumArray = new SbxArray; // Array for Enum types
159     bVBASupportOn = pm->IsVBACompat();
160     if ( bVBASupportOn )
161         EnableCompatibility();
162 
163 }
164 
165 
166 // Ist  Teil der Runtime-Library?
167 SbiSymDef* SbiParser::CheckRTLForSym( const String& rSym, SbxDataType eType )
168 {
169     SbxVariable* pVar = GetBasic()->GetRtl()->Find( rSym, SbxCLASS_DONTCARE );
170     SbiSymDef* pDef = NULL;
171     if( pVar )
172     {
173         if( pVar->IsA( TYPE(SbxMethod) ) )
174         {
175             SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym );
176             pProc_->SetType( pVar->GetType() );
177             pDef = pProc_;
178         }
179         else
180         {
181             pDef = aRtlSyms.AddSym( rSym );
182             pDef->SetType( eType );
183         }
184     }
185     return pDef;
186 }
187 
188 // Globale Chainkette schliessen
189 
190 sal_Bool SbiParser::HasGlobalCode()
191 {
192     if( bGblDefs && nGblChain )
193     {
194         aGen.BackChain( nGblChain );
195         aGen.Gen( _LEAVE );
196         // aGen.Gen( _STOP );
197         nGblChain = 0;
198     }
199     return bGblDefs;
200 }
201 
202 void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar )
203 {
204     SbiParseStack* p = new SbiParseStack;
205     p->eExitTok = eTok;
206     p->nChain   = 0;
207     p->pWithVar = pWithVar;
208     p->pNext    = pStack;
209     pStack      = p;
210     pWithVar    = pVar;
211 
212     // #29955 for-Schleifen-Ebene pflegen
213     if( eTok == FOR )
214         aGen.IncForLevel();
215 }
216 
217 void SbiParser::CloseBlock()
218 {
219     if( pStack )
220     {
221         SbiParseStack* p = pStack;
222 
223         // #29955 for-Schleifen-Ebene pflegen
224         if( p->eExitTok == FOR )
225             aGen.DecForLevel();
226 
227         aGen.BackChain( p->nChain );
228         pStack = p->pNext;
229         pWithVar = p->pWithVar;
230         delete p;
231     }
232 }
233 
234 // EXIT ...
235 
236 void SbiParser::Exit()
237 {
238     SbiToken eTok = Next();
239     for( SbiParseStack* p = pStack; p; p = p->pNext )
240     {
241         SbiToken eExitTok = p->eExitTok;
242         if( eTok == eExitTok ||
243             (eTok == PROPERTY && (eExitTok == GET || eExitTok == LET) ) )   // #i109051
244         {
245             p->nChain = aGen.Gen( _JUMP, p->nChain );
246             return;
247         }
248     }
249     if( pStack )
250         Error( SbERR_EXPECTED, pStack->eExitTok );
251     else
252         Error( SbERR_BAD_EXIT );
253 }
254 
255 sal_Bool SbiParser::TestSymbol( sal_Bool bKwdOk )
256 {
257     Peek();
258     if( eCurTok == SYMBOL || ( bKwdOk && IsKwd( eCurTok ) ) )
259     {
260         Next(); return sal_True;
261     }
262     Error( SbERR_SYMBOL_EXPECTED );
263     return sal_False;
264 }
265 
266 // Testen auf ein bestimmtes Token
267 
268 sal_Bool SbiParser::TestToken( SbiToken t )
269 {
270     if( Peek() == t )
271     {
272         Next(); return sal_True;
273     }
274     else
275     {
276         Error( SbERR_EXPECTED, t );
277         return sal_False;
278     }
279 }
280 
281 // Testen auf Komma oder EOLN
282 
283 sal_Bool SbiParser::TestComma()
284 {
285     SbiToken eTok = Peek();
286     if( IsEoln( eTok ) )
287     {
288         Next();
289         return sal_False;
290     }
291     else if( eTok != COMMA )
292     {
293         Error( SbERR_EXPECTED, COMMA );
294         return sal_False;
295     }
296     Next();
297     return sal_True;
298 }
299 
300 // Testen, ob EOLN vorliegt
301 
302 void SbiParser::TestEoln()
303 {
304     if( !IsEoln( Next() ) )
305     {
306         Error( SbERR_EXPECTED, EOLN );
307         while( !IsEoln( Next() ) ) {}
308     }
309 }
310 
311 // Parsing eines Statement-Blocks
312 // Das Parsing laeuft bis zum Ende-Token.
313 
314 void SbiParser::StmntBlock( SbiToken eEnd )
315 {
316     SbiToken xe = eEndTok;
317     eEndTok = eEnd;
318     while( !bAbort && Parse() ) {}
319     eEndTok = xe;
320     if( IsEof() )
321     {
322         Error( SbERR_BAD_BLOCK, eEnd );
323         bAbort = sal_True;
324     }
325 }
326 
327 // Die Hauptroutine. Durch wiederholten Aufrufs dieser Routine wird
328 // die Quelle geparst. Returnwert sal_False bei Ende/Fehlern.
329 
330 sal_Bool SbiParser::Parse()
331 {
332     if( bAbort ) return sal_False;
333 
334     EnableErrors();
335 
336     bErrorIsSymbol = false;
337     Peek();
338     bErrorIsSymbol = true;
339     // Dateiende?
340     if( IsEof() )
341     {
342         // AB #33133: Falls keine Sub angelegt wurde, muss hier
343         // der globale Chain abgeschlossen werden!
344         // AB #40689: Durch die neue static-Behandlung kann noch
345         // ein nGblChain vorhanden sein, daher vorher abfragen
346         if( bNewGblDefs && nGblChain == 0 )
347             nGblChain = aGen.Gen( _JUMP, 0 );
348         return sal_False;
349     }
350 
351     // Leerstatement?
352     if( IsEoln( eCurTok ) )
353     {
354         Next(); return sal_True;
355     }
356 
357     if( !bSingleLineIf && MayBeLabel( sal_True ) )
358     {
359         // Ist ein Label
360         if( !pProc )
361             Error( SbERR_NOT_IN_MAIN, aSym );
362         else
363             pProc->GetLabels().Define( aSym );
364         Next(); Peek();
365         // Leerstatement?
366         if( IsEoln( eCurTok ) )
367         {
368             Next(); return sal_True;
369         }
370     }
371 
372     // Ende des Parsings?
373     if( eCurTok == eEndTok ||
374         ( bVBASupportOn &&      // #i109075
375           (eCurTok == ENDFUNC || eCurTok == ENDPROPERTY || eCurTok == ENDSUB) &&
376           (eEndTok == ENDFUNC || eEndTok == ENDPROPERTY || eEndTok == ENDSUB) ) )
377     {
378         Next();
379         if( eCurTok != NIL )
380             aGen.Statement();
381         return sal_False;
382     }
383 
384     // Kommentar?
385     if( eCurTok == REM )
386     {
387         Next(); return sal_True;
388     }
389 
390     // Kommt ein Symbol, ist es entweder eine Variable( LET )
391     // oder eine SUB-Prozedur( CALL ohne Klammern )
392     // DOT fuer Zuweisungen im WITH-Block: .A=5
393     if( eCurTok == SYMBOL || eCurTok == DOT )
394     {
395         if( !pProc )
396             Error( SbERR_EXPECTED, SUB );
397         else
398         {
399             // Damit Zeile & Spalte stimmen...
400             Next();
401             Push( eCurTok );
402             aGen.Statement();
403                 Symbol();
404         }
405     }
406     else
407     {
408         Next();
409 
410         // Hier folgen nun die Statement-Parser.
411 
412         SbiStatement* p;
413         for( p = StmntTable; p->eTok != NIL; p++ )
414             if( p->eTok == eCurTok )
415                 break;
416         if( p->eTok != NIL )
417         {
418             if( !pProc && !p->bMain )
419                 Error( SbERR_NOT_IN_MAIN, eCurTok );
420             else if( pProc && !p->bSubr )
421                 Error( SbERR_NOT_IN_SUBR, eCurTok );
422             else
423             {
424                 // globalen Chain pflegen
425                 // AB #41606/#40689: Durch die neue static-Behandlung kann noch
426                 // ein nGblChain vorhanden sein, daher vorher abfragen
427                 if( bNewGblDefs && nGblChain == 0 &&
428                     ( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) )
429                 {
430                     nGblChain = aGen.Gen( _JUMP, 0 );
431                     bNewGblDefs = sal_False;
432                 }
433                 // Statement-Opcode bitte auch am Anfang einer Sub
434                 if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) ||
435                         eCurTok == SUB || eCurTok == FUNCTION )
436                     aGen.Statement();
437                 (this->*( p->Func ) )();
438                 SbxError nSbxErr = SbxBase::GetError();
439                 if( nSbxErr )
440                     SbxBase::ResetError(), Error( (SbError)nSbxErr );
441             }
442         }
443         else
444             Error( SbERR_UNEXPECTED, eCurTok );
445     }
446 
447     // Test auf Ende des Statements:
448     // Kann auch ein ELSE sein, da vor dem ELSE kein : stehen muss!
449 
450     if( !IsEos() )
451     {
452         Peek();
453         if( !IsEos() && eCurTok != ELSE )
454         {
455             // falls das Parsing abgebrochen wurde, bis zum ":" vorgehen:
456             Error( SbERR_UNEXPECTED, eCurTok );
457             while( !IsEos() ) Next();
458         }
459     }
460     // Der Parser bricht am Ende ab, das naechste Token ist noch nicht
461     // geholt!
462     return sal_True;
463 }
464 
465 // Innerste With-Variable liefern
466 SbiExprNode* SbiParser::GetWithVar()
467 {
468     if( pWithVar )
469         return pWithVar;
470 
471     // Sonst im Stack suchen
472     SbiParseStack* p = pStack;
473     while( p )
474     {
475         // LoopVar kann zur Zeit nur fuer with sein
476         if( p->pWithVar )
477             return p->pWithVar;
478         p = p->pNext;
479     }
480     return NULL;
481 }
482 
483 
484 // Zuweisung oder Subroutine Call
485 
486 void SbiParser::Symbol( const KeywordSymbolInfo* pKeywordSymbolInfo )
487 {
488     SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD;
489     SbiExpression aVar( this, SbSYMBOL, eMode, pKeywordSymbolInfo );
490 
491     bool bEQ = ( Peek() == EQ );
492     if( !bEQ && bVBASupportOn && aVar.IsBracket() )
493         Error( SbERR_EXPECTED, "=" );
494 
495     RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL );
496     bool bSpecialMidHandling = false;
497     SbiSymDef* pDef = aVar.GetRealVar();
498     if( bEQ && pDef && pDef->GetScope() == SbRTL )
499     {
500         String aRtlName = pDef->GetName();
501         if( aRtlName.EqualsIgnoreCaseAscii("Mid") )
502         {
503             SbiExprNode* pExprNode = aVar.GetExprNode();
504             // SbiNodeType eNodeType;
505             if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL )
506             {
507                 SbiExprList* pPar = pExprNode->GetParameters();
508                 short nParCount = pPar ? pPar->GetSize() : 0;
509                 if( nParCount == 2 || nParCount == 3 )
510                 {
511                     if( nParCount == 2 )
512                         pPar->addExpression( new SbiExpression( this, -1, SbxLONG ) );
513 
514                     TestToken( EQ );
515                     pPar->addExpression( new SbiExpression( this ) );
516 
517                     bSpecialMidHandling = true;
518                 }
519             }
520         }
521     }
522     aVar.Gen( eRecMode );
523     if( !bSpecialMidHandling )
524     {
525         if( !bEQ )
526         {
527             aGen.Gen( _GET );
528         }
529         else
530         {
531             // Dann muss es eine Zuweisung sein. Was anderes gibts nicht!
532             if( !aVar.IsLvalue() )
533                 Error( SbERR_LVALUE_EXPECTED );
534             TestToken( EQ );
535             SbiExpression aExpr( this );
536             aExpr.Gen();
537             SbiOpcode eOp = _PUT;
538             // SbiSymDef* pDef = aVar.GetRealVar();
539             if( pDef )
540             {
541                 if( pDef->GetConstDef() )
542                     Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
543                 if( pDef->GetType() == SbxOBJECT )
544                 {
545                     eOp = _SET;
546                     if( pDef->GetTypeId() )
547                     {
548                         aGen.Gen( _SETCLASS, pDef->GetTypeId() );
549                         return;
550                     }
551                 }
552             }
553             aGen.Gen( eOp );
554         }
555     }
556 }
557 
558 // Zuweisungen
559 
560 void SbiParser::Assign()
561 {
562     SbiExpression aLvalue( this, SbLVALUE );
563     TestToken( EQ );
564     SbiExpression aExpr( this );
565     aLvalue.Gen();
566     aExpr.Gen();
567     sal_uInt16 nLen = 0;
568     SbiSymDef* pDef = aLvalue.GetRealVar();
569     {
570         if( pDef->GetConstDef() )
571             Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
572         nLen = aLvalue.GetRealVar()->GetLen();
573     }
574     if( nLen )
575         aGen.Gen( _PAD, nLen );
576     aGen.Gen( _PUT );
577 }
578 
579 // Zuweisungen einer Objektvariablen
580 
581 void SbiParser::Set()
582 {
583     SbiExpression aLvalue( this, SbLVALUE );
584     SbxDataType eType = aLvalue.GetType();
585     if( eType != SbxOBJECT && eType != SbxEMPTY && eType != SbxVARIANT )
586         Error( SbERR_INVALID_OBJECT );
587     TestToken( EQ );
588     SbiSymDef* pDef = aLvalue.GetRealVar();
589     if( pDef && pDef->GetConstDef() )
590         Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
591 
592     SbiToken eTok = Peek();
593     if( eTok == NEW )
594     {
595         Next();
596         String aStr;
597         SbiSymDef* pTypeDef = new SbiSymDef( aStr );
598         TypeDecl( *pTypeDef, sal_True );
599 
600         aLvalue.Gen();
601         // aGen.Gen( _CLASS, pDef->GetTypeId() | 0x8000 );
602         aGen.Gen( _CREATE, pDef->GetId(), pTypeDef->GetTypeId() );
603         aGen.Gen( _SETCLASS, pDef->GetTypeId() );
604     }
605     else
606     {
607         SbiExpression aExpr( this );
608         aLvalue.Gen();
609         aExpr.Gen();
610         // Its a good idea to distinguish between
611         // set someting = another &
612         // someting = another
613         // ( its 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( _VBASETCLASS, pDef->GetTypeId() );
619             else
620                 aGen.Gen( _SETCLASS, pDef->GetTypeId() );
621         }
622         else
623         {
624             if ( bVBASupportOn )
625                 aGen.Gen( _VBASET );
626             else
627                 aGen.Gen( _SET );
628         }
629     }
630     // aGen.Gen( _SET );
631 }
632 
633 // JSM 07.10.95
634 void SbiParser::LSet()
635 {
636     SbiExpression aLvalue( this, SbLVALUE );
637     if( aLvalue.GetType() != SbxSTRING )
638         Error( SbERR_INVALID_OBJECT );
639     TestToken( EQ );
640     SbiSymDef* pDef = aLvalue.GetRealVar();
641     if( pDef && pDef->GetConstDef() )
642         Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
643     SbiExpression aExpr( this );
644     aLvalue.Gen();
645     aExpr.Gen();
646     aGen.Gen( _LSET );
647 }
648 
649 // JSM 07.10.95
650 void SbiParser::RSet()
651 {
652     SbiExpression aLvalue( this, SbLVALUE );
653     if( aLvalue.GetType() != SbxSTRING )
654         Error( SbERR_INVALID_OBJECT );
655     TestToken( EQ );
656     SbiSymDef* pDef = aLvalue.GetRealVar();
657     if( pDef && pDef->GetConstDef() )
658         Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
659     SbiExpression aExpr( this );
660     aLvalue.Gen();
661     aExpr.Gen();
662     aGen.Gen( _RSET );
663 }
664 
665 // DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR und so weiter
666 
667 void SbiParser::DefXXX()
668 {
669     sal_Unicode ch1, ch2;
670     SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER );
671 
672     while( !bAbort )
673     {
674         if( Next() != SYMBOL ) break;
675         ch1 = aSym.ToUpperAscii().GetBuffer()[0];
676         ch2 = 0;
677         if( Peek() == MINUS )
678         {
679             Next();
680             if( Next() != SYMBOL ) Error( SbERR_SYMBOL_EXPECTED );
681             else
682             {
683                 ch2 = aSym.ToUpperAscii().GetBuffer()[0];
684                 //ch2 = aSym.Upper();
685                 if( ch2 < ch1 ) Error( SbERR_SYNTAX ), ch2 = 0;
686             }
687         }
688         if (!ch2) ch2 = ch1;
689         ch1 -= 'A'; ch2 -= 'A';
690         for (; ch1 <= ch2; ch1++) eDefTypes[ ch1 ] = t;
691         if( !TestComma() ) break;
692     }
693 }
694 
695 // STOP/SYSTEM
696 
697 void SbiParser::Stop()
698 {
699     aGen.Gen( _STOP );
700     Peek();     // #35694: Nur Peek(), damit EOL in Single-Line-If erkannt wird
701 }
702 
703 // IMPLEMENTS
704 
705 void SbiParser::Implements()
706 {
707     if( !bClassModule )
708     {
709         Error( SbERR_UNEXPECTED, IMPLEMENTS );
710         return;
711     }
712 
713     Peek();
714     if( eCurTok != SYMBOL )
715     {
716         Error( SbERR_SYMBOL_EXPECTED );
717         return;
718     }
719 
720     String aImplementedIface = aSym;
721     Next();
722     if( Peek() == DOT )
723     {
724         String aDotStr( '.' );
725         while( Peek() == DOT )
726         {
727             aImplementedIface += aDotStr;
728             Next();
729             SbiToken ePeekTok = Peek();
730             if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
731             {
732                 Next();
733                 aImplementedIface += aSym;
734             }
735             else
736             {
737                 Next();
738                 Error( SbERR_SYMBOL_EXPECTED );
739                 break;
740             }
741         }
742     }
743     aIfaceVector.push_back( aImplementedIface );
744 }
745 
746 void SbiParser::EnableCompatibility()
747 {
748     if( !bCompatible )
749         AddConstants();
750     bCompatible = sal_True;
751 }
752 
753 // OPTION
754 
755 void SbiParser::Option()
756 {
757     switch( Next() )
758     {
759         case EXPLICIT:
760             bExplicit = sal_True; break;
761         case BASE:
762             if( Next() == NUMBER )
763             {
764                 if( nVal == 0 || nVal == 1 )
765                 {
766                     nBase = (short) nVal;
767                     break;
768                 }
769             }
770             Error( SbERR_EXPECTED, "0/1" );
771             break;
772         case PRIVATE:
773         {
774             String aString = SbiTokenizer::Symbol(Next());
775             if( !aString.EqualsIgnoreCaseAscii("Module") )
776                 Error( SbERR_EXPECTED, "Module" );
777             break;
778         }
779         case COMPARE:
780         {
781             SbiToken eTok = Next();
782             if( eTok == BINARY )
783                 bText = sal_False;
784             else if( eTok == SYMBOL && GetSym().EqualsIgnoreCaseAscii("text") )
785                 bText = sal_True;
786             else
787                 Error( SbERR_EXPECTED, "Text/Binary" );
788             break;
789         }
790         case COMPATIBLE:
791             EnableCompatibility();
792             break;
793 
794         case CLASSMODULE:
795             bClassModule = sal_True;
796             aGen.GetModule().SetModuleType( com::sun::star::script::ModuleType::CLASS );
797             break;
798         case VBASUPPORT:
799             if( Next() == NUMBER )
800             {
801                 if ( nVal == 1 || nVal == 0 )
802                 {
803                     bVBASupportOn = ( nVal == 1 );
804                     if ( bVBASupportOn )
805                         EnableCompatibility();
806                     // if the module setting is different
807                     // reset it to what the Option tells us
808                     if ( bVBASupportOn != aGen.GetModule().IsVBACompat() )
809                         aGen.GetModule().SetVBACompat( bVBASupportOn );
810                     break;
811                 }
812             }
813             Error( SbERR_EXPECTED, "0/1" );
814             break;
815         default:
816             Error( SbERR_BAD_OPTION, eCurTok );
817     }
818 }
819 
820 void addStringConst( SbiSymPool& rPool, const char* pSym, const String& rStr )
821 {
822     SbiConstDef* pConst = new SbiConstDef( String::CreateFromAscii( pSym ) );
823     pConst->SetType( SbxSTRING );
824     pConst->Set( rStr );
825     rPool.Add( pConst );
826 }
827 
828 inline void addStringConst( SbiSymPool& rPool, const char* pSym, const char* pStr )
829 {
830     addStringConst( rPool, pSym, String::CreateFromAscii( pStr ) );
831 }
832 
833 void SbiParser::AddConstants( void )
834 {
835     // #113063 Create constant RTL symbols
836     addStringConst( aPublics, "vbCr", "\x0D" );
837     addStringConst( aPublics, "vbCrLf", "\x0D\x0A" );
838     addStringConst( aPublics, "vbFormFeed", "\x0C" );
839     addStringConst( aPublics, "vbLf", "\x0A" );
840 #if defined(UNX)
841     addStringConst( aPublics, "vbNewLine", "\x0A" );
842 #else
843     addStringConst( aPublics, "vbNewLine", "\x0D\x0A" );
844 #endif
845     addStringConst( aPublics, "vbNullString", "" );
846     addStringConst( aPublics, "vbTab", "\x09" );
847     addStringConst( aPublics, "vbVerticalTab", "\x0B" );
848 
849     // Force length 1 and make char 0 afterwards
850     String aNullCharStr( String::CreateFromAscii( " " ) );
851     aNullCharStr.SetChar( 0, 0 );
852     addStringConst( aPublics, "vbNullChar", aNullCharStr );
853 }
854 
855 // ERROR n
856 
857 void SbiParser::ErrorStmnt()
858 {
859     SbiExpression aPar( this );
860     aPar.Gen();
861     aGen.Gen( _ERROR );
862 }
863 
864