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