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