xref: /trunk/main/basic/source/comp/parser.cxx (revision a3cdc23e488c57f3433f22cd4458e65c27aa499c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_basic.hxx"
24 #include <basic/sbx.hxx>
25 #include "sbcomp.hxx"
26 #include <com/sun/star/script/ModuleType.hpp>
27 
28 struct SbiParseStack {              // "Stack" für Statement-Blocks
29     SbiParseStack* pNext;           // Chain
30     SbiExprNode* pWithVar;          // Variable für WITH
31     SbiToken eExitTok;              // Exit-Token
32     sal_uInt32  nChain;                 // JUMP-Chain
33 };
34 
35 struct SbiStatement {
36     SbiToken eTok;
37     void( SbiParser::*Func )();     // Verarbeitungsroutine
38     sal_Bool  bMain;                    // sal_True: ausserhalb SUBs OK
39     sal_Bool  bSubr;                    // sal_True: in SUBs OK
40 };
41 
42 #define Y   sal_True
43 #define N   sal_False
44 
45 static SbiStatement StmntTable [] = {
46 { CALL,     &SbiParser::Call,       N, Y, }, // CALL
47 { CLOSE,    &SbiParser::Close,      N, Y, }, // CLOSE
48 { _CONST_,  &SbiParser::Dim,        Y, Y, }, // CONST
49 { DECLARE,  &SbiParser::Declare,    Y, N, }, // DECLARE
50 { DEFBOOL,  &SbiParser::DefXXX,     Y, N, }, // DEFBOOL
51 { DEFCUR,   &SbiParser::DefXXX,     Y, N, }, // DEFCUR
52 { DEFDATE,  &SbiParser::DefXXX,     Y, N, }, // DEFDATE
53 { DEFDBL,   &SbiParser::DefXXX,     Y, N, }, // DEFDBL
54 { DEFERR,   &SbiParser::DefXXX,     Y, N, }, // DEFERR
55 { DEFINT,   &SbiParser::DefXXX,     Y, N, }, // DEFINT
56 { DEFLNG,   &SbiParser::DefXXX,     Y, N, }, // DEFLNG
57 { DEFOBJ,   &SbiParser::DefXXX,     Y, N, }, // DEFOBJ
58 { DEFSNG,   &SbiParser::DefXXX,     Y, N, }, // DEFSNG
59 { DEFSTR,   &SbiParser::DefXXX,     Y, N, }, // DEFSTR
60 { DEFVAR,   &SbiParser::DefXXX,     Y, N, }, // DEFVAR
61 { DIM,      &SbiParser::Dim,        Y, Y, }, // DIM
62 { DO,       &SbiParser::DoLoop,     N, Y, }, // DO
63 { ELSE,     &SbiParser::NoIf,       N, Y, }, // ELSE
64 { ELSEIF,   &SbiParser::NoIf,       N, Y, }, // ELSEIF
65 { ENDIF,    &SbiParser::NoIf,       N, Y, }, // ENDIF
66 { END,      &SbiParser::Stop,       N, Y, }, // END
67 { ENUM,     &SbiParser::Enum,       Y, N, }, // TYPE
68 { ERASE,    &SbiParser::Erase,      N, Y, }, // ERASE
69 { _ERROR_,  &SbiParser::ErrorStmnt, N, Y, }, // ERROR
70 { EXIT,     &SbiParser::Exit,       N, Y, }, // EXIT
71 { FOR,      &SbiParser::For,        N, Y, }, // FOR
72 { FUNCTION, &SbiParser::SubFunc,    Y, N, }, // FUNCTION
73 { GOSUB,    &SbiParser::Goto,       N, Y, }, // GOSUB
74 { GLOBAL,   &SbiParser::Dim,        Y, N, }, // GLOBAL
75 { GOTO,     &SbiParser::Goto,       N, Y, }, // GOTO
76 { IF,       &SbiParser::If,         N, Y, }, // IF
77 { IMPLEMENTS, &SbiParser::Implements, Y, N, }, // IMPLEMENTS
78 { INPUT,    &SbiParser::Input,      N, Y, }, // INPUT
79 { LET,      &SbiParser::Assign,     N, Y, }, // LET
80 { LINE,     &SbiParser::Line,       N, Y, }, // LINE, -> LINE INPUT (#i92642)
81 { LINEINPUT,&SbiParser::LineInput,  N, Y, }, // LINE INPUT
82 { LOOP,     &SbiParser::BadBlock,   N, Y, }, // LOOP
83 { LSET,     &SbiParser::LSet,       N, Y, }, // LSET
84 { NAME,     &SbiParser::Name,       N, Y, }, // NAME
85 { NEXT,     &SbiParser::BadBlock,   N, Y, }, // NEXT
86 { ON,       &SbiParser::On,         N, Y, }, // ON
87 { OPEN,     &SbiParser::Open,       N, Y, }, // OPEN
88 { OPTION,   &SbiParser::Option,     Y, N, }, // OPTION
89 { PRINT,    &SbiParser::Print,      N, Y, }, // PRINT
90 { PRIVATE,  &SbiParser::Dim,        Y, N, }, // PRIVATE
91 { PROPERTY, &SbiParser::SubFunc,    Y, N, }, // FUNCTION
92 { PUBLIC,   &SbiParser::Dim,        Y, N, }, // PUBLIC
93 { REDIM,    &SbiParser::ReDim,      N, Y, }, // DIM
94 { RESUME,   &SbiParser::Resume,     N, Y, }, // RESUME
95 { RETURN,   &SbiParser::Return,     N, Y, }, // RETURN
96 { RSET,     &SbiParser::RSet,       N, Y, }, // RSET
97 { SELECT,   &SbiParser::Select,     N, Y, }, // SELECT
98 { SET,      &SbiParser::Set,        N, Y, }, // SET
99 { STATIC,   &SbiParser::Static,     Y, Y, }, // STATIC
100 { STOP,     &SbiParser::Stop,       N, Y, }, // STOP
101 { SUB,      &SbiParser::SubFunc,    Y, N, }, // SUB
102 { TYPE,     &SbiParser::Type,       Y, N, }, // TYPE
103 { UNTIL,    &SbiParser::BadBlock,   N, Y, }, // UNTIL
104 { WHILE,    &SbiParser::While,      N, Y, }, // WHILE
105 { WEND,     &SbiParser::BadBlock,   N, Y, }, // WEND
106 { WITH,     &SbiParser::With,       N, Y, }, // WITH
107 { WRITE,    &SbiParser::Write,      N, Y, }, // WRITE
108 
109 { NIL, NULL, N, N }
110 };
111 
112 
113 #ifdef _MSC_VER
114 // 'this' : used in base member initializer list
115 #pragma warning( disable: 4355 )
116 #endif
117 
118 SbiParser::SbiParser( StarBASIC* pb, SbModule* pm )
119         : SbiTokenizer( pm->GetSource32(), pb ),
120           aGblStrings( this ),
121           aLclStrings( this ),
122           aGlobals( aGblStrings, SbGLOBAL ),
123           aPublics( aGblStrings, SbPUBLIC ),
124           aRtlSyms( aGblStrings, SbRTL ),
125           aGen( *pm, this, 1024 )
126 {
127     pBasic   = pb;
128     eCurExpr = SbSYMBOL;
129     eEndTok  = NIL;
130     pProc    = NULL;
131     pStack   = NULL;
132     pWithVar = NULL;
133     nBase    = 0;
134     bText    =
135     bGblDefs =
136     bNewGblDefs =
137     bSingleLineIf =
138     bExplicit = sal_False;
139     bClassModule = ( pm->GetModuleType() == com::sun::star::script::ModuleType::CLASS );
140     OSL_TRACE("Parser - %s, bClassModule %d", rtl::OUStringToOString( pm->GetName(), RTL_TEXTENCODING_UTF8 ).getStr(), bClassModule );
141     pPool    = &aPublics;
142     for( short i = 0; i < 26; i++ )
143         eDefTypes[ i ] = SbxVARIANT; // Kein expliziter Defaulttyp
144 
145     aPublics.SetParent( &aGlobals );
146     aGlobals.SetParent( &aRtlSyms );
147 
148     // Die globale Chainkette faengt bei Adresse 0 an:
149     nGblChain = aGen.Gen( _JUMP, 0 );
150 
151     rTypeArray = new SbxArray; // Array fuer Benutzerdefinierte Typen
152     rEnumArray = new SbxArray; // Array for Enum types
153     bVBASupportOn = pm->IsVBACompat();
154     if ( bVBASupportOn )
155         EnableCompatibility();
156 
157 }
158 
159 
160 // Ist Teil der Runtime-Library?
161 SbiSymDef* SbiParser::CheckRTLForSym( const String& rSym, SbxDataType eType )
162 {
163     SbxVariable* pVar = GetBasic()->GetRtl()->Find( rSym, SbxCLASS_DONTCARE );
164     SbiSymDef* pDef = NULL;
165     if( pVar )
166     {
167         if( pVar->IsA( TYPE(SbxMethod) ) )
168         {
169             SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym );
170             SbxMethod* pMethod = (SbxMethod*) pVar;
171             if ( pMethod && pMethod->IsRuntimeFunction() )
172             {
173                 pProc_->SetType( pMethod->GetRuntimeFunctionReturnType() );
174             }
175             else
176             {
177                 pProc_->SetType( pVar->GetType() );
178             }
179             pDef = pProc_;
180         }
181         else
182         {
183             pDef = aRtlSyms.AddSym( rSym );
184             pDef->SetType( eType );
185         }
186     }
187     return pDef;
188 }
189 
190 // Globale Chainkette schliessen
191 
192 sal_Bool SbiParser::HasGlobalCode()
193 {
194     if( bGblDefs && nGblChain )
195     {
196         aGen.BackChain( nGblChain );
197         aGen.Gen( _LEAVE );
198         // aGen.Gen( _STOP );
199         nGblChain = 0;
200     }
201     return bGblDefs;
202 }
203 
204 void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar )
205 {
206     SbiParseStack* p = new SbiParseStack;
207     p->eExitTok = eTok;
208     p->nChain   = 0;
209     p->pWithVar = pWithVar;
210     p->pNext    = pStack;
211     pStack      = p;
212     pWithVar    = pVar;
213 
214     // #29955 for-Schleifen-Ebene pflegen
215     if( eTok == FOR )
216         aGen.IncForLevel();
217 }
218 
219 void SbiParser::CloseBlock()
220 {
221     if( pStack )
222     {
223         SbiParseStack* p = pStack;
224 
225         // #29955 for-Schleifen-Ebene pflegen
226         if( p->eExitTok == FOR )
227             aGen.DecForLevel();
228 
229         aGen.BackChain( p->nChain );
230         pStack = p->pNext;
231         pWithVar = p->pWithVar;
232         delete p;
233     }
234 }
235 
236 // EXIT ...
237 
238 void SbiParser::Exit()
239 {
240     SbiToken eTok = Next();
241     for( SbiParseStack* p = pStack; p; p = p->pNext )
242     {
243         SbiToken eExitTok = p->eExitTok;
244         if( eTok == eExitTok ||
245             (eTok == PROPERTY && (eExitTok == GET || eExitTok == LET) ) )   // #i109051
246         {
247             p->nChain = aGen.Gen( _JUMP, p->nChain );
248             return;
249         }
250     }
251     if( pStack )
252         Error( SbERR_EXPECTED, pStack->eExitTok );
253     else
254         Error( SbERR_BAD_EXIT );
255 }
256 
257 sal_Bool SbiParser::TestSymbol( sal_Bool bKwdOk )
258 {
259     Peek();
260     if( eCurTok == SYMBOL || ( bKwdOk && IsKwd( eCurTok ) ) )
261     {
262         Next(); return sal_True;
263     }
264     Error( SbERR_SYMBOL_EXPECTED );
265     return sal_False;
266 }
267 
268 // Testen auf ein bestimmtes Token
269 
270 sal_Bool SbiParser::TestToken( SbiToken t )
271 {
272     if( Peek() == t )
273     {
274         Next(); return sal_True;
275     }
276     else
277     {
278         Error( SbERR_EXPECTED, t );
279         return sal_False;
280     }
281 }
282 
283 // Testen auf Komma oder EOLN
284 
285 sal_Bool SbiParser::TestComma()
286 {
287     SbiToken eTok = Peek();
288     if( IsEoln( eTok ) )
289     {
290         Next();
291         return sal_False;
292     }
293     else if( eTok != COMMA )
294     {
295         Error( SbERR_EXPECTED, COMMA );
296         return sal_False;
297     }
298     Next();
299     return sal_True;
300 }
301 
302 // Testen, ob EOLN vorliegt
303 
304 void SbiParser::TestEoln()
305 {
306     if( !IsEoln( Next() ) )
307     {
308         Error( SbERR_EXPECTED, EOLN );
309         while( !IsEoln( Next() ) ) {}
310     }
311 }
312 
313 // Parsing eines Statement-Blocks
314 // Das Parsing läuft bis zum Ende-Token.
315 
316 void SbiParser::StmntBlock( SbiToken eEnd )
317 {
318     SbiToken xe = eEndTok;
319     eEndTok = eEnd;
320     while( !bAbort && Parse() ) {}
321     eEndTok = xe;
322     if( IsEof() )
323     {
324         Error( SbERR_BAD_BLOCK, eEnd );
325         bAbort = sal_True;
326     }
327 }
328 
329 // Die Hauptroutine. Durch wiederholten Aufrufs dieser Routine wird
330 // die Quelle geparst. Returnwert sal_False bei Ende/Fehlern.
331 
332 sal_Bool SbiParser::Parse()
333 {
334     if( bAbort ) return sal_False;
335 
336     EnableErrors();
337 
338     bErrorIsSymbol = false;
339     Peek();
340     bErrorIsSymbol = true;
341     // Dateiende?
342     if( IsEof() )
343     {
344         // AB #33133: Falls keine Sub angelegt wurde, muss hier
345         // der globale Chain abgeschlossen werden!
346         // AB #40689: Durch die neue static-Behandlung kann noch
347         // ein nGblChain vorhanden sein, daher vorher abfragen
348         if( bNewGblDefs && nGblChain == 0 )
349             nGblChain = aGen.Gen( _JUMP, 0 );
350         return sal_False;
351     }
352 
353     // Leerstatement?
354     if( IsEoln( eCurTok ) )
355     {
356         Next(); return sal_True;
357     }
358 
359     if( !bSingleLineIf && MayBeLabel( sal_True ) )
360     {
361         // Ist ein Label
362         if( !pProc )
363             Error( SbERR_NOT_IN_MAIN, aSym );
364         else
365             pProc->GetLabels().Define( aSym );
366         Next(); Peek();
367         // Leerstatement?
368         if( IsEoln( eCurTok ) )
369         {
370             Next(); return sal_True;
371         }
372     }
373 
374     // Ende des Parsings?
375     if( eCurTok == eEndTok ||
376         ( bVBASupportOn &&      // #i109075
377           (eCurTok == ENDFUNC || eCurTok == ENDPROPERTY || eCurTok == ENDSUB) &&
378           (eEndTok == ENDFUNC || eEndTok == ENDPROPERTY || eEndTok == ENDSUB) ) )
379     {
380         Next();
381         if( eCurTok != NIL )
382             aGen.Statement();
383         return sal_False;
384     }
385 
386     // Kommentar?
387     if( eCurTok == REM )
388     {
389         Next(); return sal_True;
390     }
391 
392     // Kommt ein Symbol, ist es entweder eine Variable( LET )
393     // oder eine SUB-Prozedur( CALL ohne Klammern )
394     // DOT für Zuweisungen im WITH-Block: .A=5
395     if( eCurTok == SYMBOL || eCurTok == DOT )
396     {
397         if( !pProc )
398             Error( SbERR_EXPECTED, SUB );
399         else
400         {
401             // Damit Zeile & Spalte stimmen...
402             Next();
403             Push( eCurTok );
404             aGen.Statement();
405                 Symbol();
406         }
407     }
408     else
409     {
410         Next();
411 
412         // Hier folgen nun die Statement-Parser.
413 
414         SbiStatement* p;
415         for( p = StmntTable; p->eTok != NIL; p++ )
416             if( p->eTok == eCurTok )
417                 break;
418         if( p->eTok != NIL )
419         {
420             if( !pProc && !p->bMain )
421                 Error( SbERR_NOT_IN_MAIN, eCurTok );
422             else if( pProc && !p->bSubr )
423                 Error( SbERR_NOT_IN_SUBR, eCurTok );
424             else
425             {
426                 // globalen Chain pflegen
427                 // AB #41606/#40689: Durch die neue static-Behandlung kann noch
428                 // ein nGblChain vorhanden sein, daher vorher abfragen
429                 if( bNewGblDefs && nGblChain == 0 &&
430                     ( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) )
431                 {
432                     nGblChain = aGen.Gen( _JUMP, 0 );
433                     bNewGblDefs = sal_False;
434                 }
435                 // Statement-Opcode bitte auch am Anfang einer Sub
436                 if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) ||
437                         eCurTok == SUB || eCurTok == FUNCTION )
438                     aGen.Statement();
439                 (this->*( p->Func ) )();
440                 SbxError nSbxErr = SbxBase::GetError();
441                 if( nSbxErr )
442                     SbxBase::ResetError(), Error( (SbError)nSbxErr );
443             }
444         }
445         else
446             Error( SbERR_UNEXPECTED, eCurTok );
447     }
448 
449     // Test auf Ende des Statements:
450     // Kann auch ein ELSE sein, da vor dem ELSE kein : stehen muss!
451 
452     if( !IsEos() )
453     {
454         Peek();
455         if( !IsEos() && eCurTok != ELSE )
456         {
457             // falls das Parsing abgebrochen wurde, bis zum ":" vorgehen:
458             Error( SbERR_UNEXPECTED, eCurTok );
459             while( !IsEos() ) Next();
460         }
461     }
462     // Der Parser bricht am Ende ab, das nächste Token ist noch nicht
463     // geholt!
464     return sal_True;
465 }
466 
467 // Innerste With-Variable liefern
468 SbiExprNode* SbiParser::GetWithVar()
469 {
470     if( pWithVar )
471         return pWithVar;
472 
473     // Sonst im Stack suchen
474     SbiParseStack* p = pStack;
475     while( p )
476     {
477         // LoopVar kann zur Zeit nur für with sein
478         if( p->pWithVar )
479             return p->pWithVar;
480         p = p->pNext;
481     }
482     return NULL;
483 }
484 
485 
486 // Zuweisung oder Subroutine Call
487 
488 void SbiParser::Symbol( const KeywordSymbolInfo* pKeywordSymbolInfo )
489 {
490     SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD;
491     SbiExpression aVar( this, SbSYMBOL, eMode, pKeywordSymbolInfo );
492 
493     bool bEQ = ( Peek() == EQ );
494     if( !bEQ && bVBASupportOn && aVar.IsBracket() )
495         Error( SbERR_EXPECTED, "=" );
496 
497     RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL );
498     bool bSpecialMidHandling = false;
499     SbiSymDef* pDef = aVar.GetRealVar();
500     if( bEQ && pDef && pDef->GetScope() == SbRTL )
501     {
502         String aRtlName = pDef->GetName();
503         if( aRtlName.EqualsIgnoreCaseAscii("Mid") )
504         {
505             SbiExprNode* pExprNode = aVar.GetExprNode();
506             // SbiNodeType eNodeType;
507             if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL )
508             {
509                 SbiExprList* pPar = pExprNode->GetParameters();
510                 short nParCount = pPar ? pPar->GetSize() : 0;
511                 if( nParCount == 2 || nParCount == 3 )
512                 {
513                     if( nParCount == 2 )
514                         pPar->addExpression( new SbiExpression( this, -1, SbxLONG ) );
515 
516                     TestToken( EQ );
517                     pPar->addExpression( new SbiExpression( this ) );
518 
519                     bSpecialMidHandling = true;
520                 }
521             }
522         }
523     }
524     aVar.Gen( eRecMode );
525     if( !bSpecialMidHandling )
526     {
527         if( !bEQ )
528         {
529             aGen.Gen( _GET );
530         }
531         else
532         {
533             // Dann muss es eine Zuweisung sein. Was anderes gibt es nicht!
534             if( !aVar.IsLvalue() )
535                 Error( SbERR_LVALUE_EXPECTED );
536             TestToken( EQ );
537             SbiExpression aExpr( this );
538             aExpr.Gen();
539             SbiOpcode eOp = _PUT;
540             // SbiSymDef* pDef = aVar.GetRealVar();
541             if( pDef )
542             {
543                 if( pDef->GetConstDef() )
544                     Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
545                 if( pDef->GetType() == SbxOBJECT )
546                 {
547                     eOp = _SET;
548                     if( pDef->GetTypeId() )
549                     {
550                         aGen.Gen( _SETCLASS, pDef->GetTypeId() );
551                         return;
552                     }
553                 }
554             }
555             aGen.Gen( eOp );
556         }
557     }
558 }
559 
560 // Zuweisungen
561 
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( SbERR_DUPLICATE_DEF, pDef->GetName() );
574         nLen = aLvalue.GetRealVar()->GetLen();
575     }
576     if( nLen )
577         aGen.Gen( _PAD, nLen );
578     aGen.Gen( _PUT );
579 }
580 
581 // Zuweisungen einer Objektvariablen
582 
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( SbERR_INVALID_OBJECT );
589     TestToken( EQ );
590     SbiSymDef* pDef = aLvalue.GetRealVar();
591     if( pDef && pDef->GetConstDef() )
592         Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
593 
594     SbiToken eTok = Peek();
595     if( eTok == NEW )
596     {
597         Next();
598         String aStr;
599         SbiSymDef* pTypeDef = new SbiSymDef( aStr );
600         TypeDecl( *pTypeDef, sal_True );
601 
602         aLvalue.Gen();
603         // aGen.Gen( _CLASS, pDef->GetTypeId() | 0x8000 );
604         aGen.Gen( _CREATE, pDef->GetId(), pTypeDef->GetTypeId() );
605         aGen.Gen( _SETCLASS, pDef->GetTypeId() );
606     }
607     else
608     {
609         SbiExpression aExpr( this );
610         aLvalue.Gen();
611         aExpr.Gen();
612         // It's a good idea to distinguish between
613         // set something = another &
614         // something = another
615         // ( it's necessary for vba objects where set is object
616         // specific and also doesn't involve processing default params )
617         if( pDef->GetTypeId() )
618         {
619             if ( bVBASupportOn )
620                 aGen.Gen( _VBASETCLASS, pDef->GetTypeId() );
621             else
622                 aGen.Gen( _SETCLASS, pDef->GetTypeId() );
623         }
624         else
625         {
626             if ( bVBASupportOn )
627                 aGen.Gen( _VBASET );
628             else
629                 aGen.Gen( _SET );
630         }
631     }
632     // aGen.Gen( _SET );
633 }
634 
635 // JSM 07.10.95
636 void SbiParser::LSet()
637 {
638     SbiExpression aLvalue( this, SbLVALUE );
639     if( aLvalue.GetType() != SbxSTRING )
640         Error( SbERR_INVALID_OBJECT );
641     TestToken( EQ );
642     SbiSymDef* pDef = aLvalue.GetRealVar();
643     if( pDef && pDef->GetConstDef() )
644         Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
645     SbiExpression aExpr( this );
646     aLvalue.Gen();
647     aExpr.Gen();
648     aGen.Gen( _LSET );
649 }
650 
651 // JSM 07.10.95
652 void SbiParser::RSet()
653 {
654     SbiExpression aLvalue( this, SbLVALUE );
655     if( aLvalue.GetType() != SbxSTRING )
656         Error( SbERR_INVALID_OBJECT );
657     TestToken( EQ );
658     SbiSymDef* pDef = aLvalue.GetRealVar();
659     if( pDef && pDef->GetConstDef() )
660         Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
661     SbiExpression aExpr( this );
662     aLvalue.Gen();
663     aExpr.Gen();
664     aGen.Gen( _RSET );
665 }
666 
667 // DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR und so weiter
668 
669 void SbiParser::DefXXX()
670 {
671     sal_Unicode ch1, ch2;
672     SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER );
673 
674     while( !bAbort )
675     {
676         if( Next() != SYMBOL ) break;
677         ch1 = aSym.ToUpperAscii().GetBuffer()[0];
678         ch2 = 0;
679         if( Peek() == MINUS )
680         {
681             Next();
682             if( Next() != SYMBOL ) Error( SbERR_SYMBOL_EXPECTED );
683             else
684             {
685                 ch2 = aSym.ToUpperAscii().GetBuffer()[0];
686                 //ch2 = aSym.Upper();
687                 if( ch2 < ch1 ) Error( SbERR_SYNTAX ), ch2 = 0;
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( _STOP );
702     Peek();     // #35694: Nur Peek(), damit EOL in Single-Line-If erkannt wird
703 }
704 
705 // IMPLEMENTS
706 
707 void SbiParser::Implements()
708 {
709     if( !bClassModule )
710     {
711         Error( SbERR_UNEXPECTED, IMPLEMENTS );
712         return;
713     }
714 
715     Peek();
716     if( eCurTok != SYMBOL )
717     {
718         Error( SbERR_SYMBOL_EXPECTED );
719         return;
720     }
721 
722     String aImplementedIface = aSym;
723     Next();
724     if( Peek() == DOT )
725     {
726         String 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( SbERR_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 = sal_True;
753 }
754 
755 // OPTION
756 
757 void SbiParser::Option()
758 {
759     switch( Next() )
760     {
761         case BASIC_EXPLICIT:
762             bExplicit = sal_True; break;
763         case BASE:
764             if( Next() == NUMBER )
765             {
766                 if( nVal == 0 || nVal == 1 )
767                 {
768                     nBase = (short) nVal;
769                     break;
770                 }
771             }
772             Error( SbERR_EXPECTED, "0/1" );
773             break;
774         case PRIVATE:
775         {
776             String aString = SbiTokenizer::Symbol(Next());
777             if( !aString.EqualsIgnoreCaseAscii("Module") )
778                 Error( SbERR_EXPECTED, "Module" );
779             break;
780         }
781         case COMPARE:
782         {
783             SbiToken eTok = Next();
784             if( eTok == BINARY )
785                 bText = sal_False;
786             else if( eTok == SYMBOL && GetSym().EqualsIgnoreCaseAscii("text") )
787                 bText = sal_True;
788             else
789                 Error( SbERR_EXPECTED, "Text/Binary" );
790             break;
791         }
792         case COMPATIBLE:
793             EnableCompatibility();
794             break;
795 
796         case CLASSMODULE:
797             bClassModule = sal_True;
798             aGen.GetModule().SetModuleType( com::sun::star::script::ModuleType::CLASS );
799             break;
800         case VBASUPPORT:
801             if( Next() == NUMBER )
802             {
803                 if ( nVal == 1 || nVal == 0 )
804                 {
805                     bVBASupportOn = ( nVal == 1 );
806                     if ( bVBASupportOn )
807                         EnableCompatibility();
808                     // if the module setting is different
809                     // reset it to what the Option tells us
810                     if ( bVBASupportOn != aGen.GetModule().IsVBACompat() )
811                         aGen.GetModule().SetVBACompat( bVBASupportOn );
812                     break;
813                 }
814             }
815             Error( SbERR_EXPECTED, "0/1" );
816             break;
817         default:
818             Error( SbERR_BAD_OPTION, eCurTok );
819     }
820 }
821 
822 void addStringConst( SbiSymPool& rPool, const char* pSym, const String& rStr )
823 {
824     SbiConstDef* pConst = new SbiConstDef( String::CreateFromAscii( pSym ) );
825     pConst->SetType( SbxSTRING );
826     pConst->Set( rStr );
827     rPool.Add( pConst );
828 }
829 
830 inline void addStringConst( SbiSymPool& rPool, const char* pSym, const char* pStr )
831 {
832     addStringConst( rPool, pSym, String::CreateFromAscii( pStr ) );
833 }
834 
835 void SbiParser::AddConstants( void )
836 {
837     // #113063 Create constant RTL symbols
838     addStringConst( aPublics, "vbCr", "\x0D" );
839     addStringConst( aPublics, "vbCrLf", "\x0D\x0A" );
840     addStringConst( aPublics, "vbFormFeed", "\x0C" );
841     addStringConst( aPublics, "vbLf", "\x0A" );
842 #if defined(UNX)
843     addStringConst( aPublics, "vbNewLine", "\x0A" );
844 #else
845     addStringConst( aPublics, "vbNewLine", "\x0D\x0A" );
846 #endif
847     addStringConst( aPublics, "vbNullString", "" );
848     addStringConst( aPublics, "vbTab", "\x09" );
849     addStringConst( aPublics, "vbVerticalTab", "\x0B" );
850 
851     // Force length 1 and make char 0 afterwards
852     String aNullCharStr( String::CreateFromAscii( " " ) );
853     aNullCharStr.SetChar( 0, 0 );
854     addStringConst( aPublics, "vbNullChar", aNullCharStr );
855 }
856 
857 // ERROR n
858 
859 void SbiParser::ErrorStmnt()
860 {
861     SbiExpression aPar( this );
862     aPar.Gen();
863     aGen.Gen( _ERROR );
864 }
865 
866 /* vim: set noet sw=4 ts=4: */
867