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